我們知道整個比特幣,以太坊的基石就是橢圓曲線加密算法。所有的數據均需要發起者通過私匙簽發,其它人通過非對稱的公匙驗證確實消息的真實性。下面我們就一起來了解一下橢圓曲線加密算法,并使用以太坊提供的工具對要發送的數據進行數字簽名,以及使用Solidity區塊鏈編程語言的ecrecover()校驗數字簽名的合法性。橢圓曲線DSA(ECDSA)簡介
假如Alice要對消息m加上數字簽名,而Bob需要驗證該簽名。
生成數字簽名
Alice根據隨機數r和基點G求出點rG = (x, y);
Alicce根據隨機數r、消息m的散列值h、和私匙a計算

最后,Alice將消息m、點rG = (x, y)和s發送給Bob,其中點rG和s就是數字簽名。
驗證數字簽名
Bob接收到消息m、點rG = (x, y)和s。
Bob根據消息求出散列值h。
最后,Bob根據上述信息,用Alice的公匙進行以下計算。

最后讓上述計算結果與rG進行比較看是否相等。
如果簽名結果正確,則計算結果應如下所示。

原書[1]中關于這部分看了三四遍,也沒看明白。但覺得做程序的明白他大概要干個什么就好。大體上來說,對于要簽名的數據m,使用它的哈希后的結果h,會生成簽名。簽名結果分為r,s,v三段值。其中r,s為32字節。v為一個字節,如果要用ecrecover()算法來驗簽,需對v值加27來組成27,28這兩個值中的一個[2]。
實踐
使用web3.js進行數據簽名
以太坊提供了web3.eth.sign方法來對數據生成數字簽名。

在上面的代碼中,我們先將要簽名的數據abc生成哈希串,使用web3.sha3("abc)。接著我們使用當前連接節點的第一個默認帳戶進行簽名。
由于我使用的是EtherumJS TestRPC,它默認打開了帳戶。否則,你還需要web3.personal.unlockAccount("0x..", "", 1000)[3]來打開數據簽名所使用帳戶。需要注意的是,當你打開你的帳戶時,可能有安全風險。因為其它程序也可以通過訪問節點進行類似的sign,這意味著,他們可以偽造你的數據[4],包括以你的名義發起交易,轉走你的錢。
運行的結果:

使用ecrecover()對簽名數據進行校驗
ecrecover[5]函數是由以太坊提供的一個全局函數,用于簽名數據的校驗。與上面所陳述的方式略有不同的是,這個函數返回的是簽名者的公匙地址。如果返回結果是簽名者的公匙地址,那么說明數據是正確的。
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)
ecrecover函數需要四個參數,需要被簽名數據的哈希結果值,r,s,v三個值。通過前面的說明,我們知道r,s,v是分別來自簽名結果串。

其中v取出來的值或者是00或01。要使用時,我們先要將其轉為整型,再加上27,所以我們將得到27或28。在調用函數時v將填入27或28。
如果要在以太坊中驗證比特幣的簽名,可能有幾處不同的地方[6]。
使用Solidity的ecrecoverDecode驗證簽名的完整例子。


上述代碼使用臨時寫的slice()函數把數據簽名中的r,s,v切割出來;由于返回的仍是一個bytes類型,所以我們使用bytesToBytes32()進行一下類型轉換[7];另外需要注意的是ecrecoverDecode()根據前面的說明,我們需要對v值,加上27后再進行調用。最后調用decode()函數,我們將會得到公匙0x60320b8a71bc314404ef7d194ad8cac0bee1e331。