Alert Source Discuss
Standards Track: ERC

ERC-191: 签名数据标准

Authors Martin Holst Swende (@holiman), Nick Johnson <arachnid@notdot.net>
Created 2016-01-20

摘要

本 ERC 提出关于如何在 Ethereum 合约中处理签名数据的规范。

动机

已经创建了几个多重签名钱包实现,它们接受 presigned 交易。presigned 交易是一块二进制 signed_data,以及签名(rsv)。signed_data 的解释尚未明确,导致了几个问题:

  • 标准 Ethereum 交易可以作为 signed_data 提交。一个 Ethereum 交易可以被解包为以下组成部分:RLP<nonce, gasPrice, startGas, to, value, data> (以下称为 RLPdata),rsv。如果对 signed_data 没有句法约束,这意味着 RLPdata 可以用作句法上有效的 presigned 交易。
  • 多重签名钱包也存在 presigned 交易未与特定 validator(即特定钱包)关联的问题。例如:
    1. 用户 ABC 拥有 2/3 钱包 X
    2. 用户 ABD 拥有 2/3 钱包 Y
    3. 用户 ABX 提交 presigned 交易。
    4. 攻击者现在可以重用他们发送给 Xpresigned 交易,并将其提交给 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.