Socket
Socket
Sign inDemoInstall

noble-hashes

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

noble-hashes

Fast 0-dependency JS implementation of SHA2, SHA3, RIPEMD, BLAKE, HMAC, HKDF, PBKDF2, Scrypt


Version published
Weekly downloads
76
increased by7.04%
Maintainers
1
Weekly downloads
 
Created
Source

noble-hashes Node CI code style: prettier

Fast, secure & minimal JS implementation of SHA2, SHA3, RIPEMD, BLAKE2, HMAC, HKDF, PBKDF2 & Scrypt.

Benefits of noble-hashes over other libraries:

  • noble brand (see below) / zero dependencies
  • Helps JS bundlers with lack of entry point; ensures small size of your app
  • No unrolled loops. Makes it much easier to verify and reduces source code size 2-5x
  • Unique tests ensure correctness. That includes chained tests (hash(hash(hash(....)))), sliding window tests, DoS tests
  • Differential fuzzing ensures even more correctness. We do it with cryptofuzz
  • Hash functions support hashing 4GB of data per update on 64-bit systems (unlimited with streaming)
  • Scrypt supports n: 2**22 with 4GB arrays (almost every other implementation crashes; some crash on 2**20), maxmem security param, onProgress callback
  • Overall size of all primitives is ~1800 TypeScript LOC, or 35KB minified (12KB gzipped). You can select specific functions, SHA256-only would be ~400 LOC / 6.5KB minified (3KB gzipped)

The library's initial development was funded by Ethereum Foundation.

Matches following specs:

This library belongs to noble crypto

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

  • No dependencies, small files
  • Easily auditable TypeScript/JS code
  • Supported in all major browsers and stable node.js versions
  • All releases are signed with PGP keys
  • Check out all libraries: secp256k1, ed25519, bls12-381, hashes

Usage

Use NPM in node.js / browser, or include single file from GitHub's releases page:

npm install noble-hashes

The library does not have an entry point. It allows you to select specific primitives and drop everything else. If you only want to use sha256, just use the library with rollup or other bundlers. This is done to make your bundles tiny.

const { sha256 } = require('noble-hashes/lib/sha256');
console.log(sha256(new Uint8Array([1, 2, 3])));
// Uint8Array(32) [3, 144,  88, 198, 242, 192, 203,  73, ...]

// you could also pass strings that will be UTF8-encoded to Uint8Array
console.log(sha256('abc'))); // == sha256(new TextEncoder().encode('abc'))

// sha384 is here, because it uses same internals as sha512
const { sha512, sha512_256, sha384 } = require('noble-hashes/lib/sha512');
// prettier-ignore
const {
  sha3_224, sha3_256, sha3_384, sha3_512,
  keccak_224, keccak_256, keccak_384, keccak_512
} = require('noble-hashes/lib/sha3');
const { ripemd160 } = require('noble-hashes/lib/ripemd160');
const { blake2b } = require('noble-hashes/lib/blake2b');
const { blake2s } = require('noble-hashes/lib/blake2s');
const { hmac } = require('noble-hashes/lib/hmac');
const { hkdf } = require('noble-hashes/lib/hkdf');
const { pbkdf2, pbkdf2Async } = require('noble-hashes/lib/pbkdf2');
const { scrypt, scryptAsync } = require('noble-hashes/lib/scrypt');

// small utility method that converts bytes to hex
const { bytesToHex as toHex } = require('noble-hashes/lib/utils');
console.log(toHex(sha256('abc')));
// ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

API

