Precompile Summary
| Property | Value |
|---|---|
| Address | 0x01 |
| Name | ECRECOVER |
| Gas | 3000 |
| Input | 128 bytes: hash (32 bytes), v (32 bytes, only byte 31 matters: 27 or 28), r (32 bytes), s (32 bytes) |
| Output | 32 bytes (20-byte Ethereum address right-padded to 32 bytes) or empty (0 bytes) on error |
| Behavior | Recovers the signer’s Ethereum address from an ECDSA signature over a message hash using the secp256k1 curve. Returns the 20-byte address right-padded to 32 bytes. Returns empty (0 bytes) on invalid input rather than reverting. |
Threat Surface
ECRECOVER is the cryptographic backbone of Ethereum’s authentication model. Every transaction validation, every ecrecover call in a smart contract, and every off-chain signature verification scheme (EIP-712 permits, meta-transactions, gasless approvals) ultimately depends on this precompile. Its threat surface is subtle but devastating: unlike opcodes that cause obvious state changes, ECRECOVER’s failures are silent — it returns address(0) instead of reverting, it accepts malleable signatures without complaint, and it provides zero replay protection by design.
The threat surface divides into three categories:
1. Silent failure masquerading as success. ECRECOVER never reverts. On invalid input — wrong v value, out-of-range r or s, malformed data — it returns an empty output that Solidity’s abi.decode interprets as address(0). If a contract compares the recovered address against an uninitialized or default address(0) variable, an attacker can forge “valid” authentication by submitting garbage signature parameters. This is not a theoretical concern: it is a recurring audit finding across DeFi protocols.
2. Signature malleability breaking uniqueness assumptions. For every valid ECDSA signature (v, r, s), a second valid signature (v', r, secp256k1.N - s) exists (where v flips between 27 and 28). ECRECOVER accepts both. EIP-2 (Homestead) restricted transaction-level signatures to low-s values, but the precompile itself enforces no such restriction. Any contract using signatures as unique identifiers — nonce-less permit schemes, signature-based deduplication, off-chain order books — is vulnerable to an attacker producing a second valid signature without knowing the private key.
3. Complete absence of replay protection. ECRECOVER is a pure function: it takes a hash and signature components, and returns an address. It has no concept of nonces, chain IDs, contract addresses, or expiration. The same signature validates every time it is called, on every chain, in every contract. Replay protection is entirely the responsibility of the calling contract and the signed message structure. When developers omit chain IDs (pre-EIP-155 transactions), contract addresses (pre-EIP-712 signatures), or nonces (custom permit implementations), the result is cross-chain replay, cross-contract replay, or indefinite signature reuse — each of which has caused real losses in the tens of millions of dollars.
Smart Contract Threats
T1: Signature Malleability (High)
For any valid ECDSA signature (v, r, s) over a message hash, a “sister signature” (v', r, secp256k1.N - s) also recovers to the same address. The v value flips between 27 and 28. ECRECOVER accepts both forms without distinction.
-
Uniqueness assumption violation. Contracts that use the signature itself (or its hash) as a unique identifier — for example, to prevent double-spending in a nonce-less meta-transaction relay, or to deduplicate signed orders in an off-chain order book — can be bypassed. An attacker observes a valid signature, computes the sister signature (a trivial arithmetic operation requiring no private key), and submits it as a “new” signature that passes deduplication checks but recovers to the same signer.
-
EIP-2 does not protect contracts. EIP-2 (Homestead, March 2016) restricted valid transaction signatures to
s <= secp256k1.N / 2at the protocol level, preventing transaction malleability. However, this restriction applies only to transaction signature validation in the consensus layer — the ECRECOVER precompile itself accepts anysvalue in[1, secp256k1.N - 1]. Contracts must enforce low-s values independently. -
OpenZeppelin ECDSA library. Since v4.7.3, OpenZeppelin’s
ECDSA.recover()enforcess <= secp256k1.N / 2and rejects high-s signatures. Contracts using rawecrecoverwithout this wrapper remain vulnerable.
Why it matters: Signature malleability transforms a single authorization act into two distinct-looking authorizations. Any system that treats signatures as unique tokens — relay networks, gasless transaction pools, signature-indexed mappings — is exploitable without any private key compromise.
T2: Zero Address Return on Invalid Input (High)
ECRECOVER returns empty output (0 bytes) on invalid input rather than reverting. When Solidity’s abi.decode processes this empty output, it produces address(0). If a contract compares the recovered address against an uninitialized or default address(0) signer variable, an attacker can forge authentication by providing deliberately invalid signature parameters.
-
Uninitialized signer variables. A pattern like
require(ecrecover(hash, v, r, s) == signer)is exploitable ifsignerwas never explicitly set (defaults toaddress(0)in Solidity). The attacker provides anyvvalue outside{27, 28}(e.g.,v = 0), causing ecrecover to returnaddress(0), which matches the uninitializedsigner. -
Deleted or zeroed signer mappings. Contracts that delete a signer from a mapping (
delete signers[key]) and later checkrequire(ecrecover(...) == signers[key])are vulnerable: the mapping returnsaddress(0)for missing keys, matching ecrecover’s failure output. -
No revert on failure. Unlike most precompiles and library functions, ecrecover’s failure mode is a silent return of a valid-looking address (
address(0)) rather than a revert. This violates the principle of least surprise and has been the root cause of multiple audit-critical findings.
Why it matters: The address(0) return transforms ecrecover’s error condition into a universal authentication bypass. Any contract that can reach a state where the expected signer is address(0) — through uninitialization, deletion, or default values — is vulnerable to trivial signature forgery.
T3: Signature Replay (Critical)
ECRECOVER is a stateless, pure function. It has no concept of nonces, expiration, chain identity, or contract identity. The same (hash, v, r, s) tuple returns the same address every time, on every chain, in every contract, forever. Replay protection is entirely the responsibility of the signed message structure and the verifying contract.
-
Cross-chain replay. A signature valid on Ethereum mainnet is equally valid on any EVM chain (Optimism, Arbitrum, BSC, Polygon, etc.) if the signed message does not include a chain ID. Before EIP-155 (Spurious Dragon, November 2016), transaction signatures omitted the chain ID entirely. After the ETH/ETC chain split (July 2016), transactions signed on one chain could be replayed on the other, draining over 40,000 ETC from exchanges.
-
Cross-contract replay. A signature intended for Contract A is valid for Contract B if the signed data does not include the verifying contract’s address. EIP-712 domain separators include both
chainIdandverifyingContract, but custom implementations often omit one or both. -
Indefinite temporal replay. Without an expiration timestamp or nonce in the signed message, a signature remains valid indefinitely. A permit signature granted for a one-time approval can be replayed after the approval is consumed and re-granted, or after the signer acquires new tokens.
-
EIP-712 and EIP-2612. These standards provide structured data signing with domain separators (chain ID, contract address, name, version) and nonces. However, adoption is not universal, and many custom signature schemes — particularly in newer DeFi protocols and cross-chain bridges — implement ad hoc signing that omits critical replay protection fields.
Why it matters: Signature replay is the highest-impact ecrecover vulnerability class in terms of real-world losses. The Optimism OP token theft ($17.6M, 2022) and the ETH/ETC chain split replays (40,000+ ETC, 2016) both stem from missing replay protection in signed messages verified via ecrecover.
T4: Frontrunning of Signature-Based Transactions (Medium)
Signed messages submitted to the public mempool can be observed by MEV searchers and frontrun. An attacker extracts the signature from a pending transaction and uses it in their own transaction before the original sender’s transaction is mined.
-
Permit frontrunning. A user submits a transaction containing
permit(owner, spender, value, deadline, v, r, s)followed bytransferFrom(owner, spender, amount). An attacker observing the mempool extracts the permit signature and frontruns with just thepermitcall. The original transaction’spermitcall then reverts (nonce already consumed), but if thetransferFromis in the same transaction, it still executes because the approval was already set by the attacker’s frontrun. More sophisticated variants use the extracted permit to set approval for the attacker’s own address. -
Meta-transaction extraction. In gasless transaction systems, a relayer submits a signed meta-transaction on behalf of the user. An attacker who observes the relayer’s pending transaction can extract the user’s signature and submit it through a different relayer or directly, potentially stealing the relayer’s fee or executing the action in a different context.
-
Order book signature theft. Off-chain order books (e.g., 0x-style limit orders) where signed orders are broadcast to a peer-to-peer network are vulnerable to frontrunning: an attacker sees a favorable signed order and fills it before the intended counterparty.
Why it matters: Frontrunning exploits the gap between signature creation and on-chain execution. While not a flaw in ecrecover itself, the precompile’s design — where a detached signature can be used by anyone who possesses it — makes all signature-based transaction patterns inherently vulnerable to mempool observation.
Protocol-Level Threats
P1: EIP-2 Scope Gap — Transaction-Level vs. Precompile-Level Malleability Protection
EIP-2 (Homestead, March 2016) restricted valid transaction signatures to low-s values (s <= secp256k1.N / 2), eliminating transaction-level signature malleability. However, this restriction was implemented in the transaction validation layer of the consensus client, not in the ECRECOVER precompile. The precompile continues to accept any s value in [1, secp256k1.N - 1].
This creates a dangerous asymmetry: developers who are aware that “Ethereum fixed signature malleability” in Homestead may incorrectly assume that ecrecover also rejects high-s signatures. It does not. Every smart contract using ecrecover for signature verification must independently enforce s <= secp256k1.N / 2 or use a library (OpenZeppelin ECDSA >= 4.7.3) that does.
P2: Client Implementation Divergence on Edge Cases
Different EVM client implementations (geth, Nethermind, Besu, Erigon, Reth) each implement the secp256k1 recovery independently or via different underlying libraries. While the core recovery algorithm is well-specified, edge case handling may diverge:
vvalues outside {27, 28}. The spec requiresvto be 27 or 28 (or 0/1 in some contexts), but clients may differ in how they handlev = 0,v = 1,v = 2, or values > 28.- Oversized inputs. Inputs longer than 128 bytes should have surplus bytes ignored, but implementation behavior may vary.
- Undersized inputs. Inputs shorter than 128 bytes are right-padded with zeros. The resulting recovery may produce different addresses depending on how the padding interacts with the signature parameters.
Any divergence between clients on these edge cases risks consensus splits — the same transaction producing different results on different nodes.
P3: Post-EIP-7702 Account Abstraction Implications
EIP-7702 allows EOAs to delegate to contract code, blurring the line between EOAs and contracts. For ecrecover-based verification:
tx.originchecks become unreliable. Contracts that userequire(tx.origin == ecrecover(...))to verify that the transaction sender is the signer may break when the signer is a delegated EOA executing through contract logic.- Signature context changes. With account abstraction, the entity that signs a message may not be the entity that submits the transaction, creating new vectors for signature extraction and replay.
Edge Cases
| Edge Case | Behavior | Security Implication |
|---|---|---|
v = 0 or v = 1 (instead of 27/28) | Returns empty output (0 bytes), decoded as address(0) by Solidity | Attacker can trigger address(0) return to match uninitialized signer variables |
v = 27 with invalid r or s | Returns empty output (0 bytes) | Same address(0) bypass risk as above |
| Input shorter than 128 bytes | Right-padded with zeros; recovery proceeds on padded data | May produce an unexpected address recovery from truncated parameters — contracts assuming full 128 bytes may be surprised |
| Input longer than 128 bytes | Surplus bytes beyond 128 are silently ignored | No direct security impact, but violates least-surprise if a contract expects strict input validation |
hash = 0x00...00 (32 zero bytes) | Valid input; recovers an address (the address corresponding to the private key that signed the zero hash) | Theoretically valid but practically no one controls the recovered address; not exploitable unless a contract uses hash = 0 as a sentinel |
r = 0 or s = 0 | Returns empty output (invalid point on curve) | Triggers address(0) return; exploitable via T2 |
r >= secp256k1 field prime or s >= curve order N | Returns empty output (out of range) | Triggers address(0) return; exploitable via T2 |
s > secp256k1.N / 2 (high-s value) | Valid recovery; returns the same address as the low-s sister signature | ECRECOVER does not enforce EIP-2 low-s restriction; exploitable via T1 (malleability) |
Valid signature with v = 27 and same with v = 28 | Each recovers a different address (two distinct public keys can produce the same (r, s) for a given hash) | Not exploitable per se, but confirms that v is essential for unique address recovery |
Real-World Exploits
Exploit 1: Optimism OP Token Theft — $17.6M via Cross-Chain Signature Replay (2022)
Root cause: Signatures intended for one chain were replayed on Optimism because the signed message structure lacked adequate chain-specific replay protection. The attacker did not need to forge any signature — they reused legitimate signatures verified via ecrecover.
Details: In June 2022, Wintermute (a market maker) was allocated 20 million OP tokens by the Optimism Foundation. Due to a miscommunication, the tokens were sent to a multi-sig address that Wintermute had not yet deployed on Optimism (it existed on Ethereum mainnet). An attacker observed the pending deployment transactions and replayed the token transfer on Optimism before the multi-sig was properly deployed, extracting approximately 20 million OP tokens (~$17.6M at the time).
The core issue was that the signatures authorizing the transfer were valid on Optimism because the signing scheme did not bind the authorization to a specific chain in a way that prevented cross-chain replay.
ECRECOVER’s role: ECRECOVER was the verification mechanism that accepted the replayed signatures. Because it is a pure function with no chain awareness, it returned the same signer address on Optimism as on mainnet. The precompile correctly did its job — the vulnerability was in the absence of chain-binding in the signed data structure.
Impact: 20M OP tokens ($17.6M) stolen. Approximately 1M OP tokens were later returned by the attacker, but the majority of the loss was permanent.
References:
Exploit 2: ETH/ETC Chain Split Signature Replay — 40,000+ ETC Drained (2016)
Root cause: Before EIP-155, Ethereum transaction signatures did not include a chain ID. After the DAO hard fork split Ethereum into ETH and ETC (July 2016), any transaction signed on one chain was valid on the other.
Details: When the Ethereum community hard forked to recover DAO funds, the original chain continued as Ethereum Classic (ETC). Because pre-fork transactions and post-fork transactions used identical signature formats (no chain ID), any ETH transaction could be “replayed” on ETC and vice versa. Attackers systematically monitored ETH transactions and replayed them on ETC, draining over 40,000 ETC from exchanges and users who were unaware of the replay risk.
EIP-155 (Spurious Dragon, November 2016) resolved this by including the chain ID in the transaction signing hash, making signatures chain-specific. However, EIP-155 only protects transaction-level signatures. Smart contract signatures verified via ecrecover remain vulnerable to cross-chain replay unless the signed message independently includes a chain ID (as in EIP-712 domain separators).
ECRECOVER’s role: ECRECOVER was the mechanism that validated replayed signatures on the target chain. Its stateless, chain-unaware design meant that identical signatures were valid on both ETH and ETC.
Impact: 40,000+ ETC drained from exchanges. Led directly to the creation of EIP-155 (chain ID in transaction signatures) and indirectly to EIP-712 (chain ID in structured data signing).
References:
Exploit 3: Widespread Replay Vulnerabilities in Signature-Verification Contracts (Ongoing)
Root cause: Systematic omission of replay protection fields (chain ID, contract address, nonces) in custom signature verification implementations using ecrecover.
Details: A 2025 academic study analyzing 15,383 deployed contracts containing signature-verification logic found 1,739 contracts vulnerable to at least one form of signature replay. The vulnerable contracts collectively held approximately $4.76M at the time of analysis. The most common omissions were: missing nonce tracking (allowing indefinite replay of the same signature), missing chain ID (allowing cross-chain replay), and missing contract address (allowing cross-contract replay).
These vulnerabilities are not limited to amateur code. Production DeFi protocols, NFT marketplaces, and bridge contracts have been found with inadequate replay protection in audit after audit. The root cause is consistent: developers treat ecrecover as an authentication primitive and assume it provides guarantees (uniqueness, chain-binding, expiration) that it fundamentally does not.
ECRECOVER’s role: ECRECOVER’s stateless design means it provides zero built-in replay protection. Every guarantee — nonce tracking, chain binding, temporal expiration — must be implemented by the calling contract in the signed message hash.
Impact: 1,739 vulnerable contracts holding ~$4.76M identified in a single study. The true scope across all EVM chains is likely much larger.
References:
Attack Scenarios
Scenario A: Signature Malleability Bypass (Double-Spend via Sister Signature)
contract VulnerableRelay {
mapping(bytes32 => bool) public executedSignatures;
function executeMetaTx(
address signer,
address to,
uint256 value,
bytes calldata data,
uint8 v,
bytes32 r,
bytes32 s
) external {
bytes32 hash = keccak256(abi.encodePacked(signer, to, value, data));
bytes32 sigId = keccak256(abi.encodePacked(v, r, s));
// VULNERABLE: uses signature as unique identifier
require(!executedSignatures[sigId], "already executed");
require(ecrecover(hash, v, r, s) == signer, "invalid sig");
executedSignatures[sigId] = true;
(bool ok,) = to.call{value: value}(data);
require(ok, "call failed");
}
}
// Attack:
// 1. User signs a meta-tx with (v=27, r, s). Relayer submits it. sigId is recorded.
// 2. Attacker computes sister signature: v'=28, r'=r, s'= secp256k1.N - s
// 3. keccak256(abi.encodePacked(28, r, N-s)) != sigId -- passes dedup check
// 4. ecrecover(hash, 28, r, N-s) == signer -- passes auth check
// 5. Meta-tx executes a second time. Attacker double-spends the signed action.Scenario B: Zero Address Forgery (Authentication Bypass via Uninitialized Signer)
contract VulnerableVault {
mapping(uint256 => address) public vaultOwners;
mapping(uint256 => uint256) public vaultBalances;
function createVault(uint256 vaultId) external payable {
require(vaultOwners[vaultId] == address(0), "exists");
vaultOwners[vaultId] = msg.sender;
vaultBalances[vaultId] += msg.value;
}
function withdrawWithSig(
uint256 vaultId,
uint8 v,
bytes32 r,
bytes32 s
) external {
bytes32 hash = keccak256(abi.encodePacked(vaultId, msg.sender));
// VULNERABLE: if vaultOwners[vaultId] was never set or was deleted,
// it defaults to address(0). Providing v=0 makes ecrecover return
// address(0), matching the uninitialized owner.
require(ecrecover(hash, v, r, s) == vaultOwners[vaultId], "unauthorized");
uint256 amount = vaultBalances[vaultId];
vaultBalances[vaultId] = 0;
payable(msg.sender).transfer(amount);
}
}
// Attack:
// 1. Find a vaultId that was never created (vaultOwners[vaultId] == address(0))
// but somehow has a balance (e.g., via direct ETH transfer or another bug)
// 2. Call withdrawWithSig(vaultId, 0, bytes32(0), bytes32(0))
// 3. ecrecover returns address(0) because v=0 is invalid
// 4. address(0) == address(0) -- check passes
// 5. Attacker drains the vaultScenario C: Cross-Chain Permit Replay
contract VulnerableToken {
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
// VULNERABLE: domain separator omits chainId
bytes32 public DOMAIN_SEPARATOR = keccak256(abi.encode(
keccak256("EIP712Domain(string name,address verifyingContract)"),
keccak256("VulnerableToken"),
address(this)
));
bytes32 public constant PERMIT_TYPEHASH = keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
);
mapping(address => uint256) public nonces;
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(block.timestamp <= deadline, "expired");
bytes32 structHash = keccak256(abi.encode(
PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline
));
bytes32 digest = keccak256(abi.encodePacked(
"\x19\x01", DOMAIN_SEPARATOR, structHash
));
// ecrecover is chain-agnostic: this signature is valid on ANY chain
// where this contract is deployed at the same address
require(ecrecover(digest, v, r, s) == owner, "invalid sig");
allowance[owner][spender] = value;
}
}
// Attack:
// 1. Token is deployed at same address on Ethereum and Arbitrum (e.g., via CREATE2)
// 2. User signs a permit on Ethereum: approve spender for 1000 tokens
// 3. DOMAIN_SEPARATOR is identical on both chains (no chainId!)
// 4. Nonces may also be in sync if the user has the same tx count on both chains
// 5. Attacker replays the permit signature on Arbitrum
// 6. ecrecover returns the same owner address -- permit succeeds on Arbitrum
// 7. Attacker drains the user's Arbitrum token balanceMitigations
| Threat | Mitigation | Implementation |
|---|---|---|
| T1: Signature malleability | Enforce low-s values | Use OpenZeppelin ECDSA.recover() (>= v4.7.3) which rejects s > secp256k1.N / 2; or manually check require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) |
| T1: Signature-as-identifier | Use hash-of-message as identifier, not hash-of-signature | Key deduplication on keccak256(abi.encodePacked(signer, nonce, action)) rather than on the signature bytes |
| T2: Zero address return | Always check for address(0) after recovery | address recovered = ecrecover(hash, v, r, s); require(recovered != address(0), "invalid signature"); |
| T2: Uninitialized signer | Validate signer is non-zero before comparison | require(signer != address(0), "signer not set"); require(recovered == signer, "unauthorized"); |
| T3: Cross-chain replay | Include chain ID in signed data | Use EIP-712 domain separator with chainId field; recompute DOMAIN_SEPARATOR dynamically if chain ID can change (post-fork) |
| T3: Cross-contract replay | Include contract address in signed data | Use EIP-712 domain separator with verifyingContract field |
| T3: Temporal replay | Include nonce and/or deadline | Implement per-signer incrementing nonces (EIP-2612 pattern); include deadline timestamp in signed struct |
| T4: Permit frontrunning | Make permit failure non-fatal | Wrap permit in a try-catch so the transaction continues even if permit was already consumed by a frontrunner |
| General | Use battle-tested libraries | Use OpenZeppelin ECDSA.recover() + EIP712 + ERC20Permit rather than raw ecrecover |
Compiler/EIP-Based Protections
- EIP-2 (Homestead, March 2016): Restricted valid transaction signatures to
s <= secp256k1.N / 2, eliminating transaction-level malleability. Does NOT apply to the ecrecover precompile — contracts must enforce this independently. - EIP-155 (Spurious Dragon, November 2016): Added chain ID to transaction signing hash, preventing cross-chain transaction replay. Does NOT protect smart contract signatures — those must include chain ID in the signed message (e.g., via EIP-712).
- EIP-712 (2017): Structured data signing standard with domain separator containing
name,version,chainId, andverifyingContract. Provides comprehensive replay protection when fully implemented. - EIP-2612 (2020): Standardized
permit()for ERC-20 tokens using EIP-712, with per-owner incrementing nonces and deadline-based expiration. The gold standard for signature-based token approvals. - OpenZeppelin ECDSA >= v4.7.3: Enforces low-s values, rejects
address(0)recovery, and providestryRecover()for graceful error handling. All contracts should use this instead of rawecrecover.
Severity Summary
| Threat ID | Category | Severity | Likelihood | Real-World Precedent |
|---|---|---|---|---|
| T1 | Smart Contract | High | Medium | Signature malleability bypasses in meta-transaction relays, order books, and nonce-less permit schemes. Mitigated by OpenZeppelin ECDSA but raw ecrecover usage remains common. |
| T2 | Smart Contract | High | Medium | Recurring audit finding: ecrecover returning address(0) matched against uninitialized signer variables. Multiple DeFi protocols affected. |
| T3 | Smart Contract | Critical | High | Optimism OP token theft (4.76M at risk). |
| T4 | Smart Contract | Medium | Medium | Permit frontrunning is a known MEV vector; mitigated by try-catch patterns but widely under-addressed. |
| P1 | Protocol | Medium | N/A | EIP-2 scope gap creates false confidence; developers assume ecrecover rejects high-s values when it does not. |
| P2 | Protocol | Low | Low | No known consensus split from ecrecover edge cases, but divergence risk exists across client implementations. |
| P3 | Protocol | Medium | Low | EIP-7702 account abstraction changes are recent; full impact on ecrecover-based verification patterns is still emerging. |
Related Precompiles
| Precompile | Relationship |
|---|---|
| SHA256 (0x02) | Often used alongside ecrecover for hashing before signature verification. Some protocols hash the message with SHA-256 before passing it to ecrecover (though keccak256 is more common in Ethereum-native contexts). |
| BN256ADD (0x06), BN256MUL (0x07), BN256PAIRING (0x08) | Alternative signature schemes (BLS signatures) use these bn256 curve precompiles. BLS signatures offer aggregation properties that ECDSA/ecrecover lacks, making them attractive for multi-signer verification in rollups and consensus protocols. |
| IDENTITY (0x04) | Sometimes used for memory copy operations in signature processing pipelines. The identity precompile copies input to output, useful for returndatacopy-style patterns in low-level signature handling. |