本文翻譯了官網(wǎng)EIP-191的相關(guān)內(nèi)容。改標(biāo)準(zhǔn)試圖拓展以太坊的簽名規(guī)則,為簽名內(nèi)容的可讀化提供的重要的基礎(chǔ)。
摘要
這個(gè)ERC提議了一個(gè)關(guān)于如何在以太坊合約中處理簽名數(shù)據(jù)的詳細(xì)說(shuō)明。
動(dòng)機(jī)
一些接受presigned交易的多簽名錢包應(yīng)用已經(jīng)出現(xiàn)了。一筆presigned交易就是一堆二進(jìn)制的signed_data,同時(shí)包含簽名(r, s, v)。因?yàn)閷?duì)signed_data的解釋并不具體,導(dǎo)致了一些問(wèn)題:
標(biāo)準(zhǔn)的以太坊交易可以作為
signed_data提交。一筆以太坊交易可以拆解成這幾個(gè)組件:RLP<nonce, gasPrice, startGas, to, value, data>(這里被稱為RLPdata),r,s,v。如果對(duì)signed_data沒有句法約束,這就意味著RLPdata可以用作句法有效的presigned交易。-
多簽名錢包同樣也有問(wèn)題:
presigned交易并不和一個(gè)特定的validator綁定在一起,舉一個(gè)特定錢包的例子:i. 用戶
A,B和C有2/3-錢包Xii. 用戶
A,B和D有2/3-錢包Yiii. 用戶
A和B提交了一個(gè)presigned交易給Xiv. 攻擊者可以復(fù)用他們的給X的
presigned交易,然后提交給Y。
說(shuō)明
我們?yōu)?code>signed_data提議了以下格式:
0x19 <1 byte version> <version specific data> <data to sign>.
版本0對(duì)于版本特定數(shù)據(jù)有<20字節(jié)地址>,這個(gè)地址就是預(yù)期的驗(yàn)證者。在多簽名錢包的例子中,就是錢包自己的地址。
最初的0x19字節(jié)用來(lái)確保signed_data不是有效的RLP
對(duì)于單個(gè)值為[0x00, 0x7f]的字節(jié),字節(jié)的RLP編碼就是它本身
這意味著任何signed_data不能是一個(gè)RLP結(jié)構(gòu),而是1個(gè)字節(jié)的RLP,后面再加上一些別的內(nèi)容。
因此,任何ERC-191 signed_data永遠(yuǎn)不會(huì)是一筆以太坊交易。
額外地,之所以用0x19是因?yàn)樽詮?a target="_blank" rel="nofollow">ethereum/go-ethereum#2940,下面的一行文字會(huì)在personal_sign方法中預(yù)添加在要簽名的hash數(shù)據(jù)之前:
"\x19Ethereum Signed Message:\n" + len(message).
因此,使用0x19是為了可以擴(kuò)展這個(gè)模式,通過(guò)定義一個(gè)版本 0x45(E)來(lái)處理這種類型的簽名。
版本字節(jié)登記
| Version byte | EIP | Description |
|---|---|---|
0x00 |
191 | Data with intended validator |
0x01 |
712 | Structured data |
0x45 |
191 |
personal_sign messages |
舉例
function submitTransactionPreSigned(address destination, uint value, bytes data, uint nonce, uint8 v, bytes32 r, bytes32 s)
public
returns (bytes32 transactionHash)
{
// Arguments when calculating hash to validate
// 1: byte(0x19) - the initial 0x19 byte
// 2: byte(0) - the version byte
// 3: this - the validator address
// 4-7 : Application specific data
transactionHash = keccak256(byte(0x19),byte(0),this,destination, value, data, nonce);
sender = ecrecover(transactionHash, v, r, s);
// ...
}