Alert Source Discuss
⚠️ Review Standards Track: ERC

ERC-7913: 签名验证器

用于通过无地址密钥验证签名的接口

Authors Hadrien Croubois (@Amxx), Ernesto García (@ernestognw), Francisco Giordano (@frangio), Aryeh Greenberg (@arr00)
Created 2025-03-21

摘要

外部拥有账户 (EOA) 可以用其关联的私钥对消息进行签名。此外,ERC-1271 定义了一种通过智能账户(如多重签名)进行签名验证的方法。在这两种情况下,签名者的身份都是一个以太坊地址。我们提出一个标准来扩展这种签名者描述和签名验证的概念,使其适用于那些没有自己的以太坊身份的密钥,即它们没有自己的地址来代表它们。

这种新机制可以用于集成新的签名者,例如非以太坊加密曲线、硬件设备,甚至电子邮件地址。这在处理智能账户的社交恢复等事情时尤为重要。

动机

随着账户抽象的发展,对非以太坊签名验证的需求日益增长。除了原生支持的 secp256k1 之外的加密算法正被用于控制智能账户。特别是,诸如 secp256r1 (由许多移动设备支持) 和 RSA 密钥 (由传统机构分发) 等曲线已被广泛使用。除了这两个例子之外,我们还看到了使用电子邮件或来自大型 Web2 服务的 JWT 进行签名的 ZK 解决方案的出现。

所有这些签名机制都有一个共同点:它们没有规范的以太坊地址来在链上表示它们。虽然用户可以为每个密钥单独部署与 ERC-1271 兼容的合约,但这将是繁琐且昂贵的。由于账户抽象试图将账户地址(持有资产)与控制它们的密钥分开,因此为密钥提供固定的链上地址(并可能错误地将资产发送到这些地址)不是正确的方法。相反,使用少量可以以标准方式处理签名的验证器合约,并让账户依赖这些验证器,感觉是正确的方法。这样做的好处是,一旦部署了验证器,任何密钥都可以使用 (verifier, key) 对表示,而无需任何设置成本。

可以授予 (verifier, key) 对控制智能账户、执行社交恢复或执行任何其他操作的权限,而无需拥有专用的链上地址。想要采用这种方法的系统需要从签名者由其地址标识的模型过渡到签名者可能没有地址,而是由 bytes 对象标识的新模型。

此定义向后兼容 EOA 和 ERC-1271 合约:在这种情况下,我们使用身份(EOA 或合约)的地址作为验证器,并且密钥为空。

规范

本文档中的关键词 “MUST”(必须)、”MUST NOT”(禁止)、”REQUIRED”(需要)、”SHALL”(应)、”SHALL NOT”(不应)、”SHOULD”(应该)、”SHOULD NOT”(不应该)、”RECOMMENDED”(推荐)、”NOT RECOMMENDED”(不推荐)、”MAY”(可以)和 “OPTIONAL”(可选)应按照 RFC 2119 和 RFC 8174 中的描述进行解释。

命名法

  • 密钥使用任意长度的 bytes 对象表示。例如,P256 或 RSA 公钥。密钥不能为空。
  • 验证器是负责验证给定类型密钥的签名的智能合约。它们具有以太坊地址。

签名验证器接口

验证器必须实现以下接口:

interface IERC7913SignatureVerifier {
  /**
   * @dev 验证 `signature` 作为 `key` 对 `hash` 的有效签名。
   *
   * 如果签名有效,则必须返回 bytes4 魔术值 0x024ad318 (IERC7913SignatureVerifier.verify.selector)。
   * 如果签名无效,则应返回 0xffffffff 或 revert。
   * 如果密钥为空,则应返回 0xffffffff 或 revert。
   */
  function verify(bytes calldata key, bytes32 hash, bytes calldata signature) external view returns (bytes4);
}

验证器应该是无状态的。

理由

验证器可用于避免部署许多 ERC-1271 “身份合约”(每个密钥一个),这将是昂贵的。使用此模型,可以使用新密钥,而无需任何部署成本。

ERC-1271 已经涵盖了不需要密钥的情况。为避免歧义,验证器合约不应支持(或不应期望支持)空密钥。长度为 20 字节的签名者(空密钥)应使用 ERC-1271 处理。

与现有系统(ecrecover 和 ERC-1271)的一致性要求消息为 bytes32 哈希。这些通常是按照 ERC-191ERC-712 生成的。使用不同哈希方法的加密系统应将此哈希视为消息,并可能按照相关标准重新哈希它。

向后兼容性

系统可以通过以下方式支持 ERC-7913 签名者以及 EOA 和 ERC-1271。

签名者是一个 bytes 对象,它是地址和可选密钥的串联:verifier || key。签名者的长度至少为 20 字节。

给定一个签名者 signer、一个消息哈希 hash 和一个签名 sign,验证按如下方式进行:

  • 如果 signer.length < 20:验证失败;
  • signer 分割成 (verifier, key),其中 verifier 是前 20 个字节,key 是剩余的字节(可能为空)
  • 如果 key 为空,则认为 verifier 是身份。
    • 如果 verifier 地址处有代码,则使用 ERC-1271 的 isValidSignature 完成验证,否则使用 ecrecover
  • 如果 key 不为空,则调用 IERC7913SignatureVerifier(verifier).verify(key, hash, signature)
    • 如果返回值是预期的魔术值 (0x024ad318),则验证成功,
    • 否则,验证失败。

参考实现

在 solidity 中,签名验证可以在以下库中实现:

import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol';

/// @dev OpenZeppelin 的 SignatureChecker 库的扩展
library SignatureCheckerExtended {
  function isValidSignatureNow(bytes calldata signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
      if (signer.length < 20 ) {
        return false;
      } else if (signer.length == 20) {
        return SignatureChecker.isValidSignatureNow(address(bytes20(signer)), hash, signature);
      } else {
        try IERC7913SignatureVerifier(address(bytes20(signer[0:20]))).verify(signer[20:], hash, signature) returns (bytes4 magic) {
          return magic == IERC7913SignatureVerifier.verify.selector;
        } catch {
          return false;
        }
      }
  }
}

安全考虑

签名者可以用于从智能账户会话密钥(具有几个小时/几天的短寿命)到社交恢复“守护者”的任何事情,这些“守护者”可能仅在设置几年后才使用。为了确保这些签名者“永久”有效,验证器合约应该是无信任的。这意味着验证器不应该是可升级的合约。

验证器也不应该依赖于部署后可以修改的任何值。用 solidity 的术语来说,verify 函数应该是 pure 的。任何参与签名验证的参数都应该是密钥的一部分,或者验证器的不可变代码的一部分。使用 immutable 变量(在 solidity 中)将是安全的。验证器的无状态方面也确保了(验证器)符合 ERC-7562 的范围规则。

版权

版权和相关权利通过 CC0 放弃。

Citation

Please cite this document as:

Hadrien Croubois (@Amxx), Ernesto García (@ernestognw), Francisco Giordano (@frangio), Aryeh Greenberg (@arr00), "ERC-7913: 签名验证器 [DRAFT]," Ethereum Improvement Proposals, no. 7913, March 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7913.