私鑰
私鑰就是一組隨機(jī)獲取的數(shù)字。
私鑰用來(lái)生成數(shù)字簽名,在交易中用于證明對(duì)以太幣的所有權(quán)。私鑰必須嚴(yán)格保密,也必須妥善保存,私鑰丟失的話是無(wú)法找回的。
通過(guò)隨機(jī)數(shù)生成私鑰
私鑰的生成就是在1到2256之間選擇數(shù)字,更準(zhǔn)確地說(shuō),以太坊私鑰可以是任何比2256略微小一點(diǎn)的正整數(shù),2256是一個(gè)77位的十進(jìn)制數(shù)字,接近于1.158×1077。私鑰的數(shù)字與2256的前38位相同,這被定義為以太坊橢圓曲線的階(詳見(jiàn)后面的橢圓密碼學(xué)的基本概念)。要生成私鑰,我們隨機(jī)取出一個(gè)256比特的數(shù)字,然后檢查它是否在有效范圍內(nèi)。用編程術(shù)語(yǔ)來(lái)說(shuō),其實(shí)現(xiàn)方式是:將一個(gè)(從密碼學(xué)意義上安全的熵源中得出的)很大的隨機(jī)字符串放入256比特的哈希算法(詳見(jiàn)后面的密碼學(xué)的哈希算法)中,比如Keccak-256或者SHA256,這兩種算法會(huì)便捷地產(chǎn)生一個(gè)256比特的數(shù)字。如果這個(gè)結(jié)果在有效范圍內(nèi),我們就有了一個(gè)合適的私鑰。否則,我們就要用另一個(gè)隨機(jī)數(shù)字再試一次。
privatekey = SHA256/Keccak-256("很大的隨機(jī)字符串")
以太坊私鑰數(shù)字區(qū)間大小為2256,這是一個(gè)大到無(wú)法言喻的數(shù)字。這個(gè)數(shù)字在十進(jìn)制中幾乎是1077,當(dāng)你隨機(jī)地選擇了一個(gè)私鑰后,幾乎不可能會(huì)有另一個(gè)人猜到,或者選中同一個(gè)。
需要注意的是,私鑰的生成是離線的,不會(huì)和網(wǎng)絡(luò)或者任何人交互。密碼學(xué)的隨機(jī)數(shù)生成使用熵源充足的隨機(jī)源做種子,可以保證兩次選擇的隨機(jī)數(shù)不重復(fù),既不可能被別人猜到。
下面就是一個(gè)隨機(jī)生成的私鑰,以十六進(jìn)制表示(“256個(gè)二進(jìn)制位,顯示為64個(gè)十六進(jìn)制數(shù),每個(gè)代表4比特)。
f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315
公鑰
每個(gè)以太坊公鑰都是橢圓曲線上的一個(gè)點(diǎn),也就是說(shuō),每個(gè)公鑰都是一組x、y坐標(biāo),這個(gè)坐標(biāo)正好滿足橢圓曲線方程。
公鑰是通過(guò)對(duì)私鑰使用橢圓曲線的乘法運(yùn)算得來(lái)的,而這個(gè)乘法運(yùn)算基本上是不可逆的:K=kG,其中k是私鑰,G是一個(gè)常量點(diǎn),稱為生成點(diǎn),K是計(jì)算得來(lái)的公鑰,是橢圓曲線函數(shù)的乘法運(yùn)算符號(hào)。這與普通乘法運(yùn)算的規(guī)則是不同的,除了與普通乘法有相同的功能屬性,其他都不一樣。舉個(gè)例子,反向運(yùn)算(普通乘法的反向運(yùn)算就是除法),也稱為獲取“離散對(duì)數(shù)”的計(jì)算,即在已知K的情況下求解k,是非常困難的,必須采用暴力窮舉的方式嘗試所有可能的k。
也就是說(shuō),橢圓曲線之上的算術(shù)運(yùn)算跟常規(guī)的數(shù)學(xué)運(yùn)算是不一樣的。一個(gè)點(diǎn)(G)可以與一個(gè)整數(shù)(k)相乘來(lái)獲得另外一個(gè)點(diǎn)(K)。但是橢圓曲線的世界里沒(méi)有除法的概念。因此不可能簡(jiǎn)單地通過(guò)計(jì)算公鑰K對(duì)G點(diǎn)的除法來(lái)計(jì)算私鑰。
橢圓曲線乘法是“單向”函數(shù):它很容易從一個(gè)方向(乘法)進(jìn)行計(jì)算,但是不可能采用反向(除法)的方式計(jì)算。
私鑰的持有者很容易算出公鑰,然后把公鑰公開(kāi),因?yàn)樗_信沒(méi)有人可以通過(guò)這個(gè)公鑰反向推算出私鑰。這個(gè)神奇的數(shù)學(xué)算“法造就了不可篡改和安全的數(shù)字簽名,用來(lái)證明以太幣的所有權(quán),以及對(duì)合約進(jìn)行控制。
在演示如何從私鑰生成公鑰之前,我們來(lái)看看橢圓曲線的細(xì)節(jié)。
橢圓曲線密碼學(xué)的基本概念
橢圓曲線密碼學(xué)是基于離散對(duì)數(shù)問(wèn)題的非對(duì)稱密碼學(xué)(也稱為公鑰密碼學(xué)),它是基于橢圓曲線上點(diǎn)位的加法和乘法的不可逆特性。
圖2是一個(gè)橢圓曲線的例子,與以太坊協(xié)議使用的類似。”

