EIP.tools

EIP.tools

⚠️ DraftStandards Track: Core

EIP-8225: ECRECOVER Native Key Awareness

Extends ECRECOVER to verify native-key signatures and reject dead ECDSA keys

Authors
Created2026-04-11
Discussion Linkhttps://ethereum-magicians.org/t/eip-8225-ecrecover-native-key-awareness/28332
Requires

Markdown

https://raw.githubusercontent.com/ethereum/EIPs/re...
Pull Request#11515PR open

EIP-GPT summary

Contents
AbstractMotivationSpecificationConstantsInput FormatReturn ValueECDSA ModeNative-Key ModeML-DSA-44 Verification (0xef0101)Gas CostECDSA ModeNative-Key ModeRationaleModifying ECRECOVER vs. New PrecompileThe 0xff SentinelForward CompatibilityReturning Empty on FailureGas ModelBackwards CompatibilityTest CasesSecurity ConsiderationsECDSA Key Rejection ConsistencyAccount Code TOCTOUMalleabilityGas GriefingForward CompatibilityCopyright

Abstract

This EIP modifies the ECRECOVER precompile (address 0x01) to support EIP-8164 native-key accounts. In ECDSA mode, after successful key recovery, the precompile checks whether the recovered address has a native-key delegation (code prefix 0xef0101–0xef01ff); if so, it returns empty rather than the address. In native-key mode, signaled by a 0xff sentinel in the v argument, the precompile accepts a target address and a scheme-specific signature, then verifies the signature against the public key embedded in that account's native-key designation. ML-DSA-44 (0xef0101) verification is defined here, and the design is forward-compatible with future native-key schemes.

Motivation

EIP-8164 lets EOAs permanently replace their ECDSA signing key with a post-quantum alternative by storing a native-key designation under the 0xef0101–0xef01ff code prefix range. Once an account has a native-key designation, the protocol rejects ECDSA-signed transactions from that account — the ECDSA key is considered dead. The ECRECOVER precompile, however, has no knowledge of this change.

This creates two problems. First, the authority model becomes inconsistent: smart contracts that rely on ecrecover for signature verification — including ERC-20 permit functions, ERC-2612 gasless approvals, and meta-transaction relayers — continue to accept ECDSA signatures from accounts whose ECDSA keys the protocol no longer recognizes as authoritative. An attacker in possession of a compromised ECDSA private key can exploit this gap even after the account owner has migrated to a native key.

Second, smart contracts have no mechanism to verify signatures produced by native-key accounts. Permit flows, governance votes, and other on-chain signature checks become inaccessible to accounts that have migrated to native keys, effectively forcing a trade-off between post-quantum security and contract interoperability.

This EIP resolves both problems by making ECRECOVER native-key-aware: ECDSA recovery results are gated against the on-chain native-key designation, and a new input mode enables contract-level verification of native-key signatures.

Specification

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

Constants

NameValueDescription
ECRECOVER_BASE_COST3000Existing ECDSA recovery gas cost (unchanged)
ML_DSA_44_VERIFY_COST50000Gas for ML-DSA-44 signature verification (matches EIP-8164)

Input Format

The precompile dispatches on byte 32 of its input:

  • If input[32] != 0xff: ECDSA mode. The input is the standard 128 bytes: hash (32) || v (32) || r (32) || s (32).
  • If input[32] == 0xff: Native-key mode. The input is variable-length: hash (32) || 0xff (1) || address (20) || signature (variable).

The 0xff sentinel is unambiguous: valid ECDSA v values are 27 or 28. Any input with 0xff at byte 32 already fails ECDSA recovery under current rules.

In native-key mode, the packing is tight starting at byte 33. The address occupies bytes 33 through 52. The signature begins at byte 53 and its length is scheme-dependent (2,420 bytes for ML-DSA-44, for a total input length of 2,473 bytes).

Return Value

Both modes return a 32-byte left-padded Ethereum address on success, or empty output (0 bytes) on failure. This preserves the existing ECRECOVER interface.

ECDSA Mode

ECDSA recovery proceeds as before, with an additional code check:

  1. Recover the address via ecrecover(hash, v, r, s). If recovery fails, return empty.
  2. Load the recovered address's account code. The address MUST be added to the transaction's accessed addresses set per EIP-2929.
  3. If the code begins with 0xef01 followed by a nonzero byte (a native-key designation per EIP-8164), return empty.
  4. Otherwise, return the recovered address left-padded to 32 bytes.

The code prefix 0xef0100 (EIP-7702 code delegation) is not a native-key designation. EIP-7702 delegated accounts retain valid ECDSA keys.

Native-Key Mode

When input[32] == 0xff:

  1. If the input is fewer than 54 bytes, return empty. No account access occurs.
  2. Parse address = input[33:53].
  3. Load the account's code. The address MUST be added to the transaction's accessed addresses set per EIP-2929.
  4. If the code does not begin with 0xef01 followed by a nonzero byte, return empty.
  5. Dispatch to the verification logic for the specific 0xef01XX prefix. If the prefix has no defined verification logic, return empty.

ML-DSA-44 Verification (0xef0101)

When the account's code begins with 0xef0101:

  1. Verify the input is exactly 2,473 bytes. Otherwise return empty.
  2. Extract pubkey = code[3:1315].
  3. Extract signature = input[53:2473].
  4. Verify ML_DSA_44_Verify(pubkey, input[0:32], signature) per FIPS 2041 Section 6 (Algorithm 3). The following strictness requirements apply (matching EIP-8164):
    • All encodings MUST be canonical per FIPS 204. Non-canonical encodings of public keys or signatures MUST be rejected.
    • The signature vector z coefficients MUST satisfy the norm bound check as specified in FIPS 204. Implementations MUST NOT skip or relax this check.
    • The hint vector h MUST have exactly the number of ones indicated by the signature metadata; duplicate or out-of-order indices MUST be rejected.
    • Implementations MUST produce identical accept/reject decisions for every possible (pubkey, message, signature) triple.
  5. If verification succeeds, return address left-padded to 32 bytes.
  6. If verification fails, return empty.

