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.