0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b
Text input, Ethereum Keccak padding 0x01
Hash text or hex bytes, extract selectors, compare expected hashes, and see how each 32-byte output maps to EVM primitives.
0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b
Text input, Ethereum Keccak padding 0x01
0xa9059cbb
Function selector candidate
calldata selector
event topic or storage key
address-sized suffix
| Input | Keccak256 Hash |
|---|
How keccak256 output maps to Ethereum primitives
a9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b
keccak256(“transfer(address,uint256)”)
bytes4)
0xa9059cbb → identifies transfer(address,uint256) calls
bytes32)
topic[0] in EVM logs; key in mapping storage slot derivation
Keccak256 is a cryptographic hash function from the Keccak family, producing a 256-bit (32-byte) output from any input of arbitrary length. It is the primary hash function used in Ethereum and the EVM, chosen for its security properties, resistance to length-extension attacks, and efficient hardware implementation.
In Solidity, keccak256 is a built-in function: keccak256(bytes memory input) returns (bytes32). It appears throughout smart contract development for computing function selectors, event topic hashes, storage slot keys, and commitment schemes.
Many developers confuse keccak256 with SHA3-256. They are NOT the same. Both are based on the same Keccak sponge construction, but NIST modified the padding domain separator when standardizing SHA-3 in FIPS 202. Ethereum adopted the original Keccak padding (0x01), not the NIST SHA-3 padding (0x06).
Important: If you use Python's hashlib.sha3_256() or Node.js's crypto.createHash('sha3-256'), you will get a different result than web3.utils.solidityKeccak256() or ethers.keccak256(). Always use a keccak256-specific library when working with Ethereum.
keccak256(publicKey), where publicKey is the uncompressed 64-byte ECDSA public key.
bytes4(keccak256("transfer(address,uint256)")) = 0xa9059cbb. The EVM uses this 4-byte prefix in calldata to dispatch calls to the correct function.
topic[0] in EVM logs is the full 32-byte keccak256(eventSignature). Unlike function selectors, the full hash is used to avoid log filtering collisions.
keccak256(abi.encode(key, baseSlot)). Understanding this is critical for storage layout analysis and attack vector discovery.
keccak256(0xff ++ deployerAddr ++ salt ++ keccak256(initcode)), last 20 bytes = deterministic contract address.
// Solidity
bytes32 hash = keccak256(abi.encodePacked("Hello, World!"));
bytes4 selector = bytes4(keccak256("transfer(address,uint256)"));
// Storage slot for mapping key
bytes32 slot = keccak256(abi.encode(userAddress, uint256(0)));
// ethers.js v6
import { keccak256, toUtf8Bytes, id } from "ethers";
// Hash a UTF-8 string
const hash = keccak256(toUtf8Bytes("Hello, World!"));
// Shorthand: hash a UTF-8 string (id = keccak256 of UTF-8)
const selector = id("transfer(address,uint256)").slice(0, 10);
// web3.js
const hash = web3.utils.keccak256("Hello, World!");
// Function selector
const selector = web3.eth.abi.encodeFunctionSignature("transfer(address,uint256)");
// Returns "0xa9059cbb"
When hashing multiple values together using abi.encodePacked, different input combinations can produce the same hash.
keccak256(abi.encodePacked("ab", "c"))
==
keccak256(abi.encodePacked("a", "bc"))
This has been exploited in real smart contract attacks for signature replay, authentication bypass, and Merkle proof forgery.
Always use abi.encode (not abi.encodePacked) when hashing multiple variable-length arguments together, or include explicit length prefixes.
Pre-computed hashes used frequently in Ethereum development
| Function / Event / Input | Keccak256 Hash | Used As | Action |
|---|---|---|---|
transfer(address,uint256) |
0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b |
Function selector (0xa9059cbb) | |
Transfer(address,address,uint256) |
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef |
Event topic[0] | |
Approval(address,address,uint256) |
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925 |
Event topic[0] | |
approve(address,uint256) |
0x095ea7b334ae44009aa867bfb386f5c3b4b443ac6f0ee573fa91c4608fbadfba |
Function selector (0x095ea7b3) | |
ownerOf(uint256) |
0x6352211e6566aa027e75ac9dbf2423197fbd9b82b9d981a3ab367d355866aa1c |
Function selector (0x6352211e) | |
“” (empty string) |
0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 |
Address checksum, CREATE2, codehash of EOA |
Keccak256 is a cryptographic hash function from the Keccak family. It accepts input of any length and produces a deterministic 256-bit (32-byte) output, always the same output for the same input, always different for different inputs (practically speaking). In Solidity, it is a built-in: keccak256(bytes memory input) returns (bytes32). Ethereum uses it everywhere: for function selectors, event topics, storage slot derivation, address generation, and more.
No, they are different, and this is a notorious source of bugs. Both algorithms are built on the same Keccak sponge construction, but NIST altered the padding domain separator when standardizing SHA-3 in FIPS 202. Ethereum uses the original Keccak padding byte (0x01), while NIST SHA-3 uses 0x06. As a result, keccak256("") = 0xc5d2460...a470, while sha3_256("") = 0xa7ffc6f...9344. Never use hashlib.sha3_256 or crypto.createHash('sha3-256') when computing Ethereum hashes.
Keccak256 is deeply embedded in the Ethereum protocol and Solidity language:
keccak256(publicKey).bytes4(keccak256("funcName(types)")), the 4-byte calldata prefix that routes function calls.topic[0] = full 32-byte keccak256(eventSignature).keccak256(abi.encode(key, slotIndex)).The keccak256 of an empty string is 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470. This is a well-known constant in Ethereum development. For example, an externally owned account (EOA) that has no deployed contract bytecode will have its extcodehash equal to this value. It is also the initial hash value used in some CREATE2 schemes. You can verify it with this tool using the empty string example chip above.
When multiple dynamic-length values are concatenated with abi.encodePacked before hashing, two different sets of inputs can produce the same packed encoding and therefore the same hash. For example: keccak256(abi.encodePacked("ab", "c")) equals keccak256(abi.encodePacked("a", "bc")) because both encode to the bytes of the string "abc". Attackers have exploited this in signature-based authorization (crafting alternative valid signatures), Merkle proof schemes, and multi-argument access control checks. The fix is to use abi.encode, which includes explicit type length prefixes that prevent such collisions.
Understand how keccak256 powers Ethereum's security model, and how misuse creates exploitable vulnerabilities. Our course covers hash-related attacks, storage layout, and advanced EVM internals.