Gathering detailed insights and metrics for @noble/hashes
Gathering detailed insights and metrics for @noble/hashes
Gathering detailed insights and metrics for @noble/hashes
Gathering detailed insights and metrics for @noble/hashes
@polkadot/x-noble-hashes
An fork of @noble/hashes with extra protection on BigInt usage
@openpgp/noble-hashes
Audited & minimal JS implementation of SHA2, SHA3, RIPEMD, HMAC
noble-hashes
Fast 0-dependency JS implementation of SHA2, SHA3, RIPEMD, BLAKE, HMAC, HKDF, PBKDF2, Scrypt
cryptils
Utilities around Master Password Algorithm (Spectre.app, by Maarten Billemont) and crypto, using Noble and Scure by Paul Miller. Stateless accounts & passwords, 2fa HOTP/TOTP, shamir secret sharing, crypto/bitcoin/nostr public and private keys, and more.
Audited & minimal JS implementation of hash functions, MACs and KDFs.
npm install @noble/hashes
Typescript
Module System
Min. Node Version
Node Version
NPM Version
99.9
Supply Chain
100
Quality
87.4
Maintenance
100
Vulnerability
100
License
JavaScript (53.84%)
TypeScript (45.77%)
Python (0.39%)
Total Downloads
341,914,453
Last Day
1,683,226
Last Week
9,806,366
Last Month
35,065,784
Last Year
232,206,146
MIT License
667 Stars
589 Commits
51 Forks
11 Watchers
7 Branches
17 Contributors
Updated on May 08, 2025
Minified
Minified + Gzipped
Latest Version
1.8.0
Package Id
@noble/hashes@1.8.0
Unpacked Size
1.09 MB
Size
151.69 kB
File Count
247
NPM Version
10.9.2
Node Version
22.13.0
Published on
Apr 21, 2025
Cumulative downloads
Total Downloads
Last Day
27.4%
1,683,226
Compared to previous day
Last Week
15%
9,806,366
Compared to previous week
Last Month
25.3%
35,065,784
Compared to previous month
Last Year
160.4%
232,206,146
Compared to previous year
6
Audited & minimal JS implementation of hash functions, MACs and KDFs.
Take a glance at GitHub Discussions for questions and support. The library's initial development was funded by Ethereum Foundation.
noble cryptography — high-security, easily auditable set of contained cryptographic libraries and tools.
npm install @noble/hashes
deno add jsr:@noble/hashes
deno doc jsr:@noble/hashes
# command-line documentation
We support all major platforms and runtimes. For React Native, you may need a polyfill for getRandomValues. A standalone file noble-hashes.js is also available.
1// import * from '@noble/hashes'; // Error: use sub-imports, to ensure small app size 2import { sha256 } from '@noble/hashes/sha2.js'; // ESM & Common.js 3sha256(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])); // returns Uint8Array 4 5// Available modules 6import { sha256, sha384, sha512, sha224, sha512_224, sha512_256 } from '@noble/hashes/sha2.js'; 7import { sha3_256, sha3_512, keccak_256, keccak_512, shake128, shake256 } from '@noble/hashes/sha3.js'; 8import { cshake256, turboshake256, kmac256, tuplehash256, k12, m14, keccakprg } from '@noble/hashes/sha3-addons.js'; 9import { blake3 } from '@noble/hashes/blake3.js'; 10import { blake2b, blake2s } from '@noble/hashes/blake2.js'; 11import { blake256, blake512 } from '@noble/hashes/blake1.js'; 12import { sha1, md5, ripemd160 } from '@noble/hashes/legacy.js'; 13import { hmac } from '@noble/hashes/hmac.js'; 14import { hkdf } from '@noble/hashes/hkdf.js'; 15import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2.js'; 16import { scrypt, scryptAsync } from '@noble/hashes/scrypt.js'; 17import { argon2d, argon2i, argon2id } from '@noble/hashes/argon2.js'; 18import * as utils from '@noble/hashes/utils'; // bytesToHex, bytesToUtf8, concatBytes...
Hash functions:
sha256()
: receive & return Uint8Array
sha256.create().update(a).update(b).digest()
: support partial updatesblake3.create({ context: 'e', dkLen: 32 })
: sometimes have options1import { sha224, sha256, sha384, sha512, sha512_224, sha512_256 } from '@noble/hashes/sha2.js'; 2const res = sha256(Uint8Array.from([0xbc])); // basic 3for (let hash of [sha256, sha384, sha512, sha224, sha512_224, sha512_256]) { 4 const arr = Uint8Array.from([0x10, 0x20, 0x30]); 5 const a = hash(arr); 6 const b = hash.create().update(arr).digest(); 7}
See RFC 4634 and the paper on truncated SHA512/256.
1import { 2 keccak_224, keccak_256, keccak_384, keccak_512, 3 sha3_224, sha3_256, sha3_384, sha3_512, 4 shake128, shake256, 5} from '@noble/hashes/sha3.js'; 6for (let hash of [ 7 sha3_224, sha3_256, sha3_384, sha3_512, 8 keccak_224, keccak_256, keccak_384, keccak_512, 9]) { 10 const arr = Uint8Array.from([0x10, 0x20, 0x30]); 11 const a = hash(arr); 12 const b = hash.create().update(arr).digest(); 13} 14const shka = shake128(Uint8Array.from([0x10]), { dkLen: 512 }); 15const shkb = shake256(Uint8Array.from([0x30]), { dkLen: 512 });
Check out the differences between SHA-3 and Keccak
1import { 2 cshake128, cshake256, 3 k12, 4 keccakprg, 5 kmac128, kmac256, 6 m14, 7 parallelhash256, 8 tuplehash256, 9 turboshake128, turboshake256 10} from '@noble/hashes/sha3-addons.js'; 11const data = Uint8Array.from([0x10, 0x20, 0x30]); 12const ec1 = cshake128(data, { personalization: 'def' }); 13const ec2 = cshake256(data, { personalization: 'def' }); 14const et1 = turboshake128(data); 15const et2 = turboshake256(data, { D: 0x05 }); 16 // tuplehash(['ab', 'c']) !== tuplehash(['a', 'bc']) !== tuplehash([data]) 17const et3 = tuplehash256([utf8ToBytes('ab'), utf8ToBytes('c')]); 18// Not parallel in JS (similar to blake3 / k12), added for compat 19const ep1 = parallelhash256(data, { blockLen: 8 }); 20const kk = Uint8Array.from([0xca]); 21const ek10 = kmac128(kk, data); 22const ek11 = kmac256(kk, data); 23const ek12 = k12(data); 24const ek13 = m14(data); 25// pseudo-random generator, first argument is capacity. XKCP recommends 254 bits capacity for 128-bit security strength. 26// * with a capacity of 254 bits. 27const p = keccakprg(254); 28p.feed('test'); 29const rand1b = p.fetch(1);
1import { blake224, blake256, blake384, blake512 } from '@noble/hashes/blake1.js'; 2import { blake2b, blake2s } from '@noble/hashes/blake2.js'; 3import { blake3 } from '@noble/hashes/blake3.js'; 4 5for (let hash of [ 6 blake224, blake256, blake384, blake512, 7 blake2b, blake2s, blake3 8]) { 9 const arr = Uint8Array.from([0x10, 0x20, 0x30]); 10 const a = hash(arr); 11 const b = hash.create().update(arr).digest(); 12} 13 14// blake2 advanced usage 15const ab = Uint8Array.from([0x01]); 16blake2s(ab); 17blake2s(ab, { key: new Uint8Array(32) }); 18blake2s(ab, { personalization: 'pers1234' }); 19blake2s(ab, { salt: 'salt1234' }); 20blake2b(ab); 21blake2b(ab, { key: new Uint8Array(64) }); 22blake2b(ab, { personalization: 'pers1234pers1234' }); 23blake2b(ab, { salt: 'salt1234salt1234' }); 24 25// blake3 advanced usage 26blake3(ab); 27blake3(ab, { dkLen: 256 }); 28blake3(ab, { key: new Uint8Array(32) }); 29blake3(ab, { context: 'application-name' });
SHA1 (RFC 3174), MD5 (RFC 1321) and RIPEMD160 (RFC 2286) legacy, weak hash functions. Don't use them in a new protocol. What "weak" means:
1import { md5, ripemd160, sha1 } from '@noble/hashes/legacy.js'; 2for (let hash of [md5, ripemd160, sha1]) { 3 const arr = Uint8Array.from([0x10, 0x20, 0x30]); 4 const a = hash(arr); 5 const b = hash.create().update(arr).digest(); 6}
1import { hmac } from '@noble/hashes/hmac.js'; 2import { sha256 } from '@noble/hashes/sha2.js'; 3const key = new Uint8Array(32).fill(1); 4const msg = new Uint8Array(32).fill(2); 5const mac1 = hmac(sha256, key, msg); 6const mac2 = hmac.create(sha256, key).update(msg).digest();
Matches RFC 2104.
1import { hkdf } from '@noble/hashes/hkdf.js'; 2import { randomBytes } from '@noble/hashes/utils.js'; 3import { sha256 } from '@noble/hashes/sha2.js'; 4const inputKey = randomBytes(32); 5const salt = randomBytes(32); 6const info = 'application-key'; 7const hk1 = hkdf(sha256, inputKey, salt, info, 32); 8 9// == same as 10import { extract, expand } from '@noble/hashes/hkdf.js'; 11import { sha256 } from '@noble/hashes/sha2.js'; 12const prk = extract(sha256, inputKey, salt); 13const hk2 = expand(sha256, prk, info, 32);
Matches RFC 5869.
1import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2.js'; 2import { sha256 } from '@noble/hashes/sha2.js'; 3const pbkey1 = pbkdf2(sha256, 'password', 'salt', { c: 32, dkLen: 32 }); 4const pbkey2 = await pbkdf2Async(sha256, 'password', 'salt', { c: 32, dkLen: 32 }); 5const pbkey3 = await pbkdf2Async(sha256, Uint8Array.from([1, 2, 3]), Uint8Array.from([4, 5, 6]), { 6 c: 32, 7 dkLen: 32, 8});
Matches RFC 2898.
1import { scrypt, scryptAsync } from '@noble/hashes/scrypt.js'; 2const scr1 = scrypt('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 }); 3const scr2 = await scryptAsync('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 }); 4const scr3 = await scryptAsync(Uint8Array.from([1, 2, 3]), Uint8Array.from([4, 5, 6]), { 5 N: 2 ** 17, 6 r: 8, 7 p: 1, 8 dkLen: 32, 9 onProgress(percentage) { 10 console.log('progress', percentage); 11 }, 12 maxmem: 2 ** 32 + 128 * 8 * 1, // N * r * p * 128 + (128*r*p) 13});
N, r, p
are work factors. To understand them, see the blog post.
r: 8, p: 1
are common. JS doesn't support parallelization, making increasing p meaningless.dkLen
is the length of output bytes e.g. 32
or 64
onProgress
can be used with async version of the function to report progress to a user.maxmem
prevents DoS and is limited to 1GB + 1KB
(2**30 + 2**10
), but can be adjusted using formula: N * r * p * 128 + (128 * r * p)
Time it takes to derive Scrypt key under different values of N (2**N) on Apple M4 (mobile phones can be 1x-4x slower):
N pow | Time | RAM |
---|---|---|
16 | 0.1s | 64MB |
17 | 0.2s | 128MB |
18 | 0.4s | 256MB |
19 | 0.8s | 512MB |
20 | 1.5s | 1GB |
21 | 3.1s | 2GB |
22 | 6.2s | 4GB |
23 | 13s | 8GB |
24 | 27s | 16GB |
[!NOTE] We support N larger than
2**20
where available, however, not all JS engines support >= 2GB ArrayBuffer-s. When using such N, you'll need to manually adjustmaxmem
, using formula above. Other JS implementations don't support large N-s.
1import { argon2d, argon2i, argon2id } from '@noble/hashes/argon2.js'; 2const arg1 = argon2id('password', 'saltsalt', { t: 2, m: 65536, p: 1, maxmem: 2 ** 32 - 1 });
Argon2 RFC 9106 implementation.
[!WARNING] Argon2 can't be fast in JS, because there is no fast Uint64Array. It is suggested to use Scrypt instead. Being 5x slower than native code means brute-forcing attackers have bigger advantage.
1import { bytesToHex as toHex, randomBytes } from '@noble/hashes/utils'; 2console.log(toHex(randomBytes(32)));
bytesToHex
will convert Uint8Array
to a hex stringrandomBytes(bytes)
will produce cryptographically secure random Uint8Array
of length bytes
The library has been independently audited:
blake3
, sha3-addons
, sha1
and argon2
, which have not been auditedIt is tested against property-based, cross-library and Wycheproof vectors, and is being fuzzed in the separate repo.
If you see anything unusual: investigate and report.
We're targetting algorithmic constant time. JIT-compiler and Garbage Collector make "constant time" extremely hard to achieve timing attack resistance in a scripting language. Which means any other JS library can't have constant-timeness. Even statically typed Rust, a language without GC, makes it harder to achieve constant-time for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages.
The library shares state buffers between hash function calls. The buffers are zeroed-out after each call. However, if an attacker can read application memory, you are doomed in any case:
scrypt(password, salt)
where password and salt are stringsawait anything()
will always write all internal variables (including numbers)
to memory. With async functions / Promises there are no guarantees when the code
chunk would be executed. Which means attacker can have plenty of time to read data from memorygh attestation verify --owner paulmillr noble-hashes.js
npm-diff
For this package, there are 0 dependencies; and a few dev dependencies:
We're deferring to built-in crypto.getRandomValues which is considered cryptographically secure (CSPRNG).
In the past, browsers had bugs that made it weak: it may happen again. Implementing a userspace CSPRNG to get resilient to the weakness is even worse: there is no reliable userspace source of quality entropy.
Cryptographically relevant quantum computer, if built, will allow to utilize Grover's algorithm to break hashes in 2^n/2 operations, instead of 2^n.
This means SHA256 should be replaced with SHA512, SHA3-256 with SHA3-512, SHAKE128 with SHAKE256 etc.
Australian ASD prohibits SHA256 and similar hashes after 2030.
1npm run bench:install && npm run bench
Benchmarks measured on Apple M4.
# 32B
sha256 x 1,968,503 ops/sec @ 508ns/op
sha512 x 740,740 ops/sec @ 1μs/op
sha3_256 x 287,686 ops/sec @ 3μs/op
sha3_512 x 288,267 ops/sec @ 3μs/op
k12 x 476,190 ops/sec @ 2μs/op
m14 x 423,190 ops/sec @ 2μs/op
blake2b x 464,252 ops/sec @ 2μs/op
blake2s x 766,871 ops/sec @ 1μs/op
blake3 x 879,507 ops/sec @ 1μs/op
# 1MB
sha256 x 331 ops/sec @ 3ms/op
sha512 x 129 ops/sec @ 7ms/op
sha3_256 x 38 ops/sec @ 25ms/op
sha3_512 x 20 ops/sec @ 47ms/op
k12 x 88 ops/sec @ 11ms/op
m14 x 62 ops/sec @ 15ms/op
blake2b x 69 ops/sec @ 14ms/op
blake2s x 57 ops/sec @ 17ms/op
blake3 x 72 ops/sec @ 13ms/op
# MAC
hmac(sha256) x 599,880 ops/sec @ 1μs/op
hmac(sha512) x 197,122 ops/sec @ 5μs/op
kmac256 x 87,981 ops/sec @ 11μs/op
blake3(key) x 796,812 ops/sec @ 1μs/op
# KDF
hkdf(sha256) x 259,942 ops/sec @ 3μs/op
blake3(context) x 424,808 ops/sec @ 2μs/op
pbkdf2(sha256, c: 2 ** 18) x 5 ops/sec @ 197ms/op
pbkdf2(sha512, c: 2 ** 18) x 1 ops/sec @ 630ms/op
scrypt(n: 2 ** 18, r: 8, p: 1) x 2 ops/sec @ 400ms/op
argon2id(t: 1, m: 256MB) 2881ms
Compare to native node.js implementation that uses C bindings instead of pure-js code:
# native (node) 32B
sha256 x 2,267,573 ops/sec
sha512 x 983,284 ops/sec
sha3_256 x 1,522,070 ops/sec
blake2b x 1,512,859 ops/sec
blake2s x 1,821,493 ops/sec
hmac(sha256) x 1,085,776 ops/sec
hkdf(sha256) x 312,109 ops/sec
# native (node) KDF
pbkdf2(sha256, c: 2 ** 18) x 5 ops/sec @ 197ms/op
pbkdf2(sha512, c: 2 ** 18) x 1 ops/sec @ 630ms/op
scrypt(n: 2 ** 18, r: 8, p: 1) x 2 ops/sec @ 378ms/op
It is possible to make this library 4x+ faster by doing code generation of full loop unrolls. We've decided against it. Reasons:
The current performance is good enough when compared to other projects; SHA256 takes only 900 nanoseconds to run.
test/misc
directory contains implementations of loop unrolling and md5.
npm install && npm run build && npm test
will build the code and run tests.npm run lint
/ npm run format
will run linter / fix linter issues.npm run bench
will run benchmarks, which may need their deps first (npm run bench:install
)npm run build:release
will build single filenpm run test:dos
and 2-hour "big" multicore test npm run test:big
.
See our approach to testingAdditional resources:
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
See LICENSE file.
No vulnerabilities found.
No security vulnerabilities found.