UNPKG

@cmdcode/musig2

Version:

Create digital signatures based on the Musig2 protocol.

1,462 lines (1,443 loc) 149 kB
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); if (char >= a