Try it Live Run Keccak256 examples in the interactive playground
Future Plans: This page is planned and under active development. Examples are placeholders and will be replaced with accurate, tested content.
Semantic Hash Type - Keccak256Hash extends Bytes32 with a keccak256 semantic flag. Same runtime representation (32 bytes), different compile-time meaning for type safety.
Overview
Keccak256Hash is a branded Uint8Array that extends Bytes32 with additional semantic meaning. It represents the output of a keccak256 hash operation through TypeScript branding.
While Bytes32 is a generic 32-byte value, Keccak256Hash explicitly communicates “this came from a keccak256 operation” at compile-time with zero runtime overhead.
import { Keccak256 } from '@tevm/voltaire/Keccak256' ;
import * as Bytes32 from '@tevm/voltaire/Bytes32' ;
// Keccak256Hash output
const hash = Keccak256 . hash ( data );
// Convert to Bytes32 for generic operations
const bytes = Bytes32 . from ( hash );
// Both are 32 bytes at runtime
console . log ( hash . length ); // 32
console . log ( bytes . length ); // 32
Type Definition
Keccak256Hash extends Bytes32 with a keccak256 semantic symbol:
import type { brand } from '@tevm/voltaire/brand' ;
import type { BrandedBytes } from '@tevm/voltaire/Bytes' ;
type Keccak256Hash = BrandedBytes < 32 > & {
readonly [ Symbol . for ( "keccak256" )] : true ;
};
Type structure:
Base: Uint8Array (32 bytes)
Brand: { readonly [brand]: "Bytes32" }
Size: { readonly size: 32 }
Semantic: { readonly [Symbol.for("keccak256")]: true }
This layered branding provides:
Runtime : Plain Uint8Array (zero overhead)
Compile-time : Type safety preventing mixing hash types
Semantic : Documents this value came from keccak256
Relationship to Bytes32
Keccak256Hash and Bytes32 are the same size (32 bytes) but convey different semantics:
import { Keccak256 } from '@tevm/voltaire/Keccak256' ;
import * as Bytes32 from '@tevm/voltaire/Bytes32' ;
// Keccak256Hash = semantic "this is a keccak256 hash"
const txHash : Keccak256Hash = Keccak256 . hash ( txData );
// Bytes32 = generic 32-byte value
const storageSlot : Bytes32Type = Bytes32 . from ( 0 );
// Same runtime representation
console . log ( txHash instanceof Uint8Array ); // true
console . log ( storageSlot instanceof Uint8Array ); // true
// Different compile-time types
type HashType = typeof txHash ; // Keccak256Hash
type BytesType = typeof storageSlot ; // Bytes32Type
When to use each:
Keccak256Hash - Transaction hashes, block hashes, merkle nodes, keccak256 outputs
Bytes32 - Storage slots, generic 32-byte values, numeric conversions
See Bytes32 documentation for generic 32-byte operations.
Migration from Hash Primitive
Old Hash primitive replaced by Keccak256Hash for clarity:
// OLD (deprecated Hash primitive)
import { Keccak256 } from '@tevm/voltaire/Keccak256' ;
const hash = Keccak256 . hash ( data );
// NEW (Keccak256Hash type)
import { Keccak256 } from '@tevm/voltaire/Keccak256' ;
const hash = Keccak256 . hash ( data );
Migration steps:
Replace Keccak256.hash() with Keccak256.hash()
Replace HashType type with Keccak256Hash
All operations remain the same (same 32-byte structure)
The new approach is more explicit about which hash algorithm produced the value.
When to Use Keccak256Hash vs Bytes32
Use Keccak256Hash when:
// Transaction hashes
const txHash = Keccak256 . hash ( txData );
// Block hashes
const blockHash = Keccak256 . hash ( blockHeader );
// Merkle tree nodes
const merkleNode = Keccak256 . hashMultiple ([ left , right ]);
// Event topics
const topic = Keccak256 . topic ( 'Transfer(address,address,uint256)' );
// Any value that came from keccak256
const digest = Keccak256 . hash ( message );
Use Bytes32 when:
import * as Bytes32 from '@tevm/voltaire/Bytes32' ;
// Storage slots
const slot = Bytes32 . from ( 0 );
// Generic 32-byte values
const padding = Bytes32 . zero ();
// Numeric conversions
const value = Bytes32 . from ( 42 n );
// When hash algorithm doesn't matter
const genericHash : Bytes32 . Bytes32Type = Bytes32 . from ( anyHash );
Constructors
All Keccak256Hash values come from Keccak256 module methods:
Keccak256.hash
Direct hashing of bytes:
import { Keccak256 } from '@tevm/voltaire/Keccak256' ;
const data = new Uint8Array ([ 1 , 2 , 3 , 4 , 5 ]);
const hash : Keccak256Hash = Keccak256 . hash ( data );
Keccak256.hashString
Hash UTF-8 string:
const hash : Keccak256Hash = Keccak256 . hashString ( 'hello world' );
Keccak256.hashHex
Hash hex-encoded string:
const hash : Keccak256Hash = Keccak256 . hashHex ( '0xdeadbeef' );
Keccak256.hashMultiple
Hash multiple chunks:
const hash : Keccak256Hash = Keccak256 . hashMultiple ([ chunk1 , chunk2 , chunk3 ]);
Keccak256.topic
Event topic (full 32-byte hash):
const topic : Keccak256Hash = Keccak256 . topic ( 'Transfer(address,address,uint256)' );
See Keccak256 index for all hash methods.
Conversions
Keccak256Hash can be converted using Bytes32 operations:
toHex
Convert to hex string:
import * as Bytes32 from '@tevm/voltaire/Bytes32' ;
const hash = Keccak256 . hash ( data );
const hex = Bytes32 . toHex ( hash );
// "0x..." (64 hex characters)
toBytes
Convert to plain Uint8Array:
const bytes = Bytes32 . toUint8Array ( hash );
console . log ( bytes instanceof Uint8Array ); // true
toBigint
Convert to bigint (big-endian):
const value = Bytes32 . toBigint ( hash );
console . log ( typeof value ); // "bigint"
toAddress
Extract address (last 20 bytes):
import { Keccak256 } from '@tevm/voltaire/Keccak256' ;
// Ethereum address derivation
const pubKeyHash = Keccak256 . hash ( publicKey );
const address = Bytes32 . toAddress ( pubKeyHash );
Operations
equals
Check equality:
import * as Bytes32 from '@tevm/voltaire/primitives/Bytes/Bytes32' ;
const hash1 = Keccak256 . hash ( data1 );
const hash2 = Keccak256 . hash ( data2 );
const same = Bytes32 . equals ( hash1 , hash2 );
compare
Compare two hashes:
const cmp = Bytes32 . compare ( hash1 , hash2 );
// -1 if hash1 < hash2
// 0 if hash1 === hash2
// 1 if hash1 > hash2
isZero
Check if all zeros (rare for cryptographic hashes):
const isEmpty = Bytes32 . isZero ( hash );
clone
Create independent copy:
const copy = Bytes32 . clone ( hash );
See Bytes32 documentation for all operations.
Ethereum Use Cases
Transaction Hashes
import { Keccak256 } from '@tevm/voltaire/Keccak256' ;
import * as Transaction from '@tevm/voltaire/Transaction' ;
// Hash transaction for signing
const tx = Transaction . from ({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f51e3e' ,
value: 1000000000000000000 n ,
nonce: 5 n ,
gasLimit: 21000 n ,
maxFeePerGas: 20000000000 n ,
maxPriorityFeePerGas: 1000000000 n ,
});
const txHash : Keccak256Hash = Keccak256 . hash ( Transaction . toBytes ( tx ));
Block Hashes
// Block header hash
const blockHeaderData = encodeBlockHeader ( block );
const blockHash : Keccak256Hash = Keccak256 . hash ( blockHeaderData );
Merkle Tree Nodes
// Compute merkle parent node
const leftNode = Keccak256 . hash ( leftData );
const rightNode = Keccak256 . hash ( rightData );
// Parent = keccak256(left || right)
const parentNode : Keccak256Hash = Keccak256 . hashMultiple ([ leftNode , rightNode ]);
Event Topics
// Event signature hash
const transferTopic : Keccak256Hash = Keccak256 . topic ( 'Transfer(address,address,uint256)' );
// Used in log filtering
const logs = await provider . getLogs ({
topics: [ transferTopic ],
address: tokenAddress ,
});
Address Derivation
import * as Bytes32 from '@tevm/voltaire/Bytes32' ;
// Ethereum address = last 20 bytes of keccak256(publicKey)
const pubKeyHash : Keccak256Hash = Keccak256 . hash ( publicKey );
const address = Bytes32 . toAddress ( pubKeyHash );
Storage Proofs
// Storage slot key
const storageKey = Keccak256 . hashMultiple ([
address ,
Bytes32 . from ( slot ),
]);
// Merkle proof verification
function verifyProof ( leaf : Keccak256Hash , proof : Keccak256Hash [], root : Keccak256Hash ) : boolean {
let current = leaf ;
for ( const sibling of proof ) {
current = Keccak256 . hashMultiple ([ current , sibling ]);
}
return Bytes32 . equals ( current , root );
}