PRIVATE’DAN PUBLIC’E : ANAHTARLARINIZ NASIL OLUŞTURULUR?

Artstein
8 min readOct 24, 2022

--

RANDOMNESS

Private Key, Gizli(Özel) Anahtar, rastgele seçilmiş 1 ile 2²⁵⁶ arasında bir sayıdan ibarettir. 2²⁵⁶ yaklaşık 10⁷⁷ dir. Gözlemlenebilir evrendeki atom sayısının 10⁷⁷ ile 10⁸⁰ arasında olduğu tahmin ediliyor. Yani evrendeki her atoma(yaklaşık) yetecek kadar private-key’imiz var.

Private-key üretim süreci offline’dır. Yani herhangi bir blokzincir veya herhangi bir 3. parti ile iletişim gerektirmez. Bir private-key’in deterministik olmaması gerekir. Çünkü her ne kadar aralığımız geniş olsa da deterministik olsaydı kırılma ihtimali yüksek olurdu. Private Key üretimi için rastgeleliğe ihtiyacımız var.

Rastgelelik(Randomness) bir düzenin veya bir ilkenin olmadığı durumdur, tahmin edilemezliktir. Random(Rastgele) sayılar çeşitli sebeplerden dolayı gereklidir(Veri şifreleme, veri tabanlarından örnek alma, kumar…). Bir random sayı, her biri aynı olasılıkta olan veriler arasından seçilen bir sayıdır. Random sayılar farklı amaçlarla kullanılırlar. Bu sebepten dolayı farklı algoritmalarla üretilirler.

  1. True Random Number Generator(Gerçek Rasgele Sayı Üreteci — TRNG)

True Random Number Generator’lar rastgele fiziksel işlemlerden elde edilir. Örneğin bir madeni parayı alıp bir yüzüne 0 bir yüzüne 1 derseniz ve bu parayı 256 defa atıp 0 ve 1leri not alırsanız ve bir private key elde etmiş olursunuz. Alternatif yöntem olarak kozmik radyasyon alınabilir, Mouse’ınızı ekranda gezdirmeniz istenebilir veya sizden bir metin yazmanız istenebilir(tuşlara basma süreniz mikrosaniye olarak ölçülür ve kullanabilir).

2. Pseudo Random Number Generator(PRNG)

Pseudo-random sayılar, aslında random değildir. Yani bizim alıştığımız şekilde değil, zar atmak gibi değil yani :) Aslında Pseudo-Random Number Generator’lar matematiksel formüller kullanarak random gözüken sayılar üretirler. Yani aslında önceden belirlenmişlerdir. Bunlara güzel bir örnek olarak, aşağıda da açıklayacağım, Linear Congruential methodu örnek verilebilir. Bu alandaki araştırmalar sayesinde modern algoritmalar gerçekten random gibi gözüküyorlar.

Linear Congruential Generator, pseudo-random sayıları üretmek için en yaygın kullanılan ve en eski algoritmadır. Aşağıdaki gibi çalışır :

Xn+1 = (aXn + c) mod m

X pseudo-random sayı dizisidir.

m, 0 < m — mod
a, 0 < a < m — çarpan
c, 0 ≤ c < m — artış
x0, 0 ≤ x0 < m — the seed(başlangıç değeri)

PRNG Özellikleri

  • Verimli: PRNG kısa sürede çok fazla sayı üretebilir ve bu ihtiyacı olan uygulamalar için avantajlıdır.
  • Deterministik: Eğer başlangıç değer biliniyorsa sayı dizisi tekrar üretilebilir.
  • Periyodik: PRNG’ler periyodiktir, yani dizi eninde sonunda kendini tekrar edecektir. Periyodik olmaları istenmeyen bir özelliktir, modern PRNG’lerde periyotlar o kadar uzundur ki görmezden gelinebilir.

PRNG Uygulamaları

PRNG’ler çok fazla random sayıya ihtiyaç duyduğunuz ve aynı diziyi kolayca tekrar oynatmak istediğiniz uygulamalarda kullanışlıdır. Telefon konuşmalarının şifrelenmesinde bir PRNG algoritması kullanan, yukarıda da bahsettiğim Linear Congruential Generator kullanılır. Sayıların tahmin edilemez(unpredictable) olması gerektiği yerlerde, kumarda veya veri şifrelemede, kullanılamazlar.

