ERC-7913 - Signature Verifiers

Created 2025-03-21
Status Draft
Category ERC
Type Standards Track
Authors

Abstract

Externally Owned Accounts (EOA) can sign messages with their associated private keys. Additionally ERC-1271 defines a method for signature verification by smart accounts such as multisig. In both cases the identity of the signer is an ethereum address. We propose a standard to extend this concept of signer description, and signature verification, to keys that do not have an ethereum identity of their own, in the sense that they don't have their own address to represent them.

This new mechanism can be used to integrate new signers such as non-ethereum cryptographic curves, hardware devices, or even email addresses. This is particularly relevant when dealing with things like social-recovery of smart accounts.

Motivation

With the development of account abstraction, there is an increasing need for non-ethereum signature verification. Cryptographic algorithms besides the natively supported secp256k1 are being used for controlling smart accounts. In particular, curves such as secp256r1 (supported by many mobile devices) and RSA keys (that are distributed by traditional institutions) are widely available. Beyond these two examples, we also see the emergence of ZK solutions for signing with emails or JWT from big Web2 services.

All these signature mechanisms have one thing in common: they do not have a canonical ethereum address to represent them onchain. While users could deploy ERC-1271 compatible contracts for each key individually, this would be cumbersome and expensive. As account abstraction tries to separate account addresses (that hold assets) from the key that controls them, giving fixed on-chain addresses to keys (and possibly sending assets to these addresses by mistake) is not the right approach. Instead, using a small number of verifier contracts that can process signatures in a standard way, and having the accounts rely on these verifiers, feels like the correct approach. This has the advantage that once the verifier is deployed, any key can be represented using a (verifier, key) pair without requiring any setup cost.

The (verifier, key) pairs can be given permission to control a smart account, perform social recovery, or do any other operation without ever having a dedicated on-chain address. Systems that want to adopt this approach need to transition away from the model were signers are identified by their address to a new model where signers may not have an address, and are identified by a bytes object.

This definition is backward compatible with EOA and ERC-1271 contract: in that case, we use the address of the identity (EOA or contract) as the verifier and the key is empty.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Nomenclature

Signature Verifier interface

Verifiers MUST implement the following interface:

interface IERC7913SignatureVerifier {
  /**
   * @dev Verifies `signature` as a valid signature of `hash` by `key`.
   *
   * MUST return the bytes4 magic value 0x024ad318 (IERC7913SignatureVerifier.verify.selector) if the signature is valid.
   * SHOULD return 0xffffffff or revert if the signature is not valid.
   * SHOULD return 0xffffffff or revert if the key is empty
   */
  function verify(bytes calldata key, bytes32 hash, bytes calldata signature) external view returns (bytes4);
}

Verifiers SHOULD be stateless.

Rationale

Verifiers can be used to avoid deploying many ERC-1271 "identity contract" (one per key), which would be expensive. Using this model, new keys can be used without any deployment costs.

ERC-1271 already covers the cases were a key is not necessary. To avoid ambiguity, the verifiers contracts should not support (or be expected to support) empty keys. Signers that are 20 bytes long (empty key) should be handled using ERC-1271.

Consistency with existing systems (ecrecover and ERC-1271) requires the message to be bytes32 hash. These are usually produced following ERC-191 or ERC-712. Cryptographic systems that use different hashing methods SHOULD see this hash as a message, and possibly rehash it following the relevant standards.

Backwards Compatibility

A system can support ERC-7913 signers alongside EOAs and ERC-1271 in the following way.

A signer is a bytes object that is the concatenation of an address and optionally a key: verifier || key. A signer is at least 20 bytes long.

Given a signer signer, a message hash hash, and a signature sign, verification is done as follows:

Reference Implementation

In solidity, signature verification COULD be implemented in the following library:

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

/// @dev Extention of openzeppelin's SignatureChecker library
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;
        }
      }
  }
}

Security Considerations

Signer may be used for anything from smart account session key (with a short lifetime of a few hours/days) to social recovery "guardians" that may only be used several years after they are setup. In order to ensure that these signers remain valid "in perpetuity", the verifier contract SHOULD be trustless. This means that the verifiers SHOULD not be upgradeable contracts.

Verifiers SHOULD also not depend on any value that can be modified after deployment. In solidity terms, the verify function SHOULD be pure. Any parameters that are involved in signature verification SHOULD either be part of the key, or part of immutable code of the verifier. Using immutable variable (in solidity) would be safe. The stateless aspect of the verifier also ensure compliance (of the verifier) with ERC-7562 scope rules.

Copyright

Copyright and related rights waived via CC0.