js-sha3 review
js-sha3 0.13.0 implements SHA-3, Keccak, SHAKE, cSHAKE, KMAC, TupleHash, and the newly added ParallelHash in JavaScript. Each family supports direct calls and stateful updates, accepts UTF-8 strings or byte containers, and can return hex, arrays, or ArrayBuffer output. It runs in Node, browsers, and workers without native bindings. Our package inspection found no dependencies and a 5.5 KB gzipped all-exports bundle, but this is still a cryptographic primitive: it does not hash passwords, manage keys, or choose the correct construction for a protocol.
js-sha3 0.13.0 installed as 1 dependency-free package in 0.8 seconds, and our browser build was 5.5 KB gzipped with 0 audit findings. Use it for cross-runtime SHA-3, Keccak, or SP 800-185 work; use node:crypto for Node-only hashing and a password KDF for stored credentials.
We installed it
| Install | ✓ · 0.8s | 1 package on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package with exports map |
| Browser | 5.5 KB | gzipped (15.5 KB minified), bundled with esbuild |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does js-sha3 install cleanly?
Yes. In a fresh container with an empty cache, npm install js-sha3 finished in 0.8s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does js-sha3 add to a browser bundle?
5.5 KB gzipped (15.5 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does js-sha3 work with both ESM and CommonJS?
Yes. Both import 'js-sha3' and require('js-sha3') worked in Node 22 in our run. The package is published as CommonJS with an exports map.
Does js-sha3 include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
js-sha3 or @noble/hashes: which should you use?
@noble/hashes: Use it for a modern ESM set of reviewed cryptographic primitives that includes SHA-3 and additional hashes and KDFs. js-sha3 0.13.0 installed as 1 dependency-free package in 0.8 seconds, and our browser build was 5.5 KB gzipped with 0 audit findings.
When should you not use js-sha3?
All hashing stays in Node on an OpenSSL build with SHA-3 support. node:crypto avoids a JavaScript implementation and another package.
Use it if
- One JavaScript implementation must produce matching SHA-3 or Keccak results in Node, browsers, and workers.
- A protocol calls for cSHAKE, KMAC, TupleHash, or ParallelHash and the host crypto API does not expose it.
- Large input must be fed incrementally, with hex, byte-array, or ArrayBuffer output selected at finalization.
- An Ethereum-style or older protocol explicitly names Keccak, so standardized SHA-3 would produce the wrong digest.
- All hashing stays in Node on an OpenSSL build with SHA-3 support. node:crypto avoids a JavaScript implementation and another package.
- The input is a password. This API has no salt policy, memory cost, or password KDF; choose Argon2, scrypt, or bcrypt.
- Your code treats SHA3-256 and Keccak-256 as aliases. Their padding differs, and the README records the naming correction made after 0.1.x.
- Callers naturally specify XOF output in bytes. These methods accept outputBits, so `32` produces 4 bytes rather than a 32-byte value.
- An independent cryptographic audit or a stable 1.x contract is mandatory. The project publishes tests and vectors, while the package remains at 0.13.0 and claims no external audit.
Setup reality
We installed js-sha3 0.13.0 in 0.8 seconds in a fresh Node 22 Bookworm container. It left 1 package and 1 MB on disk, with 0 known vulnerabilities from npm audit. The package has no direct or peer dependencies, is 172 KB unpacked, carries an MIT license, and bundles TypeScript declarations. It is CommonJS behind an exports map; both require() and ESM import worked. Our all-exports browser bundle measured 15.5 KB minified and 5.5 KB gzipped.
No credentials, build tools, or configuration files are involved. Strings are converted to UTF-8, while Uint8Array, ArrayBuffer, and number arrays represent bytes directly. That distinction matters for binary protocols and non-ASCII text. SHA-3 and Keccak have similar names but different padding. Compare against a published vector for the exact algorithm before accepting integration output.
SHAKE, cSHAKE, KMAC, TupleHash, and ParallelHash take their result length in bits. cSHAKE also accepts a function name and customization string; KMAC starts with a key; ParallelHash adds a block size. TupleHash frames every array element separately, so hashing ['ab', 'c'] is deliberately different from hashing one abc string.
Calling hex(), array(), digest(), arrayBuffer(), or toString() finalizes an incremental instance. Version 0.8.0 and later throws if update() follows finalization. The older buffer() output is deprecated in favor of arrayBuffer(). TupleHash streaming adds another exactness rule: beginInput() needs the byte count before updateChunk(), and a JavaScript string's character count is not its UTF-8 byte length.
Patterns
Create a SHA3-256 text digest hash-text-sha3
import { sha3_256 } from 'js-sha3';
const hex = sha3_256('The quick brown fox');
console.log(hex);The function encodes a string as UTF-8 and returns lowercase hex. keccak256 uses different domain padding and will not match this digest.
Produce the Keccak-256 variant hash-keccak-256
import { keccak256 } from 'js-sha3';
const digest = keccak256('message');Choose this name only when a protocol explicitly requires Keccak-256, including many Ethereum formats. SHA3-256 is a separate construction.
Hash a Uint8Array hash-byte-array
import { sha3_256 } from 'js-sha3';
const bytes = new Uint8Array([0x00, 0xff, 0x10, 0x80]);
const hex = sha3_256(bytes);Uint8Array, ArrayBuffer, and number arrays are consumed as bytes. Passing their printed string form would hash UTF-8 text instead.
Get an ArrayBuffer digest return-array-buffer
import { sha3_512 } from 'js-sha3';
const buffer = sha3_512.arrayBuffer('message');
const bytes = new Uint8Array(buffer);The README deprecates buffer() because it can be mistaken for Node Buffer. arrayBuffer() is the supported binary output method.
Feed a hash in chunks stream-hash-input
import { sha3_256 } from 'js-sha3';
const hash = sha3_256.create();
hash.update(headerBytes);
hash.update(bodyChunk1);
hash.update(bodyChunk2);
const hex = hash.hex();hex() finalizes this instance. Since 0.8.0, another update() after any final output call throws an error.
Choose a SHAKE result length generate-shake-output
import { shake256 } from 'js-sha3';
const output256 = shake256('domain-separated input', 256);
const output512 = shake256('domain-separated input', 512);Output length is expressed in bits. A value of 256 yields 32 bytes, while 512 yields 64 bytes.
Customize a cSHAKE digest customize-cshake
import { cshake128 } from 'js-sha3';
const hex = cshake128(
'payload',
256,
'ExampleFunction',
'my-app/v1'
);The function-name and customization values participate in hashing. Producers and verifiers must supply the same bytes in both positions.
Authenticate data with KMAC128 authenticate-with-kmac
import { kmac128 } from 'js-sha3';
const tag = kmac128(
secretKeyBytes,
messageBytes,
256,
'payments/v1'
);Arguments are key, message, result bits, then customization. Supply random key bytes from a secret store rather than a human password.
Preserve boundaries with TupleHash hash-structured-tuple
import { tuplehash128 } from 'js-sha3';
const digest = tuplehash128(
['abc', 'd'],
256,
'records/v1'
);Each element is framed separately. `['abc', 'd']` and `['ab', 'cd']` therefore produce different results despite identical concatenation.
Chunk one TupleHash element stream-tuple-input
import { tuplehash128 } from 'js-sha3';
const hash = tuplehash128.create(256, 'records/v1');
hash.beginInput(3).updateChunk([0x61, 0x62]).updateChunk([0x63]);
hash.beginInput(1).updateChunk([0x64]);
const digest = hash.hex();beginInput() requires the next element's byte length. Count encoded UTF-8 bytes for non-ASCII text, not JavaScript characters.
Set ParallelHash block size parallel-hash-blocks
import { parallelhash128 } from 'js-sha3';
const blockSize = 1024;
const outputBits = 256;
const digest = parallelhash128(data, blockSize, outputBits, 'archive/v1');ParallelHash arrived in 0.13.0. The second parameter sets block bytes, and the third sets output bits.
Compare two MAC values in Node compare-node-digests
import { timingSafeEqual } from 'node:crypto';
import { kmac256 } from 'js-sha3';
const actual = Buffer.from(kmac256.array(key, message, 256, 'api/v1'));
const expected = Buffer.from(expectedHex, 'hex');
const valid = actual.length === expected.length && timingSafeEqual(actual, expected);timingSafeEqual avoids content-dependent early exit but throws for unequal lengths. Confirm both buffer lengths before the comparison.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| @noble/hashes | npm | Use it for a modern ESM set of reviewed cryptographic primitives that includes SHA-3 and additional hashes and KDFs. |
| hash-wasm | npm | Use it when large browser inputs benefit from WebAssembly implementations and a streaming interface. |
| crypto-js | npm | Use it inside an existing CryptoJS codebase whose data already uses WordArray and several bundled algorithms. |
More security guides
cryptography · pyjwt · jose · requests-oauthlib · oauthlib · dompurify · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