Randomness’ı da açıkladığımıza göre bir soru sorabiliriz. Biz sayıların random olduğunu nasıl bilebiliriz? Bu soruyu bir paranın hilesiz olup olmadığını nasıl anlarız şeklinde basitleştirebiliriz. Sonuçta hilesiz bir paranın hangi yüzünün geleceğini de bilmiyoruz o da random. Bu durumda parayı defalarca kez atarım eşit sayıda yazı ve tura gelip gelmediğini kontrol ederim diyebilirsiniz. Bunun üzerinden gidelim. Hilesiz olduğunu iddia ettiğimiz bir parayı 2 kez atalım. Bu durumda 4 olasılık var. YY — YT — TY — TT (Y : Yazı, T: Tura). Hilesiz bir parada her bir durumun olma olasılığı eşittir. Yani bunların her birinin olma olasılığı 1/4'tür. Yani burada eşit sayıda yazı ve tura gelme ihtimali 1/4 + 1/4 = 1/2'dir. Parayı 3 defa veya herhangi bir tek sayı defa attığımızda yarı yarıya gelme ihtimali olmadığı için bu sefer 4 kez atalım. 2⁴ ‘ten 16 olası durumumuz var. Bunlar YYYY dan TTTT’ ya kadar gidiyor. Paraların yarısının Yazı yarısının Tura olduğu durum sayısı burada 6'dır. YYTT — TTYY — YTYT — TYTY — YTTY — TYYT olasılıkları var. Yani bu sefer de paraların yarısının Yazı yarısının Tura gelme olasılığı 6/16 = 0,375 ‘dir. Yarısının Yazı yarısının Tura gelme olasılığı düştü. Parayı eğer daha fazla defa atsaydık bu olasılık düşmeye devam edecekti. Ve bir noktada 0 olacaktı. Biz bu durumda paranın hileli olup olmadığını anlayamayacaktık. Yani bir paranın hileli olup olmadığını anlamak, bir sayının gerçekten random olup olmadığını anlamak imkansız. Bu durumda bizim yapmamız gereken, herhangi iki durumun çakışma olasılığını çok düşürmek. Yani seçtiğimiz iki sayının aynı olma ihtimalini 0’a çok yakın hale getirirsek bu sayıya random diyebiliriz. Bu yüzden private key’lerimizi 2²⁵⁶ kadar büyük bir alanda seçiyoruz. Bu yüzden gerçek olaylardan almaya çalışıyoruz çünkü aralık çok büyük, bir başkasının bulma olasılığı epey düşük.

RANDOMNESS’TAN PRIVATE’A

Non-Deterministic Wallet Her public key için bir private key’in olduğu cüzdanlardır. Her cüzdan için farklı random sayı üretilir, farklı private key kullanılır. Bu tür cüzdanlar aynı zamanda JBOK(Just A Bunch Of Keys) olarak da bilinir.

Deterministik Cüzdanlar tüm anahtarların bir master anahtar(seed) tarafından üretildiği cüzdanlardır. Üretilen bütün anahtarlarda eğer seed(random üretilen sayı) biliniyorsa diğer bütün anahtarlar tekrar üretilebilir. Bunları üretmek için farklı yöntemler vardır ancak en yaygın kullanılanı Hierarchical Deterministic Wallet’dır. Bu cüzdanları veri kayıplarına karşı daha güvenli yapmak için seed, kelimeler olarak tutulur.

Deterministik Cüzdanlar tek seed’den çok fazla anahtar üretmek için geliştirildi. Şu anda en gelişmiş türü BIP-32 ile tanımlanan Hierarchical Deterministic(HD)’dır.

Ancak bildiğimiz gibi her zaman 12 kelime olmuyor cüzdanlarımız. Aradaki fark Entropy(random üretilen sayının) daha uzun olması.

Checksum = Hash’i alınan verinin ilk kaç hanesinin random sayının sonuna ekleneceğidir. Yani 160 bitlik random sayımızı aldığımız zaman bunun Hash’inin ilk 5 hanesini bu 160'ın sonuna ekliyoruz ve 165 bitlik verimiz oluyor. Bunu 13 bitlik 15 parçaya ayırdığımızda da 15 kelimelik cüzdanımızı oluşturmuş oluyoruz.

Mnemonic kelimelerimizi de bulduğumuza göre artık seed değerini bulmaya geçebiliriz. Üretilen seed değeri, deterministik cüzdanlarda diğer anahtarları üretmek için kullanılır.

