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
| Name | Value | Description |
|---|---|---|
ECRECOVER_BASE_COST | 3000 | Existing ECDSA recovery gas cost (unchanged) |
ML_DSA_44_VERIFY_COST | 50000 | Gas 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:
- Recover the address via
ecrecover(hash, v, r, s). If recovery fails, return empty. - Load the recovered address's account code. The address MUST be added to the transaction's accessed addresses set per EIP-2929.
- If the code begins with
0xef01followed by a nonzero byte (a native-key designation per EIP-8164), return empty. - 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:
- If the input is fewer than 54 bytes, return empty. No account access occurs.
- Parse
address = input[33:53]. - Load the account's code. The address MUST be added to the transaction's accessed addresses set per EIP-2929.
- If the code does not begin with
0xef01followed by a nonzero byte, return empty. - Dispatch to the verification logic for the specific
0xef01XXprefix. If the prefix has no defined verification logic, return empty.
ML-DSA-44 Verification (0xef0101)
When the account's code begins with 0xef0101:
- Verify the input is exactly 2,473 bytes. Otherwise return empty.
- Extract
pubkey = code[3:1315]. - Extract
signature = input[53:2473]. - 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
zcoefficients MUST satisfy the norm bound check as specified in FIPS 204. Implementations MUST NOT skip or relax this check. - The hint vector
hMUST 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.
- If verification succeeds, return
addressleft-padded to 32 bytes. - If verification fails, return empty.
Gas Cost
ECDSA Mode
| Component | Cost |
|---|---|
| Base recovery | ECRECOVER_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
| Component | Cost |
|---|---|
| Account access | 2600 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
Copyright and related rights waived via CC0.
