EIP-1271 Link to heading

EIP-1271 解决的核心问题:智能合约签名验证 Link to heading

传统的签名验证只能处理 EOA(外部账户)的签名:

  • 使用 ecrecover 从签名中恢复签名者地址
  • 只适用于私钥控制的账户

但随着智能合约钱包的普及,出现了新问题:

  • 多签钱包:需要多个签名才能执行操作
  • 智能合约钱包:使用复杂逻辑控制资产
  • DAO 治理:需要验证组织的"集体签名"

EIP-1271 定义了统一的接口,让智能合约能够:

  1. 实现自定义的签名验证逻辑
  2. 与现有的签名验证系统兼容
  3. 支持复杂的多签、阈值签名等场景

EIP-1271 标准接口 Link to heading

interface IERC1271 {
    /**
     * @dev 验证签名是否有效
     * @param hash 要验证的数据哈希
     * @param signature 签名数据
     * @return magicValue 验证通过返回 0x1626ba7e,否则返回其他值
     */
    function isValidSignature(
        bytes32 hash,
        bytes memory signature
    ) external view returns (bytes4 magicValue);
}

说明

  • 成功:0x1626ba7e (bytes4(keccak256(“isValidSignature(bytes32,bytes)”)))
  • 失败:返回任何其他值

示例 Link to heading

多签钱包实现 Link to heading

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

contract MultiSigWallet {
    using ECDSA for bytes32;

    // EIP-1271 魔数
    bytes4 constant internal MAGICVALUE = 0x1626ba7e;
    
    address[] public owners;
    uint256 public threshold; // 需要的最少签名数
    
    constructor(address[] memory _owners, uint256 _threshold) {
        require(_threshold > 0 && _threshold <= _owners.length, "Invalid threshold");
        owners = _owners;
        threshold = _threshold;
    }
    
    // EIP-1271 实现
    function isValidSignature(
        bytes32 hash,
        bytes memory signature
    ) external view returns (bytes4 magicValue) {
        // 解析多个签名
        require(signature.length % 65 == 0, "Invalid signature length");
        uint256 sigCount = signature.length / 65;
        require(sigCount >= threshold, "Not enough signatures");
        
        address[] memory signers = new address[](sigCount);
        
        // 验证每个签名
        for (uint256 i = 0; i < sigCount; i++) {
            bytes memory sig = new bytes(65);
            for (uint256 j = 0; j < 65; j++) {
                sig[j] = signature[i * 65 + j];
            }
            
            address signer = hash.recover(sig);
            require(_isOwner(signer), "Invalid signer");
            
            // 检查重复签名
            for (uint256 k = 0; k < i; k++) {
                require(signers[k] != signer, "Duplicate signature");
            }
            
            signers[i] = signer;
        }
        
        return MAGICVALUE;
    }
    
    function _isOwner(address addr) internal view returns (bool) {
        for (uint256 i = 0; i < owners.length; i++) {
            if (owners[i] == addr) {
                return true;
            }
        }
        return false;
    }
}

通用签名验证器 Link to heading

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

contract UniversalSignatureValidator {
    using ECDSA for bytes32;
    
    bytes4 constant internal MAGICVALUE = 0x1626ba7e;
    
    /**
     * @dev 通用签名验证函数
     * @param signer 签名者地址(可能是 EOA 或合约)
     * @param hash 要验证的哈希
     * @param signature 签名数据
     */
    function isValidSignature(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) public view returns (bool) {
        // 检查是否为合约地址
        if (signer.code.length > 0) {
            // 合约签名:调用 EIP-1271
            try IERC1271(signer).isValidSignature(hash, signature) returns (bytes4 result) {
                return result == MAGICVALUE;
            } catch {
                return false;
            }
        } else {
            // EOA 签名:使用 ecrecover
            address recovered = hash.recover(signature);
            return recovered == signer;
        }
    }
}

与 EIP-712 结合使用 Link to heading

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";

contract OrderValidator is EIP712 {
    struct Order {
        address maker;
        address taker;
        uint256 amount;
        uint256 deadline;
    }
    
    bytes32 private constant ORDER_TYPEHASH =
        keccak256("Order(address maker,address taker,uint256 amount,uint256 deadline)");
    
    constructor() EIP712("OrderValidator", "1") {}
    
    function validateOrder(
        Order memory order,
        bytes memory signature
    ) external view returns (bool) {
        bytes32 structHash = keccak256(
            abi.encode(ORDER_TYPEHASH, order.maker, order.taker, order.amount, order.deadline)
        );
        bytes32 hash = _hashTypedDataV4(structHash);
        
        // 使用通用验证器
        UniversalSignatureValidator validator = UniversalSignatureValidator(0x...);
        return validator.isValidSignature(order.maker, hash, signature);
    }
}

应用场景 Link to heading

  1. 多签钱包

    • 需要多个所有者签名才能执行操作
    • 支持阈值签名(如 3/5 多签)
  2. 智能合约钱包

    • 基于规则的签名验证
    • 社交恢复、时间锁等高级功能
  3. DAO 治理

    • 验证提案的"组织签名"
    • 支持委托投票等复杂场景
  4. DeFi 协议集成

    • 让智能合约钱包能够使用 permit 功能
    • 支持复杂的 DeFi 操作授权

与其他 EIP 的关系 Link to heading

  • EIP-712 + EIP-1271:让智能合约能够签署和验证结构化数据
  • ERC-2612 + EIP-1271:让智能合约钱包也能使用 permit 功能
  • EIP-4494 + EIP-1271:智能合约钱包的 NFT permit 支持

安全注意事项 Link to heading

  • 重放攻击防护:结合 nonce、chainId、deadline 等机制
  • 签名唯一性:防止同一签名被多次使用
  • 权限验证:确保只有授权的签名者能够通过验证
  • 合约升级:考虑签名验证逻辑的升级兼容性

小结 Link to heading

  • EIP-1271 为智能合约提供了标准的签名验证接口
  • 支持多签、阈值签名等复杂的验证逻辑
  • 与 EIP-712 结合,实现结构化数据的合约签名
  • 是智能合约钱包和 DeFi 生态的重要基础设施