Any hash function:

  1. Can be called directly, like sha256(new Uint8Array([1, 3])), or initialized as a class: sha256.create().update(new Uint8Array([1, 3]).digest()
  2. Can receive either an Uint8Array, or a string that would be automatically converted to Uint8Array via new TextEncoder().encode(string). The output is always Uint8Array.
  3. Can receive an option object as a second argument: sha256('abc', {cleanup: true}); or sha256.create({cleanup: true}).update('abc').digest()
SHA2 (sha256, sha512, sha512_256)
import { sha256 } from 'noble-hashes/lib/sha256.js';
// function sha256(data: Uint8Array): Uint8Array;
const hash1 = sha256('abc');
const hash2 = sha256.create().update(Uint8Array.from([1, 2, 3])).digest();
import { sha512 } from 'noble-hashes/lib/sha512.js';
const hash3 = sha512('abc');
const hash4 = sha512.create().update(Uint8Array.from([1, 2, 3])).digest();

// SHA512/256 variant
import { sha512_256 } from 'noble-hashes/lib/sha512.js';
const hash3_a = sha512_256('abc');
const hash4_a = sha512_256.create().update(Uint8Array.from([1, 2, 3])).digest();

import { sha384 } from 'noble-hashes/lib/sha512.js';
const hash3_b = sha384('abc');
const hash4_b = sha384.create().update(Uint8Array.from([1, 2, 3])).digest();

To learn more about SHA512/256, check out the paper.

SHA3 (sha3_256, keccak_256, etc)
import {
  sha3_224, sha3_256, sha3_384, sha3_512,
  keccak_224, keccak_256, keccak_384, keccak_512
} from 'noble-hashes/lib/sha3.js';
const hash5 = sha3_256('abc');
const hash6 = sha3_256.create().update(Uint8Array.from([1, 2, 3])).digest();
const hash7 = keccak_256('abc');

See the differences between SHA-3 and Keccak

RIPEMD-160
import { ripemd160 } from 'noble-hashes/lib/ripemd160.js';
// function ripemd160(data: Uint8Array): Uint8Array;
const hash8 = ripemd160('abc');
const hash9 = ripemd160().create().update(Uint8Array.from([1, 2, 3])).digest();
BLAKE2b, BLAKE2s
import { blake2b } from 'noble-hashes/lib/blake2b.js';
import { blake2s } from 'noble-hashes/lib/blake2s.js';
const hash10 = blake2s('abc');
const b2params = {key: new Uint8Array([1]), personalization: t, salt: t, dkLen: 32};
const hash11 = blake2s('abc', b2params);
const hash12 = blake2s.create(b2params).update(Uint8Array.from([1, 2, 3])).digest();
HMAC
import { hmac } from 'noble-hashes/lib/mac.js';
import { sha256 } from 'noble-hashes/lib/sha256.js';
const mac1 = hmac(sha256, 'key', 'message');
const mac2 = hmac.create(sha256, Uint8Array.from([1, 2, 3])).update(Uint8Array.from([4, 5, 6]).digest();
HKDF
import { hkdf } from 'noble-hashes/lib/kdf.js';
import { sha256 } from 'noble-hashes/lib/sha256.js';
import { randomBytes } from 'noble-hashes/utils.js';
const inputKey = randomBytes(32);
const salt = randomBytes(32);
const info = 'abc';
const dkLen = 32;
const hk1 = hkdf(sha256, inputKey, salt, info, dkLen);

// == same as
import { hkdf_extract, hkdf_expand } from 'noble-hashes/lib/kdf.js';
import { sha256 } from 'noble-hashes/lib/sha256.js';
const prk = hkdf_extract(sha256, inputKey, salt)
const hk2 = hkdf_expand(sha256, prk, info, dkLen);
PBKDF2
import { pbkdf2, pbkdf2Async } from 'noble-hashes/lib/kdf.js';
import { sha256 } from 'noble-hashes/lib/sha256.js';
const pbkey1 = pbkdf2(sha256, 'password', 'salt', { c: 32, dkLen: 32 });
const pbkey2 = await pbkdf2Async(sha256, 'password', 'salt', { c: 32, dkLen: 32 });
const pbkey3 = await pbkdf2Async(
  sha256, Uint8Array.from([1, 2, 3]), Uint8Array.from([4, 5, 6]), { c: 32, dkLen: 32 }
);
Scrypt
import { scrypt, scryptAsync } from 'noble-hashes/lib/scrypt.js';
const scr1 = scrypt('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 });
const scr2 = await scryptAsync('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 });
const scr3 = await scryptAsync(
  Uint8Array.from([1, 2, 3]), Uint8Array.from([4, 5, 6]),
  {
    N: 2 ** 22,
    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)
  }
);
  • N, r, p are work factors. To understand them, see the blog post.
  • dkLen is the length of output bytes
  • It is common to use N from 2**10 to 2**22 and {r: 8, p: 1, dkLen: 32}
  • onProgress can be used with async version of the function to report progress to a user.

Memory usage of scrypt is calculated with the formula N * r * p * 128 + (128 * r * p), which means {N: 2 ** 22, r: 8, p: 1} will use 4GB + 1KB of memory. To prevent DoS, we limit scrypt to 1GB + 1KB of RAM used, which corresponds to {N: 2 ** 20, r: 8, p: 1}. If you want to use higher values, increase maxmem using the formula above.

Note: noble supports 2**22 (4GB RAM) which is the highest amount amongst JS libs. Many other implementations don't support it. We cannot support 2**23, because there is a limitation in JS engines that makes allocating arrays bigger than 4GB impossible, but we're looking into other possible solutions.

utils
import { bytesToHex as toHex, randomBytes } from 'noble-hashes/lib/scrypt.js';
console.log(toHex(randomBytes(32)));
  • bytesToHex will convert Uint8Array to a hex string
  • randomBytes(bytes) will produce cryptographically secure random Uint8Array of length bytes

Security

Noble is production-ready.

The library will be audited by an independent security firm in the next few months.

The library has been fuzzed by Guido Vranken's cryptofuzz. You can run the fuzzer by yourself to check it.

A note on timing attacks: JIT-compiler and Garbage Collector make "constant time" extremely hard to achieve 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.

We consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading rootkits with every npm install. Our goal is to minimize this attack vector.

Speed

Benchmarks measured with Apple M1. 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 941,619 ops/sec @ 1μs/op
SHA384 32B x 420,875 ops/sec @ 2μs/op
SHA512 32B x 422,654 ops/sec @ 2μs/op
SHA512-256 32B x 422,832 ops/sec @ 2μs/op
SHA3-256 32B x 184,229 ops/sec @ 5μs/op
keccak-256 32B x 186,046 ops/sec @ 5μs/op
BLAKE2s 32B x 505,561 ops/sec @ 1μs/op
BLAKE2b 32B x 284,981 ops/sec @ 3μs/op
HMAC-SHA256 32B x 277,161 ops/sec @ 3μs/op
RIPEMD160 32B x 984,251 ops/sec @ 1μs/op
HKDF-SHA256 32B noble x 115,500 ops/sec @ 8μs/op
PBKDF2-HMAC-SHA256 262144 noble x 2 ops/sec @ 338ms/op
PBKDF2-HMAC-SHA512 262144 noble x 0 ops/sec @ 1024ms/op
Scrypt r: 8, p: 1, n: 262144 noble x 1 ops/sec @ 637ms/op

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

SHA256 32B node x 569,151 ops/sec @ 1μs/op
SHA384 32B node x 548,245 ops/sec @ 1μs/op
SHA512 32B node x 551,267 ops/sec @ 1μs/op
SHA512-256 32B node x 534,473 ops/sec @ 1μs/op
SHA3 32B node x 545,553 ops/sec @ 1μs/op
BLAKE2s 32B node x 545,256 ops/sec @ 1μs/op
BLAKE2b 32B node x 583,090 ops/sec @ 1μs/op
HMAC-SHA256 32B node x 500,751 ops/sec @ 1μs/op
RIPEMD160 32B node x 509,424 ops/sec @ 1μs/op
HKDF-SHA256 32B node x 207,856 ops/sec @ 4μs/op
PBKDF2-256 262144 node x 23 ops/sec @ 42ms/op
Scrypt 262144 node x 1 ops/sec @ 564ms/op
// `scrypt.js` package
Scrypt 262144 scrypt.js x 0 ops/sec @ 1678ms/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 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 is 1.6x faster than native C bindings.

Contributing & testing

  1. Clone the repository.
  2. npm install to install build dependencies like TypeScript
  3. npm run build to compile TypeScript code
  4. npm run test will execute all main tests. See our approach to testing
  5. npm run test-dos will test against DoS; by measuring function complexity. Takes ~20 minutes
  6. npm 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.

License

The MIT License (MIT)

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

See LICENSE file.

Keywords

FAQs

Package last updated on 18 Oct 2021

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc