About nodejs-keccak256-v1
A Node.js and TypeScript guide to Ethereum Keccak-256 that explains how it differs from Node.js SHA3-256. It covers common Ethereum hashing tasks and warns against using it for SHA-256 applications.
Key features
- 01Distinguishing Keccak-256 from SHA3-256
- 02Ethereum function selectors and event topics
- 03EIP-712, signature, and Merkle hashing
- 04Storage slot and address derivation examples
- 05Usage with viem, ethers, and web3.js
Use cases
- 01Computing contract function selectors and event topics
- 02Building EIP-712 or Merkle helpers
- 03Reviewing Ethereum data hashing code
- 04Checking code for SHA3-256 usage
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ blockmatic/ basilic-skills --skill nodejs-keccak256-v1After installing, type/nodejs-keccak256-v1in Claude Code to confirm it loaded.
Details
From the project READMENode.js Keccak-256
Ethereum uses Keccak-256, not the NIST-standardized SHA3 variant exposed by Node's crypto.createHash('sha3-256').
Scope: Ethereum hashing only — function selectors, event topics, EIP-712, Merkle proofs, storage slots, address derivation.
MUST NOT: Rewrite Node createHash('sha256') used for JWT tokens, OAuth PKCE, API keys, or other app secrets. Keccak is not SHA-256.
Prefer: keccak256 from viem when viem is already a project dependency. Use ethers only when the app already depends on it.
When to Use
- Computing Ethereum function selectors or event topics
- Building EIP-712, signature, Merkle, or storage-slot helpers in JS/TS
- Reviewing any code that hashes Ethereum data with Node crypto directly
How It Works
The two algorithms produce different outputs for the same input, and Node will not warn you.
import crypto from 'crypto';
import { keccak256, toUtf8Bytes } from 'ethers';
const data = 'hello';
const nistSha3 = crypto.createHash('sha3-256').update(data).digest('hex');
const keccak = keccak256(toUtf8Bytes(data)).slice(2);
console.log(nistSha3 === keccak); // false
Examples
ethers v6
import { keccak256, toUtf8Bytes, solidityPackedKeccak256, id } from 'ethers';
const hash = keccak256(new Uint8Array([0x01, 0x02]));
const hash2 = keccak256(toUtf8Bytes('hello'));
const topic = id('Transfer(address,address,uint256)');
const packed = solidityPackedKeccak256(
['address', 'uint256'],
['0x742d35Cc6634C0532925a3b8D4C9B569890FaC1c', 100n],
);
viem
import { keccak256, toBytes } from 'viem';
const hash = keccak256(toBytes('hello'));
web3.js
const hash = web3.utils.keccak256('hello');
const packed = web3.utils.soliditySha3(
{ type: 'address', value: '0x742d35Cc6634C0532925a3b8D4C9B569890FaC1c' },
{ type: 'uint256', value: '100' },
);
Common patterns
import { id, keccak256, AbiCoder } from 'ethers';
const selector = id('transfer(address,uint256)').slice(0, 10);
const typeHash = keccak256(toUtf8Bytes('Transfer(address from,address to,uint256 value)'));
function getMappingSlot(key: string, mappingSlot: number): string {
return keccak256(
AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [key, mappingSlot]),
);
}
Address from public key
import { keccak256 } from 'ethers';
function pubkeyToAddress(pubkeyBytes: Uint8Array): string {
const hash = keccak256(pubkeyBytes.slice(1));
return '0x' + hash.slice(-40);
}
Audit your codebase
grep -rn "createHash.*sha3" --include="*.ts" --include="*.js" --exclude-dir=node_modules .
grep -rn "keccak256" --include="*.ts" --include="*.js" . | grep -v node_modules
Interactions
Rule
For Ethereum contexts, never use crypto.createHash('sha3-256'). Use Keccak-aware helpers from ethers, viem, web3, or another explicit Keccak implementation.