Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Audited & minimal JS implementation of hash functions, MACs and KDFs.

License

NotificationsYou must be signed in to change notification settings

paulmillr/noble-hashes

Repository files navigation

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
  • 🪶 20KB (gzipped) for everything, 2.4KB for single-hash build

Check outUpgrading for information about upgrading from previous versions.Take a glance atGitHub Discussions for questions and support.The library's initial development was funded byEthereum Foundation.

This library belongs tonoble cryptography

noble cryptography — high-security, easily auditable set of contained cryptographic libraries and tools.

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 apolyfill for getRandomValues.A standalone filenoble-hashes.js is also available.

// import * from '@noble/hashes'; // Error: use sub-imports, to ensure small app sizeimport{sha256}from'@noble/hashes/sha2.js';consthash=sha256(Uint8Array.from([0xca,0xfe,0x01,0x23]));// Available modulesimport{sha256,sha384,sha512,sha224,sha512_224,sha512_256}from'@noble/hashes/sha2.js';import{sha3_256,sha3_512,keccak_256,keccak_512,shake128,shake256,}from'@noble/hashes/sha3.js';import{cshake256,turboshake256,kmac256,tuplehash256,kt128,kt256,keccakprg,}from'@noble/hashes/sha3-addons.js';import{blake3}from'@noble/hashes/blake3.js';import{blake2b,blake2s}from'@noble/hashes/blake2.js';import{blake256,blake512}from'@noble/hashes/blake1.js';import{sha1,md5,ripemd160}from'@noble/hashes/legacy.js';import{hmac}from'@noble/hashes/hmac.js';import{hkdf}from'@noble/hashes/hkdf.js';import{pbkdf2,pbkdf2Async}from'@noble/hashes/pbkdf2.js';import{scrypt,scryptAsync}from'@noble/hashes/scrypt.js';import{argon2d,argon2i,argon2id}from'@noble/hashes/argon2.js';// sha256, sha384, sha512, hmac, hkdf, pbkdf2import*aswebcryptofrom'@noble/hashes/webcrypto.js';// bytesToHex, bytesToUtf8, concatBytesimport*asutilsfrom'@noble/hashes/utils.js';

Implementations

Hash functions:

  • sha256(): receive & returnUint8Array
  • 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

sha2: sha256, sha384, sha512 and others

import{sha224,sha256,sha384,sha512,sha512_224,sha512_256}from'@noble/hashes/sha2.js';constres=sha256(Uint8Array.from([0xbc]));// basicfor(lethashof[sha256,sha384,sha512,sha224,sha512_224,sha512_256]){constarr=Uint8Array.from([0x10,0x20,0x30]);consta=hash(arr);constb=hash.create().update(arr).digest();}

Check outRFC 4634 andthe paper on truncated SHA512/256.

sha3: FIPS, SHAKE, Keccak

import{sha3_224,sha3_256,sha3_384,sha3_512,keccak_224,keccak_256,keccak_384,keccak_512,shake128,shake256,}from'@noble/hashes/sha3.js';for(lethashof[sha3_224,sha3_256,sha3_384,sha3_512,keccak_224,keccak_256,keccak_384,keccak_512,]){constarr=Uint8Array.from([0x10,0x20,0x30]);consta=hash(arr);constb=hash.create().update(arr).digest();}constshka=shake128(Uint8Array.from([0x10]),{dkLen:512});constshkb=shake256(Uint8Array.from([0x30]),{dkLen:512});

Check outFIPS-202,Website.

Check outthe differences between SHA-3 and Keccak

sha3-addons: cSHAKE, KMAC, K12, TurboSHAKE

import{cshake128,cshake256,kt128,kt256,keccakprg,kmac128,kmac256,parallelhash256,tuplehash256,turboshake128,turboshake256,}from'@noble/hashes/sha3-addons.js';constdata=Uint8Array.from([0x10,0x20,0x30]);constec1=cshake128(data,{personalization:'def'});constec2=cshake256(data,{personalization:'def'});constet1=turboshake128(data);constet2=turboshake256(data,{D:0x05});// tuplehash(['ab', 'c']) !== tuplehash(['a', 'bc']) !== tuplehash([data])constet3=tuplehash256([utf8ToBytes('ab'),utf8ToBytes('c')]);// Not parallel in JS (similar to blake3 / kt128), added for compatconstep1=parallelhash256(data,{blockLen:8});constkk=Uint8Array.from([0xca]);constek10=kmac128(kk,data);constek11=kmac256(kk,data);constek12=kt128(data);// kangarootwelve 128-bitconstek13=kt256(data);// kangarootwelve 256-bit// pseudo-random generator, first argument is capacity. XKCP recommends 254 bits capacity for 128-bit security strength.// * with a capacity of 254 bits.constp=keccakprg(254);p.feed('test');constrand1b=p.fetch(1);
  • cSHAKE, KMAC, TupleHash, ParallelHash + XOF are available, matchingNIST SP 800-185
  • Reduced-round Keccak KT128 (KangarooTwelve 🦘, K12) and TurboSHAKE are available, matchingkangaroo-draft-17.
  • KeccakPRG: pseudo-random generator based on Keccak

blake1, blake2, blake3

import{blake224,blake256,blake384,blake512}from'@noble/hashes/blake1.js';import{blake2b,blake2s}from'@noble/hashes/blake2.js';import{blake3}from'@noble/hashes/blake3.js';for(lethashof[blake224,blake256,blake384,blake512,blake2b,blake2s,blake3]){constarr=Uint8Array.from([0x10,0x20,0x30]);consta=hash(arr);constb=hash.create().update(arr).digest();}// blake2 advanced usageconstab=Uint8Array.from([0x01]);blake2s(ab);blake2s(ab,{key:newUint8Array(32)});blake2s(ab,{personalization:'pers1234'});blake2s(ab,{salt:'salt1234'});blake2b(ab);blake2b(ab,{key:newUint8Array(64)});blake2b(ab,{personalization:'pers1234pers1234'});blake2b(ab,{salt:'salt1234salt1234'});// blake3 advanced usageblake3(ab);blake3(ab,{dkLen:256});blake3(ab,{key:newUint8Array(32)});blake3(ab,{context:'application-name'});
  • Blake1 is legacy hash, one of SHA3 proposals. It is rarely used anywhere. Seepdf.
  • Blake2 is popular fast hash. blake2b focuses on 64-bit platforms while blake2s is for 8-bit to 32-bit ones. SeeRFC 7693,Website
  • Blake3 is faster, reduced-round blake2. SeeWebsite & specs

legacy: sha1, md5, ripemd160

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:

import{md5,ripemd160,sha1}from'@noble/hashes/legacy.js';for(lethashof[md5,ripemd160,sha1]){constarr=Uint8Array.from([0x10,0x20,0x30]);consta=hash(arr);constb=hash.create().update(arr).digest();}

hmac

import{hmac}from'@noble/hashes/hmac.js';import{sha256}from'@noble/hashes/sha2.js';constkey=newUint8Array(32).fill(1);constmsg=newUint8Array(32).fill(2);constmac1=hmac(sha256,key,msg);constmac2=hmac.create(sha256,key).update(msg).digest();

Conforms toRFC 2104.

hkdf

import{hkdf}from'@noble/hashes/hkdf.js';import{randomBytes}from'@noble/hashes/utils.js';import{sha256}from'@noble/hashes/sha2.js';constinputKey=randomBytes(32);constsalt=randomBytes(32);constinfo='application-key';consthk1=hkdf(sha256,inputKey,salt,info,32);// == same asimport{extract,expand}from'@noble/hashes/hkdf.js';import{sha256}from'@noble/hashes/sha2.js';constprk=extract(sha256,inputKey,salt);consthk2=expand(sha256,prk,info,32);

Conforms toRFC 5869.

pbkdf2

import{pbkdf2,pbkdf2Async}from'@noble/hashes/pbkdf2.js';import{sha256}from'@noble/hashes/sha2.js';constpbkey1=pbkdf2(sha256,'password','salt',{c:524288,dkLen:32});constpbkey2=awaitpbkdf2Async(sha256,'password','salt',{c:524288,dkLen:32});constpbkey3=awaitpbkdf2Async(sha256,Uint8Array.from([1,2,3]),Uint8Array.from([4,5,6]),{c:524288,dkLen:32,});

