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
@noble/curves
Audited & minimal JS implementation of elliptic curve cryptography
ethereum-cryptography
All the cryptographic primitives used in Ethereum
@mainsail/crypto-hash-noble
Hashing powered by @noble/hashes for the Mainsail blockchain
Audited & minimal JS implementation of hash functions, MACs and KDFs.
npm install @noble/hashes
99.9
Supply Chain
100
Quality
88.3
Maintenance
100
Vulnerability
100
License
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
594 Stars
460 Commits
45 Forks
12 Watching
2 Branches
16 Contributors
Updated on 29 Nov 2024
Minified
Minified + Gzipped
JavaScript (57.46%)
TypeScript (42.07%)
Python (0.46%)
Cumulative downloads
Total Downloads
Last day
-4.5%
675,160
Compared to previous day
Last week
9.4%
4,201,296
Compared to previous week
Last month
3.7%
16,668,563
Compared to previous month
Last year
156.7%
141,219,703
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
We support all major platforms and runtimes. For Deno, ensure to use npm specifier. 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'; // ECMAScript modules (ESM) and Common.js 3// import { sha256 } from 'npm:@noble/hashes@1.3.0/sha2'; // Deno 4console.log(sha256(new Uint8Array([1, 2, 3]))); // Uint8Array(32) [3, 144, 88, 198, 242...] 5// you could also pass strings that will be UTF8-encoded to Uint8Array 6console.log(sha256('abc')); // == sha256(new TextEncoder().encode('abc'))
All hash functions:
Uint8Array
and return Uint8Array
string
, which is automatically converted to Uint8Array
via utf8 encoding (not hex)1function hash(message: Uint8Array | string): Uint8Array; 2hash(new Uint8Array([1, 3])); 3hash('string') == hash(new TextEncoder().encode('string'));
All hash functions can be constructed via hash.create()
method:
Hash
subclass instance, which has update()
and digest()
methodsdigest()
finalizes the hash and makes it no longer usable1hash 2 .create() 3 .update(new Uint8Array([1, 3])) 4 .digest();
Some hash functions can also receive options
object, which can be either passed as a:
blake3('abc', { key: 'd', dkLen: 32 })
blake3.create({ context: 'e', dkLen: 32 })
1import { sha256, sha384, sha512, sha224, sha512_256, sha512_384 } from '@noble/hashes/sha2'; 2// also available as aliases: 3// import ... from '@noble/hashes/sha256' 4// import ... from '@noble/hashes/sha512' 5 6// Variant A: 7const h1a = sha256('abc'); 8 9// Variant B: 10const h1b = sha256 11 .create() 12 .update(Uint8Array.from([1, 2, 3])) 13 .digest(); 14 15for (let hash of [sha384, sha512, sha224, sha512_256, sha512_384]) { 16 const res1 = hash('abc'); 17 const res2 = hash 18 .create() 19 .update('def') 20 .update(Uint8Array.from([1, 2, 3])) 21 .digest(); 22}
See RFC 4634 and the paper on truncated SHA512/256.
1import { 2 sha3_224, 3 sha3_256, 4 sha3_384, 5 sha3_512, 6 keccak_224, 7 keccak_256, 8 keccak_384, 9 keccak_512, 10 shake128, 11 shake256, 12} from '@noble/hashes/sha3'; 13const h5a = sha3_256('abc'); 14const h5b = sha3_256 15 .create() 16 .update(Uint8Array.from([1, 2, 3])) 17 .digest(); 18const h6a = keccak_256('abc'); 19const h7a = shake128('abc', { dkLen: 512 }); 20const h7b = shake256('abc', { dkLen: 512 });
See FIPS PUB 202, Website.
Check out the differences between SHA-3 and Keccak
1import { 2 cshake128, 3 cshake256, 4 kmac128, 5 kmac256, 6 k12, 7 m14, 8 turboshake128, 9 turboshake256, 10 tuplehash128, 11 tuplehash256, 12 parallelhash128, 13 parallelhash256, 14 keccakprg, 15} from '@noble/hashes/sha3-addons'; 16const h7c = cshake128('abc', { personalization: 'def' }); 17const h7d = cshake256('abc', { personalization: 'def' }); 18const h7e = kmac128('key', 'message'); 19const h7f = kmac256('key', 'message'); 20const h7h = k12('abc'); 21const h7g = m14('abc'); 22const h7t1 = turboshake128('abc'); 23const h7t2 = turboshake256('def', { D: 0x05 }); 24const h7i = tuplehash128(['ab', 'c']); // tuplehash(['ab', 'c']) !== tuplehash(['a', 'bc']) !== tuplehash(['abc']) 25// Same as k12/blake3, but without reduced number of rounds. Doesn't speedup anything due lack of SIMD and threading, 26// added for compatibility. 27const h7j = parallelhash128('abc', { blockLen: 8 }); 28// pseudo-random generator, first argument is capacity. XKCP recommends 254 bits capacity for 128-bit security strength. 29// * with a capacity of 254 bits. 30const p = keccakprg(254); 31p.feed('test'); 32const rand1b = p.fetch(1);
1import { ripemd160 } from '@noble/hashes/ripemd160'; 2// function ripemd160(data: Uint8Array): Uint8Array; 3const hash8 = ripemd160('abc'); 4const hash9 = ripemd160 5 .create() 6 .update(Uint8Array.from([1, 2, 3])) 7 .digest();
1import { blake2b } from '@noble/hashes/blake2b'; 2import { blake2s } from '@noble/hashes/blake2s'; 3import { blake3 } from '@noble/hashes/blake3'; 4 5const h10a = blake2s('abc'); 6const b2params = { key: new Uint8Array([1]), personalization: t, salt: t, dkLen: 32 }; 7const h10b = blake2s('abc', b2params); 8const h10c = blake2s 9 .create(b2params) 10 .update(Uint8Array.from([1, 2, 3])) 11 .digest(); 12 13// All params are optional 14const h11 = blake3('abc', { dkLen: 256, key: 'def', context: 'fji' });
SHA1 was cryptographically broken, however, it was not broken for cases like HMAC.
See RFC4226 B.2.
Don't use it for a new protocol.
1import { sha1 } from '@noble/hashes/sha1'; 2const h12 = sha1('def');
1import { hmac } from '@noble/hashes/hmac'; 2import { sha256 } from '@noble/hashes/sha2'; 3const mac1 = hmac(sha256, 'key', 'message'); 4const mac2 = hmac 5 .create(sha256, Uint8Array.from([1, 2, 3])) 6 .update(Uint8Array.from([4, 5, 6])) 7 .digest();
Matches RFC 2104.
1import { hkdf } from '@noble/hashes/hkdf'; 2import { sha256 } from '@noble/hashes/sha2'; 3import { randomBytes } from '@noble/hashes/utils'; 4const inputKey = randomBytes(32); 5const salt = randomBytes(32); 6const info = 'abc'; 7const dkLen = 32; 8const hk1 = hkdf(sha256, inputKey, salt, info, dkLen); 9 10// == same as 11import * as hkdf from '@noble/hashes/hkdf'; 12import { sha256 } from '@noble/hashes/sha2'; 13const prk = hkdf.extract(sha256, inputKey, salt); 14const hk2 = hkdf.expand(sha256, prk, info, dkLen);
Matches RFC 5869.
1import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2'; 2import { sha256 } from '@noble/hashes/sha2'; 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'; 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 M2 (mobile phones can be 1x-4x slower):
N pow | Time |
---|---|
16 | 0.17s |
17 | 0.35s |
18 | 0.7s |
19 | 1.4s |
20 | 2.9s |
21 | 5.6s |
22 | 11s |
23 | 26s |
24 | 56s |
[!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'; 2const result = 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
1import { sha256, sha384, sha512, sha224, sha512_256, sha512_384 } from '@noble/hashes/sha2'; 2// prettier-ignore 3import { 4 sha3_224, sha3_256, sha3_384, sha3_512, 5 keccak_224, keccak_256, keccak_384, keccak_512, 6 shake128, shake256 7} from '@noble/hashes/sha3'; 8// prettier-ignore 9import { 10 cshake128, cshake256, 11 turboshake128, turboshake256, 12 kmac128, kmac256, 13 tuplehash256, parallelhash256, 14 k12, m14, keccakprg 15} from '@noble/hashes/sha3-addons'; 16import { ripemd160 } from '@noble/hashes/ripemd160'; 17import { blake3 } from '@noble/hashes/blake3'; 18import { blake2b } from '@noble/hashes/blake2b'; 19import { blake2s } from '@noble/hashes/blake2s'; 20import { hmac } from '@noble/hashes/hmac'; 21import { hkdf } from '@noble/hashes/hkdf'; 22import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2'; 23import { scrypt, scryptAsync } from '@noble/hashes/scrypt'; 24 25import { sha1 } from '@noble/hashes/sha1'; // legacy 26 27// small utility method that converts bytes to hex 28import { bytesToHex as toHex } from '@noble/hashes/utils'; 29console.log(toHex(sha256('abc'))); // ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
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 has fuzzing by Guido Vranken's cryptofuzz.
If you see anything unusual: investigate and report.
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. Nonetheless we're targetting algorithmic constant time.
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 memorynpm-diff
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.
Benchmarks measured on Apple M1 with macOS 12.
Note that PBKDF2 and Scrypt are tested with extremely high work factor.
To run benchmarks, execute npm run bench:install
and then npm run bench
SHA256 32B x 1,219,512 ops/sec @ 820ns/op ± 2.58% (min: 625ns, max: 4ms)
SHA384 32B x 512,032 ops/sec @ 1μs/op
SHA512 32B x 509,943 ops/sec @ 1μs/op
SHA3-256, keccak256, shake256 32B x 199,600 ops/sec @ 5μs/op
Kangaroo12 32B x 336,360 ops/sec @ 2μs/op
Marsupilami14 32B x 298,418 ops/sec @ 3μs/op
BLAKE2b 32B x 379,794 ops/sec @ 2μs/op
BLAKE2s 32B x 515,995 ops/sec @ 1μs/op ± 1.07% (min: 1μs, max: 4ms)
BLAKE3 32B x 588,235 ops/sec @ 1μs/op ± 1.36% (min: 1μs, max: 5ms)
RIPEMD160 32B x 1,140,250 ops/sec @ 877ns/op ± 3.12% (min: 708ns, max: 6ms)
HMAC-SHA256 32B x 377,358 ops/sec @ 2μs/op
HKDF-SHA256 32B x 108,377 ops/sec @ 9μs/op
PBKDF2-HMAC-SHA256 262144 x 3 ops/sec @ 326ms/op
PBKDF2-HMAC-SHA512 262144 x 1 ops/sec @ 970ms/op
Scrypt r: 8, p: 1, n: 262144 x 1 ops/sec @ 616ms/op
Compare to native node.js implementation that uses C bindings instead of pure-js code:
SHA256 32B node x 1,302,083 ops/sec @ 768ns/op ± 10.54% (min: 416ns, max: 7ms)
SHA384 32B node x 975,609 ops/sec @ 1μs/op ± 11.32% (min: 625ns, max: 8ms)
SHA512 32B node x 983,284 ops/sec @ 1μs/op ± 11.24% (min: 625ns, max: 8ms)
SHA3-256 32B node x 910,746 ops/sec @ 1μs/op ± 12.19% (min: 666ns, max: 10ms)
keccak, k12, m14 are not implemented
BLAKE2b 32B node x 967,117 ops/sec @ 1μs/op ± 11.26% (min: 625ns, max: 9ms)
BLAKE2s 32B node x 1,055,966 ops/sec @ 947ns/op ± 11.07% (min: 583ns, max: 7ms)
BLAKE3 is not implemented
RIPEMD160 32B node x 1,002,004 ops/sec @ 998ns/op ± 10.66% (min: 625ns, max: 7ms)
HMAC-SHA256 32B node x 919,963 ops/sec @ 1μs/op ± 6.13% (min: 833ns, max: 5ms)
HKDF-SHA256 32 node x 369,276 ops/sec @ 2μs/op ± 13.59% (min: 1μs, max: 9ms)
PBKDF2-HMAC-SHA256 262144 node x 25 ops/sec @ 39ms/op
PBKDF2-HMAC-SHA512 262144 node x 7 ops/sec @ 132ms/op
Scrypt r: 8, p: 1, n: 262144 node x 1 ops/sec @ 523ms/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.
npm install
to install build dependencies like TypeScriptnpm run build
to compile TypeScript codenpm run test
will execute all main tests. See our approach to testingnpm run test:dos
will test against DoS; by measuring function complexity. Takes ~20 minutesnpm run test:big
will execute hashing on 4GB inputs,
scrypt with 1024 different N, r, p
combinations, etc. Takes several hours. Using 8-32+ core CPU helps.npm run format
will fix lint issuestest/misc
directory contains implementations of loop unrolling and md5.
Check out paulmillr.com/noble for useful resources, articles, documentation and demos related to the library.
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
See LICENSE file.
No vulnerabilities found.
No security vulnerabilities found.