Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

3. Verifier

3.1 Purpose and invariants

The Verifier is a single shared contract responsible for signature verification and scheme dispatch only. It has no records, no roles, no policy state, and no per-name configuration.

A conformant Verifier:

  • MUST be permissionlessly callable. Any contract or EOA can invoke verify(...) without prior registration.
  • MUST NOT hold per-call state. verify is view; no replay protection lives at this layer.
  • MUST NOT revert on an unsupported schemeId. It MUST return valid = false instead, so the caller (typically the AuthResolverImpl's verifyAction) can map the outcome to a structured DenyReason (per §5.1).
  • MUST be deployed once per chain. The AuthResolverImpl's deployment salt embeds a versionId (§4.3); the Verifier's address is captured by that versioning.

3.2 Registered signature schemes (v1)

v1 ships exactly three registered schemes, chosen to cover the EOA, smart-contract-account, and passkey signing models present across named Wave-1 MARP candidates from day zero:

schemeIdSchemeVerification primitiveCovers
keccak256("WebAuthn-ES256")ECDSA over P-256 with SHA-256 challenge hashingEIP-7951 P-256 precompilePasskey-backed signing (WebAuthn authenticators)
keccak256("ECDSA-secp256k1")ECDSA over secp256k1 with keccak256 challenge hashingecrecoverEOA signing, including standard agent-runtime signing endpoints (e.g., Bankr Agents' /agent/sign)
keccak256("EIP-1271")Contract-account signaturestaticcall to pubKey-encoded contract's isValidSignature(bytes32, bytes) returning the EIP-1271 magic valueSmart-contract-account signing (EIP-7702-delegated wallets, ZeroDev/Kernel, generic ERC-4337 accounts)

A conformant Verifier:

  • MUST register all three schemes at deployment. Returning false from isSchemeSupported for any of the three is a conformance violation.
  • MUST dispatch by schemeId. The mapping above is the source of truth for v1.
  • For WebAuthn-ES256, the message parameter MUST be passed to the EIP-7951 precompile as the pre-hashed challenge per the WebAuthn assertion verification procedure. The Verifier MUST NOT re-hash the message before precompile invocation.
  • For ECDSA-secp256k1, the pubKey parameter MUST be 64 bytes (uncompressed, no 0x04 prefix); the Verifier MUST recover the address via ecrecover and compare against keccak256(pubKey)[12:]. EIP-712 typed-data hashing is the caller's responsibility — the Verifier sees the final 32-byte digest in message.
  • For EIP-1271, the pubKey parameter MUST be a 20-byte contract address (left-padded to bytes if the caller passes a longer encoding; the Verifier MUST take the rightmost 20 bytes). The Verifier MUST staticcall isValidSignature(bytes32 hash, bytes signature) and return true if and only if the returned 4 bytes equal 0x1626ba7e.

3.3 IVerifier interface (NORMATIVE)

interface IVerifier {
 /// @notice Verify a signature using a registered signature scheme.
 /// @param schemeId keccak256 identifier (see §3.2).
 /// @param message Scheme-specific message bytes. For WebAuthn-ES256 this is the
 /// pre-hashed challenge; for ECDSA-secp256k1 this is a 32-byte digest;
 /// for EIP-1271 this is a 32-byte hash passed to the contract.
 /// @param signature Scheme-specific signature blob.
 /// @param pubKey Scheme-specific public key (uncompressed P-256 point for WebAuthn-ES256;
 /// 64-byte uncompressed secp256k1 key; 20-byte address for EIP-1271).
 /// @return valid True iff the signature verifies under the scheme.
 function verify(bytes32 schemeId,
 bytes calldata message,
 bytes calldata signature,
 bytes calldata pubKey) external view returns (bool valid);
 
 /// @notice Whether the Verifier dispatches the given scheme.
 function isSchemeSupported(bytes32 schemeId) external view returns (bool);
}

3.4 Dispatch surface and extensibility

The schemeId parameter is the extensibility surface. Future cycles MAY register additional schemes (BLS12-381 aggregation, post-quantum candidates) by deploying a successor Verifier and bumping the versionId embedded in the AuthResolverImpl deployment salt (§4.3). Adding a scheme is a new Verifier deployment, not an upgrade of the v1 Verifier — v1 is immutable at the dispatch layer.

A conformant Verifier MUST NOT expose a setter that adds, removes, or modifies scheme handlers post-deployment. Scheme registration is fixed at construction.

3.5 Security considerations

  • No batch entry point. v1 does not expose a batched verifyMany. Relying parties needing to verify N signatures call verify N times. Deferred to v1.1 if pilot integrations request it.
  • No replay protection. Replay binding is the caller's responsibility (typically via stateHash in VerificationResult per §5.1, or via EIP-712 typed-data nonces in the application-layer message).
  • Scheme handler trust. The EIP-1271 path executes a staticcall to a contract address the caller controls (via pubKey). The Verifier MUST treat the call as untrusted (gas-bounded, revert-safe). Implementations SHOULD cap the staticcall gas to a documented limit (e.g., 100,000 gas) and treat any revert as valid = false.
  • Precompile availability. The EIP-7951 precompile MUST be live on the target chain at the AuthResolverImpl deployment block. Per ENS documentation (search "EIP-7951"), the precompile is available on Ethereum mainnet after the Fusaka hardfork. Per-L2 availability is not uniformly enumerated; deployment targets MUST confirm precompile presence on each chain before the AuthResolverImpl proxy is deployed there.

3.6 Conformance criteria (NORMATIVE)

A conformant Verifier satisfies every MUST/MUST NOT and SHOULD/MAY in this table. This restates the normative content in §3.1–§3.5; the source sections remain authoritative for any discrepancy.

#RequirementTypeSource
V1Permissionlessly callable; no per-call stateMUST§3.1
V2verify is view; no replay protection at this layerMUST§3.1, §3.5
V3Return false (not revert) for unsupported schemeIdMUST§3.1
V4Deployed once per chainMUST§3.1
V5Register all three v1 schemes (WebAuthn-ES256, ECDSA-secp256k1, EIP-1271) at constructionMUST§3.2
V6Dispatch by schemeId per the §3.2 tableMUST§3.2
V7For WebAuthn-ES256: pass message as the pre-hashed challenge to the EIP-7951 precompileMUST§3.2
V8For WebAuthn-ES256: NOT re-hash the message before precompile invocationMUST NOT§3.2
V9For ECDSA-secp256k1: pubKey is 64 bytes uncompressed (no 0x04 prefix); recover via ecrecover and compare against keccak256(pubKey)[12:]MUST§3.2
V10For EIP-1271: take rightmost 20 bytes of pubKey as the contract addressMUST§3.2
V11For EIP-1271: staticcall isValidSignature(bytes32, bytes); return true iff returned 4 bytes equal 0x1626ba7eMUST§3.2
V12NOT expose any setter that adds, removes, or modifies scheme handlers post-deploymentMUST NOT§3.4
V13EIP-7951 precompile MUST be live on target chain at deployment block (per Fusaka hardfork status for mainnet; per-L2 confirmation required)MUST§3.5
V14Treat EIP-1271 staticcall as untrusted (gas-bounded, revert-safe)MUST§3.5
V15Cap EIP-1271 staticcall gas to a documented limit (e.g., 100K) and treat any revert as valid = falseSHOULD§3.5
V16Expose a batched verifyMany entry pointMAY (deferred to v1.1)§3.5