Gas Cost

ECDSA Mode

ComponentCost
Base recoveryECRECOVER_BASE_COST (3000)
Account access (on successful recovery)2600 cold / 100 warm per EIP-2929

If ecrecover itself fails (invalid v, r, or s), no account access occurs and only ECRECOVER_BASE_COST is charged.

Native-Key Mode

ComponentCost
Account access2600 cold / 100 warm per EIP-2929
ML-DSA-44 verification (0xef0101)ML_DSA_44_VERIFY_COST (50000)

Account access is always charged when the input is at least 54 bytes. If the input is fewer than 54 bytes, the cost is 0.

Verification cost is charged whenever the account has a recognized native-key delegation and the input is of the expected length for that scheme. It is charged regardless of whether verification succeeds or fails. Future native-key schemes define their own verification costs.

Rationale

Modifying ECRECOVER vs. New Precompile

Modifying the existing precompile at address 0x01 gives contracts the ECDSA guard for free. Every contract that calls ecrecover today — ERC-20 permits, meta-transaction verifiers, multisig confirmation checks — automatically rejects dead ECDSA keys after the fork without redeployment. A separate precompile for native-key verification would require every signature-checking contract to be updated, even for the guard behavior.

The 0xff Sentinel

The sentinel reuses the existing input layout. Byte 32 is the ECDSA v parameter, which is 27 or 28. The value 0xff is unambiguous and already causes ECDSA recovery to fail. Tight packing after the sentinel (address at byte 33, signature at byte 53) avoids wasting calldata gas on padding.

Forward Compatibility

The ECDSA guard checks the full 0xef0101–0xef01ff range, so future native-key schemes are guarded automatically without a precompile update. Verification dispatch, by contrast, requires explicit per-scheme logic — this is intentional. Each scheme has different signature sizes, verification algorithms, and gas costs. A generic dispatch would require either a variable-cost model negotiated at runtime or overly conservative gas pricing.

Returning Empty on Failure

All failure modes return empty (0 bytes) rather than reverting. This preserves the existing ecrecover interface where callers check for a zero return. Reverting would be a breaking change: existing contracts that use staticcall and check the return value would behave differently post-fork.

Gas Model

The ECDSA path charges account access only after successful recovery. If recovery fails (bad v, r, s), there is no address to look up and no access cost is incurred. The native-key path always charges account access because the target address is explicit in the input. Verification cost is charged on both success and failure to prevent gas-based signature validity oracles — an attacker should not be able to distinguish valid from invalid signatures by observing gas consumption.

Backwards Compatibility

This EIP introduces a behavioral change to the existing ECRECOVER precompile (address 0x01) that affects all callers.

In ECDSA mode, a successful recovery now incurs an additional account code lookup, increasing gas cost by 100 (warm) to 2,600 (cold) gas per EIP-2929. Contracts that pass a hardcoded gas stipend of exactly 3,000 to the precompile fail post-fork. In practice this is uncommon — most contracts forward remaining gas or use a generous allowance.

Contracts that verify ECDSA signatures from accounts that have migrated to a native key (EIP-8164) now receive an empty return where they previously received a valid address. This is intentional: it aligns contract-level signature validation with the protocol's view that the ECDSA key is permanently inert.

ERC-20 permit functions and ERC-2612 contracts benefit from the ECDSA guard automatically. Accepting signatures from native-key accounts requires callers to construct the native-key input format (0xff sentinel), which requires contract updates or wrapper contracts.

No new transaction type, opcode, or precompile address is introduced.

Test Cases

Pending.

Security Considerations

ECDSA Key Rejection Consistency

The ECDSA guard must produce results consistent with EIP-8164's transaction-level ECDSA rejection rule. If the precompile accepts an ECDSA signature that transaction validation would reject (or vice versa), contracts and the protocol hold inconsistent views of account authority. Implementations must check the same code prefix range (0xef0101–0xef01ff) and must not cache or defer the code lookup.

Account Code TOCTOU

The code lookup and signature verification occur atomically within the precompile call. An account's native-key delegation cannot change mid-execution: delegations are set during authorization list processing, before transaction execution begins. There is no time-of-check-to-time-of-use risk.

Malleability

The precompile inherits the ML-DSA-44 strictness requirements specified in EIP-8164, including canonical encoding validation, norm bound checking, and hint vector validation. No additional malleability surface is introduced.

Gas Griefing

An attacker can force a cold account access (2,600 gas) by supplying an arbitrary address in native-key mode. This is comparable to any opcode that touches account state, such as BALANCE or EXTCODESIZE, and does not represent a novel attack vector.

Forward Compatibility

When the target account's code begins with an 0xef01XX prefix that has no defined verification logic, the precompile returns empty. A contract cannot distinguish "no delegation" from "delegation with an unsupported scheme." This is not the ideal default, but it preserves the existing ecrecover interface where all failure modes return empty rather than reverting. Reverting would be a breaking change to the precompile's interface contract.

{
  "type": "standard",
  "id": 1,
  "author": [
    {
      "literal": "National Institute of Standards and Technology"
    }
  ],
  "title": "Module-Lattice-Based Digital Signature Standard",
  "DOI": "10.6028/NIST.FIPS.204",
  "URL": "https://csrc.nist.gov/pubs/fips/204/final",
  "original-date": {
    "date-parts": [
      [2024, 8, 13]
    ]
  }
}

Copyright and related rights waived via CC0.

Footnotes

  1. ↩
EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth