noble-hashes keeps JavaScript cryptography small enough to read
Audited & minimal JS implementation of hash functions, MACs and KDFs.
At a glance
- What is it?
- noble-hashes is a zero dependency TypeScript library of hash functions, MACs and KDFs from the noble cryptography family, built around three constraints: an independent security audit, a very small shipped size, and code a reviewer can read in one sitting. It also ships a WebCrypto wrapper, which is the more honest choice for most production applications.
- Who is it for?
- Adopt noble-hashes when you need a hash, a MAC or a KDF in JavaScript, you want zero dependencies and you value being able to audit the implementation yourself. Do not adopt it in place of the platform WebCrypto API in an application where a native implementation is available and sufficient, since the webcrypto wrapper exists for exactly that reason.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 61 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 6, 2026, and from our analysis. They are not legal advice.
Star history
- paulmillr/noble-hashes944 ★ · +12
| Repository | 2026-10-21 | 2026-11-06 |
|---|---|---|
| paulmillr/noble-hashes | 932 | 944 |
12 Stars in the last 16 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Three constraints: audit, size, and readability
The README leads with six properties, and three of them explain the rest of the library. The first is an audit by an independent security firm. The second is minimality, stated as 2.8KB gzipped for sha256, with unused code excluded from your builds. The third is that there are no unrolled loops, which the README says makes it easier to verify and reduces source code size up to 5x. That third point is the one that explains the code style. Cryptographic implementations are often written with the loop body manually duplicated so the compiler does not have to unroll it. noble-hashes refuses to do that. The consequence is that the source is a normal loop that a reviewer can read, and a bundler can still optimise it, but the raw text of the library is much shorter than an unrolled equivalent. The other three properties are speed, described as hand optimized for the caveats of JS engines, and reliability through chained and ACVP tests that ensure correctness. The library covers SHA, RIPEMD, BLAKE, HMAC, HKDF, PBKDF, Scrypt and Argon2. It belongs to a family rather than standing alone. The noble cryptography project describes itself as a high security, easily auditable set of contained cryptographic libraries and tools, with zero or minimal dependencies and highly readable TypeScript. The siblings are ciphers, curves, hashes, post-quantum, plus 5kb secp256k1 and ed25519 libraries, and the initial development of the hashes library was funded by the Ethereum Foundation.
Sub-imports are enforced, and the root import fails on purpose
The very first usage example in the README is a warning, and it is easy to miss.
// import * from '@noble/hashes'; // Error: use sub-imports, to ensure small app size
import { sha256 } from '@noble/hashes/sha2.js';
const hash = sha256(Uint8Array.from([0xca, 0xfe, 0x01, 0x23]));Importing the package root is an error, not a warning. Every algorithm lives behind its own path, and the exports map in package.json confirms it: an entry for sha2.js, sha3.js, sha3-addons.js, blake1.js, blake2.js, blake3.js, legacy.js, hmac.js, hkdf.js, pbkdf2.js, scrypt.js, argon2.js, eskdf.js, webcrypto.js and utils. This is unusual and it is deliberate. A bundler that tree shakes cannot always prove that a root level namespace import is unused, so the library removes the temptation rather than relying on the bundler. The result is that the algorithm you never import cannot end up in your bundle, which is what the 2.8KB figure for sha256 is measuring. Installation is straightforward, and the library supports npm and Deno.
npm install @noble/hashesdeno add jsr:@noble/hashesThe README states that all major platforms and runtimes are supported, with a caveat for React Native, where you may need a polyfill for getRandomValues. A standalone file is also published on the releases page for people who want to vendor a single script.
The algorithm families and how their APIs differ
Most functions follow one shape, returning a Uint8Array, and most also have a streaming form.
import { sha256 } from '@noble/hashes/sha2.js';
const res = sha256(Uint8Array.from([0xbc]));The sha2 module covers sha224, sha256, sha384, sha512, sha512_224 and sha512_256. The sha3 module covers the FIPS variants sha3_224 through sha3_512, the Keccak variants keccak_224 through keccak_512, and the extendable output functions shake128 and shake256, where the output length is a parameter.
import {
sha3_224, sha3_256, sha3_384, sha3_512,
keccak_224, keccak_256, keccak_384, keccak_512,
shake128, shake256,
} from '@noble/hashes/sha3.js';
const s = sha3_256(Uint8Array.from([0x10, 0x20, 0x30]));
const shka = shake128(Uint8Array.from([0x10]), { dkLen: 512 });
const shkb = shake256(Uint8Array.from([0x30]), { dkLen: 512 });The BLAKE family has the richest option surface, because BLAKE2 and BLAKE3 both take a key, and BLAKE2 also takes a salt and a personalisation string.
import { blake3 } from '@noble/hashes/blake3.js';
const ab = Uint8Array.from([0x01]);
const txt = new TextEncoder();
blake3(ab, { dkLen: 256 });
blake3(ab, { key: new Uint8Array(32) });
blake3(ab, { context: txt.encode('application-name') });The legacy module is where the weak algorithms are quarantined, which is a good design decision on its own.
import { md5, ripemd160, sha1 } from '@noble/hashes/legacy.js';
const h = sha1(Uint8Array.from([0x10, 0x20, 0x30]));Putting sha1 and md5 behind a path named legacy rather than exporting them alongside sha256 removes the chance that a casual import treats them as interchangeable with the modern ones.
MACs and KDFs: the parts you actually use in an application
The MAC and KDF layers are where a hash library becomes a working cryptography toolkit. HMAC takes the hash function as its first argument, which is how it stays generic over sha2, sha3 and blake variants.
import { hmac } from '@noble/hashes/hmac.js';
import { sha256 } from '@noble/hashes/sha2.js';
const key = new Uint8Array(32).fill(1);
const msg = new Uint8Array(32).fill(2);
const mac1 = hmac(sha256, key, msg);
const mac2 = hmac.create(sha256, key).update(msg).digest();HKDF is exposed both as a single call and as its two steps, extract and expand, which is the same result by construction.
import { hkdf } from '@noble/hashes/hkdf.js';
import { randomBytes } from '@noble/hashes/utils.js';
import { sha256 } from '@noble/hashes/sha2.js';
const inputKey = randomBytes(32);
const salt = randomBytes(32);
const info = new TextEncoder().encode('application-key');
const hk1 = hkdf(sha256, inputKey, salt, info, 32);The password based KDFs come in both a blocking and an asynchronous form, and the async one matters for a server.
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2.js';
import { sha256 } from '@noble/hashes/sha2.js';
const pbkey1 = pbkdf2(sha256, 'password', 'salt', { c: 524288, dkLen: 32 });
const pbkey2 = await pbkdf2Async(sha256, 'password', 'salt', { c: 524288, dkLen: 32 });Scrypt follows the same pattern with scrypt and scryptAsync, and the module list also covers argon2 and eskdf. The SHA3 addons module carries the less common constructions: cshake128 and cshake256, kmac128 and kmac256, kt128 and kt256, turboshake128 and turboshake256, keccakprg as a random byte generator, and the tuple and parallel hash variants. The tuple hash example in the README shows the property that matters for it, that tuplehash of ['ab', 'c'] differs from tuplehash of ['a', 'bc'].
The WebCrypto wrapper and the limits of the JavaScript implementations
The README describes one of the exports as a wrapper with an identical API over native WebCrypto. That entry point exists for a good reason: when the platform provides a native implementation, using it is usually both faster and safer than shipping your own. The JavaScript implementations also carry their own limits, and the README is explicit about the first one. The parallel hash function carries the comment that it is not parallel in JavaScript, similar to blake3 and kt128, and that it was added for compatibility. So a construction whose specification is defined in terms of parallelism loses that property here. A second limit is scale. The README states the library can hash up to 4GB per chunk, with any amount of chunks. The chunk figure is the ceiling per call, not a ceiling on the total, but it means very large inputs need the streaming API rather than a single call. A third is the blocking behaviour of the synchronous variants. pbkdf2, scrypt and the plain hash functions have sync forms that will occupy the event loop for their duration. In a Node.js server that handles other requests on the same thread, the async variants exist for that reason. Finally, the legacy module. sha1, md5 and ripemd160 are available because they are needed for interoperability with existing systems and file formats, and the module name is the warning. Nothing in the library prevents you from hashing a password with md5, which is why the separation matters.
MIT licence, PGP signed releases, and a test suite split by cost
The licence field on the repository says MIT, and the noble family as a whole advertises PGP signed releases and transparent NPM builds as part of its release process. The initial development of this library was funded by the Ethereum Foundation, which is worth knowing if you are evaluating the maintenance model of the wider set. The repository layout supports the claim of being transparent. There is an audit/ directory for the audit material, a benchmark/ directory, a test/ directory, a SECURITY.md file and a CHANGELOG.md file. The test scripts show a deliberate split by how long they take, which is the practical way to test a crypto library.
npm test
npm run test:slow
npm run test:dos
npm run test:acvp
npm run test:kdfThe quick suite runs node test/index.ts, while the slow ones are separate targets for denial of service, ACVP vectors, KDFs and extreme scrypt parameters. There is also a benchmark:size target using bismar, which is where the 2.8KB figure is measured, and benchmark:thirdparty scripts that compare against other libraries. On releases, the version in package.json is 2.4.0, and the tagged releases are 2.4.0 on 2026-08-27, 2.3.0 on 2026-08-06 and 2.2.0 on 2026-04-11. The last push was on 2026-09-08 and the repository is not archived, so this is a project with current work behind it rather than an abandoned one.
Editorial conclusion
Adopt noble-hashes when you need a hash, a MAC or a KDF in JavaScript, you want zero dependencies and you value being able to audit the implementation yourself. Do not adopt it in place of the platform WebCrypto API in an application where a native implementation is available and sufficient, since the webcrypto wrapper exists for exactly that reason. Before shipping, check the exports map in package.json against the algorithm you intend to import, because the package deliberately refuses to work through a bare root import.
Frequently asked questions
How do I install noble-hashes?
Run npm install @noble/hashes, or deno add jsr:@noble/hashes for Deno. The package has zero runtime dependencies, and a standalone noble-hashes.js file is also published on the releases page.
Why does importing from the root of @noble/hashes fail?
The README marks the root import with an error comment saying to use sub-imports to ensure small app size. Each algorithm has its own export path, such as @noble/hashes/sha2.js, and the exports map in package.json lists them individually.
Which hash algorithms does noble-hashes include?
The sha2 module has sha224, sha256, sha384, sha512, sha512_224 and sha512_256. The sha3 module has the FIPS SHAKE and Keccak variants, the blake modules cover blake1, blake2 and blake3, and legacy.js holds md5, ripemd160 and sha1.
What MAC and KDF functions are available?
MACs include hmac, kmac and the blake3 key mode. KDFs include hkdf, pbkdf2, scrypt, argon2 and eskdf, and the sha3-addons module adds cshake, kt128 and kt256, turboshake and keccakprg.
Is noble-hashes audited?
The README states that the library is audited by an independent security firm, and the repository carries an audit/ directory along with a SECURITY.md file. It also states that chained and ACVP tests ensure correctness.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/paulmillr-noble-hashes)Star history chart for your README
[](https://hysenlabs.com/projects/paulmillr-noble-hashes)Was this useful?