Remove x-noble-* packages (all upstream) (#1323)
This commit is contained in:
@@ -14,7 +14,6 @@ module.exports = Object.assign({}, config, {
|
||||
// eslint-disable-next-line sort-keys
|
||||
'@polkadot/util(.*)$': '<rootDir>/packages/util/src/$1',
|
||||
'@polkadot/x-(bigint|global)(.*)$': '<rootDir>/packages/x-$1/src/$2',
|
||||
'@polkadot/x-(fetch|randomvalues|textdecoder|textencoder|ws)(.*)$': '<rootDir>/packages/x-$1/src/node',
|
||||
'@polkadot/x-noble-(hashes|secp256k1)(.*)$': '<rootDir>/packages/x-noble-$1/src/$2'
|
||||
'@polkadot/x-(fetch|randomvalues|textdecoder|textencoder|ws)(.*)$': '<rootDir>/packages/x-$1/src/node'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021 Paul Miller (https://paulmillr.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the “Software”), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,438 +0,0 @@
|
||||
# noble-hashes  [](https://github.com/prettier/prettier)
|
||||
|
||||
Fast, secure & minimal JS implementation of SHA2, SHA3, RIPEMD, BLAKE2/3, HMAC, HKDF, PBKDF2 & Scrypt.
|
||||
|
||||
- **noble** family, 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
|
||||
- 🏎 Ultra-fast, hand-optimized for caveats of JS engines
|
||||
- 🔍 Unique tests ensure correctness: chained tests, sliding window tests, DoS tests
|
||||
- 🧪 Differential fuzzing ensures even more correctness with [cryptofuzz](https://github.com/guidovranken/cryptofuzz)
|
||||
- 🔑 Scrypt supports `n: 2**22` with 4GB arrays while other implementations crash on `2**21` or even `2**20`, `maxmem` security param, `onProgress` callback
|
||||
- 🦘 SHA3 supports Keccak, TupleHash, KangarooTwelve and MarsupilamiFourteen
|
||||
- All primitives are just ~2KLOC / 41KB minified / 14KB gzipped. SHA256-only is 240LOC / 7KB minified / 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, 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](https://github.com/paulmillr/noble-secp256k1),
|
||||
[ed25519](https://github.com/paulmillr/noble-ed25519),
|
||||
[bls12-381](https://github.com/paulmillr/noble-bls12-381),
|
||||
[hashes](https://github.com/paulmillr/noble-hashes)
|
||||
|
||||
## Usage
|
||||
|
||||
Use NPM in node.js / browser, or include single file from
|
||||
[GitHub's releases page](https://github.com/paulmillr/noble-hashes/releases):
|
||||
|
||||
> 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.
|
||||
|
||||
```js
|
||||
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,
|
||||
shake128, shake256
|
||||
} = require('@noble/hashes/lib/sha3');
|
||||
// prettier-ignore
|
||||
const {
|
||||
cshake128, cshake256, kmac128, kmac256,
|
||||
k12, m14,
|
||||
tuplehash256, parallelhash256, keccakprg
|
||||
} = require('@noble/hashes/lib/sha3-addons');
|
||||
const { ripemd160 } = require('@noble/hashes/lib/ripemd160');
|
||||
const { blake3 } = require('@noble/hashes/lib/blake3');
|
||||
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
|
||||
|
||||
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)
|
||||
- [HMAC](#hmac)
|
||||
- [HKDF](#hkdf)
|
||||
- [PBKDF2](#pbkdf2)
|
||||
- [Scrypt](#scrypt)
|
||||
- [utils](#utils)
|
||||
|
||||
##### SHA2 (sha256, sha384, sha512, sha512_256)
|
||||
|
||||
```typescript
|
||||
import { sha256 } from '@noble/hashes/lib/sha256.js';
|
||||
const h1a = sha256('abc');
|
||||
const h1b = sha256
|
||||
.create()
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { sha512 } from '@noble/hashes/lib/sha512.js';
|
||||
const h2a = sha512('abc');
|
||||
const h2b = sha512
|
||||
.create()
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
|
||||
// SHA512/256 variant
|
||||
import { sha512_256 } from '@noble/hashes/lib/sha512.js';
|
||||
const h3a = sha512_256('abc');
|
||||
const h3b = sha512_256
|
||||
.create()
|
||||
.update(Uint8Array.from([1, 2, 3]))
|
||||
.digest();
|
||||
|
||||
// SHA384
|
||||
import { sha384 } from '@noble/hashes/lib/sha512.js';
|
||||
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/lib/sha3.js';
|
||||
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/lib/sha3-addons.js';
|
||||
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/lib/ripemd160.js';
|
||||
// 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/lib/blake2b.js';
|
||||
import { blake2s } from '@noble/hashes/lib/blake2s.js';
|
||||
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/lib/blake3.js';
|
||||
// All params are optional
|
||||
const h11 = blake3('abc', { dkLen: 256, key: 'def', context: 'fji' });
|
||||
```
|
||||
|
||||
See [Website](https://blake3.io).
|
||||
|
||||
##### HMAC
|
||||
|
||||
```typescript
|
||||
import { hmac } from '@noble/hashes/lib/hmac.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();
|
||||
```
|
||||
|
||||
Matches [RFC 2104](https://datatracker.ietf.org/doc/html/rfc2104).
|
||||
|
||||
##### HKDF
|
||||
|
||||
```typescript
|
||||
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);
|
||||
```
|
||||
|
||||
Matches [RFC 5869](https://datatracker.ietf.org/doc/html/rfc5869).
|
||||
|
||||
##### PBKDF2
|
||||
|
||||
```typescript
|
||||
import { pbkdf2, pbkdf2Async } from '@noble/hashes/lib/pbkdf2.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,
|
||||
});
|
||||
```
|
||||
|
||||
Matches [RFC 2898](https://datatracker.ietf.org/doc/html/rfc2898).
|
||||
|
||||
##### Scrypt
|
||||
|
||||
```typescript
|
||||
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)
|
||||
});
|
||||
```
|
||||
|
||||
Matches [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.
|
||||
|
||||
##### utils
|
||||
|
||||
```typescript
|
||||
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](https://github.com/guidovranken/cryptofuzz). You can run the fuzzer by yourself to check it.
|
||||
|
||||
A note on [timing attacks](https://en.wikipedia.org/wiki/Timing_attack): _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.
|
||||
|
||||
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 on Apple M1 with macOS 12 using 32-byte inputs.
|
||||
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 x 1,131,221 ops/sec @ 884ns/op
|
||||
SHA384 x 452,284 ops/sec @ 2μs/op
|
||||
SHA512 x 451,059 ops/sec @ 2μs/op
|
||||
SHA3-256, keccak256, shake256 x 185,494 ops/sec @ 5μs/op
|
||||
Kangaroo12 x 300,480 ops/sec @ 3μs/op
|
||||
Marsupilami14 x 269,614 ops/sec @ 3μs/op
|
||||
BLAKE2b x 291,375 ops/sec @ 3μs/op
|
||||
BLAKE2s x 505,561 ops/sec @ 1μs/op
|
||||
BLAKE3 x 576,036 ops/sec @ 1μs/op
|
||||
HMAC-SHA256 x 342,583 ops/sec @ 2μs/op
|
||||
RIPEMD160 x 1,191,895 ops/sec @ 839ns/op
|
||||
HKDF-SHA256 x 115,500 ops/sec @ 8μs/op
|
||||
PBKDF2-HMAC-SHA256 262144 x 2 ops/sec @ 338ms/op
|
||||
PBKDF2-HMAC-SHA512 262144 x 0 ops/sec @ 1024ms/op
|
||||
Scrypt r: 8, p: 1, n: 262144 x 1 ops/sec @ 637ms/op
|
||||
```
|
||||
|
||||
Compare to native node.js implementation that uses C bindings instead of pure-js code:
|
||||
|
||||
```
|
||||
SHA256 32B native x 1,164,144 ops/sec @ 859ns/op
|
||||
SHA384 32B native x 938,086 ops/sec @ 1μs/op
|
||||
SHA512 32B native x 946,969 ops/sec @ 1μs/op
|
||||
SHA3 32B native x 879,507 ops/sec @ 1μs/op
|
||||
keccak, k12, m14 are not implemented
|
||||
BLAKE2b 32B native x 879,507 ops/sec @ 1μs/op
|
||||
BLAKE2s 32B native x 977,517 ops/sec @ 1μs/op
|
||||
BLAKE3 is not implemented
|
||||
RIPEMD160 32B native x 913,242 ops/sec @ 1μs/op
|
||||
HMAC-SHA256 32B native x 755,287 ops/sec @ 1μs/op
|
||||
HKDF-SHA256 32B native x 207,856 ops/sec @ 4μs/op
|
||||
PBKDF2-HMAC-SHA256 262144 native x 23 ops/sec @ 42ms/op
|
||||
Scrypt 262144 native x 1 ops/sec @ 564ms/op
|
||||
Scrypt 262144 scrypt.js x 0 ops/sec @ 1678ms/op
|
||||
```
|
||||
|
||||
It is possible to [make this library 4x+ faster](./test/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) 2021 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)
|
||||
|
||||
See LICENSE file.
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
"bugs": "https://github.com/polkadot-js/common/issues",
|
||||
"contributors": [],
|
||||
"description": "An fork of @noble/hashes with extra protection on BigInt usage",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/common/tree/master/packages/x-noble-hashes#readme",
|
||||
"license": "MIT",
|
||||
"maintainers": [],
|
||||
"name": "@polkadot/x-noble-hashes",
|
||||
"repository": {
|
||||
"directory": "packages/x-noble-hashes",
|
||||
"type": "git",
|
||||
"url": "https://github.com/polkadot-js/common.git"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"version": "8.1.3-28",
|
||||
"browser": {
|
||||
"crypto": false
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.16.5"
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
import { assertNumber, Hash, Input, toBytes, u32 } from './utils';
|
||||
// prettier-ignore
|
||||
export const SIGMA = new Uint8Array([
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
|
||||
11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
|
||||
7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
|
||||
9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
|
||||
2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
|
||||
12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
|
||||
13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
|
||||
6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
|
||||
10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
|
||||
// For BLAKE2b, the two extra permutations for rounds 10 and 11 are SIGMA[10..11] = SIGMA[0..1].
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
|
||||
]);
|
||||
|
||||
export type BlakeOpts = {
|
||||
dkLen?: number;
|
||||
key?: Input;
|
||||
salt?: Input;
|
||||
personalization?: Input;
|
||||
};
|
||||
|
||||
export abstract class BLAKE2<T extends BLAKE2<T>> extends Hash<T> {
|
||||
protected abstract compress(msg: Uint32Array, offset: number, isLast: boolean): void;
|
||||
protected abstract get(): number[];
|
||||
protected abstract set(...args: number[]): void;
|
||||
abstract override destroy(): void;
|
||||
protected buffer: Uint8Array;
|
||||
protected buffer32: Uint32Array;
|
||||
protected length: number = 0;
|
||||
protected pos: number = 0;
|
||||
protected finished = false;
|
||||
protected destroyed = false;
|
||||
|
||||
constructor(
|
||||
readonly blockLen: number,
|
||||
public outputLen: number,
|
||||
opts: BlakeOpts = {},
|
||||
keyLen: number,
|
||||
saltLen: number,
|
||||
persLen: number
|
||||
) {
|
||||
super();
|
||||
assertNumber(blockLen);
|
||||
assertNumber(outputLen);
|
||||
assertNumber(keyLen);
|
||||
if (outputLen < 0 || outputLen > keyLen)
|
||||
throw new Error('Blake2: outputLen bigger than keyLen');
|
||||
if (opts.key !== undefined && (opts.key.length < 1 || opts.key.length > keyLen))
|
||||
throw new Error(`Key should be up 1..${keyLen} byte long or undefined`);
|
||||
if (opts.salt !== undefined && opts.salt.length !== saltLen)
|
||||
throw new Error(`Salt should be ${saltLen} byte long or undefined`);
|
||||
if (opts.personalization !== undefined && opts.personalization.length !== persLen)
|
||||
throw new Error(`Personalization should be ${persLen} byte long or undefined`);
|
||||
this.buffer32 = u32((this.buffer = new Uint8Array(blockLen)));
|
||||
}
|
||||
update(data: Input) {
|
||||
if (this.destroyed) throw new Error('instance is destroyed');
|
||||
// Main difference with other hashes: there is flag for last block,
|
||||
// so we cannot process current block before we know that there
|
||||
// is the next one. This significantly complicates logic and reduces ability
|
||||
// to do zero-copy processing
|
||||
const { finished, blockLen, buffer, buffer32 } = this;
|
||||
if (finished) throw new Error('digest() was already called');
|
||||
data = toBytes(data);
|
||||
const len = data.length;
|
||||
for (let pos = 0; pos < len; ) {
|
||||
// If buffer is full and we still have input (don't process last block, same as blake2s)
|
||||
if (this.pos === blockLen) {
|
||||
this.compress(buffer32, 0, false);
|
||||
this.pos = 0;
|
||||
}
|
||||
const take = Math.min(blockLen - this.pos, len - pos);
|
||||
const dataOffset = data.byteOffset + pos;
|
||||
// full block && aligned to 4 bytes && not last in input
|
||||
if (take === blockLen && !(dataOffset % 4) && pos + take < len) {
|
||||
const data32 = new Uint32Array(data.buffer, dataOffset, Math.floor((len - pos) / 4));
|
||||
for (let pos32 = 0; pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) {
|
||||
this.length += blockLen;
|
||||
this.compress(data32, pos32, false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buffer.set(data.subarray(pos, pos + take), this.pos);
|
||||
this.pos += take;
|
||||
this.length += take;
|
||||
pos += take;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
digestInto(out: Uint8Array) {
|
||||
if (this.destroyed) throw new Error('instance is destroyed');
|
||||
if (!(out instanceof Uint8Array) || out.length < this.outputLen)
|
||||
throw new Error('_Blake2: Invalid output buffer');
|
||||
const { finished, pos, buffer32 } = this;
|
||||
if (finished) throw new Error('digest() was already called');
|
||||
this.finished = true;
|
||||
// Padding
|
||||
this.buffer.subarray(pos).fill(0);
|
||||
this.compress(buffer32, 0, true);
|
||||
const out32 = u32(out);
|
||||
this.get().forEach((v, i) => (out32[i] = v));
|
||||
}
|
||||
digest() {
|
||||
const { buffer, outputLen } = this;
|
||||
this.digestInto(buffer);
|
||||
const res = buffer.slice(0, outputLen);
|
||||
this.destroy();
|
||||
return res;
|
||||
}
|
||||
_cloneInto(to?: T): T {
|
||||
const { buffer, length, finished, destroyed, outputLen, pos } = this;
|
||||
to ||= new (this.constructor as any)({ dkLen: outputLen }) as T;
|
||||
to.set(...this.get());
|
||||
to.length = length;
|
||||
to.finished = finished;
|
||||
to.destroyed = destroyed;
|
||||
to.outputLen = outputLen;
|
||||
to.buffer.set(buffer);
|
||||
to.pos = pos;
|
||||
return to;
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
import { Hash, createView, Input, toBytes } from './utils';
|
||||
|
||||
// Polyfill for Safari 14
|
||||
function setBigUint64(view: DataView, byteOffset: number, value: bigint, isLE: boolean): void {
|
||||
if (typeof view.setBigUint64 === 'function') return view.setBigUint64(byteOffset, value, isLE);
|
||||
const _32n = BigInt(32);
|
||||
const _u32_max = BigInt(0xffffffff);
|
||||
const wh = Number((value >> _32n) & _u32_max);
|
||||
const wl = Number(value & _u32_max);
|
||||
const h = isLE ? 4 : 0;
|
||||
const l = isLE ? 0 : 4;
|
||||
view.setUint32(byteOffset + h, wh, isLE);
|
||||
view.setUint32(byteOffset + l, wl, isLE);
|
||||
}
|
||||
|
||||
// Base SHA2 class (RFC 6234)
|
||||
export abstract class SHA2<T extends SHA2<T>> extends Hash<T> {
|
||||
protected abstract process(buf: DataView, offset: number): void;
|
||||
protected abstract get(): number[];
|
||||
protected abstract set(...args: number[]): void;
|
||||
abstract override destroy(): void;
|
||||
protected abstract roundClean(): void;
|
||||
// For partial updates less than block size
|
||||
protected buffer: Uint8Array;
|
||||
protected view: DataView;
|
||||
protected finished = false;
|
||||
protected length = 0;
|
||||
protected pos = 0;
|
||||
protected destroyed = false;
|
||||
|
||||
constructor(
|
||||
readonly blockLen: number,
|
||||
public outputLen: number,
|
||||
readonly padOffset: number,
|
||||
readonly isLE: boolean
|
||||
) {
|
||||
super();
|
||||
this.buffer = new Uint8Array(blockLen);
|
||||
this.view = createView(this.buffer);
|
||||
}
|
||||
update(data: Input): this {
|
||||
if (this.destroyed) throw new Error('instance is destroyed');
|
||||
const { view, buffer, blockLen, finished } = this;
|
||||
if (finished) throw new Error('digest() was already called');
|
||||
data = toBytes(data);
|
||||
const len = data.length;
|
||||
for (let pos = 0; pos < len; ) {
|
||||
const take = Math.min(blockLen - this.pos, len - pos);
|
||||
// Fast path: we have at least one block in input, cast it to view and process
|
||||
if (take === blockLen) {
|
||||
const dataView = createView(data);
|
||||
for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);
|
||||
continue;
|
||||
}
|
||||
buffer.set(data.subarray(pos, pos + take), this.pos);
|
||||
this.pos += take;
|
||||
pos += take;
|
||||
if (this.pos === blockLen) {
|
||||
this.process(view, 0);
|
||||
this.pos = 0;
|
||||
}
|
||||
}
|
||||
this.length += data.length;
|
||||
this.roundClean();
|
||||
return this;
|
||||
}
|
||||
digestInto(out: Uint8Array) {
|
||||
if (this.destroyed) throw new Error('instance is destroyed');
|
||||
if (!(out instanceof Uint8Array) || out.length < this.outputLen)
|
||||
throw new Error('_Sha2: Invalid output buffer');
|
||||
if (this.finished) throw new Error('digest() was already called');
|
||||
this.finished = true;
|
||||
// Padding
|
||||
// We can avoid allocation of buffer for padding completely if it
|
||||
// was previously not allocated here. But it won't change performance.
|
||||
const { buffer, view, blockLen, isLE } = this;
|
||||
let { pos } = this;
|
||||
// append the bit '1' to the message
|
||||
buffer[pos++] = 0b10000000;
|
||||
this.buffer.subarray(pos).fill(0);
|
||||
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
|
||||
if (this.padOffset > blockLen - pos) {
|
||||
this.process(view, 0);
|
||||
pos = 0;
|
||||
}
|
||||
// Pad until full block byte with zeros
|
||||
for (let i = pos; i < blockLen; i++) buffer[i] = 0;
|
||||
// NOTE: sha512 requires length to be 128bit integer, but length in JS will overflow before that
|
||||
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
|
||||
// So we just write lowest 64bit of that value.
|
||||
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
|
||||
this.process(view, 0);
|
||||
const oview = createView(out);
|
||||
this.get().forEach((v, i) => oview.setUint32(4 * i, v, isLE));
|
||||
}
|
||||
digest() {
|
||||
const { buffer, outputLen } = this;
|
||||
this.digestInto(buffer);
|
||||
const res = buffer.slice(0, outputLen);
|
||||
this.destroy();
|
||||
return res;
|
||||
}
|
||||
_cloneInto(to?: T): T {
|
||||
to ||= new (this.constructor as any)() as T;
|
||||
to.set(...this.get());
|
||||
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
||||
to.length = length;
|
||||
to.pos = pos;
|
||||
to.finished = finished;
|
||||
to.destroyed = destroyed;
|
||||
if (length % blockLen) to.buffer.set(buffer);
|
||||
return to;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
const U32_MASK64 = BigInt(2 ** 32 - 1);
|
||||
const _32n = BigInt(32);
|
||||
|
||||
export function fromBig(n: bigint, le = false) {
|
||||
if (le) return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) };
|
||||
return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
|
||||
}
|
||||
|
||||
export function split(lst: bigint[], le = false) {
|
||||
let Ah = new Uint32Array(lst.length);
|
||||
let Al = new Uint32Array(lst.length);
|
||||
for (let i = 0; i < lst.length; i++) {
|
||||
const { h, l } = fromBig(lst[i], le);
|
||||
[Ah[i], Al[i]] = [h, l];
|
||||
}
|
||||
return [Ah, Al];
|
||||
}
|
||||
|
||||
export const toBig = (h: number, l: number) => (BigInt(h >>> 0) << _32n) | BigInt(l >>> 0);
|
||||
// for Shift in [0, 32)
|
||||
export const shrSH = (h: number, l: number, s: number) => h >>> s;
|
||||
export const shrSL = (h: number, l: number, s: number) => (h << (32 - s)) | (l >>> s);
|
||||
// Right rotate for Shift in [1, 32)
|
||||
export const rotrSH = (h: number, l: number, s: number) => (h >>> s) | (l << (32 - s));
|
||||
export const rotrSL = (h: number, l: number, s: number) => (h << (32 - s)) | (l >>> s);
|
||||
// Right rotate for Shift in (32, 64), NOTE: 32 is special case.
|
||||
export const rotrBH = (h: number, l: number, s: number) => (h << (64 - s)) | (l >>> (s - 32));
|
||||
export const rotrBL = (h: number, l: number, s: number) => (h >>> (s - 32)) | (l << (64 - s));
|
||||
// Right rotate for shift===32 (just swaps l&h)
|
||||
export const rotr32H = (h: number, l: number) => l;
|
||||
export const rotr32L = (h: number, l: number) => h;
|
||||
// Left rotate for Shift in [1, 32)
|
||||
export const rotlSH = (h: number, l: number, s: number) => (h << s) | (l >>> (32 - s));
|
||||
export const rotlSL = (h: number, l: number, s: number) => (l << s) | (h >>> (32 - s));
|
||||
// Left rotate for Shift in (32, 64), NOTE: 32 is special case.
|
||||
export const rotlBH = (h: number, l: number, s: number) => (l << (s - 32)) | (h >>> (64 - s));
|
||||
export const rotlBL = (h: number, l: number, s: number) => (h << (s - 32)) | (l >>> (64 - s));
|
||||
|
||||
// JS uses 32-bit signed integers for bitwise operations which means we cannot
|
||||
// simple take carry out of low bit sum by shift, we need to use division.
|
||||
export function add(Ah: number, Al: number, Bh: number, Bl: number) {
|
||||
const l = (Al >>> 0) + (Bl >>> 0);
|
||||
return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 };
|
||||
}
|
||||
// Addition with more than 2 elements
|
||||
export const add3L = (Al: number, Bl: number, Cl: number) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
|
||||
export const add3H = (low: number, Ah: number, Bh: number, Ch: number) =>
|
||||
(Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0;
|
||||
export const add4L = (Al: number, Bl: number, Cl: number, Dl: number) =>
|
||||
(Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
|
||||
export const add4H = (low: number, Ah: number, Bh: number, Ch: number, Dh: number) =>
|
||||
(Ah + Bh + Ch + Dh + ((low / 2 ** 32) | 0)) | 0;
|
||||
export const add5L = (Al: number, Bl: number, Cl: number, Dl: number, El: number) =>
|
||||
(Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
|
||||
export const add5H = (low: number, Ah: number, Bh: number, Ch: number, Dh: number, Eh: number) =>
|
||||
(Ah + Bh + Ch + Dh + Eh + ((low / 2 ** 32) | 0)) | 0;
|
||||
@@ -1,200 +0,0 @@
|
||||
import * as blake2 from './_blake2';
|
||||
import * as u64 from './_u64';
|
||||
import { toBytes, u32, wrapConstructorWithOpts } from './utils';
|
||||
|
||||
// Same as SHA-512 but LE
|
||||
// prettier-ignore
|
||||
const IV = new Uint32Array([
|
||||
0xf3bcc908, 0x6a09e667, 0x84caa73b, 0xbb67ae85, 0xfe94f82b, 0x3c6ef372, 0x5f1d36f1, 0xa54ff53a,
|
||||
0xade682d1, 0x510e527f, 0x2b3e6c1f, 0x9b05688c, 0xfb41bd6b, 0x1f83d9ab, 0x137e2179, 0x5be0cd19
|
||||
]);
|
||||
// Temporary buffer
|
||||
const BUF = new Uint32Array(32);
|
||||
|
||||
// Mixing function G splitted in two halfs
|
||||
function G1(a: number, b: number, c: number, d: number, msg: Uint32Array, x: number) {
|
||||
// NOTE: V is LE here
|
||||
const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore
|
||||
let Al = BUF[2 * a], Ah = BUF[2 * a + 1]; // prettier-ignore
|
||||
let Bl = BUF[2 * b], Bh = BUF[2 * b + 1]; // prettier-ignore
|
||||
let Cl = BUF[2 * c], Ch = BUF[2 * c + 1]; // prettier-ignore
|
||||
let Dl = BUF[2 * d], Dh = BUF[2 * d + 1]; // prettier-ignore
|
||||
// v[a] = (v[a] + v[b] + x) | 0;
|
||||
let ll = u64.add3L(Al, Bl, Xl);
|
||||
Ah = u64.add3H(ll, Ah, Bh, Xh);
|
||||
Al = ll | 0;
|
||||
// v[d] = rotr(v[d] ^ v[a], 32)
|
||||
({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });
|
||||
({ Dh, Dl } = { Dh: u64.rotr32H(Dh, Dl), Dl: u64.rotr32L(Dh, Dl) });
|
||||
// v[c] = (v[c] + v[d]) | 0;
|
||||
({ h: Ch, l: Cl } = u64.add(Ch, Cl, Dh, Dl));
|
||||
// v[b] = rotr(v[b] ^ v[c], 24)
|
||||
({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });
|
||||
({ Bh, Bl } = { Bh: u64.rotrSH(Bh, Bl, 24), Bl: u64.rotrSL(Bh, Bl, 24) });
|
||||
(BUF[2 * a] = Al), (BUF[2 * a + 1] = Ah);
|
||||
(BUF[2 * b] = Bl), (BUF[2 * b + 1] = Bh);
|
||||
(BUF[2 * c] = Cl), (BUF[2 * c + 1] = Ch);
|
||||
(BUF[2 * d] = Dl), (BUF[2 * d + 1] = Dh);
|
||||
}
|
||||
|
||||
function G2(a: number, b: number, c: number, d: number, msg: Uint32Array, x: number) {
|
||||
// NOTE: V is LE here
|
||||
const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore
|
||||
let Al = BUF[2 * a], Ah = BUF[2 * a + 1]; // prettier-ignore
|
||||
let Bl = BUF[2 * b], Bh = BUF[2 * b + 1]; // prettier-ignore
|
||||
let Cl = BUF[2 * c], Ch = BUF[2 * c + 1]; // prettier-ignore
|
||||
let Dl = BUF[2 * d], Dh = BUF[2 * d + 1]; // prettier-ignore
|
||||
// v[a] = (v[a] + v[b] + x) | 0;
|
||||
let ll = u64.add3L(Al, Bl, Xl);
|
||||
Ah = u64.add3H(ll, Ah, Bh, Xh);
|
||||
Al = ll | 0;
|
||||
// v[d] = rotr(v[d] ^ v[a], 16)
|
||||
({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });
|
||||
({ Dh, Dl } = { Dh: u64.rotrSH(Dh, Dl, 16), Dl: u64.rotrSL(Dh, Dl, 16) });
|
||||
// v[c] = (v[c] + v[d]) | 0;
|
||||
({ h: Ch, l: Cl } = u64.add(Ch, Cl, Dh, Dl));
|
||||
// v[b] = rotr(v[b] ^ v[c], 63)
|
||||
({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });
|
||||
({ Bh, Bl } = { Bh: u64.rotrBH(Bh, Bl, 63), Bl: u64.rotrBL(Bh, Bl, 63) });
|
||||
(BUF[2 * a] = Al), (BUF[2 * a + 1] = Ah);
|
||||
(BUF[2 * b] = Bl), (BUF[2 * b + 1] = Bh);
|
||||
(BUF[2 * c] = Cl), (BUF[2 * c + 1] = Ch);
|
||||
(BUF[2 * d] = Dl), (BUF[2 * d + 1] = Dh);
|
||||
}
|
||||
|
||||
class BLAKE2b extends blake2.BLAKE2<BLAKE2b> {
|
||||
// Same as SHA-512, but LE
|
||||
private v0l = IV[0] | 0;
|
||||
private v0h = IV[1] | 0;
|
||||
private v1l = IV[2] | 0;
|
||||
private v1h = IV[3] | 0;
|
||||
private v2l = IV[4] | 0;
|
||||
private v2h = IV[5] | 0;
|
||||
private v3l = IV[6] | 0;
|
||||
private v3h = IV[7] | 0;
|
||||
private v4l = IV[8] | 0;
|
||||
private v4h = IV[9] | 0;
|
||||
private v5l = IV[10] | 0;
|
||||
private v5h = IV[11] | 0;
|
||||
private v6l = IV[12] | 0;
|
||||
private v6h = IV[13] | 0;
|
||||
private v7l = IV[14] | 0;
|
||||
private v7h = IV[15] | 0;
|
||||
|
||||
constructor(opts: blake2.BlakeOpts = {}) {
|
||||
super(128, opts.dkLen === undefined ? 64 : opts.dkLen, opts, 64, 16, 16);
|
||||
const keyLength = opts.key ? opts.key.length : 0;
|
||||
this.v0l ^= this.outputLen | (keyLength << 8) | (0x01 << 16) | (0x01 << 24);
|
||||
if (opts.salt) {
|
||||
const salt = u32(toBytes(opts.salt));
|
||||
this.v4l ^= salt[0];
|
||||
this.v4h ^= salt[1];
|
||||
this.v5l ^= salt[2];
|
||||
this.v5h ^= salt[3];
|
||||
}
|
||||
if (opts.personalization) {
|
||||
const pers = u32(toBytes(opts.personalization));
|
||||
this.v6l ^= pers[0];
|
||||
this.v6h ^= pers[1];
|
||||
this.v7l ^= pers[2];
|
||||
this.v7h ^= pers[3];
|
||||
}
|
||||
if (opts.key) {
|
||||
// Pad to blockLen and update
|
||||
const tmp = new Uint8Array(this.blockLen);
|
||||
tmp.set(toBytes(opts.key));
|
||||
this.update(tmp);
|
||||
}
|
||||
}
|
||||
// prettier-ignore
|
||||
protected get(): [
|
||||
number, number, number, number, number, number, number, number,
|
||||
number, number, number, number, number, number, number, number
|
||||
] {
|
||||
let {v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h} = this;
|
||||
return [v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h];
|
||||
}
|
||||
// prettier-ignore
|
||||
protected set(
|
||||
v0l: number, v0h: number, v1l: number, v1h: number,
|
||||
v2l: number, v2h: number, v3l: number, v3h: number,
|
||||
v4l: number, v4h: number, v5l: number, v5h: number,
|
||||
v6l: number, v6h: number, v7l: number, v7h: number
|
||||
) {
|
||||
this.v0l = v0l | 0;
|
||||
this.v0h = v0h | 0;
|
||||
this.v1l = v1l | 0;
|
||||
this.v1h = v1h | 0;
|
||||
this.v2l = v2l | 0;
|
||||
this.v2h = v2h | 0;
|
||||
this.v3l = v3l | 0;
|
||||
this.v3h = v3h | 0;
|
||||
this.v4l = v4l | 0;
|
||||
this.v4h = v4h | 0;
|
||||
this.v5l = v5l | 0;
|
||||
this.v5h = v5h | 0;
|
||||
this.v6l = v6l | 0;
|
||||
this.v6h = v6h | 0;
|
||||
this.v7l = v7l | 0;
|
||||
this.v7h = v7h | 0;
|
||||
}
|
||||
protected compress(msg: Uint32Array, offset: number, isLast: boolean) {
|
||||
this.get().forEach((v, i) => (BUF[i] = v)); // First half from state.
|
||||
BUF.set(IV, 16); // Second half from IV.
|
||||
let { h, l } = u64.fromBig(BigInt(this.length));
|
||||
BUF[24] = IV[8] ^ l; // Low word of the offset.
|
||||
BUF[25] = IV[9] ^ h; // High word.
|
||||
// Invert all bits for last block
|
||||
if (isLast) {
|
||||
BUF[28] = ~BUF[28];
|
||||
BUF[29] = ~BUF[29];
|
||||
}
|
||||
let j = 0;
|
||||
const s = blake2.SIGMA;
|
||||
for (let i = 0; i < 12; i++) {
|
||||
G1(0, 4, 8, 12, msg, offset + 2 * s[j++]);
|
||||
G2(0, 4, 8, 12, msg, offset + 2 * s[j++]);
|
||||
G1(1, 5, 9, 13, msg, offset + 2 * s[j++]);
|
||||
G2(1, 5, 9, 13, msg, offset + 2 * s[j++]);
|
||||
G1(2, 6, 10, 14, msg, offset + 2 * s[j++]);
|
||||
G2(2, 6, 10, 14, msg, offset + 2 * s[j++]);
|
||||
G1(3, 7, 11, 15, msg, offset + 2 * s[j++]);
|
||||
G2(3, 7, 11, 15, msg, offset + 2 * s[j++]);
|
||||
|
||||
G1(0, 5, 10, 15, msg, offset + 2 * s[j++]);
|
||||
G2(0, 5, 10, 15, msg, offset + 2 * s[j++]);
|
||||
G1(1, 6, 11, 12, msg, offset + 2 * s[j++]);
|
||||
G2(1, 6, 11, 12, msg, offset + 2 * s[j++]);
|
||||
G1(2, 7, 8, 13, msg, offset + 2 * s[j++]);
|
||||
G2(2, 7, 8, 13, msg, offset + 2 * s[j++]);
|
||||
G1(3, 4, 9, 14, msg, offset + 2 * s[j++]);
|
||||
G2(3, 4, 9, 14, msg, offset + 2 * s[j++]);
|
||||
}
|
||||
this.v0l ^= BUF[0] ^ BUF[16];
|
||||
this.v0h ^= BUF[1] ^ BUF[17];
|
||||
this.v1l ^= BUF[2] ^ BUF[18];
|
||||
this.v1h ^= BUF[3] ^ BUF[19];
|
||||
this.v2l ^= BUF[4] ^ BUF[20];
|
||||
this.v2h ^= BUF[5] ^ BUF[21];
|
||||
this.v3l ^= BUF[6] ^ BUF[22];
|
||||
this.v3h ^= BUF[7] ^ BUF[23];
|
||||
this.v4l ^= BUF[8] ^ BUF[24];
|
||||
this.v4h ^= BUF[9] ^ BUF[25];
|
||||
this.v5l ^= BUF[10] ^ BUF[26];
|
||||
this.v5h ^= BUF[11] ^ BUF[27];
|
||||
this.v6l ^= BUF[12] ^ BUF[28];
|
||||
this.v6h ^= BUF[13] ^ BUF[29];
|
||||
this.v7l ^= BUF[14] ^ BUF[30];
|
||||
this.v7h ^= BUF[15] ^ BUF[31];
|
||||
BUF.fill(0);
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.buffer32.fill(0);
|
||||
this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export const blake2b = wrapConstructorWithOpts<BLAKE2b, blake2.BlakeOpts>(
|
||||
(opts) => new BLAKE2b(opts)
|
||||
);
|
||||
@@ -1,133 +0,0 @@
|
||||
import * as u64 from './_u64';
|
||||
import * as blake2 from './_blake2';
|
||||
import { rotr, toBytes, wrapConstructorWithOpts, u32 } from './utils';
|
||||
|
||||
// Initial state:
|
||||
// first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19)
|
||||
// same as SHA-256
|
||||
// prettier-ignore
|
||||
export const IV = new Uint32Array([
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
]);
|
||||
|
||||
// Mixing function G splitted in two halfs
|
||||
function G1(a: number, b: number, c: number, d: number, x: number) {
|
||||
a = (a + b + x) | 0;
|
||||
d = rotr(d ^ a, 16);
|
||||
c = (c + d) | 0;
|
||||
b = rotr(b ^ c, 12);
|
||||
return { a, b, c, d };
|
||||
}
|
||||
|
||||
function G2(a: number, b: number, c: number, d: number, x: number) {
|
||||
a = (a + b + x) | 0;
|
||||
d = rotr(d ^ a, 8);
|
||||
c = (c + d) | 0;
|
||||
b = rotr(b ^ c, 7);
|
||||
return { a, b, c, d };
|
||||
}
|
||||
// prettier-ignore
|
||||
export function compress(s: Uint8Array, offset: number, msg: Uint32Array, rounds: number,
|
||||
v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number,
|
||||
v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number,
|
||||
) {
|
||||
let j = 0;
|
||||
for (let i = 0; i < rounds; i++) {
|
||||
({ a: v0, b: v4, c: v8, d: v12 } = G1(v0, v4, v8, v12, msg[offset + s[j++]]));
|
||||
({ a: v0, b: v4, c: v8, d: v12 } = G2(v0, v4, v8, v12, msg[offset + s[j++]]));
|
||||
({ a: v1, b: v5, c: v9, d: v13 } = G1(v1, v5, v9, v13, msg[offset + s[j++]]));
|
||||
({ a: v1, b: v5, c: v9, d: v13 } = G2(v1, v5, v9, v13, msg[offset + s[j++]]));
|
||||
({ a: v2, b: v6, c: v10, d: v14 } = G1(v2, v6, v10, v14, msg[offset + s[j++]]));
|
||||
({ a: v2, b: v6, c: v10, d: v14 } = G2(v2, v6, v10, v14, msg[offset + s[j++]]));
|
||||
({ a: v3, b: v7, c: v11, d: v15 } = G1(v3, v7, v11, v15, msg[offset + s[j++]]));
|
||||
({ a: v3, b: v7, c: v11, d: v15 } = G2(v3, v7, v11, v15, msg[offset + s[j++]]));
|
||||
|
||||
({ a: v0, b: v5, c: v10, d: v15 } = G1(v0, v5, v10, v15, msg[offset + s[j++]]));
|
||||
({ a: v0, b: v5, c: v10, d: v15 } = G2(v0, v5, v10, v15, msg[offset + s[j++]]));
|
||||
({ a: v1, b: v6, c: v11, d: v12 } = G1(v1, v6, v11, v12, msg[offset + s[j++]]));
|
||||
({ a: v1, b: v6, c: v11, d: v12 } = G2(v1, v6, v11, v12, msg[offset + s[j++]]));
|
||||
({ a: v2, b: v7, c: v8, d: v13 } = G1(v2, v7, v8, v13, msg[offset + s[j++]]));
|
||||
({ a: v2, b: v7, c: v8, d: v13 } = G2(v2, v7, v8, v13, msg[offset + s[j++]]));
|
||||
({ a: v3, b: v4, c: v9, d: v14 } = G1(v3, v4, v9, v14, msg[offset + s[j++]]));
|
||||
({ a: v3, b: v4, c: v9, d: v14 } = G2(v3, v4, v9, v14, msg[offset + s[j++]]));
|
||||
}
|
||||
return { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 };
|
||||
}
|
||||
|
||||
class BLAKE2s extends blake2.BLAKE2<BLAKE2s> {
|
||||
// Internal state, same as SHA-256
|
||||
private v0 = IV[0] | 0;
|
||||
private v1 = IV[1] | 0;
|
||||
private v2 = IV[2] | 0;
|
||||
private v3 = IV[3] | 0;
|
||||
private v4 = IV[4] | 0;
|
||||
private v5 = IV[5] | 0;
|
||||
private v6 = IV[6] | 0;
|
||||
private v7 = IV[7] | 0;
|
||||
|
||||
constructor(opts: blake2.BlakeOpts = {}) {
|
||||
super(64, opts.dkLen === undefined ? 32 : opts.dkLen, opts, 32, 8, 8);
|
||||
const keyLength = opts.key ? opts.key.length : 0;
|
||||
this.v0 ^= this.outputLen | (keyLength << 8) | (0x01 << 16) | (0x01 << 24);
|
||||
if (opts.salt) {
|
||||
const salt = u32(toBytes(opts.salt));
|
||||
this.v4 ^= salt[0];
|
||||
this.v5 ^= salt[1];
|
||||
}
|
||||
if (opts.personalization) {
|
||||
const pers = u32(toBytes(opts.personalization));
|
||||
this.v6 ^= pers[0];
|
||||
this.v7 ^= pers[1];
|
||||
}
|
||||
if (opts.key) {
|
||||
// Pad to blockLen and update
|
||||
const tmp = new Uint8Array(this.blockLen);
|
||||
tmp.set(toBytes(opts.key));
|
||||
this.update(tmp);
|
||||
}
|
||||
}
|
||||
protected get(): [number, number, number, number, number, number, number, number] {
|
||||
const { v0, v1, v2, v3, v4, v5, v6, v7 } = this;
|
||||
return [v0, v1, v2, v3, v4, v5, v6, v7];
|
||||
}
|
||||
// prettier-ignore
|
||||
protected set(
|
||||
v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number
|
||||
) {
|
||||
this.v0 = v0 | 0;
|
||||
this.v1 = v1 | 0;
|
||||
this.v2 = v2 | 0;
|
||||
this.v3 = v3 | 0;
|
||||
this.v4 = v4 | 0;
|
||||
this.v5 = v5 | 0;
|
||||
this.v6 = v6 | 0;
|
||||
this.v7 = v7 | 0;
|
||||
}
|
||||
protected compress(msg: Uint32Array, offset: number, isLast: boolean) {
|
||||
const { h, l } = u64.fromBig(BigInt(this.length));
|
||||
// prettier-ignore
|
||||
const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } =
|
||||
compress(
|
||||
blake2.SIGMA, offset, msg, 10,
|
||||
this.v0, this.v1, this.v2, this.v3, this.v4, this.v5, this.v6, this.v7,
|
||||
IV[0], IV[1], IV[2], IV[3], l ^ IV[4], h ^ IV[5], isLast ? ~IV[6] : IV[6], IV[7]
|
||||
);
|
||||
this.v0 ^= v0 ^ v8;
|
||||
this.v1 ^= v1 ^ v9;
|
||||
this.v2 ^= v2 ^ v10;
|
||||
this.v3 ^= v3 ^ v11;
|
||||
this.v4 ^= v4 ^ v12;
|
||||
this.v5 ^= v5 ^ v13;
|
||||
this.v6 ^= v6 ^ v14;
|
||||
this.v7 ^= v7 ^ v15;
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.buffer32.fill(0);
|
||||
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export const blake2s = wrapConstructorWithOpts<BLAKE2s, blake2.BlakeOpts>(
|
||||
(opts) => new BLAKE2s(opts)
|
||||
);
|
||||
@@ -1,240 +0,0 @@
|
||||
import * as u64 from './_u64';
|
||||
import * as blake2 from './_blake2';
|
||||
import * as blake2s from './blake2s';
|
||||
import { Input, u8, u32, toBytes, wrapConstructorWithOpts, assertNumber, HashXOF } from './utils';
|
||||
|
||||
// Flag bitset
|
||||
enum Flags {
|
||||
CHUNK_START = 1 << 0,
|
||||
CHUNK_END = 1 << 1,
|
||||
PARENT = 1 << 2,
|
||||
ROOT = 1 << 3,
|
||||
KEYED_HASH = 1 << 4,
|
||||
DERIVE_KEY_CONTEXT = 1 << 5,
|
||||
DERIVE_KEY_MATERIAL = 1 << 6,
|
||||
}
|
||||
|
||||
const SIGMA: Uint8Array = (() => {
|
||||
const Id = Array.from({ length: 16 }, (_, i) => i);
|
||||
const permute = (arr: number[]) =>
|
||||
[2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8].map((i) => arr[i]);
|
||||
const res: number[] = [];
|
||||
for (let i = 0, v = Id; i < 7; i++, v = permute(v)) res.push(...v);
|
||||
return Uint8Array.from(res);
|
||||
})();
|
||||
|
||||
// - key: is 256-bit key
|
||||
// - context: string should be hardcoded, globally unique, and application - specific.
|
||||
// A good default format for the context string is "[application] [commit timestamp] [purpose]"
|
||||
// - Only one of 'key' (keyed mode) or 'context' (derive key mode) can be used at same time
|
||||
export type Blake3Opts = { dkLen?: number; key?: Input; context?: Input };
|
||||
|
||||
// Why is this so slow? It should be 6x faster than blake2b.
|
||||
// - There is only 30% reduction in number of rounds from blake2s
|
||||
// - This function uses tree mode to achive parallelisation via SIMD and threading,
|
||||
// however in JS we don't have threads and SIMD, so we get only overhead from tree structure
|
||||
// - It is possible to speed it up via Web Workers, hovewer it will make code singnificantly more
|
||||
// complicated, which we are trying to avoid, since this library is intended to be used
|
||||
// for cryptographic purposes. Also, parallelization happens only on chunk level (1024 bytes),
|
||||
// which won't really benefit small inputs.
|
||||
class BLAKE3 extends blake2.BLAKE2<BLAKE3> implements HashXOF<BLAKE3> {
|
||||
private IV: Uint32Array;
|
||||
private flags = 0 | 0;
|
||||
private state: Uint32Array;
|
||||
private chunkPos = 0; // Position of current block in chunk
|
||||
private chunksDone = 0; // How many chunks we already have
|
||||
private stack: Uint32Array[] = [];
|
||||
// Output
|
||||
private posOut = 0;
|
||||
private bufferOut32 = new Uint32Array(16);
|
||||
private bufferOut: Uint8Array;
|
||||
private chunkOut = 0; // index of output chunk
|
||||
private enableXOF = true;
|
||||
|
||||
constructor(opts: Blake3Opts = {}, flags = 0) {
|
||||
super(64, opts.dkLen === undefined ? 32 : opts.dkLen, {}, Number.MAX_SAFE_INTEGER, 0, 0);
|
||||
this.outputLen = opts.dkLen === undefined ? 32 : opts.dkLen;
|
||||
assertNumber(this.outputLen);
|
||||
if (opts.key !== undefined && opts.context !== undefined)
|
||||
throw new Error('Blake3: only key or context can be specified at same time');
|
||||
else if (opts.key !== undefined) {
|
||||
const key = toBytes(opts.key);
|
||||
if (key.length !== 32) throw new Error('Blake3: key should be 32 byte');
|
||||
this.IV = u32(key);
|
||||
this.flags = flags | Flags.KEYED_HASH;
|
||||
} else if (opts.context !== undefined) {
|
||||
const context_key = new BLAKE3({ dkLen: 32 }, Flags.DERIVE_KEY_CONTEXT)
|
||||
.update(opts.context)
|
||||
.digest();
|
||||
this.IV = u32(context_key);
|
||||
this.flags = flags | Flags.DERIVE_KEY_MATERIAL;
|
||||
} else {
|
||||
this.IV = blake2s.IV.slice();
|
||||
this.flags = flags;
|
||||
}
|
||||
this.state = this.IV.slice();
|
||||
this.bufferOut = u8(this.bufferOut32);
|
||||
}
|
||||
// Unused
|
||||
protected get() {
|
||||
return [];
|
||||
}
|
||||
protected set() {}
|
||||
private b2Compress(counter: number, flags: number, buf: Uint32Array, bufPos: number = 0) {
|
||||
const { state, pos } = this;
|
||||
const { h, l } = u64.fromBig(BigInt(counter), true);
|
||||
// prettier-ignore
|
||||
const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } =
|
||||
blake2s.compress(
|
||||
SIGMA, bufPos, buf, 7,
|
||||
state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7],
|
||||
blake2s.IV[0], blake2s.IV[1], blake2s.IV[2], blake2s.IV[3], h, l, pos, flags
|
||||
);
|
||||
state[0] = v0 ^ v8;
|
||||
state[1] = v1 ^ v9;
|
||||
state[2] = v2 ^ v10;
|
||||
state[3] = v3 ^ v11;
|
||||
state[4] = v4 ^ v12;
|
||||
state[5] = v5 ^ v13;
|
||||
state[6] = v6 ^ v14;
|
||||
state[7] = v7 ^ v15;
|
||||
}
|
||||
protected compress(buf: Uint32Array, bufPos: number = 0, isLast: boolean = false) {
|
||||
// Compress last block
|
||||
let flags = this.flags;
|
||||
if (!this.chunkPos) flags |= Flags.CHUNK_START;
|
||||
if (this.chunkPos === 15 || isLast) flags |= Flags.CHUNK_END;
|
||||
if (!isLast) this.pos = this.blockLen;
|
||||
this.b2Compress(this.chunksDone, flags, buf, bufPos);
|
||||
this.chunkPos += 1;
|
||||
// If current block is last in chunk (16 blocks), then compress chunks
|
||||
if (this.chunkPos === 16 || isLast) {
|
||||
let chunk = this.state;
|
||||
this.state = this.IV.slice();
|
||||
// If not the last one, compress only when there are trailing zeros in chunk counter
|
||||
// chunks used as binary tree where current stack is path. Zero means current leaf is finished and can be compressed.
|
||||
// 1 (001) - leaf not finished (just push current chunk to stack)
|
||||
// 2 (010) - leaf finished at depth=1 (merge with last elm on stack and push back)
|
||||
// 3 (011) - last leaf not finished
|
||||
// 4 (100) - leafs finished at depth=1 and depth=2
|
||||
for (let last, chunks = this.chunksDone + 1; isLast || !(chunks & 1); chunks >>= 1) {
|
||||
if (!(last = this.stack.pop())) break;
|
||||
this.buffer32.set(last, 0);
|
||||
this.buffer32.set(chunk, 8);
|
||||
this.pos = this.blockLen;
|
||||
this.b2Compress(0, this.flags | Flags.PARENT, this.buffer32, 0);
|
||||
chunk = this.state;
|
||||
this.state = this.IV.slice();
|
||||
}
|
||||
this.chunksDone++;
|
||||
this.chunkPos = 0;
|
||||
this.stack.push(chunk);
|
||||
}
|
||||
this.pos = 0;
|
||||
}
|
||||
override _cloneInto(to?: BLAKE3): BLAKE3 {
|
||||
to = super._cloneInto(to) as BLAKE3;
|
||||
const { IV, flags, state, chunkPos, posOut, chunkOut, stack, chunksDone } = this;
|
||||
to.state.set(state.slice());
|
||||
to.stack = stack.map((i) => Uint32Array.from(i));
|
||||
to.IV.set(IV);
|
||||
to.flags = flags;
|
||||
to.chunkPos = chunkPos;
|
||||
to.chunksDone = chunksDone;
|
||||
to.posOut = posOut;
|
||||
to.chunkOut = chunkOut;
|
||||
to.enableXOF = this.enableXOF;
|
||||
to.bufferOut32.set(this.bufferOut32);
|
||||
return to;
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.state.fill(0);
|
||||
this.buffer32.fill(0);
|
||||
this.IV.fill(0);
|
||||
this.bufferOut32.fill(0);
|
||||
for (let i of this.stack) i.fill(0);
|
||||
}
|
||||
// Same as b2Compress, but doesn't modify state and returns 16 u32 array (instead of 8)
|
||||
private b2CompressOut() {
|
||||
const { state, pos, flags, buffer32, bufferOut32 } = this;
|
||||
const { h, l } = u64.fromBig(BigInt(this.chunkOut++));
|
||||
// prettier-ignore
|
||||
const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } =
|
||||
blake2s.compress(
|
||||
SIGMA, 0, buffer32, 7,
|
||||
state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7],
|
||||
blake2s.IV[0], blake2s.IV[1], blake2s.IV[2], blake2s.IV[3], l, h, pos, flags
|
||||
);
|
||||
bufferOut32[0] = v0 ^ v8;
|
||||
bufferOut32[1] = v1 ^ v9;
|
||||
bufferOut32[2] = v2 ^ v10;
|
||||
bufferOut32[3] = v3 ^ v11;
|
||||
bufferOut32[4] = v4 ^ v12;
|
||||
bufferOut32[5] = v5 ^ v13;
|
||||
bufferOut32[6] = v6 ^ v14;
|
||||
bufferOut32[7] = v7 ^ v15;
|
||||
bufferOut32[8] = state[0] ^ v8;
|
||||
bufferOut32[9] = state[1] ^ v9;
|
||||
bufferOut32[10] = state[2] ^ v10;
|
||||
bufferOut32[11] = state[3] ^ v11;
|
||||
bufferOut32[12] = state[4] ^ v12;
|
||||
bufferOut32[13] = state[5] ^ v13;
|
||||
bufferOut32[14] = state[6] ^ v14;
|
||||
bufferOut32[15] = state[7] ^ v15;
|
||||
this.posOut = 0;
|
||||
}
|
||||
protected finish() {
|
||||
if (this.finished) return;
|
||||
this.finished = true;
|
||||
// Padding
|
||||
this.buffer.fill(0, this.pos);
|
||||
// Process last chunk
|
||||
let flags = this.flags | Flags.ROOT;
|
||||
if (this.stack.length) {
|
||||
flags |= Flags.PARENT;
|
||||
this.compress(this.buffer32, 0, true);
|
||||
this.chunksDone = 0;
|
||||
this.pos = this.blockLen;
|
||||
} else {
|
||||
flags |= (!this.chunkPos ? Flags.CHUNK_START : 0) | Flags.CHUNK_END;
|
||||
}
|
||||
this.flags = flags;
|
||||
this.b2CompressOut();
|
||||
}
|
||||
private writeInto(out: Uint8Array) {
|
||||
if (this.destroyed) throw new Error('instance is destroyed');
|
||||
if (!(out instanceof Uint8Array)) throw new Error('Blake3: Invalid output buffer');
|
||||
this.finish();
|
||||
const { blockLen, bufferOut } = this;
|
||||
for (let pos = 0, len = out.length; pos < len; ) {
|
||||
if (this.posOut >= blockLen) this.b2CompressOut();
|
||||
const take = Math.min(this.blockLen - this.posOut, len - pos);
|
||||
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
|
||||
this.posOut += take;
|
||||
pos += take;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
xofInto(out: Uint8Array): Uint8Array {
|
||||
if (!this.enableXOF) throw new Error('XOF impossible after digest call');
|
||||
return this.writeInto(out);
|
||||
}
|
||||
xof(bytes: number): Uint8Array {
|
||||
assertNumber(bytes);
|
||||
return this.xofInto(new Uint8Array(bytes));
|
||||
}
|
||||
override digestInto(out: Uint8Array) {
|
||||
if (out.length < this.outputLen) throw new Error('Blake3: Invalid output buffer');
|
||||
if (this.finished) throw new Error('digest() was already called');
|
||||
this.enableXOF = false;
|
||||
this.writeInto(out);
|
||||
this.destroy();
|
||||
return out;
|
||||
}
|
||||
override digest() {
|
||||
return this.digestInto(new Uint8Array(this.outputLen));
|
||||
}
|
||||
}
|
||||
|
||||
export const blake3 = wrapConstructorWithOpts<BLAKE3, Blake3Opts>((opts) => new BLAKE3(opts));
|
||||
@@ -1,6 +0,0 @@
|
||||
import nodeCrypto from 'crypto';
|
||||
|
||||
export const crypto: { node?: any; web?: any } = {
|
||||
node: nodeCrypto,
|
||||
web: undefined,
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
// Global symbol available in browsers only
|
||||
declare const self: Record<string, any> | undefined;
|
||||
export const crypto: { node?: any; web?: any } = {
|
||||
node: undefined,
|
||||
web: typeof self === 'object' && 'crypto' in self ? self.crypto : undefined,
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
// prettier-ignore
|
||||
import {
|
||||
assertHash, assertNumber, CHash, Input, toBytes
|
||||
} from './utils';
|
||||
import { hmac } from './hmac';
|
||||
|
||||
// HKDF (RFC 5869)
|
||||
// HKDF-Extract(IKM, salt) -> PRK NOTE: arguments position differs from spec (IKM is first one, since it is not optional)
|
||||
export function hkdf_extract(hash: CHash, ikm: Input, salt?: Input) {
|
||||
assertHash(hash);
|
||||
// NOTE: some libraries treats zero-length array as 'not provided', we don't, since we have undefined as 'not provided'
|
||||
// More info: https://github.com/RustCrypto/KDFs/issues/15
|
||||
if (salt === undefined) salt = new Uint8Array(hash.outputLen); // if not provided, it is set to a string of HashLen zeros
|
||||
return hmac(hash, toBytes(salt), toBytes(ikm));
|
||||
}
|
||||
|
||||
// HKDF-Expand(PRK, info, L) -> OKM
|
||||
const HKDF_COUNTER = new Uint8Array([0]);
|
||||
const EMPTY_BUFFER = new Uint8Array();
|
||||
export function hkdf_expand(
|
||||
hash: CHash,
|
||||
prk: Input, // a pseudorandom key of at least HashLen octets (usually, the output from the extract step)
|
||||
info?: Input, // optional context and application specific information (can be a zero-length string)
|
||||
length: number = 32 // length of output keying material in octets
|
||||
) {
|
||||
assertHash(hash);
|
||||
assertNumber(length);
|
||||
if (length > 255 * hash.outputLen) throw new Error('Length should be <= 255*HashLen');
|
||||
const blocks = Math.ceil(length / hash.outputLen);
|
||||
if (info === undefined) info = EMPTY_BUFFER;
|
||||
// first L(ength) octets of T
|
||||
const okm = new Uint8Array(blocks * hash.outputLen);
|
||||
// Re-use HMAC instance between blocks
|
||||
const HMAC = hmac.init(hash, prk);
|
||||
const HMACTmp = HMAC._cloneInto();
|
||||
const T = new Uint8Array(HMAC.outputLen);
|
||||
for (let counter = 0; counter < blocks; counter++) {
|
||||
HKDF_COUNTER[0] = counter + 1;
|
||||
// T(0) = empty string (zero length)
|
||||
// T(N) = HMAC-Hash(PRK, T(N-1) | info | N)
|
||||
HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T)
|
||||
.update(info)
|
||||
.update(HKDF_COUNTER)
|
||||
.digestInto(T);
|
||||
okm.set(T, hash.outputLen * counter);
|
||||
HMAC._cloneInto(HMACTmp);
|
||||
}
|
||||
HMAC.destroy();
|
||||
HMACTmp.destroy();
|
||||
T.fill(0);
|
||||
return okm.slice(0, length);
|
||||
}
|
||||
// Extract+Expand
|
||||
export const hkdf = (
|
||||
hash: CHash,
|
||||
ikm: Input,
|
||||
salt: Input | undefined,
|
||||
info: Input | undefined,
|
||||
length: number
|
||||
) => hkdf_expand(hash, hkdf_extract(hash, ikm, salt), info, length);
|
||||
@@ -1,76 +0,0 @@
|
||||
import { assertHash, Hash, CHash, Input, toBytes } from './utils';
|
||||
// HMAC (RFC 2104)
|
||||
class HMAC<T extends Hash<T>> extends Hash<HMAC<T>> {
|
||||
oHash: T;
|
||||
iHash: T;
|
||||
blockLen: number;
|
||||
outputLen: number;
|
||||
private finished = false;
|
||||
private destroyed = false;
|
||||
|
||||
constructor(hash: CHash, _key: Input) {
|
||||
super();
|
||||
assertHash(hash);
|
||||
const key = toBytes(_key);
|
||||
this.iHash = hash.create() as T;
|
||||
if (!(this.iHash instanceof Hash))
|
||||
throw new TypeError('Expected instance of class which extends utils.Hash');
|
||||
const blockLen = (this.blockLen = this.iHash.blockLen);
|
||||
this.outputLen = this.iHash.outputLen;
|
||||
const pad = new Uint8Array(blockLen);
|
||||
// blockLen can be bigger than outputLen
|
||||
pad.set(key.length > this.iHash.blockLen ? hash.create().update(key).digest() : key);
|
||||
for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36;
|
||||
this.iHash.update(pad);
|
||||
// By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
|
||||
this.oHash = hash.create() as T;
|
||||
// Undo internal XOR && apply outer XOR
|
||||
for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36 ^ 0x5c;
|
||||
this.oHash.update(pad);
|
||||
pad.fill(0);
|
||||
}
|
||||
update(buf: Input) {
|
||||
if (this.destroyed) throw new Error('instance is destroyed');
|
||||
this.iHash.update(buf);
|
||||
return this;
|
||||
}
|
||||
digestInto(out: Uint8Array) {
|
||||
if (this.destroyed) throw new Error('instance is destroyed');
|
||||
if (!(out instanceof Uint8Array) || out.length !== this.outputLen)
|
||||
throw new Error('HMAC: Invalid output buffer');
|
||||
if (this.finished) throw new Error('digest() was already called');
|
||||
this.finished = true;
|
||||
this.iHash.digestInto(out);
|
||||
this.oHash.update(out);
|
||||
this.oHash.digestInto(out);
|
||||
this.destroy();
|
||||
}
|
||||
digest() {
|
||||
const out = new Uint8Array(this.oHash.outputLen);
|
||||
this.digestInto(out);
|
||||
return out;
|
||||
}
|
||||
_cloneInto(to?: HMAC<T>): HMAC<T> {
|
||||
// Create new instance without calling constructor since key already in state and we don't know it.
|
||||
to ||= Object.create(Object.getPrototypeOf(this), {});
|
||||
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
||||
to = to as this;
|
||||
to.finished = finished;
|
||||
to.destroyed = destroyed;
|
||||
to.blockLen = blockLen;
|
||||
to.outputLen = outputLen;
|
||||
to.oHash = oHash._cloneInto(to.oHash);
|
||||
to.iHash = iHash._cloneInto(to.iHash);
|
||||
return to;
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.oHash.destroy();
|
||||
this.iHash.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
export const hmac = (hash: CHash, key: Input, message: Input): Uint8Array =>
|
||||
new HMAC<any>(hash, key).update(message).digest();
|
||||
hmac.create = (hash: CHash, key: Input) => new HMAC<any>(hash, key);
|
||||
hmac.init = hmac.create;
|
||||
@@ -1,3 +0,0 @@
|
||||
throw new Error(
|
||||
'noble-hashes have no entry-point. Please consult the README.md to learn how to use them'
|
||||
);
|
||||
@@ -1,6 +0,0 @@
|
||||
// Copyright 2017-2021 @polkadot/x-noble-hashes authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Auto-generated by @polkadot/dev, do not edit
|
||||
|
||||
export const packageInfo = { name: '@polkadot/x-noble-hashes', version: '8.1.3-28' };
|
||||
@@ -1,92 +0,0 @@
|
||||
import { hmac } from './hmac';
|
||||
// prettier-ignore
|
||||
import {
|
||||
Hash, CHash, Input, createView, toBytes, assertNumber, assertHash, checkOpts, asyncLoop
|
||||
} from './utils';
|
||||
|
||||
// PBKDF (RFC 2898)
|
||||
export type Pbkdf2Opt = {
|
||||
c: number; // Iterations
|
||||
dkLen?: number; // Desired key length in bytes (Intended output length in octets of the derived key
|
||||
asyncTick?: number; // Maximum time in ms for which async function can block execution
|
||||
};
|
||||
// Common prologue and epilogue for sync/async functions
|
||||
function pbkdf2Init(hash: CHash, _password: Input, _salt: Input, _opts: Pbkdf2Opt) {
|
||||
assertHash(hash);
|
||||
const opts = checkOpts({ dkLen: 32, asyncTick: 10 }, _opts);
|
||||
const { c, dkLen, asyncTick } = opts;
|
||||
assertNumber(c);
|
||||
assertNumber(dkLen);
|
||||
assertNumber(asyncTick);
|
||||
if (c < 1) throw new Error('PBKDF2: iterations (c) should be >= 1');
|
||||
const password = toBytes(_password);
|
||||
const salt = toBytes(_salt);
|
||||
// DK = PBKDF2(PRF, Password, Salt, c, dkLen);
|
||||
const DK = new Uint8Array(dkLen);
|
||||
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
||||
const PRF = hmac.init(hash, password);
|
||||
const PRFSalt = PRF._cloneInto().update(salt);
|
||||
return { c, dkLen, asyncTick, DK, PRF, PRFSalt };
|
||||
}
|
||||
|
||||
function pbkdf2Output<T extends Hash<T>>(
|
||||
PRF: Hash<T>,
|
||||
PRFSalt: Hash<T>,
|
||||
DK: Uint8Array,
|
||||
prfW: Hash<T>,
|
||||
u: Uint8Array
|
||||
) {
|
||||
PRF.destroy();
|
||||
PRFSalt.destroy();
|
||||
if (prfW) prfW.destroy();
|
||||
u.fill(0);
|
||||
return DK;
|
||||
}
|
||||
|
||||
export function pbkdf2(hash: CHash, password: Input, salt: Input, _opts: Pbkdf2Opt) {
|
||||
const { c, dkLen, DK, PRF, PRFSalt } = pbkdf2Init(hash, password, salt, _opts);
|
||||
let prfW: any; // Working copy
|
||||
const arr = new Uint8Array(4);
|
||||
const view = createView(arr);
|
||||
const u = new Uint8Array(PRF.outputLen);
|
||||
// DK = T1 + T2 + ⋯ + Tdklen/hlen
|
||||
for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) {
|
||||
// Ti = F(Password, Salt, c, i)
|
||||
const Ti = DK.subarray(pos, pos + PRF.outputLen);
|
||||
view.setInt32(0, ti, false);
|
||||
// F(Password, Salt, c, i) = U1 ^ U2 ^ ⋯ ^ Uc
|
||||
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
||||
(prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u);
|
||||
Ti.set(u.subarray(0, Ti.length));
|
||||
for (let ui = 1; ui < c; ui++) {
|
||||
// Uc = PRF(Password, Uc−1)
|
||||
PRF._cloneInto(prfW).update(u).digestInto(u);
|
||||
for (let i = 0; i < Ti.length; i++) Ti[i] ^= u[i];
|
||||
}
|
||||
}
|
||||
return pbkdf2Output(PRF, PRFSalt, DK, prfW, u);
|
||||
}
|
||||
|
||||
export async function pbkdf2Async(hash: CHash, password: Input, salt: Input, _opts: Pbkdf2Opt) {
|
||||
const { c, dkLen, asyncTick, DK, PRF, PRFSalt } = pbkdf2Init(hash, password, salt, _opts);
|
||||
let prfW: any; // Working copy
|
||||
const arr = new Uint8Array(4);
|
||||
const view = createView(arr);
|
||||
const u = new Uint8Array(PRF.outputLen);
|
||||
// DK = T1 + T2 + ⋯ + Tdklen/hlen
|
||||
for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) {
|
||||
// Ti = F(Password, Salt, c, i)
|
||||
const Ti = DK.subarray(pos, pos + PRF.outputLen);
|
||||
view.setInt32(0, ti, false);
|
||||
// F(Password, Salt, c, i) = U1 ^ U2 ^ ⋯ ^ Uc
|
||||
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
||||
(prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u);
|
||||
Ti.set(u.subarray(0, Ti.length));
|
||||
await asyncLoop(c - 1, asyncTick, (i) => {
|
||||
// Uc = PRF(Password, Uc−1)
|
||||
PRF._cloneInto(prfW).update(u).digestInto(u);
|
||||
for (let i = 0; i < Ti.length; i++) Ti[i] ^= u[i];
|
||||
});
|
||||
}
|
||||
return pbkdf2Output(PRF, PRFSalt, DK, prfW, u);
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
import { SHA2 } from './_sha2';
|
||||
|
||||
import { wrapConstructor } from './utils';
|
||||
|
||||
// https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
||||
// https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf
|
||||
const Rho = new Uint8Array([7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8]);
|
||||
const Id = Uint8Array.from({ length: 16 }, (_, i) => i);
|
||||
const Pi = Id.map((i) => (9 * i + 5) % 16);
|
||||
let idxL = [Id];
|
||||
let idxR = [Pi];
|
||||
for (let i = 0; i < 4; i++) for (let j of [idxL, idxR]) j.push(j[i].map((k) => Rho[k]));
|
||||
|
||||
const shifts = [
|
||||
[11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],
|
||||
[12, 13, 11, 15, 6, 9, 9, 7, 12, 15, 11, 13, 7, 8, 7, 7],
|
||||
[13, 15, 14, 11, 7, 7, 6, 8, 13, 14, 13, 12, 5, 5, 6, 9],
|
||||
[14, 11, 12, 14, 8, 6, 5, 5, 15, 12, 15, 14, 9, 9, 8, 6],
|
||||
[15, 12, 13, 13, 9, 5, 8, 6, 14, 11, 12, 11, 8, 6, 5, 5],
|
||||
].map((i) => new Uint8Array(i));
|
||||
|
||||
const shiftsL = idxL.map((idx, i) => idx.map((j) => shifts[i][j]));
|
||||
const shiftsR = idxR.map((idx, i) => idx.map((j) => shifts[i][j]));
|
||||
|
||||
const Kl = new Uint32Array([0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e]);
|
||||
const Kr = new Uint32Array([0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000]);
|
||||
// The rotate left (circular left shift) operation for uint32
|
||||
const rotl = (word: number, shift: number) => (word << shift) | (word >>> (32 - shift));
|
||||
// It's called f() in spec.
|
||||
function f(group: number, x: number, y: number, z: number): number {
|
||||
if (group === 0) return x ^ y ^ z;
|
||||
else if (group === 1) return (x & y) | (~x & z);
|
||||
else if (group === 2) return (x | ~y) ^ z;
|
||||
else if (group === 3) return (x & z) | (y & ~z);
|
||||
else return x ^ (y | ~z);
|
||||
}
|
||||
// Temporary buffer, not used to store anything between runs
|
||||
const BUF = new Uint32Array(16);
|
||||
export class RIPEMD160 extends SHA2<RIPEMD160> {
|
||||
private h0 = 0x67452301 | 0;
|
||||
private h1 = 0xefcdab89 | 0;
|
||||
private h2 = 0x98badcfe | 0;
|
||||
private h3 = 0x10325476 | 0;
|
||||
private h4 = 0xc3d2e1f0 | 0;
|
||||
|
||||
constructor() {
|
||||
super(64, 20, 8, true);
|
||||
}
|
||||
protected get(): [number, number, number, number, number] {
|
||||
const { h0, h1, h2, h3, h4 } = this;
|
||||
return [h0, h1, h2, h3, h4];
|
||||
}
|
||||
protected set(h0: number, h1: number, h2: number, h3: number, h4: number) {
|
||||
this.h0 = h0 | 0;
|
||||
this.h1 = h1 | 0;
|
||||
this.h2 = h2 | 0;
|
||||
this.h3 = h3 | 0;
|
||||
this.h4 = h4 | 0;
|
||||
}
|
||||
protected process(view: DataView, offset: number): void {
|
||||
for (let i = 0; i < 16; i++, offset += 4) BUF[i] = view.getUint32(offset, true);
|
||||
// prettier-ignore
|
||||
let al = this.h0 | 0, ar = al,
|
||||
bl = this.h1 | 0, br = bl,
|
||||
cl = this.h2 | 0, cr = cl,
|
||||
dl = this.h3 | 0, dr = dl,
|
||||
el = this.h4 | 0, er = el;
|
||||
|
||||
// Instead of iterating 0 to 80, we split it into 5 groups
|
||||
// And use the groups in constants, functions, etc. Much simpler
|
||||
for (let group = 0; group < 5; group++) {
|
||||
const rGroup = 4 - group;
|
||||
const hbl = Kl[group], hbr = Kr[group]; // prettier-ignore
|
||||
const rl = idxL[group], rr = idxR[group]; // prettier-ignore
|
||||
const sl = shiftsL[group], sr = shiftsR[group]; // prettier-ignore
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const tl = (rotl(al + f(group, bl, cl, dl) + BUF[rl[i]] + hbl, sl[i]) + el) | 0;
|
||||
al = el, el = dl, dl = rotl(cl, 10) | 0, cl = bl, bl = tl; // prettier-ignore
|
||||
}
|
||||
// 2 loops are 10% faster
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const tr = (rotl(ar + f(rGroup, br, cr, dr) + BUF[rr[i]] + hbr, sr[i]) + er) | 0;
|
||||
ar = er, er = dr, dr = rotl(cr, 10) | 0, cr = br, br = tr; // prettier-ignore
|
||||
}
|
||||
}
|
||||
// Add the compressed chunk to the current hash value
|
||||
this.set(
|
||||
(this.h1 + cl + dr) | 0,
|
||||
(this.h2 + dl + er) | 0,
|
||||
(this.h3 + el + ar) | 0,
|
||||
(this.h4 + al + br) | 0,
|
||||
(this.h0 + bl + cr) | 0
|
||||
);
|
||||
}
|
||||
protected roundClean() {
|
||||
BUF.fill(0);
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.buffer.fill(0);
|
||||
this.set(0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export const ripemd160 = wrapConstructor(() => new RIPEMD160());
|
||||
@@ -1,219 +0,0 @@
|
||||
import { sha256 } from './sha256';
|
||||
import { pbkdf2 } from './pbkdf2';
|
||||
import { assertNumber, asyncLoop, checkOpts, Input, u32 } from './utils';
|
||||
|
||||
// Left rotate for uint32
|
||||
const rotl = (a: number, b: number) => (a << b) | (a >>> (32 - b));
|
||||
|
||||
// prettier-ignore
|
||||
function XorAndSalsa(
|
||||
prev: Uint32Array,
|
||||
pi: number,
|
||||
input: Uint32Array,
|
||||
ii: number,
|
||||
out: Uint32Array,
|
||||
oi: number
|
||||
) {
|
||||
// Based on https://cr.yp.to/salsa20.html
|
||||
// Xor blocks
|
||||
let y00 = prev[pi++] ^ input[ii++], y01 = prev[pi++] ^ input[ii++];
|
||||
let y02 = prev[pi++] ^ input[ii++], y03 = prev[pi++] ^ input[ii++];
|
||||
let y04 = prev[pi++] ^ input[ii++], y05 = prev[pi++] ^ input[ii++];
|
||||
let y06 = prev[pi++] ^ input[ii++], y07 = prev[pi++] ^ input[ii++];
|
||||
let y08 = prev[pi++] ^ input[ii++], y09 = prev[pi++] ^ input[ii++];
|
||||
let y10 = prev[pi++] ^ input[ii++], y11 = prev[pi++] ^ input[ii++];
|
||||
let y12 = prev[pi++] ^ input[ii++], y13 = prev[pi++] ^ input[ii++];
|
||||
let y14 = prev[pi++] ^ input[ii++], y15 = prev[pi++] ^ input[ii++];
|
||||
// Save state to temporary variables (salsa)
|
||||
let x00 = y00, x01 = y01, x02 = y02, x03 = y03,
|
||||
x04 = y04, x05 = y05, x06 = y06, x07 = y07,
|
||||
x08 = y08, x09 = y09, x10 = y10, x11 = y11,
|
||||
x12 = y12, x13 = y13, x14 = y14, x15 = y15;
|
||||
// Main loop (salsa)
|
||||
for (let i = 0; i < 8; i += 2) {
|
||||
x04 ^= rotl(x00 + x12 | 0, 7); x08 ^= rotl(x04 + x00 | 0, 9);
|
||||
x12 ^= rotl(x08 + x04 | 0, 13); x00 ^= rotl(x12 + x08 | 0, 18);
|
||||
x09 ^= rotl(x05 + x01 | 0, 7); x13 ^= rotl(x09 + x05 | 0, 9);
|
||||
x01 ^= rotl(x13 + x09 | 0, 13); x05 ^= rotl(x01 + x13 | 0, 18);
|
||||
x14 ^= rotl(x10 + x06 | 0, 7); x02 ^= rotl(x14 + x10 | 0, 9);
|
||||
x06 ^= rotl(x02 + x14 | 0, 13); x10 ^= rotl(x06 + x02 | 0, 18);
|
||||
x03 ^= rotl(x15 + x11 | 0, 7); x07 ^= rotl(x03 + x15 | 0, 9);
|
||||
x11 ^= rotl(x07 + x03 | 0, 13); x15 ^= rotl(x11 + x07 | 0, 18);
|
||||
x01 ^= rotl(x00 + x03 | 0, 7); x02 ^= rotl(x01 + x00 | 0, 9);
|
||||
x03 ^= rotl(x02 + x01 | 0, 13); x00 ^= rotl(x03 + x02 | 0, 18);
|
||||
x06 ^= rotl(x05 + x04 | 0, 7); x07 ^= rotl(x06 + x05 | 0, 9);
|
||||
x04 ^= rotl(x07 + x06 | 0, 13); x05 ^= rotl(x04 + x07 | 0, 18);
|
||||
x11 ^= rotl(x10 + x09 | 0, 7); x08 ^= rotl(x11 + x10 | 0, 9);
|
||||
x09 ^= rotl(x08 + x11 | 0, 13); x10 ^= rotl(x09 + x08 | 0, 18);
|
||||
x12 ^= rotl(x15 + x14 | 0, 7); x13 ^= rotl(x12 + x15 | 0, 9);
|
||||
x14 ^= rotl(x13 + x12 | 0, 13); x15 ^= rotl(x14 + x13 | 0, 18);
|
||||
}
|
||||
// Write output (salsa)
|
||||
out[oi++] = (y00 + x00) | 0; out[oi++] = (y01 + x01) | 0;
|
||||
out[oi++] = (y02 + x02) | 0; out[oi++] = (y03 + x03) | 0;
|
||||
out[oi++] = (y04 + x04) | 0; out[oi++] = (y05 + x05) | 0;
|
||||
out[oi++] = (y06 + x06) | 0; out[oi++] = (y07 + x07) | 0;
|
||||
out[oi++] = (y08 + x08) | 0; out[oi++] = (y09 + x09) | 0;
|
||||
out[oi++] = (y10 + x10) | 0; out[oi++] = (y11 + x11) | 0;
|
||||
out[oi++] = (y12 + x12) | 0; out[oi++] = (y13 + x13) | 0;
|
||||
out[oi++] = (y14 + x14) | 0; out[oi++] = (y15 + x15) | 0;
|
||||
}
|
||||
|
||||
function BlockMix(input: Uint32Array, ii: number, out: Uint32Array, oi: number, r: number) {
|
||||
// The block B is r 128-byte chunks (which is equivalent of 2r 64-byte chunks)
|
||||
let head = oi + 0;
|
||||
let tail = oi + 16 * r;
|
||||
for (let i = 0; i < 16; i++) out[tail + i] = input[ii + (2 * r - 1) * 16 + i]; // X ← B[2r−1]
|
||||
for (let i = 0; i < r; i++, head += 16, ii += 16) {
|
||||
// We write odd & even Yi at same time. Even: 0bXXXXX0 Odd: 0bXXXXX1
|
||||
XorAndSalsa(out, tail, input, ii, out, head); // head[i] = Salsa(blockIn[2*i] ^ tail[i-1])
|
||||
if (i > 0) tail += 16; // First iteration overwrites tmp value in tail
|
||||
XorAndSalsa(out, head, input, (ii += 16), out, tail); // tail[i] = Salsa(blockIn[2*i+1] ^ head[i])
|
||||
}
|
||||
}
|
||||
|
||||
// RFC 7914
|
||||
export type ScryptOpts = {
|
||||
N: number; // costFactor CPU/memory cost parameter - Must be a power of 2 (e.g. 1024)
|
||||
r: number; // blocksize parameter, which fine-tunes sequential memory read size and performance. (8 is commonly used)
|
||||
p: number; // Parallelization parameter. (1 .. 232-1 * hLen/MFlen)
|
||||
dkLen?: number; // Desired key length in bytes (Intended output length in octets of the derived key
|
||||
asyncTick?: number; // Maximum time in ms for which async function can block execution
|
||||
maxmem?: number;
|
||||
onProgress?: (progress: number) => void;
|
||||
};
|
||||
|
||||
// Common prologue and epilogue for sync/async functions
|
||||
function scryptInit(password: Input, salt: Input, _opts?: ScryptOpts) {
|
||||
// Maxmem - 1GB+1KB by default
|
||||
const opts = checkOpts(
|
||||
{
|
||||
dkLen: 32,
|
||||
asyncTick: 10,
|
||||
maxmem: 1024 ** 3 + 1024,
|
||||
},
|
||||
_opts
|
||||
);
|
||||
const { N, r, p, dkLen, asyncTick, maxmem, onProgress } = opts;
|
||||
assertNumber(N);
|
||||
assertNumber(r);
|
||||
assertNumber(p);
|
||||
assertNumber(dkLen);
|
||||
assertNumber(asyncTick);
|
||||
assertNumber(maxmem);
|
||||
if (onProgress !== undefined && typeof onProgress !== 'function')
|
||||
throw new Error('progressCb should be function');
|
||||
const blockSize = 128 * r;
|
||||
const blockSize32 = blockSize / 4;
|
||||
if (N <= 1 || (N & (N - 1)) !== 0 || N >= 2 ** (blockSize / 8) || N > 2 ** 32) {
|
||||
// NOTE: we limit N to be less than 2**32 because of 32 bit variant of Integrify function
|
||||
// There is no JS engines that allows alocate more than 4GB per single Uint8Array for now, but can change in future.
|
||||
throw new Error(
|
||||
'Scrypt: N must be larger than 1, a power of 2, less than 2^(128 * r / 8) and less than 2^32'
|
||||
);
|
||||
}
|
||||
if (p < 0 || p > ((2 ** 32 - 1) * 32) / blockSize) {
|
||||
throw new Error(
|
||||
'Scrypt: p must be a positive integer less than or equal to ((2^32 - 1) * 32) / (128 * r)'
|
||||
);
|
||||
}
|
||||
if (dkLen < 0 || dkLen > (2 ** 32 - 1) * 32) {
|
||||
throw new Error(
|
||||
'Scrypt: dkLen should be positive integer less than or equal to (2^32 - 1) * 32'
|
||||
);
|
||||
}
|
||||
const memUsed = blockSize * (N + p);
|
||||
if (memUsed > maxmem) {
|
||||
throw new Error(
|
||||
`Scrypt: parameters too large, ${memUsed} (128 * r * (N + p)) > ${maxmem} (maxmem)`
|
||||
);
|
||||
}
|
||||
// [B0...Bp−1] ← PBKDF2HMAC-SHA256(Passphrase, Salt, 1, blockSize*ParallelizationFactor)
|
||||
// Since it has only one iteration there is no reason to use async variant
|
||||
const B = pbkdf2(sha256, password, salt, { c: 1, dkLen: blockSize * p });
|
||||
const B32 = u32(B);
|
||||
// Re-used between parallel iterations. Array(iterations) of B
|
||||
const V = u32(new Uint8Array(blockSize * N));
|
||||
const tmp = u32(new Uint8Array(blockSize));
|
||||
let blockMixCb = () => {};
|
||||
if (onProgress) {
|
||||
const totalBlockMix = 2 * N * p;
|
||||
// Invoke callback if progress changes from 10.01 to 10.02
|
||||
// Allows to draw smooth progress bar on up to 8K screen
|
||||
const callbackPer = Math.max(Math.floor(totalBlockMix / 10000), 1);
|
||||
let blockMixCnt = 0;
|
||||
blockMixCb = () => {
|
||||
blockMixCnt++;
|
||||
if (onProgress && (!(blockMixCnt % callbackPer) || blockMixCnt === totalBlockMix))
|
||||
onProgress(blockMixCnt / totalBlockMix);
|
||||
};
|
||||
}
|
||||
return { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick };
|
||||
}
|
||||
|
||||
function scryptOutput(
|
||||
password: Input,
|
||||
dkLen: number,
|
||||
B: Uint8Array,
|
||||
V: Uint32Array,
|
||||
tmp: Uint32Array
|
||||
) {
|
||||
const res = pbkdf2(sha256, password, B, { c: 1, dkLen });
|
||||
B.fill(0);
|
||||
V.fill(0);
|
||||
tmp.fill(0);
|
||||
return res;
|
||||
}
|
||||
|
||||
export function scrypt(password: Input, salt: Input, _opts: ScryptOpts) {
|
||||
const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb } = scryptInit(
|
||||
password,
|
||||
salt,
|
||||
_opts
|
||||
);
|
||||
for (let pi = 0; pi < p; pi++) {
|
||||
const Pi = blockSize32 * pi;
|
||||
for (let i = 0; i < blockSize32; i++) V[i] = B32[Pi + i]; // V[0] = B[i]
|
||||
for (let i = 0, pos = 0; i < N - 1; i++) {
|
||||
BlockMix(V, pos, V, (pos += blockSize32), r); // V[i] = BlockMix(V[i-1]);
|
||||
blockMixCb();
|
||||
}
|
||||
BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); // Process last element
|
||||
blockMixCb();
|
||||
for (let i = 0; i < N; i++) {
|
||||
// First u32 of the last 64-byte block (u32 is LE)
|
||||
const j = B32[Pi + blockSize32 - 16] % N; // j = Integrify(X) % iterations
|
||||
for (let k = 0; k < blockSize32; k++) tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; // tmp = B ^ V[j]
|
||||
BlockMix(tmp, 0, B32, Pi, r); // B = BlockMix(B ^ V[j])
|
||||
blockMixCb();
|
||||
}
|
||||
}
|
||||
return scryptOutput(password, dkLen, B, V, tmp);
|
||||
}
|
||||
|
||||
export async function scryptAsync(password: Uint8Array, salt: Uint8Array, _opts: ScryptOpts) {
|
||||
const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick } = scryptInit(
|
||||
password,
|
||||
salt,
|
||||
_opts
|
||||
);
|
||||
for (let pi = 0; pi < p; pi++) {
|
||||
const Pi = blockSize32 * pi;
|
||||
for (let i = 0; i < blockSize32; i++) V[i] = B32[Pi + i]; // V[0] = B[i]
|
||||
let pos = 0;
|
||||
await asyncLoop(N - 1, asyncTick, (i) => {
|
||||
BlockMix(V, pos, V, (pos += blockSize32), r); // V[i] = BlockMix(V[i-1]);
|
||||
blockMixCb();
|
||||
});
|
||||
BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); // Process last element
|
||||
blockMixCb();
|
||||
await asyncLoop(N, asyncTick, (i) => {
|
||||
// First u32 of the last 64-byte block (u32 is LE)
|
||||
const j = B32[Pi + blockSize32 - 16] % N; // j = Integrify(X) % iterations
|
||||
for (let k = 0; k < blockSize32; k++) tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; // tmp = B ^ V[j]
|
||||
BlockMix(tmp, 0, B32, Pi, r); // B = BlockMix(B ^ V[j])
|
||||
blockMixCb();
|
||||
});
|
||||
}
|
||||
return scryptOutput(password, dkLen, B, V, tmp);
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
import { SHA2 } from './_sha2';
|
||||
import { rotr, wrapConstructor } from './utils';
|
||||
|
||||
// Choice: a ? b : c
|
||||
const Chi = (a: number, b: number, c: number) => (a & b) ^ (~a & c);
|
||||
// Majority function, true if any two inpust is true
|
||||
const Maj = (a: number, b: number, c: number) => (a & b) ^ (a & c) ^ (b & c);
|
||||
|
||||
// Round constants:
|
||||
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
|
||||
// prettier-ignore
|
||||
const SHA256_K = new Uint32Array([
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
]);
|
||||
|
||||
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
|
||||
// prettier-ignore
|
||||
const IV = new Uint32Array([
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
]);
|
||||
|
||||
// Temporary buffer, not used to store anything between runs
|
||||
// Named this way because it matches specification.
|
||||
const SHA256_W = new Uint32Array(64);
|
||||
class SHA256 extends SHA2<SHA256> {
|
||||
// We cannot use array here since array allows indexing by variable
|
||||
// which means optimizer/compiler cannot use registers.
|
||||
private A = IV[0] | 0;
|
||||
private B = IV[1] | 0;
|
||||
private C = IV[2] | 0;
|
||||
private D = IV[3] | 0;
|
||||
private E = IV[4] | 0;
|
||||
private F = IV[5] | 0;
|
||||
private G = IV[6] | 0;
|
||||
private H = IV[7] | 0;
|
||||
|
||||
constructor() {
|
||||
super(64, 32, 8, false);
|
||||
}
|
||||
protected get(): [number, number, number, number, number, number, number, number] {
|
||||
const { A, B, C, D, E, F, G, H } = this;
|
||||
return [A, B, C, D, E, F, G, H];
|
||||
}
|
||||
// prettier-ignore
|
||||
protected set(
|
||||
A: number, B: number, C: number, D: number, E: number, F: number, G: number, H: number
|
||||
) {
|
||||
this.A = A | 0;
|
||||
this.B = B | 0;
|
||||
this.C = C | 0;
|
||||
this.D = D | 0;
|
||||
this.E = E | 0;
|
||||
this.F = F | 0;
|
||||
this.G = G | 0;
|
||||
this.H = H | 0;
|
||||
}
|
||||
protected process(view: DataView, offset: number): void {
|
||||
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
|
||||
for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);
|
||||
for (let i = 16; i < 64; i++) {
|
||||
const W15 = SHA256_W[i - 15];
|
||||
const W2 = SHA256_W[i - 2];
|
||||
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
|
||||
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
|
||||
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
|
||||
}
|
||||
// Compression function main loop, 64 rounds
|
||||
let { A, B, C, D, E, F, G, H } = this;
|
||||
for (let i = 0; i < 64; i++) {
|
||||
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
|
||||
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
|
||||
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
|
||||
const T2 = (sigma0 + Maj(A, B, C)) | 0;
|
||||
H = G;
|
||||
G = F;
|
||||
F = E;
|
||||
E = (D + T1) | 0;
|
||||
D = C;
|
||||
C = B;
|
||||
B = A;
|
||||
A = (T1 + T2) | 0;
|
||||
}
|
||||
// Add the compressed chunk to the current hash value
|
||||
A = (A + this.A) | 0;
|
||||
B = (B + this.B) | 0;
|
||||
C = (C + this.C) | 0;
|
||||
D = (D + this.D) | 0;
|
||||
E = (E + this.E) | 0;
|
||||
F = (F + this.F) | 0;
|
||||
G = (G + this.G) | 0;
|
||||
H = (H + this.H) | 0;
|
||||
this.set(A, B, C, D, E, F, G, H);
|
||||
}
|
||||
protected roundClean() {
|
||||
SHA256_W.fill(0);
|
||||
}
|
||||
destroy() {
|
||||
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
this.buffer.fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
export const sha256 = wrapConstructor(() => new SHA256());
|
||||
@@ -1,399 +0,0 @@
|
||||
import { Input, toBytes, wrapConstructorWithOpts, assertNumber, u32, Hash, HashXOF } from './utils';
|
||||
import { Keccak, ShakeOpts } from './sha3';
|
||||
// cSHAKE && KMAC (NIST SP800-185)
|
||||
function leftEncode(n: number): Uint8Array {
|
||||
const res = [n & 0xff];
|
||||
n >>= 8;
|
||||
for (; n > 0; n >>= 8) res.unshift(n & 0xff);
|
||||
res.unshift(res.length);
|
||||
return new Uint8Array(res);
|
||||
}
|
||||
|
||||
function rightEncode(n: number): Uint8Array {
|
||||
const res = [n & 0xff];
|
||||
n >>= 8;
|
||||
for (; n > 0; n >>= 8) res.unshift(n & 0xff);
|
||||
res.push(res.length);
|
||||
return new Uint8Array(res);
|
||||
}
|
||||
|
||||
const toBytesOptional = (buf?: Input) => (buf !== undefined ? toBytes(buf) : new Uint8Array([]));
|
||||
// NOTE: second modulo is necessary since we don't need to add padding if current element takes whole block
|
||||
const getPadding = (len: number, block: number) => new Uint8Array((block - (len % block)) % block);
|
||||
export type cShakeOpts = ShakeOpts & { personalization?: Input; NISTfn?: Input };
|
||||
|
||||
// Personalization
|
||||
function cshakePers(hash: Keccak, opts: cShakeOpts = {}): Keccak {
|
||||
if (!opts || (!opts.personalization && !opts.NISTfn)) return hash;
|
||||
// Encode and pad inplace to avoid unneccesary memory copies/slices (so we don't need to zero them later)
|
||||
// bytepad(encode_string(N) || encode_string(S), 168)
|
||||
const blockLenBytes = leftEncode(hash.blockLen);
|
||||
const fn = toBytesOptional(opts.NISTfn);
|
||||
const fnLen = leftEncode(8 * fn.length); // length in bits
|
||||
const pers = toBytesOptional(opts.personalization);
|
||||
const persLen = leftEncode(8 * pers.length); // length in bits
|
||||
if (!fn.length && !pers.length) return hash;
|
||||
hash.suffix = 0x04;
|
||||
hash.update(blockLenBytes).update(fnLen).update(fn).update(persLen).update(pers);
|
||||
let totalLen = blockLenBytes.length + fnLen.length + fn.length + persLen.length + pers.length;
|
||||
hash.update(getPadding(totalLen, hash.blockLen));
|
||||
return hash;
|
||||
}
|
||||
|
||||
const gencShake = (suffix: number, blockLen: number, outputLen: number) =>
|
||||
wrapConstructorWithOpts<Keccak, cShakeOpts>((opts: cShakeOpts = {}) =>
|
||||
cshakePers(
|
||||
new Keccak(blockLen, suffix, opts.dkLen !== undefined ? opts.dkLen : outputLen, true),
|
||||
opts
|
||||
)
|
||||
);
|
||||
|
||||
export const cshake128 = gencShake(0x1f, 168, 128 / 8);
|
||||
export const cshake256 = gencShake(0x1f, 136, 256 / 8);
|
||||
|
||||
class KMAC extends Keccak implements HashXOF<KMAC> {
|
||||
constructor(
|
||||
blockLen: number,
|
||||
outputLen: number,
|
||||
enableXOF: boolean,
|
||||
key: Input,
|
||||
opts: cShakeOpts = {}
|
||||
) {
|
||||
super(blockLen, 0x1f, outputLen, enableXOF);
|
||||
cshakePers(this, { NISTfn: 'KMAC', personalization: opts.personalization });
|
||||
key = toBytes(key);
|
||||
// 1. newX = bytepad(encode_string(K), 168) || X || right_encode(L).
|
||||
const blockLenBytes = leftEncode(this.blockLen);
|
||||
const keyLen = leftEncode(8 * key.length);
|
||||
this.update(blockLenBytes).update(keyLen).update(key);
|
||||
const totalLen = blockLenBytes.length + keyLen.length + key.length;
|
||||
this.update(getPadding(totalLen, this.blockLen));
|
||||
}
|
||||
protected override finish() {
|
||||
if (!this.finished) this.update(rightEncode(this.enableXOF ? 0 : this.outputLen * 8)); // outputLen in bits
|
||||
super.finish();
|
||||
}
|
||||
override _cloneInto(to?: KMAC): KMAC {
|
||||
// Create new instance without calling constructor since key already in state and we don't know it.
|
||||
// Force "to" to be instance of KMAC instead of Sha3.
|
||||
if (!to) {
|
||||
to = Object.create(Object.getPrototypeOf(this), {}) as KMAC;
|
||||
to.state = this.state.slice();
|
||||
to.blockLen = this.blockLen;
|
||||
to.state32 = u32(to.state);
|
||||
}
|
||||
return super._cloneInto(to) as KMAC;
|
||||
}
|
||||
override clone(): KMAC {
|
||||
return this._cloneInto();
|
||||
}
|
||||
}
|
||||
|
||||
function genKmac(blockLen: number, outputLen: number, xof = false) {
|
||||
const kmac = (key: Input, message: Input, opts?: cShakeOpts): Uint8Array =>
|
||||
kmac.create(key, opts).update(message).digest();
|
||||
kmac.create = (key: Input, opts: cShakeOpts = {}) =>
|
||||
new KMAC(blockLen, opts.dkLen !== undefined ? opts.dkLen : outputLen, xof, key, opts);
|
||||
kmac.init = kmac.create;
|
||||
return kmac;
|
||||
}
|
||||
|
||||
export const kmac128 = genKmac(168, 128 / 8);
|
||||
export const kmac256 = genKmac(136, 256 / 8);
|
||||
export const kmac128xof = genKmac(168, 128 / 8, true);
|
||||
export const kmac256xof = genKmac(136, 256 / 8, true);
|
||||
|
||||
// TupleHash
|
||||
// Usage: tuple(['ab', 'cd']) != tuple(['a', 'bcd'])
|
||||
class TupleHash extends Keccak implements HashXOF<TupleHash> {
|
||||
constructor(blockLen: number, outputLen: number, enableXOF: boolean, opts: cShakeOpts = {}) {
|
||||
super(blockLen, 0x1f, outputLen, enableXOF);
|
||||
cshakePers(this, { NISTfn: 'TupleHash', personalization: opts.personalization });
|
||||
// Change update after cshake processed
|
||||
this.update = (data: Input) => {
|
||||
data = toBytes(data);
|
||||
super.update(leftEncode(data.length * 8));
|
||||
super.update(data);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
protected override finish() {
|
||||
if (!this.finished) super.update(rightEncode(this.enableXOF ? 0 : this.outputLen * 8)); // outputLen in bits
|
||||
super.finish();
|
||||
}
|
||||
override _cloneInto(to?: TupleHash): TupleHash {
|
||||
to ||= new TupleHash(this.blockLen, this.outputLen, this.enableXOF);
|
||||
return super._cloneInto(to) as TupleHash;
|
||||
}
|
||||
override clone(): TupleHash {
|
||||
return this._cloneInto();
|
||||
}
|
||||
}
|
||||
|
||||
function genTuple(blockLen: number, outputLen: number, xof = false) {
|
||||
const tuple = (messages: Input[], opts?: cShakeOpts): Uint8Array => {
|
||||
const h = tuple.create(opts);
|
||||
for (const msg of messages) h.update(msg);
|
||||
return h.digest();
|
||||
};
|
||||
tuple.create = (opts: cShakeOpts = {}) =>
|
||||
new TupleHash(blockLen, opts.dkLen !== undefined ? opts.dkLen : outputLen, xof, opts);
|
||||
tuple.init = tuple.create;
|
||||
return tuple;
|
||||
}
|
||||
|
||||
export const tuplehash128 = genTuple(168, 128 / 8);
|
||||
export const tuplehash256 = genTuple(136, 256 / 8);
|
||||
export const tuplehash128xof = genTuple(168, 128 / 8, true);
|
||||
export const tuplehash256xof = genTuple(136, 256 / 8, true);
|
||||
|
||||
// ParallelHash (same as K12/M14, but without speedup for inputs less 8kb, reduced number of rounds and more simple)
|
||||
type ParallelOpts = cShakeOpts & { blockLen?: number };
|
||||
|
||||
class ParallelHash extends Keccak implements HashXOF<ParallelHash> {
|
||||
private leafHash?: Hash<Keccak>;
|
||||
private chunkPos = 0; // Position of current block in chunk
|
||||
private chunksDone = 0; // How many chunks we already have
|
||||
private chunkLen: number;
|
||||
constructor(
|
||||
blockLen: number,
|
||||
outputLen: number,
|
||||
protected leafCons: () => Hash<Keccak>,
|
||||
enableXOF: boolean,
|
||||
opts: ParallelOpts = {}
|
||||
) {
|
||||
super(blockLen, 0x1f, outputLen, enableXOF);
|
||||
cshakePers(this, { NISTfn: 'ParallelHash', personalization: opts.personalization });
|
||||
let { blockLen: B } = opts;
|
||||
B ||= 8;
|
||||
assertNumber(B);
|
||||
this.chunkLen = B;
|
||||
super.update(leftEncode(B));
|
||||
// Change update after cshake processed
|
||||
this.update = (data: Input) => {
|
||||
data = toBytes(data);
|
||||
const { chunkLen, leafCons } = this;
|
||||
for (let pos = 0, len = data.length; pos < len; ) {
|
||||
if (this.chunkPos == chunkLen || !this.leafHash) {
|
||||
if (this.leafHash) {
|
||||
super.update(this.leafHash.digest());
|
||||
this.chunksDone++;
|
||||
}
|
||||
this.leafHash = leafCons();
|
||||
this.chunkPos = 0;
|
||||
}
|
||||
const take = Math.min(chunkLen - this.chunkPos, len - pos);
|
||||
this.leafHash.update(data.subarray(pos, pos + take));
|
||||
this.chunkPos += take;
|
||||
pos += take;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
protected override finish() {
|
||||
if (this.finished) return;
|
||||
if (this.leafHash) {
|
||||
super.update(this.leafHash.digest());
|
||||
this.chunksDone++;
|
||||
}
|
||||
super.update(rightEncode(this.chunksDone));
|
||||
super.update(rightEncode(this.enableXOF ? 0 : this.outputLen * 8)); // outputLen in bits
|
||||
super.finish();
|
||||
}
|
||||
override _cloneInto(to?: ParallelHash): ParallelHash {
|
||||
to ||= new ParallelHash(this.blockLen, this.outputLen, this.leafCons, this.enableXOF);
|
||||
if (this.leafHash) to.leafHash = this.leafHash._cloneInto(to.leafHash as Keccak);
|
||||
to.chunkPos = this.chunkPos;
|
||||
to.chunkLen = this.chunkLen;
|
||||
to.chunksDone = this.chunksDone;
|
||||
return super._cloneInto(to) as ParallelHash;
|
||||
}
|
||||
override destroy() {
|
||||
super.destroy.call(this);
|
||||
if (this.leafHash) this.leafHash.destroy();
|
||||
}
|
||||
override clone(): ParallelHash {
|
||||
return this._cloneInto();
|
||||
}
|
||||
}
|
||||
|
||||
function genParallel(
|
||||
blockLen: number,
|
||||
outputLen: number,
|
||||
leaf: ReturnType<typeof gencShake>,
|
||||
xof = false
|
||||
) {
|
||||
const parallel = (message: Input, opts?: ParallelOpts): Uint8Array =>
|
||||
parallel.create(opts).update(message).digest();
|
||||
parallel.create = (opts: ParallelOpts = {}) =>
|
||||
new ParallelHash(
|
||||
blockLen,
|
||||
opts.dkLen !== undefined ? opts.dkLen : outputLen,
|
||||
() => leaf.init({ dkLen: 2 * outputLen }),
|
||||
xof,
|
||||
opts
|
||||
);
|
||||
parallel.init = parallel.create;
|
||||
return parallel;
|
||||
}
|
||||
|
||||
export const parallelhash128 = genParallel(168, 128 / 8, cshake128);
|
||||
export const parallelhash256 = genParallel(136, 256 / 8, cshake256);
|
||||
export const parallelhash128xof = genParallel(168, 128 / 8, cshake128, true);
|
||||
export const parallelhash256xof = genParallel(136, 256 / 8, cshake256, true);
|
||||
|
||||
// Kangaroo
|
||||
// Same as NIST rightEncode, but returns [0] for zero string
|
||||
function rightEncodeK12(n: number): Uint8Array {
|
||||
const res = [];
|
||||
for (; n > 0; n >>= 8) res.unshift(n & 0xff);
|
||||
res.push(res.length);
|
||||
return new Uint8Array(res);
|
||||
}
|
||||
|
||||
export type KangarooOpts = { dkLen?: number; personalization?: Input };
|
||||
const EMPTY = new Uint8Array([]);
|
||||
|
||||
class KangarooTwelve extends Keccak implements HashXOF<KangarooTwelve> {
|
||||
readonly chunkLen = 8192;
|
||||
private leafHash?: Keccak;
|
||||
private personalization: Uint8Array;
|
||||
private chunkPos = 0; // Position of current block in chunk
|
||||
private chunksDone = 0; // How many chunks we already have
|
||||
constructor(
|
||||
blockLen: number,
|
||||
protected leafLen: number,
|
||||
outputLen: number,
|
||||
rounds: number,
|
||||
opts: KangarooOpts
|
||||
) {
|
||||
super(blockLen, 0x07, outputLen, true, rounds);
|
||||
const { personalization } = opts;
|
||||
this.personalization = toBytesOptional(personalization);
|
||||
}
|
||||
override update(data: Input) {
|
||||
data = toBytes(data);
|
||||
const { chunkLen, blockLen, leafLen, rounds } = this;
|
||||
for (let pos = 0, len = data.length; pos < len; ) {
|
||||
if (this.chunkPos == chunkLen) {
|
||||
if (this.leafHash) super.update(this.leafHash.digest());
|
||||
else {
|
||||
this.suffix = 0x06; // Its safe to change suffix here since its used only in digest()
|
||||
super.update(new Uint8Array([3, 0, 0, 0, 0, 0, 0, 0]));
|
||||
}
|
||||
this.leafHash = new Keccak(blockLen, 0x0b, leafLen, false, rounds);
|
||||
this.chunksDone++;
|
||||
this.chunkPos = 0;
|
||||
}
|
||||
const take = Math.min(chunkLen - this.chunkPos, len - pos);
|
||||
const chunk = data.subarray(pos, pos + take);
|
||||
if (this.leafHash) this.leafHash.update(chunk);
|
||||
else super.update(chunk);
|
||||
this.chunkPos += take;
|
||||
pos += take;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
protected override finish() {
|
||||
if (this.finished) return;
|
||||
const { personalization } = this;
|
||||
this.update(personalization).update(rightEncodeK12(personalization.length));
|
||||
// Leaf hash
|
||||
if (this.leafHash) {
|
||||
super.update(this.leafHash.digest());
|
||||
super.update(rightEncodeK12(this.chunksDone));
|
||||
super.update(new Uint8Array([0xff, 0xff]));
|
||||
}
|
||||
super.finish.call(this);
|
||||
}
|
||||
override destroy() {
|
||||
super.destroy.call(this);
|
||||
if (this.leafHash) this.leafHash.destroy();
|
||||
// We cannot zero personalization buffer since it is user provided and we don't want to mutate user input
|
||||
this.personalization = EMPTY;
|
||||
}
|
||||
override _cloneInto(to?: KangarooTwelve): KangarooTwelve {
|
||||
const { blockLen, leafLen, leafHash, outputLen, rounds } = this;
|
||||
to ||= new KangarooTwelve(blockLen, leafLen, outputLen, rounds, {});
|
||||
super._cloneInto(to);
|
||||
if (leafHash) to.leafHash = leafHash._cloneInto(to.leafHash);
|
||||
to.personalization.set(this.personalization);
|
||||
to.leafLen = this.leafLen;
|
||||
to.chunkPos = this.chunkPos;
|
||||
to.chunksDone = this.chunksDone;
|
||||
return to;
|
||||
}
|
||||
override clone(): KangarooTwelve {
|
||||
return this._cloneInto();
|
||||
}
|
||||
}
|
||||
// Default to 32 bytes, so it can be used without opts
|
||||
export const k12 = wrapConstructorWithOpts<KangarooTwelve, KangarooOpts>(
|
||||
(opts: KangarooOpts = {}) =>
|
||||
new KangarooTwelve(168, 32, opts.dkLen !== undefined ? opts.dkLen : 32, 12, opts)
|
||||
);
|
||||
// MarsupilamiFourteen
|
||||
export const m14 = wrapConstructorWithOpts<KangarooTwelve, KangarooOpts>(
|
||||
(opts: KangarooOpts = {}) =>
|
||||
new KangarooTwelve(136, 64, opts.dkLen !== undefined ? opts.dkLen : 64, 14, opts)
|
||||
);
|
||||
|
||||
// https://keccak.team/files/CSF-0.1.pdf
|
||||
// + https://github.com/XKCP/XKCP/tree/master/lib/high/Keccak/PRG
|
||||
class KeccakPRG extends Keccak {
|
||||
protected rate: number;
|
||||
constructor(capacity: number) {
|
||||
assertNumber(capacity);
|
||||
// Rho should be full bytes
|
||||
if (capacity < 0 || capacity > 1600 - 10 || (1600 - capacity - 2) % 8)
|
||||
throw new Error('KeccakPRG: Invalid capacity');
|
||||
// blockLen = rho in bytes
|
||||
super((1600 - capacity - 2) / 8, 0, 0, true);
|
||||
this.rate = 1600 - capacity;
|
||||
this.posOut = Math.floor((this.rate + 7) / 8);
|
||||
}
|
||||
override keccak() {
|
||||
// Duplex padding
|
||||
this.state[this.pos] ^= 0x01;
|
||||
this.state[this.blockLen] ^= 0x02; // Rho is full bytes
|
||||
super.keccak();
|
||||
this.pos = 0;
|
||||
this.posOut = 0;
|
||||
}
|
||||
override update(data: Input) {
|
||||
super.update(data);
|
||||
this.posOut = this.blockLen;
|
||||
return this;
|
||||
}
|
||||
feed(data: Input) {
|
||||
return this.update(data);
|
||||
}
|
||||
protected override finish() {}
|
||||
override digestInto(out: Uint8Array): Uint8Array {
|
||||
throw new Error('KeccakPRG: digest is not allowed, please use .fetch instead.');
|
||||
}
|
||||
fetch(bytes: number): Uint8Array {
|
||||
return this.xof(bytes);
|
||||
}
|
||||
// Ensure irreversibility (even if state leaked previous outputs cannot be computed)
|
||||
forget() {
|
||||
if (this.rate < 1600 / 2 + 1) throw new Error('KeccakPRG: rate too low to use forget');
|
||||
this.keccak();
|
||||
for (let i = 0; i < this.blockLen; i++) this.state[i] = 0;
|
||||
this.pos = this.blockLen;
|
||||
this.keccak();
|
||||
this.posOut = this.blockLen;
|
||||
}
|
||||
override _cloneInto(to?: KeccakPRG): KeccakPRG {
|
||||
const { rate } = this;
|
||||
to ||= new KeccakPRG(1600 - rate);
|
||||
super._cloneInto(to);
|
||||
to.rate = rate;
|
||||
return to;
|
||||
}
|
||||
override clone(): KeccakPRG {
|
||||
return this._cloneInto();
|
||||
}
|
||||
}
|
||||
|
||||
export const keccakprg = (capacity = 254) => new KeccakPRG(capacity);
|
||||
@@ -1,214 +0,0 @@
|
||||
import * as u64 from './_u64';
|
||||
import {
|
||||
Hash,
|
||||
u32,
|
||||
Input,
|
||||
toBytes,
|
||||
wrapConstructor,
|
||||
wrapConstructorWithOpts,
|
||||
assertNumber,
|
||||
HashXOF,
|
||||
} from './utils';
|
||||
|
||||
// Various per round constants calculations
|
||||
const [SHA3_PI, SHA3_ROTL, _SHA3_IOTA]: [number[], number[], bigint[]] = [[], [], []];
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
const _2n = BigInt(2);
|
||||
const _7n = BigInt(7);
|
||||
const _256n = BigInt(256);
|
||||
const _0x71n = BigInt(0x71);
|
||||
for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
|
||||
// Pi
|
||||
[x, y] = [y, (2 * x + 3 * y) % 5];
|
||||
SHA3_PI.push(2 * (5 * y + x));
|
||||
// Rotational
|
||||
SHA3_ROTL.push((((round + 1) * (round + 2)) / 2) % 64);
|
||||
// Iota
|
||||
let t = _0n;
|
||||
for (let j = 0; j < 7; j++) {
|
||||
R = ((R << _1n) ^ ((R >> _7n) * _0x71n)) % _256n;
|
||||
if (R & _2n) t ^= _1n << ((_1n << BigInt(j)) - _1n);
|
||||
}
|
||||
_SHA3_IOTA.push(t);
|
||||
}
|
||||
const [SHA3_IOTA_H, SHA3_IOTA_L] = u64.split(_SHA3_IOTA, true);
|
||||
|
||||
// Left rotation (without 0, 32, 64)
|
||||
const rotlH = (h: number, l: number, s: number) =>
|
||||
s > 32 ? u64.rotlBH(h, l, s) : u64.rotlSH(h, l, s);
|
||||
const rotlL = (h: number, l: number, s: number) =>
|
||||
s > 32 ? u64.rotlBL(h, l, s) : u64.rotlSL(h, l, s);
|
||||
|
||||
// Same as keccakf1600, but allows to skip some rounds
|
||||
export function keccakP(s: Uint32Array, rounds: number = 24) {
|
||||
const B = new Uint32Array(5 * 2);
|
||||
// NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js)
|
||||
for (let round = 24 - rounds; round < 24; round++) {
|
||||
// Theta θ
|
||||
for (let x = 0; x < 10; x++) B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
|
||||
for (let x = 0; x < 10; x += 2) {
|
||||
const idx1 = (x + 8) % 10;
|
||||
const idx0 = (x + 2) % 10;
|
||||
const B0 = B[idx0];
|
||||
const B1 = B[idx0 + 1];
|
||||
const Th = rotlH(B0, B1, 1) ^ B[idx1];
|
||||
const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
|
||||
for (let y = 0; y < 50; y += 10) {
|
||||
s[x + y] ^= Th;
|
||||
s[x + y + 1] ^= Tl;
|
||||
}
|
||||
}
|
||||
// Rho (ρ) and Pi (π)
|
||||
let curH = s[2];
|
||||
let curL = s[3];
|
||||
for (let t = 0; t < 24; t++) {
|
||||
const shift = SHA3_ROTL[t];
|
||||
const Th = rotlH(curH, curL, shift);
|
||||
const Tl = rotlL(curH, curL, shift);
|
||||
const PI = SHA3_PI[t];
|
||||
curH = s[PI];
|
||||
curL = s[PI + 1];
|
||||
s[PI] = Th;
|
||||
s[PI + 1] = Tl;
|
||||
}
|
||||
// Chi (χ)
|
||||
for (let y = 0; y < 50; y += 10) {
|
||||
for (let x = 0; x < 10; x++) B[x] = s[y + x];
|
||||
for (let x = 0; x < 10; x++) s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
|
||||
}
|
||||
// Iota (ι)
|
||||
s[0] ^= SHA3_IOTA_H[round];
|
||||
s[1] ^= SHA3_IOTA_L[round];
|
||||
}
|
||||
B.fill(0);
|
||||
}
|
||||
|
||||
export class Keccak extends Hash<Keccak> implements HashXOF<Keccak> {
|
||||
protected state: Uint8Array;
|
||||
protected pos = 0;
|
||||
protected posOut = 0;
|
||||
protected finished = false;
|
||||
protected state32: Uint32Array;
|
||||
protected destroyed = false;
|
||||
// NOTE: we accept arguments in bytes instead of bits here.
|
||||
constructor(
|
||||
public blockLen: number,
|
||||
public suffix: number,
|
||||
public outputLen: number,
|
||||
protected enableXOF = false,
|
||||
protected rounds: number = 24
|
||||
) {
|
||||
super();
|
||||
// Can be passed from user as dkLen
|
||||
assertNumber(outputLen);
|
||||
// 1600 = 5x5 matrix of 64bit. 1600 bits === 200 bytes
|
||||
if (0 >= this.blockLen || this.blockLen >= 200)
|
||||
throw new Error('Sha3 supports only keccak-f1600 function');
|
||||
this.state = new Uint8Array(200);
|
||||
this.state32 = u32(this.state);
|
||||
}
|
||||
protected keccak() {
|
||||
keccakP(this.state32, this.rounds);
|
||||
this.posOut = 0;
|
||||
this.pos = 0;
|
||||
}
|
||||
update(data: Input) {
|
||||
if (this.destroyed) throw new Error('instance is destroyed');
|
||||
if (this.finished) throw new Error('digest() was already called');
|
||||
const { blockLen, state } = this;
|
||||
data = toBytes(data);
|
||||
const len = data.length;
|
||||
for (let pos = 0; pos < len; ) {
|
||||
const take = Math.min(blockLen - this.pos, len - pos);
|
||||
for (let i = 0; i < take; i++) state[this.pos++] ^= data[pos++];
|
||||
if (this.pos === blockLen) this.keccak();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
protected finish() {
|
||||
if (this.finished) return;
|
||||
this.finished = true;
|
||||
const { state, suffix, pos, blockLen } = this;
|
||||
// Do the padding
|
||||
state[pos] ^= suffix;
|
||||
if ((suffix & 0x80) !== 0 && pos === blockLen - 1) this.keccak();
|
||||
state[blockLen - 1] ^= 0x80;
|
||||
this.keccak();
|
||||
}
|
||||
protected writeInto(out: Uint8Array): Uint8Array {
|
||||
if (this.destroyed) throw new Error('instance is destroyed');
|
||||
if (!(out instanceof Uint8Array)) throw new Error('Keccak: invalid output buffer');
|
||||
this.finish();
|
||||
for (let pos = 0, len = out.length; pos < len; ) {
|
||||
if (this.posOut >= this.blockLen) this.keccak();
|
||||
const take = Math.min(this.blockLen - this.posOut, len - pos);
|
||||
out.set(this.state.subarray(this.posOut, this.posOut + take), pos);
|
||||
this.posOut += take;
|
||||
pos += take;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
xofInto(out: Uint8Array): Uint8Array {
|
||||
// Sha3/Keccak usage with XOF is probably mistake, only SHAKE instances can do XOF
|
||||
if (!this.enableXOF) throw new Error('XOF is not possible for this instance');
|
||||
return this.writeInto(out);
|
||||
}
|
||||
xof(bytes: number): Uint8Array {
|
||||
assertNumber(bytes);
|
||||
return this.xofInto(new Uint8Array(bytes));
|
||||
}
|
||||
digestInto(out: Uint8Array) {
|
||||
if (out.length < this.outputLen) throw new Error('Keccak: invalid output buffer');
|
||||
if (this.finished) throw new Error('digest() was already called');
|
||||
this.finish();
|
||||
this.writeInto(out);
|
||||
this.destroy();
|
||||
return out;
|
||||
}
|
||||
digest() {
|
||||
return this.digestInto(new Uint8Array(this.outputLen));
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.state.fill(0);
|
||||
}
|
||||
_cloneInto(to?: Keccak): Keccak {
|
||||
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
|
||||
to ||= new Keccak(blockLen, suffix, outputLen, enableXOF, rounds);
|
||||
to.state32.set(this.state32);
|
||||
to.pos = this.pos;
|
||||
to.posOut = this.posOut;
|
||||
to.finished = this.finished;
|
||||
to.rounds = rounds;
|
||||
// Suffix can change in cSHAKE
|
||||
to.suffix = suffix;
|
||||
to.outputLen = outputLen;
|
||||
to.enableXOF = enableXOF;
|
||||
to.destroyed = this.destroyed;
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
const gen = (suffix: number, blockLen: number, outputLen: number) =>
|
||||
wrapConstructor(() => new Keccak(blockLen, suffix, outputLen));
|
||||
|
||||
export const sha3_224 = gen(0x06, 144, 224 / 8);
|
||||
export const sha3_256 = gen(0x06, 136, 256 / 8);
|
||||
export const sha3_384 = gen(0x06, 104, 384 / 8);
|
||||
export const sha3_512 = gen(0x06, 72, 512 / 8);
|
||||
export const keccak_224 = gen(0x01, 144, 224 / 8);
|
||||
export const keccak_256 = gen(0x01, 136, 256 / 8);
|
||||
export const keccak_384 = gen(0x01, 104, 384 / 8);
|
||||
export const keccak_512 = gen(0x01, 72, 512 / 8);
|
||||
|
||||
export type ShakeOpts = { dkLen?: number };
|
||||
|
||||
const genShake = (suffix: number, blockLen: number, outputLen: number) =>
|
||||
wrapConstructorWithOpts<Keccak, ShakeOpts>(
|
||||
(opts: ShakeOpts = {}) =>
|
||||
new Keccak(blockLen, suffix, opts.dkLen !== undefined ? opts.dkLen : outputLen, true)
|
||||
);
|
||||
|
||||
export const shake128 = genShake(0x1f, 168, 128 / 8);
|
||||
export const shake256 = genShake(0x1f, 136, 256 / 8);
|
||||
@@ -1,221 +0,0 @@
|
||||
import { SHA2 } from './_sha2';
|
||||
import * as u64 from './_u64';
|
||||
import { wrapConstructor } from './utils';
|
||||
|
||||
// Round contants (first 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409):
|
||||
// prettier-ignore
|
||||
const [SHA512_Kh, SHA512_Kl] = u64.split([
|
||||
'0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',
|
||||
'0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',
|
||||
'0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',
|
||||
'0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',
|
||||
'0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',
|
||||
'0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',
|
||||
'0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',
|
||||
'0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',
|
||||
'0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',
|
||||
'0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',
|
||||
'0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',
|
||||
'0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',
|
||||
'0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',
|
||||
'0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',
|
||||
'0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',
|
||||
'0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',
|
||||
'0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',
|
||||
'0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',
|
||||
'0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',
|
||||
'0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'
|
||||
].map(n => BigInt(n)));
|
||||
|
||||
// Temporary buffer, not used to store anything between runs
|
||||
const SHA512_W_H = new Uint32Array(80);
|
||||
const SHA512_W_L = new Uint32Array(80);
|
||||
|
||||
export class SHA512 extends SHA2<SHA512> {
|
||||
// We cannot use array here since array allows indexing by variable which means optimizer/compiler cannot use registers.
|
||||
// Also looks cleaner and easier to verify with spec.
|
||||
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
|
||||
// h -- high 32 bits, l -- low 32 bits
|
||||
Ah = 0x6a09e667 | 0;
|
||||
Al = 0xf3bcc908 | 0;
|
||||
Bh = 0xbb67ae85 | 0;
|
||||
Bl = 0x84caa73b | 0;
|
||||
Ch = 0x3c6ef372 | 0;
|
||||
Cl = 0xfe94f82b | 0;
|
||||
Dh = 0xa54ff53a | 0;
|
||||
Dl = 0x5f1d36f1 | 0;
|
||||
Eh = 0x510e527f | 0;
|
||||
El = 0xade682d1 | 0;
|
||||
Fh = 0x9b05688c | 0;
|
||||
Fl = 0x2b3e6c1f | 0;
|
||||
Gh = 0x1f83d9ab | 0;
|
||||
Gl = 0xfb41bd6b | 0;
|
||||
Hh = 0x5be0cd19 | 0;
|
||||
Hl = 0x137e2179 | 0;
|
||||
|
||||
constructor() {
|
||||
super(128, 64, 16, false);
|
||||
}
|
||||
// prettier-ignore
|
||||
protected get(): [
|
||||
number, number, number, number, number, number, number, number,
|
||||
number, number, number, number, number, number, number, number
|
||||
] {
|
||||
const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
|
||||
return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];
|
||||
}
|
||||
// prettier-ignore
|
||||
protected set(
|
||||
Ah: number, Al: number, Bh: number, Bl: number, Ch: number, Cl: number, Dh: number, Dl: number,
|
||||
Eh: number, El: number, Fh: number, Fl: number, Gh: number, Gl: number, Hh: number, Hl: number
|
||||
) {
|
||||
this.Ah = Ah | 0;
|
||||
this.Al = Al | 0;
|
||||
this.Bh = Bh | 0;
|
||||
this.Bl = Bl | 0;
|
||||
this.Ch = Ch | 0;
|
||||
this.Cl = Cl | 0;
|
||||
this.Dh = Dh | 0;
|
||||
this.Dl = Dl | 0;
|
||||
this.Eh = Eh | 0;
|
||||
this.El = El | 0;
|
||||
this.Fh = Fh | 0;
|
||||
this.Fl = Fl | 0;
|
||||
this.Gh = Gh | 0;
|
||||
this.Gl = Gl | 0;
|
||||
this.Hh = Hh | 0;
|
||||
this.Hl = Hl | 0;
|
||||
}
|
||||
protected process(view: DataView, offset: number) {
|
||||
// Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array
|
||||
for (let i = 0; i < 16; i++, offset += 4) {
|
||||
SHA512_W_H[i] = view.getUint32(offset);
|
||||
SHA512_W_L[i] = view.getUint32((offset += 4));
|
||||
}
|
||||
for (let i = 16; i < 80; i++) {
|
||||
// s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)
|
||||
const W15h = SHA512_W_H[i - 15] | 0;
|
||||
const W15l = SHA512_W_L[i - 15] | 0;
|
||||
const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);
|
||||
const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);
|
||||
// s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)
|
||||
const W2h = SHA512_W_H[i - 2] | 0;
|
||||
const W2l = SHA512_W_L[i - 2] | 0;
|
||||
const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);
|
||||
const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);
|
||||
// SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];
|
||||
const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);
|
||||
const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);
|
||||
SHA512_W_H[i] = SUMh | 0;
|
||||
SHA512_W_L[i] = SUMl | 0;
|
||||
}
|
||||
let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
|
||||
// Compression function main loop, 80 rounds
|
||||
for (let i = 0; i < 80; i++) {
|
||||
// S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)
|
||||
const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);
|
||||
const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);
|
||||
//const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
|
||||
const CHIh = (Eh & Fh) ^ (~Eh & Gh);
|
||||
const CHIl = (El & Fl) ^ (~El & Gl);
|
||||
// T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]
|
||||
// prettier-ignore
|
||||
const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);
|
||||
const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);
|
||||
const T1l = T1ll | 0;
|
||||
// S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)
|
||||
const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);
|
||||
const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);
|
||||
const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);
|
||||
const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);
|
||||
Hh = Gh | 0;
|
||||
Hl = Gl | 0;
|
||||
Gh = Fh | 0;
|
||||
Gl = Fl | 0;
|
||||
Fh = Eh | 0;
|
||||
Fl = El | 0;
|
||||
({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));
|
||||
Dh = Ch | 0;
|
||||
Dl = Cl | 0;
|
||||
Ch = Bh | 0;
|
||||
Cl = Bl | 0;
|
||||
Bh = Ah | 0;
|
||||
Bl = Al | 0;
|
||||
const All = u64.add3L(T1l, sigma0l, MAJl);
|
||||
Ah = u64.add3H(All, T1h, sigma0h, MAJh);
|
||||
Al = All | 0;
|
||||
}
|
||||
// Add the compressed chunk to the current hash value
|
||||
({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));
|
||||
({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));
|
||||
({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));
|
||||
({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));
|
||||
({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));
|
||||
({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));
|
||||
({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));
|
||||
({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));
|
||||
this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);
|
||||
}
|
||||
protected roundClean() {
|
||||
SHA512_W_H.fill(0);
|
||||
SHA512_W_L.fill(0);
|
||||
}
|
||||
destroy() {
|
||||
this.buffer.fill(0);
|
||||
this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
class SHA512_256 extends SHA512 {
|
||||
// h -- high 32 bits, l -- low 32 bits
|
||||
override Ah = 0x22312194 | 0;
|
||||
override Al = 0xfc2bf72c | 0;
|
||||
override Bh = 0x9f555fa3 | 0;
|
||||
override Bl = 0xc84c64c2 | 0;
|
||||
override Ch = 0x2393b86b | 0;
|
||||
override Cl = 0x6f53b151 | 0;
|
||||
override Dh = 0x96387719 | 0;
|
||||
override Dl = 0x5940eabd | 0;
|
||||
override Eh = 0x96283ee2 | 0;
|
||||
override El = 0xa88effe3 | 0;
|
||||
override Fh = 0xbe5e1e25 | 0;
|
||||
override Fl = 0x53863992 | 0;
|
||||
override Gh = 0x2b0199fc | 0;
|
||||
override Gl = 0x2c85b8aa | 0;
|
||||
override Hh = 0x0eb72ddc | 0;
|
||||
override Hl = 0x81c52ca2 | 0;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.outputLen = 32;
|
||||
}
|
||||
}
|
||||
|
||||
class SHA384 extends SHA512 {
|
||||
// h -- high 32 bits, l -- low 32 bits
|
||||
override Ah = 0xcbbb9d5d | 0;
|
||||
override Al = 0xc1059ed8 | 0;
|
||||
override Bh = 0x629a292a | 0;
|
||||
override Bl = 0x367cd507 | 0;
|
||||
override Ch = 0x9159015a | 0;
|
||||
override Cl = 0x3070dd17 | 0;
|
||||
override Dh = 0x152fecd8 | 0;
|
||||
override Dl = 0xf70e5939 | 0;
|
||||
override Eh = 0x67332667 | 0;
|
||||
override El = 0xffc00b31 | 0;
|
||||
override Fh = 0x8eb44a87 | 0;
|
||||
override Fl = 0x68581511 | 0;
|
||||
override Gh = 0xdb0c2e0d | 0;
|
||||
override Gl = 0x64f98fa7 | 0;
|
||||
override Hh = 0x47b5481d | 0;
|
||||
override Hl = 0xbefa4fa4 | 0;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.outputLen = 48;
|
||||
}
|
||||
}
|
||||
|
||||
export const sha512 = wrapConstructor(() => new SHA512());
|
||||
export const sha512_256 = wrapConstructor(() => new SHA512_256());
|
||||
export const sha384 = wrapConstructor(() => new SHA384());
|
||||
@@ -1,175 +0,0 @@
|
||||
/*! noble-hashes - MIT License (c) 2021 Paul Miller (paulmillr.com) */
|
||||
|
||||
// The import here is via the package name. This is to ensure
|
||||
// that exports mapping/resolution does fall into place.
|
||||
import { crypto } from '@polkadot/x-noble-hashes/crypto';
|
||||
|
||||
// prettier-ignore
|
||||
export type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |
|
||||
Uint16Array | Int16Array | Uint32Array | Int32Array;
|
||||
|
||||
// Cast array to different type
|
||||
export const u8 = (arr: TypedArray) => new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
||||
export const u32 = (arr: TypedArray) =>
|
||||
new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
||||
|
||||
// Cast array to view
|
||||
export const createView = (arr: TypedArray) =>
|
||||
new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
||||
|
||||
// The rotate right (circular right shift) operation for uint32
|
||||
export const rotr = (word: number, shift: number) => (word << (32 - shift)) | (word >>> shift);
|
||||
|
||||
export const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
|
||||
// There is almost no big endian hardware, but js typed arrays uses platform specific endianess.
|
||||
// So, just to be sure not to corrupt anything.
|
||||
if (!isLE) throw new Error('Non little-endian hardware is not supported');
|
||||
|
||||
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
|
||||
export function bytesToHex(uint8a: Uint8Array): string {
|
||||
// pre-caching chars could speed this up 6x.
|
||||
let hex = '';
|
||||
for (let i = 0; i < uint8a.length; i++) {
|
||||
hex += hexes[uint8a[i]];
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
// Currently avoid insertion of polyfills with packers (browserify/webpack/etc)
|
||||
// But setTimeout is pretty slow, maybe worth to investigate howto do minimal polyfill here
|
||||
export const nextTick: () => Promise<unknown> = (() => {
|
||||
const nodeRequire =
|
||||
typeof module !== 'undefined' &&
|
||||
typeof module.require === 'function' &&
|
||||
module.require.bind(module);
|
||||
try {
|
||||
if (nodeRequire) {
|
||||
const { setImmediate } = nodeRequire('timers');
|
||||
return () => new Promise((resolve) => setImmediate(resolve));
|
||||
}
|
||||
} catch (e) {}
|
||||
return () => new Promise((resolve) => setTimeout(resolve, 0));
|
||||
})();
|
||||
|
||||
// Returns control to thread each 'tick' ms to avoid blocking
|
||||
export async function asyncLoop(iters: number, tick: number, cb: (i: number) => void) {
|
||||
let ts = Date.now();
|
||||
for (let i = 0; i < iters; i++) {
|
||||
cb(i);
|
||||
// Date.now() is not monotonic, so in case if clock goes backwards we return return control too
|
||||
const diff = Date.now() - ts;
|
||||
if (diff >= 0 && diff < tick) continue;
|
||||
await nextTick();
|
||||
ts += diff;
|
||||
}
|
||||
}
|
||||
|
||||
// Global symbols in both browsers and Node.js since v11
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder
|
||||
// https://nodejs.org/docs/latest-v12.x/api/util.html#util_class_util_textencoder
|
||||
// https://nodejs.org/docs/latest-v12.x/api/util.html#util_class_util_textdecoder
|
||||
// See https://github.com/microsoft/TypeScript/issues/31535
|
||||
declare const TextEncoder: any;
|
||||
declare const TextDecoder: any;
|
||||
export type Input = Uint8Array | string;
|
||||
export function toBytes(data: Input) {
|
||||
if (typeof data === 'string') data = new TextEncoder().encode(data);
|
||||
if (!(data instanceof Uint8Array))
|
||||
throw new TypeError(`Expected input type is Uint8Array (got ${typeof data})`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export function assertNumber(n: number) {
|
||||
if (!Number.isSafeInteger(n)) throw new Error(`Wrong integer: ${n}`);
|
||||
}
|
||||
|
||||
export function assertBool(b: boolean) {
|
||||
if (typeof b !== 'boolean') {
|
||||
throw new Error(`Expected boolean, not ${b}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertHash(hash: CHash) {
|
||||
if (typeof hash !== 'function' || typeof hash.init !== 'function')
|
||||
throw new Error('Hash should be wrapped by utils.wrapConstructor');
|
||||
assertNumber(hash.outputLen);
|
||||
assertNumber(hash.blockLen);
|
||||
}
|
||||
|
||||
// For runtime check if class implements interface
|
||||
export abstract class Hash<T extends Hash<T>> {
|
||||
abstract blockLen: number; // Bytes per block
|
||||
abstract outputLen: number; // Bytes in output
|
||||
abstract update(buf: Input): this;
|
||||
// Writes digest into buf
|
||||
abstract digestInto(buf: Uint8Array): void;
|
||||
abstract digest(): Uint8Array;
|
||||
// Cleanup internal state. Not '.clean' because instance is not usable after that.
|
||||
// Clean usually resets instance to initial state, but it is not possible for keyed hashes if key is consumed into state.
|
||||
// NOTE: if digest is not consumed by user, user need manually call '.destroy' if zeroing is required
|
||||
abstract destroy(): void;
|
||||
// Unsafe because doesn't check if "to" is correct. Can be used as clone() if no opts passed.
|
||||
// Why cloneInto instead of clone? Mostly performance (same as _digestInto), but also has nice property: it reuses instance
|
||||
// which means all internal buffers is overwritten, which also causes overwrite buffer which used for digest (in some cases).
|
||||
// We don't provide any guarantees about cleanup (it is impossible to!), so should be enough for now.
|
||||
abstract _cloneInto(to?: T): T;
|
||||
// Safe version that clones internal state
|
||||
clone(): T {
|
||||
return this._cloneInto();
|
||||
}
|
||||
}
|
||||
|
||||
export type HashXOF<T extends Hash<T>> = Hash<T> & {
|
||||
// XOF: streaming API to read digest in chunks. Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.
|
||||
// NOTE: when hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot destroy state,
|
||||
// next call can require more bytes.
|
||||
xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream
|
||||
xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf
|
||||
};
|
||||
|
||||
// Check if object doens't have custom constructor (like Uint8Array/Array)
|
||||
const isPlainObject = (obj: any) =>
|
||||
Object.prototype.toString.call(obj) === '[object Object]' && obj.constructor === Object;
|
||||
|
||||
type EmptyObj = {};
|
||||
export function checkOpts<T1 extends EmptyObj, T2 extends EmptyObj>(def: T1, _opts?: T2): T1 & T2 {
|
||||
if (_opts !== undefined && (typeof _opts !== 'object' || !isPlainObject(_opts)))
|
||||
throw new TypeError('Options should be object or undefined');
|
||||
const opts = Object.assign(def, _opts);
|
||||
return opts as T1 & T2;
|
||||
}
|
||||
|
||||
export type CHash = ReturnType<typeof wrapConstructor>;
|
||||
|
||||
export function wrapConstructor<T extends Hash<T>>(hashConstructor: () => Hash<T>) {
|
||||
const hashC = (message: Input): Uint8Array => hashConstructor().update(toBytes(message)).digest();
|
||||
const tmp = hashConstructor();
|
||||
hashC.outputLen = tmp.outputLen;
|
||||
hashC.blockLen = tmp.blockLen;
|
||||
hashC.create = () => hashConstructor();
|
||||
hashC.init = hashC.create;
|
||||
return hashC;
|
||||
}
|
||||
|
||||
export function wrapConstructorWithOpts<H extends Hash<H>, T extends Object>(
|
||||
hashCons: (opts?: T) => Hash<H>
|
||||
) {
|
||||
const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();
|
||||
const tmp = hashCons({} as T);
|
||||
hashC.outputLen = tmp.outputLen;
|
||||
hashC.blockLen = tmp.blockLen;
|
||||
hashC.create = (opts: T) => hashCons(opts);
|
||||
hashC.init = hashC.create;
|
||||
return hashC;
|
||||
}
|
||||
|
||||
export function randomBytes(bytesLength = 32): Uint8Array {
|
||||
if (crypto.web) {
|
||||
return crypto.web.getRandomValues(new Uint8Array(bytesLength));
|
||||
} else if (crypto.node) {
|
||||
return new Uint8Array(crypto.node.randomBytes(bytesLength).buffer);
|
||||
} else {
|
||||
throw new Error("The environment doesn't have randomBytes function");
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "..",
|
||||
"outDir": "./build",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"references": []
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Paul Miller (https://paulmillr.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the “Software”), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,314 +0,0 @@
|
||||
# noble-secp256k1  [](https://github.com/prettier/prettier)
|
||||
|
||||
[Fastest](#speed) JS implementation of [secp256k1](https://www.secg.org/sec2-v2.pdf),
|
||||
an elliptic curve that could be used for asymmetric encryption,
|
||||
ECDH key agreement protocol and signature schemes. Supports deterministic **ECDSA** from RFC6979 and **Schnorr** signatures from BIP0340.
|
||||
|
||||
[**Audited**](#security) with crowdfunding by an independent security firm. Tested against thousands of test vectors from a different library. Check out [the online demo](https://paulmillr.com/ecc) and blog post: [Learning fast elliptic-curve cryptography in JS](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/)
|
||||
|
||||
### This library belongs to *noble* crypto
|
||||
|
||||
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
|
||||
|
||||
- No dependencies, one small file
|
||||
- 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](https://github.com/paulmillr/noble-secp256k1),
|
||||
[ed25519](https://github.com/paulmillr/noble-ed25519),
|
||||
[bls12-381](https://github.com/paulmillr/noble-bls12-381),
|
||||
[hashes](https://github.com/paulmillr/noble-hashes)
|
||||
|
||||
## Usage
|
||||
|
||||
Use NPM in node.js / browser, or include single file from
|
||||
[GitHub's releases page](https://github.com/paulmillr/noble-secp256k1/releases):
|
||||
|
||||
> npm install @noble/secp256k1
|
||||
|
||||
```js
|
||||
import * as secp from "@noble/secp256k1";
|
||||
// if you're using single file, use global variable nobleSecp256k1 instead
|
||||
|
||||
(async () => {
|
||||
// You pass either a hex string, or Uint8Array
|
||||
const privateKey = "6b911fd37cdf5c81d4c0adb1ab7fa822ed253ab0ad9aa18d77257c88b29b718e";
|
||||
const messageHash = "a33321f98e4ff1c283c76998f14f57447545d339b3db534c6d886decb4209f28";
|
||||
const publicKey = secp.getPublicKey(privateKey);
|
||||
const signature = await secp.sign(messageHash, privateKey);
|
||||
const isSigned = secp.verify(signature, messageHash, publicKey);
|
||||
|
||||
// Supports Schnorr signatures
|
||||
const rpub = secp.schnorr.getPublicKey(privateKey);
|
||||
const rsignature = await secp.schnorr.sign(messageHash, privateKey);
|
||||
const risSigned = await secp.schnorr.verify(rsignature, messageHash, rpub);
|
||||
})();
|
||||
```
|
||||
|
||||
Deno:
|
||||
|
||||
```typescript
|
||||
import * as secp from "https://deno.land/x/secp256k1/mod.ts";
|
||||
const publicKey = secp.getPublicKey("6b911fd37cdf5c81d4c0adb1ab7fa822ed253ab0ad9aa18d77257c88b29b718e");
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
- [`getPublicKey(privateKey)`](#getpublickeyprivatekey)
|
||||
- [`getSharedSecret(privateKeyA, publicKeyB)`](#getsharedsecretprivatekeya-publickeyb)
|
||||
- [`sign(hash, privateKey)`](#signhash-privatekey)
|
||||
- [`verify(signature, hash, publicKey)`](#verifysignature-hash-publickey)
|
||||
- [`recoverPublicKey(hash, signature, recovery)`](#recoverpublickeyhash-signature-recovery)
|
||||
- [`schnorr.getPublicKey(privateKey)`](#schnorrgetpublickeyprivatekey)
|
||||
- [`schnorr.sign(hash, privateKey)`](#schnorrsignhash-privatekey)
|
||||
- [`schnorr.verify(signature, hash, publicKey)`](#schnorrverifysignature-hash-publickey)
|
||||
- [Helpers](#helpers)
|
||||
|
||||
##### `getPublicKey(privateKey)`
|
||||
```typescript
|
||||
function getPublicKey(privateKey: Uint8Array, isCompressed?: false): Uint8Array;
|
||||
function getPublicKey(privateKey: string, isCompressed?: false): string;
|
||||
function getPublicKey(privateKey: bigint): Uint8Array;
|
||||
```
|
||||
`privateKey` will be used to generate public key.
|
||||
Public key is generated by doing scalar multiplication of a base Point(x, y) by a fixed
|
||||
integer. The result is another `Point(x, y)` which we will by default encode to hex Uint8Array.
|
||||
`isCompressed` (default is `false`) determines whether the output should contain `y` coordinate of the point.
|
||||
|
||||
To get Point instance, use `Point.fromPrivateKey(privateKey)`.
|
||||
|
||||
##### `getSharedSecret(privateKeyA, publicKeyB)`
|
||||
```typescript
|
||||
function getSharedSecret(privateKeyA: Uint8Array, publicKeyB: Uint8Array): Uint8Array;
|
||||
function getSharedSecret(privateKeyA: string, publicKeyB: string): string;
|
||||
function getSharedSecret(privateKeyA: bigint, publicKeyB: Point): Uint8Array;
|
||||
```
|
||||
|
||||
Computes ECDH (Elliptic Curve Diffie-Hellman) shared secret between a private key and a different public key.
|
||||
|
||||
To get Point instance, use `Point.fromHex(publicKeyB).multiply(privateKeyA)`.
|
||||
|
||||
To speed-up the function massively by precomputing EC multiplications,
|
||||
use `getSharedSecret(privateKeyA, secp.utils.precompute(8, publicKeyB))`
|
||||
|
||||
|
||||
##### `sign(hash, privateKey)`
|
||||
```typescript
|
||||
function sign(msgHash: Uint8Array, privateKey: Uint8Array, opts?: Options): Promise<Uint8Array>;
|
||||
function sign(msgHash: string, privateKey: string, opts?: Options): Promise<string>;
|
||||
function sign(msgHash: Uint8Array, privateKey: Uint8Array, opts?: Options): Promise<[Uint8Array | string, number]>;
|
||||
```
|
||||
|
||||
Generates deterministic ECDSA signature as per RFC6979.
|
||||
|
||||
- `msgHash: Uint8Array | string` - message hash which would be signed
|
||||
- `privateKey: Uint8Array | string | bigint` - private key which will sign the hash
|
||||
- `options?: Options` - *optional* object related to signature value and format
|
||||
- `options?.recovered: boolean = false` - whether the recovered bit should be included in the result. In this case, the result would be an array of two items.
|
||||
- `options?.canonical: boolean = false` - whether a signature `s` should be no more than 1/2 prime order
|
||||
- `options?.der: boolean = true` - whether the returned signature should be in DER format. If `false`, it would be in Compact format (32-byte r + 32-byte s)
|
||||
|
||||
The function is asynchronous because we're utilizing built-in HMAC API to not rely on dependencies.
|
||||
|
||||
`signSync` counterpart could also be used, you need to set `utils.hmacSha256Sync` to a function with signature `key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array`. Example with `noble-hashes` package:
|
||||
|
||||
```ts
|
||||
const { hmac } = require('noble-hashes/lib/hmac');
|
||||
const { sha256 } = require('noble-hashes/lib/sha256');
|
||||
secp256k1.utils.hmacSha256Sync = (key: Uint8Array, ...msgs: Uint8Array[]) => {
|
||||
const h = hmac.create(sha256, key);
|
||||
msgs.forEach(msg => h.update(msg));
|
||||
return h.digest();
|
||||
};
|
||||
|
||||
// Can be used now
|
||||
secp256k1.signSync(msgHash, privateKey)
|
||||
```
|
||||
|
||||
##### `verify(signature, hash, publicKey)`
|
||||
```typescript
|
||||
function verify(signature: Uint8Array, msgHash: Uint8Array, publicKey: Uint8Array): boolean
|
||||
function verify(signature: string, msgHash: string, publicKey: string): boolean
|
||||
```
|
||||
- `signature: Uint8Array | string | { r: bigint, s: bigint }` - object returned by the `sign` function
|
||||
- `msgHash: Uint8Array | string` - message hash that needs to be verified
|
||||
- `publicKey: Uint8Array | string | Point` - e.g. that was generated from `privateKey` by `getPublicKey`
|
||||
- Returns `boolean`: `true` if `signature == hash`; otherwise `false`
|
||||
|
||||
##### `recoverPublicKey(hash, signature, recovery)`
|
||||
```typescript
|
||||
function recoverPublicKey(msgHash: Uint8Array, signature: Uint8Array, recovery: number): Uint8Array | undefined;
|
||||
function recoverPublicKey(msgHash: string, signature: string, recovery: number): string | undefined;
|
||||
```
|
||||
- `msgHash: Uint8Array | string` - message hash which would be signed
|
||||
- `signature: Uint8Array | string | { r: bigint, s: bigint }` - object returned by the `sign` function
|
||||
- `recovery: number` - recovery bit returned by `sign` with `recovered` option
|
||||
Public key is generated by doing scalar multiplication of a base Point(x, y) by a fixed
|
||||
integer. The result is another `Point(x, y)` which we will by default encode to hex Uint8Array.
|
||||
If signature is invalid - function will return `undefined` as result.
|
||||
|
||||
To get Point instance, use `Point.fromSignature(hash, signature, recovery)`.
|
||||
|
||||
##### `schnorr.getPublicKey(privateKey)`
|
||||
```typescript
|
||||
function schnorrGetPublicKey(privateKey: Uint8Array): Uint8Array;
|
||||
function schnorrGetPublicKey(privateKey: string): string;
|
||||
```
|
||||
|
||||
Returns 32-byte public key. *Warning:* it is incompatible with non-schnorr pubkey.
|
||||
|
||||
Specifically, its *y* coordinate may be flipped. See BIP0340 for clarification.
|
||||
|
||||
##### `schnorr.sign(hash, privateKey)`
|
||||
```typescript
|
||||
function schnorrSign(msgHash: Uint8Array, privateKey: Uint8Array, auxilaryRandom?: Uint8Array): Promise<Uint8Array>;
|
||||
function schnorrSign(msgHash: string, privateKey: string, auxilaryRandom?: string): Promise<string>;
|
||||
```
|
||||
|
||||
Generates Schnorr signature as per BIP0340. Asynchronous, so use `await`.
|
||||
|
||||
- `msgHash: Uint8Array | string` - message hash which would be signed
|
||||
- `privateKey: Uint8Array | string | bigint` - private key which will sign the hash
|
||||
- `auxilaryRandom?: Uint8Array` — optional 32 random bytes. By default, the method gathers cryptogarphically secure random.
|
||||
- Returns Schnorr signature in Hex format.
|
||||
|
||||
##### `schnorr.verify(signature, hash, publicKey)`
|
||||
```typescript
|
||||
function schnorrVerify(signature: Uint8Array | string, msgHash: Uint8Array | string, publicKey: Uint8Array | string): boolean
|
||||
```
|
||||
- `signature: Uint8Array | string | { r: bigint, s: bigint }` - object returned by the `sign` function
|
||||
- `msgHash: Uint8Array | string` - message hash that needs to be verified
|
||||
- `publicKey: Uint8Array | string | Point` - e.g. that was generated from `privateKey` by `getPublicKey`
|
||||
- Returns `boolean`: `true` if `signature == hash`; otherwise `false`
|
||||
|
||||
#### Point methods
|
||||
|
||||
##### Helpers
|
||||
|
||||
###### `utils.randomPrivateKey(): Uint8Array`
|
||||
|
||||
Returns `Uint8Array` of 32 cryptographically secure random bytes that can be used as private key. The signature is:
|
||||
|
||||
```ts
|
||||
(key: Uint8Array, ...msgs: Uint8Array[]): Uint8Array;
|
||||
```
|
||||
|
||||
###### `utils.hmacSha256Sync`
|
||||
|
||||
The function is not defined by default, but could be used to implement `signSync` method (see above).
|
||||
|
||||
###### `utils.precompute(W = 8, point = BASE_POINT): Point`
|
||||
|
||||
Returns cached point which you can use to pass to `getSharedSecret` or to `#multiply` by it.
|
||||
|
||||
This is done by default, no need to run it unless you want to
|
||||
disable precomputation or change window size.
|
||||
|
||||
We're doing scalar multiplication (used in getPublicKey etc) with
|
||||
precomputed BASE_POINT values.
|
||||
|
||||
This slows down first getPublicKey() by milliseconds (see Speed section),
|
||||
but allows to speed-up subsequent getPublicKey() calls up to 20x.
|
||||
|
||||
You may want to precompute values for your own point.
|
||||
|
||||
```typescript
|
||||
secp256k1.CURVE.P // Field, 2 ** 256 - 2 ** 32 - 977
|
||||
secp256k1.CURVE.n // Order, 2 ** 256 - 432420386565659656852420866394968145599
|
||||
secp256k1.Point.BASE // new secp256k1.Point(Gx, Gy) where
|
||||
// Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240n
|
||||
// Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
|
||||
|
||||
// Elliptic curve point in Affine (x, y) coordinates.
|
||||
secp256k1.Point {
|
||||
constructor(x: bigint, y: bigint);
|
||||
// Supports compressed and non-compressed hex
|
||||
static fromHex(hex: Uint8Array | string);
|
||||
static fromPrivateKey(privateKey: Uint8Array | string | number | bigint);
|
||||
static fromSignature(
|
||||
msgHash: Hex,
|
||||
signature: Signature,
|
||||
recovery: number | bigint
|
||||
): Point | undefined {
|
||||
toRawBytes(isCompressed = false): Uint8Array;
|
||||
toHex(isCompressed = false): string;
|
||||
equals(other: Point): boolean;
|
||||
negate(): Point;
|
||||
add(other: Point): Point;
|
||||
subtract(other: Point): Point;
|
||||
// Constant-time scalar multiplication.
|
||||
multiply(scalar: bigint | Uint8Array): Point;
|
||||
}
|
||||
secp256k1.Signature {
|
||||
constructor(r: bigint, s: bigint);
|
||||
// DER encoded ECDSA signature
|
||||
static fromDER(hex: Uint8Array | string);
|
||||
// R, S 32-byte each
|
||||
static fromCompact(hex: Uint8Array | string);
|
||||
toDERRawBytes(): Uint8Array;
|
||||
toDERHex(): string;
|
||||
toCompactRawBytes(): Uint8Array;
|
||||
toCompactHex(): string;
|
||||
}
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
Noble is production-ready.
|
||||
|
||||
1. The library has been audited by an independent security firm cure53: [PDF](https://cure53.de/pentest-report_noble-lib.pdf). The audit has been [crowdfunded](https://gitcoin.co/grants/2451/audit-of-noble-secp256k1-cryptographic-library) by community with help of [Umbra.cash](https://umbra.cash).
|
||||
2. The library has also been fuzzed by [Guido Vranken's cryptofuzz](https://github.com/guidovranken/cryptofuzz). You can run the fuzzer by yourself to check it.
|
||||
|
||||
We're using built-in JS `BigInt`, which is "unsuitable for use in cryptography" as [per official spec](https://github.com/tc39/proposal-bigint#cryptography). This means that the lib is potentially vulnerable to [timing attacks](https://en.wikipedia.org/wiki/Timing_attack). But, *JIT-compiler* and *Garbage Collector* make "constant time" extremely hard to achieve in a scripting language. Which means *any other JS library doesn't use constant-time bigints*. Including bn.js or anything else. 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've hardened implementation of koblitz curve multiplication to be algorithmically constant time.
|
||||
|
||||
We however 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.
|
||||
|
||||
getPublicKey(utils.randomPrivateKey()) x 6,121 ops/sec @ 163μs/op
|
||||
sign x 4,679 ops/sec @ 213μs/op
|
||||
verify x 923 ops/sec @ 1ms/op
|
||||
recoverPublicKey x 491 ops/sec @ 2ms/op
|
||||
getSharedSecret aka ecdh x 534 ops/sec @ 1ms/op
|
||||
getSharedSecret (precomputed) x 7,105 ops/sec @ 140μs/op
|
||||
Point.fromHex (decompression) x 12,171 ops/sec @ 82μs/op
|
||||
schnorr.sign x 409 ops/sec @ 2ms/op
|
||||
schnorr.verify x 504 ops/sec @ 1ms/op
|
||||
|
||||
Compare to other libraries (`openssl` uses native bindings, not JS):
|
||||
|
||||
elliptic#getPublicKey x 1,940 ops/sec
|
||||
sjcl#getPublicKey x 211 ops/sec
|
||||
|
||||
elliptic#sign x 1,808 ops/sec
|
||||
sjcl#sign x 199 ops/sec
|
||||
openssl#sign x 4,243 ops/sec
|
||||
ecdsa#sign x 116 ops/sec
|
||||
bip-schnorr#sign x 60 ops/sec
|
||||
|
||||
elliptic#verify x 812 ops/sec
|
||||
sjcl#verify x 166 ops/sec
|
||||
openssl#verify x 4,452 ops/sec
|
||||
ecdsa#verify x 80 ops/sec
|
||||
bip-schnorr#verify x 56 ops/sec
|
||||
|
||||
elliptic#ecdh x 971 ops/sec
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Check out a blog post about this library: [Learning fast elliptic-curve cryptography in JS](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
|
||||
|
||||
1. Clone the repository.
|
||||
2. `npm install` to install build dependencies like TypeScript
|
||||
3. `npm run compile` to compile TypeScript code
|
||||
4. `npm run test` to run jest on `test/index.ts`
|
||||
|
||||
Special thanks to [Roman Koblov](https://github.com/romankoblov), who have helped to improve scalar multiplication speed.
|
||||
|
||||
## License
|
||||
|
||||
MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
"bugs": "https://github.com/polkadot-js/common/issues",
|
||||
"contributors": [],
|
||||
"description": "An fork of @noble/secp256k1 with extra protection on BigInt usage",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"homepage": "https://github.com/polkadot-js/common/tree/master/packages/x-noble-secp256k1#readme",
|
||||
"license": "MIT",
|
||||
"maintainers": [],
|
||||
"name": "@polkadot/x-noble-secp256k1",
|
||||
"repository": {
|
||||
"directory": "packages/x-noble-secp256k1",
|
||||
"type": "git",
|
||||
"url": "https://github.com/polkadot-js/common.git"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"version": "8.1.3-28",
|
||||
"browser": {
|
||||
"crypto": false
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.16.5"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
// Copyright 2017-2021 @polkadot/x-noble-secp256k1 authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Auto-generated by @polkadot/dev, do not edit
|
||||
|
||||
export const packageInfo = { name: '@polkadot/x-noble-secp256k1', version: '8.1.3-28' };
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "..",
|
||||
"outDir": "./build",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"references": []
|
||||
}
|
||||
@@ -16,7 +16,7 @@ const external = [
|
||||
...pkgs
|
||||
];
|
||||
|
||||
const entries = ['hw-ledger-transports', 'networks', 'x-bigint', 'x-fetch', 'x-global', 'x-noble-hashes', 'x-noble-secp256k1', 'x-randomvalues', 'x-textdecoder', 'x-textencoder', 'x-ws'].reduce((all, p) => ({
|
||||
const entries = ['hw-ledger-transports', 'networks', 'x-bigint', 'x-fetch', 'x-global', 'x-randomvalues', 'x-textdecoder', 'x-textencoder', 'x-ws'].reduce((all, p) => ({
|
||||
...all,
|
||||
[`@polkadot/${p}`]: path.resolve(process.cwd(), `packages/${p}/build`)
|
||||
}), {});
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
"@polkadot/x-bigint": ["x-bigint/src"],
|
||||
"@polkadot/x-fetch": ["x-fetch/src/browser"],
|
||||
"@polkadot/x-global": ["x-global/src"],
|
||||
"@polkadot/x-noble-hashes/*": ["x-noble-hashes/src/*"],
|
||||
"@polkadot/x-noble-secp256k1": ["x-noble-secp256k1/src"],
|
||||
"@polkadot/x-randomvalues": ["x-randomvalues/src/browser"],
|
||||
"@polkadot/x-textdecoder": ["x-textdecoder/src/browser"],
|
||||
"@polkadot/x-textencoder": ["x-textencoder/src/browser"],
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
{ "path": "./packages/x-bundle" },
|
||||
{ "path": "./packages/x-fetch" },
|
||||
{ "path": "./packages/x-global" },
|
||||
{ "path": "./packages/x-noble-hashes" },
|
||||
{ "path": "./packages/x-noble-secp256k1" },
|
||||
{ "path": "./packages/x-randomvalues" },
|
||||
{ "path": "./packages/x-textdecoder" },
|
||||
{ "path": "./packages/x-textencoder" },
|
||||
|
||||
16
yarn.lock
16
yarn.lock
@@ -2214,22 +2214,6 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@polkadot/x-noble-hashes@workspace:packages/x-noble-hashes":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@polkadot/x-noble-hashes@workspace:packages/x-noble-hashes"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.16.5
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@polkadot/x-noble-secp256k1@workspace:packages/x-noble-secp256k1":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@polkadot/x-noble-secp256k1@workspace:packages/x-noble-secp256k1"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.16.5
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@polkadot/x-randomvalues@8.1.3-28, @polkadot/x-randomvalues@workspace:packages/x-randomvalues":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@polkadot/x-randomvalues@workspace:packages/x-randomvalues"
|
||||
|
||||
Reference in New Issue
Block a user