Conforms toRFC 2898.

scrypt

import{scrypt,scryptAsync}from'@noble/hashes/scrypt.js';constscr1=scrypt('password','salt',{N:2**16,r:8,p:1,dkLen:32});constscr2=awaitscryptAsync('password','salt',{N:2**16,r:8,p:1,dkLen:32});constscr3=awaitscryptAsync(Uint8Array.from([1,2,3]),Uint8Array.from([4,5,6]),{N:2**17,r:8,p:1,dkLen:32,onProgress(percentage){console.log('progress',percentage);},maxmem:2**32+128*8*1,// N * r * p * 128 + (128*r*p)});

Conforms toRFC 7914,Website

  • N, r, p are work factors. It is common to only adjust N, while keepingr: 8, p: 1.Seethe blog post.JS doesn't support parallelization, making increasingp meaningless.
  • dkLen is the length of output bytes e.g.32 or64
  • onProgress can be used with async version of the function to report progress to a user.
  • maxmem prevents 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 M4 (mobile phones can be 1x-4x slower):

N powTimeRAM
160.1s64MB
170.2s128MB
180.4s256MB
190.8s512MB
201.5s1GB
213.1s2GB
226.2s4GB
2313s8GB
2427s16GB

Note

We support N larger than2**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.

argon2

import{argon2d,argon2i,argon2id}from'@noble/hashes/argon2.js';constarg1=argon2id('password','saltsalt',{t:2,m:65536,p:1,maxmem:2**32-1});

Argon2RFC 9106 implementation.

Warning

Argon2 can't be fast in JS, because there is no fast Uint64Array.It is suggested to useScrypt instead.Being 5x slower than native code means brute-forcing attackers have bigger advantage.

webcrypto: friendly wrapper

import{sha256,sha384,sha512,hmac,hkdf,pbkdf2}from'@noble/hashes/webcrypto.js';constwhash=awaitsha256(Uint8Array.from([0xca,0xfe,0x01,0x23]));constkey=newUint8Array(32).fill(1);constmsg=newUint8Array(32).fill(2);constwmac=awaithmac(sha256,key,msg);constinputKey=randomBytes(32);constsalt=randomBytes(32);constinfo='application-key';consthk1=awaithkdf(sha256,inputKey,salt,info,32);constpbkey1=awaitpbkdf2(sha256,'password','salt',{c:524288,dkLen:32});

Sometimes people want to use built-incrypto.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.

utils

import{bytesToHexastoHex,randomBytes}from'@noble/hashes/utils.js';console.log(toHex(randomBytes(32)));
  • bytesToHex will convertUint8Array to a hex string
  • randomBytes(bytes) will produce cryptographically secure randomUint8Array of lengthbytes

Security

The library has been independently audited:

It is tested against property-based, cross-library and Wycheproof vectors,and is being fuzzed inthe separate repo.

If you see anything unusual: investigate and report.

Constant-timeness

We're targetting algorithmic constant time.JIT-compiler andGarbage Collector make "constant time"extremely hard to achievetiming attack resistancein a scripting language. Which meansany other JS library can't haveconstant-timeness. Even statically typed Rust, a language without GC,makes it harder to achieve constant-timefor some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones.Use low-level libraries & languages.

Memory dumping

The library shares state buffers between hashfunction calls. The buffers are zeroed-out after each call. However, if an attackercan 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: derivingkey fromscrypt(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 codechunk 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 withoutcomplex tests-suite which will dump process memory and verify that there isno 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 sametest-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.Check outattested checksums of single-file buildsandprovenance 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 withnpm-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:

  • micro-bmark, micro-should and jsbt are used for benchmarking / testing / build tooling and 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

Randomness

We're deferring to built-incrypto.getRandomValueswhich 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 weaknessis even worse: there is no reliable userspace source of quality entropy.

Quantum computers

Cryptographically relevant quantum computer, if built, will allow toutilize 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 hashesafter 2030.

Speed

npm run bench

Benchmarks measured on Apple M4.

# 32Bsha256 x 2,016,129 ops/sec @ 496ns/opsha512 x 740,740 ops/sec @ 1μs/opsha3_256 x 287,686 ops/sec @ 3μs/opsha3_512 x 288,267 ops/sec @ 3μs/opk12 x 476,190 ops/sec @ 2μs/opblake2b x 464,252 ops/sec @ 2μs/opblake2s x 766,871 ops/sec @ 1μs/opblake3 x 879,507 ops/sec @ 1μs/op# 1MBsha256 x 331 ops/sec @ 3ms/opsha512 x 129 ops/sec @ 7ms/opsha3_256 x 38 ops/sec @ 25ms/opsha3_512 x 20 ops/sec @ 47ms/opk12 x 88 ops/sec @ 11ms/opblake2b x 69 ops/sec @ 14ms/opblake2s x 57 ops/sec @ 17ms/opblake3 x 72 ops/sec @ 13ms/op# MAChmac(sha256) x 599,880 ops/sec @ 1μs/ophmac(sha512) x 197,122 ops/sec @ 5μs/opkmac256 x 87,981 ops/sec @ 11μs/opblake3(key) x 796,812 ops/sec @ 1μs/op# KDFhkdf(sha256) x 259,942 ops/sec @ 3μs/opblake3(context) x 424,808 ops/sec @ 2μs/oppbkdf2(sha256, c: 2 ** 18) x 5 ops/sec @ 197ms/oppbkdf2(sha512, c: 2 ** 18) x 1 ops/sec @ 630ms/opscrypt(n: 2 ** 18, r: 8, p: 1) x 2 ops/sec @ 400ms/opargon2id(t: 1, m: 256MB) 2881ms

Compare to native node.js implementation that uses C bindings instead of pure-js code:

# native (node) 32Bsha256 x 2,267,573 ops/secsha512 x 983,284 ops/secsha3_256 x 1,522,070 ops/secblake2b x 1,512,859 ops/secblake2s x 1,821,493 ops/sechmac(sha256) x 1,085,776 ops/sechkdf(sha256) x 312,109 ops/sec# native (node) KDFpbkdf2(sha256, c: 2 ** 18) x 5 ops/sec @ 197ms/oppbkdf2(sha512, c: 2 ** 18) x 1 ops/sec @ 630ms/opscrypt(n: 2 ** 18, r: 8, p: 1) x 2 ops/sec @ 378ms/op

It is possible tomake this library 3x+ faster bydoing 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

Upgrading

Supported node.js versions:

  • v2: v20.19+ (ESM-only)
  • v1: v14.21+ (ESM & CJS)

v2.0 changelog:

  • Bump minimum node.js version from v14 to v20.19
  • Bump compilation target from es2020 to es2022
  • Make package ESM-only
    • node.js v20.19+ allows loading ESM modules from common.js
  • Remove extension-less exports: e.g.sha3 becamesha3.js
    • This allows using package without import maps and allows package to be used in browsers directly, without bundlers
  • Only allow Uint8Array as hash inputs, prohibitstring
    • Strict validation checks improve security
    • To replicate previous behavior, useutils.utf8ToBytes
  • Rename / remove some modules for consistency. Previously, sha384 resided in sha512, which was weird
    • sha256,sha512 =>sha2.js (consistent withsha3)
    • blake2b,blake2s =>blake2.js (consistent withblake1,blake3)
    • 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
    • Improve option autocomplete
    • Simplify types inutils
    • Use single createHasher for wrapping instead of 3 methods

Contributing & testing

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 file
  • There isadditional 20-min DoS testnpm run test:dos and 2-hour "big" multicore testnpm run test:big.Seeour approach to testing

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 outPoly1305 & GHash in noble-ciphers.

Additional resources:

License

The MIT License (MIT)

Copyright (c) 2022 Paul Miller(https://paulmillr.com)

See LICENSE file.


[8]ページ先頭

©2009-2025 Movatter.jp