Seed’i üretmek için PBKDF2 key-stretching algotimasını kullanılır.

PRIVATE’DAN PUBLIC’E

Modüler Aritmetik

Modüler aritmetik, tamsayılarda kullanılan bir hesap yöntemidir. Saatin her on iki saatte bir yinelenmesi gibi modül denen belli bir değere gelindiğinde yeniden sıfıra dönülmesiyle olur. Kriptografi’de çok önemli bir yere sahiptir.

a, r, m ∈ Z ve m > 0 olsun. A ≡ r (mod m) eğer m | (a-r) sağlanıyorsa. Yani m değerimiz eğer (a-r) ifadesini bölüyorsa a ≡ r (mod m) olur. Burada m modül, r kalandır.

Örnek: a=42, m=5 ise r nedir?

42 = 4 * 9 + 6'dır. R=6 olur. Ama ben aynı zamanda 42 = 3*9 +15 de diyebilirdim bu durumda r = 15 olurdu.

Bu durumda birden fazla r değeri olduğunu söyleyebiliriz. Sağlamasını yapmak için de m | (a-r) sağlanıyor mu bakalım. 42–6 = 36'dır ve 9, 36'yı böler. Bu durumda mod işlemini doğru yaptık deriz.

Peki r’ı ifade etmenin, bulmanın daha kolay yolu var mı? Çünkü küçük sayılar için bu işlemler kolay gibi görünüyor ama sayılar büyüdüğünde bir sıkıntı olacaktır. Bu durumda denklik sınıflarını tanıtıyoruz.

{……… , -10,-5,0,5,10,………}

{……… , -9,-4,1,6,11,16,………}

{……… , -8,-3,2,7,12,………}

{……… , -7,-2,3,8,13,………}

{……… , -6,-1,4,9,14,………}

Modüler aritmetikte işlem yaparken herhangi bir denklik sınıfındaki bir eleman, aynı denklik sınıfındaki bir diğer elemanın yerine kullanılabilir. Yani demek istediğim 13*16–8 ≡ ?? (mod 5) bulmak istiyorsak 13,16 ve 8'i kullanmak yerine bulundukları kümelerdeki diğer elemanları, örneğin 13 ile aynı kümede bulunan 3'ü ben kullanmak istiyorum, kullanabilirim. 16 yerine 1'i ve 8 yerine 3'ü kullanıyorum ve eşitliğimiz 3*1–3 haline geliyor. 13*16–8'in mod5'de 0'a denk geldiğini buluyoruz. 13,16 ve 8 için belki yapmamıza gerek yoktu ama sayılar büyüdüğü zaman buna mecbur kalacaktık.

Elliptic Curve Cryptography

Elliptic curve cryptography, bir tür asimetrik kriptografidir.

Bir Elliptic Curve’ın görselleştirilmiş hali

y² (mod p) = x³+ 7 (mod p) (p = 2²⁵⁶ — 2³² — 2⁹ — 2⁸ — 2⁷ — 2⁶ — 2⁴ — 1, çok büyük bir asal sayı)

P eğer asal olmasaydı bazı durumlarda sonuçları bulamazdık. Örneğin 1 = 2^x mod14'ü bulmak istiyoruz. Böyle bir x değeri yoktur. Ama eğer 14 yerine asal bir sayı seçseydik her durumda 1 = a^x (mod n) denklemini sağlayabilirdik. Bu denklemi her x için sağlamamız her private-key için bir public key bulmamızda gereklidir. Eğer asal olmasaydı çoğunlukta yine işe yarardı ancak bazı durumlarda saçmalayabilirdi.

Mod p eğrinin sınırlı bir alanda tanımlı olduğunu gösterir. Eğer alanımız sınırsız olsaydı bizim hesaplamamız da zor olacaktı. En baştan eğriyi zor hesaplayacaktık.

Bu eğri reel sayılar yerine sınırlı bir alanda tanımlandığı için bir nokta deseni gibi gözüküyor.

Sınırlı alan’da tanımlanmış Elliptic Curve

Elliptic Curve Aritmetik İşlemleri

Elliptic curve’ler üzerindeki işlemler “normal” aritmetik gibi değildir. Elliptic curve’ler üzerindeki toplama işlemi sayı doğrusunda ilerlemek yerine elliptic curve üzerindeki noktalar üzerinde ilerler. Toplamayı tanımladıktan sonra zaten çarpma da toplamanın tekrar tekrar yapılması olduğundan çarpma işlemini de elde ederiz.

