原理
以太坊數(shù)字簽名和比特幣的關(guān)系
以太坊數(shù)字簽名,幾乎完全沿用了比特幣的數(shù)字簽名算法ECDSA-secp256k1。只有哈希的生成方式不一樣嫁乘,這個之后會說疆柔。ECDSA-secp256k1是一種非對稱加密算法。
什么是ECDSA
以太坊數(shù)字簽名算法使用的是橢圓曲線數(shù)字簽名算法刁俭,英文簡稱ECDSA。其中EC是“橢圓曲線”的簡稱,DSA是“數(shù)字簽名算法”的簡稱宛渐。
什么是secp256k1
橢圓曲線算法簡單的說就是用X和Y坐標(biāo)畫一個曲線。這個曲線怎么畫眯搭,需要很多個參數(shù)來確定窥翩。以太坊使用了一套叫secp256k1的參數(shù)確定了橢圓的形狀。所以鳞仙,以太坊的簽名算法全稱就是是ECDSA-secp256k1寇蚊。
什么是非對稱加密
什么是對稱加密,什么是非對稱加密呢棍好?簡單的說仗岸,只有一個密鑰的,就是對稱加密借笙,加密解密用它扒怖。有兩個密鑰的,就是非對稱加密业稼,加密用一個密鑰盗痒,解密用另外一個。相對于對稱加密算法而言低散,非對稱加密優(yōu)點(diǎn)是不需要在網(wǎng)絡(luò)上暴露加密的密鑰俯邓,從機(jī)制上來說更安全;缺點(diǎn)是加密效率比對稱加密低很多谦纱。所以非對稱加密一般只用于諸如數(shù)字簽名這類數(shù)據(jù)量較小的加密運(yùn)算看成。
常見的非對稱加密算法除了橢圓加密算法之外,還有著名的RSA跨嘉。橢圓加密相比RSA的區(qū)別是:
- 橢圓加密的密鑰更短
- 橢圓加密計算更快而安全性相當(dāng)
- RSA的私鑰和公鑰是何以互換加解密的川慌,但橢圓加密只能私鑰加密公鑰解密吃嘿。
私鑰
以太坊的私鑰是一個32字節(jié)的數(shù),取值范圍從1~0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140梦重。這個數(shù)可以由偽隨機(jī)算法(PRNG)產(chǎn)生兑燥。其實0也是一個合法的私鑰,只不過這是一個特殊私鑰琴拧,以太坊的創(chuàng)世區(qū)塊就是這個私鑰生成的降瞳。
公鑰
以太坊的非壓縮公鑰是一個65字節(jié)的數(shù),這個是繼承至比特幣的蚓胸。但以太坊只使用了其中64個字節(jié)挣饥,有一個字節(jié)這64個字節(jié)中,32字節(jié)表示橢圓曲線的X坐標(biāo)沛膳,32字節(jié)表示橢圓曲線的Y坐標(biāo)扔枫。這個XY坐標(biāo)是私鑰通過ECDSA-secp256k1推導(dǎo)出來的。所以說锹安,橢圓曲線算法的公鑰是通過私鑰計算出來的短荐。而反過來,用公鑰推導(dǎo)私鑰叹哭,以現(xiàn)有計算機(jī)的計算幾乎是不可能的忍宋,這也是以太坊和比特幣存在的基礎(chǔ)。如果哪天計算機(jī)技術(shù)出現(xiàn)大飛躍风罩,比如量子計算機(jī)普及糠排,現(xiàn)有鏈上所有賬戶的私鑰都會曝光。當(dāng)然超升,區(qū)塊鏈技術(shù)本身也會一定會持續(xù)演進(jìn)的乳讥。
哈希
哈希,也可以形象的叫做“摘要”廓俭。就是無論消息有多大,都可以生成一個固定長度的“摘要”唉工,這個“摘要”可以用來校驗消息是否被篡改研乒。只要消息被修改了一個字節(jié),“摘要”的校驗就會失敗淋硝。
比特幣的哈希算法使用的是SHA2-256雹熬。相對于SHA1,SHA2只是擴(kuò)展了哈希的字節(jié)數(shù)而已谣膳。目前SHA1已經(jīng)被攻破竿报,SHA2被攻破只是時間問題。
以太坊的哈希算法采用的是全新的SHA3-256继谚。和SHA1烈菌,SHA2不一樣,SHA3并不是單純擴(kuò)展字節(jié)數(shù),而是采用了新的Keccak算法芽世。同樣字節(jié)寬度的SHA3比SHA2更安全挚赊。
地址
以太坊的地址是公鑰經(jīng)過一系列哈希和變換,在經(jīng)由Base58編碼生成的字符串济瓢。過程不述荠割。Base58編碼和Base64差不多,都是使用“”可讀符號“來表示二進(jìn)制數(shù)據(jù)旺矾,Base58相對Base64移除了一些容易產(chǎn)生視覺混淆的字母和數(shù)字蔑鹦。
簽名
簽名其實就是用私鑰對消息的哈希進(jìn)行加密。當(dāng)一個以太坊節(jié)點(diǎn)向另一個節(jié)點(diǎn)發(fā)送消息時箕宙,會用自己的私鑰將消息的哈希做簽名嚎朽,然后吧簽名和消息本身發(fā)送給對方。
過程如圖:
校驗簽名
節(jié)點(diǎn)收到對方發(fā)來的消息和簽名后扒吁,會先做一個“recover”的動作火鼻,用消息和簽名推導(dǎo)出對方的公鑰。再通過公鑰雕崩,簽名魁索,消息的哈希值計算出一個叫“r”的值,這個r是簽名的一部分盼铁,校驗簽名就是拿計算出來的r和簽名中攜帶的r經(jīng)行對比粗蔚,如果一致就校驗通過。
過程如圖:
代碼實現(xiàn)
以太坊項目geth有兩套ECDSA-secp256p1的實現(xiàn)饶火。一套是純go的鹏控,一套是基于C庫的。底層算法都不是以太坊開發(fā)人員寫的肤寝,采用的是開源世界的拿來主義当辐。
go實現(xiàn)
接口源碼在crypto/signature_nocgo.go。這個文件只是一個wrapper鲤看,真實的實現(xiàn)調(diào)用了一個第三方的比特幣的go項目缘揪,源碼在vendor//github.com/bitcsuite/bitcd。
C實現(xiàn)
接口源碼在crypto/signature_cgo.go义桂。這也是一個wrapper找筝,再往下調(diào)用的是crypto/secp256k1/。這個還是wrapper慷吊,再往下是比特幣C語言項目的libsecp256k1庫袖裕。
API及其功能
signature_nocgo.go和signature_cgo.go的接口是一樣的,具體如下:
//通過消息的哈希和簽名恢復(fù)公鑰
func Ecrecover(hash, sig []byte) ([]byte, error) {}
//通過哈希和私鑰計算ECDSA簽名
func Sign(hash []byte, prv *ecdsa.PrivateKey) {}
//通過公鑰溉瓶,哈希校驗簽名
func VerifySignature(pubkey, hash, signature []byte) bool {}
//將33字節(jié)的公鑰解壓成65字節(jié)公鑰
func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {}
//將65字節(jié)非壓縮公鑰壓縮稱33字節(jié)壓縮公鑰
func CompressPubkey(pubkey *ecdsa.PublicKey) {}