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 / ACVP tests and fuzzing
- 🔁 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
- 🥈 Optional, friendly wrapper over native WebCrypto
- 🪶 21KB (gzipped) for everything, 2.4KB for single-hash build
Check out Upgrading for information about upgrading from previous versions. 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.
- Zero or minimal dependencies
- Highly readable TypeScript / JS code
- PGP-signed releases and transparent NPM builds
- All libraries: ciphers, curves, hashes, post-quantum, 5kb secp256k1 / ed25519
- Check out homepage for reading resources, documentation and apps built with noble
npm install @noble/hashes
deno add jsr:@noble/hashes
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.
- sha2: sha256, sha384, sha512
- sha3: FIPS, SHAKE, Keccak
- sha3-addons: cSHAKE, KMAC, KT128, TurboSHAKE
- blake1, blake2, blake3
- legacy: sha1, md5, ripemd160
- MACs: hmac | kmac | blake3 key mode
- KDFs: hkdf | pbkdf2 | scrypt | argon2
- webcrypto: friendly wrapper
- utils
- Security | Speed | Contributing & testing | License
Hash functions:
- sha256(): receive & return Uint8Array
- sha256.create().update(a).update(b).digest(): support partial updates
- blake3.create({ context: 'e', dkLen: 32 }): can have options
- support little-endian architecture; also experimentally big-endian
- can hash up to 4GB per chunk, with any amount of chunks
Check out RFC 4634 and the paper on truncated SHA512/256.
Check out the differences between SHA-3 and Keccak
- cSHAKE, KMAC, TupleHash, ParallelHash + XOF are available, matching NIST SP 800-185
- Reduced-round Keccak KT128 (KangarooTwelve 🦘, K12) and TurboSHAKE are available, matching RFC 9861.
- KeccakPRG: pseudo-random generator based on Keccak
- Blake1 is legacy hash, one of SHA3 proposals. It is rarely used anywhere. See pdf.
- Blake2 is popular fast hash. blake2b focuses on 64-bit platforms while blake2s is for 8-bit to 32-bit ones. See RFC 7693, Website
- Blake3 is faster, reduced-round blake2. See Website & specs
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:
- Collisions can be made with 2^18 effort in MD5, 2^60 in SHA1, 2^80 in RIPEMD160.
- No practical pre-image attacks (only theoretical, 2^123.4)
- HMAC seems kinda ok: https://datatracker.ietf.org/doc/html/rfc6151
Conforms to RFC 2104.
Conforms to RFC 5869.
Conforms to RFC 2898.
- N, r, p are work factors. It is common to only adjust N, while keeping r: 8, p: 1. See the blog post. 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):
| 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 adjust maxmem, using formula above. Other JS implementations don't support large N-s.
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.
Sometimes people want to use built-in crypto.subtle instead of pure JS implementation. However, it has terrible API.
We simplify access to built-ins with API which mirrors noble-hashes. The overhead is minimal - just 30+ lines of code, which verify input correctness.
Note
Webcrypto methods are always async.
- bytesToHex will convert Uint8Array to a hex string
- randomBytes(bytes) will produce cryptographically secure random Uint8Array of length bytes
The library has been independently audited:
- at version 1.0.0, in Jan 2022, by Cure53
- PDFs: website, in-repo
- Changes since audit.
- Scope: everything, besides blake3, sha3-addons, sha1 and argon2, which have not been audited
- The audit has been funded by Ethereum Foundation with help of Nomic Labs
It 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:
- 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 strings
- Input 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 memory
- There 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
- Commits are signed with PGP keys, to prevent forgery. Make sure to verify commit signatures
- Releases are transparent and built on GitHub CI. Check out attested checksums of single-file builds and provenance logs
- Rare releasing is followed to ensure less re-audit need for end-users
- Dependencies are minimized and locked-down: any dependency could get hacked and users will be downloading malware with every install.
- We make sure to use as few dependencies as possible
- Automatic dep updates are prevented by locking-down version ranges; diffs are checked with npm-diff
- Dev Dependencies are disabled for end-users; they are only used to develop / build the source code
For this package, there are 0 dependencies; and a few dev dependencies:
- jsbt contains helpers for building, benchmarking & testing secure JS apps. It is developed by the same author
- prettier, fast-check and typescript are used for code quality / test generation / ts compilation. It's hard to audit their source code thoroughly and fully because of their size
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.
Benchmarks measured on Apple M4.
Compare to native node.js implementation that uses C bindings instead of pure-js code:
It is possible to make this library 3x+ faster by doing code generation of full loop unrolls. We've decided against it. Reasons:
- current perf is good enough, even compared to other libraries - SHA256 only takes 500 nanoseconds
- 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
Supported node.js versions:
- v2: v20.19+ (ESM-only)
- v1: v14.21+ (ESM & CJS)
v2.0 changelog:
- The package is now ESM-only. ESM can finally be loaded from common.js on node v20.19+
- .js extension must be used for all modules
- Old: @noble/hashes/sha3
- New: @noble/hashes/sha3.js
- This simplifies working in browsers natively without transpilers
- Only allow Uint8Array as hash inputs, prohibit string
- Strict validation checks improve security
- To replicate previous behavior, use utils.utf8ToBytes
- Rename / remove some modules for consistency. Previously, sha384 resided in sha512, which was weird
- sha256, sha512 => sha2.js (consistent with sha3.js)
- blake2b, blake2s => blake2.js (consistent with blake3.js, blake1.js)
- ripemd160, sha1, md5 => legacy.js (all low-security hashes are there)
- _assert => utils.js
- crypto internal module got removed: use built-in WebCrypto instead
- Improve typescript types & option autocomplete
- Bump compilation target from es2020 to es2022
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
- npm run build:release will build single file
- There is additional 20-min DoS test npm run test:dos and 2-hour "big" multicore test npm run test:big. See our approach to testing
Additional resources:
- NTT hashes are outside of scope of the library. They depend on some math which is not available in noble-hashes, it doesn't make sense to add it here. You can view some of them in different repos:
- Polynomial MACs are also outside of scope of the library. They are rarely used outside of encryption. Check out Poly1305 & GHash in noble-ciphers.
- See 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.
.png)
