@cmdcode/musig2
Version:
Create digital signatures based on the Musig2 protocol.
1,464 lines (1,443 loc) • 149 kB
JavaScript
'use strict';
const MUSIG_DEFAULTS = {
key_tweaks: []
};
const CONST$1 = {
SAFE_MIN_VALUE: 0xffn ** 16n
};
function musig_config(options = {}) {
return { ...MUSIG_DEFAULTS, ...options };
}
function number(n) {
if (!Number.isSafeInteger(n) || n < 0)
throw new Error(`Wrong positive integer: ${n}`);
}
// copied from utils
function isBytes$3(a) {
return (a instanceof Uint8Array ||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
}
function bytes(b, ...lengths) {
if (!isBytes$3(b))
throw new Error('Expected Uint8Array');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
}
function hash(hash) {
if (typeof hash !== 'function' || typeof hash.create !== 'function')
throw new Error('Hash should be wrapped by utils.wrapConstructor');
number(hash.outputLen);
number(hash.blockLen);
}
function exists(instance, checkFinished = true) {
if (instance.destroyed)
throw new Error('Hash instance has been destroyed');
if (checkFinished && instance.finished)
throw new Error('Hash#digest() has already been called');
}
function output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
}
}
const crypto = typeof globalThis === 'object' && 'crypto' in globalThis ? globalThis.crypto : undefined;
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.
function isBytes$2(a) {
return (a instanceof Uint8Array ||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
}
// Cast array to view
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
// The rotate right (circular right shift) operation for uint32
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
// big-endian hardware is rare. Just in case someone still decides to run hashes:
// early-throw an error because we don't support BE yet.
// Other libraries would silently corrupt the data instead of throwing an error,
// when they don't support it.
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
if (!isLE)
throw new Error('Non little-endian hardware is not supported');
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
function utf8ToBytes$1(str) {
if (typeof str !== 'string')
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes$1(data);
if (!isBytes$2(data))
throw new Error(`expected Uint8Array, got ${typeof data}`);
return data;
}
/**
* Copies several Uint8Arrays into one.
*/
function concatBytes$1(...arrays) {
let sum = 0;
for (let i = 0; i < arrays.length; i++) {
const a = arrays[i];
if (!isBytes$2(a))
throw new Error('Uint8Array expected');
sum += a.length;
}
const res = new Uint8Array(sum);
for (let i = 0, pad = 0; i < arrays.length; i++) {
const a = arrays[i];
res.set(a, pad);
pad += a.length;
}
return res;
}
// For runtime check if class implements interface
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
/**
* Secure PRNG. Uses `crypto.getRandomValues`, which defers to OS.
*/
function randomBytes(bytesLength = 32) {
if (crypto && typeof crypto.getRandomValues === 'function') {
return crypto.getRandomValues(new Uint8Array(bytesLength));
}
throw new Error('crypto.getRandomValues must be defined');
}
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
// Base SHA2 class (RFC 6234)
class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
if (take === blockLen) {
const dataView = createView(data);
for (; blockLen <= len - pos; pos += blockLen)
this.process(dataView, pos);
continue;
}
buffer.set(data.subarray(pos, pos + take), this.pos);
this.pos += take;
pos += take;
if (this.pos === blockLen) {
this.process(view, 0);
this.pos = 0;
}
}
this.length += data.length;
this.roundClean();
return this;
}
digestInto(out) {
exists(this);
output(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should be aligned to 32bit');
const outLen = len / 4;
const state = this.get();
if (outLen > state.length)
throw new Error('_sha2: outputLen bigger than state');
for (let i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
// BTC network is doing 2^67 hashes/sec as per early 2023.
// Choice: a ? b : c
const Chi = (a, b, c) => (a & b) ^ (~a & c);
// Majority function, true if any two inpust is true
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
// Round constants:
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
// prettier-ignore
const SHA256_K = /* @__PURE__ */ new Uint32Array([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
// prettier-ignore
const IV = /* @__PURE__ */ new Uint32Array([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
]);
// Temporary buffer, not used to store anything between runs
// Named this way because it matches specification.
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends SHA2 {
constructor() {
super(64, 32, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
get() {
const { A, B, C, D, E, F, G, H } = this;
return [A, B, C, D, E, F, G, H];
}
// prettier-ignore
set(A, B, C, D, E, F, G, H) {
this.A = A | 0;
this.B = B | 0;
this.C = C | 0;
this.D = D | 0;
this.E = E | 0;
this.F = F | 0;
this.G = G | 0;
this.H = H | 0;
}
process(view, offset) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
const T2 = (sigma0 + Maj(A, B, C)) | 0;
H = G;
G = F;
F = E;
E = (D + T1) | 0;
D = C;
C = B;
B = A;
A = (T1 + T2) | 0;
}
// Add the compressed chunk to the current hash value
A = (A + this.A) | 0;
B = (B + this.B) | 0;
C = (C + this.C) | 0;
D = (D + this.D) | 0;
E = (E + this.E) | 0;
F = (F + this.F) | 0;
G = (G + this.G) | 0;
H = (H + this.H) | 0;
this.set(A, B, C, D, E, F, G, H);
}
roundClean() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
function within_size(data, size) {
if (data.length > size) {
throw new TypeError(`Data is larger than array size: ${data.length} > ${size}`);
}
}
function is_hex$1(hex) {
if (hex.match(/[^a-fA-f0-9]/) !== null) {
throw new TypeError('Invalid characters in hex string: ' + hex);
}
if (hex.length % 2 !== 0) {
throw new Error(`Length of hex string is invalid: ${hex.length}`);
}
}
function is_safe_num(num) {
if (num > Number.MAX_SAFE_INTEGER) {
throw new TypeError('Number exceeds safe bounds!');
}
}
function is_prefix(actual, target) {
if (actual !== target) {
throw new TypeError(`Bech32 prefix does not match: ${actual} !== ${target}`);
}
}
const ec = new TextEncoder();
const dc = new TextDecoder();
function strToBytes(str) {
return ec.encode(str);
}
function bytesToStr(bytes) {
return dc.decode(bytes);
}
function hex_size(hexstr, size) {
is_hex$1(hexstr);
const len = hexstr.length / 2;
if (size === undefined)
size = len;
if (len > size) {
throw new TypeError(`Hex string is larger than array size: ${len} > ${size}`);
}
return size;
}
function hexToBytes$1(hexstr, size, endian = 'le') {
size = hex_size(hexstr, size);
const use_le = (endian === 'le');
const buffer = new ArrayBuffer(size);
const dataView = new DataView(buffer);
let offset = (use_le) ? 0 : size - 1;
for (let i = 0; i < hexstr.length; i += 2) {
const char = hexstr.substring(i, i + 2);
const num = parseInt(char, 16);
if (use_le) {
dataView.setUint8(offset++, num);
}
else {
dataView.setUint8(offset--, num);
}
}
return new Uint8Array(buffer);
}
function bytesToHex$1(bytes) {
let chars = '';
for (let i = 0; i < bytes.length; i++) {
chars += bytes[i].toString(16).padStart(2, '0');
}
return chars;
}
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// Utilities
function isBytes$1(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) => {
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 = '=') {
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);
},
};
}
/**
* 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) => {
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) {
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) {
return {
encode: (bytes) => {
if (!isBytes$1(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) {
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$1(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) {
if (typeof fn !== 'function')
throw new Error('checksum fn should be function');
return {
encode(data) {
if (!isBytes$1(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$1(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;
},
};
}
const base64 = /* @__PURE__ */ chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'), padding(6), join(''));
const base64urlnopad = /* @__PURE__ */ chain(radix2(6), alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'), join(''));
// base58 code
// -----------
const genBase58 = (abc) => chain(radix(58), alphabet(abc), join(''));
const base58 = /* @__PURE__ */ genBase58('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
const createBase58check = (sha256) => chain(checksum(4, (data) => sha256(sha256(data))), base58);
// legacy export, bad name
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 (!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 };
}
const bech32 = /* @__PURE__ */ genBech32('bech32');
const bech32m = /* @__PURE__ */ genBech32('bech32m');
const B58chk = {
encode: (data) => base58check(sha256).encode(data),
decode: (data) => base58check(sha256).decode(data)
};
const Base64 = {
encode: (data) => base64.encode(data),
decode: (data) => base64.decode(data)
};
const B64url = {
encode: (data) => base64urlnopad.encode(data),
decode: (data) => base64urlnopad.decode(data)
};
const Bech32 = {
to_words: bech32.toWords,
to_bytes: bech32.fromWords,
encode: (prefix, words, limit = false) => {
return bech32.encode(prefix, words, limit);
},
decode: (data, limit = false) => {
const { prefix, words } = bech32.decode(data, limit);
return { prefix, words };
}
};
const Bech32m = {
to_words: bech32m.toWords,
to_bytes: bech32m.fromWords,
encode: (prefix, words, limit = false) => {
return bech32m.encode(prefix, words, limit);
},
decode: (data, limit = false) => {
const { prefix, words } = bech32m.decode(data, limit);
return { prefix, words };
}
};
const _0n$5 = BigInt(0);
const _255n = BigInt(255);
const _256n = BigInt(256);
function big_size(big) {
if (big <= 0xffn)
return 1;
if (big <= 0xffffn)
return 2;
if (big <= 0xffffffffn)
return 4;
if (big <= 0xffffffffffffffffn)
return 8;
if (big <= 0xffffffffffffffffffffffffffffffffn)
return 16;
if (big <= 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn) {
return 32;
}
throw new TypeError('Must specify a fixed buffer size for bigints greater than 32 bytes.');
}
function bigToBytes(big, size, endian = 'be') {
if (size === undefined)
size = big_size(big);
const use_le = (endian === 'le');
const buffer = new ArrayBuffer(size);
const dataView = new DataView(buffer);
let offset = (use_le) ? 0 : size - 1;
while (big > _0n$5) {
const byte = big & _255n;
const num = Number(byte);
if (use_le) {
dataView.setUint8(offset++, num);
}
else {
dataView.setUint8(offset--, num);
}
big = (big - byte) / _256n;
}
return new Uint8Array(buffer);
}
function bytesToBig(bytes) {
let num = BigInt(0);
for (let i = bytes.length - 1; i >= 0; i--) {
num = (num * _256n) + BigInt(bytes[i]);
}
return BigInt(num);
}
function binToBytes(binary) {
const bins = binary.split('').map(Number);
if (bins.length % 8 !== 0) {
throw new Error(`Binary array is invalid length: ${binary.length}`);
}
const bytes = new Uint8Array(bins.length / 8);
for (let i = 0, ct = 0; i < bins.length; i += 8, ct++) {
let byte = 0;
for (let j = 0; j < 8; j++) {
byte |= (bins[i + j] << (7 - j));
}
bytes[ct] = byte;
}
return bytes;
}
function bytesToBin(bytes) {
const bin = new Array(bytes.length * 8);
let count = 0;
for (const num of bytes) {
if (num > 255) {
throw new Error(`Invalid byte value: ${num}. Byte values must be between 0 and 255.`);
}
for (let i = 7; i >= 0; i--, count++) {
bin[count] = (num >> i) & 1;
}
}
return bin.join('');
}
function num_size(num) {
if (num <= 0xFF)
return 1;
if (num <= 0xFFFF)
return 2;
if (num <= 0xFFFFFFFF)
return 4;
throw new TypeError('Numbers larger than 4 bytes must specify a fixed size!');
}
function numToBytes(num, size, endian = 'be') {
if (size === undefined)
size = num_size(num);
const use_le = (endian === 'le');
const buffer = new ArrayBuffer(size);
const dataView = new DataView(buffer);
let offset = (use_le) ? 0 : size - 1;
while (num > 0) {
const byte = num & 255;
if (use_le) {
dataView.setUint8(offset++, num);
}
else {
dataView.setUint8(offset--, num);
}
num = (num - byte) / 256;
}
return new Uint8Array(buffer);
}
function bytesToNum(bytes) {
let num = 0;
for (let i = bytes.length - 1; i >= 0; i--) {
num = (num * 256) + bytes[i];
is_safe_num(num);
}
return num;
}
function is_hex(input) {
if (input.match(/[^a-fA-F0-9]/) === null &&
input.length % 2 === 0) {
return true;
}
return false;
}
function is_bytes(input) {
if (typeof input === 'string' && is_hex(input)) {
return true;
}
else if (typeof input === 'number' ||
typeof input === 'bigint' ||
input instanceof Uint8Array) {
return true;
}
else if (Array.isArray(input) &&
input.every(e => typeof e === 'number')) {
return true;
}
else {
return false;
}
}
function set_buffer(data, size, endian = 'be') {
if (size === undefined)
size = data.length;
within_size(data, size);
const buffer = new Uint8Array(size).fill(0);
const offset = (endian === 'be') ? 0 : size - data.length;
buffer.set(data, offset);
return buffer;
}
function join_array(arr) {
let i, offset = 0;
const size = arr.reduce((len, arr) => len + arr.length, 0);
const buff = new Uint8Array(size);
for (i = 0; i < arr.length; i++) {
const a = arr[i];
buff.set(a, offset);
offset += a.length;
}
return buff;
}
function bigint_replacer(_, v) {
return typeof v === 'bigint'
? `${v}n`
: v;
}
function bigint_reviver(_, v) {
return typeof v === 'string' && /^[0-9]+n$/.test(v)
? BigInt(v.slice(0, -1))
: v;
}
function parse_data$1(data_blob, chunk_size, total_size) {
const len = data_blob.length, count = total_size / chunk_size;
if (total_size % chunk_size !== 0) {
throw new TypeError(`Invalid parameters: ${total_size} % ${chunk_size} !== 0`);
}
if (len !== total_size) {
throw new TypeError(`Invalid data stream: ${len} !== ${total_size}`);
}
if (len % chunk_size !== 0) {
throw new TypeError(`Invalid data stream: ${len} % ${chunk_size} !== 0`);
}
const chunks = new Array(count);
for (let i = 0; i < count; i++) {
const idx = i * chunk_size;
chunks[i] = data_blob.subarray(idx, idx + chunk_size);
}
return chunks;
}
function buffer_data(data, size, endian) {
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
}
else if (data instanceof Uint8Array) {
return set_buffer(data, size, endian);
}
else if (Array.isArray(data)) {
const bytes = data.map(e => buffer_data(e, size, endian));
return join_array(bytes);
}
else if (typeof data === 'string') {
return hexToBytes$1(data, size, endian);
}
else if (typeof data === 'bigint') {
return bigToBytes(data, size, endian);
}
else if (typeof data === 'number') {
return numToBytes(data, size, endian);
}
else if (typeof data === 'boolean') {
return Uint8Array.of(data ? 1 : 0);
}
throw new TypeError('Unsupported format:' + String(typeof data));
}
class Buff extends Uint8Array {
static { this.num = numToBuff; }
static { this.big = bigToBuff; }
static { this.bin = binToBuff; }
static { this.raw = rawToBuff; }
static { this.str = strToBuff; }
static { this.hex = hexToBuff; }
static { this.bytes = buffer; }
static { this.json = jsonToBuff; }
static { this.base64 = base64ToBuff; }
static { this.b64url = b64urlToBuff; }
static { this.bech32 = bech32ToBuff; }
static { this.bech32m = bech32mToBuff; }
static { this.b58chk = b58chkToBuff; }
static { this.encode = strToBytes; }
static { this.decode = bytesToStr; }
static { this.parse = parse_data; }
static { this.is_bytes = is_bytes; }
static { this.is_hex = is_hex; }
static { this.is_equal = is_equal; }
static random(size = 32) {
const rand = randomBytes(size);
return new Buff(rand, size);
}
static now(size = 4) {
const stamp = Math.floor(Date.now() / 1000);
return new Buff(stamp, size);
}
constructor(data, size, endian) {
if (data instanceof Buff &&
size === undefined) {
return data;
}
const buffer = buffer_data(data, size, endian);
super(buffer);
}
get arr() {
return [...this];
}
get num() {
return this.to_num();
}
get big() {
return this.to_big();
}
get str() {
return this.to_str();
}
get hex() {
return this.to_hex();
}
get raw() {
return new Uint8Array(this);
}
get bin() {
return this.to_bin();
}
get b58chk() {
return this.to_b58chk();
}
get base64() {
return this.to_base64();
}
get b64url() {
return this.to_b64url();
}
get digest() {
return this.to_hash();
}
get id() {
return this.to_hash().hex;
}
get stream() {
return new Stream(this);
}
to_num(endian = 'be') {
const bytes = (endian === 'be')
? this.reverse()
: this;
return bytesToNum(bytes);
}
to_big(endian = 'be') {
const bytes = (endian === 'be')
? this.reverse()
: this;
return bytesToBig(bytes);
}
to_bin() {
return bytesToBin(this);
}
to_hash() {
const digest = sha256(this);
return new Buff(digest);
}
to_json(reviver) {
if (reviver === undefined) {
reviver = bigint_reviver;
}
const str = bytesToStr(this);
return JSON.parse(str, reviver);
}
to_bech32(prefix, limit) {
const { encode, to_words } = Bech32;
const words = to_words(this);
return encode(prefix, words, limit);
}
to_bech32m(prefix, limit) {
const { encode, to_words } = Bech32m;
const words = to_words(this);
return encode(prefix, words, limit);
}
to_str() { return bytesToStr(this); }
to_hex() { return bytesToHex$1(this); }
to_bytes() { return new Uint8Array(this); }
to_b58chk() { return B58chk.encode(this); }
to_base64() { return Base64.encode(this); }
to_b64url() { return B64url.encode(this); }
append(data) {
return Buff.join([this, Buff.bytes(data)]);
}
equals(data) {
return buffer(data).hex === this.hex;
}
prepend(data) {
return Buff.join([Buff.bytes(data), this]);
}
reverse() {
const arr = new Uint8Array(this).reverse();
return new Buff(arr);
}
slice(start, end) {
const arr = new Uint8Array(this).slice(start, end);
return new Buff(arr);
}
set(array, offset) {
this.set(array, offset);
}
subarray(begin, end) {
const arr = new Uint8Array(this).subarray(begin, end);
return new Buff(arr);
}
write(bytes, offset) {
const b = Buff.bytes(bytes);
this.set(b, offset);
}
add_varint(endian) {
const size = Buff.calc_varint(this.length, endian);
return Buff.join([size, this]);
}
toJSON() {
return this.hex;
}
toString() {
return this.hex;
}
static from(data) {
return new Buff(Uint8Array.from(data));
}
static of(...args) {
return new Buff(Uint8Array.of(...args));
}
static join(arr) {
const bytes = arr.map(e => Buff.bytes(e));
const joined = join_array(bytes);
return new Buff(joined);
}
static sort(arr, size) {
const hex = arr.map(e => buffer(e, size).hex);
hex.sort();
return hex.map(e => Buff.hex(e, size));
}
static calc_varint(num, endian) {
if (num < 0xFD) {
return Buff.num(num, 1);
}
else if (num < 0x10000) {
return Buff.of(0xFD, ...Buff.num(num, 2, endian));
}
else if (num < 0x100000000) {
return Buff.of(0xFE, ...Buff.num(num, 4, endian));
}
else if (BigInt(num) < 0x10000000000000000n) {
return Buff.of(0xFF, ...Buff.num(num, 8, endian));
}
else {
throw new Error(`Value is too large: ${num}`);
}
}
}
function numToBuff(number, size, endian) {
return new Buff(number, size, endian);
}
function binToBuff(data, size, endian) {
return new Buff(binToBytes(data), size, endian);
}
function bigToBuff(bigint, size, endian) {
return new Buff(bigint, size, endian);
}
function rawToBuff(data, size, endian) {
return new Buff(data, size, endian);
}
function strToBuff(data, size, endian) {
return new Buff(strToBytes(data), size, endian);
}
function hexToBuff(data, size, endian) {
return new Buff(data, size, endian);
}
function jsonToBuff(data, replacer) {
if (replacer === undefined) {
replacer = bigint_replacer;
}
const str = JSON.stringify(data, replacer);
return new Buff(strToBytes(str));
}
function base64ToBuff(data) {
return new Buff(Base64.decode(data));
}
function b64urlToBuff(data) {
return new Buff(B64url.decode(data));
}
function bech32ToBuff(data, limit, chk_prefix) {
const { decode, to_bytes } = Bech32;
const { prefix, words } = decode(data, limit);
const bytes = to_bytes(words);
if (typeof chk_prefix === 'string') {
is_prefix(prefix, chk_prefix);
}
return new Buff(bytes);
}
function bech32mToBuff(data, limit, chk_prefix) {
const { decode, to_bytes } = Bech32m;
const { prefix, words } = decode(data, limit);
const bytes = to_bytes(words);
if (typeof chk_prefix === 'string') {
is_prefix(prefix, chk_prefix);
}
return new Buff(bytes);
}
function b58chkToBuff(data) {
return new Buff(B58chk.decode(data));
}
function parse_data(data_blob, chunk_size, total_size) {
const bytes = buffer_data(data_blob);
const chunks = parse_data$1(bytes, chunk_size, total_size);
return chunks.map(e => Buff.bytes(e));
}
function is_equal(a, b) {
return new Buff(a).hex === new Buff(b).hex;
}
function buffer(bytes, size, end) {
return new Buff(bytes, size, end);
}
class Stream {
constructor(data) {
this.data = Buff.bytes(data);
this.size = this.data.length;
}
peek(size) {
if (size > this.size) {
throw new Error(`Size greater than stream: ${size} > ${this.size}`);
}
return new Buff(this.data.slice(0, size));
}
read(size) {
const chunk = this.peek(size);
this.data = this.data.slice(size);
this.size = this.data.length;
return chunk;
}
read_varint(endian) {
const num = this.read(1).num;
switch (true) {
case (num >= 0 && num < 0xFD):
return num;
case (num === 0xFD):
return this.read(2).to_num(endian);
case (num === 0xFE):
return this.read(4).to_num(endian);
case (num === 0xFF):
return this.read(8).to_num(endian);
default:
throw new Error(`Varint is out of range: ${num}`);
}
}
}
// HMAC (RFC 2104)
class HMAC extends Hash {
constructor(hash$1, _key) {
super();
this.finished = false;
this.destroyed = false;
hash(hash$1);
const key = toBytes(_key);
this.iHash = hash$1.create();
if (typeof this.iHash.update !== 'function')
throw new Error('Expected instance of class which extends utils.Hash');
this.blockLen = this.iHash.blockLen;
this.outputLen = this.iHash.outputLen;
const blockLen = this.blockLen;
const pad = new Uint8Array(blockLen);
// blockLen can be bigger than outputLen
pad.set(key.length > blockLen ? hash$1.create().update(key).digest() : key);
for (let i = 0; i < pad.length; i++)
pad[i] ^= 0x36;
this.iHash.update(pad);
// By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
this.oHash = hash$1.create();
// Undo internal XOR && apply outer XOR
for (let i = 0; i < pad.length; i++)
pad[i] ^= 0x36 ^ 0x5c;
this.oHash.update(pad);
pad.fill(0);
}
update(buf) {
exists(this);
this.iHash.update(buf);
return this;
}
digestInto(out) {
exists(this);
bytes(out, this.outputLen);
this.finished = true;
this.iHash.digestInto(out);
this.oHash.update(out);
this.oHash.digestInto(out);
this.destroy();
}
digest() {
const out = new Uint8Array(this.oHash.outputLen);
this.digestInto(out);
return out;
}
_cloneInto(to) {
// Create new instance without calling constructor since key already in state and we don't know it.
to || (to = Object.create(Object.getPrototypeOf(this), {}));
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
to = to;
to.finished = finished;
to.destroyed = destroyed;
to.blockLen = blockLen;
to.outputLen = outputLen;
to.oHash = oHash._cloneInto(to.oHash);
to.iHash = iHash._cloneInto(to.iHash);
return to;
}
destroy() {
this.destroyed = true;
this.oHash.destroy();
this.iHash.destroy();
}
}
/**
* HMAC: RFC2104 message authentication code.
* @param hash - function that would be used e.g. sha256
* @param key - message key
* @param message - message data
*/
const hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
hmac.create = (hash, key) => new HMAC(hash, key);
function taghash(tag) {
const hash = Buff.str(tag).digest;
return Buff.join([hash, hash]);
}
function hash340(tag, ...data) {
const hash = taghash(tag);
return Buff.join([hash, ...data]).digest;
}
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// 100 lines of code in the file are duplicated from noble-hashes (utils).
// This is OK: `abstract` directory does not use noble-hashes.
// User may opt-in into using different hashing library. This way, noble-hashes
// won't be included into their bundle.
const _0n$4 = BigInt(0);
const _1n$5 = BigInt(1);
const _2n$3 = BigInt(2);
function isBytes(a) {
return (a instanceof Uint8Array ||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
}
// Array where index 0xf0 (240) is mapped to string 'f0'
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
if (!isBytes(bytes))
throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}
return hex;
}
function numberToHexUnpadded(num) {
const hex = num.toString(16);
return hex.length & 1 ? `0${hex}` : hex;
}
function hexToNumber(hex) {
if (typeof hex !== 'string')
throw new Error('hex string expected, got ' + typeof hex);
// Big Endian
return BigInt(hex === '' ? '0' : `0x${hex}`);
}
// We use optimized technique to convert hex string to byte array
const asciis = { _0: 48, _9: 57, _A: 65, _F: 70, _a: 97, _f: 102 };
function asciiToBase16(char) {
if (char >= asciis._0 && char <= asciis._9)
return char - asciis._0;
if (char >= asciis._A && char <= asciis._F)
return char - (asciis._A - 10);