noble-hashes
Audited & minimal JS implementation of hash functions, MACs and KDFs.
🔒 Audited by an independent security firm
🔻 Tree-shakeable: unused code is excluded from your builds
🏎 Fast: hand-optimized for caveats of JS engines
🔍 Reliable: chained / sliding window / DoS tests and fuzzing ensure correctness
🔁 No unrolled loops: makes it easier to verify and reduces source code size up to 5x
🦘 Includes SHA, RIPEMD, BLAKE, HMAC, HKDF, PBKDF, Scrypt, Argon2 & KangarooTwelve
🪶 47KB for everything, 5KB (2.5KB gzipped) for single-hash build
Take a glance at GitHub Discussions for questions and support. The library's initial development was funded by Ethereum Foundation.
This library belongs to noble cryptography
noble cryptography — high-security, easily auditable set of contained cryptographic libraries and tools.
Zero or minimal dependencies
Highly readable TypeScript / JS code
PGP-signed releases and transparent NPM builds
Check out homepage for reading resources, documentation and apps built with noble
Usage
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.
Implementations
Hash functions:
receive & return
Uint8Arraymay receive
string(not hex), which is automatically utf8-encoded toUint8Arraysupport little-endian architecture; also experimentally big-endian
can hash up to 4GB per chunk, with any amount of chunks
can be constructed via
hash.create()methodthe result is
Hashsubclass instance, which hasupdate()anddigest()methodsdigest()finalizes the hash and makes it no longer usable
some of them can receive
options:second argument to hash function:
blake3('abc', { key: 'd', dkLen: 32 })first argument to class initializer:
blake3.create({ context: 'e', dkLen: 32 })
sha2: sha256, sha384, sha512 and others
See RFC 4634 and the paper on truncated SHA512/256.
sha3: FIPS, SHAKE, Keccak
Check out the differences between SHA-3 and Keccak
sha3-addons: cSHAKE, KMAC, K12, M14, TurboSHAKE
Full NIST SP 800-185: cSHAKE, KMAC, TupleHash, ParallelHash + XOF variants
🦘 K12 aka KangarooTwelve
M14 aka MarsupilamiFourteen
TurboSHAKE
KeccakPRG: Pseudo-random generator based on Keccak
ripemd160
blake, blake2b, blake2s, blake3
Blake1 is legacy hash, one of SHA3 proposals. It is rarely used anywhere. See pdf.
Blake3 is faster, reduced-round blake2. See Website & specs
sha1: legacy hash
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.
hmac
Matches RFC 2104.
hkdf
Matches RFC 5869.
pbkdf2
Matches RFC 2898.
scrypt
N, r, pare work factors. To understand them, see the blog post.r: 8, p: 1are common. JS doesn't support parallelization, making increasing p meaningless.dkLenis the length of output bytes e.g.32or64onProgresscan be used with async version of the function to report progress to a user.maxmemprevents DoS and is limited to1GB + 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):
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**20where 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.
argon2
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.
utils
bytesToHexwill convertUint8Arrayto a hex stringrandomBytes(bytes)will produce cryptographically secure randomUint8Arrayof lengthbytes
All available imports
Security
The library has been independently audited:
at version 1.0.0, in Jan 2022, by Cure53
Scope: everything, besides
blake3,sha3-addons,sha1andargon2, which have not been auditedThe audit has been funded by Ethereum Foundation with help of Nomic Labs
It 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.
Constant-timeness
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.
Memory dumping
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:
At some point, input will be a string and strings are immutable in JS: there is no way to overwrite them with zeros. For example: deriving key from
scrypt(password, salt)where password and salt are stringsInput from a file will stay in file buffers
Input / output will be re-used multiple times in application which means it could stay in memory
await 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 memoryThere is no way to guarantee anything about zeroing sensitive data without complex tests-suite which will dump process memory and verify that there is no sensitive data left. For JS it means testing all browsers (incl. mobile), which is complex. And of course it will be useless without using the same test-suite in the actual application that consumes the library
Supply chain security
Commits are signed with PGP keys, to prevent forgery. Make sure to verify commit signatures.
Releases are transparent and built on GitHub CI. Make sure to verify provenance logs
Rare releasing is followed to ensure less re-audit need for end-users
Dependencies are minimized and locked-down:
If your app has 500 dependencies, any dep could get hacked and you'll be downloading malware with every install. We make sure to use as few dependencies as possible
We prevent automatic dependency updates by locking-down version ranges. Every update is checked with
npm-diff
Dev Dependencies are only used if you want to contribute to the repo. They are disabled for end-users:
scure-base, scure-bip32, scure-bip39, micro-bmark and micro-should are developed by the same author and follow identical security practices
prettier (linter), fast-check (property-based testing) and typescript are used for code quality, vector generation and ts compilation. The packages are big, which makes it hard to audit their source code thoroughly and fully
Randomness
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.
Quantum computers
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.
Speed
Benchmarks measured on Apple M2 with node v22.
Compare to native node.js implementation that uses C bindings instead of pure-js code:
It is possible to make this library 4x+ faster by doing code generation of full loop unrolls. We've decided against it. Reasons:
the library must be auditable, with minimum amount of code, and zero dependencies
most method invocations with the lib are going to be something like hashing 32b to 64kb of data
hashing big inputs is 10x faster with low-level languages, which means you should probably pick 'em instead
The current performance is good enough when compared to other projects; SHA256 takes only 900 nanoseconds to run.
Contributing & testing
test/misc directory contains implementations of loop unrolling and md5.
npm install && npm run build && npm testwill build the code and run tests.npm run lint/npm run formatwill run linter / fix linter issues.npm run benchwill run benchmarks, which may need their deps first (npm run bench:install)cd build && npm install && npm run build:releasewill build single fileThere is additional 20-min DoS test
npm run test:dosand 2-hour "big" multicore testnpm run test:big. See our approach to testing
Check out github.com/paulmillr/guidelines for general coding practices and rules.
See paulmillr.com/noble for useful resources, articles, documentation and demos related to the library.
License
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
See LICENSE file.
Last updated