remove node_modules and .gitignore them
This commit is contained in:
-21
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2022 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.
|
||||
-201
@@ -1,201 +0,0 @@
|
||||
# scure-base
|
||||
|
||||
Audited & minimal implementation of bech32, base64, base58, base32 & base16.
|
||||
|
||||
- 🔒 [Audited](#security) by an independent security firm
|
||||
- 🔻 Tree-shaking-friendly: use only what's necessary, other code won't be included
|
||||
- 📦 ESM and common.js
|
||||
- ✍️ Written in [functional style](#design-rationale), easily composable
|
||||
- 💼 Matches specs
|
||||
- [BIP173](https://en.bitcoin.it/wiki/BIP_0173), [BIP350](https://en.bitcoin.it/wiki/BIP_0350) for bech32 / bech32m
|
||||
- [RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648) (aka RFC 3548) for Base16, Base32, Base32Hex, Base64, Base64Url
|
||||
- [Base58](https://www.ietf.org/archive/id/draft-msporny-base58-03.txt),
|
||||
[Base58check](https://en.bitcoin.it/wiki/Base58Check_encoding),
|
||||
[Base32 Crockford](https://www.crockford.com/base32.html)
|
||||
|
||||
Check out [Projects using scure-base](#projects-using-scure-base).
|
||||
|
||||
### This library belongs to _scure_
|
||||
|
||||
> **scure** — secure, independently audited packages for every use case.
|
||||
|
||||
- Minimal or zero dependencies
|
||||
- Releases are signed with PGP keys and built transparently with NPM provenance
|
||||
- Check out all libraries:
|
||||
[base](https://github.com/paulmillr/scure-base),
|
||||
[bip32](https://github.com/paulmillr/scure-bip32),
|
||||
[bip39](https://github.com/paulmillr/scure-bip39),
|
||||
[btc-signer](https://github.com/paulmillr/scure-btc-signer),
|
||||
[starknet](https://github.com/paulmillr/scure-starknet)
|
||||
|
||||
## Usage
|
||||
|
||||
> npm install @scure/base
|
||||
|
||||
We support all major platforms and runtimes. The library is hybrid ESM / Common.js package.
|
||||
|
||||
```js
|
||||
import { base16, base32, base64, base58 } from '@scure/base';
|
||||
// Flavors
|
||||
import {
|
||||
base58xmr,
|
||||
base58xrp,
|
||||
base32hex,
|
||||
base32crockford,
|
||||
base64url,
|
||||
base64urlnopad,
|
||||
} from '@scure/base';
|
||||
|
||||
const data = Uint8Array.from([1, 2, 3]);
|
||||
base64.decode(base64.encode(data));
|
||||
|
||||
// Convert utf8 string to Uint8Array
|
||||
const data2 = new TextEncoder().encode('hello');
|
||||
base58.encode(data2);
|
||||
|
||||
// Everything has the same API except for bech32 and base58check
|
||||
base32.encode(data);
|
||||
base16.encode(data);
|
||||
base32hex.encode(data);
|
||||
```
|
||||
|
||||
base58check is a special case: you need to pass `sha256()` function:
|
||||
|
||||
```js
|
||||
import { base58check } from '@scure/base';
|
||||
base58check(sha256).encode(data);
|
||||
```
|
||||
|
||||
Alternative API:
|
||||
|
||||
```js
|
||||
import { str, bytes } from '@scure/base';
|
||||
const encoded = str('base64', data);
|
||||
const data = bytes('base64', encoded);
|
||||
```
|
||||
|
||||
## Bech32, Bech32m and Bitcoin
|
||||
|
||||
We provide low-level bech32 operations.
|
||||
If you need high-level methods for BTC (addresses, and others), use
|
||||
[scure-btc-signer](https://github.com/paulmillr/scure-btc-signer) instead.
|
||||
|
||||
Bitcoin addresses use both 5-bit words and bytes representations.
|
||||
They can't be parsed using `bech32.decodeToBytes`. Instead, do something this:
|
||||
|
||||
```ts
|
||||
const decoded = bech32.decode(address);
|
||||
// NOTE: words in bitcoin addresses contain version as first element,
|
||||
// with actual witnes program words in rest
|
||||
// BIP-141: The value of the first push is called the "version byte".
|
||||
// The following byte vector pushed is called the "witness program".
|
||||
const [version, ...dataW] = decoded.words;
|
||||
const program = bech32.fromWords(dataW); // actual witness program
|
||||
```
|
||||
|
||||
Same applies to Lightning Invoice Protocol
|
||||
[BOLT-11](https://github.com/lightning/bolts/blob/master/11-payment-encoding.md).
|
||||
We have many tests in `./test/bip173.test.js` that serve as minimal examples of
|
||||
Bitcoin address and Lightning Invoice Protocol parsers.
|
||||
Keep in mind that you'll need to verify the examples before using them in your code.
|
||||
|
||||
## Design rationale
|
||||
|
||||
The code may feel unnecessarily complicated; but actually it's much easier to reason about.
|
||||
Any encoding library consists of two functions:
|
||||
|
||||
```
|
||||
encode(A) -> B
|
||||
decode(B) -> A
|
||||
where X = decode(encode(X))
|
||||
# encode(decode(X)) can be !== X!
|
||||
# because decoding can normalize input
|
||||
|
||||
e.g.
|
||||
base58checksum = {
|
||||
encode(): {
|
||||
// checksum
|
||||
// radix conversion
|
||||
// alphabet
|
||||
},
|
||||
decode(): {
|
||||
// alphabet
|
||||
// radix conversion
|
||||
// checksum
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
But instead of creating two big functions for each specific case,
|
||||
we create them from tiny composamble building blocks:
|
||||
|
||||
```
|
||||
base58checksum = chain(checksum(), radix(), alphabet())
|
||||
```
|
||||
|
||||
Which is the same as chain/pipe/sequence function in Functional Programming,
|
||||
but significantly more useful since it enforces same order of execution of encode/decode.
|
||||
Basically you only define encode (in declarative way) and get correct decode for free.
|
||||
So, instead of reasoning about two big functions you need only reason about primitives and encode chain.
|
||||
The design revealed obvious bug in older version of the lib,
|
||||
where xmr version of base58 had errors in decode's block processing.
|
||||
|
||||
Besides base-encodings, we can reuse the same approach with any encode/decode function
|
||||
(`bytes2number`, `bytes2u32`, etc).
|
||||
For example, you can easily encode entropy to mnemonic (BIP-39):
|
||||
|
||||
```ts
|
||||
export function getCoder(wordlist: string[]) {
|
||||
if (!Array.isArray(wordlist) || wordlist.length !== 2 ** 11 || typeof wordlist[0] !== 'string') {
|
||||
throw new Error('Worlist: expected array of 2048 strings');
|
||||
}
|
||||
return mbc.chain(mbu.checksum(1, checksum), mbu.radix2(11, true), mbu.alphabet(wordlist));
|
||||
}
|
||||
```
|
||||
|
||||
## base58 is O(n^2) and radixes
|
||||
|
||||
`Uint8Array` is represented as big-endian number:
|
||||
|
||||
```
|
||||
[1, 2, 3, 4, 5] -> 1*(256**4) + 2*(256**3) 3*(256**2) + 4*(256**1) + 5*(256**0)
|
||||
where 256 = 2**8 (8 bits per byte)
|
||||
```
|
||||
|
||||
which is then converted to a number in another radix/base (16/32/58/64, etc).
|
||||
|
||||
However, generic conversion between bases has [quadratic O(n^2) time complexity](https://cs.stackexchange.com/q/21799).
|
||||
|
||||
Which means base58 has quadratic time complexity too. Use base58 only when you have small
|
||||
constant sized input, because variable length sized input from user can cause DoS.
|
||||
|
||||
On the other hand, if both bases are power of same number (like `2**8 <-> 2**64`),
|
||||
there is linear algorithm. For now we have implementation for power-of-two bases only (radix2).
|
||||
|
||||
## Security
|
||||
|
||||
The library has been independently audited:
|
||||
|
||||
- at version 1.0.0, in Jan 2022, by [cure53](https://cure53.de)
|
||||
- PDFs: [online](https://cure53.de/pentest-report_hashing-libs.pdf), [offline](./audit/2022-01-05-cure53-audit-nbl2.pdf)
|
||||
- [Changes since audit](https://github.com/paulmillr/scure-base/compare/1.0.0..main).
|
||||
- The audit has been funded by [Ethereum Foundation](https://ethereum.org/en/) with help of [Nomic Labs](https://nomiclabs.io)
|
||||
|
||||
The library was initially developed for [js-ethereum-cryptography](https://github.com/ethereum/js-ethereum-cryptography).
|
||||
At commit [ae00e6d7](https://github.com/ethereum/js-ethereum-cryptography/commit/ae00e6d7d24fb3c76a1c7fe10039f6ecd120b77e),
|
||||
it was extracted to a separate package called `micro-base`.
|
||||
After the audit we've decided to use `@scure` NPM namespace for security.
|
||||
|
||||
## Resources
|
||||
|
||||
### Projects using scure-base
|
||||
|
||||
- [prefixed-api-key](https://github.com/truestamp/prefixed-api-key):
|
||||
A re-write of seamapi/prefixed-api-key that enhances the
|
||||
cryptographic security properties and safety when verifying a key. The keys and verifiers
|
||||
of these two libraries are not compatible.
|
||||
[Motivating post on the issues with using JWT from fly.io](https://fly.io/blog/api-tokens-a-tedious-survey/)
|
||||
|
||||
## License
|
||||
|
||||
MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.
|
||||
-565
@@ -1,565 +0,0 @@
|
||||
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
|
||||
// Utilities
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
export function assertNumber(n: number) {
|
||||
if (!Number.isSafeInteger(n)) throw new Error(`Wrong integer: ${n}`);
|
||||
}
|
||||
export interface Coder<F, T> {
|
||||
encode(from: F): T;
|
||||
decode(to: T): F;
|
||||
}
|
||||
|
||||
export interface BytesCoder extends Coder<Uint8Array, string> {
|
||||
encode: (data: Uint8Array) => string;
|
||||
decode: (str: string) => Uint8Array;
|
||||
}
|
||||
|
||||
// TODO: some recusive type inference so it would check correct order of input/output inside rest?
|
||||
// like <string, number>, <number, bytes>, <bytes, float>
|
||||
type Chain = [Coder<any, any>, ...Coder<any, any>[]];
|
||||
// Extract info from Coder type
|
||||
type Input<F> = F extends Coder<infer T, any> ? T : never;
|
||||
type Output<F> = F extends Coder<any, infer T> ? T : never;
|
||||
// Generic function for arrays
|
||||
type First<T> = T extends [infer U, ...any[]] ? U : never;
|
||||
type Last<T> = T extends [...any[], infer U] ? U : never;
|
||||
type Tail<T> = T extends [any, ...infer U] ? U : never;
|
||||
|
||||
type AsChain<C extends Chain, Rest = Tail<C>> = {
|
||||
// C[K] = Coder<Input<C[K]>, Input<Rest[k]>>
|
||||
[K in keyof C]: Coder<Input<C[K]>, Input<K extends keyof Rest ? Rest[K] : any>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function chain<T extends Chain & AsChain<T>>(...args: T): Coder<Input<First<T>>, Output<Last<T>>> {
|
||||
// Wrap call in closure so JIT can inline calls
|
||||
const wrap = (a: any, b: any) => (c: any) => a(b(c));
|
||||
// Construct chain of args[-1].encode(args[-2].encode([...]))
|
||||
const encode = Array.from(args)
|
||||
.reverse()
|
||||
.reduce((acc, i: any) => (acc ? wrap(acc, i.encode) : i.encode), undefined) as any;
|
||||
// Construct chain of args[0].decode(args[1].decode(...))
|
||||
const decode = args.reduce(
|
||||
(acc, i: any) => (acc ? wrap(acc, i.decode) : i.decode),
|
||||
undefined
|
||||
) as any;
|
||||
return { encode, decode };
|
||||
}
|
||||
|
||||
type Alphabet = string[] | string;
|
||||
|
||||
/**
|
||||
* Encodes integer radix representation to array of strings using alphabet and back
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function alphabet(alphabet: Alphabet): Coder<number[], string[]> {
|
||||
return {
|
||||
encode: (digits: number[]) => {
|
||||
if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
|
||||
throw new Error('alphabet.encode input should be an array of numbers');
|
||||
return digits.map((i) => {
|
||||
assertNumber(i);
|
||||
if (i < 0 || i >= alphabet.length)
|
||||
throw new Error(`Digit index outside alphabet: ${i} (alphabet: ${alphabet.length})`);
|
||||
return alphabet[i]!;
|
||||
});
|
||||
},
|
||||
decode: (input: string[]) => {
|
||||
if (!Array.isArray(input) || (input.length && typeof input[0] !== 'string'))
|
||||
throw new Error('alphabet.decode input should be array of strings');
|
||||
return input.map((letter) => {
|
||||
if (typeof letter !== 'string')
|
||||
throw new Error(`alphabet.decode: not string element=${letter}`);
|
||||
const index = alphabet.indexOf(letter);
|
||||
if (index === -1) throw new Error(`Unknown letter: "${letter}". Allowed: ${alphabet}`);
|
||||
return index;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function join(separator = ''): Coder<string[], string> {
|
||||
if (typeof separator !== 'string') throw new Error('join separator should be string');
|
||||
return {
|
||||
encode: (from) => {
|
||||
if (!Array.isArray(from) || (from.length && typeof from[0] !== 'string'))
|
||||
throw new Error('join.encode input should be array of strings');
|
||||
for (let i of from)
|
||||
if (typeof i !== 'string') throw new Error(`join.encode: non-string input=${i}`);
|
||||
return from.join(separator);
|
||||
},
|
||||
decode: (to) => {
|
||||
if (typeof to !== 'string') throw new Error('join.decode input should be string');
|
||||
return to.split(separator);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Pad strings array so it has integer number of bits
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function padding(bits: number, chr = '='): Coder<string[], string[]> {
|
||||
assertNumber(bits);
|
||||
if (typeof chr !== 'string') throw new Error('padding chr should be string');
|
||||
return {
|
||||
encode(data: string[]): string[] {
|
||||
if (!Array.isArray(data) || (data.length && typeof data[0] !== 'string'))
|
||||
throw new Error('padding.encode input should be array of strings');
|
||||
for (let i of data)
|
||||
if (typeof i !== 'string') throw new Error(`padding.encode: non-string input=${i}`);
|
||||
while ((data.length * bits) % 8) data.push(chr);
|
||||
return data;
|
||||
},
|
||||
decode(input: string[]): string[] {
|
||||
if (!Array.isArray(input) || (input.length && typeof input[0] !== 'string'))
|
||||
throw new Error('padding.encode input should be array of strings');
|
||||
for (let i of input)
|
||||
if (typeof i !== 'string') throw new Error(`padding.decode: non-string input=${i}`);
|
||||
let end = input.length;
|
||||
if ((end * bits) % 8)
|
||||
throw new Error('Invalid padding: string should have whole number of bytes');
|
||||
for (; end > 0 && input[end - 1] === chr; end--) {
|
||||
if (!(((end - 1) * bits) % 8))
|
||||
throw new Error('Invalid padding: string has too much padding');
|
||||
}
|
||||
return input.slice(0, end);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function normalize<T>(fn: (val: T) => T): Coder<T, T> {
|
||||
if (typeof fn !== 'function') throw new Error('normalize fn should be function');
|
||||
return { encode: (from: T) => from, decode: (to: T) => fn(to) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Slow: O(n^2) time complexity
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function convertRadix(data: number[], from: number, to: number) {
|
||||
// base 1 is impossible
|
||||
if (from < 2) throw new Error(`convertRadix: wrong from=${from}, base cannot be less than 2`);
|
||||
if (to < 2) throw new Error(`convertRadix: wrong to=${to}, base cannot be less than 2`);
|
||||
if (!Array.isArray(data)) throw new Error('convertRadix: data should be array');
|
||||
if (!data.length) return [];
|
||||
let pos = 0;
|
||||
const res = [];
|
||||
const digits = Array.from(data);
|
||||
digits.forEach((d) => {
|
||||
assertNumber(d);
|
||||
if (d < 0 || d >= from) throw new Error(`Wrong integer: ${d}`);
|
||||
});
|
||||
while (true) {
|
||||
let carry = 0;
|
||||
let done = true;
|
||||
for (let i = pos; i < digits.length; i++) {
|
||||
const digit = digits[i]!;
|
||||
const digitBase = from * carry + digit;
|
||||
if (
|
||||
!Number.isSafeInteger(digitBase) ||
|
||||
(from * carry) / from !== carry ||
|
||||
digitBase - digit !== from * carry
|
||||
) {
|
||||
throw new Error('convertRadix: carry overflow');
|
||||
}
|
||||
carry = digitBase % to;
|
||||
const rounded = Math.floor(digitBase / to);
|
||||
digits[i] = rounded;
|
||||
if (!Number.isSafeInteger(rounded) || rounded * to + carry !== digitBase)
|
||||
throw new Error('convertRadix: carry overflow');
|
||||
if (!done) continue;
|
||||
else if (!rounded) pos = i;
|
||||
else done = false;
|
||||
}
|
||||
res.push(carry);
|
||||
if (done) break;
|
||||
}
|
||||
for (let i = 0; i < data.length - 1 && data[i] === 0; i++) res.push(0);
|
||||
return res.reverse();
|
||||
}
|
||||
|
||||
const gcd = /* @__NO_SIDE_EFFECTS__ */ (a: number, b: number): number => (!b ? a : gcd(b, a % b));
|
||||
const radix2carry = /*@__NO_SIDE_EFFECTS__ */ (from: number, to: number) =>
|
||||
from + (to - gcd(from, to));
|
||||
/**
|
||||
* Implemented with numbers, because BigInt is 5x slower
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function convertRadix2(data: number[], from: number, to: number, padding: boolean): number[] {
|
||||
if (!Array.isArray(data)) throw new Error('convertRadix2: data should be array');
|
||||
if (from <= 0 || from > 32) throw new Error(`convertRadix2: wrong from=${from}`);
|
||||
if (to <= 0 || to > 32) throw new Error(`convertRadix2: wrong to=${to}`);
|
||||
if (radix2carry(from, to) > 32) {
|
||||
throw new Error(
|
||||
`convertRadix2: carry overflow from=${from} to=${to} carryBits=${radix2carry(from, to)}`
|
||||
);
|
||||
}
|
||||
let carry = 0;
|
||||
let pos = 0; // bitwise position in current element
|
||||
const mask = 2 ** to - 1;
|
||||
const res: number[] = [];
|
||||
for (const n of data) {
|
||||
assertNumber(n);
|
||||
if (n >= 2 ** from) throw new Error(`convertRadix2: invalid data word=${n} from=${from}`);
|
||||
carry = (carry << from) | n;
|
||||
if (pos + from > 32) throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
|
||||
pos += from;
|
||||
for (; pos >= to; pos -= to) res.push(((carry >> (pos - to)) & mask) >>> 0);
|
||||
carry &= 2 ** pos - 1; // clean carry, otherwise it will cause overflow
|
||||
}
|
||||
carry = (carry << (to - pos)) & mask;
|
||||
if (!padding && pos >= from) throw new Error('Excess padding');
|
||||
if (!padding && carry) throw new Error(`Non-zero padding: ${carry}`);
|
||||
if (padding && pos > 0) res.push(carry >>> 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function radix(num: number): Coder<Uint8Array, number[]> {
|
||||
assertNumber(num);
|
||||
return {
|
||||
encode: (bytes: Uint8Array) => {
|
||||
if (!(bytes instanceof Uint8Array))
|
||||
throw new Error('radix.encode input should be Uint8Array');
|
||||
return convertRadix(Array.from(bytes), 2 ** 8, num);
|
||||
},
|
||||
decode: (digits: number[]) => {
|
||||
if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
|
||||
throw new Error('radix.decode input should be array of strings');
|
||||
return Uint8Array.from(convertRadix(digits, num, 2 ** 8));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* If both bases are power of same number (like `2**8 <-> 2**64`),
|
||||
* there is a linear algorithm. For now we have implementation for power-of-two bases only.
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function radix2(bits: number, revPadding = false): Coder<Uint8Array, number[]> {
|
||||
assertNumber(bits);
|
||||
if (bits <= 0 || bits > 32) throw new Error('radix2: bits should be in (0..32]');
|
||||
if (radix2carry(8, bits) > 32 || radix2carry(bits, 8) > 32)
|
||||
throw new Error('radix2: carry overflow');
|
||||
return {
|
||||
encode: (bytes: Uint8Array) => {
|
||||
if (!(bytes instanceof Uint8Array))
|
||||
throw new Error('radix2.encode input should be Uint8Array');
|
||||
return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
|
||||
},
|
||||
decode: (digits: number[]) => {
|
||||
if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
|
||||
throw new Error('radix2.decode input should be array of strings');
|
||||
return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
type ArgumentTypes<F extends Function> = F extends (...args: infer A) => any ? A : never;
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function unsafeWrapper<T extends (...args: any) => any>(fn: T) {
|
||||
if (typeof fn !== 'function') throw new Error('unsafeWrapper fn should be function');
|
||||
return function (...args: ArgumentTypes<T>): ReturnType<T> | void {
|
||||
try {
|
||||
return fn.apply(null, args);
|
||||
} catch (e) {}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function checksum(
|
||||
len: number,
|
||||
fn: (data: Uint8Array) => Uint8Array
|
||||
): Coder<Uint8Array, Uint8Array> {
|
||||
assertNumber(len);
|
||||
if (typeof fn !== 'function') throw new Error('checksum fn should be function');
|
||||
return {
|
||||
encode(data: Uint8Array) {
|
||||
if (!(data instanceof Uint8Array))
|
||||
throw new Error('checksum.encode: input should be Uint8Array');
|
||||
const checksum = fn(data).slice(0, len);
|
||||
const res = new Uint8Array(data.length + len);
|
||||
res.set(data);
|
||||
res.set(checksum, data.length);
|
||||
return res;
|
||||
},
|
||||
decode(data: Uint8Array) {
|
||||
if (!(data instanceof Uint8Array))
|
||||
throw new Error('checksum.decode: input should be Uint8Array');
|
||||
const payload = data.slice(0, -len);
|
||||
const newChecksum = fn(payload).slice(0, len);
|
||||
const oldChecksum = data.slice(-len);
|
||||
for (let i = 0; i < len; i++)
|
||||
if (newChecksum[i] !== oldChecksum[i]) throw new Error('Invalid checksum');
|
||||
return payload;
|
||||
},
|
||||
};
|
||||
}
|
||||
export const utils = { alphabet, chain, checksum, radix, radix2, join, padding };
|
||||
|
||||
// RFC 4648 aka RFC 3548
|
||||
// ---------------------
|
||||
export const base16: BytesCoder = /* @__PURE__ */ chain(
|
||||
radix2(4),
|
||||
alphabet('0123456789ABCDEF'),
|
||||
join('')
|
||||
);
|
||||
export const base32: BytesCoder = /* @__PURE__ */ chain(
|
||||
radix2(5),
|
||||
alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'),
|
||||
padding(5),
|
||||
join('')
|
||||
);
|
||||
export const base32hex: BytesCoder = /* @__PURE__ */ chain(
|
||||
radix2(5),
|
||||
alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'),
|
||||
padding(5),
|
||||
join('')
|
||||
);
|
||||
export const base32crockford: BytesCoder = /* @__PURE__ */ chain(
|
||||
radix2(5),
|
||||
alphabet('0123456789ABCDEFGHJKMNPQRSTVWXYZ'),
|
||||
join(''),
|
||||
normalize((s: string) => s.toUpperCase().replace(/O/g, '0').replace(/[IL]/g, '1'))
|
||||
);
|
||||
export const base64: BytesCoder = /* @__PURE__ */ chain(
|
||||
radix2(6),
|
||||
alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'),
|
||||
padding(6),
|
||||
join('')
|
||||
);
|
||||
export const base64url: BytesCoder = /* @__PURE__ */ chain(
|
||||
radix2(6),
|
||||
alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'),
|
||||
padding(6),
|
||||
join('')
|
||||
);
|
||||
export const base64urlnopad: BytesCoder = /* @__PURE__ */ chain(
|
||||
radix2(6),
|
||||
alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'),
|
||||
join('')
|
||||
);
|
||||
|
||||
// base58 code
|
||||
// -----------
|
||||
const genBase58 = (abc: string) => chain(radix(58), alphabet(abc), join(''));
|
||||
|
||||
export const base58: BytesCoder = /* @__PURE__ */ genBase58(
|
||||
'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||
);
|
||||
export const base58flickr: BytesCoder = /* @__PURE__ */ genBase58(
|
||||
'123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
|
||||
);
|
||||
export const base58xrp: BytesCoder = /* @__PURE__ */ genBase58(
|
||||
'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz'
|
||||
);
|
||||
|
||||
// xmr ver is done in 8-byte blocks (which equals 11 chars in decoding). Last (non-full) block padded with '1' to size in XMR_BLOCK_LEN.
|
||||
// Block encoding significantly reduces quadratic complexity of base58.
|
||||
|
||||
// Data len (index) -> encoded block len
|
||||
const XMR_BLOCK_LEN = [0, 2, 3, 5, 6, 7, 9, 10, 11];
|
||||
export const base58xmr: BytesCoder = {
|
||||
encode(data: Uint8Array) {
|
||||
let res = '';
|
||||
for (let i = 0; i < data.length; i += 8) {
|
||||
const block = data.subarray(i, i + 8);
|
||||
res += base58.encode(block).padStart(XMR_BLOCK_LEN[block.length]!, '1');
|
||||
}
|
||||
return res;
|
||||
},
|
||||
decode(str: string) {
|
||||
let res: number[] = [];
|
||||
for (let i = 0; i < str.length; i += 11) {
|
||||
const slice = str.slice(i, i + 11);
|
||||
const blockLen = XMR_BLOCK_LEN.indexOf(slice.length);
|
||||
const block = base58.decode(slice);
|
||||
for (let j = 0; j < block.length - blockLen; j++) {
|
||||
if (block[j] !== 0) throw new Error('base58xmr: wrong padding');
|
||||
}
|
||||
res = res.concat(Array.from(block.slice(block.length - blockLen)));
|
||||
}
|
||||
return Uint8Array.from(res);
|
||||
},
|
||||
};
|
||||
|
||||
export const base58check = /* @__PURE__ */ (sha256: (data: Uint8Array) => Uint8Array): BytesCoder =>
|
||||
chain(
|
||||
checksum(4, (data) => sha256(sha256(data))),
|
||||
base58
|
||||
);
|
||||
|
||||
// Bech32 code
|
||||
// -----------
|
||||
export interface Bech32Decoded<Prefix extends string = string> {
|
||||
prefix: Prefix;
|
||||
words: number[];
|
||||
}
|
||||
export interface Bech32DecodedWithArray<Prefix extends string = string> {
|
||||
prefix: Prefix;
|
||||
words: number[];
|
||||
bytes: Uint8Array;
|
||||
}
|
||||
|
||||
const BECH_ALPHABET: Coder<number[], string> = /* @__PURE__ */ chain(
|
||||
alphabet('qpzry9x8gf2tvdw0s3jn54khce6mua7l'),
|
||||
join('')
|
||||
);
|
||||
|
||||
const POLYMOD_GENERATORS = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function bech32Polymod(pre: number): number {
|
||||
const b = pre >> 25;
|
||||
let chk = (pre & 0x1ffffff) << 5;
|
||||
for (let i = 0; i < POLYMOD_GENERATORS.length; i++) {
|
||||
if (((b >> i) & 1) === 1) chk ^= POLYMOD_GENERATORS[i]!;
|
||||
}
|
||||
return chk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function bechChecksum(prefix: string, words: number[], encodingConst = 1): string {
|
||||
const len = prefix.length;
|
||||
let chk = 1;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const c = prefix.charCodeAt(i);
|
||||
if (c < 33 || c > 126) throw new Error(`Invalid prefix (${prefix})`);
|
||||
chk = bech32Polymod(chk) ^ (c >> 5);
|
||||
}
|
||||
chk = bech32Polymod(chk);
|
||||
for (let i = 0; i < len; i++) chk = bech32Polymod(chk) ^ (prefix.charCodeAt(i) & 0x1f);
|
||||
for (let v of words) chk = bech32Polymod(chk) ^ v;
|
||||
for (let i = 0; i < 6; i++) chk = bech32Polymod(chk);
|
||||
chk ^= encodingConst;
|
||||
return BECH_ALPHABET.encode(convertRadix2([chk % 2 ** 30], 30, 5, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function genBech32(encoding: 'bech32' | 'bech32m') {
|
||||
const ENCODING_CONST = encoding === 'bech32' ? 1 : 0x2bc830a3;
|
||||
const _words = radix2(5);
|
||||
const fromWords = _words.decode;
|
||||
const toWords = _words.encode;
|
||||
const fromWordsUnsafe = unsafeWrapper(fromWords);
|
||||
|
||||
function encode<Prefix extends string>(
|
||||
prefix: Prefix,
|
||||
words: number[] | Uint8Array,
|
||||
limit: number | false = 90
|
||||
): `${Lowercase<Prefix>}1${string}` {
|
||||
if (typeof prefix !== 'string')
|
||||
throw new Error(`bech32.encode prefix should be string, not ${typeof prefix}`);
|
||||
if (!Array.isArray(words) || (words.length && typeof words[0] !== 'number'))
|
||||
throw new Error(`bech32.encode words should be array of numbers, not ${typeof words}`);
|
||||
const actualLength = prefix.length + 7 + words.length;
|
||||
if (limit !== false && actualLength > limit)
|
||||
throw new TypeError(`Length ${actualLength} exceeds limit ${limit}`);
|
||||
const lowered = prefix.toLowerCase();
|
||||
const sum = bechChecksum(lowered, words, ENCODING_CONST);
|
||||
return `${lowered}1${BECH_ALPHABET.encode(words)}${sum}` as `${Lowercase<Prefix>}1${string}`;
|
||||
}
|
||||
|
||||
function decode<Prefix extends string>(
|
||||
str: `${Prefix}1${string}`,
|
||||
limit?: number | false
|
||||
): Bech32Decoded<Prefix>;
|
||||
function decode(str: string, limit?: number | false): Bech32Decoded;
|
||||
function decode(str: string, limit: number | false = 90): Bech32Decoded {
|
||||
if (typeof str !== 'string')
|
||||
throw new Error(`bech32.decode input should be string, not ${typeof str}`);
|
||||
if (str.length < 8 || (limit !== false && str.length > limit))
|
||||
throw new TypeError(`Wrong string length: ${str.length} (${str}). Expected (8..${limit})`);
|
||||
// don't allow mixed case
|
||||
const lowered = str.toLowerCase();
|
||||
if (str !== lowered && str !== str.toUpperCase())
|
||||
throw new Error(`String must be lowercase or uppercase`);
|
||||
str = lowered;
|
||||
const sepIndex = str.lastIndexOf('1');
|
||||
if (sepIndex === 0 || sepIndex === -1)
|
||||
throw new Error(`Letter "1" must be present between prefix and data only`);
|
||||
const prefix = str.slice(0, sepIndex);
|
||||
const _words = str.slice(sepIndex + 1);
|
||||
if (_words.length < 6) throw new Error('Data must be at least 6 characters long');
|
||||
const words = BECH_ALPHABET.decode(_words).slice(0, -6);
|
||||
const sum = bechChecksum(prefix, words, ENCODING_CONST);
|
||||
if (!_words.endsWith(sum)) throw new Error(`Invalid checksum in ${str}: expected "${sum}"`);
|
||||
return { prefix, words };
|
||||
}
|
||||
|
||||
const decodeUnsafe = unsafeWrapper(decode);
|
||||
|
||||
function decodeToBytes(str: string): Bech32DecodedWithArray {
|
||||
const { prefix, words } = decode(str, false);
|
||||
return { prefix, words, bytes: fromWords(words) };
|
||||
}
|
||||
|
||||
return { encode, decode, decodeToBytes, decodeUnsafe, fromWords, fromWordsUnsafe, toWords };
|
||||
}
|
||||
|
||||
export const bech32 = /* @__PURE__ */ genBech32('bech32');
|
||||
export const bech32m = /* @__PURE__ */ genBech32('bech32m');
|
||||
|
||||
declare const TextEncoder: any;
|
||||
declare const TextDecoder: any;
|
||||
|
||||
export const utf8: BytesCoder = {
|
||||
encode: (data) => new TextDecoder().decode(data),
|
||||
decode: (str) => new TextEncoder().encode(str),
|
||||
};
|
||||
|
||||
export const hex: BytesCoder = /* @__PURE__ */ chain(
|
||||
radix2(4),
|
||||
alphabet('0123456789abcdef'),
|
||||
join(''),
|
||||
normalize((s: string) => {
|
||||
if (typeof s !== 'string' || s.length % 2)
|
||||
throw new TypeError(`hex.decode: expected string, got ${typeof s} with length ${s.length}`);
|
||||
return s.toLowerCase();
|
||||
})
|
||||
);
|
||||
|
||||
// prettier-ignore
|
||||
const CODERS = {
|
||||
utf8, hex, base16, base32, base64, base64url, base58, base58xmr
|
||||
};
|
||||
type CoderType = keyof typeof CODERS;
|
||||
const coderTypeError =
|
||||
'Invalid encoding type. Available types: utf8, hex, base16, base32, base64, base64url, base58, base58xmr';
|
||||
|
||||
export const bytesToString = (type: CoderType, bytes: Uint8Array): string => {
|
||||
if (typeof type !== 'string' || !CODERS.hasOwnProperty(type)) throw new TypeError(coderTypeError);
|
||||
if (!(bytes instanceof Uint8Array)) throw new TypeError('bytesToString() expects Uint8Array');
|
||||
return CODERS[type].encode(bytes);
|
||||
};
|
||||
export const str = bytesToString; // as in python, but for bytes only
|
||||
|
||||
export const stringToBytes = (type: CoderType, str: string): Uint8Array => {
|
||||
if (!CODERS.hasOwnProperty(type)) throw new TypeError(coderTypeError);
|
||||
if (typeof str !== 'string') throw new TypeError('stringToBytes() expects string');
|
||||
return CODERS[type].decode(str);
|
||||
};
|
||||
export const bytes = stringToBytes;
|
||||
-462
@@ -1,462 +0,0 @@
|
||||
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Utilities
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
export function assertNumber(n) {
|
||||
if (!Number.isSafeInteger(n))
|
||||
throw new Error(`Wrong integer: ${n}`);
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function chain(...args) {
|
||||
// Wrap call in closure so JIT can inline calls
|
||||
const wrap = (a, b) => (c) => a(b(c));
|
||||
// Construct chain of args[-1].encode(args[-2].encode([...]))
|
||||
const encode = Array.from(args)
|
||||
.reverse()
|
||||
.reduce((acc, i) => (acc ? wrap(acc, i.encode) : i.encode), undefined);
|
||||
// Construct chain of args[0].decode(args[1].decode(...))
|
||||
const decode = args.reduce((acc, i) => (acc ? wrap(acc, i.decode) : i.decode), undefined);
|
||||
return { encode, decode };
|
||||
}
|
||||
/**
|
||||
* Encodes integer radix representation to array of strings using alphabet and back
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function alphabet(alphabet) {
|
||||
return {
|
||||
encode: (digits) => {
|
||||
if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
|
||||
throw new Error('alphabet.encode input should be an array of numbers');
|
||||
return digits.map((i) => {
|
||||
assertNumber(i);
|
||||
if (i < 0 || i >= alphabet.length)
|
||||
throw new Error(`Digit index outside alphabet: ${i} (alphabet: ${alphabet.length})`);
|
||||
return alphabet[i];
|
||||
});
|
||||
},
|
||||
decode: (input) => {
|
||||
if (!Array.isArray(input) || (input.length && typeof input[0] !== 'string'))
|
||||
throw new Error('alphabet.decode input should be array of strings');
|
||||
return input.map((letter) => {
|
||||
if (typeof letter !== 'string')
|
||||
throw new Error(`alphabet.decode: not string element=${letter}`);
|
||||
const index = alphabet.indexOf(letter);
|
||||
if (index === -1)
|
||||
throw new Error(`Unknown letter: "${letter}". Allowed: ${alphabet}`);
|
||||
return index;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function join(separator = '') {
|
||||
if (typeof separator !== 'string')
|
||||
throw new Error('join separator should be string');
|
||||
return {
|
||||
encode: (from) => {
|
||||
if (!Array.isArray(from) || (from.length && typeof from[0] !== 'string'))
|
||||
throw new Error('join.encode input should be array of strings');
|
||||
for (let i of from)
|
||||
if (typeof i !== 'string')
|
||||
throw new Error(`join.encode: non-string input=${i}`);
|
||||
return from.join(separator);
|
||||
},
|
||||
decode: (to) => {
|
||||
if (typeof to !== 'string')
|
||||
throw new Error('join.decode input should be string');
|
||||
return to.split(separator);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Pad strings array so it has integer number of bits
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function padding(bits, chr = '=') {
|
||||
assertNumber(bits);
|
||||
if (typeof chr !== 'string')
|
||||
throw new Error('padding chr should be string');
|
||||
return {
|
||||
encode(data) {
|
||||
if (!Array.isArray(data) || (data.length && typeof data[0] !== 'string'))
|
||||
throw new Error('padding.encode input should be array of strings');
|
||||
for (let i of data)
|
||||
if (typeof i !== 'string')
|
||||
throw new Error(`padding.encode: non-string input=${i}`);
|
||||
while ((data.length * bits) % 8)
|
||||
data.push(chr);
|
||||
return data;
|
||||
},
|
||||
decode(input) {
|
||||
if (!Array.isArray(input) || (input.length && typeof input[0] !== 'string'))
|
||||
throw new Error('padding.encode input should be array of strings');
|
||||
for (let i of input)
|
||||
if (typeof i !== 'string')
|
||||
throw new Error(`padding.decode: non-string input=${i}`);
|
||||
let end = input.length;
|
||||
if ((end * bits) % 8)
|
||||
throw new Error('Invalid padding: string should have whole number of bytes');
|
||||
for (; end > 0 && input[end - 1] === chr; end--) {
|
||||
if (!(((end - 1) * bits) % 8))
|
||||
throw new Error('Invalid padding: string has too much padding');
|
||||
}
|
||||
return input.slice(0, end);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function normalize(fn) {
|
||||
if (typeof fn !== 'function')
|
||||
throw new Error('normalize fn should be function');
|
||||
return { encode: (from) => from, decode: (to) => fn(to) };
|
||||
}
|
||||
/**
|
||||
* Slow: O(n^2) time complexity
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function convertRadix(data, from, to) {
|
||||
// base 1 is impossible
|
||||
if (from < 2)
|
||||
throw new Error(`convertRadix: wrong from=${from}, base cannot be less than 2`);
|
||||
if (to < 2)
|
||||
throw new Error(`convertRadix: wrong to=${to}, base cannot be less than 2`);
|
||||
if (!Array.isArray(data))
|
||||
throw new Error('convertRadix: data should be array');
|
||||
if (!data.length)
|
||||
return [];
|
||||
let pos = 0;
|
||||
const res = [];
|
||||
const digits = Array.from(data);
|
||||
digits.forEach((d) => {
|
||||
assertNumber(d);
|
||||
if (d < 0 || d >= from)
|
||||
throw new Error(`Wrong integer: ${d}`);
|
||||
});
|
||||
while (true) {
|
||||
let carry = 0;
|
||||
let done = true;
|
||||
for (let i = pos; i < digits.length; i++) {
|
||||
const digit = digits[i];
|
||||
const digitBase = from * carry + digit;
|
||||
if (!Number.isSafeInteger(digitBase) ||
|
||||
(from * carry) / from !== carry ||
|
||||
digitBase - digit !== from * carry) {
|
||||
throw new Error('convertRadix: carry overflow');
|
||||
}
|
||||
carry = digitBase % to;
|
||||
const rounded = Math.floor(digitBase / to);
|
||||
digits[i] = rounded;
|
||||
if (!Number.isSafeInteger(rounded) || rounded * to + carry !== digitBase)
|
||||
throw new Error('convertRadix: carry overflow');
|
||||
if (!done)
|
||||
continue;
|
||||
else if (!rounded)
|
||||
pos = i;
|
||||
else
|
||||
done = false;
|
||||
}
|
||||
res.push(carry);
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
for (let i = 0; i < data.length - 1 && data[i] === 0; i++)
|
||||
res.push(0);
|
||||
return res.reverse();
|
||||
}
|
||||
const gcd = /* @__NO_SIDE_EFFECTS__ */ (a, b) => (!b ? a : gcd(b, a % b));
|
||||
const radix2carry = /*@__NO_SIDE_EFFECTS__ */ (from, to) => from + (to - gcd(from, to));
|
||||
/**
|
||||
* Implemented with numbers, because BigInt is 5x slower
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function convertRadix2(data, from, to, padding) {
|
||||
if (!Array.isArray(data))
|
||||
throw new Error('convertRadix2: data should be array');
|
||||
if (from <= 0 || from > 32)
|
||||
throw new Error(`convertRadix2: wrong from=${from}`);
|
||||
if (to <= 0 || to > 32)
|
||||
throw new Error(`convertRadix2: wrong to=${to}`);
|
||||
if (radix2carry(from, to) > 32) {
|
||||
throw new Error(`convertRadix2: carry overflow from=${from} to=${to} carryBits=${radix2carry(from, to)}`);
|
||||
}
|
||||
let carry = 0;
|
||||
let pos = 0; // bitwise position in current element
|
||||
const mask = 2 ** to - 1;
|
||||
const res = [];
|
||||
for (const n of data) {
|
||||
assertNumber(n);
|
||||
if (n >= 2 ** from)
|
||||
throw new Error(`convertRadix2: invalid data word=${n} from=${from}`);
|
||||
carry = (carry << from) | n;
|
||||
if (pos + from > 32)
|
||||
throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
|
||||
pos += from;
|
||||
for (; pos >= to; pos -= to)
|
||||
res.push(((carry >> (pos - to)) & mask) >>> 0);
|
||||
carry &= 2 ** pos - 1; // clean carry, otherwise it will cause overflow
|
||||
}
|
||||
carry = (carry << (to - pos)) & mask;
|
||||
if (!padding && pos >= from)
|
||||
throw new Error('Excess padding');
|
||||
if (!padding && carry)
|
||||
throw new Error(`Non-zero padding: ${carry}`);
|
||||
if (padding && pos > 0)
|
||||
res.push(carry >>> 0);
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function radix(num) {
|
||||
assertNumber(num);
|
||||
return {
|
||||
encode: (bytes) => {
|
||||
if (!(bytes instanceof Uint8Array))
|
||||
throw new Error('radix.encode input should be Uint8Array');
|
||||
return convertRadix(Array.from(bytes), 2 ** 8, num);
|
||||
},
|
||||
decode: (digits) => {
|
||||
if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
|
||||
throw new Error('radix.decode input should be array of strings');
|
||||
return Uint8Array.from(convertRadix(digits, num, 2 ** 8));
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* If both bases are power of same number (like `2**8 <-> 2**64`),
|
||||
* there is a linear algorithm. For now we have implementation for power-of-two bases only.
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function radix2(bits, revPadding = false) {
|
||||
assertNumber(bits);
|
||||
if (bits <= 0 || bits > 32)
|
||||
throw new Error('radix2: bits should be in (0..32]');
|
||||
if (radix2carry(8, bits) > 32 || radix2carry(bits, 8) > 32)
|
||||
throw new Error('radix2: carry overflow');
|
||||
return {
|
||||
encode: (bytes) => {
|
||||
if (!(bytes instanceof Uint8Array))
|
||||
throw new Error('radix2.encode input should be Uint8Array');
|
||||
return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
|
||||
},
|
||||
decode: (digits) => {
|
||||
if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
|
||||
throw new Error('radix2.decode input should be array of strings');
|
||||
return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function unsafeWrapper(fn) {
|
||||
if (typeof fn !== 'function')
|
||||
throw new Error('unsafeWrapper fn should be function');
|
||||
return function (...args) {
|
||||
try {
|
||||
return fn.apply(null, args);
|
||||
}
|
||||
catch (e) { }
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function checksum(len, fn) {
|
||||
assertNumber(len);
|
||||
if (typeof fn !== 'function')
|
||||
throw new Error('checksum fn should be function');
|
||||
return {
|
||||
encode(data) {
|
||||
if (!(data instanceof Uint8Array))
|
||||
throw new Error('checksum.encode: input should be Uint8Array');
|
||||
const checksum = fn(data).slice(0, len);
|
||||
const res = new Uint8Array(data.length + len);
|
||||
res.set(data);
|
||||
res.set(checksum, data.length);
|
||||
return res;
|
||||
},
|
||||
decode(data) {
|
||||
if (!(data instanceof Uint8Array))
|
||||
throw new Error('checksum.decode: input should be Uint8Array');
|
||||
const payload = data.slice(0, -len);
|
||||
const newChecksum = fn(payload).slice(0, len);
|
||||
const oldChecksum = data.slice(-len);
|
||||
for (let i = 0; i < len; i++)
|
||||
if (newChecksum[i] !== oldChecksum[i])
|
||||
throw new Error('Invalid checksum');
|
||||
return payload;
|
||||
},
|
||||
};
|
||||
}
|
||||
export const utils = { alphabet, chain, checksum, radix, radix2, join, padding };
|
||||
// RFC 4648 aka RFC 3548
|
||||
// ---------------------
|
||||
export const base16 = /* @__PURE__ */ chain(radix2(4), alphabet('0123456789ABCDEF'), join(''));
|
||||
export const base32 = /* @__PURE__ */ chain(radix2(5), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'), padding(5), join(''));
|
||||
export const base32hex = /* @__PURE__ */ chain(radix2(5), alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'), padding(5), join(''));
|
||||
export const base32crockford = /* @__PURE__ */ chain(radix2(5), alphabet('0123456789ABCDEFGHJKMNPQRSTVWXYZ'), join(''), normalize((s) => s.toUpperCase().replace(/O/g, '0').replace(/[IL]/g, '1')));
|
||||
export const base64 = /* @__PURE__ */ chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'), padding(6), join(''));
|
||||
export const base64url = /* @__PURE__ */ chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'), padding(6), join(''));
|
||||
export const base64urlnopad = /* @__PURE__ */ chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'), join(''));
|
||||
// base58 code
|
||||
// -----------
|
||||
const genBase58 = (abc) => chain(radix(58), alphabet(abc), join(''));
|
||||
export const base58 = /* @__PURE__ */ genBase58('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
|
||||
export const base58flickr = /* @__PURE__ */ genBase58('123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ');
|
||||
export const base58xrp = /* @__PURE__ */ genBase58('rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz');
|
||||
// xmr ver is done in 8-byte blocks (which equals 11 chars in decoding). Last (non-full) block padded with '1' to size in XMR_BLOCK_LEN.
|
||||
// Block encoding significantly reduces quadratic complexity of base58.
|
||||
// Data len (index) -> encoded block len
|
||||
const XMR_BLOCK_LEN = [0, 2, 3, 5, 6, 7, 9, 10, 11];
|
||||
export const base58xmr = {
|
||||
encode(data) {
|
||||
let res = '';
|
||||
for (let i = 0; i < data.length; i += 8) {
|
||||
const block = data.subarray(i, i + 8);
|
||||
res += base58.encode(block).padStart(XMR_BLOCK_LEN[block.length], '1');
|
||||
}
|
||||
return res;
|
||||
},
|
||||
decode(str) {
|
||||
let res = [];
|
||||
for (let i = 0; i < str.length; i += 11) {
|
||||
const slice = str.slice(i, i + 11);
|
||||
const blockLen = XMR_BLOCK_LEN.indexOf(slice.length);
|
||||
const block = base58.decode(slice);
|
||||
for (let j = 0; j < block.length - blockLen; j++) {
|
||||
if (block[j] !== 0)
|
||||
throw new Error('base58xmr: wrong padding');
|
||||
}
|
||||
res = res.concat(Array.from(block.slice(block.length - blockLen)));
|
||||
}
|
||||
return Uint8Array.from(res);
|
||||
},
|
||||
};
|
||||
export const base58check = /* @__PURE__ */ (sha256) => chain(checksum(4, (data) => sha256(sha256(data))), base58);
|
||||
const BECH_ALPHABET = /* @__PURE__ */ chain(alphabet('qpzry9x8gf2tvdw0s3jn54khce6mua7l'), join(''));
|
||||
const POLYMOD_GENERATORS = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function bech32Polymod(pre) {
|
||||
const b = pre >> 25;
|
||||
let chk = (pre & 0x1ffffff) << 5;
|
||||
for (let i = 0; i < POLYMOD_GENERATORS.length; i++) {
|
||||
if (((b >> i) & 1) === 1)
|
||||
chk ^= POLYMOD_GENERATORS[i];
|
||||
}
|
||||
return chk;
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function bechChecksum(prefix, words, encodingConst = 1) {
|
||||
const len = prefix.length;
|
||||
let chk = 1;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const c = prefix.charCodeAt(i);
|
||||
if (c < 33 || c > 126)
|
||||
throw new Error(`Invalid prefix (${prefix})`);
|
||||
chk = bech32Polymod(chk) ^ (c >> 5);
|
||||
}
|
||||
chk = bech32Polymod(chk);
|
||||
for (let i = 0; i < len; i++)
|
||||
chk = bech32Polymod(chk) ^ (prefix.charCodeAt(i) & 0x1f);
|
||||
for (let v of words)
|
||||
chk = bech32Polymod(chk) ^ v;
|
||||
for (let i = 0; i < 6; i++)
|
||||
chk = bech32Polymod(chk);
|
||||
chk ^= encodingConst;
|
||||
return BECH_ALPHABET.encode(convertRadix2([chk % 2 ** 30], 30, 5, false));
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function genBech32(encoding) {
|
||||
const ENCODING_CONST = encoding === 'bech32' ? 1 : 0x2bc830a3;
|
||||
const _words = radix2(5);
|
||||
const fromWords = _words.decode;
|
||||
const toWords = _words.encode;
|
||||
const fromWordsUnsafe = unsafeWrapper(fromWords);
|
||||
function encode(prefix, words, limit = 90) {
|
||||
if (typeof prefix !== 'string')
|
||||
throw new Error(`bech32.encode prefix should be string, not ${typeof prefix}`);
|
||||
if (!Array.isArray(words) || (words.length && typeof words[0] !== 'number'))
|
||||
throw new Error(`bech32.encode words should be array of numbers, not ${typeof words}`);
|
||||
const actualLength = prefix.length + 7 + words.length;
|
||||
if (limit !== false && actualLength > limit)
|
||||
throw new TypeError(`Length ${actualLength} exceeds limit ${limit}`);
|
||||
const lowered = prefix.toLowerCase();
|
||||
const sum = bechChecksum(lowered, words, ENCODING_CONST);
|
||||
return `${lowered}1${BECH_ALPHABET.encode(words)}${sum}`;
|
||||
}
|
||||
function decode(str, limit = 90) {
|
||||
if (typeof str !== 'string')
|
||||
throw new Error(`bech32.decode input should be string, not ${typeof str}`);
|
||||
if (str.length < 8 || (limit !== false && str.length > limit))
|
||||
throw new TypeError(`Wrong string length: ${str.length} (${str}). Expected (8..${limit})`);
|
||||
// don't allow mixed case
|
||||
const lowered = str.toLowerCase();
|
||||
if (str !== lowered && str !== str.toUpperCase())
|
||||
throw new Error(`String must be lowercase or uppercase`);
|
||||
str = lowered;
|
||||
const sepIndex = str.lastIndexOf('1');
|
||||
if (sepIndex === 0 || sepIndex === -1)
|
||||
throw new Error(`Letter "1" must be present between prefix and data only`);
|
||||
const prefix = str.slice(0, sepIndex);
|
||||
const _words = str.slice(sepIndex + 1);
|
||||
if (_words.length < 6)
|
||||
throw new Error('Data must be at least 6 characters long');
|
||||
const words = BECH_ALPHABET.decode(_words).slice(0, -6);
|
||||
const sum = bechChecksum(prefix, words, ENCODING_CONST);
|
||||
if (!_words.endsWith(sum))
|
||||
throw new Error(`Invalid checksum in ${str}: expected "${sum}"`);
|
||||
return { prefix, words };
|
||||
}
|
||||
const decodeUnsafe = unsafeWrapper(decode);
|
||||
function decodeToBytes(str) {
|
||||
const { prefix, words } = decode(str, false);
|
||||
return { prefix, words, bytes: fromWords(words) };
|
||||
}
|
||||
return { encode, decode, decodeToBytes, decodeUnsafe, fromWords, fromWordsUnsafe, toWords };
|
||||
}
|
||||
export const bech32 = /* @__PURE__ */ genBech32('bech32');
|
||||
export const bech32m = /* @__PURE__ */ genBech32('bech32m');
|
||||
export const utf8 = {
|
||||
encode: (data) => new TextDecoder().decode(data),
|
||||
decode: (str) => new TextEncoder().encode(str),
|
||||
};
|
||||
export const hex = /* @__PURE__ */ chain(radix2(4), alphabet('0123456789abcdef'), join(''), normalize((s) => {
|
||||
if (typeof s !== 'string' || s.length % 2)
|
||||
throw new TypeError(`hex.decode: expected string, got ${typeof s} with length ${s.length}`);
|
||||
return s.toLowerCase();
|
||||
}));
|
||||
// prettier-ignore
|
||||
const CODERS = {
|
||||
utf8, hex, base16, base32, base64, base64url, base58, base58xmr
|
||||
};
|
||||
const coderTypeError = 'Invalid encoding type. Available types: utf8, hex, base16, base32, base64, base64url, base58, base58xmr';
|
||||
export const bytesToString = (type, bytes) => {
|
||||
if (typeof type !== 'string' || !CODERS.hasOwnProperty(type))
|
||||
throw new TypeError(coderTypeError);
|
||||
if (!(bytes instanceof Uint8Array))
|
||||
throw new TypeError('bytesToString() expects Uint8Array');
|
||||
return CODERS[type].encode(bytes);
|
||||
};
|
||||
export const str = bytesToString; // as in python, but for bytes only
|
||||
export const stringToBytes = (type, str) => {
|
||||
if (!CODERS.hasOwnProperty(type))
|
||||
throw new TypeError(coderTypeError);
|
||||
if (typeof str !== 'string')
|
||||
throw new TypeError('stringToBytes() expects string');
|
||||
return CODERS[type].decode(str);
|
||||
};
|
||||
export const bytes = stringToBytes;
|
||||
-1
@@ -1 +0,0 @@
|
||||
{ "type": "module", "sideEffects": false }
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
export declare function assertNumber(n: number): void;
|
||||
export interface Coder<F, T> {
|
||||
encode(from: F): T;
|
||||
decode(to: T): F;
|
||||
}
|
||||
export interface BytesCoder extends Coder<Uint8Array, string> {
|
||||
encode: (data: Uint8Array) => string;
|
||||
decode: (str: string) => Uint8Array;
|
||||
}
|
||||
type Chain = [Coder<any, any>, ...Coder<any, any>[]];
|
||||
type Input<F> = F extends Coder<infer T, any> ? T : never;
|
||||
type Output<F> = F extends Coder<any, infer T> ? T : never;
|
||||
type First<T> = T extends [infer U, ...any[]] ? U : never;
|
||||
type Last<T> = T extends [...any[], infer U] ? U : never;
|
||||
type Tail<T> = T extends [any, ...infer U] ? U : never;
|
||||
type AsChain<C extends Chain, Rest = Tail<C>> = {
|
||||
[K in keyof C]: Coder<Input<C[K]>, Input<K extends keyof Rest ? Rest[K] : any>>;
|
||||
};
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
declare function chain<T extends Chain & AsChain<T>>(...args: T): Coder<Input<First<T>>, Output<Last<T>>>;
|
||||
type Alphabet = string[] | string;
|
||||
/**
|
||||
* Encodes integer radix representation to array of strings using alphabet and back
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
declare function alphabet(alphabet: Alphabet): Coder<number[], string[]>;
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
declare function join(separator?: string): Coder<string[], string>;
|
||||
/**
|
||||
* Pad strings array so it has integer number of bits
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
declare function padding(bits: number, chr?: string): Coder<string[], string[]>;
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
declare function radix(num: number): Coder<Uint8Array, number[]>;
|
||||
/**
|
||||
* If both bases are power of same number (like `2**8 <-> 2**64`),
|
||||
* there is a linear algorithm. For now we have implementation for power-of-two bases only.
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
declare function radix2(bits: number, revPadding?: boolean): Coder<Uint8Array, number[]>;
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
declare function checksum(len: number, fn: (data: Uint8Array) => Uint8Array): Coder<Uint8Array, Uint8Array>;
|
||||
export declare const utils: {
|
||||
alphabet: typeof alphabet;
|
||||
chain: typeof chain;
|
||||
checksum: typeof checksum;
|
||||
radix: typeof radix;
|
||||
radix2: typeof radix2;
|
||||
join: typeof join;
|
||||
padding: typeof padding;
|
||||
};
|
||||
export declare const base16: BytesCoder;
|
||||
export declare const base32: BytesCoder;
|
||||
export declare const base32hex: BytesCoder;
|
||||
export declare const base32crockford: BytesCoder;
|
||||
export declare const base64: BytesCoder;
|
||||
export declare const base64url: BytesCoder;
|
||||
export declare const base64urlnopad: BytesCoder;
|
||||
export declare const base58: BytesCoder;
|
||||
export declare const base58flickr: BytesCoder;
|
||||
export declare const base58xrp: BytesCoder;
|
||||
export declare const base58xmr: BytesCoder;
|
||||
export declare const base58check: (sha256: (data: Uint8Array) => Uint8Array) => BytesCoder;
|
||||
export interface Bech32Decoded<Prefix extends string = string> {
|
||||
prefix: Prefix;
|
||||
words: number[];
|
||||
}
|
||||
export interface Bech32DecodedWithArray<Prefix extends string = string> {
|
||||
prefix: Prefix;
|
||||
words: number[];
|
||||
bytes: Uint8Array;
|
||||
}
|
||||
export declare const bech32: {
|
||||
encode: <Prefix extends string>(prefix: Prefix, words: number[] | Uint8Array, limit?: number | false) => `${Lowercase<Prefix>}1${string}`;
|
||||
decode: {
|
||||
<Prefix_1 extends string>(str: `${Prefix_1}1${string}`, limit?: number | false): Bech32Decoded<Prefix_1>;
|
||||
(str: string, limit?: number | false): Bech32Decoded;
|
||||
};
|
||||
decodeToBytes: (str: string) => Bech32DecodedWithArray;
|
||||
decodeUnsafe: (str: string, limit?: number | false | undefined) => void | Bech32Decoded<string>;
|
||||
fromWords: (to: number[]) => Uint8Array;
|
||||
fromWordsUnsafe: (to: number[]) => void | Uint8Array;
|
||||
toWords: (from: Uint8Array) => number[];
|
||||
};
|
||||
export declare const bech32m: {
|
||||
encode: <Prefix extends string>(prefix: Prefix, words: number[] | Uint8Array, limit?: number | false) => `${Lowercase<Prefix>}1${string}`;
|
||||
decode: {
|
||||
<Prefix_1 extends string>(str: `${Prefix_1}1${string}`, limit?: number | false): Bech32Decoded<Prefix_1>;
|
||||
(str: string, limit?: number | false): Bech32Decoded;
|
||||
};
|
||||
decodeToBytes: (str: string) => Bech32DecodedWithArray;
|
||||
decodeUnsafe: (str: string, limit?: number | false | undefined) => void | Bech32Decoded<string>;
|
||||
fromWords: (to: number[]) => Uint8Array;
|
||||
fromWordsUnsafe: (to: number[]) => void | Uint8Array;
|
||||
toWords: (from: Uint8Array) => number[];
|
||||
};
|
||||
export declare const utf8: BytesCoder;
|
||||
export declare const hex: BytesCoder;
|
||||
declare const CODERS: {
|
||||
utf8: BytesCoder;
|
||||
hex: BytesCoder;
|
||||
base16: BytesCoder;
|
||||
base32: BytesCoder;
|
||||
base64: BytesCoder;
|
||||
base64url: BytesCoder;
|
||||
base58: BytesCoder;
|
||||
base58xmr: BytesCoder;
|
||||
};
|
||||
type CoderType = keyof typeof CODERS;
|
||||
export declare const bytesToString: (type: CoderType, bytes: Uint8Array) => string;
|
||||
export declare const str: (type: CoderType, bytes: Uint8Array) => string;
|
||||
export declare const stringToBytes: (type: CoderType, str: string) => Uint8Array;
|
||||
export declare const bytes: (type: CoderType, str: string) => Uint8Array;
|
||||
export {};
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAGpE;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,QAErC;AACD,MAAM,WAAW,KAAK,CAAC,CAAC,EAAE,CAAC;IACzB,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;IACnB,MAAM,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;CAClB;AAED,MAAM,WAAW,UAAW,SAAQ,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC;IAC3D,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC;IACrC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC;CACrC;AAID,KAAK,KAAK,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;AAErD,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAC1D,KAAK,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE3D,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAC1D,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AACzD,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAEvD,KAAK,OAAO,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI;KAE7C,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,SAAS,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;CAChF,CAAC;AAEF;;GAEG;AACH,iBAAS,KAAK,CAAC,CAAC,SAAS,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAahG;AAED,KAAK,QAAQ,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC;AAElC;;;GAGG;AACH,iBAAS,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAwB/D;AAED;;GAEG;AACH,iBAAS,IAAI,CAAC,SAAS,SAAK,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAerD;AAED;;;GAGG;AACH,iBAAS,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAM,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CA2BnE;AA4FD;;GAEG;AACH,iBAAS,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAcvD;AAED;;;;GAIG;AACH,iBAAS,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAiB7E;AAeD;;GAEG;AACH,iBAAS,QAAQ,CACf,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,UAAU,GACnC,KAAK,CAAC,UAAU,EAAE,UAAU,CAAC,CAwB/B;AACD,eAAO,MAAM,KAAK;;;;;;;;CAA8D,CAAC;AAIjF,eAAO,MAAM,MAAM,EAAE,UAIpB,CAAC;AACF,eAAO,MAAM,MAAM,EAAE,UAKpB,CAAC;AACF,eAAO,MAAM,SAAS,EAAE,UAKvB,CAAC;AACF,eAAO,MAAM,eAAe,EAAE,UAK7B,CAAC;AACF,eAAO,MAAM,MAAM,EAAE,UAKpB,CAAC;AACF,eAAO,MAAM,SAAS,EAAE,UAKvB,CAAC;AACF,eAAO,MAAM,cAAc,EAAE,UAI5B,CAAC;AAMF,eAAO,MAAM,MAAM,EAAE,UAEpB,CAAC;AACF,eAAO,MAAM,YAAY,EAAE,UAE1B,CAAC;AACF,eAAO,MAAM,SAAS,EAAE,UAEvB,CAAC;AAOF,eAAO,MAAM,SAAS,EAAE,UAsBvB,CAAC;AAEF,eAAO,MAAM,WAAW,kBAAmC,UAAU,KAAK,UAAU,KAAG,UAIpF,CAAC;AAIJ,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AACD,MAAM,WAAW,sBAAsB,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,UAAU,CAAC;CACnB;AAuGD,eAAO,MAAM,MAAM;2DApDR,MAAM,EAAE,GAAG,UAAU,UACrB,MAAM,GAAG,KAAK;;wEAgBb,MAAM,GAAG,KAAK;cAEH,MAAM,UAAU,MAAM,GAAG,KAAK,GAAG,aAAa;;yBAyBvC,MAAM,KAAG,sBAAsB;;;;;CAQJ,CAAC;AAC1D,eAAO,MAAM,OAAO;2DArDT,MAAM,EAAE,GAAG,UAAU,UACrB,MAAM,GAAG,KAAK;;wEAgBb,MAAM,GAAG,KAAK;cAEH,MAAM,UAAU,MAAM,GAAG,KAAK,GAAG,aAAa;;yBAyBvC,MAAM,KAAG,sBAAsB;;;;;CASF,CAAC;AAK5D,eAAO,MAAM,IAAI,EAAE,UAGlB,CAAC;AAEF,eAAO,MAAM,GAAG,EAAE,UASjB,CAAC;AAGF,QAAA,MAAM,MAAM;;;;;;;;;CAEX,CAAC;AACF,KAAK,SAAS,GAAG,MAAM,OAAO,MAAM,CAAC;AAIrC,eAAO,MAAM,aAAa,SAAU,SAAS,SAAS,UAAU,KAAG,MAIlE,CAAC;AACF,eAAO,MAAM,GAAG,SALoB,SAAS,SAAS,UAAU,KAAG,MAKnC,CAAC;AAEjC,eAAO,MAAM,aAAa,SAAU,SAAS,OAAO,MAAM,KAAG,UAI5D,CAAC;AACF,eAAO,MAAM,KAAK,SALkB,SAAS,OAAO,MAAM,KAAG,UAK3B,CAAC"}
|
||||
-469
@@ -1,469 +0,0 @@
|
||||
"use strict";
|
||||
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.bytes = exports.stringToBytes = exports.str = exports.bytesToString = exports.hex = exports.utf8 = exports.bech32m = exports.bech32 = exports.base58check = exports.base58xmr = exports.base58xrp = exports.base58flickr = exports.base58 = exports.base64urlnopad = exports.base64url = exports.base64 = exports.base32crockford = exports.base32hex = exports.base32 = exports.base16 = exports.utils = exports.assertNumber = void 0;
|
||||
// Utilities
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function assertNumber(n) {
|
||||
if (!Number.isSafeInteger(n))
|
||||
throw new Error(`Wrong integer: ${n}`);
|
||||
}
|
||||
exports.assertNumber = assertNumber;
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function chain(...args) {
|
||||
// Wrap call in closure so JIT can inline calls
|
||||
const wrap = (a, b) => (c) => a(b(c));
|
||||
// Construct chain of args[-1].encode(args[-2].encode([...]))
|
||||
const encode = Array.from(args)
|
||||
.reverse()
|
||||
.reduce((acc, i) => (acc ? wrap(acc, i.encode) : i.encode), undefined);
|
||||
// Construct chain of args[0].decode(args[1].decode(...))
|
||||
const decode = args.reduce((acc, i) => (acc ? wrap(acc, i.decode) : i.decode), undefined);
|
||||
return { encode, decode };
|
||||
}
|
||||
/**
|
||||
* Encodes integer radix representation to array of strings using alphabet and back
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function alphabet(alphabet) {
|
||||
return {
|
||||
encode: (digits) => {
|
||||
if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
|
||||
throw new Error('alphabet.encode input should be an array of numbers');
|
||||
return digits.map((i) => {
|
||||
assertNumber(i);
|
||||
if (i < 0 || i >= alphabet.length)
|
||||
throw new Error(`Digit index outside alphabet: ${i} (alphabet: ${alphabet.length})`);
|
||||
return alphabet[i];
|
||||
});
|
||||
},
|
||||
decode: (input) => {
|
||||
if (!Array.isArray(input) || (input.length && typeof input[0] !== 'string'))
|
||||
throw new Error('alphabet.decode input should be array of strings');
|
||||
return input.map((letter) => {
|
||||
if (typeof letter !== 'string')
|
||||
throw new Error(`alphabet.decode: not string element=${letter}`);
|
||||
const index = alphabet.indexOf(letter);
|
||||
if (index === -1)
|
||||
throw new Error(`Unknown letter: "${letter}". Allowed: ${alphabet}`);
|
||||
return index;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function join(separator = '') {
|
||||
if (typeof separator !== 'string')
|
||||
throw new Error('join separator should be string');
|
||||
return {
|
||||
encode: (from) => {
|
||||
if (!Array.isArray(from) || (from.length && typeof from[0] !== 'string'))
|
||||
throw new Error('join.encode input should be array of strings');
|
||||
for (let i of from)
|
||||
if (typeof i !== 'string')
|
||||
throw new Error(`join.encode: non-string input=${i}`);
|
||||
return from.join(separator);
|
||||
},
|
||||
decode: (to) => {
|
||||
if (typeof to !== 'string')
|
||||
throw new Error('join.decode input should be string');
|
||||
return to.split(separator);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Pad strings array so it has integer number of bits
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function padding(bits, chr = '=') {
|
||||
assertNumber(bits);
|
||||
if (typeof chr !== 'string')
|
||||
throw new Error('padding chr should be string');
|
||||
return {
|
||||
encode(data) {
|
||||
if (!Array.isArray(data) || (data.length && typeof data[0] !== 'string'))
|
||||
throw new Error('padding.encode input should be array of strings');
|
||||
for (let i of data)
|
||||
if (typeof i !== 'string')
|
||||
throw new Error(`padding.encode: non-string input=${i}`);
|
||||
while ((data.length * bits) % 8)
|
||||
data.push(chr);
|
||||
return data;
|
||||
},
|
||||
decode(input) {
|
||||
if (!Array.isArray(input) || (input.length && typeof input[0] !== 'string'))
|
||||
throw new Error('padding.encode input should be array of strings');
|
||||
for (let i of input)
|
||||
if (typeof i !== 'string')
|
||||
throw new Error(`padding.decode: non-string input=${i}`);
|
||||
let end = input.length;
|
||||
if ((end * bits) % 8)
|
||||
throw new Error('Invalid padding: string should have whole number of bytes');
|
||||
for (; end > 0 && input[end - 1] === chr; end--) {
|
||||
if (!(((end - 1) * bits) % 8))
|
||||
throw new Error('Invalid padding: string has too much padding');
|
||||
}
|
||||
return input.slice(0, end);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function normalize(fn) {
|
||||
if (typeof fn !== 'function')
|
||||
throw new Error('normalize fn should be function');
|
||||
return { encode: (from) => from, decode: (to) => fn(to) };
|
||||
}
|
||||
/**
|
||||
* Slow: O(n^2) time complexity
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function convertRadix(data, from, to) {
|
||||
// base 1 is impossible
|
||||
if (from < 2)
|
||||
throw new Error(`convertRadix: wrong from=${from}, base cannot be less than 2`);
|
||||
if (to < 2)
|
||||
throw new Error(`convertRadix: wrong to=${to}, base cannot be less than 2`);
|
||||
if (!Array.isArray(data))
|
||||
throw new Error('convertRadix: data should be array');
|
||||
if (!data.length)
|
||||
return [];
|
||||
let pos = 0;
|
||||
const res = [];
|
||||
const digits = Array.from(data);
|
||||
digits.forEach((d) => {
|
||||
assertNumber(d);
|
||||
if (d < 0 || d >= from)
|
||||
throw new Error(`Wrong integer: ${d}`);
|
||||
});
|
||||
while (true) {
|
||||
let carry = 0;
|
||||
let done = true;
|
||||
for (let i = pos; i < digits.length; i++) {
|
||||
const digit = digits[i];
|
||||
const digitBase = from * carry + digit;
|
||||
if (!Number.isSafeInteger(digitBase) ||
|
||||
(from * carry) / from !== carry ||
|
||||
digitBase - digit !== from * carry) {
|
||||
throw new Error('convertRadix: carry overflow');
|
||||
}
|
||||
carry = digitBase % to;
|
||||
const rounded = Math.floor(digitBase / to);
|
||||
digits[i] = rounded;
|
||||
if (!Number.isSafeInteger(rounded) || rounded * to + carry !== digitBase)
|
||||
throw new Error('convertRadix: carry overflow');
|
||||
if (!done)
|
||||
continue;
|
||||
else if (!rounded)
|
||||
pos = i;
|
||||
else
|
||||
done = false;
|
||||
}
|
||||
res.push(carry);
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
for (let i = 0; i < data.length - 1 && data[i] === 0; i++)
|
||||
res.push(0);
|
||||
return res.reverse();
|
||||
}
|
||||
const gcd = /* @__NO_SIDE_EFFECTS__ */ (a, b) => (!b ? a : gcd(b, a % b));
|
||||
const radix2carry = /*@__NO_SIDE_EFFECTS__ */ (from, to) => from + (to - gcd(from, to));
|
||||
/**
|
||||
* Implemented with numbers, because BigInt is 5x slower
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function convertRadix2(data, from, to, padding) {
|
||||
if (!Array.isArray(data))
|
||||
throw new Error('convertRadix2: data should be array');
|
||||
if (from <= 0 || from > 32)
|
||||
throw new Error(`convertRadix2: wrong from=${from}`);
|
||||
if (to <= 0 || to > 32)
|
||||
throw new Error(`convertRadix2: wrong to=${to}`);
|
||||
if (radix2carry(from, to) > 32) {
|
||||
throw new Error(`convertRadix2: carry overflow from=${from} to=${to} carryBits=${radix2carry(from, to)}`);
|
||||
}
|
||||
let carry = 0;
|
||||
let pos = 0; // bitwise position in current element
|
||||
const mask = 2 ** to - 1;
|
||||
const res = [];
|
||||
for (const n of data) {
|
||||
assertNumber(n);
|
||||
if (n >= 2 ** from)
|
||||
throw new Error(`convertRadix2: invalid data word=${n} from=${from}`);
|
||||
carry = (carry << from) | n;
|
||||
if (pos + from > 32)
|
||||
throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
|
||||
pos += from;
|
||||
for (; pos >= to; pos -= to)
|
||||
res.push(((carry >> (pos - to)) & mask) >>> 0);
|
||||
carry &= 2 ** pos - 1; // clean carry, otherwise it will cause overflow
|
||||
}
|
||||
carry = (carry << (to - pos)) & mask;
|
||||
if (!padding && pos >= from)
|
||||
throw new Error('Excess padding');
|
||||
if (!padding && carry)
|
||||
throw new Error(`Non-zero padding: ${carry}`);
|
||||
if (padding && pos > 0)
|
||||
res.push(carry >>> 0);
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function radix(num) {
|
||||
assertNumber(num);
|
||||
return {
|
||||
encode: (bytes) => {
|
||||
if (!(bytes instanceof Uint8Array))
|
||||
throw new Error('radix.encode input should be Uint8Array');
|
||||
return convertRadix(Array.from(bytes), 2 ** 8, num);
|
||||
},
|
||||
decode: (digits) => {
|
||||
if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
|
||||
throw new Error('radix.decode input should be array of strings');
|
||||
return Uint8Array.from(convertRadix(digits, num, 2 ** 8));
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* If both bases are power of same number (like `2**8 <-> 2**64`),
|
||||
* there is a linear algorithm. For now we have implementation for power-of-two bases only.
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function radix2(bits, revPadding = false) {
|
||||
assertNumber(bits);
|
||||
if (bits <= 0 || bits > 32)
|
||||
throw new Error('radix2: bits should be in (0..32]');
|
||||
if (radix2carry(8, bits) > 32 || radix2carry(bits, 8) > 32)
|
||||
throw new Error('radix2: carry overflow');
|
||||
return {
|
||||
encode: (bytes) => {
|
||||
if (!(bytes instanceof Uint8Array))
|
||||
throw new Error('radix2.encode input should be Uint8Array');
|
||||
return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
|
||||
},
|
||||
decode: (digits) => {
|
||||
if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
|
||||
throw new Error('radix2.decode input should be array of strings');
|
||||
return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function unsafeWrapper(fn) {
|
||||
if (typeof fn !== 'function')
|
||||
throw new Error('unsafeWrapper fn should be function');
|
||||
return function (...args) {
|
||||
try {
|
||||
return fn.apply(null, args);
|
||||
}
|
||||
catch (e) { }
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function checksum(len, fn) {
|
||||
assertNumber(len);
|
||||
if (typeof fn !== 'function')
|
||||
throw new Error('checksum fn should be function');
|
||||
return {
|
||||
encode(data) {
|
||||
if (!(data instanceof Uint8Array))
|
||||
throw new Error('checksum.encode: input should be Uint8Array');
|
||||
const checksum = fn(data).slice(0, len);
|
||||
const res = new Uint8Array(data.length + len);
|
||||
res.set(data);
|
||||
res.set(checksum, data.length);
|
||||
return res;
|
||||
},
|
||||
decode(data) {
|
||||
if (!(data instanceof Uint8Array))
|
||||
throw new Error('checksum.decode: input should be Uint8Array');
|
||||
const payload = data.slice(0, -len);
|
||||
const newChecksum = fn(payload).slice(0, len);
|
||||
const oldChecksum = data.slice(-len);
|
||||
for (let i = 0; i < len; i++)
|
||||
if (newChecksum[i] !== oldChecksum[i])
|
||||
throw new Error('Invalid checksum');
|
||||
return payload;
|
||||
},
|
||||
};
|
||||
}
|
||||
exports.utils = { alphabet, chain, checksum, radix, radix2, join, padding };
|
||||
// RFC 4648 aka RFC 3548
|
||||
// ---------------------
|
||||
exports.base16 = chain(radix2(4), alphabet('0123456789ABCDEF'), join(''));
|
||||
exports.base32 = chain(radix2(5), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'), padding(5), join(''));
|
||||
exports.base32hex = chain(radix2(5), alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'), padding(5), join(''));
|
||||
exports.base32crockford = chain(radix2(5), alphabet('0123456789ABCDEFGHJKMNPQRSTVWXYZ'), join(''), normalize((s) => s.toUpperCase().replace(/O/g, '0').replace(/[IL]/g, '1')));
|
||||
exports.base64 = chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'), padding(6), join(''));
|
||||
exports.base64url = chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'), padding(6), join(''));
|
||||
exports.base64urlnopad = chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'), join(''));
|
||||
// base58 code
|
||||
// -----------
|
||||
const genBase58 = (abc) => chain(radix(58), alphabet(abc), join(''));
|
||||
exports.base58 = genBase58('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
|
||||
exports.base58flickr = genBase58('123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ');
|
||||
exports.base58xrp = genBase58('rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz');
|
||||
// xmr ver is done in 8-byte blocks (which equals 11 chars in decoding). Last (non-full) block padded with '1' to size in XMR_BLOCK_LEN.
|
||||
// Block encoding significantly reduces quadratic complexity of base58.
|
||||
// Data len (index) -> encoded block len
|
||||
const XMR_BLOCK_LEN = [0, 2, 3, 5, 6, 7, 9, 10, 11];
|
||||
exports.base58xmr = {
|
||||
encode(data) {
|
||||
let res = '';
|
||||
for (let i = 0; i < data.length; i += 8) {
|
||||
const block = data.subarray(i, i + 8);
|
||||
res += exports.base58.encode(block).padStart(XMR_BLOCK_LEN[block.length], '1');
|
||||
}
|
||||
return res;
|
||||
},
|
||||
decode(str) {
|
||||
let res = [];
|
||||
for (let i = 0; i < str.length; i += 11) {
|
||||
const slice = str.slice(i, i + 11);
|
||||
const blockLen = XMR_BLOCK_LEN.indexOf(slice.length);
|
||||
const block = exports.base58.decode(slice);
|
||||
for (let j = 0; j < block.length - blockLen; j++) {
|
||||
if (block[j] !== 0)
|
||||
throw new Error('base58xmr: wrong padding');
|
||||
}
|
||||
res = res.concat(Array.from(block.slice(block.length - blockLen)));
|
||||
}
|
||||
return Uint8Array.from(res);
|
||||
},
|
||||
};
|
||||
const base58check = (sha256) => chain(checksum(4, (data) => sha256(sha256(data))), exports.base58);
|
||||
exports.base58check = base58check;
|
||||
const BECH_ALPHABET = /* @__PURE__ */ chain(alphabet('qpzry9x8gf2tvdw0s3jn54khce6mua7l'), join(''));
|
||||
const POLYMOD_GENERATORS = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function bech32Polymod(pre) {
|
||||
const b = pre >> 25;
|
||||
let chk = (pre & 0x1ffffff) << 5;
|
||||
for (let i = 0; i < POLYMOD_GENERATORS.length; i++) {
|
||||
if (((b >> i) & 1) === 1)
|
||||
chk ^= POLYMOD_GENERATORS[i];
|
||||
}
|
||||
return chk;
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function bechChecksum(prefix, words, encodingConst = 1) {
|
||||
const len = prefix.length;
|
||||
let chk = 1;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const c = prefix.charCodeAt(i);
|
||||
if (c < 33 || c > 126)
|
||||
throw new Error(`Invalid prefix (${prefix})`);
|
||||
chk = bech32Polymod(chk) ^ (c >> 5);
|
||||
}
|
||||
chk = bech32Polymod(chk);
|
||||
for (let i = 0; i < len; i++)
|
||||
chk = bech32Polymod(chk) ^ (prefix.charCodeAt(i) & 0x1f);
|
||||
for (let v of words)
|
||||
chk = bech32Polymod(chk) ^ v;
|
||||
for (let i = 0; i < 6; i++)
|
||||
chk = bech32Polymod(chk);
|
||||
chk ^= encodingConst;
|
||||
return BECH_ALPHABET.encode(convertRadix2([chk % 2 ** 30], 30, 5, false));
|
||||
}
|
||||
/**
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
function genBech32(encoding) {
|
||||
const ENCODING_CONST = encoding === 'bech32' ? 1 : 0x2bc830a3;
|
||||
const _words = radix2(5);
|
||||
const fromWords = _words.decode;
|
||||
const toWords = _words.encode;
|
||||
const fromWordsUnsafe = unsafeWrapper(fromWords);
|
||||
function encode(prefix, words, limit = 90) {
|
||||
if (typeof prefix !== 'string')
|
||||
throw new Error(`bech32.encode prefix should be string, not ${typeof prefix}`);
|
||||
if (!Array.isArray(words) || (words.length && typeof words[0] !== 'number'))
|
||||
throw new Error(`bech32.encode words should be array of numbers, not ${typeof words}`);
|
||||
const actualLength = prefix.length + 7 + words.length;
|
||||
if (limit !== false && actualLength > limit)
|
||||
throw new TypeError(`Length ${actualLength} exceeds limit ${limit}`);
|
||||
const lowered = prefix.toLowerCase();
|
||||
const sum = bechChecksum(lowered, words, ENCODING_CONST);
|
||||
return `${lowered}1${BECH_ALPHABET.encode(words)}${sum}`;
|
||||
}
|
||||
function decode(str, limit = 90) {
|
||||
if (typeof str !== 'string')
|
||||
throw new Error(`bech32.decode input should be string, not ${typeof str}`);
|
||||
if (str.length < 8 || (limit !== false && str.length > limit))
|
||||
throw new TypeError(`Wrong string length: ${str.length} (${str}). Expected (8..${limit})`);
|
||||
// don't allow mixed case
|
||||
const lowered = str.toLowerCase();
|
||||
if (str !== lowered && str !== str.toUpperCase())
|
||||
throw new Error(`String must be lowercase or uppercase`);
|
||||
str = lowered;
|
||||
const sepIndex = str.lastIndexOf('1');
|
||||
if (sepIndex === 0 || sepIndex === -1)
|
||||
throw new Error(`Letter "1" must be present between prefix and data only`);
|
||||
const prefix = str.slice(0, sepIndex);
|
||||
const _words = str.slice(sepIndex + 1);
|
||||
if (_words.length < 6)
|
||||
throw new Error('Data must be at least 6 characters long');
|
||||
const words = BECH_ALPHABET.decode(_words).slice(0, -6);
|
||||
const sum = bechChecksum(prefix, words, ENCODING_CONST);
|
||||
if (!_words.endsWith(sum))
|
||||
throw new Error(`Invalid checksum in ${str}: expected "${sum}"`);
|
||||
return { prefix, words };
|
||||
}
|
||||
const decodeUnsafe = unsafeWrapper(decode);
|
||||
function decodeToBytes(str) {
|
||||
const { prefix, words } = decode(str, false);
|
||||
return { prefix, words, bytes: fromWords(words) };
|
||||
}
|
||||
return { encode, decode, decodeToBytes, decodeUnsafe, fromWords, fromWordsUnsafe, toWords };
|
||||
}
|
||||
exports.bech32 = genBech32('bech32');
|
||||
exports.bech32m = genBech32('bech32m');
|
||||
exports.utf8 = {
|
||||
encode: (data) => new TextDecoder().decode(data),
|
||||
decode: (str) => new TextEncoder().encode(str),
|
||||
};
|
||||
exports.hex = chain(radix2(4), alphabet('0123456789abcdef'), join(''), normalize((s) => {
|
||||
if (typeof s !== 'string' || s.length % 2)
|
||||
throw new TypeError(`hex.decode: expected string, got ${typeof s} with length ${s.length}`);
|
||||
return s.toLowerCase();
|
||||
}));
|
||||
// prettier-ignore
|
||||
const CODERS = {
|
||||
utf8: exports.utf8, hex: exports.hex, base16: exports.base16, base32: exports.base32, base64: exports.base64, base64url: exports.base64url, base58: exports.base58, base58xmr: exports.base58xmr
|
||||
};
|
||||
const coderTypeError = 'Invalid encoding type. Available types: utf8, hex, base16, base32, base64, base64url, base58, base58xmr';
|
||||
const bytesToString = (type, bytes) => {
|
||||
if (typeof type !== 'string' || !CODERS.hasOwnProperty(type))
|
||||
throw new TypeError(coderTypeError);
|
||||
if (!(bytes instanceof Uint8Array))
|
||||
throw new TypeError('bytesToString() expects Uint8Array');
|
||||
return CODERS[type].encode(bytes);
|
||||
};
|
||||
exports.bytesToString = bytesToString;
|
||||
exports.str = exports.bytesToString; // as in python, but for bytes only
|
||||
const stringToBytes = (type, str) => {
|
||||
if (!CODERS.hasOwnProperty(type))
|
||||
throw new TypeError(coderTypeError);
|
||||
if (typeof str !== 'string')
|
||||
throw new TypeError('stringToBytes() expects string');
|
||||
return CODERS[type].decode(str);
|
||||
};
|
||||
exports.stringToBytes = stringToBytes;
|
||||
exports.bytes = exports.stringToBytes;
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"name": "@scure/base",
|
||||
"version": "1.1.3",
|
||||
"description": "Secure, audited & 0-dep implementation of base64, bech32, base58, base32 & base16",
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/esm/index.js",
|
||||
"lib/esm/package.json",
|
||||
"lib/index.d.ts",
|
||||
"lib/index.d.ts.map",
|
||||
"index.ts"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/esm/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/index.d.ts",
|
||||
"import": "./lib/esm/index.js",
|
||||
"default": "./lib/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"bench": "node test/benchmark/index.js",
|
||||
"build": "tsc && tsc -p tsconfig.esm.json",
|
||||
"lint": "prettier --check index.ts",
|
||||
"format": "prettier --write index.ts",
|
||||
"test": "node test/index.js",
|
||||
"test:deno": "deno test test/deno.ts"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"author": "Paul Miller (https://paulmillr.com)",
|
||||
"license": "MIT",
|
||||
"homepage": "https://paulmillr.com/noble/#scure",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/paulmillr/scure-base.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "2.8.4",
|
||||
"typescript": "5.0.2"
|
||||
},
|
||||
"keywords": [
|
||||
"bech32",
|
||||
"bech32m",
|
||||
"base64",
|
||||
"base58",
|
||||
"base32",
|
||||
"base16",
|
||||
"rfc4648",
|
||||
"rfc3548",
|
||||
"crockford",
|
||||
"encode",
|
||||
"encoder",
|
||||
"base-x",
|
||||
"base"
|
||||
],
|
||||
"funding": "https://paulmillr.com/funding/"
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2022 Patricio Palladino, Paul Miller (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.
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
# scure-bip32
|
||||
|
||||
Secure, [audited](#security) & minimal implementation of BIP32 hierarchical deterministic (HD) wallets over secp256k1.
|
||||
|
||||
Compared to popular `hdkey` package, scure-bip32:
|
||||
|
||||
- Supports ESM and common.js
|
||||
- Is 418KB all-bundled instead of 5.9MB
|
||||
- Uses 3 dependencies instead of 24
|
||||
- Had an external security [audit](#security) by Cure53
|
||||
|
||||
Check out [scure-bip39](https://github.com/paulmillr/scure-bip39) if you need mnemonic phrases. See [ed25519-keygen](https://github.com/paulmillr/ed25519-keygen) if you need SLIP-0010/BIP32 ed25519 hdkey implementation.
|
||||
|
||||
### This library belongs to *scure*
|
||||
|
||||
> **scure** — secure, independently audited packages for every use case.
|
||||
|
||||
- Audited by a third-party
|
||||
- Releases are signed with PGP keys and built transparently with NPM provenance
|
||||
- Check out all libraries:
|
||||
[base](https://github.com/paulmillr/scure-base),
|
||||
[bip32](https://github.com/paulmillr/scure-bip32),
|
||||
[bip39](https://github.com/paulmillr/scure-bip39),
|
||||
[btc-signer](https://github.com/paulmillr/scure-btc-signer)
|
||||
|
||||
## Usage
|
||||
|
||||
> npm install @scure/bip32
|
||||
|
||||
This module exports a single class `HDKey`, which should be used like this:
|
||||
|
||||
```ts
|
||||
const { HDKey } = require("@scure/bip32");
|
||||
const hdkey1 = HDKey.fromMasterSeed(seed);
|
||||
const hdkey2 = HDKey.fromExtendedKey(base58key);
|
||||
const hdkey3 = HDKey.fromJSON({ xpriv: string });
|
||||
|
||||
// props
|
||||
[hdkey1.depth, hdkey1.index, hdkey1.chainCode];
|
||||
console.log(hdkey2.privateKey, hdkey2.publicKey);
|
||||
console.log(hdkey3.derive("m/0/2147483647'/1"));
|
||||
const sig = hdkey3.sign(hash);
|
||||
hdkey3.verify(hash, sig);
|
||||
```
|
||||
|
||||
Note: `chainCode` property is essentially a private part
|
||||
of a secret "master" key, it should be guarded from unauthorized access.
|
||||
|
||||
The full API is:
|
||||
|
||||
```ts
|
||||
class HDKey {
|
||||
public static HARDENED_OFFSET: number;
|
||||
public static fromMasterSeed(seed: Uint8Array, versions: Versions): HDKey;
|
||||
public static fromExtendedKey(base58key: string, versions: Versions): HDKey;
|
||||
public static fromJSON(json: { xpriv: string }): HDKey;
|
||||
|
||||
readonly versions: Versions;
|
||||
readonly depth: number = 0;
|
||||
readonly index: number = 0;
|
||||
readonly chainCode: Uint8Array | null = null;
|
||||
readonly parentFingerprint: number = 0;
|
||||
|
||||
get fingerprint(): number;
|
||||
get identifier(): Uint8Array | undefined;
|
||||
get pubKeyHash(): Uint8Array | undefined;
|
||||
get privateKey(): Uint8Array | null;
|
||||
get publicKey(): Uint8Array | null;
|
||||
get privateExtendedKey(): string;
|
||||
get publicExtendedKey(): string;
|
||||
|
||||
derive(path: string): HDKey;
|
||||
deriveChild(index: number): HDKey;
|
||||
sign(hash: Uint8Array): Uint8Array;
|
||||
verify(hash: Uint8Array, signature: Uint8Array): boolean;
|
||||
wipePrivateData(): this;
|
||||
}
|
||||
|
||||
interface Versions {
|
||||
private: number;
|
||||
public: number;
|
||||
}
|
||||
```
|
||||
|
||||
The `hdkey` submodule provides a library for keys derivation according to
|
||||
[BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki).
|
||||
|
||||
It has almost the exact same API than the version `1.x` of
|
||||
[`hdkey` from cryptocoinjs](https://github.com/cryptocoinjs/hdkey),
|
||||
but it's backed by this package's primitives, and has built-in TypeScript types.
|
||||
Its only difference is that it has to be be used with a named import.
|
||||
The implementation is [loosely based on hdkey, which has MIT License](#LICENSE).
|
||||
|
||||
## Security
|
||||
|
||||
The library has been audited by Cure53 on Jan 5, 2022. Check out the audit [PDF](./audit/2022-01-05-cure53-audit-nbl2.pdf) & [URL](https://cure53.de/pentest-report_hashing-libs.pdf). See [changes since audit](https://github.com/paulmillr/scure-bip32/compare/1.0.1..main).
|
||||
|
||||
1. The library was initially developed for [js-ethereum-cryptography](https://github.com/ethereum/js-ethereum-cryptography)
|
||||
2. At commit [ae00e6d7](https://github.com/ethereum/js-ethereum-cryptography/commit/ae00e6d7d24fb3c76a1c7fe10039f6ecd120b77e), it
|
||||
was extracted to a separate package called `micro-bip32`
|
||||
3. After the audit we've decided to use NPM namespace for security. Since `@micro` namespace was taken, we've renamed the package to `@scure/bip32`
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](./LICENSE)
|
||||
|
||||
Copyright (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com)
|
||||
-307
@@ -1,307 +0,0 @@
|
||||
/*! scure-bip32 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) */
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { ripemd160 } from '@noble/hashes/ripemd160';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { bytes as assertBytes } from '@noble/hashes/_assert';
|
||||
import { bytesToHex, concatBytes, createView, hexToBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { secp256k1 as secp } from '@noble/curves/secp256k1';
|
||||
import { mod } from '@noble/curves/abstract/modular';
|
||||
import { base58check as base58checker } from '@scure/base';
|
||||
|
||||
const Point = secp.ProjectivePoint;
|
||||
const base58check = base58checker(sha256);
|
||||
|
||||
function bytesToNumber(bytes: Uint8Array): bigint {
|
||||
return BigInt(`0x${bytesToHex(bytes)}`);
|
||||
}
|
||||
|
||||
function numberToBytes(num: bigint): Uint8Array {
|
||||
return hexToBytes(num.toString(16).padStart(64, '0'));
|
||||
}
|
||||
|
||||
const MASTER_SECRET = utf8ToBytes('Bitcoin seed');
|
||||
// Bitcoin hardcoded by default
|
||||
const BITCOIN_VERSIONS: Versions = { private: 0x0488ade4, public: 0x0488b21e };
|
||||
export const HARDENED_OFFSET: number = 0x80000000;
|
||||
|
||||
export interface Versions {
|
||||
private: number;
|
||||
public: number;
|
||||
}
|
||||
|
||||
const hash160 = (data: Uint8Array) => ripemd160(sha256(data));
|
||||
const fromU32 = (data: Uint8Array) => createView(data).getUint32(0, false);
|
||||
const toU32 = (n: number) => {
|
||||
if (!Number.isSafeInteger(n) || n < 0 || n > 2 ** 32 - 1) {
|
||||
throw new Error(`Invalid number=${n}. Should be from 0 to 2 ** 32 - 1`);
|
||||
}
|
||||
const buf = new Uint8Array(4);
|
||||
createView(buf).setUint32(0, n, false);
|
||||
return buf;
|
||||
};
|
||||
|
||||
interface HDKeyOpt {
|
||||
versions: Versions;
|
||||
depth?: number;
|
||||
index?: number;
|
||||
parentFingerprint?: number;
|
||||
chainCode: Uint8Array;
|
||||
publicKey?: Uint8Array;
|
||||
privateKey?: Uint8Array | bigint;
|
||||
}
|
||||
|
||||
export class HDKey {
|
||||
get fingerprint(): number {
|
||||
if (!this.pubHash) {
|
||||
throw new Error('No publicKey set!');
|
||||
}
|
||||
return fromU32(this.pubHash);
|
||||
}
|
||||
get identifier(): Uint8Array | undefined {
|
||||
return this.pubHash;
|
||||
}
|
||||
get pubKeyHash(): Uint8Array | undefined {
|
||||
return this.pubHash;
|
||||
}
|
||||
get privateKey(): Uint8Array | null {
|
||||
return this.privKeyBytes || null;
|
||||
}
|
||||
get publicKey(): Uint8Array | null {
|
||||
return this.pubKey || null;
|
||||
}
|
||||
get privateExtendedKey(): string {
|
||||
const priv = this.privateKey;
|
||||
if (!priv) {
|
||||
throw new Error('No private key');
|
||||
}
|
||||
return base58check.encode(
|
||||
this.serialize(this.versions.private, concatBytes(new Uint8Array([0]), priv))
|
||||
);
|
||||
}
|
||||
get publicExtendedKey(): string {
|
||||
if (!this.pubKey) {
|
||||
throw new Error('No public key');
|
||||
}
|
||||
return base58check.encode(this.serialize(this.versions.public, this.pubKey));
|
||||
}
|
||||
|
||||
public static fromMasterSeed(seed: Uint8Array, versions: Versions = BITCOIN_VERSIONS): HDKey {
|
||||
assertBytes(seed);
|
||||
if (8 * seed.length < 128 || 8 * seed.length > 512) {
|
||||
throw new Error(
|
||||
`HDKey: wrong seed length=${seed.length}. Should be between 128 and 512 bits; 256 bits is advised)`
|
||||
);
|
||||
}
|
||||
const I = hmac(sha512, MASTER_SECRET, seed);
|
||||
return new HDKey({
|
||||
versions,
|
||||
chainCode: I.slice(32),
|
||||
privateKey: I.slice(0, 32),
|
||||
});
|
||||
}
|
||||
|
||||
public static fromExtendedKey(base58key: string, versions: Versions = BITCOIN_VERSIONS): HDKey {
|
||||
// => version(4) || depth(1) || fingerprint(4) || index(4) || chain(32) || key(33)
|
||||
const keyBuffer: Uint8Array = base58check.decode(base58key);
|
||||
const keyView = createView(keyBuffer);
|
||||
const version = keyView.getUint32(0, false);
|
||||
const opt = {
|
||||
versions,
|
||||
depth: keyBuffer[4],
|
||||
parentFingerprint: keyView.getUint32(5, false),
|
||||
index: keyView.getUint32(9, false),
|
||||
chainCode: keyBuffer.slice(13, 45),
|
||||
};
|
||||
const key = keyBuffer.slice(45);
|
||||
const isPriv = key[0] === 0;
|
||||
if (version !== versions[isPriv ? 'private' : 'public']) {
|
||||
throw new Error('Version mismatch');
|
||||
}
|
||||
if (isPriv) {
|
||||
return new HDKey({ ...opt, privateKey: key.slice(1) });
|
||||
} else {
|
||||
return new HDKey({ ...opt, publicKey: key });
|
||||
}
|
||||
}
|
||||
|
||||
public static fromJSON(json: { xpriv: string }): HDKey {
|
||||
return HDKey.fromExtendedKey(json.xpriv);
|
||||
}
|
||||
public readonly versions: Versions;
|
||||
public readonly depth: number = 0;
|
||||
public readonly index: number = 0;
|
||||
public readonly chainCode: Uint8Array | null = null;
|
||||
public readonly parentFingerprint: number = 0;
|
||||
private privKey?: bigint;
|
||||
private privKeyBytes?: Uint8Array;
|
||||
private pubKey?: Uint8Array;
|
||||
private pubHash: Uint8Array | undefined;
|
||||
|
||||
constructor(opt: HDKeyOpt) {
|
||||
if (!opt || typeof opt !== 'object') {
|
||||
throw new Error('HDKey.constructor must not be called directly');
|
||||
}
|
||||
this.versions = opt.versions || BITCOIN_VERSIONS;
|
||||
this.depth = opt.depth || 0;
|
||||
this.chainCode = opt.chainCode;
|
||||
this.index = opt.index || 0;
|
||||
this.parentFingerprint = opt.parentFingerprint || 0;
|
||||
if (!this.depth) {
|
||||
if (this.parentFingerprint || this.index) {
|
||||
throw new Error('HDKey: zero depth with non-zero index/parent fingerprint');
|
||||
}
|
||||
}
|
||||
if (opt.publicKey && opt.privateKey) {
|
||||
throw new Error('HDKey: publicKey and privateKey at same time.');
|
||||
}
|
||||
if (opt.privateKey) {
|
||||
if (!secp.utils.isValidPrivateKey(opt.privateKey)) {
|
||||
throw new Error('Invalid private key');
|
||||
}
|
||||
this.privKey =
|
||||
typeof opt.privateKey === 'bigint' ? opt.privateKey : bytesToNumber(opt.privateKey);
|
||||
this.privKeyBytes = numberToBytes(this.privKey);
|
||||
this.pubKey = secp.getPublicKey(opt.privateKey, true);
|
||||
} else if (opt.publicKey) {
|
||||
this.pubKey = Point.fromHex(opt.publicKey).toRawBytes(true); // force compressed point
|
||||
} else {
|
||||
throw new Error('HDKey: no public or private key provided');
|
||||
}
|
||||
this.pubHash = hash160(this.pubKey);
|
||||
}
|
||||
|
||||
public derive(path: string): HDKey {
|
||||
if (!/^[mM]'?/.test(path)) {
|
||||
throw new Error('Path must start with "m" or "M"');
|
||||
}
|
||||
if (/^[mM]'?$/.test(path)) {
|
||||
return this;
|
||||
}
|
||||
const parts = path.replace(/^[mM]'?\//, '').split('/');
|
||||
// tslint:disable-next-line
|
||||
let child: HDKey = this;
|
||||
for (const c of parts) {
|
||||
const m = /^(\d+)('?)$/.exec(c);
|
||||
if (!m || m.length !== 3) {
|
||||
throw new Error(`Invalid child index: ${c}`);
|
||||
}
|
||||
let idx = +m[1];
|
||||
if (!Number.isSafeInteger(idx) || idx >= HARDENED_OFFSET) {
|
||||
throw new Error('Invalid index');
|
||||
}
|
||||
// hardened key
|
||||
if (m[2] === "'") {
|
||||
idx += HARDENED_OFFSET;
|
||||
}
|
||||
child = child.deriveChild(idx);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
public deriveChild(index: number): HDKey {
|
||||
if (!this.pubKey || !this.chainCode) {
|
||||
throw new Error('No publicKey or chainCode set');
|
||||
}
|
||||
let data = toU32(index);
|
||||
if (index >= HARDENED_OFFSET) {
|
||||
// Hardened
|
||||
const priv = this.privateKey;
|
||||
if (!priv) {
|
||||
throw new Error('Could not derive hardened child key');
|
||||
}
|
||||
// Hardened child: 0x00 || ser256(kpar) || ser32(index)
|
||||
data = concatBytes(new Uint8Array([0]), priv, data);
|
||||
} else {
|
||||
// Normal child: serP(point(kpar)) || ser32(index)
|
||||
data = concatBytes(this.pubKey, data);
|
||||
}
|
||||
const I = hmac(sha512, this.chainCode, data);
|
||||
const childTweak = bytesToNumber(I.slice(0, 32));
|
||||
const chainCode = I.slice(32);
|
||||
if (!secp.utils.isValidPrivateKey(childTweak)) {
|
||||
throw new Error('Tweak bigger than curve order');
|
||||
}
|
||||
const opt: HDKeyOpt = {
|
||||
versions: this.versions,
|
||||
chainCode,
|
||||
depth: this.depth + 1,
|
||||
parentFingerprint: this.fingerprint,
|
||||
index,
|
||||
};
|
||||
try {
|
||||
// Private parent key -> private child key
|
||||
if (this.privateKey) {
|
||||
const added = mod(this.privKey! + childTweak, secp.CURVE.n);
|
||||
if (!secp.utils.isValidPrivateKey(added)) {
|
||||
throw new Error('The tweak was out of range or the resulted private key is invalid');
|
||||
}
|
||||
opt.privateKey = added;
|
||||
} else {
|
||||
const added = Point.fromHex(this.pubKey).add(Point.fromPrivateKey(childTweak));
|
||||
// Cryptographically impossible: hmac-sha512 preimage would need to be found
|
||||
if (added.equals(Point.ZERO)) {
|
||||
throw new Error('The tweak was equal to negative P, which made the result key invalid');
|
||||
}
|
||||
opt.publicKey = added.toRawBytes(true);
|
||||
}
|
||||
return new HDKey(opt);
|
||||
} catch (err) {
|
||||
return this.deriveChild(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public sign(hash: Uint8Array): Uint8Array {
|
||||
if (!this.privateKey) {
|
||||
throw new Error('No privateKey set!');
|
||||
}
|
||||
assertBytes(hash, 32);
|
||||
return secp.sign(hash, this.privKey!).toCompactRawBytes();
|
||||
}
|
||||
|
||||
public verify(hash: Uint8Array, signature: Uint8Array): boolean {
|
||||
assertBytes(hash, 32);
|
||||
assertBytes(signature, 64);
|
||||
if (!this.publicKey) {
|
||||
throw new Error('No publicKey set!');
|
||||
}
|
||||
let sig;
|
||||
try {
|
||||
sig = secp.Signature.fromCompact(signature);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
return secp.verify(sig, hash, this.publicKey);
|
||||
}
|
||||
|
||||
public wipePrivateData(): this {
|
||||
this.privKey = undefined;
|
||||
if (this.privKeyBytes) {
|
||||
this.privKeyBytes.fill(0);
|
||||
this.privKeyBytes = undefined;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public toJSON(): { xpriv: string; xpub: string } {
|
||||
return {
|
||||
xpriv: this.privateExtendedKey,
|
||||
xpub: this.publicExtendedKey,
|
||||
};
|
||||
}
|
||||
|
||||
private serialize(version: number, key: Uint8Array) {
|
||||
if (!this.chainCode) {
|
||||
throw new Error('No chainCode set');
|
||||
}
|
||||
assertBytes(key, 33);
|
||||
// version(4) || depth(1) || fingerprint(4) || index(4) || chain(32) || key(33)
|
||||
return concatBytes(
|
||||
toU32(version),
|
||||
new Uint8Array([this.depth]),
|
||||
toU32(this.parentFingerprint),
|
||||
toU32(this.index),
|
||||
this.chainCode,
|
||||
key
|
||||
);
|
||||
}
|
||||
}
|
||||
-257
@@ -1,257 +0,0 @@
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { ripemd160 } from '@noble/hashes/ripemd160';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { bytes as assertBytes } from '@noble/hashes/_assert';
|
||||
import { bytesToHex, concatBytes, createView, hexToBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { secp256k1 as secp } from '@noble/curves/secp256k1';
|
||||
import { mod } from '@noble/curves/abstract/modular';
|
||||
import { base58check as base58checker } from '@scure/base';
|
||||
const Point = secp.ProjectivePoint;
|
||||
const base58check = base58checker(sha256);
|
||||
function bytesToNumber(bytes) {
|
||||
return BigInt(`0x${bytesToHex(bytes)}`);
|
||||
}
|
||||
function numberToBytes(num) {
|
||||
return hexToBytes(num.toString(16).padStart(64, '0'));
|
||||
}
|
||||
const MASTER_SECRET = utf8ToBytes('Bitcoin seed');
|
||||
const BITCOIN_VERSIONS = { private: 0x0488ade4, public: 0x0488b21e };
|
||||
export const HARDENED_OFFSET = 0x80000000;
|
||||
const hash160 = (data) => ripemd160(sha256(data));
|
||||
const fromU32 = (data) => createView(data).getUint32(0, false);
|
||||
const toU32 = (n) => {
|
||||
if (!Number.isSafeInteger(n) || n < 0 || n > 2 ** 32 - 1) {
|
||||
throw new Error(`Invalid number=${n}. Should be from 0 to 2 ** 32 - 1`);
|
||||
}
|
||||
const buf = new Uint8Array(4);
|
||||
createView(buf).setUint32(0, n, false);
|
||||
return buf;
|
||||
};
|
||||
export class HDKey {
|
||||
get fingerprint() {
|
||||
if (!this.pubHash) {
|
||||
throw new Error('No publicKey set!');
|
||||
}
|
||||
return fromU32(this.pubHash);
|
||||
}
|
||||
get identifier() {
|
||||
return this.pubHash;
|
||||
}
|
||||
get pubKeyHash() {
|
||||
return this.pubHash;
|
||||
}
|
||||
get privateKey() {
|
||||
return this.privKeyBytes || null;
|
||||
}
|
||||
get publicKey() {
|
||||
return this.pubKey || null;
|
||||
}
|
||||
get privateExtendedKey() {
|
||||
const priv = this.privateKey;
|
||||
if (!priv) {
|
||||
throw new Error('No private key');
|
||||
}
|
||||
return base58check.encode(this.serialize(this.versions.private, concatBytes(new Uint8Array([0]), priv)));
|
||||
}
|
||||
get publicExtendedKey() {
|
||||
if (!this.pubKey) {
|
||||
throw new Error('No public key');
|
||||
}
|
||||
return base58check.encode(this.serialize(this.versions.public, this.pubKey));
|
||||
}
|
||||
static fromMasterSeed(seed, versions = BITCOIN_VERSIONS) {
|
||||
assertBytes(seed);
|
||||
if (8 * seed.length < 128 || 8 * seed.length > 512) {
|
||||
throw new Error(`HDKey: wrong seed length=${seed.length}. Should be between 128 and 512 bits; 256 bits is advised)`);
|
||||
}
|
||||
const I = hmac(sha512, MASTER_SECRET, seed);
|
||||
return new HDKey({
|
||||
versions,
|
||||
chainCode: I.slice(32),
|
||||
privateKey: I.slice(0, 32),
|
||||
});
|
||||
}
|
||||
static fromExtendedKey(base58key, versions = BITCOIN_VERSIONS) {
|
||||
const keyBuffer = base58check.decode(base58key);
|
||||
const keyView = createView(keyBuffer);
|
||||
const version = keyView.getUint32(0, false);
|
||||
const opt = {
|
||||
versions,
|
||||
depth: keyBuffer[4],
|
||||
parentFingerprint: keyView.getUint32(5, false),
|
||||
index: keyView.getUint32(9, false),
|
||||
chainCode: keyBuffer.slice(13, 45),
|
||||
};
|
||||
const key = keyBuffer.slice(45);
|
||||
const isPriv = key[0] === 0;
|
||||
if (version !== versions[isPriv ? 'private' : 'public']) {
|
||||
throw new Error('Version mismatch');
|
||||
}
|
||||
if (isPriv) {
|
||||
return new HDKey({ ...opt, privateKey: key.slice(1) });
|
||||
}
|
||||
else {
|
||||
return new HDKey({ ...opt, publicKey: key });
|
||||
}
|
||||
}
|
||||
static fromJSON(json) {
|
||||
return HDKey.fromExtendedKey(json.xpriv);
|
||||
}
|
||||
constructor(opt) {
|
||||
this.depth = 0;
|
||||
this.index = 0;
|
||||
this.chainCode = null;
|
||||
this.parentFingerprint = 0;
|
||||
if (!opt || typeof opt !== 'object') {
|
||||
throw new Error('HDKey.constructor must not be called directly');
|
||||
}
|
||||
this.versions = opt.versions || BITCOIN_VERSIONS;
|
||||
this.depth = opt.depth || 0;
|
||||
this.chainCode = opt.chainCode;
|
||||
this.index = opt.index || 0;
|
||||
this.parentFingerprint = opt.parentFingerprint || 0;
|
||||
if (!this.depth) {
|
||||
if (this.parentFingerprint || this.index) {
|
||||
throw new Error('HDKey: zero depth with non-zero index/parent fingerprint');
|
||||
}
|
||||
}
|
||||
if (opt.publicKey && opt.privateKey) {
|
||||
throw new Error('HDKey: publicKey and privateKey at same time.');
|
||||
}
|
||||
if (opt.privateKey) {
|
||||
if (!secp.utils.isValidPrivateKey(opt.privateKey)) {
|
||||
throw new Error('Invalid private key');
|
||||
}
|
||||
this.privKey =
|
||||
typeof opt.privateKey === 'bigint' ? opt.privateKey : bytesToNumber(opt.privateKey);
|
||||
this.privKeyBytes = numberToBytes(this.privKey);
|
||||
this.pubKey = secp.getPublicKey(opt.privateKey, true);
|
||||
}
|
||||
else if (opt.publicKey) {
|
||||
this.pubKey = Point.fromHex(opt.publicKey).toRawBytes(true);
|
||||
}
|
||||
else {
|
||||
throw new Error('HDKey: no public or private key provided');
|
||||
}
|
||||
this.pubHash = hash160(this.pubKey);
|
||||
}
|
||||
derive(path) {
|
||||
if (!/^[mM]'?/.test(path)) {
|
||||
throw new Error('Path must start with "m" or "M"');
|
||||
}
|
||||
if (/^[mM]'?$/.test(path)) {
|
||||
return this;
|
||||
}
|
||||
const parts = path.replace(/^[mM]'?\//, '').split('/');
|
||||
let child = this;
|
||||
for (const c of parts) {
|
||||
const m = /^(\d+)('?)$/.exec(c);
|
||||
if (!m || m.length !== 3) {
|
||||
throw new Error(`Invalid child index: ${c}`);
|
||||
}
|
||||
let idx = +m[1];
|
||||
if (!Number.isSafeInteger(idx) || idx >= HARDENED_OFFSET) {
|
||||
throw new Error('Invalid index');
|
||||
}
|
||||
if (m[2] === "'") {
|
||||
idx += HARDENED_OFFSET;
|
||||
}
|
||||
child = child.deriveChild(idx);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
deriveChild(index) {
|
||||
if (!this.pubKey || !this.chainCode) {
|
||||
throw new Error('No publicKey or chainCode set');
|
||||
}
|
||||
let data = toU32(index);
|
||||
if (index >= HARDENED_OFFSET) {
|
||||
const priv = this.privateKey;
|
||||
if (!priv) {
|
||||
throw new Error('Could not derive hardened child key');
|
||||
}
|
||||
data = concatBytes(new Uint8Array([0]), priv, data);
|
||||
}
|
||||
else {
|
||||
data = concatBytes(this.pubKey, data);
|
||||
}
|
||||
const I = hmac(sha512, this.chainCode, data);
|
||||
const childTweak = bytesToNumber(I.slice(0, 32));
|
||||
const chainCode = I.slice(32);
|
||||
if (!secp.utils.isValidPrivateKey(childTweak)) {
|
||||
throw new Error('Tweak bigger than curve order');
|
||||
}
|
||||
const opt = {
|
||||
versions: this.versions,
|
||||
chainCode,
|
||||
depth: this.depth + 1,
|
||||
parentFingerprint: this.fingerprint,
|
||||
index,
|
||||
};
|
||||
try {
|
||||
if (this.privateKey) {
|
||||
const added = mod(this.privKey + childTweak, secp.CURVE.n);
|
||||
if (!secp.utils.isValidPrivateKey(added)) {
|
||||
throw new Error('The tweak was out of range or the resulted private key is invalid');
|
||||
}
|
||||
opt.privateKey = added;
|
||||
}
|
||||
else {
|
||||
const added = Point.fromHex(this.pubKey).add(Point.fromPrivateKey(childTweak));
|
||||
if (added.equals(Point.ZERO)) {
|
||||
throw new Error('The tweak was equal to negative P, which made the result key invalid');
|
||||
}
|
||||
opt.publicKey = added.toRawBytes(true);
|
||||
}
|
||||
return new HDKey(opt);
|
||||
}
|
||||
catch (err) {
|
||||
return this.deriveChild(index + 1);
|
||||
}
|
||||
}
|
||||
sign(hash) {
|
||||
if (!this.privateKey) {
|
||||
throw new Error('No privateKey set!');
|
||||
}
|
||||
assertBytes(hash, 32);
|
||||
return secp.sign(hash, this.privKey).toCompactRawBytes();
|
||||
}
|
||||
verify(hash, signature) {
|
||||
assertBytes(hash, 32);
|
||||
assertBytes(signature, 64);
|
||||
if (!this.publicKey) {
|
||||
throw new Error('No publicKey set!');
|
||||
}
|
||||
let sig;
|
||||
try {
|
||||
sig = secp.Signature.fromCompact(signature);
|
||||
}
|
||||
catch (error) {
|
||||
return false;
|
||||
}
|
||||
return secp.verify(sig, hash, this.publicKey);
|
||||
}
|
||||
wipePrivateData() {
|
||||
this.privKey = undefined;
|
||||
if (this.privKeyBytes) {
|
||||
this.privKeyBytes.fill(0);
|
||||
this.privKeyBytes = undefined;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
toJSON() {
|
||||
return {
|
||||
xpriv: this.privateExtendedKey,
|
||||
xpub: this.publicExtendedKey,
|
||||
};
|
||||
}
|
||||
serialize(version, key) {
|
||||
if (!this.chainCode) {
|
||||
throw new Error('No chainCode set');
|
||||
}
|
||||
assertBytes(key, 33);
|
||||
return concatBytes(toU32(version), new Uint8Array([this.depth]), toU32(this.parentFingerprint), toU32(this.index), this.chainCode, key);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
-1
File diff suppressed because one or more lines are too long
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"type": "module",
|
||||
"browser": {
|
||||
"crypto": false
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
export declare const HARDENED_OFFSET: number;
|
||||
export interface Versions {
|
||||
private: number;
|
||||
public: number;
|
||||
}
|
||||
interface HDKeyOpt {
|
||||
versions: Versions;
|
||||
depth?: number;
|
||||
index?: number;
|
||||
parentFingerprint?: number;
|
||||
chainCode: Uint8Array;
|
||||
publicKey?: Uint8Array;
|
||||
privateKey?: Uint8Array | bigint;
|
||||
}
|
||||
export declare class HDKey {
|
||||
get fingerprint(): number;
|
||||
get identifier(): Uint8Array | undefined;
|
||||
get pubKeyHash(): Uint8Array | undefined;
|
||||
get privateKey(): Uint8Array | null;
|
||||
get publicKey(): Uint8Array | null;
|
||||
get privateExtendedKey(): string;
|
||||
get publicExtendedKey(): string;
|
||||
static fromMasterSeed(seed: Uint8Array, versions?: Versions): HDKey;
|
||||
static fromExtendedKey(base58key: string, versions?: Versions): HDKey;
|
||||
static fromJSON(json: {
|
||||
xpriv: string;
|
||||
}): HDKey;
|
||||
readonly versions: Versions;
|
||||
readonly depth: number;
|
||||
readonly index: number;
|
||||
readonly chainCode: Uint8Array | null;
|
||||
readonly parentFingerprint: number;
|
||||
private privKey?;
|
||||
private privKeyBytes?;
|
||||
private pubKey?;
|
||||
private pubHash;
|
||||
constructor(opt: HDKeyOpt);
|
||||
derive(path: string): HDKey;
|
||||
deriveChild(index: number): HDKey;
|
||||
sign(hash: Uint8Array): Uint8Array;
|
||||
verify(hash: Uint8Array, signature: Uint8Array): boolean;
|
||||
wipePrivateData(): this;
|
||||
toJSON(): {
|
||||
xpriv: string;
|
||||
xpub: string;
|
||||
};
|
||||
private serialize;
|
||||
}
|
||||
export {};
|
||||
-261
@@ -1,261 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.HDKey = exports.HARDENED_OFFSET = void 0;
|
||||
const hmac_1 = require("@noble/hashes/hmac");
|
||||
const ripemd160_1 = require("@noble/hashes/ripemd160");
|
||||
const sha256_1 = require("@noble/hashes/sha256");
|
||||
const sha512_1 = require("@noble/hashes/sha512");
|
||||
const _assert_1 = require("@noble/hashes/_assert");
|
||||
const utils_1 = require("@noble/hashes/utils");
|
||||
const secp256k1_1 = require("@noble/curves/secp256k1");
|
||||
const modular_1 = require("@noble/curves/abstract/modular");
|
||||
const base_1 = require("@scure/base");
|
||||
const Point = secp256k1_1.secp256k1.ProjectivePoint;
|
||||
const base58check = (0, base_1.base58check)(sha256_1.sha256);
|
||||
function bytesToNumber(bytes) {
|
||||
return BigInt(`0x${(0, utils_1.bytesToHex)(bytes)}`);
|
||||
}
|
||||
function numberToBytes(num) {
|
||||
return (0, utils_1.hexToBytes)(num.toString(16).padStart(64, '0'));
|
||||
}
|
||||
const MASTER_SECRET = (0, utils_1.utf8ToBytes)('Bitcoin seed');
|
||||
const BITCOIN_VERSIONS = { private: 0x0488ade4, public: 0x0488b21e };
|
||||
exports.HARDENED_OFFSET = 0x80000000;
|
||||
const hash160 = (data) => (0, ripemd160_1.ripemd160)((0, sha256_1.sha256)(data));
|
||||
const fromU32 = (data) => (0, utils_1.createView)(data).getUint32(0, false);
|
||||
const toU32 = (n) => {
|
||||
if (!Number.isSafeInteger(n) || n < 0 || n > 2 ** 32 - 1) {
|
||||
throw new Error(`Invalid number=${n}. Should be from 0 to 2 ** 32 - 1`);
|
||||
}
|
||||
const buf = new Uint8Array(4);
|
||||
(0, utils_1.createView)(buf).setUint32(0, n, false);
|
||||
return buf;
|
||||
};
|
||||
class HDKey {
|
||||
get fingerprint() {
|
||||
if (!this.pubHash) {
|
||||
throw new Error('No publicKey set!');
|
||||
}
|
||||
return fromU32(this.pubHash);
|
||||
}
|
||||
get identifier() {
|
||||
return this.pubHash;
|
||||
}
|
||||
get pubKeyHash() {
|
||||
return this.pubHash;
|
||||
}
|
||||
get privateKey() {
|
||||
return this.privKeyBytes || null;
|
||||
}
|
||||
get publicKey() {
|
||||
return this.pubKey || null;
|
||||
}
|
||||
get privateExtendedKey() {
|
||||
const priv = this.privateKey;
|
||||
if (!priv) {
|
||||
throw new Error('No private key');
|
||||
}
|
||||
return base58check.encode(this.serialize(this.versions.private, (0, utils_1.concatBytes)(new Uint8Array([0]), priv)));
|
||||
}
|
||||
get publicExtendedKey() {
|
||||
if (!this.pubKey) {
|
||||
throw new Error('No public key');
|
||||
}
|
||||
return base58check.encode(this.serialize(this.versions.public, this.pubKey));
|
||||
}
|
||||
static fromMasterSeed(seed, versions = BITCOIN_VERSIONS) {
|
||||
(0, _assert_1.bytes)(seed);
|
||||
if (8 * seed.length < 128 || 8 * seed.length > 512) {
|
||||
throw new Error(`HDKey: wrong seed length=${seed.length}. Should be between 128 and 512 bits; 256 bits is advised)`);
|
||||
}
|
||||
const I = (0, hmac_1.hmac)(sha512_1.sha512, MASTER_SECRET, seed);
|
||||
return new HDKey({
|
||||
versions,
|
||||
chainCode: I.slice(32),
|
||||
privateKey: I.slice(0, 32),
|
||||
});
|
||||
}
|
||||
static fromExtendedKey(base58key, versions = BITCOIN_VERSIONS) {
|
||||
const keyBuffer = base58check.decode(base58key);
|
||||
const keyView = (0, utils_1.createView)(keyBuffer);
|
||||
const version = keyView.getUint32(0, false);
|
||||
const opt = {
|
||||
versions,
|
||||
depth: keyBuffer[4],
|
||||
parentFingerprint: keyView.getUint32(5, false),
|
||||
index: keyView.getUint32(9, false),
|
||||
chainCode: keyBuffer.slice(13, 45),
|
||||
};
|
||||
const key = keyBuffer.slice(45);
|
||||
const isPriv = key[0] === 0;
|
||||
if (version !== versions[isPriv ? 'private' : 'public']) {
|
||||
throw new Error('Version mismatch');
|
||||
}
|
||||
if (isPriv) {
|
||||
return new HDKey({ ...opt, privateKey: key.slice(1) });
|
||||
}
|
||||
else {
|
||||
return new HDKey({ ...opt, publicKey: key });
|
||||
}
|
||||
}
|
||||
static fromJSON(json) {
|
||||
return HDKey.fromExtendedKey(json.xpriv);
|
||||
}
|
||||
constructor(opt) {
|
||||
this.depth = 0;
|
||||
this.index = 0;
|
||||
this.chainCode = null;
|
||||
this.parentFingerprint = 0;
|
||||
if (!opt || typeof opt !== 'object') {
|
||||
throw new Error('HDKey.constructor must not be called directly');
|
||||
}
|
||||
this.versions = opt.versions || BITCOIN_VERSIONS;
|
||||
this.depth = opt.depth || 0;
|
||||
this.chainCode = opt.chainCode;
|
||||
this.index = opt.index || 0;
|
||||
this.parentFingerprint = opt.parentFingerprint || 0;
|
||||
if (!this.depth) {
|
||||
if (this.parentFingerprint || this.index) {
|
||||
throw new Error('HDKey: zero depth with non-zero index/parent fingerprint');
|
||||
}
|
||||
}
|
||||
if (opt.publicKey && opt.privateKey) {
|
||||
throw new Error('HDKey: publicKey and privateKey at same time.');
|
||||
}
|
||||
if (opt.privateKey) {
|
||||
if (!secp256k1_1.secp256k1.utils.isValidPrivateKey(opt.privateKey)) {
|
||||
throw new Error('Invalid private key');
|
||||
}
|
||||
this.privKey =
|
||||
typeof opt.privateKey === 'bigint' ? opt.privateKey : bytesToNumber(opt.privateKey);
|
||||
this.privKeyBytes = numberToBytes(this.privKey);
|
||||
this.pubKey = secp256k1_1.secp256k1.getPublicKey(opt.privateKey, true);
|
||||
}
|
||||
else if (opt.publicKey) {
|
||||
this.pubKey = Point.fromHex(opt.publicKey).toRawBytes(true);
|
||||
}
|
||||
else {
|
||||
throw new Error('HDKey: no public or private key provided');
|
||||
}
|
||||
this.pubHash = hash160(this.pubKey);
|
||||
}
|
||||
derive(path) {
|
||||
if (!/^[mM]'?/.test(path)) {
|
||||
throw new Error('Path must start with "m" or "M"');
|
||||
}
|
||||
if (/^[mM]'?$/.test(path)) {
|
||||
return this;
|
||||
}
|
||||
const parts = path.replace(/^[mM]'?\//, '').split('/');
|
||||
let child = this;
|
||||
for (const c of parts) {
|
||||
const m = /^(\d+)('?)$/.exec(c);
|
||||
if (!m || m.length !== 3) {
|
||||
throw new Error(`Invalid child index: ${c}`);
|
||||
}
|
||||
let idx = +m[1];
|
||||
if (!Number.isSafeInteger(idx) || idx >= exports.HARDENED_OFFSET) {
|
||||
throw new Error('Invalid index');
|
||||
}
|
||||
if (m[2] === "'") {
|
||||
idx += exports.HARDENED_OFFSET;
|
||||
}
|
||||
child = child.deriveChild(idx);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
deriveChild(index) {
|
||||
if (!this.pubKey || !this.chainCode) {
|
||||
throw new Error('No publicKey or chainCode set');
|
||||
}
|
||||
let data = toU32(index);
|
||||
if (index >= exports.HARDENED_OFFSET) {
|
||||
const priv = this.privateKey;
|
||||
if (!priv) {
|
||||
throw new Error('Could not derive hardened child key');
|
||||
}
|
||||
data = (0, utils_1.concatBytes)(new Uint8Array([0]), priv, data);
|
||||
}
|
||||
else {
|
||||
data = (0, utils_1.concatBytes)(this.pubKey, data);
|
||||
}
|
||||
const I = (0, hmac_1.hmac)(sha512_1.sha512, this.chainCode, data);
|
||||
const childTweak = bytesToNumber(I.slice(0, 32));
|
||||
const chainCode = I.slice(32);
|
||||
if (!secp256k1_1.secp256k1.utils.isValidPrivateKey(childTweak)) {
|
||||
throw new Error('Tweak bigger than curve order');
|
||||
}
|
||||
const opt = {
|
||||
versions: this.versions,
|
||||
chainCode,
|
||||
depth: this.depth + 1,
|
||||
parentFingerprint: this.fingerprint,
|
||||
index,
|
||||
};
|
||||
try {
|
||||
if (this.privateKey) {
|
||||
const added = (0, modular_1.mod)(this.privKey + childTweak, secp256k1_1.secp256k1.CURVE.n);
|
||||
if (!secp256k1_1.secp256k1.utils.isValidPrivateKey(added)) {
|
||||
throw new Error('The tweak was out of range or the resulted private key is invalid');
|
||||
}
|
||||
opt.privateKey = added;
|
||||
}
|
||||
else {
|
||||
const added = Point.fromHex(this.pubKey).add(Point.fromPrivateKey(childTweak));
|
||||
if (added.equals(Point.ZERO)) {
|
||||
throw new Error('The tweak was equal to negative P, which made the result key invalid');
|
||||
}
|
||||
opt.publicKey = added.toRawBytes(true);
|
||||
}
|
||||
return new HDKey(opt);
|
||||
}
|
||||
catch (err) {
|
||||
return this.deriveChild(index + 1);
|
||||
}
|
||||
}
|
||||
sign(hash) {
|
||||
if (!this.privateKey) {
|
||||
throw new Error('No privateKey set!');
|
||||
}
|
||||
(0, _assert_1.bytes)(hash, 32);
|
||||
return secp256k1_1.secp256k1.sign(hash, this.privKey).toCompactRawBytes();
|
||||
}
|
||||
verify(hash, signature) {
|
||||
(0, _assert_1.bytes)(hash, 32);
|
||||
(0, _assert_1.bytes)(signature, 64);
|
||||
if (!this.publicKey) {
|
||||
throw new Error('No publicKey set!');
|
||||
}
|
||||
let sig;
|
||||
try {
|
||||
sig = secp256k1_1.secp256k1.Signature.fromCompact(signature);
|
||||
}
|
||||
catch (error) {
|
||||
return false;
|
||||
}
|
||||
return secp256k1_1.secp256k1.verify(sig, hash, this.publicKey);
|
||||
}
|
||||
wipePrivateData() {
|
||||
this.privKey = undefined;
|
||||
if (this.privKeyBytes) {
|
||||
this.privKeyBytes.fill(0);
|
||||
this.privKeyBytes = undefined;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
toJSON() {
|
||||
return {
|
||||
xpriv: this.privateExtendedKey,
|
||||
xpub: this.publicExtendedKey,
|
||||
};
|
||||
}
|
||||
serialize(version, key) {
|
||||
if (!this.chainCode) {
|
||||
throw new Error('No chainCode set');
|
||||
}
|
||||
(0, _assert_1.bytes)(key, 33);
|
||||
return (0, utils_1.concatBytes)(toU32(version), new Uint8Array([this.depth]), toU32(this.parentFingerprint), toU32(this.index), this.chainCode, key);
|
||||
}
|
||||
}
|
||||
exports.HDKey = HDKey;
|
||||
//# sourceMappingURL=index.js.map
|
||||
-1
File diff suppressed because one or more lines are too long
-72
@@ -1,72 +0,0 @@
|
||||
{
|
||||
"name": "@scure/bip32",
|
||||
"version": "1.3.1",
|
||||
"description": "Secure, audited & minimal implementation of BIP32 hierarchical deterministic (HD) wallets over secp256k1",
|
||||
"files": [
|
||||
"index.ts",
|
||||
"lib/index.js",
|
||||
"lib/index.d.ts",
|
||||
"lib/index.js.map",
|
||||
"lib/esm/package.json",
|
||||
"lib/esm/index.js",
|
||||
"lib/esm/index.js.map"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/esm/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/index.d.ts",
|
||||
"import": "./lib/esm/index.js",
|
||||
"default": "./lib/index.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@noble/curves": "~1.1.0",
|
||||
"@noble/hashes": "~1.3.1",
|
||||
"@scure/base": "~1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "2.8.4",
|
||||
"typescript": "5.0.2"
|
||||
},
|
||||
"author": "Paul Miller (https://paulmillr.com)",
|
||||
"homepage": "https://paulmillr.com/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paulmillr/scure-bip32.git"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Patricio Palladino",
|
||||
"email": "patricio@nomiclabs.io"
|
||||
},
|
||||
{
|
||||
"name": "Paul Miller",
|
||||
"url": "https://paulmillr.com"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc -d && tsc -p tsconfig.esm.json",
|
||||
"lint": "prettier --check 'index.ts' 'test/*.test.ts'",
|
||||
"format": "prettier --write 'index.ts' 'test/*.test.ts'",
|
||||
"test": "cd test && tsc && node hdkey.test.js"
|
||||
},
|
||||
"keywords": [
|
||||
"bip32",
|
||||
"hierarchical",
|
||||
"deterministic",
|
||||
"hd key",
|
||||
"bip0032",
|
||||
"bip-32",
|
||||
"bip39",
|
||||
"micro",
|
||||
"scure",
|
||||
"mnemonic",
|
||||
"phrase",
|
||||
"code"
|
||||
],
|
||||
"funding": "https://paulmillr.com/funding/"
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2022 Patricio Palladino, Paul Miller (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.
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
# scure-bip39
|
||||
|
||||
Secure, [audited](#security) & minimal implementation of BIP39 mnemonic phrases.
|
||||
|
||||
Compared to popular `bip39` package, scure-bip39:
|
||||
|
||||
- Supports ESM and common.js
|
||||
- Supports tree-shaking: only actually used wordlists are bundled
|
||||
- Is 491KB all-bundled instead of 1.3MB
|
||||
- Uses 2 dependencies instead of 15
|
||||
- Wordlists are 157KB instead of 315KB
|
||||
- Had an external security [audit](#security) by Cure53
|
||||
|
||||
Check out [scure-bip32](https://github.com/paulmillr/scure-bip32) if you need
|
||||
hierarchical deterministic wallets ("HD Wallets").
|
||||
|
||||
### This library belongs to *scure*
|
||||
|
||||
> **scure** — secure, independently audited packages for every use case.
|
||||
|
||||
- All releases are signed with PGP keys
|
||||
- As minimal as possible
|
||||
- Check out all libraries:
|
||||
[base](https://github.com/paulmillr/scure-base),
|
||||
[bip32](https://github.com/paulmillr/scure-bip32),
|
||||
[bip39](https://github.com/paulmillr/scure-bip39),
|
||||
[btc-signer](https://github.com/paulmillr/scure-btc-signer)
|
||||
|
||||
## Usage
|
||||
|
||||
> npm install @scure/bip39
|
||||
|
||||
Or
|
||||
|
||||
> yarn add @scure/bip39
|
||||
|
||||
```js
|
||||
import * as bip39 from '@scure/bip39';
|
||||
import { wordlist } from '@scure/bip39/wordlists/english';
|
||||
|
||||
// Generate x random words. Uses Cryptographically-Secure Random Number Generator.
|
||||
const mn = bip39.generateMnemonic(wordlist);
|
||||
console.log(mn);
|
||||
|
||||
// Reversible: Converts mnemonic string to raw entropy in form of byte array.
|
||||
const ent = bip39.mnemonicToEntropy(mn, wordlist)
|
||||
|
||||
// Reversible: Converts raw entropy in form of byte array to mnemonic string.
|
||||
bip39.entropyToMnemonic(ent, wordlist);
|
||||
|
||||
// Validates mnemonic for being 12-24 words contained in `wordlist`.
|
||||
bip39.validateMnemonic(mn, wordlist);
|
||||
|
||||
// Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
|
||||
await bip39.mnemonicToSeed(mn, 'password');
|
||||
bip39.mnemonicToSeedSync(mn, 'password');
|
||||
```
|
||||
|
||||
This submodule contains the word lists defined by BIP39 for Czech, English, French, Italian, Japanese, Korean, Simplified and Traditional Chinese, and Spanish. These are not imported by default, as that would increase bundle sizes too much. Instead, you should import and use them explicitly.
|
||||
|
||||
```typescript
|
||||
function generateMnemonic(wordlist: string[], strength?: number): string;
|
||||
function mnemonicToEntropy(mnemonic: string, wordlist: string[]): Uint8Array;
|
||||
function entropyToMnemonic(entropy: Uint8Array, wordlist: string[]): string;
|
||||
function validateMnemonic(mnemonic: string, wordlist: string[]): boolean;
|
||||
function mnemonicToSeed(mnemonic: string, passphrase?: string): Promise<Uint8Array>;
|
||||
function mnemonicToSeedSync(mnemonic: string, passphrase?: string): Uint8Array;
|
||||
```
|
||||
|
||||
All wordlists:
|
||||
|
||||
```typescript
|
||||
import { wordlist as czech } from '@scure/bip39/wordlists/czech';
|
||||
import { wordlist as english } from '@scure/bip39/wordlists/english';
|
||||
import { wordlist as french } from '@scure/bip39/wordlists/french';
|
||||
import { wordlist as italian } from '@scure/bip39/wordlists/italian';
|
||||
import { wordlist as japanese } from '@scure/bip39/wordlists/japanese';
|
||||
import { wordlist as korean } from '@scure/bip39/wordlists/korean';
|
||||
import { wordlist as simp } from '@scure/bip39/wordlists/simplified-chinese';
|
||||
import { wordlist as spanish } from '@scure/bip39/wordlists/spanish';
|
||||
import { wordlist as trad } from '@scure/bip39/wordlists/traditional-chinese';
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
The library has been audited by Cure53 on Jan 5, 2022. Check out the audit [PDF](./audit/2022-01-05-cure53-audit-nbl2.pdf) & [URL](https://cure53.de/pentest-report_hashing-libs.pdf). See [changes since audit](https://github.com/paulmillr/scure-bip39/compare/1.0.0..main).
|
||||
|
||||
1. The library was initially developed for [js-ethereum-cryptography](https://github.com/ethereum/js-ethereum-cryptography)
|
||||
2. At commit [ae00e6d7](https://github.com/ethereum/js-ethereum-cryptography/commit/ae00e6d7d24fb3c76a1c7fe10039f6ecd120b77e), it
|
||||
was extracted to a separate package called `micro-bip39`
|
||||
3. After the audit we've decided to use NPM namespace for security. Since `@micro` namespace was taken, we've renamed the package to `@scure/bip39`
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](./LICENSE)
|
||||
|
||||
Copyright (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com)
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
import assert from '@noble/hashes/_assert';
|
||||
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
import { utils as baseUtils } from '@scure/base';
|
||||
const isJapanese = (wordlist) => wordlist[0] === '\u3042\u3044\u3053\u304f\u3057\u3093';
|
||||
function nfkd(str) {
|
||||
if (typeof str !== 'string')
|
||||
throw new TypeError(`Invalid mnemonic type: ${typeof str}`);
|
||||
return str.normalize('NFKD');
|
||||
}
|
||||
function normalize(str) {
|
||||
const norm = nfkd(str);
|
||||
const words = norm.split(' ');
|
||||
if (![12, 15, 18, 21, 24].includes(words.length))
|
||||
throw new Error('Invalid mnemonic');
|
||||
return { nfkd: norm, words };
|
||||
}
|
||||
function assertEntropy(entropy) {
|
||||
assert.bytes(entropy, 16, 20, 24, 28, 32);
|
||||
}
|
||||
export function generateMnemonic(wordlist, strength = 128) {
|
||||
assert.number(strength);
|
||||
if (strength % 32 !== 0 || strength > 256)
|
||||
throw new TypeError('Invalid entropy');
|
||||
return entropyToMnemonic(randomBytes(strength / 8), wordlist);
|
||||
}
|
||||
const calcChecksum = (entropy) => {
|
||||
const bitsLeft = 8 - entropy.length / 4;
|
||||
return new Uint8Array([(sha256(entropy)[0] >> bitsLeft) << bitsLeft]);
|
||||
};
|
||||
function getCoder(wordlist) {
|
||||
if (!Array.isArray(wordlist) || wordlist.length !== 2048 || typeof wordlist[0] !== 'string')
|
||||
throw new Error('Worlist: expected array of 2048 strings');
|
||||
wordlist.forEach((i) => {
|
||||
if (typeof i !== 'string')
|
||||
throw new Error(`Wordlist: non-string element: ${i}`);
|
||||
});
|
||||
return baseUtils.chain(baseUtils.checksum(1, calcChecksum), baseUtils.radix2(11, true), baseUtils.alphabet(wordlist));
|
||||
}
|
||||
export function mnemonicToEntropy(mnemonic, wordlist) {
|
||||
const { words } = normalize(mnemonic);
|
||||
const entropy = getCoder(wordlist).decode(words);
|
||||
assertEntropy(entropy);
|
||||
return entropy;
|
||||
}
|
||||
export function entropyToMnemonic(entropy, wordlist) {
|
||||
assertEntropy(entropy);
|
||||
const words = getCoder(wordlist).encode(entropy);
|
||||
return words.join(isJapanese(wordlist) ? '\u3000' : ' ');
|
||||
}
|
||||
export function validateMnemonic(mnemonic, wordlist) {
|
||||
try {
|
||||
mnemonicToEntropy(mnemonic, wordlist);
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const salt = (passphrase) => nfkd(`mnemonic${passphrase}`);
|
||||
export function mnemonicToSeed(mnemonic, passphrase = '') {
|
||||
return pbkdf2Async(sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
|
||||
}
|
||||
export function mnemonicToSeedSync(mnemonic, passphrase = '') {
|
||||
return pbkdf2(sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,uBAAuB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AAGjD,MAAM,UAAU,GAAG,CAAC,QAAkB,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,sCAAsC,CAAC;AAKlG,SAAS,IAAI,CAAC,GAAW;IACvB,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,0BAA0B,OAAO,GAAG,EAAE,CAAC,CAAC;IACzF,OAAO,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtF,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,aAAa,CAAC,OAAmB;IACxC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC5C,CAAC;AAUD,MAAM,UAAU,gBAAgB,CAAC,QAAkB,EAAE,WAAmB,GAAG;IACzE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxB,IAAI,QAAQ,GAAG,EAAE,KAAK,CAAC,IAAI,QAAQ,GAAG,GAAG;QAAE,MAAM,IAAI,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAClF,OAAO,iBAAiB,CAAC,WAAW,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,YAAY,GAAG,CAAC,OAAmB,EAAE,EAAE;IAE3C,MAAM,QAAQ,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAGxC,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC;AACxE,CAAC,CAAC;AAEF,SAAS,QAAQ,CAAC,QAAkB;IAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ;QACzF,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QACrB,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IACH,OAAO,SAAS,CAAC,KAAK,CACpB,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,EACnC,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,EAC1B,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAC7B,CAAC;AACJ,CAAC;AAeD,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,QAAkB;IACpE,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjD,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,OAAO,OAAO,CAAC;AACjB,CAAC;AAeD,MAAM,UAAU,iBAAiB,CAAC,OAAmB,EAAE,QAAkB;IACvE,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC3D,CAAC;AAKD,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,QAAkB;IACnE,IAAI;QACF,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;KACvC;IAAC,OAAO,CAAC,EAAE;QACV,OAAO,KAAK,CAAC;KACd;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,IAAI,GAAG,CAAC,UAAkB,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,UAAU,EAAE,CAAC,CAAC;AAYnE,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,UAAU,GAAG,EAAE;IAC9D,OAAO,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;AACjG,CAAC;AAYD,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,UAAU,GAAG,EAAE;IAClE,OAAO,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;AAC5F,CAAC"}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
-2049
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"czech.js","sourceRoot":"","sources":["../../src/wordlists/czech.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+/D7B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC"}
|
||||
-2049
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"english.js","sourceRoot":"","sources":["../../src/wordlists/english.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA+/D9B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC"}
|
||||
-2049
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"french.js","sourceRoot":"","sources":["../../src/wordlists/french.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SA+/DzB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC"}
|
||||
-2049
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"italian.js","sourceRoot":"","sources":["../../src/wordlists/italian.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA+/D5B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC"}
|
||||
-2049
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"japanese.js","sourceRoot":"","sources":["../../src/wordlists/japanese.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA+/D9B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC"}
|
||||
-2049
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"korean.js","sourceRoot":"","sources":["../../src/wordlists/korean.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+/D3B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC"}
|
||||
-2049
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"simplified-chinese.js","sourceRoot":"","sources":["../../src/wordlists/simplified-chinese.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+/DhC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC"}
|
||||
-2049
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"spanish.js","sourceRoot":"","sources":["../../src/wordlists/spanish.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA+/D5B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC"}
|
||||
-2049
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"traditional-chinese.js","sourceRoot":"","sources":["../../src/wordlists/traditional-chinese.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+/DhC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC"}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Generate x random words. Uses Cryptographically-Secure Random Number Generator.
|
||||
* @param wordlist imported wordlist for specific language
|
||||
* @param strength mnemonic strength 128-256 bits
|
||||
* @example
|
||||
* generateMnemonic(wordlist, 128)
|
||||
* // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
|
||||
*/
|
||||
export declare function generateMnemonic(wordlist: string[], strength?: number): string;
|
||||
/**
|
||||
* Reversible: Converts mnemonic string to raw entropy in form of byte array.
|
||||
* @param mnemonic 12-24 words
|
||||
* @param wordlist imported wordlist for specific language
|
||||
* @example
|
||||
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
|
||||
* mnemonicToEntropy(mnem, wordlist)
|
||||
* // Produces
|
||||
* new Uint8Array([
|
||||
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
||||
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
|
||||
* ])
|
||||
*/
|
||||
export declare function mnemonicToEntropy(mnemonic: string, wordlist: string[]): Uint8Array;
|
||||
/**
|
||||
* Reversible: Converts raw entropy in form of byte array to mnemonic string.
|
||||
* @param entropy byte array
|
||||
* @param wordlist imported wordlist for specific language
|
||||
* @returns 12-24 words
|
||||
* @example
|
||||
* const ent = new Uint8Array([
|
||||
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
||||
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
|
||||
* ]);
|
||||
* entropyToMnemonic(ent, wordlist);
|
||||
* // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
|
||||
*/
|
||||
export declare function entropyToMnemonic(entropy: Uint8Array, wordlist: string[]): string;
|
||||
/**
|
||||
* Validates mnemonic for being 12-24 words contained in `wordlist`.
|
||||
*/
|
||||
export declare function validateMnemonic(mnemonic: string, wordlist: string[]): boolean;
|
||||
/**
|
||||
* Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
|
||||
* @param mnemonic 12-24 words
|
||||
* @param passphrase string that will additionally protect the key
|
||||
* @returns 64 bytes of key data
|
||||
* @example
|
||||
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
|
||||
* await mnemonicToSeed(mnem, 'password');
|
||||
* // new Uint8Array([...64 bytes])
|
||||
*/
|
||||
export declare function mnemonicToSeed(mnemonic: string, passphrase?: string): Promise<Uint8Array>;
|
||||
/**
|
||||
* Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
|
||||
* @param mnemonic 12-24 words
|
||||
* @param passphrase string that will additionally protect the key
|
||||
* @returns 64 bytes of key data
|
||||
* @example
|
||||
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
|
||||
* mnemonicToSeedSync(mnem, 'password');
|
||||
* // new Uint8Array([...64 bytes])
|
||||
*/
|
||||
export declare function mnemonicToSeedSync(mnemonic: string, passphrase?: string): Uint8Array;
|
||||
-142
@@ -1,142 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.mnemonicToSeedSync = exports.mnemonicToSeed = exports.validateMnemonic = exports.entropyToMnemonic = exports.mnemonicToEntropy = exports.generateMnemonic = void 0;
|
||||
/*! scure-bip39 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) */
|
||||
const _assert_1 = require("@noble/hashes/_assert");
|
||||
const pbkdf2_1 = require("@noble/hashes/pbkdf2");
|
||||
const sha256_1 = require("@noble/hashes/sha256");
|
||||
const sha512_1 = require("@noble/hashes/sha512");
|
||||
const utils_1 = require("@noble/hashes/utils");
|
||||
const base_1 = require("@scure/base");
|
||||
// Japanese wordlist
|
||||
const isJapanese = (wordlist) => wordlist[0] === '\u3042\u3044\u3053\u304f\u3057\u3093';
|
||||
// Normalization replaces equivalent sequences of characters
|
||||
// so that any two texts that are equivalent will be reduced
|
||||
// to the same sequence of code points, called the normal form of the original text.
|
||||
function nfkd(str) {
|
||||
if (typeof str !== 'string')
|
||||
throw new TypeError(`Invalid mnemonic type: ${typeof str}`);
|
||||
return str.normalize('NFKD');
|
||||
}
|
||||
function normalize(str) {
|
||||
const norm = nfkd(str);
|
||||
const words = norm.split(' ');
|
||||
if (![12, 15, 18, 21, 24].includes(words.length))
|
||||
throw new Error('Invalid mnemonic');
|
||||
return { nfkd: norm, words };
|
||||
}
|
||||
function assertEntropy(entropy) {
|
||||
_assert_1.default.bytes(entropy, 16, 20, 24, 28, 32);
|
||||
}
|
||||
/**
|
||||
* Generate x random words. Uses Cryptographically-Secure Random Number Generator.
|
||||
* @param wordlist imported wordlist for specific language
|
||||
* @param strength mnemonic strength 128-256 bits
|
||||
* @example
|
||||
* generateMnemonic(wordlist, 128)
|
||||
* // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
|
||||
*/
|
||||
function generateMnemonic(wordlist, strength = 128) {
|
||||
_assert_1.default.number(strength);
|
||||
if (strength % 32 !== 0 || strength > 256)
|
||||
throw new TypeError('Invalid entropy');
|
||||
return entropyToMnemonic((0, utils_1.randomBytes)(strength / 8), wordlist);
|
||||
}
|
||||
exports.generateMnemonic = generateMnemonic;
|
||||
const calcChecksum = (entropy) => {
|
||||
// Checksum is ent.length/4 bits long
|
||||
const bitsLeft = 8 - entropy.length / 4;
|
||||
// Zero rightmost "bitsLeft" bits in byte
|
||||
// For example: bitsLeft=4 val=10111101 -> 10110000
|
||||
return new Uint8Array([((0, sha256_1.sha256)(entropy)[0] >> bitsLeft) << bitsLeft]);
|
||||
};
|
||||
function getCoder(wordlist) {
|
||||
if (!Array.isArray(wordlist) || wordlist.length !== 2048 || typeof wordlist[0] !== 'string')
|
||||
throw new Error('Worlist: expected array of 2048 strings');
|
||||
wordlist.forEach((i) => {
|
||||
if (typeof i !== 'string')
|
||||
throw new Error(`Wordlist: non-string element: ${i}`);
|
||||
});
|
||||
return base_1.utils.chain(base_1.utils.checksum(1, calcChecksum), base_1.utils.radix2(11, true), base_1.utils.alphabet(wordlist));
|
||||
}
|
||||
/**
|
||||
* Reversible: Converts mnemonic string to raw entropy in form of byte array.
|
||||
* @param mnemonic 12-24 words
|
||||
* @param wordlist imported wordlist for specific language
|
||||
* @example
|
||||
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
|
||||
* mnemonicToEntropy(mnem, wordlist)
|
||||
* // Produces
|
||||
* new Uint8Array([
|
||||
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
||||
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
|
||||
* ])
|
||||
*/
|
||||
function mnemonicToEntropy(mnemonic, wordlist) {
|
||||
const { words } = normalize(mnemonic);
|
||||
const entropy = getCoder(wordlist).decode(words);
|
||||
assertEntropy(entropy);
|
||||
return entropy;
|
||||
}
|
||||
exports.mnemonicToEntropy = mnemonicToEntropy;
|
||||
/**
|
||||
* Reversible: Converts raw entropy in form of byte array to mnemonic string.
|
||||
* @param entropy byte array
|
||||
* @param wordlist imported wordlist for specific language
|
||||
* @returns 12-24 words
|
||||
* @example
|
||||
* const ent = new Uint8Array([
|
||||
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
||||
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
|
||||
* ]);
|
||||
* entropyToMnemonic(ent, wordlist);
|
||||
* // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
|
||||
*/
|
||||
function entropyToMnemonic(entropy, wordlist) {
|
||||
assertEntropy(entropy);
|
||||
const words = getCoder(wordlist).encode(entropy);
|
||||
return words.join(isJapanese(wordlist) ? '\u3000' : ' ');
|
||||
}
|
||||
exports.entropyToMnemonic = entropyToMnemonic;
|
||||
/**
|
||||
* Validates mnemonic for being 12-24 words contained in `wordlist`.
|
||||
*/
|
||||
function validateMnemonic(mnemonic, wordlist) {
|
||||
try {
|
||||
mnemonicToEntropy(mnemonic, wordlist);
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
exports.validateMnemonic = validateMnemonic;
|
||||
const salt = (passphrase) => nfkd(`mnemonic${passphrase}`);
|
||||
/**
|
||||
* Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
|
||||
* @param mnemonic 12-24 words
|
||||
* @param passphrase string that will additionally protect the key
|
||||
* @returns 64 bytes of key data
|
||||
* @example
|
||||
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
|
||||
* await mnemonicToSeed(mnem, 'password');
|
||||
* // new Uint8Array([...64 bytes])
|
||||
*/
|
||||
function mnemonicToSeed(mnemonic, passphrase = '') {
|
||||
return (0, pbkdf2_1.pbkdf2Async)(sha512_1.sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
|
||||
}
|
||||
exports.mnemonicToSeed = mnemonicToSeed;
|
||||
/**
|
||||
* Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
|
||||
* @param mnemonic 12-24 words
|
||||
* @param passphrase string that will additionally protect the key
|
||||
* @returns 64 bytes of key data
|
||||
* @example
|
||||
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
|
||||
* mnemonicToSeedSync(mnem, 'password');
|
||||
* // new Uint8Array([...64 bytes])
|
||||
*/
|
||||
function mnemonicToSeedSync(mnemonic, passphrase = '') {
|
||||
return (0, pbkdf2_1.pbkdf2)(sha512_1.sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
|
||||
}
|
||||
exports.mnemonicToSeedSync = mnemonicToSeedSync;
|
||||
-116
@@ -1,116 +0,0 @@
|
||||
{
|
||||
"name": "@scure/bip39",
|
||||
"version": "1.2.1",
|
||||
"description": "Secure, audited & minimal implementation of BIP39 mnemonic phrases",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"wordlists/*.js",
|
||||
"wordlists/*.d.ts",
|
||||
"esm"
|
||||
],
|
||||
"types": "index.d.ts",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "~1.3.0",
|
||||
"@scure/base": "~1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "2.8.4",
|
||||
"typescript": "5.0.2"
|
||||
},
|
||||
"author": "Paul Miller (https://paulmillr.com)",
|
||||
"homepage": "https://paulmillr.com/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paulmillr/scure-bip39.git"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Patricio Palladino",
|
||||
"email": "patricio@nomiclabs.io"
|
||||
},
|
||||
{
|
||||
"name": "Paul Miller",
|
||||
"url": "https://paulmillr.com"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc && tsc -p tsconfig.esm.json",
|
||||
"lint": "prettier --check 'src/**/*.ts' 'test/*.test.ts'",
|
||||
"format": "prettier --write 'src/**/*.ts' 'test/*.test.ts'",
|
||||
"test": "cd test && tsc && node bip39.test.js"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./esm/index.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./index": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./esm/index.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./wordlists/czech": {
|
||||
"types": "./wordlists/czech.d.ts",
|
||||
"import": "./esm/wordlists/czech.js",
|
||||
"default": "./wordlists/czech.js"
|
||||
},
|
||||
"./wordlists/english": {
|
||||
"types": "./wordlists/english.d.ts",
|
||||
"import": "./esm/wordlists/english.js",
|
||||
"default": "./wordlists/english.js"
|
||||
},
|
||||
"./wordlists/french": {
|
||||
"types": "./wordlists/french.d.ts",
|
||||
"import": "./esm/wordlists/french.js",
|
||||
"default": "./wordlists/french.js"
|
||||
},
|
||||
"./wordlists/italian": {
|
||||
"types": "./wordlists/italian.d.ts",
|
||||
"import": "./esm/wordlists/italian.js",
|
||||
"default": "./wordlists/italian.js"
|
||||
},
|
||||
"./wordlists/japanese": {
|
||||
"types": "./wordlists/japanese.d.ts",
|
||||
"import": "./esm/wordlists/japanese.js",
|
||||
"default": "./wordlists/japanese.js"
|
||||
},
|
||||
"./wordlists/korean": {
|
||||
"types": "./wordlists/korean.d.ts",
|
||||
"import": "./esm/wordlists/korean.js",
|
||||
"default": "./wordlists/korean.js"
|
||||
},
|
||||
"./wordlists/simplified-chinese": {
|
||||
"types": "./wordlists/simplified-chinese.d.ts",
|
||||
"import": "./esm/wordlists/simplified-chinese.js",
|
||||
"default": "./wordlists/simplified-chinese.js"
|
||||
},
|
||||
"./wordlists/spanish": {
|
||||
"types": "./wordlists/spanish.d.ts",
|
||||
"import": "./esm/wordlists/spanish.js",
|
||||
"default": "./wordlists/spanish.js"
|
||||
},
|
||||
"./wordlists/traditional-chinese": {
|
||||
"types": "./wordlists/traditional-chinese.d.ts",
|
||||
"import": "./esm/wordlists/traditional-chinese.js",
|
||||
"default": "./wordlists/traditional-chinese.js"
|
||||
}
|
||||
},
|
||||
"keywords": [
|
||||
"bip39",
|
||||
"mnemonic",
|
||||
"phrase",
|
||||
"code",
|
||||
"bip0039",
|
||||
"bip-39",
|
||||
"micro",
|
||||
"scure",
|
||||
"wordlist",
|
||||
"noble"
|
||||
],
|
||||
"funding": "https://paulmillr.com/funding/"
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
export declare const wordlist: string[];
|
||||
-2051
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
export declare const wordlist: string[];
|
||||
-2051
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
export declare const wordlist: string[];
|
||||
-2051
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
export declare const wordlist: string[];
|
||||
-2051
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
export declare const wordlist: string[];
|
||||
-2051
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
export declare const wordlist: string[];
|
||||
-2051
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
export declare const wordlist: string[];
|
||||
-2051
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
export declare const wordlist: string[];
|
||||
-2051
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
export declare const wordlist: string[];
|
||||
-2051
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user