ERC-1271: Standard Signature Validation Method for Contracts

article Francisco Giordano, Matt Condon, Philippe Castonguay, Amir Bandeali, Jorge Izquierdo, Bertrand Masius

The Ethereum standard that lets smart contracts verify signatures on their own behalf. Created July 2018 as a Standards Track ERC, it defines a single function — isValidSignature(bytes32 hash, bytes signature) returns (bytes4 magicValue) — that any contract can implement to answer the question “is this signature valid for you?”. EIP-1271 is the bridge that lets smart contract wallets, DAOs, multisigs, and any other contract-owned identity participate in the EIP-712 off-chain signing ecosystem that was originally built for EOAs.

Core contribution

The problem: EOAs sign messages with their private keys and verifiers call ecrecover to confirm. Smart contracts have no private key, so ecrecover cannot work for them. Before EIP-1271, any application that accepted off-chain signatures implicitly required an EOA signer, and contract-owned identities (Safes, DAOs, Argent wallets) were locked out of signature-gated flows.

The solution: A single-method interface. A contract that wants to be treated as a signer implements isValidSignature(hash, signature). Verifiers call this method instead of ecrecover when the signer address has code. The function returns the magic value 0x1626ba7e (the first four bytes of keccak256("isValidSignature(bytes32,bytes)")) if valid, and anything else — including reverting — if not.

The magic value: bytes4(0x1626ba7e) is returned instead of a boolean. The rationale is stricter verification semantics: a contract that has not implemented the method at all, or that implements it incorrectly and returns arbitrary bytes, will not accidentally satisfy a boolean check. The verifier must see the exact magic value.

Specification highlights

  • Function signature: function isValidSignature(bytes32 _hash, bytes memory _signature) public view returns (bytes4 magicValue);
  • Return value: 0x1626ba7e on success; any other value (or revert) on failure.
  • State modification: MUST NOT modify state. Enforced via view modifier (Solidity 0.5+) or STATICCALL in older versions. This rules out GasToken-style minting attacks and lets clients call the method cheaply off-chain.
  • Hash parameter: A bytes32 digest, not the raw message. Contracts may expect any hashing scheme (raw keccak, Ethereum Signed Message, EIP-712 digest) — the standard is agnostic. Verifiers are responsible for producing the correct digest before calling.
  • Signature parameter: Opaque bytes. The contract interprets them however it wants: ECDSA, multisig threshold signatures, BLS, pre-approved hash lookup, time-based rules, state-based rules, role-based rules.

Design rationales

  • Gas agnosticism: No gas limit is prescribed. A verifying contract may implement expensive logic — a multisig checking 20 signatures, a BLS aggregation, a stateful lookup. Callers must not hardcode a gas cap when invoking isValidSignature on an external contract, because a too-low cap would make valid signatures un-verifiable.
  • Context-dependent logic: The method can inspect any state it wants — nonces, deadlines, authorized signer lists, role mappings — so signature validity can depend on more than just the cryptographic check. This is explicitly supported: “time based or state based”.
  • Two arguments instead of one: A raw message plus hashing scheme would be ambiguous. Instead the hash is computed by the caller and passed directly. Callers and contracts must agree on the hashing scheme out of band — typically EIP-712 with a domain separator.

Security considerations

  • No gas limit on callers: Callers MUST NOT hardcode gas when invoking isValidSignature. A signing contract may intentionally or incidentally use large amounts of gas; a capped call would starve it and reject a valid signature.
  • Contract responsibility: Each signing contract is fully responsible for the correctness of its own validation logic. A buggy implementation that returns the magic value for signatures it should reject is a catastrophic failure — attackers can move assets, execute votes, or impersonate the contract with arbitrary signatures. The standard provides the interface; it does not audit the implementation.
  • Backwards compatibility: EIP-1271 is purely additive. EOAs still work the same way through ecrecover; contracts that do not implement isValidSignature behave as before. Verifiers typically probe: “if the signer has code, call isValidSignature; otherwise use ecrecover”. OpenZeppelin’s SignatureChecker.isValidSignatureNow implements exactly that fallback.

Ecosystem impact

EIP-1271 is the signature-verification contract for every smart-account flow in modern Ethereum:

  • Safe (Gnosis) implements isValidSignature via its CompatibilityFallbackHandler. It supports two modes: (a) passing a non-empty signature that gets verified by checkSignatures against the current owner set and threshold, and (b) passing empty bytes, which causes the Safe to look up the hash in its on-chain signedMessages mapping — pre-approved by an earlier SignMessageLib.signMessage delegatecall. See Creating a Farcaster Account by Hand for a live walkthrough of the pre-approved variant.
  • ERC-4337 account abstraction uses EIP-1271 as the contract-account signature interface: validateUserOp on a smart account implementation effectively performs an EIP-1271 check on the UserOperation hash.
  • OpenSea / Seaport accepts orders signed by Safe multisigs and other contract accounts through EIP-1271.
  • ERC-2612 permit on tokens that support it can be authorized by contract signers via EIP-1271.
  • Sign-In with Ethereum (EIP-4361) verifies contract-signer logins via EIP-1271.
  • Argent, Ambire, Sequence, Biconomy and every other smart-account wallet depend on EIP-1271 to interoperate with dapps that expected EOAs.

Without EIP-1271, smart contract wallets are second-class citizens on the signature layer. With it, they are indistinguishable from EOAs at the application interface.

Ingestion manifest

MOC updated: Digital Identity

https://eips.ethereum.org/EIPS/eip-1271