Add debug logging to see received auth data
This commit is contained in:
536
node_modules/@noble/hashes/README.md
generated
vendored
Normal file
536
node_modules/@noble/hashes/README.md
generated
vendored
Normal file
@@ -0,0 +1,536 @@
|
||||
# noble-hashes
|
||||
|
||||
Audited & minimal JS implementation of SHA2, SHA3, RIPEMD, BLAKE2/3, HMAC, HKDF, PBKDF2 & Scrypt.
|
||||
|
||||
- 🔒 [**Audited**](#security) by an independent security firm
|
||||
- 🔻 Tree-shaking-friendly: use only what's necessary, other code won't be included
|
||||
- 🏎 Ultra-fast, hand-optimized for caveats of JS engines
|
||||
- 🔍 Unique tests ensure correctness: chained tests, sliding window tests, DoS tests, fuzzing
|
||||
- 🔁 No unrolled loops: makes it easier to verify and reduces source code size up to 5x
|
||||
- 🐢 Scrypt supports `N: 2**22`, while other implementations are limited to `2**20`
|
||||
- 🦘 SHA3 supports Keccak, TupleHash, KangarooTwelve and MarsupilamiFourteen
|
||||
- 🪶 Just 3.4k lines / 17KB gzipped. SHA256-only is 240 lines / 3KB gzipped
|
||||
|
||||
The library's initial development was funded by [Ethereum Foundation](https://ethereum.org/).
|
||||
|
||||
### This library belongs to _noble_ crypto
|
||||
|
||||
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
|
||||
|
||||
- No dependencies, protection against supply chain attacks
|
||||
- Auditable TypeScript / JS code
|
||||
- Supported in all major browsers and stable node.js versions
|
||||
- All releases are signed with PGP keys
|
||||
- Check out [homepage](https://paulmillr.com/noble/) & all libraries:
|
||||
[curves](https://github.com/paulmillr/noble-curves)
|
||||
(4kb versions [secp256k1](https://github.com/paulmillr/noble-secp256k1),
|
||||
[ed25519](https://github.com/paulmillr/noble-ed25519)),
|
||||
[hashes](https://github.com/paulmillr/noble-hashes)
|
||||
|
||||
## Usage
|
||||
|
||||
> npm install @noble/hashes
|
||||
|
||||
We support all major platforms and runtimes.
|
||||
For [Deno](https://deno.land), ensure to use [npm specifier](https://deno.land/manual@v1.28.0/node/npm_specifiers).
|
||||
For React Native, you may need a [polyfill for getRandomValues](https://github.com/LinusU/react-native-get-random-values).
|
||||
If you don't like NPM, a standalone [noble-hashes.js](https://github.com/paulmillr/noble-hashes/releases) is also available.
|
||||
|
||||
The library is tree-shaking-friendly and does not expose root entry point as
|
||||
`@noble/hashes`. Instead, you need to import specific primitives.
|
||||
This is done to ensure small size of your apps.
|
||||
|
||||
```js
|
||||
import { sha256 } from '@noble/hashes/sha256'; // ECMAScript modules (ESM) and Common.js
|
||||
// import { sha256 } from 'npm:@noble/hashes@1.3.0/sha256'; // Deno
|
||||
console.log(sha256(new Uint8Array([1, 2, 3]))); // Uint8Array(32) [3, 144, 88, 198, 242...]
|
||||
// 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
|
||||
import { sha512, sha512_256, sha384 } from '@noble/hashes/sha512';
|
||||
// prettier-ignore
|
||||
import {
|
||||
sha3_224, sha3_256, sha3_384, sha3_512,
|
||||
keccak_224, keccak_256, keccak_384, keccak_512,
|
||||
shake128, shake256
|
||||
} from '@noble/hashes/sha3';
|
||||
// prettier-ignore
|
||||
import {
|
||||
cshake128, cshake256, kmac128, kmac256,
|
||||
k12, m14,
|
||||
tuplehash256, parallelhash256, keccakprg
|
||||
} from '@noble/hashes/sha3-addons';
|
||||
import { ripemd160 } from '@noble/hashes/ripemd160';
|
||||
import { blake3 } from '@noble/hashes/blake3';
|
||||
import { blake2b } from '@noble/hashes/blake2b';
|
||||
import { blake2s } from '@noble/hashes/blake2s';
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { hkdf } from '@noble/hashes/hkdf';
|
||||
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
|
||||
import { scrypt, scryptAsync } from '@noble/hashes/scrypt';
|
||||
|
||||
import { sha1 } from '@noble/hashes/sha1'; // legacy
|
||||
|
||||
// small utility method that converts bytes to hex
|
||||
import { bytesToHex as toHex } from '@noble/hashes/utils';
|
||||
console.log(toHex(sha256('abc'))); // ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
All hash functions:
|
||||
|
||||
- can be called directly, with `Uint8Array`.
|
||||
- return `Uint8Array`
|
||||
- can receive `string`, which is automatically converted to `Uint8Array`
|
||||
via utf8 encoding **(not hex)**
|
||||
- support hashing 4GB of data per update on 64-bit systems (unlimited with streaming)
|
||||
|
||||
```ts
|
||||
function hash(message: Uint8Array | string): Uint8Array;
|
||||
hash(new Uint8Array([1, 3]));
|
||||
hash('string') == hash(new TextEncoder().encode('string'));
|
||||
```
|
||||
|
||||
All hash functions can be constructed via `hash.create()` method:
|
||||
|
||||
- the result is `Hash` subclass instance, which has `update()` and `digest()` methods
|
||||
- `digest()` finalizes the hash and makes it no longer usable
|
||||
|
||||
```ts
|
||||
hash
|
||||
.create()
|
||||
.update(new Uint8Array([1, 3]))
|
||||
.digest();
|
||||
```
|
||||
|
||||
_Some_ hash functions can also receive `options` object, which can be either passed as a:
|
||||
|
||||
- second argument to hash function: `blake3('abc', { key: 'd', dkLen: 32 })`
|
||||
- first argument to class initializer: `blake3.create({ context: 'e', dkLen: 32 })`
|
||||
|
||||
## Modules
|
||||
|
||||
- [SHA2 (sha256, sha384, sha512, sha512_256)](#sha2-sha256-sha384-sha512-sha512_256)
|
||||
- [SHA3 (FIPS, SHAKE, Keccak)](#sha3-fips-shake-keccak)
|
||||
- [SHA3 Addons (cSHAKE, KMAC, KangarooTwelve, MarsupilamiFourteen)](#sha3-addons-cshake-kmac-tuplehash-parallelhash-kangarootwelve-marsupilamifourteen)
|
||||
- [RIPEMD-160](#ripemd-160)
|
||||
- [BLAKE2b, BLAKE2s](#blake2b-blake2s)
|
||||
- [BLAKE3](#blake3)
|
||||
- [SHA1 (legacy)](#sha1-legacy)
|
||||
- [HMAC](#hmac)
|
||||
- [HKDF](#hkdf)
|
||||
- [PBKDF2](#pbkdf2)
|
||||
- [Scrypt](#scrypt)
|
||||
- [ESKDF](#eskdf)
|
||||
- [utils](#utils)
|
||||
|
||||
##### SHA2 (sha256, sha384, sha512, sha512_256)
|
||||
|
||||
```typescript
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
const h1a = sha256('abc');
|
||||
const h1b = sha256
|
||||
.create()
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
const h2a = sha512('abc');
|
||||
const h2b = sha512
|
||||
.create()
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
|
||||
// SHA512/256 variant
|
||||
import { sha512_256 } from '@noble/hashes/sha512';
|
||||
const h3a = sha512_256('abc');
|
||||
const h3b = sha512_256
|
||||
.create()
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
|
||||
// SHA384
|
||||
import { sha384 } from '@noble/hashes/sha512';
|
||||
const h4a = sha384('abc');
|
||||
const h4b = sha384
|
||||
.create()
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
```
|
||||
|
||||
See [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) and
|
||||
[the paper on SHA512/256](https://eprint.iacr.org/2010/548.pdf).
|
||||
|
||||
##### SHA3 (FIPS, SHAKE, Keccak)
|
||||
|
||||
```typescript
|
||||
import {
|
||||
sha3_224,
|
||||
sha3_256,
|
||||
sha3_384,
|
||||
sha3_512,
|
||||
keccak_224,
|
||||
keccak_256,
|
||||
keccak_384,
|
||||
keccak_512,
|
||||
shake128,
|
||||
shake256,
|
||||
} from '@noble/hashes/sha3';
|
||||
const h5a = sha3_256('abc');
|
||||
const h5b = sha3_256
|
||||
.create()
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
const h6a = keccak_256('abc');
|
||||
const h7a = shake128('abc', { dkLen: 512 });
|
||||
const h7b = shake256('abc', { dkLen: 512 });
|
||||
```
|
||||
|
||||
See [FIPS PUB 202](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf),
|
||||
[Website](https://keccak.team/keccak.html).
|
||||
|
||||
Check out [the differences between SHA-3 and Keccak](https://crypto.stackexchange.com/questions/15727/what-are-the-key-differences-between-the-draft-sha-3-standard-and-the-keccak-sub)
|
||||
|
||||
##### SHA3 Addons (cSHAKE, KMAC, TupleHash, ParallelHash, KangarooTwelve, MarsupilamiFourteen)
|
||||
|
||||
```typescript
|
||||
import {
|
||||
cshake128,
|
||||
cshake256,
|
||||
kmac128,
|
||||
kmac256,
|
||||
k12,
|
||||
m14,
|
||||
tuplehash128,
|
||||
tuplehash256,
|
||||
parallelhash128,
|
||||
parallelhash256,
|
||||
keccakprg,
|
||||
} from '@noble/hashes/sha3-addons';
|
||||
const h7c = cshake128('abc', { personalization: 'def' });
|
||||
const h7d = cshake256('abc', { personalization: 'def' });
|
||||
const h7e = kmac128('key', 'message');
|
||||
const h7f = kmac256('key', 'message');
|
||||
const h7h = k12('abc');
|
||||
const h7g = m14('abc');
|
||||
const h7i = tuplehash128(['ab', 'c']); // tuplehash(['ab', 'c']) !== tuplehash(['a', 'bc']) !== tuplehash(['abc'])
|
||||
// Same as k12/blake3, but without reduced number of rounds. Doesn't speedup anything due lack of SIMD and threading,
|
||||
// added for compatibility.
|
||||
const h7j = parallelhash128('abc', { blockLen: 8 });
|
||||
// pseudo-random generator, first argument is capacity. XKCP recommends 254 bits capacity for 128-bit security strength.
|
||||
// * with a capacity of 254 bits.
|
||||
const p = keccakprg(254);
|
||||
p.feed('test');
|
||||
const rand1b = p.fetch(1);
|
||||
```
|
||||
|
||||
- Full [NIST SP 800-185](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf):
|
||||
cSHAKE, KMAC, TupleHash, ParallelHash + XOF variants
|
||||
- 🦘 K12 ([KangarooTwelve Paper](https://keccak.team/files/KangarooTwelve.pdf),
|
||||
[RFC Draft](https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-06.txt))
|
||||
and M14 aka MarsupilamiFourteen are basically parallel versions of Keccak with
|
||||
reduced number of rounds (same as Blake3 and ParallelHash).
|
||||
- [KeccakPRG](https://keccak.team/files/CSF-0.1.pdf): Pseudo-random generator based on Keccak
|
||||
|
||||
##### RIPEMD-160
|
||||
|
||||
```typescript
|
||||
import { ripemd160 } from '@noble/hashes/ripemd160';
|
||||
// function ripemd160(data: Uint8Array): Uint8Array;
|
||||
const hash8 = ripemd160('abc');
|
||||
const hash9 = ripemd160()
|
||||
.create()
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
```
|
||||
|
||||
See [RFC 2286](https://datatracker.ietf.org/doc/html/rfc2286),
|
||||
[Website](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html)
|
||||
|
||||
##### BLAKE2b, BLAKE2s
|
||||
|
||||
```typescript
|
||||
import { blake2b } from '@noble/hashes/blake2b';
|
||||
import { blake2s } from '@noble/hashes/blake2s';
|
||||
const h10a = blake2s('abc');
|
||||
const b2params = { key: new Uint8Array([1]), personalization: t, salt: t, dkLen: 32 };
|
||||
const h10b = blake2s('abc', b2params);
|
||||
const h10c = blake2s
|
||||
.create(b2params)
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
```
|
||||
|
||||
See [RFC 7693](https://datatracker.ietf.org/doc/html/rfc7693), [Website](https://www.blake2.net).
|
||||
|
||||
##### BLAKE3
|
||||
|
||||
```typescript
|
||||
import { blake3 } from '@noble/hashes/blake3';
|
||||
// All params are optional
|
||||
const h11 = blake3('abc', { dkLen: 256, key: 'def', context: 'fji' });
|
||||
```
|
||||
|
||||
##### SHA1 (legacy)
|
||||
|
||||
SHA1 was cryptographically broken, however, it was not broken for cases like HMAC.
|
||||
|
||||
See [RFC4226 B.2](https://datatracker.ietf.org/doc/html/rfc4226#appendix-B.2).
|
||||
|
||||
Don't use it for a new protocol.
|
||||
|
||||
```typescript
|
||||
import { sha1 } from '@noble/hashes/sha1';
|
||||
const h12 = sha1('def');
|
||||
```
|
||||
|
||||
##### HMAC
|
||||
|
||||
```typescript
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
const mac1 = hmac(sha256, 'key', 'message');
|
||||
const mac2 = hmac.create(sha256, Uint8Array.from([1, 2, 3])).update(Uint8Array.from([4, 5, 6])).digest();
|
||||
```
|
||||
|
||||
Matches [RFC 2104](https://datatracker.ietf.org/doc/html/rfc2104).
|
||||
|
||||
##### HKDF
|
||||
|
||||
```typescript
|
||||
import { hkdf } from '@noble/hashes/hkdf';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
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 * as hkdf from '@noble/hashes/hkdf';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
const prk = hkdf.extract(sha256, inputKey, salt);
|
||||
const hk2 = hkdf.expand(sha256, prk, info, dkLen);
|
||||
```
|
||||
|
||||
Matches [RFC 5869](https://datatracker.ietf.org/doc/html/rfc5869).
|
||||
|
||||
##### PBKDF2
|
||||
|
||||
```typescript
|
||||
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
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,
|
||||
});
|
||||
```
|
||||
|
||||
Matches [RFC 2898](https://datatracker.ietf.org/doc/html/rfc2898).
|
||||
|
||||
##### Scrypt
|
||||
|
||||
```typescript
|
||||
import { scrypt, scryptAsync } from '@noble/hashes/scrypt';
|
||||
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)
|
||||
});
|
||||
```
|
||||
|
||||
Conforms to [RFC 7914](https://datatracker.ietf.org/doc/html/rfc7914),
|
||||
[Website](https://www.tarsnap.com/scrypt.html)
|
||||
|
||||
- `N, r, p` are work factors. To understand them, see [the blog post](https://blog.filippo.io/the-scrypt-parameters/).
|
||||
- `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.
|
||||
|
||||
##### Argon2
|
||||
|
||||
Experimental Argon2 RFC 9106 implementation. It may be removed at any time.
|
||||
|
||||
```ts
|
||||
import { argon2d, argon2i, argon2id } from '@noble/hashes/argon2';
|
||||
const result = argon2id('password', 'salt', { t: 2, m: 65536, p: 1 });
|
||||
```
|
||||
|
||||
##### ESKDF
|
||||
|
||||
A tiny stretched KDF for various applications like AES key-gen. Takes >= 2 seconds to execute.
|
||||
|
||||
Takes following params:
|
||||
|
||||
- `username` - username, email, or identifier, min: 8 characters, should have enough entropy
|
||||
- `password` - min: 8 characters, should have enough entropy
|
||||
|
||||
Produces ESKDF instance that has `deriveChildKey(protocol, accountId[, options])` function.
|
||||
|
||||
- `protocol` - 3-15 character protocol name
|
||||
- `accountId` - numeric identifier of account
|
||||
- `options` - `keyLength: 32` with specified key length (default is 32),
|
||||
or `modulus: 2n ** 221n - 17n` with specified modulus. It will fetch modulus + 64 bits of
|
||||
data, execute modular division. The result will have negligible bias as per FIPS 186 B.4.1.
|
||||
Can be used to generate, for example, elliptic curve keys.
|
||||
|
||||
Takes username and password, then takes protocol name and account id.
|
||||
|
||||
```typescript
|
||||
import { eskdf } from '@noble/hashes/eskdf';
|
||||
const kdf = await eskdf('example@university', 'beginning-new-example');
|
||||
console.log(kdf.fingerprint);
|
||||
const key1 = kdf.deriveChildKey('aes', 0);
|
||||
const key2 = kdf.deriveChildKey('aes', 0, { keyLength: 16 });
|
||||
const ecc1 = kdf.deriveChildKey('ecc', 0, { modulus: 2n ** 252n - 27742317777372353535851937790883648493n })
|
||||
kdf.expire();
|
||||
```
|
||||
|
||||
##### utils
|
||||
|
||||
```typescript
|
||||
import { bytesToHex as toHex, randomBytes } from '@noble/hashes/utils';
|
||||
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.
|
||||
|
||||
1. The library has been audited in Jan 2022 by an independent security firm
|
||||
cure53: [PDF](https://cure53.de/pentest-report_hashing-libs.pdf).
|
||||
No vulnerabilities have been found. The audit has been funded by
|
||||
[Ethereum Foundation](https://ethereum.org/en/) with help of [Nomic Labs](https://nomiclabs.io).
|
||||
Modules `blake3`, `sha3-addons`, `sha1` and `argon2` have not been audited.
|
||||
See [changes since audit](https://github.com/paulmillr/noble-hashes/compare/1.0.0..main).
|
||||
2. The library has been fuzzed by [Guido Vranken's cryptofuzz](https://github.com/guidovranken/cryptofuzz).
|
||||
You can run the fuzzer by yourself to check it.
|
||||
3. [Timing attack](https://en.wikipedia.org/wiki/Timing_attack) considerations:
|
||||
_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](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security)
|
||||
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.
|
||||
4. Memory dump considerations: 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
|
||||
|
||||
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
|
||||
malware with every `npm install`. Our goal is to minimize this attack vector.
|
||||
|
||||
## Speed
|
||||
|
||||
Benchmarks measured on Apple M1 with macOS 12.
|
||||
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 1,219,512 ops/sec @ 820ns/op ± 2.58% (min: 625ns, max: 4ms)
|
||||
SHA384 32B x 512,032 ops/sec @ 1μs/op
|
||||
SHA512 32B x 509,943 ops/sec @ 1μs/op
|
||||
SHA3-256, keccak256, shake256 32B x 199,600 ops/sec @ 5μs/op
|
||||
Kangaroo12 32B x 336,360 ops/sec @ 2μs/op
|
||||
Marsupilami14 32B x 298,418 ops/sec @ 3μs/op
|
||||
BLAKE2b 32B x 379,794 ops/sec @ 2μs/op
|
||||
BLAKE2s 32B x 515,995 ops/sec @ 1μs/op ± 1.07% (min: 1μs, max: 4ms)
|
||||
BLAKE3 32B x 588,235 ops/sec @ 1μs/op ± 1.36% (min: 1μs, max: 5ms)
|
||||
RIPEMD160 32B x 1,140,250 ops/sec @ 877ns/op ± 3.12% (min: 708ns, max: 6ms)
|
||||
HMAC-SHA256 32B x 377,358 ops/sec @ 2μs/op
|
||||
|
||||
HKDF-SHA256 32B x 108,377 ops/sec @ 9μs/op
|
||||
PBKDF2-HMAC-SHA256 262144 x 3 ops/sec @ 326ms/op
|
||||
PBKDF2-HMAC-SHA512 262144 x 1 ops/sec @ 970ms/op
|
||||
Scrypt r: 8, p: 1, n: 262144 x 1 ops/sec @ 616ms/op
|
||||
```
|
||||
|
||||
Compare to native node.js implementation that uses C bindings instead of pure-js code:
|
||||
|
||||
```
|
||||
SHA256 32B node x 1,302,083 ops/sec @ 768ns/op ± 10.54% (min: 416ns, max: 7ms)
|
||||
SHA384 32B node x 975,609 ops/sec @ 1μs/op ± 11.32% (min: 625ns, max: 8ms)
|
||||
SHA512 32B node x 983,284 ops/sec @ 1μs/op ± 11.24% (min: 625ns, max: 8ms)
|
||||
SHA3-256 32B node x 910,746 ops/sec @ 1μs/op ± 12.19% (min: 666ns, max: 10ms)
|
||||
keccak, k12, m14 are not implemented
|
||||
BLAKE2b 32B node x 967,117 ops/sec @ 1μs/op ± 11.26% (min: 625ns, max: 9ms)
|
||||
BLAKE2s 32B node x 1,055,966 ops/sec @ 947ns/op ± 11.07% (min: 583ns, max: 7ms)
|
||||
BLAKE3 is not implemented
|
||||
RIPEMD160 32B node x 1,002,004 ops/sec @ 998ns/op ± 10.66% (min: 625ns, max: 7ms)
|
||||
HMAC-SHA256 32B node x 919,963 ops/sec @ 1μs/op ± 6.13% (min: 833ns, max: 5ms)
|
||||
HKDF-SHA256 32 node x 369,276 ops/sec @ 2μs/op ± 13.59% (min: 1μs, max: 9ms)
|
||||
PBKDF2-HMAC-SHA256 262144 node x 25 ops/sec @ 39ms/op
|
||||
PBKDF2-HMAC-SHA512 262144 node x 7 ops/sec @ 132ms/op
|
||||
Scrypt r: 8, p: 1, n: 262144 node x 1 ops/sec @ 523ms/op
|
||||
```
|
||||
|
||||
It is possible to [make this library 4x+ faster](./benchmark/README.md) 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
|
||||
|
||||
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](./test/README.md)
|
||||
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) 2022 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)
|
||||
|
||||
See LICENSE file.
|
||||
Reference in New Issue
Block a user