Web3 & Smart Contracts · 2 min read

Reverse Lookup of EVM Function Selectors

When you read calldata for an unverified contract, the function selector is just 4 bytes of hex with no name attached. To translate it into a human-readable function, you need keccak256. Every selector is the first 4 bytes of keccak256 over the canonical function signature, with no spaces and no parameter names. The lookup is one-way by design, but the search space for plausible signatures is small enough that databases and manual guessing both work.

Try it now

Keccak-256 Hasher

Runs in your browser, nothing leaves your device.

For a function like balanceOf(address), the canonical signature is the literal string balanceOf(address). Keccak256 of that string yields a 32-byte hash. The first 4 bytes are the selector: 0x70a08231. Solidity does this at compile time, but you can replicate it in any tool that supports keccak256. Note that keccak256 is not the same as SHA-3 despite being closely related, do not use a SHA-3 implementation by mistake.

Given an unknown selector, the practical approach is a forward search: take a database of known function signatures (4byte.directory, openchain.xyz), hash each one, and look for the matching first 4 bytes. Most common selectors are already indexed. For genuinely custom contracts, you may need to read the bytecode or look for hints in the deployer's other contracts.

If a selector is not in any public database, the function is either obscure, intentionally obfuscated, or part of a private contract. Some attackers craft custom function names to avoid showing up in selector databases. The selector itself is still deterministic, so once you suspect a signature, you can verify by hashing it yourself.

Common ERC-20 selectors

Input
transfer(address,uint256), balanceOf(address), approve(address,uint256)
Result
0xa9059cbb, 0x70a08231, 0x095ea7b3 (first 4 bytes of keccak256 over each signature)

Confirming a guessed signature

Input
Unknown selector 0x42842e0e on an NFT contract
Result
keccak256('safeTransferFrom(address,address,uint256)') starts with 0x42842e0e. Confirmed.

Security context

Selector collisions exist because 4 bytes is only 4.3 billion possibilities. A motivated attacker can grind function names until they find one that collides with a well-known selector, then deploy a contract where the malicious function answers to the friendly name's selector. When the stakes are high, do not trust the selector alone. Read the contract source if it is verified.

Solidity computes keccak256 of the function's canonical signature at compile time and uses the first 4 bytes as the selector. The compiler emits a dispatch table at the start of the contract's runtime bytecode that compares incoming calldata against each selector and jumps to the matching function.

Almost. Event topic 0 is the full 32-byte keccak256 of the event signature, not just the first 4 bytes. Same hash function, longer slice. Anonymous events skip topic 0 entirely.

Related techniques

Comparing (/4):

Tool Comparison

Feature
Type
Pricing
Platforms
Description