UNPKG

@cmdcode/tapscript

Version:

A basic library for working with Tapscript, signatures and Bitcoin transactions.

1,649 lines (1,625 loc) 408 kB
function number$3(n) { if (!Number.isSafeInteger(n) || n < 0) throw new Error(`Wrong positive integer: ${n}`); } function bool$3(b) { if (typeof b !== 'boolean') throw new Error(`Expected boolean, not ${b}`); } function bytes$3(b, ...lengths) { if (!(b instanceof Uint8Array)) throw new TypeError('Expected Uint8Array'); if (lengths.length > 0 && !lengths.includes(b.length)) throw new TypeError(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`); } function hash$4(hash) { if (typeof hash !== 'function' || typeof hash.create !== 'function') throw new Error('Hash should be wrapped by utils.wrapConstructor'); number$3(hash.outputLen); number$3(hash.blockLen); } function exists$3(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$3(out, instance) { bytes$3(out); const min = instance.outputLen; if (out.length < min) { throw new Error(`digestInto() expects output buffer of length at least ${min}`); } } const assert$1$2 = { number: number$3, bool: bool$3, bytes: bytes$3, hash: hash$4, exists: exists$3, output: output$3, }; var assert$2$1 = assert$1$2; /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */ // Cast array to view const createView$3 = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength); // The rotate right (circular right shift) operation for uint32 const rotr$3 = (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. const isLE$3 = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44; if (!isLE$3) throw new Error('Non little-endian hardware is not supported'); Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0')); function utf8ToBytes$4(str) { if (typeof str !== 'string') { throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`); } return new TextEncoder().encode(str); } function toBytes$5(data) { if (typeof data === 'string') data = utf8ToBytes$4(data); if (!(data instanceof Uint8Array)) throw new TypeError(`Expected input type is Uint8Array (got ${typeof data})`); return data; } // For runtime check if class implements interface let Hash$3 = class Hash { // Safe version that clones internal state clone() { return this._cloneInto(); } }; function wrapConstructor$3(hashConstructor) { const hashC = (message) => hashConstructor().update(toBytes$5(message)).digest(); const tmp = hashConstructor(); hashC.outputLen = tmp.outputLen; hashC.blockLen = tmp.blockLen; hashC.create = () => hashConstructor(); return hashC; } // Polyfill for Safari 14 function setBigUint64$3(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) let SHA2$3 = class SHA2 extends Hash$3 { 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$3(this.buffer); } update(data) { assert$2$1.exists(this); const { view, buffer, blockLen } = this; data = toBytes$5(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$3(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) { assert$2$1.exists(this); assert$2$1.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$3(view, blockLen - 8, BigInt(this.length * 8), isLE); this.process(view, 0); const oview = createView$3(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; } }; // Choice: a ? b : c const Chi$3 = (a, b, c) => (a & b) ^ (~a & c); // Majority function, true if any two inpust is true const Maj$3 = (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$3 = 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$3 = 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$3 = new Uint32Array(64); let SHA256$3 = class SHA256 extends SHA2$3 { 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$3[0] | 0; this.B = IV$3[1] | 0; this.C = IV$3[2] | 0; this.D = IV$3[3] | 0; this.E = IV$3[4] | 0; this.F = IV$3[5] | 0; this.G = IV$3[6] | 0; this.H = IV$3[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$3[i] = view.getUint32(offset, false); for (let i = 16; i < 64; i++) { const W15 = SHA256_W$3[i - 15]; const W2 = SHA256_W$3[i - 2]; const s0 = rotr$3(W15, 7) ^ rotr$3(W15, 18) ^ (W15 >>> 3); const s1 = rotr$3(W2, 17) ^ rotr$3(W2, 19) ^ (W2 >>> 10); SHA256_W$3[i] = (s1 + SHA256_W$3[i - 7] + s0 + SHA256_W$3[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$3(E, 6) ^ rotr$3(E, 11) ^ rotr$3(E, 25); const T1 = (H + sigma1 + Chi$3(E, F, G) + SHA256_K$3[i] + SHA256_W$3[i]) | 0; const sigma0 = rotr$3(A, 2) ^ rotr$3(A, 13) ^ rotr$3(A, 22); const T2 = (sigma0 + Maj$3(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$3.fill(0); } destroy() { this.set(0, 0, 0, 0, 0, 0, 0, 0); this.buffer.fill(0); } }; // Constants from https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf let SHA224$3 = class SHA224 extends SHA256$3 { constructor() { super(); this.A = 0xc1059ed8 | 0; this.B = 0x367cd507 | 0; this.C = 0x3070dd17 | 0; this.D = 0xf70e5939 | 0; this.E = 0xffc00b31 | 0; this.F = 0x68581511 | 0; this.G = 0x64f98fa7 | 0; this.H = 0xbefa4fa4 | 0; this.outputLen = 28; } }; /** * SHA2-256 hash function * @param message - data that would be hashed */ const sha256$4 = wrapConstructor$3(() => new SHA256$3()); wrapConstructor$3(() => new SHA224$3()); function within_size$1(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$1(num) { if (num > Number.MAX_SAFE_INTEGER) { throw new TypeError('Number exceeds safe bounds!'); } } const { getRandomValues: getRandomValues$1 } = crypto ?? globalThis.crypto ?? window.crypto; function random$2(size = 32) { if (typeof getRandomValues$1 === 'function') { return crypto.getRandomValues(new Uint8Array(size)); } throw new Error('Crypto module missing getRandomValues!'); } function set_buffer$1(data, size, endian = 'be') { if (size === undefined) size = data.length; within_size$1(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$1(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; } const ec$2$1 = new TextEncoder(); const ALPHABETS$1 = [ { name: 'base58', charset: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' } ]; function getAlphabet$1(name) { for (const alpha of ALPHABETS$1) { if (alpha.name === name) { return alpha.charset; } } throw TypeError('Charset does not exist: ' + name); } function encode$1$2(data, charset, padding = false) { if (typeof data === 'string') data = ec$2$1.encode(data); const alphabet = getAlphabet$1(charset); const len = alphabet.length; const d = []; let s = '', i, j = 0, c, n; for (i = 0; i < data.length; i++) { j = 0; c = data[i]; s += (c > 0 || (s.length ^ i) > 0) ? '' : '1'; while (j in d || c > 0) { n = d[j]; n = n > 0 ? n * 256 + c : c; c = n / len | 0; d[j] = n % len; j++; } } while (j-- > 0) { s += alphabet[d[j]]; } return (padding && s.length % 4 > 0) ? s + '='.repeat(4 - s.length % 4) : s; } function decode$1$2(encoded, charset) { const alphabet = getAlphabet$1(charset); const len = alphabet.length, d = [], b = []; encoded = encoded.replace('=', ''); let i, j = 0, c, n; for (i = 0; i < encoded.length; i++) { j = 0; c = alphabet.indexOf(encoded[i]); if (c < 0) { throw new Error(`Character range out of bounds: ${c}`); } if (!(c > 0 || (b.length ^ i) > 0)) b.push(0); while (j in d || c > 0) { n = d[j]; n = n > 0 ? n * len + c : c; c = n >> 8; d[j] = n % 256; j++; } } while (j-- > 0) { b.push(d[j]); } return new Uint8Array(b); } function hash256$2(data) { return sha256$4(sha256$4(data)); } function addChecksum$1(data) { const sum = hash256$2(data); return join_array$1([data, sum.slice(0, 4)]); } function checkTheSum$1(data) { const ret = data.slice(0, -4); const chk = data.slice(-4); const sum = hash256$2(ret).slice(0, 4); if (sum.toString() !== chk.toString()) { throw new Error('Invalid checksum!'); } return ret; } const BaseX$1 = { encode: encode$1$2, decode: decode$1$2 }; const Base58C$1 = { encode: (data) => { const withSum = addChecksum$1(data); return BaseX$1.encode(withSum, 'base58'); }, decode: (data) => { const decoded = BaseX$1.decode(data, 'base58'); return checkTheSum$1(decoded); } }; const CHARSET$1 = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; const GENERATOR$1 = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; const ENCODINGS$1 = [ { version: 0, name: 'bech32', const: 1 }, { version: 1, name: 'bech32m', const: 0x2bc830a3 } ]; function polymod$1(values) { let chk = 1; for (let p = 0; p < values.length; ++p) { const top = chk >> 25; chk = (chk & 0x1ffffff) << 5 ^ values[p]; for (let i = 0; i < 5; ++i) { if (((top >> i) & 1) !== 0) { chk ^= GENERATOR$1[i]; } } } return chk; } function hrpExpand$1(hrp) { const ret = []; let p; for (p = 0; p < hrp.length; ++p) { ret.push(hrp.charCodeAt(p) >> 5); } ret.push(0); for (p = 0; p < hrp.length; ++p) { ret.push(hrp.charCodeAt(p) & 31); } return ret; } function verifyChecksum$1(hrp, data, enc) { const combined = hrpExpand$1(hrp).concat(data); return polymod$1(combined) === enc.const; } function createChecksum$1(hrp, data, enc) { const values = hrpExpand$1(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]); const mod = polymod$1(values) ^ enc.const; const ret = []; for (let p = 0; p < 6; ++p) { ret.push((mod >> 5 * (5 - p)) & 31); } return ret; } function convertBits$1(data, fromBits, toBits, pad = true) { const ret = []; let acc = 0; let bits = 0; const maxVal = (1 << toBits) - 1; const maxAcc = (1 << (fromBits + toBits - 1)) - 1; for (const val of data) { if (val < 0 || (val >> fromBits) > 0) { throw new Error('Failed to perform base conversion. Invalid value: ' + String(val)); } acc = ((acc << fromBits) | val) & maxAcc; bits += fromBits; while (bits >= toBits) { bits -= toBits; ret.push((acc >> bits) & maxVal); } } if (pad) { if (bits > 0) { ret.push((acc << (toBits - bits)) & maxVal); } } else if (bits >= fromBits || ((acc << (toBits - bits)) & maxVal) > 0) { throw new Error('Failed to perform base conversion. Invalid Size!'); } return ret; } function encode$6(hrp, data, enc) { const combined = data.concat(createChecksum$1(hrp, data, enc)); let ret = hrp + '1'; for (let p = 0; p < combined.length; ++p) { ret += CHARSET$1.charAt(combined[p]); } return ret; } function decode$6(bechstr) { if (!checkBounds$1(bechstr)) { throw new Error('Encoded string goes out of bounds!'); } bechstr = bechstr.toLowerCase(); if (!checkSeparatorPos$1(bechstr)) { throw new Error('Encoded string has invalid separator!'); } const data = []; const pos = bechstr.lastIndexOf('1'); const hrp = bechstr.substring(0, pos); for (let p = pos + 1; p < bechstr.length; ++p) { const d = CHARSET$1.indexOf(bechstr.charAt(p)); if (d === -1) { throw new Error('Character idx out of bounds: ' + String(p)); } data.push(d); } const enc = ENCODINGS$1.find(e => e.version === data[0]) ?? ENCODINGS$1[0]; if (!verifyChecksum$1(hrp, data, enc)) { throw new Error('Checksum verification failed!'); } return [hrp, data.slice(0, data.length - 6)]; } function checkBounds$1(bechstr) { let p; let char; let hasLower = false; let hasUpper = false; for (p = 0; p < bechstr.length; ++p) { char = bechstr.charCodeAt(p); if (char < 33 || char > 126) { return false; } if (char >= 97 && char <= 122) { hasLower = true; } if (char >= 65 && char <= 90) { hasUpper = true; } } if (hasLower && hasUpper) return false; return true; } function checkSeparatorPos$1(bechstr) { const pos = bechstr.lastIndexOf('1'); return !(pos < 1 || pos + 7 > bechstr.length || bechstr.length > 90); } function b32encode$1(data, hrp = 'bc', version = 0) { const dat = [version, ...convertBits$1([...data], 8, 5)]; const enc = ENCODINGS$1.find(e => e.version === version) ?? ENCODINGS$1[0]; const str = encode$6(hrp, dat, enc); b32decode$1(str); return str; } function b32decode$1(str) { str = str.toLowerCase(); const hrp = str.split('1', 1)[0]; const [hrpgot, data] = decode$6(str); const decoded = convertBits$1(data.slice(1), 5, 8, false); const length = decoded.length; switch (true) { case (hrp !== hrpgot): throw new Error('Returned hrp string is invalid.'); case (decoded === null || length < 2 || length > 40): throw new Error('Decoded string is invalid or out of spec.'); case (data[0] > 16): throw new Error('Returned version bit is out of range.'); default: return Uint8Array.from(decoded); } } function getVersion$2(str) { str = str.toLowerCase(); const [_, data] = decode$6(str); return data[0]; } const Bech32$1 = { encode: b32encode$1, decode: b32decode$1, version: getVersion$2 }; const BASE64_MAP$1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; const B64URL_MAP$1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; const ec$1$1 = new TextEncoder(); function b64encode$1(input, urlSafe = false, padding = true) { if (typeof input === 'string') input = ec$1$1.encode(input); const map = urlSafe ? B64URL_MAP$1 : BASE64_MAP$1; let output = ''; let bits = 0; let buffer = 0; for (let i = 0; i < input.length; i++) { buffer = (buffer << 8) | input[i]; bits += 8; while (bits >= 6) { bits -= 6; output += map[(buffer >> bits) & 0x3f]; } } if (bits > 0) { buffer <<= 6 - bits; output += map[buffer & 0x3f]; while (bits < 6) { output += padding ? '=' : ''; bits += 2; } } return output; } function b64decode$1(input, urlSafe = false) { const map = (urlSafe || input.includes('-') || input.includes('_')) ? B64URL_MAP$1.split('') : BASE64_MAP$1.split(''); input = input.replace(/=+$/, ''); const chars = input.split(''); let bits = 0; let value = 0; const bytes = []; for (let i = 0; i < chars.length; i++) { const c = chars[i]; const index = map.indexOf(c); if (index === -1) { throw new Error('Invalid character: ' + c); } bits += 6; value <<= 6; value |= index; if (bits >= 8) { bits -= 8; bytes.push((value >>> bits) & 0xff); } } return new Uint8Array(bytes); } const Base64$1 = { encode: b64encode$1, decode: b64decode$1 }; const B64URL$1 = { encode: (data) => b64encode$1(data, true, false), decode: (data) => b64decode$1(data, true) }; const _0n = BigInt(0); const _255n$1 = BigInt(255); const _256n$1 = BigInt(256); function big_size$1(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$1(big, size, endian = 'be') { if (size === undefined) size = big_size$1(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) { const byte = big & _255n$1; const num = Number(byte); if (use_le) { dataView.setUint8(offset++, num); } else { dataView.setUint8(offset--, num); } big = (big - byte) / _256n$1; } return new Uint8Array(buffer); } function bytesToBig$1(bytes) { let num = BigInt(0); for (let i = bytes.length - 1; i >= 0; i--) { num = (num * _256n$1) + BigInt(bytes[i]); } return BigInt(num); } function binToBytes$1(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$1(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$1(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$1(num, size, endian = 'be') { if (size === undefined) size = num_size$1(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$1(bytes) { let num = 0; for (let i = bytes.length - 1; i >= 0; i--) { num = (num * 256) + bytes[i]; is_safe_num$1(num); } return num; } const ec$3 = new TextEncoder(); const dc$1 = new TextDecoder(); function strToBytes$1(str) { return ec$3.encode(str); } function bytesToStr$1(bytes) { return dc$1.decode(bytes); } function hex_size$1(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$2(hexstr, size, endian = 'le') { size = hex_size$1(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$2(bytes) { let chars = ''; for (let i = 0; i < bytes.length; i++) { chars += bytes[i].toString(16).padStart(2, '0'); } return chars; } function jsonToBytes$1(obj) { const str = JSON.stringify(obj, (_, v) => { return typeof v === 'bigint' ? `${v}n` : v; }); return strToBytes$1(str); } function buffer$1(data, size, endian) { if (data instanceof ArrayBuffer) { return new Uint8Array(data); } if (data instanceof Uint8Array) { return set_buffer$1(data, size, endian); } if (typeof data === 'string') { return hexToBytes$2(data, size, endian); } if (typeof data === 'bigint') { return bigToBytes$1(data, size, endian); } if (typeof data === 'number') { return numToBytes$1(data, size, endian); } if (typeof data === 'boolean') { return Uint8Array.of(data ? 1 : 0); } throw TypeError('Unsupported format:' + String(typeof data)); } let Buff$1 = class Buff extends Uint8Array { static { this.num = numToBuff$1; } static { this.big = bigToBuff$1; } static { this.bin = binToBuff$1; } static { this.raw = rawToBuff$1; } static { this.str = strToBuff$1; } static { this.hex = hexToBuff$1; } static { this.bytes = bytesToBuff$1; } static { this.json = jsonToBuff$1; } static { this.base64 = base64ToBuff$1; } static { this.b64url = b64urlToBuff$1; } static { this.bech32 = bech32ToBuff$1; } static { this.b58chk = b58chkToBuff$1; } static { this.encode = strToBytes$1; } static { this.decode = bytesToStr$1; } static random(size = 32) { const rand = random$2(size); return new Buff(rand, size); } constructor(data, size, endian) { const buffer$1$1 = buffer$1(data, size, endian); super(buffer$1$1); } get arr() { return [...this]; } get num() { return this.toNum(); } get big() { return this.toBig(); } get str() { return this.toStr(); } get hex() { return this.toHex(); } get raw() { return new Uint8Array(this); } get bin() { return this.toBin(); } get b58chk() { return this.tob58chk(); } get base64() { return this.toBase64(); } get b64url() { return this.toB64url(); } get digest() { return this.toHash(); } get id() { return this.toHash().hex; } get stream() { return new Stream$1(this); } toNum(endian = 'be') { const bytes = (endian === 'be') ? this.reverse() : this; return bytesToNum$1(bytes); } toBin() { return bytesToBin$1(this); } toBig(endian = 'be') { const bytes = (endian === 'be') ? this.reverse() : this; return bytesToBig$1(bytes); } toHash() { const digest = sha256$4(this); return new Buff(digest); } toJson() { const str = bytesToStr$1(this); return JSON.parse(str); } toBech32(hrp, version = 0) { return Bech32$1.encode(this, hrp, version); } toStr() { return bytesToStr$1(this); } toHex() { return bytesToHex$2(this); } toBytes() { return new Uint8Array(this); } tob58chk() { return Base58C$1.encode(this); } toBase64() { return Base64$1.encode(this); } toB64url() { return B64URL$1.encode(this); } prepend(data) { return Buff.join([Buff.bytes(data), this]); } append(data) { return Buff.join([this, Buff.bytes(data)]); } slice(start, end) { const arr = new Uint8Array(this).slice(start, end); return new Buff(arr); } subarray(begin, end) { const arr = new Uint8Array(this).subarray(begin, end); return new Buff(arr); } reverse() { const arr = new Uint8Array(this).reverse(); return new Buff(arr); } write(bytes, offset) { const b = Buff.bytes(bytes); this.set(b, offset); } prefixSize(endian) { const size = Buff.varInt(this.length, endian); return Buff.join([size, this]); } 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$1(bytes); return new Buff(joined); } static 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$1(number, size, endian) { return new Buff$1(number, size, endian); } function binToBuff$1(data, size, endian) { return new Buff$1(binToBytes$1(data), size, endian); } function bigToBuff$1(bigint, size, endian) { return new Buff$1(bigint, size, endian); } function rawToBuff$1(data, size, endian) { return new Buff$1(data, size, endian); } function strToBuff$1(data, size, endian) { return new Buff$1(strToBytes$1(data), size, endian); } function hexToBuff$1(data, size, endian) { return new Buff$1(data, size, endian); } function bytesToBuff$1(data, size, endian) { return new Buff$1(data, size, endian); } function jsonToBuff$1(data) { return new Buff$1(jsonToBytes$1(data)); } function base64ToBuff$1(data) { return new Buff$1(Base64$1.decode(data)); } function b64urlToBuff$1(data) { return new Buff$1(B64URL$1.decode(data)); } function bech32ToBuff$1(data) { return new Buff$1(Bech32$1.decode(data)); } function b58chkToBuff$1(data) { return new Buff$1(Base58C$1.decode(data)); } let Stream$1 = class Stream { constructor(data) { this.data = Buff$1.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$1(this.data.slice(0, size)); } read(size) { size = size ?? this.readSize(); const chunk = this.peek(size); this.data = this.data.slice(size); this.size = this.data.length; return chunk; } readSize(endian) { const num = this.read(1).num; switch (true) { case (num >= 0 && num < 0xFD): return num; case (num === 0xFD): return this.read(2).toNum(endian); case (num === 0xFE): return this.read(4).toNum(endian); case (num === 0xFF): return this.read(8).toNum(endian); default: throw new Error(`Varint is out of range: ${num}`); } } }; function checkSize(input, size) { const bytes = Buff$1.bytes(input); if (bytes.length !== size) { throw new Error(`Invalid input size: ${bytes.hex} !== ${size}`); } } function safeThrow(errorMsg, shouldThrow) { if (shouldThrow) { throw new Error(errorMsg); } else { return false; } } function hashTag(tag, ...data) { const htag = Buff$1.str(tag).digest.raw; const buff = data.map(e => Buff$1.bytes(e)); return Buff$1.join([htag, htag, Buff$1.join(buff)]).digest; } const OPCODE_MAP = { OP_0: 0, OP_PUSHDATA1: 76, OP_PUSHDATA2: 77, OP_PUSHDATA4: 78, OP_1NEGATE: 79, OP_SUCCESS80: 80, OP_1: 81, OP_2: 82, OP_3: 83, OP_4: 84, OP_5: 85, OP_6: 86, OP_7: 87, OP_8: 88, OP_9: 89, OP_10: 90, OP_11: 91, OP_12: 92, OP_13: 93, OP_14: 94, OP_15: 95, OP_16: 96, OP_NOP: 97, OP_SUCCESS98: 98, OP_IF: 99, OP_NOTIF: 100, OP_ELSE: 103, OP_ENDIF: 104, OP_VERIFY: 105, OP_RETURN: 106, OP_TOALTSTACK: 107, OP_FROMALTSTACK: 108, OP_2DROP: 109, OP_2DUP: 110, OP_3DUP: 111, OP_2OVER: 112, OP_2ROT: 113, OP_2SWAP: 114, OP_IFDUP: 115, OP_DEPTH: 116, OP_DROP: 117, OP_DUP: 118, OP_NIP: 119, OP_OVER: 120, OP_PICK: 121, OP_ROLL: 122, OP_ROT: 123, OP_SWAP: 124, OP_TUCK: 125, OP_SUCCESS126: 126, OP_SUCCESS127: 127, OP_SUCCESS128: 128, OP_SUCCESS129: 129, OP_SIZE: 130, OP_SUCCESS131: 131, OP_SUCCESS132: 132, OP_SUCCESS133: 133, OP_SUCCESS134: 134, OP_EQUAL: 135, OP_EQUALVERIFY: 136, OP_SUCCESS137: 137, OP_SUCCESS138: 138, OP_1ADD: 139, OP_1SUB: 140, OP_SUCCESS141: 141, OP_SUCCESS142: 142, OP_NEGATE: 143, OP_ABS: 144, OP_NOT: 145, OP_0NOTEQUAL: 146, OP_ADD: 147, OP_SUB: 148, OP_SUCCESS149: 149, OP_SUCCESS150: 150, OP_SUCCESS151: 151, OP_SUCCESS152: 152, OP_SUCCESS153: 153, OP_BOOLAND: 154, OP_BOOLOR: 155, OP_NUMEQUAL: 156, OP_NUMEQUALVERIFY: 157, OP_NUMNOTEQUAL: 158, OP_LESSTHAN: 159, OP_GREATERTHAN: 160, OP_LESSTHANOREQUAL: 161, OP_GREATERTHANOREQUAL: 162, OP_MIN: 163, OP_MAX: 164, OP_WITHIN: 165, OP_RIPEMD160: 166, OP_SHA1: 167, OP_SHA256: 168, OP_HASH160: 169, OP_HASH256: 170, OP_CODESEPARATOR: 171, OP_CHECKSIG: 172, OP_CHECKSIGVERIFY: 173, OP_CHECKMULTISIG: 174, OP_CHECKMULTISIGVERIFY: 175, OP_NOP1: 176, OP_CHECKLOCKTIMEVERIFY: 177, OP_CHECKSEQUENCEVERIFY: 178, OP_NOP4: 179, OP_NOP5: 180, OP_NOP6: 181, OP_NOP7: 182, OP_NOP8: 183, OP_NOP9: 184, OP_NOP10: 185, OP_CHECKSIGADD: 186, OP_SUCCESS187: 187, OP_SUCCESS188: 188, OP_SUCCESS189: 189, OP_SUCCESS190: 190, OP_SUCCESS191: 191, OP_SUCCESS192: 192, OP_SUCCESS193: 193, OP_SUCCESS194: 194, OP_SUCCESS195: 195, OP_SUCCESS196: 196, OP_SUCCESS197: 197, OP_SUCCESS198: 198, OP_SUCCESS199: 199, OP_SUCCESS200: 200, OP_SUCCESS201: 201, OP_SUCCESS202: 202, OP_SUCCESS203: 203, OP_SUCCESS204: 204, OP_SUCCESS205: 205, OP_SUCCESS206: 206, OP_SUCCESS207: 207, OP_SUCCESS208: 208, OP_SUCCESS209: 209, OP_SUCCESS210: 210, OP_SUCCESS211: 211, OP_SUCCESS212: 212, OP_SUCCESS213: 213, OP_SUCCESS214: 214, OP_SUCCESS215: 215, OP_SUCCESS216: 216, OP_SUCCESS217: 217, OP_SUCCESS218: 218, OP_SUCCESS219: 219, OP_SUCCESS220: 220, OP_SUCCESS221: 221, OP_SUCCESS222: 222, OP_SUCCESS223: 223, OP_SUCCESS224: 224, OP_SUCCESS225: 225, OP_SUCCESS226: 226, OP_SUCCESS227: 227, OP_SUCCESS228: 228, OP_SUCCESS229: 229, OP_SUCCESS230: 230, OP_SUCCESS231: 231, OP_SUCCESS232: 232, OP_SUCCESS233: 233, OP_SUCCESS234: 234, OP_SUCCESS235: 235, OP_SUCCESS236: 236, OP_SUCCESS237: 237, OP_SUCCESS238: 238, OP_SUCCESS239: 239, OP_SUCCESS240: 240, OP_SUCCESS241: 241, OP_SUCCESS242: 242, OP_SUCCESS243: 243, OP_SUCCESS244: 244, OP_SUCCESS245: 245, OP_SUCCESS246: 246, OP_SUCCESS247: 247, OP_SUCCESS248: 248, OP_SUCCESS249: 249, OP_SUCCESS250: 250, OP_SUCCESS251: 251, OP_SUCCESS252: 252, OP_SUCCESS253: 253, OP_SUCCESS254: 254 }; function getOpLabel(num) { if (num > 186 && num < 255) { return 'OP_SUCCESS' + String(num); } for (const [k, v] of Object.entries(OPCODE_MAP)) { if (v === num) return k; } throw new Error('OPCODE not found:' + String(num)); } function getOpCode(string) { for (const [k, v] of Object.entries(OPCODE_MAP)) { if (k === string) return Number(v); } throw new Error('OPCODE not found:' + string); } function getWordType(word) { switch (true) { case (word === 0): return 'opcode'; case (word >= 1 && word <= 75): return 'varint'; case (word === 76): return 'pushdata1'; case (word === 77): return 'pushdata2'; case (word === 78): return 'pushdata4'; case (word <= 254): return 'opcode'; default: throw new Error(`Invalid word range: ${word}`); } } function isValidWord(word) { const MIN_RANGE = 75; const MAX_RANGE = 254; const DISABLED_OPCODES = []; switch (true) { case (typeof (word) !== 'number'): return false; case (word === 0): return true; case (DISABLED_OPCODES.includes(word)): return false; case (MIN_RANGE < word && word < MAX_RANGE): return true; default: return false; } } function isHex(value) { return (typeof value === 'string' && value.length % 2 === 0 && /[0-9a-fA-F]/.test(value)); } function isBytes$1(value) { return (isHex(value) || value instanceof Uint8Array); } const MAX_WORD_SIZE = 0x208; function encodeScript(script = [], varint = true) { let buff = Buff$1.num(0); if (Array.isArray(script)) { buff = Buff$1.raw(encodeWords(script)); } if (isHex(script)) { buff = Buff$1.hex(script); } if (script instanceof Uint8Array) { buff = Buff$1.raw(script); } if (varint) { buff = buff.prefixSize('le'); } return buff; } function encodeWords(wordArray) { const words = []; for (const word of wordArray) { words.push(encodeWord(word)); } return (words.length > 0) ? Buff$1.join(words) : new Uint8Array(); } function encodeWord(word) { let buff = new Uint8Array(); if (typeof (word) === 'string') { if (word.startsWith('OP_')) { return Buff$1.num(getOpCode(word), 1); } else if (isHex(word)) { buff = Buff$1.hex(word); } else { buff = Buff$1.str(word); } } else { buff = Buff$1.bytes(word); } if (buff.length === 1) { if (buff[0] !== 0 && buff[0] <= 16) { buff[0] += 0x50; return buff; } else if (buff[0] > 128 && buff[0] <= 255) { buff = new Uint8Array([buff[0], 0]); } return Buff$1.join([encodeSize(buff.length), buff]); } else if (buff.length > MAX_WORD_SIZE) { const words = splitWord(buff); return encodeWords(words); } else { return Buff$1.join([encodeSize(buff.length), buff]); } } function encodeSize(size) { const OP_DATAPUSH1 = Buff$1.num(0x4c, 1); const OP_DATAPUSH2 = Buff$1.num(0x4d, 1); switch (true) { case (size <= 0x4b): return Buff$1.num(size); case (size > 0x4b && size < 0x100): return Buff$1.join([OP_DATAPUSH1, Buff$1.num(size, 1, 'le')]); case (size >= 0x100 && size <= MAX_WORD_SIZE): return Buff$1.join([OP_DATAPUSH2, Buff$1.num(size, 2, 'le')]); default: throw new Error('Invalid word size:' + size.toString()); } } function splitWord(word) { const words = []; const buff = new Stream$1(word); while (buff.size > MAX_WORD_SIZE) { words.push(buff.read(MAX_WORD_SIZE)); } words.push(buff.read(buff.size)); return words; } function decodeScript(script, varint = false) { let buff = Buff$1.bytes(script); if (varint) { const stream = buff.stream; const len = stream.readSize('le'); buff = buff.slice(1); if (buff.length !== len) { throw new Error(`Varint does not match stream size: ${len} !== ${buff.length}`); } } return decodeWords(buff); } function decodeWords(words) { const stream = new Stream$1(words); const stack = []; const stackSize = stream.size; let word; let wordType; let wordSize; let count = 0; while (count < stackSize) { word = stream.read(1).num; wordType = getWordType(word); count++; switch (wordType) { case 'varint': stack.push(stream.read(word).hex); count += word; break; case 'pushdata1': wordSize = stream.read(1).reverse().num; stack.push(stream.read(wordSize).hex); count += wordSize + 1; break; case 'pushdata2': wordSize = stream.read(2).reverse().num; stack.push(stream.read(wordSize).hex); count += wordSize + 2; break; case 'pushdata4': wordSize = stream.read(4).reverse().num; stack.push(stream.read(wordSize).hex); count += wordSize + 4; break; case 'opcode': if (!isValidWord(word)) { throw new Error(`Invalid OPCODE: ${word}`); } stack.push(getOpLabel(word)); break; default: throw new Error(`Word type undefined: ${word}`); } } return stack; } function toAsm(script, varint) { if (Array.isArray(script)) { script = encodeScript(script, varint); } if (script instanceof Uint8Array || isHex(script)) { return decodeScript(script, varint); } throw new Error('Invalid format: ' + String(typeof script)); } function toBytes$4(script, varint) { if (script instanceof Uint8Array || isHex(script)) { script = decodeScript(script, varint); } if (Array.isArray(script)) { return encodeScript(script, varint); } throw new Error('Invalid format: ' + String(typeof script)); } function toParam(script) { if (!Array.isArray(script)) { return Buff$1.bytes(script); } throw new Error('Invalid format: ' + String(typeof script)); } const FmtScript = { toAsm, toBytes: toBytes$4, toParam }; const Script = { encode: encodeScript, decode: decodeScript, fmt: FmtScript }; function number$2(n) { if (!Number.isSafeInteger(n) || n < 0) throw new Error(`Wrong positive integer: ${n}`); } function bool$2(b) { if (typeof b !== 'boolean') throw new Error(`Expected boolean, not ${b}`); } function bytes$2(b, ...lengths) { if (!(b instanceof Uint8Array)) throw new TypeError('Expected Uint8Array'); if (lengths.length > 0 && !lengths.includes(b.length)) throw new TypeError(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`); } function hash$3(hash) { if (typeof hash !== 'function' || typeof hash.create !== 'function') throw new Error('Hash should be wrapped by utils.wrapConstructor'); number$2(hash.outputLen); number$2(hash.blockLen); } function exists$2(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$2(out, instance) { bytes$2(out); const min = instance.outputLen; if (out.length < min) { throw new Error(`digestInto() expects output buffer of length at least ${min}`); } } const assert$3 = { number: number$2, bool: bool$2, bytes: bytes$2, hash: hash$3, exists: exists$2, output: output$2, }; var assert$4 = assert$3; const crypto$1 = typeof globalThis === 'object' && 'crypto' in globalThis ? globalThis.crypto : undefined; /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */ // We use `globalThis.crypto`, but 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, we can just drop the import. // Cast array to view const createView$2 = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength); // The rotate right (circular right shift) operation for uint32 const rotr$2 = (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. const isLE$2 = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44; if (!isLE$2) throw new Error('Non little-endian hardware is not supported'); Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0')); function utf8ToBytes$3(str) { if (typeof str !== 'string') { throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`); } return new TextEncoder().encode(str); } function toBytes$2(data) { if (typeof data === 'string') data = utf8ToBytes$3(data); if (!(data instanceof Uint8Array)) throw new TypeError(`Expected input type is Uint8Array (got ${typeof data})`); return data; } /** * Concats Uint8Array-s into one; like `Buffer.concat([buf1, buf2])` * @example concatBytes(buf1, buf2) */ function concatBytes$1(...arrays) { if (!arrays.every((a) => a instanceof Uint8Array)) throw new Error('Uint8Array list expected'); if (arrays.length === 1) return arrays[0]; const length = arrays.reduce((a, arr) => a + arr.length, 0); const result = new Uint8Array(length); for (let i = 0, pad = 0; i < arrays.length; i++) { const arr = arrays[i]; result.set(arr, pad); pad += arr.length; } return result; } // For runtime check if class implements interface let Hash$2 = class Hash { // Safe version that clones internal state clone() { return this._cloneInto(); } }; function wrapConstructor$2(hashConstructor) { const hashC = (message) => hashConstructor().update(toBytes$2(message)).digest(); const tmp = hashConstructor(); hashC.outputLen = tmp.outputLen; hashC.blockLen = tmp.blockLen; hashC.create = () => hashConstructor(); return hashC; } /** * Secure PRNG. Uses `globalThis.crypto` or node.js crypto module. */ function randomBytes(bytesLength = 32) { if (crypto$1 && typeof crypto$1.getRan