私鑰
私鑰就是一組隨機獲取的數(shù)字厕妖。
私鑰用來生成數(shù)字簽名答憔,在交易中用于證明對以太幣的所有權(quán)且改。私鑰必須嚴格保密,也必須妥善保存怜跑,私鑰丟失的話是無法找回的。
通過隨機數(shù)生成私鑰
私鑰的生成就是在1到2256之間選擇數(shù)字吠勘,更準確地說性芬,以太坊私鑰可以是任何比2256略微小一點的正整數(shù),2256是一個77位的十進制數(shù)字剧防,接近于1.158×1077植锉。私鑰的數(shù)字與2256的前38位相同,這被定義為以太坊橢圓曲線的階(詳見后面的橢圓密碼學(xué)的基本概念)峭拘。要生成私鑰俊庇,我們隨機取出一個256比特的數(shù)字,然后檢查它是否在有效范圍內(nèi)鸡挠。用編程術(shù)語來說辉饱,其實現(xiàn)方式是:將一個(從密碼學(xué)意義上安全的熵源中得出的)很大的隨機字符串放入256比特的哈希算法(詳見后面的密碼學(xué)的哈希算法)中,比如Keccak-256或者SHA256拣展,這兩種算法會便捷地產(chǎn)生一個256比特的數(shù)字彭沼。如果這個結(jié)果在有效范圍內(nèi),我們就有了一個合適的私鑰备埃。否則姓惑,我們就要用另一個隨機數(shù)字再試一次褐奴。
privatekey = SHA256/Keccak-256("很大的隨機字符串")
以太坊私鑰數(shù)字區(qū)間大小為2256,這是一個大到無法言喻的數(shù)字挺益。這個數(shù)字在十進制中幾乎是1077歉糜,當(dāng)你隨機地選擇了一個私鑰后,幾乎不可能會有另一個人猜到望众,或者選中同一個匪补。
需要注意的是,私鑰的生成是離線的烂翰,不會和網(wǎng)絡(luò)或者任何人交互夯缺。密碼學(xué)的隨機數(shù)生成使用熵源充足的隨機源做種子,可以保證兩次選擇的隨機數(shù)不重復(fù)甘耿,既不可能被別人猜到踊兜。
下面就是一個隨機生成的私鑰,以十六進制表示(“256個二進制位佳恬,顯示為64個十六進制數(shù)捏境,每個代表4比特)。
f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315
公鑰
每個以太坊公鑰都是橢圓曲線上的一個點毁葱,也就是說垫言,每個公鑰都是一組x、y坐標(biāo)倾剿,這個坐標(biāo)正好滿足橢圓曲線方程筷频。
公鑰是通過對私鑰使用橢圓曲線的乘法運算得來的,而這個乘法運算基本上是不可逆的:K=kG前痘,其中k是私鑰凛捏,G是一個常量點,稱為生成點芹缔,K是計算得來的公鑰坯癣,是橢圓曲線函數(shù)的乘法運算符號。這與普通乘法運算的規(guī)則是不同的乖菱,除了與普通乘法有相同的功能屬性坡锡,其他都不一樣。舉個例子窒所,反向運算(普通乘法的反向運算就是除法)鹉勒,也稱為獲取“離散對數(shù)”的計算,即在已知K的情況下求解k吵取,是非常困難的禽额,必須采用暴力窮舉的方式嘗試所有可能的k。
也就是說,橢圓曲線之上的算術(shù)運算跟常規(guī)的數(shù)學(xué)運算是不一樣的脯倒。一個點(G)可以與一個整數(shù)(k)相乘來獲得另外一個點(K)实辑。但是橢圓曲線的世界里沒有除法的概念。因此不可能簡單地通過計算公鑰K對G點的除法來計算私鑰藻丢。
橢圓曲線乘法是“單向”函數(shù):它很容易從一個方向(乘法)進行計算剪撬,但是不可能采用反向(除法)的方式計算。
私鑰的持有者很容易算出公鑰悠反,然后把公鑰公開残黑,因為他確信沒有人可以通過這個公鑰反向推算出私鑰。這個神奇的數(shù)學(xué)算“法造就了不可篡改和安全的數(shù)字簽名斋否,用來證明以太幣的所有權(quán)梨水,以及對合約進行控制。
在演示如何從私鑰生成公鑰之前茵臭,我們來看看橢圓曲線的細節(jié)疫诽。
橢圓曲線密碼學(xué)的基本概念
橢圓曲線密碼學(xué)是基于離散對數(shù)問題的非對稱密碼學(xué)(也稱為公鑰密碼學(xué)),它是基于橢圓曲線上點位的加法和乘法的不可逆特性旦委。
圖2是一個橢圓曲線的例子奇徒,與以太坊協(xié)議使用的類似∮酰”
圖2.橢圓曲線函數(shù)圖像示
以太坊使用跟比特幣系統(tǒng)相同的橢圓曲線算法逼龟,稱為secp256k1。
這樣以太坊就可以直接使用比特幣系統(tǒng)中的大量橢圓曲線函數(shù)庫和相關(guān)的開發(fā)工具追葡。
以太坊使用一條特定的橢圓曲線和一組數(shù)學(xué)常量,這是一個被稱為secp256k1的標(biāo)準奕短,由NIST設(shè)定宜肉。secp256k1曲線由下列函數(shù)定義,這些函數(shù)生成了橢圓曲線:
或
mod p(素數(shù)的模)表示曲線位于素數(shù)階p的有限域中翎碑,這也可以表示為Fp谬返,其中的p=2256–232–29–28–27–26–24–1是一個非常大的素數(shù)。
曲線的定義位于素數(shù)階p的有限域中日杈,而不是我們常見的實數(shù)空間遣铝。這個曲線的模式就像是散布在兩個維度上的一組點,這是很難圖形化表示的莉擒。然而酿炸,對于位于實數(shù)域的橢圓曲線,對應(yīng)的算法也是一樣的涨冀。例如填硕,圖3展示了同樣一個位于有限域的橢圓曲線,但是它的素數(shù)階(17)要小得多,顯示為一個網(wǎng)格中的一系列點扁眯。橢圓曲線使用的secp256k1可以被認為是比這個復(fù)雜得多的模式壮莹,散布在一個巨大無比的網(wǎng)格之中。
圖3.橢圓曲線密碼學(xué):橢圓曲線F(p)姻檀,且p=17
例如命满,下面的Q點對應(yīng)的(x,y)坐標(biāo)是secp256k1曲線上的一個點位:
Q =
(49790390825249384486033144355916864607616083520101638681403973749255924539515,59574132161899900045862086493921015780032175291755807399284007721050341297360)
代碼1演示了如何使用Python編程來檢驗這個點是否位于橢圓曲線上绣版。變量x和y是Q點的坐標(biāo)胶台。變量p是橢圓曲線的素數(shù)階(這個素數(shù)用來進行所有的求模計算)。Python代碼的最后一行是橢圓曲線的等式(%運算符在Python中代表求模運算)僵娃。如果x和y的確是橢圓曲線上的點概作,那么它們就會滿足方程,并且運算的結(jié)果是零(0L是一個零值長整數(shù))默怨。你可以自己編程嘗試讯榕,通過Python的IDE,把下面的代碼復(fù)制到>>>提示符之后:
Python 3.4.0 (default, Mar 30 2014, 19:23:13)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> p = 115792089237316195423570985008687907853269984665640564039457584007908834 \
671663
>>> x = 49790390825249384486033144355916864607616083520101638681403973749255924539515
>>> y = 59574132161899900045862086493921015780032175291755807399284007721050341297360
>>> (x ** 3 + 7 - y**2) % p
0L
代碼1:通過Python檢驗這個點是否位于橢圓曲線上
橢圓曲線上的運算
橢圓曲線的加法是兩個點的相加
橢圓曲線上的很多數(shù)學(xué)運算看上去跟我們在學(xué)校學(xué)習(xí)的整數(shù)世界的數(shù)學(xué)運算類似匙睹。特別是愚屁,我們可以定義一個加法運算符,它并不是做數(shù)字之間的加法痕檬,而是把曲線上的兩個點相加霎槐。有了加法運算符以后,我們還可以定義乘法運算符梦谜,用來在一個點和一個整數(shù)之間進行乘法運算丘跌,類似于重復(fù)進行加法運算。
橢圓曲線上加法運算的定義就是給定橢圓曲線上的兩個點P1和P2唁桩,橢圓曲線上存在第三個點闭树,滿足P3=P1+P2。
從幾何學(xué)的意義上來說荒澡,第三個點的計算其實是在P1和P2之間畫一條線报辱。這條線會與橢圓曲線存在唯一的相交點(超神奇),這個點稱為P3'=(x,y)单山,對應(yīng)著在x軸我們就可以得到P3=(x,-y)碍现。
如果P1和P2是同一點,那么P1和P2之間的這條線就應(yīng)該是橢圓曲線上P1(P2)點的切線米奸。這條切線會跟橢圓曲線存在唯一的相交點昼接。你可以通過微積分的方式來確定這條切線的斜率。這樣的計算是真的可以產(chǎn)出結(jié)果的悴晰,即使我們只有曲線上的兩個坐標(biāo)辩棒,仍舊可以算出對應(yīng)的切線斜率。
橢圓曲線的無限遠點在加法中的作用和我們平時所用加法中的0類似
在橢圓曲線的數(shù)學(xué)運算中,存在一個“無限遠點”一睁,這個點類似常規(guī)數(shù)學(xué)中的零钻弄。在計算機中,它有時被表述為x=y=0(這并不滿足橢圓曲線的方程者吁,但這是一個很容易驗證的例子)窘俺。有一些特殊的案例可以用來解釋為什么我們需要這個無限遠點。
在一些情況下(比如P1和P2有相同的x值复凳,卻有不同的y值)瘤泪,那么兩點的連線就是一條垂直的直線,這樣的情況下育八,P3就是無限遠點对途。
如果P1是無限遠點,那么P1+P2=P2髓棋。同樣实檀,如果P2是無限遠點,那么P1+P2=P1按声。這個例子展示了“無限遠點”如何扮演著普通數(shù)學(xué)中零的作用膳犹。
這意味著,加法是滿足結(jié)合律的签则,也就是說(A+B)+C=A+(B+C)须床。這意味著我們可以直接寫A+B+C,即使不用圓括號渐裂,也不會產(chǎn)生運算上的歧義豺旬。
我們已經(jīng)定義了加法,現(xiàn)在可以借此延伸出乘法的定義柒凉。對于橢圓曲線上的P點哈垢,如果k是一個整數(shù),那么k*P=P+P+P+…+P(相加k次)扛拨。注意,有時候k會被稱為“指數(shù)”举塔,這比較容易令人混淆绑警。
生成公鑰
我們從隨機得來的私鑰k開始,使用橢圓曲線上預(yù)先定義好的名為生成點的G點來產(chǎn)生另一個位于橢圓曲線上的點央渣,這就是對應(yīng)的公鑰K计盒。
K=k*G
生成點由secp256k1橢圓曲線標(biāo)準定義,在所有的secp256k1實現(xiàn)中芽丹,這個點保持不變北启,所有從這個曲線產(chǎn)生的公鑰都是經(jīng)過相同的生成點計算而來的。因為對于所有的以太坊用戶而言,生成點始終保持不變咕村,所以使用一個私鑰k與生成點G計算之后场钉,總是會得出相同的公鑰K。k和K之間的關(guān)系是固定的懈涛,但是只能從一個方向進行計算逛万,也就是通過k算出K。這也是為什么一個以太坊地址(從公鑰K而來)可以被公開分享批钠,而不用擔(dān)心對應(yīng)的私鑰(k)可能會被人反向算出宇植。
如同我們在上一節(jié)中提到的,k*G的乘法運算相當(dāng)于是重復(fù)多次的加法運算埋心,也就是G+G+G+…+G指郁,重復(fù)k次。概括而言拷呆,為了從私鑰k計算出公鑰K闲坎,我們需要把生成點G反復(fù)相加k次。
通過私鑰可以推算出公鑰洋腮,但是通過公鑰無法反向計算得出私鑰箫柳,因為這個數(shù)學(xué)算法是單向的。
現(xiàn)在啥供,讓我們把這項計算用在之前“私鑰”一節(jié)中生成的那個私鑰悯恍,并通過這個私鑰來計算得出公鑰:
K = f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315 * G
一些密碼學(xué)類庫可以幫助我們使用橢圓曲線加法來計算K。計算所得的公鑰K定義為一個點:
K=(x,y)
其中:
x = 6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b
y = 83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0
在以太坊協(xié)議中伙狐,你可能會看到采用130個十六進制字符(65字節(jié))表示的公鑰涮毫。這是由SECG所發(fā)布的行業(yè)標(biāo)準的一種序列化編碼方式,在高效密碼學(xué)標(biāo)準(SECI)中有文獻記載(http://www.secg.org/sec1-v2.pdf)這個標(biāo)準定義了四種可能的前綴用來標(biāo)示橢圓曲線上的點位贷屎,見表1罢防。
表1:序列化EC公鑰前綴
前綴 | 含義 | 長度(以字節(jié)記) |
---|---|---|
0x00 | 無窮遠點 | 1 |
0x04 | 未壓縮點 | 65 |
0x01 | 偶數(shù)y壓縮的點 | 33 |
0x03 | 奇數(shù)y壓縮的點 | 33 |
以太坊只使用未壓縮的公鑰,因此唯一相關(guān)的前綴就是0x04唉侄。包括x和y坐標(biāo)的公鑰經(jīng)過編碼后的形態(tài)如下:
04 + x-coordinate (32 bytes/64 hex) + y-coordinate (32 bytes/64 hex)
因此咒吐,我們在上文計算得出的公鑰,經(jīng)過編碼后的形態(tài)為:
046e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0 \
c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0