Part III · Chapter 15 of 43 · Constantinople

EIP-1052: fingerprinting a contract in one opcode

To check whether another address runs exactly the bytecode you expect, you used to copy its entire code into memory and hash it yourself — an O(code-size) operation just to get a 32-byte fingerprint. EIP-1052 adds EXTCODEHASH, which returns that hash directly, in constant time.

Updated Jul 2, 2026 · 7 min
Assumed
  • accounts & code (EXTCODECOPY)
  • keccak256 hashing

Constantinople, February 2019. A contract often needs to know what another account is made of. Is this address a contract or a plain wallet? Is it running the exact bytecode I audited, or something I don’t recognize? The cleanest way to answer is with a fingerprint — a hash of the account’s code you can compare against a known value. The EVM could already hash things and could already read other accounts’ code, but it had no way to get that fingerprint cheaply: you had to haul the entire code into memory and hash it yourself. EIP-1052 adds the one opcode that skips the haul. Let’s derive it.

1 step Copy-then-hash

The problem: to hash the code, you first had to copy all of it

Before EIP-1052, the EVM’s tools for inspecting another account’s code were EXTCODESIZE Returns the length in bytes of the code at a given address. Useful, but a length isn't an identity — two different contracts can share a size. (its length) and EXTCODECOPY Copies a range of another account's code into the caller's memory. To fingerprint the code you had to copy all of it, then hash the copy — cost proportional to the code's size, plus memory-expansion gas. (its bytes). Neither gives you a fingerprint directly. So to obtain the keccak256 of a contract’s code — the thing you actually want for an identity check — you had to EXTCODECOPY the whole code into your own memory and then run KECCAK256 over it. The cost scales with the code’s size and pays memory-expansion gas on top, all to produce a single 32-byte value. For a large contract, that’s a lot of work for a comparison.

want: a 32-byte fingerprint of another contract's code other contract's code (could be huge) EXTCODECOPY copy all → memory KECCAK256 32-byte hash O(code size) + memory just to get 32 bytes expensive and wasteful for a simple identity check
Before EIP-1052, fingerprinting another contract's code meant EXTCODECOPY-ing all of it into memory and then KECCAK256-ing the copy — cost proportional to the code's size plus memory expansion, just to produce a 32-byte identity. Expensive and wasteful for a simple check.

→ Step 2: expose the code hash as its own opcode.

2 step Add EXTCODEHASH

EIP-1052: EXTCODEHASH returns the hash directly

The fix adds EXTCODEHASH Opcode 0x3f. Given an address, returns the keccak256 hash of that account's code in constant time — no copying. The node can serve it directly, since the code hash is part of an account's stored representation. (0x3f): give it an address, get back the keccak256 of that account’s code in a single, constant-time instruction — no copying, no memory expansion. But it comes with edges you must respect, all about the absence of code. A non-existent account An address that has never been touched — no balance, nonce, or code. EXTCODEHASH returns 0 for it, distinguishing 'nothing here' from 'here but codeless'. returns 0. An account that exists but has no code — a plain EOA, or a contract mid-construction — returns the empty-code hash keccak256 of the empty byte string (0xc5d2460186…), the code hash of any existing account with no deployed code. EXTCODEHASH returns this for EOAs, which is different from the 0 returned for non-existent accounts. , keccak256(""). Two distinct “no code” answers, and using the opcode correctly means telling them apart.

EXTCODEHASH(addr): the code hash, in one opcode addr keccak256(code) — O(1), no copying non-existent account → 0 exists but no code (EOA) → hash of the empty string two 'no code' cases to tell apart with care
EXTCODEHASH(addr) returns keccak256 of the account's code in one constant-time opcode — no copying. The sharp edges: a non-existent account returns 0, while an existing account with no code (an EOA) returns the empty-string hash. Two 'no code' cases to distinguish carefully.

→ Step 3: what the cheap fingerprint unlocks.

3 step Cheap identity checks

The payoff: verifying what you’re talking to

A constant-time code hash makes a whole family of checks practical. A contract can confirm a counterparty is running exactly the known-safe bytecode it expects before trusting it. It can distinguish contracts from EOAs (with the empty-code and construction caveats in mind). And it pairs naturally with CREATE2: after deploying to a deterministic address, a contract can EXTCODEHASH it to confirm the deployed code is precisely what was intended — a real safety check for factories and upgrade patterns. What used to be an O(code-size) copy-and-hash is now one O(1) opcode, cheap enough to do inline on a hot path.

cheap code-identity checks is the counterparty exactly the known-safe bytecode? contract or EOA? (mind the empty-code & construction cases) verify a CREATE2 deployment matches the expected code an O(code-size) operation becomes O(1)
EXTCODEHASH makes code-identity checks cheap: is a counterparty the exact known-safe bytecode? contract or EOA? does a CREATE2 deployment match the expected code? An O(code-size) copy-and-hash becomes an O(1) opcode you can afford on a hot path.
04 Go Deeper Where to take it from here