Elliptic curve üzerindeki toplama, P1 ve P2 elliptic curve üzerinde olmak üzere, P3 = P1 + P2'yi sağlayacak şekilde bir P3 olduğunu söyler. Geometrik olarak bu P3 noktası, P1 ve P2 arasında bir doğru çizerek hesaplanır. P1 ve P2 ‘den geçen bir doğru mutlaka elliptic curve üzerindeki bir P3 noktasından da geçecektir(Bezout teoremi). Doğrunun eğri ile kesiştiği 3. nokta P3’ = (x, y) olsun. P3 ‘ü bulmak için x ekseninde yansımasını alırız ve P3 = (x, –y) buluruz.

Elliptic curve’lerde aynı zamanda “point at infinity” denilen 0 ile toplamaya denk gelen bir nokta da vardır. Bilgisayarlarda bazen x = y = 0 olarak gösterilir(elliptic curve denklemini sağlamaz ama ayrı olarak kontrol edilebilecek bir durumdur). Bazı durumlarda( P1 ve P2'nin eşit x ama farklı y değerlerinin olduğu), doğru dikey olacaktır. Bu durumda P3 = point at infinity olur.

Eğer P1 point at infinity ise , P1 + P2 = P2, eğer P2 point at infinity ise P1 + P2 = P1 olur. Bu “normal” aritmetikte sıfır demektir.

Elliptic curve’lerde (A + B) + C = A + (B + C) eşitliği de sağlanır.

Toplamayı tanımladığımıza göre artık multiplication(çarpma)’yı tanımlayabiliriz.

Bildiğimiz gibi çarpma aslında tekrarlı toplamadır. Yani biz 5 * 5 dediğimiz zaman aslında 5 + 5 + 5 + 5 + 5'i kast ediyoruz. Elliptic curve’ler için de durum böyledir ancak toplama operatörünün sağlaması gereken kurallar yukarıda belirttiğimiz gibidir. Yani “normal” toplamadan farklıdır.

Örneğin eğer 5 * P1 ‘i hesaplamak istersek P1 + P1 + P1 + P1 + P1 ‘i hesaplamamız gerekir. 5 küçük bir sayı olduğu için bu işlem bize bir sorun yaratmaz ancak büyük sayılarla uğraşıyorsak tek tek yapmak sorun yaratacaktır. Onun yerine biz gruplama yaparız. Yani P1 + P1 ‘i hesaplarız. Bu işlemin sonucuna Q1 diyelim. P1 + P1 + P1 + P1 + P1 işlemi Q1 + Q1 + P1 ‘e dönüşür. Bu da bize işlem kolaylığı sağlar. Burada yaptığımız P1 + P1 işlemine Doubling, P1 + Q1 işlemine de addition(toplama) denir.

Public Key

Bir Ethereum Public-Key’i aslında Elliptic Curve üzerindeki(denklemi sağlayan) bir noktadır. Yani en basit anlatım ile Public-key aslında 2 sayının bir araya gelmesidir. Bu değer, private key’den elde edilen, tek yönlü bir hesaplamanın ürünüdür. Yani private key’i kullanarak public-key’e gitmek kolaydır ama tersi mümkün değildir.

Public key, yukarıda bahsettiğim elliptic curve multiplication ile elde edilir. K = k * G, k private key, G generator point denilen bir sabit nokta, K da public key’dir. Burada hesapladığımız K, x ve y koordinatlarından oluşur. Finalde sonucumuza ulaşmak için x ve y koordinatlarını yanyana yazarız. Yani x = 51, y=41 ise 5141 şeklinde oluşturuyoruz(sayılar tabii ki çok daha uzundur, buradaki basit bir örnek). Bu işlemi de yaptıktan sonra sonucumuzu Keccak256 ile hash’liyoruz. En son olarak da bu sonucun son 20 basamağını tutup, geri kalanını siliyoruz. Bu 20 basamağın başına da Hexadecimal olduğunu belirmek için 0x ekliyor ve süreci sonlandırıyoruz.

Sürecin kısa özeti

Kaynaklar : Mastering Ethereum, https://www.random.org/ , https://www.royalfork.org/2017/12/10/eth-graphical-address/

--

--