ERC-191: 签名数据标准
Authors | Martin Holst Swende (@holiman), Nick Johnson <arachnid@notdot.net> |
---|---|
Created | 2016-01-20 |
摘要
本 ERC 提出关于如何在 Ethereum 合约中处理签名数据的规范。
动机
已经创建了几个多重签名钱包实现,它们接受 presigned
交易。presigned
交易是一块二进制 signed_data
,以及签名(r
、s
和 v
)。signed_data
的解释尚未明确,导致了几个问题:
- 标准 Ethereum 交易可以作为
signed_data
提交。一个 Ethereum 交易可以被解包为以下组成部分:RLP<nonce, gasPrice, startGas, to, value, data>
(以下称为RLPdata
),r
,s
和v
。如果对signed_data
没有句法约束,这意味着RLPdata
可以用作句法上有效的presigned
交易。 - 多重签名钱包也存在
presigned
交易未与特定validator
(即特定钱包)关联的问题。例如:- 用户
A
、B
和C
拥有2/3
钱包X
- 用户
A
、B
和D
拥有2/3
钱包Y
- 用户
A
和B
向X
提交presigned
交易。 - 攻击者现在可以重用他们发送给
X
的presigned
交易,并将其提交给Y
。
- 用户
规范
我们为 signed_data
提出以下格式
0x19 <1 byte version> <version specific data> <data to sign>.
初始的 0x19
字节旨在确保 signed_data
不是有效的 RLP。
对于一个值在 [0x00, 0x7f] 范围内的单字节,该字节是其自身的 RLP 编码。
这意味着任何 signed_data
都不能是一个 RLP 结构,而是一个 1 字节的 RLP
有效负载,后跟其他内容。因此,任何 EIP-191 signed_data
永远不能是 Ethereum 交易。
此外,选择 0x19
是因为自 ethereum/go-ethereum#2940 以来,以下内容会添加到 personal_sign 中哈希计算之前:
"\x19Ethereum Signed Message:\n" + len(message).
因此,使用 0x19
可以通过定义版本 0x45
(E
) 来处理这些类型的签名来扩展该方案。
版本字节注册表
版本字节 | EIP | 描述 |
---|---|---|
0x00 |
191 | 带有目标验证器的数据 |
0x01 |
712 | 结构化数据 |
0x45 |
191 | personal_sign 消息 |
版本 0x00
0x19 <0x00> <intended validator address> <data to sign>
版本 0x00
的版本特定数据是 <intended validator address>
。在多重签名钱包基于传递的签名执行操作的情况下,验证器地址是多重签名钱包本身的地址。要签名的数据可以是任何任意数据。
版本 0x01
版本 0x01
用于 EIP-712 中定义的结构化数据。
版本 0x45
(E)
0x19 <0x45 (E)> <thereum Signed Message:\n" + len(message)> <data to sign>
版本 0x45
(E) 的版本特定数据是 <thereum Signed Message:\n" + len(message)>
。要签名的数据可以是任何任意数据。
注意:
Ethereum Signed Message
中的E
指的是版本字节 0x45。字符E
在十六进制中是0x45
,这使得剩余部分thereum Signed Message:\n + len(message)
成为版本特定的数据。
示例
以下代码片段是用 Solidity 0.8.0 编写的。
版本 0x00
function signatureBasedExecution(address target, uint256 nonce, bytes memory payload, uint8 v, bytes32 r, bytes32 s) public payable {
// Arguments when calculating hash to validate
// 用于计算哈希以进行验证的参数
// 1: byte(0x19) - the initial 0x19 byte
// 1:byte(0x19) - 初始的 0x19 字节
// 2: byte(0) - the version byte
// 2:byte(0) - 版本字节
// 3: address(this) - the validator address
// 3:address(this) - 验证器地址
// 4-6 : Application specific data
// 4-6:应用程序特定数据
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), address(this), msg.value, nonce, payload));
// recovering the signer from the hash and the signature
// 从哈希和签名中恢复签名者
addressRecovered = ecrecover(hash, v, r, s);
// logic of the wallet
// 钱包的逻辑
// if (addressRecovered == owner) executeOnTarget(target, payload);
// 如果 (addressRecovered == owner) 在目标上执行 (target, payload);
}
版权
在 CC0 下放弃版权及相关权利。
Citation
Please cite this document as:
Martin Holst Swende (@holiman), Nick Johnson <arachnid@notdot.net>, "ERC-191: 签名数据标准," Ethereum Improvement Proposals, no. 191, January 2016. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-191.