Add comprehensive installation and setup documentation

- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
This commit is contained in:
Dorian
2026-01-27 17:18:21 +00:00
parent a81f655133
commit 0d073fa89e
22658 changed files with 4494151 additions and 6 deletions
+21
View File
@@ -0,0 +1,21 @@
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.
+214
View File
@@ -0,0 +1,214 @@
# scure-base
Audited & minimal implementation of bech32, base64, base58, base32 & base16.
- 🔒 [Audited](#security) by an independent security firm
- 🔻 Tree-shakeable: unused code is excluded from your builds
- 📦 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** — audited micro-libraries.
- Zero or minimal dependencies
- Highly readable TypeScript / JS code
- PGP-signed releases and transparent NPM builds
- Check out [homepage](https://paulmillr.com/noble/#scure) & 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`
> `deno add @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,
base32nopad,
base32hex,
base32hexnopad,
base32crockford,
base64nopad,
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 { createBase58check } from '@scure/base';
createBase58check(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 witness 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 composable 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('Wordlist: 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
- [scure-btc-signer](https://github.com/paulmillr/scure-btc-signer)
- [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/)
- [coinspace](https://github.com/CoinSpace/CoinSpace) wallet and its modules:
[ada](https://github.com/CoinSpace/cs-cardano-wallet),
[btc](https://github.com/CoinSpace/cs-bitcoin-wallet)
[eos](https://github.com/CoinSpace/cs-eos-wallet),
[sol](https://github.com/CoinSpace/cs-solana-wallet),
[xmr](https://github.com/CoinSpace/cs-monero-wallet)
## License
MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.
+616
View File
@@ -0,0 +1,616 @@
/*! 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;
}
function isBytes(a: unknown): a is Uint8Array {
return (
a instanceof Uint8Array ||
(a != null && typeof a === 'object' && a.constructor.name === '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>>> {
const id = (a: any) => a;
// 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 = args.map((x) => x.encode).reduceRight(wrap, id);
// Construct chain of args[0].decode(args[1].decode(...))
const decode = args.map((x) => x.decode).reduce(wrap, id);
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): 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 (!isBytes(bytes)) 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 numbers');
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 (!isBytes(bytes)) 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 numbers');
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 (!isBytes(data)) 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 (!isBytes(data)) 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;
},
};
}
// prettier-ignore
export const utils = {
alphabet, chain, checksum, convertRadix, convertRadix2, 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 base32nopad: BytesCoder = /* @__PURE__ */ chain(
radix2(5),
alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'),
join('')
);
export const base32hex: BytesCoder = /* @__PURE__ */ chain(
radix2(5),
alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'),
padding(5),
join('')
);
export const base32hexnopad: BytesCoder = /* @__PURE__ */ chain(
radix2(5),
alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'),
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 base64nopad: BytesCoder = /* @__PURE__ */ chain(
radix2(6),
alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'),
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 createBase58check = (sha256: (data: Uint8Array) => Uint8Array): BytesCoder =>
chain(
checksum(4, (data) => sha256(sha256(data))),
base58
);
// legacy export, bad name
export const base58check = createBase58check;
// 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));
}
export interface Bech32 {
encode<Prefix extends string>(
prefix: Prefix,
words: number[] | Uint8Array,
limit?: number | false
): `${Lowercase<Prefix>}1${string}`;
decode<Prefix extends string>(
str: `${Prefix}1${string}`,
limit?: number | false
): Bech32Decoded<Prefix>;
encodeFromBytes(prefix: string, bytes: Uint8Array): string;
decodeToBytes(str: string): Bech32DecodedWithArray;
decodeUnsafe(str: string, limit?: number | false): void | Bech32Decoded<string>;
fromWords(to: number[]): Uint8Array;
fromWordsUnsafe(to: number[]): void | Uint8Array;
toWords(from: Uint8Array): number[];
}
/**
* @__NO_SIDE_EFFECTS__
*/
function genBech32(encoding: 'bech32' | 'bech32m'): Bech32 {
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 (words instanceof Uint8Array) words = Array.from(words);
if (!Array.isArray(words) || (words.length && typeof words[0] !== 'number'))
throw new Error(`bech32.encode words should be array of numbers, not ${typeof words}`);
if (prefix.length === 0) throw new TypeError(`Invalid prefix length ${prefix.length}`);
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`);
const sepIndex = lowered.lastIndexOf('1');
if (sepIndex === 0 || sepIndex === -1)
throw new Error(`Letter "1" must be present between prefix and data only`);
const prefix = lowered.slice(0, sepIndex);
const data = lowered.slice(sepIndex + 1);
if (data.length < 6) throw new Error('Data must be at least 6 characters long');
const words = BECH_ALPHABET.decode(data).slice(0, -6);
const sum = bechChecksum(prefix, words, ENCODING_CONST);
if (!data.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) };
}
function encodeFromBytes(prefix: string, bytes: Uint8Array) {
return encode(prefix, toWords(bytes));
}
return {
encode,
decode,
encodeFromBytes,
decodeToBytes,
decodeUnsafe,
fromWords,
fromWordsUnsafe,
toWords,
};
}
export const bech32: Bech32 = /* @__PURE__ */ genBech32('bech32');
export const bech32m: Bech32 = /* @__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 (!isBytes(bytes)) 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;
+132
View File
@@ -0,0 +1,132 @@
/*! 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[]>;
/**
* Slow: O(n^2) time complexity
* @__NO_SIDE_EFFECTS__
*/
declare function convertRadix(data: number[], from: number, to: number): number[];
/**
* Implemented with numbers, because BigInt is 5x slower
* @__NO_SIDE_EFFECTS__
*/
declare function convertRadix2(data: number[], from: number, to: number, padding: boolean): number[];
/**
* @__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;
convertRadix: typeof convertRadix;
convertRadix2: typeof convertRadix2;
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 base32nopad: BytesCoder;
export declare const base32hex: BytesCoder;
export declare const base32hexnopad: BytesCoder;
export declare const base32crockford: BytesCoder;
export declare const base64: BytesCoder;
export declare const base64nopad: 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 createBase58check: (sha256: (data: Uint8Array) => Uint8Array) => 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 interface Bech32 {
encode<Prefix extends string>(prefix: Prefix, words: number[] | Uint8Array, limit?: number | false): `${Lowercase<Prefix>}1${string}`;
decode<Prefix extends string>(str: `${Prefix}1${string}`, limit?: number | false): Bech32Decoded<Prefix>;
encodeFromBytes(prefix: string, bytes: Uint8Array): string;
decodeToBytes(str: string): Bech32DecodedWithArray;
decodeUnsafe(str: string, limit?: number | false): void | Bech32Decoded<string>;
fromWords(to: number[]): Uint8Array;
fromWordsUnsafe(to: number[]): void | Uint8Array;
toWords(from: Uint8Array): number[];
}
export declare const bech32: Bech32;
export declare const bech32m: Bech32;
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
View File
@@ -0,0 +1 @@
{"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;AAWD,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,CAShG;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;AAUD;;;GAGG;AACH,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAwCxE;AAKD;;;GAGG;AACH,iBAAS,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,CA2B3F;AAED;;GAEG;AACH,iBAAS,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAavD;AAED;;;;GAIG;AACH,iBAAS,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAgB7E;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,CAsB/B;AAGD,eAAO,MAAM,KAAK;;;;;;;;;;CAEjB,CAAC;AAIF,eAAO,MAAM,MAAM,EAAE,UAIpB,CAAC;AACF,eAAO,MAAM,MAAM,EAAE,UAKpB,CAAC;AACF,eAAO,MAAM,WAAW,EAAE,UAIzB,CAAC;AACF,eAAO,MAAM,SAAS,EAAE,UAKvB,CAAC;AACF,eAAO,MAAM,cAAc,EAAE,UAI5B,CAAC;AACF,eAAO,MAAM,eAAe,EAAE,UAK7B,CAAC;AACF,eAAO,MAAM,MAAM,EAAE,UAKpB,CAAC;AACF,eAAO,MAAM,WAAW,EAAE,UAIzB,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,iBAAiB,WAAY,CAAC,IAAI,EAAE,UAAU,KAAK,UAAU,KAAG,UAI1E,CAAC;AAEJ,eAAO,MAAM,WAAW,WANkB,CAAC,IAAI,EAAE,UAAU,KAAK,UAAU,KAAG,UAMjC,CAAC;AAI7C,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;AAuCD,MAAM,WAAW,MAAM;IACrB,MAAM,CAAC,MAAM,SAAS,MAAM,EAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,EAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,GACrB,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;IACpC,MAAM,CAAC,MAAM,SAAS,MAAM,EAC1B,GAAG,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE,EAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,GACrB,aAAa,CAAC,MAAM,CAAC,CAAC;IACzB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAAC;IAC3D,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,sBAAsB,CAAC;IACnD,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAChF,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;IACpC,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,UAAU,CAAC;IACjD,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,CAAC;CACrC;AA+ED,eAAO,MAAM,MAAM,EAAE,MAA4C,CAAC;AAClE,eAAO,MAAM,OAAO,EAAE,MAA6C,CAAC;AAKpE,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"}
+489
View File
@@ -0,0 +1,489 @@
/*! 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}`);
}
function isBytes(a) {
return (a instanceof Uint8Array ||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
}
/**
* @__NO_SIDE_EFFECTS__
*/
function chain(...args) {
const id = (a) => a;
// 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 = args.map((x) => x.encode).reduceRight(wrap, id);
// Construct chain of args[0].decode(args[1].decode(...))
const decode = args.map((x) => x.decode).reduce(wrap, id);
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 (!isBytes(bytes))
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 numbers');
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 (!isBytes(bytes))
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 numbers');
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 (!isBytes(data))
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 (!isBytes(data))
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;
},
};
}
// prettier-ignore
export const utils = {
alphabet, chain, checksum, convertRadix, convertRadix2, 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 base32nopad = /* @__PURE__ */ chain(radix2(5), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'), join(''));
export const base32hex = /* @__PURE__ */ chain(radix2(5), alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'), padding(5), join(''));
export const base32hexnopad = /* @__PURE__ */ chain(radix2(5), alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'), 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 base64nopad = /* @__PURE__ */ chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'), 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 createBase58check = (sha256) => chain(checksum(4, (data) => sha256(sha256(data))), base58);
// legacy export, bad name
export const base58check = createBase58check;
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 (words instanceof Uint8Array)
words = Array.from(words);
if (!Array.isArray(words) || (words.length && typeof words[0] !== 'number'))
throw new Error(`bech32.encode words should be array of numbers, not ${typeof words}`);
if (prefix.length === 0)
throw new TypeError(`Invalid prefix length ${prefix.length}`);
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`);
const sepIndex = lowered.lastIndexOf('1');
if (sepIndex === 0 || sepIndex === -1)
throw new Error(`Letter "1" must be present between prefix and data only`);
const prefix = lowered.slice(0, sepIndex);
const data = lowered.slice(sepIndex + 1);
if (data.length < 6)
throw new Error('Data must be at least 6 characters long');
const words = BECH_ALPHABET.decode(data).slice(0, -6);
const sum = bechChecksum(prefix, words, ENCODING_CONST);
if (!data.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) };
}
function encodeFromBytes(prefix, bytes) {
return encode(prefix, toWords(bytes));
}
return {
encode,
decode,
encodeFromBytes,
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 (!isBytes(bytes))
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;
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{ "type": "module", "sideEffects": false }
+132
View File
@@ -0,0 +1,132 @@
/*! 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[]>;
/**
* Slow: O(n^2) time complexity
* @__NO_SIDE_EFFECTS__
*/
declare function convertRadix(data: number[], from: number, to: number): number[];
/**
* Implemented with numbers, because BigInt is 5x slower
* @__NO_SIDE_EFFECTS__
*/
declare function convertRadix2(data: number[], from: number, to: number, padding: boolean): number[];
/**
* @__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;
convertRadix: typeof convertRadix;
convertRadix2: typeof convertRadix2;
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 base32nopad: BytesCoder;
export declare const base32hex: BytesCoder;
export declare const base32hexnopad: BytesCoder;
export declare const base32crockford: BytesCoder;
export declare const base64: BytesCoder;
export declare const base64nopad: 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 createBase58check: (sha256: (data: Uint8Array) => Uint8Array) => 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 interface Bech32 {
encode<Prefix extends string>(prefix: Prefix, words: number[] | Uint8Array, limit?: number | false): `${Lowercase<Prefix>}1${string}`;
decode<Prefix extends string>(str: `${Prefix}1${string}`, limit?: number | false): Bech32Decoded<Prefix>;
encodeFromBytes(prefix: string, bytes: Uint8Array): string;
decodeToBytes(str: string): Bech32DecodedWithArray;
decodeUnsafe(str: string, limit?: number | false): void | Bech32Decoded<string>;
fromWords(to: number[]): Uint8Array;
fromWordsUnsafe(to: number[]): void | Uint8Array;
toWords(from: Uint8Array): number[];
}
export declare const bech32: Bech32;
export declare const bech32m: Bech32;
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
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
+496
View File
@@ -0,0 +1,496 @@
"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.createBase58check = exports.base58xmr = exports.base58xrp = exports.base58flickr = exports.base58 = exports.base64urlnopad = exports.base64url = exports.base64nopad = exports.base64 = exports.base32crockford = exports.base32hexnopad = exports.base32hex = exports.base32nopad = exports.base32 = exports.base16 = exports.utils = void 0;
exports.assertNumber = assertNumber;
// Utilities
/**
* @__NO_SIDE_EFFECTS__
*/
function assertNumber(n) {
if (!Number.isSafeInteger(n))
throw new Error(`Wrong integer: ${n}`);
}
function isBytes(a) {
return (a instanceof Uint8Array ||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
}
/**
* @__NO_SIDE_EFFECTS__
*/
function chain(...args) {
const id = (a) => a;
// 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 = args.map((x) => x.encode).reduceRight(wrap, id);
// Construct chain of args[0].decode(args[1].decode(...))
const decode = args.map((x) => x.decode).reduce(wrap, id);
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 (!isBytes(bytes))
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 numbers');
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 (!isBytes(bytes))
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 numbers');
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 (!isBytes(data))
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 (!isBytes(data))
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;
},
};
}
// prettier-ignore
exports.utils = {
alphabet, chain, checksum, convertRadix, convertRadix2, 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.base32nopad = chain(radix2(5), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'), join(''));
exports.base32hex = chain(radix2(5), alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'), padding(5), join(''));
exports.base32hexnopad = chain(radix2(5), alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'), 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.base64nopad = chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'), 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 createBase58check = (sha256) => chain(checksum(4, (data) => sha256(sha256(data))), exports.base58);
exports.createBase58check = createBase58check;
// legacy export, bad name
exports.base58check = exports.createBase58check;
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 (words instanceof Uint8Array)
words = Array.from(words);
if (!Array.isArray(words) || (words.length && typeof words[0] !== 'number'))
throw new Error(`bech32.encode words should be array of numbers, not ${typeof words}`);
if (prefix.length === 0)
throw new TypeError(`Invalid prefix length ${prefix.length}`);
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`);
const sepIndex = lowered.lastIndexOf('1');
if (sepIndex === 0 || sepIndex === -1)
throw new Error(`Letter "1" must be present between prefix and data only`);
const prefix = lowered.slice(0, sepIndex);
const data = lowered.slice(sepIndex + 1);
if (data.length < 6)
throw new Error('Data must be at least 6 characters long');
const words = BECH_ALPHABET.decode(data).slice(0, -6);
const sum = bechChecksum(prefix, words, ENCODING_CONST);
if (!data.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) };
}
function encodeFromBytes(prefix, bytes) {
return encode(prefix, toWords(bytes));
}
return {
encode,
decode,
encodeFromBytes,
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 (!isBytes(bytes))
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;
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+64
View File
@@ -0,0 +1,64 @@
{
"name": "@scure/base",
"version": "1.1.9",
"description": "Secure, audited & 0-dep implementation of base64, bech32, base58, base32 & base16",
"files": [
"lib/index.js",
"lib/index.js.map",
"lib/index.d.ts",
"lib/index.d.ts.map",
"lib/esm/index.js",
"lib/esm/index.js.map",
"lib/esm/index.d.ts",
"lib/esm/index.d.ts.map",
"lib/esm/package.json",
"index.ts"
],
"main": "lib/index.js",
"module": "lib/esm/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"import": "./lib/esm/index.js",
"require": "./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": {
"@paulmillr/jsbt": "0.2.1",
"micro-should": "0.4.0",
"prettier": "3.3.2",
"typescript": "5.5.2"
},
"keywords": [
"bech32",
"bech32m",
"base64",
"base58",
"base32",
"base16",
"rfc4648",
"rfc3548",
"crockford",
"encode",
"encoder",
"base-x",
"base"
],
"funding": "https://paulmillr.com/funding/"
}