Keccak-256 Hash Calculator
Compute the Keccak-256 hash Ethereum uses, from text or hex. You also get the SHA3-256 hash and the 4-byte function selector.
0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b0xa9059cbb0x4b40e901eada9ab2d6dfa2a4e5f5088af21b56bb877126cc83f68849c4aa9609Keccak-256 in Ethereum
Keccak-256 is the hash function at the heart of Ethereum. It derives event topics, function selectors, storage slots and the addresses of contracts. When you see a 32-byte hash in a log or an ABI, it almost always came from Keccak-256.
A common gotcha: Ethereum's Keccak-256 is not identical to NIST SHA3-256. They differ in a padding constant, so a SHA3-256 library will give the wrong answer for Ethereum work. This tool shows both side by side so you can confirm which one you need.
The canonical signature, and why yours does not match
Selectors and topics are hashes of a string, and the string has to be written exactly one way. Almost every "my selector is wrong" bug is a signature that looks right to a human and is a different string to the hash function.
No spaces anywhere. No parameter names. Types spelled in full, so uint256 and not the uint alias that Solidity lets you write, and int256 not int. Structs flatten into a parenthesised tuple of their field types. Enums become uint8, and contract types become address.
transfer(address,uint256) // correct -> 0xa9059cbb
transfer(address, uint256) // space -> different hash
transfer(address to,uint256 amt) // names -> different hash
transfer(address,uint) // uint alias -> different hash
// A struct parameter flattens into a tuple:
// struct Order { address maker; uint256 price; }
fill((address,uint256),bytes)
// Arrays keep their brackets:
batchTransfer(address[],uint256[])Two more places the same rule applies. Errors are selectors too, so a revert that comes back as four opaque bytes is just InsufficientBalance(uint256,uint256) hashed the same way, which is how a decoder turns it back into a readable name. And events use the full 32 bytes rather than the first four, which is what topic0 is.
Topics, storage slots and addresses
The same hash shows up in four places you will meet constantly, and knowing the formula for each saves a lot of guessing at a debugger.
import { id, keccak256, AbiCoder, getCreateAddress } from "ethers";
// 1. Event topic0: hash the event signature.
id("Transfer(address,address,uint256)");
// 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
// 2. Mapping slot: keccak256(abi.encode(key, declarationSlot)).
const coder = AbiCoder.defaultAbiCoder();
keccak256(coder.encode(["address", "uint256"], [holder, 0n]));
// -> the storage slot holding balanceOf[holder]
// 3. Dynamic array data: keccak256(abi.encode(declarationSlot)),
// then element i lives at that hash + i.
keccak256(coder.encode(["uint256"], [2n]));
// 4. Contract address from a normal deploy: hash of sender + nonce.
getCreateAddress({ from: deployer, nonce: 7 });Only indexed event parameters become topics, at most three of them after topic0, and everything else is ABI-encoded into data. Indexed strings and bytes are stored as the hash of their contents rather than the contents, so you can filter for a value you already know and you cannot read it back out of the log.
Once you have topic0, the filter itself is the expensive part. eth_getLogs is the call shared providers restrict hardest, because a wide range over a busy topic makes the node do real work; block range limits exist for exactly that reason. Reading storage slots directly with eth_call has the same shape of problem at scale, and the words that come back need the hex converter before they mean anything.
Frequently asked questions
Is Keccak-256 the same as SHA3-256?
No. Ethereum uses the original Keccak submission, which differs from the finalized NIST SHA3-256 standard by one padding byte. The hashes are different, so this tool shows both.
How do I get a function selector?
Hash the canonical function signature, for example transfer(address,uint256), and take the first 4 bytes. This tool shows that selector below the full hash.
Why does my selector not match the one on the explorer?
Almost always because the signature is not canonical. Drop every space and parameter name, and write the full type: uint256 rather than uint, and (address,uint256) for a struct. transfer(address, uint256) with a space hashes to something completely different.
What is topic0 in a log?
The Keccak-256 hash of the event signature, for example Transfer(address,address,uint256). Nodes index logs by topic, so hashing the signature here gives you the exact value to filter on with eth_getLogs.
Why do only some event parameters appear in topics?
Only parameters marked indexed become topics, and an event can have at most three of them beyond topic0. Everything else is ABI-encoded into the data field. Indexed dynamic types such as string and bytes are stored as the hash of the value, so you can filter for a known string but you cannot recover it from the log.
Text or hex input, which should I use?
Use text to hash a string such as a function signature. Use hex to hash raw bytes, for example packed ABI data, where the input is already a 0x hex string.
Does the hashing happen on a server?
No. Hashing runs locally in your browser with the js-sha3 library. Your input never leaves the page.
A topic hash is only useful pointed at a node
Once you have topic0 you still have to run the filter, and eth_getLogs is where shared gateways push back hardest: block-range caps, throttling, and truncated results on exactly the queries you care about. A node you are running on has no reason to say no.
Why eth_getLogs has block range limits