圖2.橢圓曲線函數(shù)圖像示
以太坊使用跟比特幣系統(tǒng)相同的橢圓曲線算法,稱為secp256k1。
這樣以太坊就可以直接使用比特幣系統(tǒng)中的大量橢圓曲線函數(shù)庫(kù)和相關(guān)的開(kāi)發(fā)工具。
以太坊使用一條特定的橢圓曲線和一組數(shù)學(xué)常量,這是一個(gè)被稱為secp256k1的標(biāo)準(zhǔn),由NIST設(shè)定。secp256k1曲線由下列函數(shù)定義,這些函數(shù)生成了橢圓曲線:
或
mod p(素?cái)?shù)的模)表示曲線位于素?cái)?shù)階p的有限域中,這也可以表示為Fp,其中的p=2256–232–29–28–27–26–24–1是一個(gè)非常大的素?cái)?shù)。
曲線的定義位于素?cái)?shù)階p的有限域中,而不是我們常見(jiàn)的實(shí)數(shù)空間。這個(gè)曲線的模式就像是散布在兩個(gè)維度上的一組點(diǎn),這是很難圖形化表示的。然而,對(duì)于位于實(shí)數(shù)域的橢圓曲線,對(duì)應(yīng)的算法也是一樣的。例如,圖3展示了同樣一個(gè)位于有限域的橢圓曲線,但是它的素?cái)?shù)階(17)要小得多,顯示為一個(gè)網(wǎng)格中的一系列點(diǎn)。橢圓曲線使用的secp256k1可以被認(rèn)為是比這個(gè)復(fù)雜得多的模式,散布在一個(gè)巨大無(wú)比的網(wǎng)格之中。
圖3.橢圓曲線密碼學(xué):橢圓曲線F(p),且p=17
例如,下面的Q點(diǎn)對(duì)應(yīng)的(x,y)坐標(biāo)是secp256k1曲線上的一個(gè)點(diǎn)位:
Q =
(49790390825249384486033144355916864607616083520101638681403973749255924539515,59574132161899900045862086493921015780032175291755807399284007721050341297360)
代碼1演示了如何使用Python編程來(lái)檢驗(yàn)這個(gè)點(diǎn)是否位于橢圓曲線上。變量x和y是Q點(diǎn)的坐標(biāo)。變量p是橢圓曲線的素?cái)?shù)階(這個(gè)素?cái)?shù)用來(lái)進(jìn)行所有的求模計(jì)算)。Python代碼的最后一行是橢圓曲線的等式(%運(yùn)算符在Python中代表求模運(yùn)算)。如果x和y的確是橢圓曲線上的點(diǎn),那么它們就會(huì)滿足方程,并且運(yùn)算的結(jié)果是零(0L是一個(gè)零值長(zhǎng)整數(shù))。你可以自己編程嘗試,通過(guò)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:通過(guò)Python檢驗(yàn)這個(gè)點(diǎn)是否位于橢圓曲線上
橢圓曲線上的運(yùn)算
橢圓曲線的加法是兩個(gè)點(diǎn)的相加
橢圓曲線上的很多數(shù)學(xué)運(yùn)算看上去跟我們?cè)趯W(xué)校學(xué)習(xí)的整數(shù)世界的數(shù)學(xué)運(yùn)算類似。特別是,我們可以定義一個(gè)加法運(yùn)算符,它并不是做數(shù)字之間的加法,而是把曲線上的兩個(gè)點(diǎn)相加。有了加法運(yùn)算符以后,我們還可以定義乘法運(yùn)算符,用來(lái)在一個(gè)點(diǎn)和一個(gè)整數(shù)之間進(jìn)行乘法運(yùn)算,類似于重復(fù)進(jìn)行加法運(yùn)算。
橢圓曲線上加法運(yùn)算的定義就是給定橢圓曲線上的兩個(gè)點(diǎn)P1和P2,橢圓曲線上存在第三個(gè)點(diǎn),滿足P3=P1+P2。
從幾何學(xué)的意義上來(lái)說(shuō),第三個(gè)點(diǎn)的計(jì)算其實(shí)是在P1和P2之間畫一條線。這條線會(huì)與橢圓曲線存在唯一的相交點(diǎn)(超神奇),這個(gè)點(diǎn)稱為P3'=(x,y),對(duì)應(yīng)著在x軸我們就可以得到P3=(x,-y)。
如果P1和P2是同一點(diǎn),那么P1和P2之間的這條線就應(yīng)該是橢圓曲線上P1(P2)點(diǎn)的切線。這條切線會(huì)跟橢圓曲線存在唯一的相交點(diǎn)。你可以通過(guò)微積分的方式來(lái)確定這條切線的斜率。這樣的計(jì)算是真的可以產(chǎn)出結(jié)果的,即使我們只有曲線上的兩個(gè)坐標(biāo),仍舊可以算出對(duì)應(yīng)的切線斜率。
橢圓曲線的無(wú)限遠(yuǎn)點(diǎn)在加法中的作用和我們平時(shí)所用加法中的0類似
在橢圓曲線的數(shù)學(xué)運(yùn)算中,存在一個(gè)“無(wú)限遠(yuǎn)點(diǎn)”,這個(gè)點(diǎn)類似常規(guī)數(shù)學(xué)中的零。在計(jì)算機(jī)中,它有時(shí)被表述為x=y=0(這并不滿足橢圓曲線的方程,但這是一個(gè)很容易驗(yàn)證的例子)。有一些特殊的案例可以用來(lái)解釋為什么我們需要這個(gè)無(wú)限遠(yuǎn)點(diǎn)。
在一些情況下(比如P1和P2有相同的x值,卻有不同的y值),那么兩點(diǎn)的連線就是一條垂直的直線,這樣的情況下,P3就是無(wú)限遠(yuǎn)點(diǎn)。
如果P1是無(wú)限遠(yuǎn)點(diǎn),那么P1+P2=P2。同樣,如果P2是無(wú)限遠(yuǎn)點(diǎn),那么P1+P2=P1。這個(gè)例子展示了“無(wú)限遠(yuǎn)點(diǎn)”如何扮演著普通數(shù)學(xué)中零的作用。
這意味著,加法是滿足結(jié)合律的,也就是說(shuō)(A+B)+C=A+(B+C)。這意味著我們可以直接寫A+B+C,即使不用圓括號(hào),也不會(huì)產(chǎn)生運(yùn)算上的歧義。
我們已經(jīng)定義了加法,現(xiàn)在可以借此延伸出乘法的定義。對(duì)于橢圓曲線上的P點(diǎn),如果k是一個(gè)整數(shù),那么k*P=P+P+P+…+P(相加k次)。注意,有時(shí)候k會(huì)被稱為“指數(shù)”,這比較容易令人混淆。
生成公鑰
我們從隨機(jī)得來(lái)的私鑰k開(kāi)始,使用橢圓曲線上預(yù)先定義好的名為生成點(diǎn)的G點(diǎn)來(lái)產(chǎn)生另一個(gè)位于橢圓曲線上的點(diǎn),這就是對(duì)應(yīng)的公鑰K。
K=k*G
生成點(diǎn)由secp256k1橢圓曲線標(biāo)準(zhǔn)定義,在所有的secp256k1實(shí)現(xiàn)中,這個(gè)點(diǎn)保持不變,所有從這個(gè)曲線產(chǎn)生的公鑰都是經(jīng)過(guò)相同的生成點(diǎn)計(jì)算而來(lái)的。因?yàn)閷?duì)于所有的以太坊用戶而言,生成點(diǎn)始終保持不變,所以使用一個(gè)私鑰k與生成點(diǎn)G計(jì)算之后,總是會(huì)得出相同的公鑰K。k和K之間的關(guān)系是固定的,但是只能從一個(gè)方向進(jìn)行計(jì)算,也就是通過(guò)k算出K。這也是為什么一個(gè)以太坊地址(從公鑰K而來(lái))可以被公開(kāi)分享,而不用擔(dān)心對(duì)應(yīng)的私鑰(k)可能會(huì)被人反向算出。
如同我們?cè)谏弦还?jié)中提到的,k*G的乘法運(yùn)算相當(dāng)于是重復(fù)多次的加法運(yùn)算,也就是G+G+G+…+G,重復(fù)k次。概括而言,為了從私鑰k計(jì)算出公鑰K,我們需要把生成點(diǎn)G反復(fù)相加k次。
通過(guò)私鑰可以推算出公鑰,但是通過(guò)公鑰無(wú)法反向計(jì)算得出私鑰,因?yàn)檫@個(gè)數(shù)學(xué)算法是單向的。
現(xiàn)在,讓我們把這項(xiàng)計(jì)算用在之前“私鑰”一節(jié)中生成的那個(gè)私鑰,并通過(guò)這個(gè)私鑰來(lái)計(jì)算得出公鑰:
K = f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315 * G
一些密碼學(xué)類庫(kù)可以幫助我們使用橢圓曲線加法來(lái)計(jì)算K。計(jì)算所得的公鑰K定義為一個(gè)點(diǎn):
K=(x,y)
其中:
x = 6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b
y = 83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0
在以太坊協(xié)議中,你可能會(huì)看到采用130個(gè)十六進(jìn)制字符(65字節(jié))表示的公鑰。這是由SECG所發(fā)布的行業(yè)標(biāo)準(zhǔn)的一種序列化編碼方式,在高效密碼學(xué)標(biāo)準(zhǔn)(SECI)中有文獻(xiàn)記載(http://www.secg.org/sec1-v2.pdf)這個(gè)標(biāo)準(zhǔn)定義了四種可能的前綴用來(lái)標(biāo)示橢圓曲線上的點(diǎn)位,見(jiàn)表1。
表1:序列化EC公鑰前綴
| 前綴 | 含義 | 長(zhǎng)度(以字節(jié)記) |
|---|---|---|
| 0x00 | 無(wú)窮遠(yuǎn)點(diǎn) | 1 |
| 0x04 | 未壓縮點(diǎn) | 65 |
| 0x01 | 偶數(shù)y壓縮的點(diǎn) | 33 |
| 0x03 | 奇數(shù)y壓縮的點(diǎn) | 33 |
以太坊只使用未壓縮的公鑰,因此唯一相關(guān)的前綴就是0x04。包括x和y坐標(biāo)的公鑰經(jīng)過(guò)編碼后的形態(tài)如下:
04 + x-coordinate (32 bytes/64 hex) + y-coordinate (32 bytes/64 hex)
因此,我們?cè)谏衔挠?jì)算得出的公鑰,經(jīng)過(guò)編碼后的形態(tài)為:
046e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0 \
c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0
