本文翻译了官网EIP-191的相关内容。改标准试图拓展以太坊的签名规则,为签名内容的可读化提供的重要的基础。
摘要
这个ERC提议了一个关于如何在以太坊合约中处理签名数据的详细说明。
动机
一些接受presigned
交易的多签名钱包应用已经出现了。一笔presigned
交易就是一堆二进制的signed_data
,同时包含签名(r
, s
, v
)。因为对signed_data
的解释并不具体,导致了一些问题:
- 标准的以太坊交易可以作为
signed_data
提交。一笔以太坊交易可以拆解成这几个组件:RLP<nonce, gasPrice, startGas, to, value, data>
(这里被称为RLPdata
),r
,s
,v
。如果对signed_data
没有句法约束,这就意味着RLPdata
可以用作句法有效的presigned
交易。 - 多签名钱包同样也有问题:
presigned
交易并不和一个特定的validator
绑定在一起,举一个特定钱包的例子:i. 用户
A
,B
和C
有2/3
-钱包X
ii. 用户
A
,B
和D
有2/3
-钱包Y
iii. 用户
A
和B
提交了一个presigned
交易给X
iv. 攻击者可以复用他们的给X的
presigned
交易,然后提交给Y
。
说明
我们为signed_data
提议了以下格式:
0x19 <1 byte version> <version specific data> <data to sign>.
版本0
对于版本特定数据有<20字节地址>
,这个地址就是预期的验证者。在多签名钱包的例子中,就是钱包自己的地址。
最初的0x19
字节用来确保signed_data
不是有效的RLP
对于单个值为[0x00, 0x7f]的字节,字节的RLP编码就是它本身
这意味着任何signed_data
不能是一个RLP结构,而是1个字节的RLP
,后面再加上一些别的内容。
因此,任何ERC-191 signed_data
永远不会是一笔以太坊交易。
额外地,之所以用0x19
是因为自从ethereum/go-ethereum#2940,下面的一行文字会在personal_sign
方法中预添加在要签名的hash数据之前:
"\x19Ethereum Signed Message:\n" + len(message).
因此,使用0x19
是为了可以扩展这个模式,通过定义一个版本 0x45
(E
)来处理这种类型的签名。
版本字节登记
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);
// ...
}
}