"use strict"; /*! noble-secp256k1 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ Object.defineProperty(exports, "__esModule", { value: true }); exports.utils = exports.schnorr = exports.verify = exports.signSync = exports.sign = exports.getSharedSecret = exports.recoverPublicKey = exports.getPublicKey = exports.hexToBytes = exports.bytesToHex = exports.Signature = exports.Point = exports.CURVE = void 0; const nodeCrypto = require("crypto"); const _0n = BigInt(0); const _1n = BigInt(1); const _2n = BigInt(2); const _3n = BigInt(3); const _8n = BigInt(8); const CURVE = Object.freeze({ a: _0n, b: BigInt(7), P: BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'), n: BigInt('0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'), h: _1n, Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'), Gy: BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424'), beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'), }); exports.CURVE = CURVE; const divNearest = (a, b) => (a + b / _2n) / b; const endo = { beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'), splitScalar(k) { const { n } = CURVE; const a1 = BigInt('0x3086d221a7d46bcde86c90e49284eb15'); const b1 = -_1n * BigInt('0xe4437ed6010e88286f547fa90abfe4c3'); const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8'); const b2 = a1; const POW_2_128 = BigInt('0x100000000000000000000000000000000'); const c1 = divNearest(b2 * k, n); const c2 = divNearest(-b1 * k, n); let k1 = mod(k - c1 * a1 - c2 * a2, n); let k2 = mod(-c1 * b1 - c2 * b2, n); const k1neg = k1 > POW_2_128; const k2neg = k2 > POW_2_128; if (k1neg) k1 = n - k1; if (k2neg) k2 = n - k2; if (k1 > POW_2_128 || k2 > POW_2_128) { throw new Error('splitScalarEndo: Endomorphism failed, k=' + k); } return { k1neg, k1, k2neg, k2 }; }, }; const fieldLen = 32; const groupLen = 32; const hashLen = 32; const compressedLen = fieldLen + 1; const uncompressedLen = 2 * fieldLen + 1; function weierstrass(x) { const { a, b } = CURVE; const x2 = mod(x * x); const x3 = mod(x2 * x); return mod(x3 + a * x + b); } const USE_ENDOMORPHISM = CURVE.a === _0n; class ShaError extends Error { constructor(message) { super(message); } } function assertJacPoint(other) { if (!(other instanceof JacobianPoint)) throw new TypeError('JacobianPoint expected'); } class JacobianPoint { constructor(x, y, z) { this.x = x; this.y = y; this.z = z; } static fromAffine(p) { if (!(p instanceof Point)) { throw new TypeError('JacobianPoint#fromAffine: expected Point'); } if (p.equals(Point.ZERO)) return JacobianPoint.ZERO; return new JacobianPoint(p.x, p.y, _1n); } static toAffineBatch(points) { const toInv = invertBatch(points.map((p) => p.z)); return points.map((p, i) => p.toAffine(toInv[i])); } static normalizeZ(points) { return JacobianPoint.toAffineBatch(points).map(JacobianPoint.fromAffine); } equals(other) { assertJacPoint(other); const { x: X1, y: Y1, z: Z1 } = this; const { x: X2, y: Y2, z: Z2 } = other; const Z1Z1 = mod(Z1 * Z1); const Z2Z2 = mod(Z2 * Z2); const U1 = mod(X1 * Z2Z2); const U2 = mod(X2 * Z1Z1); const S1 = mod(mod(Y1 * Z2) * Z2Z2); const S2 = mod(mod(Y2 * Z1) * Z1Z1); return U1 === U2 && S1 === S2; } negate() { return new JacobianPoint(this.x, mod(-this.y), this.z); } double() { const { x: X1, y: Y1, z: Z1 } = this; const A = mod(X1 * X1); const B = mod(Y1 * Y1); const C = mod(B * B); const x1b = X1 + B; const D = mod(_2n * (mod(x1b * x1b) - A - C)); const E = mod(_3n * A); const F = mod(E * E); const X3 = mod(F - _2n * D); const Y3 = mod(E * (D - X3) - _8n * C); const Z3 = mod(_2n * Y1 * Z1); return new JacobianPoint(X3, Y3, Z3); } add(other) { assertJacPoint(other); const { x: X1, y: Y1, z: Z1 } = this; const { x: X2, y: Y2, z: Z2 } = other; if (X2 === _0n || Y2 === _0n) return this; if (X1 === _0n || Y1 === _0n) return other; const Z1Z1 = mod(Z1 * Z1); const Z2Z2 = mod(Z2 * Z2); const U1 = mod(X1 * Z2Z2); const U2 = mod(X2 * Z1Z1); const S1 = mod(mod(Y1 * Z2) * Z2Z2); const S2 = mod(mod(Y2 * Z1) * Z1Z1); const H = mod(U2 - U1); const r = mod(S2 - S1); if (H === _0n) { if (r === _0n) { return this.double(); } else { return JacobianPoint.ZERO; } } const HH = mod(H * H); const HHH = mod(H * HH); const V = mod(U1 * HH); const X3 = mod(r * r - HHH - _2n * V); const Y3 = mod(r * (V - X3) - S1 * HHH); const Z3 = mod(Z1 * Z2 * H); return new JacobianPoint(X3, Y3, Z3); } subtract(other) { return this.add(other.negate()); } multiplyUnsafe(scalar) { const P0 = JacobianPoint.ZERO; if (typeof scalar === 'bigint' && scalar === _0n) return P0; let n = normalizeScalar(scalar); if (n === _1n) return this; if (!USE_ENDOMORPHISM) { let p = P0; let d = this; while (n > _0n) { if (n & _1n) p = p.add(d); d = d.double(); n >>= _1n; } return p; } let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n); let k1p = P0; let k2p = P0; let d = this; while (k1 > _0n || k2 > _0n) { if (k1 & _1n) k1p = k1p.add(d); if (k2 & _1n) k2p = k2p.add(d); d = d.double(); k1 >>= _1n; k2 >>= _1n; } if (k1neg) k1p = k1p.negate(); if (k2neg) k2p = k2p.negate(); k2p = new JacobianPoint(mod(k2p.x * endo.beta), k2p.y, k2p.z); return k1p.add(k2p); } precomputeWindow(W) { const windows = USE_ENDOMORPHISM ? 128 / W + 1 : 256 / W + 1; const points = []; let p = this; let base = p; for (let window = 0; window < windows; window++) { base = p; points.push(base); for (let i = 1; i < 2 ** (W - 1); i++) { base = base.add(p); points.push(base); } p = base.double(); } return points; } wNAF(n, affinePoint) { if (!affinePoint && this.equals(JacobianPoint.BASE)) affinePoint = Point.BASE; const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1; if (256 % W) { throw new Error('Point#wNAF: Invalid precomputation window, must be power of 2'); } let precomputes = affinePoint && pointPrecomputes.get(affinePoint); if (!precomputes) { precomputes = this.precomputeWindow(W); if (affinePoint && W !== 1) { precomputes = JacobianPoint.normalizeZ(precomputes); pointPrecomputes.set(affinePoint, precomputes); } } let p = JacobianPoint.ZERO; let f = JacobianPoint.BASE; const windows = 1 + (USE_ENDOMORPHISM ? 128 / W : 256 / W); const windowSize = 2 ** (W - 1); const mask = BigInt(2 ** W - 1); const maxNumber = 2 ** W; const shiftBy = BigInt(W); for (let window = 0; window < windows; window++) { const offset = window * windowSize; let wbits = Number(n & mask); n >>= shiftBy; if (wbits > windowSize) { wbits -= maxNumber; n += _1n; } const offset1 = offset; const offset2 = offset + Math.abs(wbits) - 1; const cond1 = window % 2 !== 0; const cond2 = wbits < 0; if (wbits === 0) { f = f.add(constTimeNegate(cond1, precomputes[offset1])); } else { p = p.add(constTimeNegate(cond2, precomputes[offset2])); } } return { p, f }; } multiply(scalar, affinePoint) { let n = normalizeScalar(scalar); let point; let fake; if (USE_ENDOMORPHISM) { const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n); let { p: k1p, f: f1p } = this.wNAF(k1, affinePoint); let { p: k2p, f: f2p } = this.wNAF(k2, affinePoint); k1p = constTimeNegate(k1neg, k1p); k2p = constTimeNegate(k2neg, k2p); k2p = new JacobianPoint(mod(k2p.x * endo.beta), k2p.y, k2p.z); point = k1p.add(k2p); fake = f1p.add(f2p); } else { const { p, f } = this.wNAF(n, affinePoint); point = p; fake = f; } return JacobianPoint.normalizeZ([point, fake])[0]; } toAffine(invZ) { const { x, y, z } = this; const is0 = this.equals(JacobianPoint.ZERO); if (invZ == null) invZ = is0 ? _8n : invert(z); const iz1 = invZ; const iz2 = mod(iz1 * iz1); const iz3 = mod(iz2 * iz1); const ax = mod(x * iz2); const ay = mod(y * iz3); const zz = mod(z * iz1); if (is0) return Point.ZERO; if (zz !== _1n) throw new Error('invZ was invalid'); return new Point(ax, ay); } } JacobianPoint.BASE = new JacobianPoint(CURVE.Gx, CURVE.Gy, _1n); JacobianPoint.ZERO = new JacobianPoint(_0n, _1n, _0n); function constTimeNegate(condition, item) { const neg = item.negate(); return condition ? neg : item; } const pointPrecomputes = new WeakMap(); class Point { constructor(x, y) { this.x = x; this.y = y; } _setWindowSize(windowSize) { this._WINDOW_SIZE = windowSize; pointPrecomputes.delete(this); } hasEvenY() { return this.y % _2n === _0n; } static fromCompressedHex(bytes) { const isShort = bytes.length === 32; const x = bytesToNumber(isShort ? bytes : bytes.subarray(1)); if (!isValidFieldElement(x)) throw new Error('Point is not on curve'); const y2 = weierstrass(x); let y = sqrtMod(y2); const isYOdd = (y & _1n) === _1n; if (isShort) { if (isYOdd) y = mod(-y); } else { const isFirstByteOdd = (bytes[0] & 1) === 1; if (isFirstByteOdd !== isYOdd) y = mod(-y); } const point = new Point(x, y); point.assertValidity(); return point; } static fromUncompressedHex(bytes) { const x = bytesToNumber(bytes.subarray(1, fieldLen + 1)); const y = bytesToNumber(bytes.subarray(fieldLen + 1, fieldLen * 2 + 1)); const point = new Point(x, y); point.assertValidity(); return point; } static fromHex(hex) { const bytes = ensureBytes(hex); const len = bytes.length; const header = bytes[0]; if (len === fieldLen) return this.fromCompressedHex(bytes); if (len === compressedLen && (header === 0x02 || header === 0x03)) { return this.fromCompressedHex(bytes); } if (len === uncompressedLen && header === 0x04) return this.fromUncompressedHex(bytes); throw new Error(`Point.fromHex: received invalid point. Expected 32-${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes, not ${len}`); } static fromPrivateKey(privateKey) { return Point.BASE.multiply(normalizePrivateKey(privateKey)); } static fromSignature(msgHash, signature, recovery) { const { r, s } = normalizeSignature(signature); if (![0, 1, 2, 3].includes(recovery)) throw new Error('Cannot recover: invalid recovery bit'); const h = truncateHash(ensureBytes(msgHash)); const { n } = CURVE; const radj = recovery === 2 || recovery === 3 ? r + n : r; const rinv = invert(radj, n); const u1 = mod(-h * rinv, n); const u2 = mod(s * rinv, n); const prefix = recovery & 1 ? '03' : '02'; const R = Point.fromHex(prefix + numTo32bStr(radj)); const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); if (!Q) throw new Error('Cannot recover signature: point at infinify'); Q.assertValidity(); return Q; } toRawBytes(isCompressed = false) { return hexToBytes(this.toHex(isCompressed)); } toHex(isCompressed = false) { const x = numTo32bStr(this.x); if (isCompressed) { const prefix = this.hasEvenY() ? '02' : '03'; return `${prefix}${x}`; } else { return `04${x}${numTo32bStr(this.y)}`; } } toHexX() { return this.toHex(true).slice(2); } toRawX() { return this.toRawBytes(true).slice(1); } assertValidity() { const msg = 'Point is not on elliptic curve'; const { x, y } = this; if (!isValidFieldElement(x) || !isValidFieldElement(y)) throw new Error(msg); const left = mod(y * y); const right = weierstrass(x); if (mod(left - right) !== _0n) throw new Error(msg); } equals(other) { return this.x === other.x && this.y === other.y; } negate() { return new Point(this.x, mod(-this.y)); } double() { return JacobianPoint.fromAffine(this).double().toAffine(); } add(other) { return JacobianPoint.fromAffine(this).add(JacobianPoint.fromAffine(other)).toAffine(); } subtract(other) { return this.add(other.negate()); } multiply(scalar) { return JacobianPoint.fromAffine(this).multiply(scalar, this).toAffine(); } multiplyAndAddUnsafe(Q, a, b) { const P = JacobianPoint.fromAffine(this); const aP = a === _0n || a === _1n || this !== Point.BASE ? P.multiplyUnsafe(a) : P.multiply(a); const bQ = JacobianPoint.fromAffine(Q).multiplyUnsafe(b); const sum = aP.add(bQ); return sum.equals(JacobianPoint.ZERO) ? undefined : sum.toAffine(); } } exports.Point = Point; Point.BASE = new Point(CURVE.Gx, CURVE.Gy); Point.ZERO = new Point(_0n, _0n); function sliceDER(s) { return Number.parseInt(s[0], 16) >= 8 ? '00' + s : s; } function parseDERInt(data) { if (data.length < 2 || data[0] !== 0x02) { throw new Error(`Invalid signature integer tag: ${bytesToHex(data)}`); } const len = data[1]; const res = data.subarray(2, len + 2); if (!len || res.length !== len) { throw new Error(`Invalid signature integer: wrong length`); } if (res[0] === 0x00 && res[1] <= 0x7f) { throw new Error('Invalid signature integer: trailing length'); } return { data: bytesToNumber(res), left: data.subarray(len + 2) }; } function parseDERSignature(data) { if (data.length < 2 || data[0] != 0x30) { throw new Error(`Invalid signature tag: ${bytesToHex(data)}`); } if (data[1] !== data.length - 2) { throw new Error('Invalid signature: incorrect length'); } const { data: r, left: sBytes } = parseDERInt(data.subarray(2)); const { data: s, left: rBytesLeft } = parseDERInt(sBytes); if (rBytesLeft.length) { throw new Error(`Invalid signature: left bytes after parsing: ${bytesToHex(rBytesLeft)}`); } return { r, s }; } class Signature { constructor(r, s) { this.r = r; this.s = s; this.assertValidity(); } static fromCompact(hex) { const arr = isBytes(hex); const name = 'Signature.fromCompact'; if (typeof hex !== 'string' && !arr) throw new TypeError(`${name}: Expected string or Uint8Array`); const str = arr ? bytesToHex(hex) : hex; if (str.length !== 128) throw new Error(`${name}: Expected 64-byte hex`); return new Signature(hexToNumber(str.slice(0, 64)), hexToNumber(str.slice(64, 128))); } static fromDER(hex) { const arr = isBytes(hex); if (typeof hex !== 'string' && !arr) throw new TypeError(`Signature.fromDER: Expected string or Uint8Array`); const { r, s } = parseDERSignature(arr ? hex : hexToBytes(hex)); return new Signature(r, s); } static fromHex(hex) { return this.fromDER(hex); } assertValidity() { const { r, s } = this; if (!isWithinCurveOrder(r)) throw new Error('Invalid Signature: r must be 0 < r < n'); if (!isWithinCurveOrder(s)) throw new Error('Invalid Signature: s must be 0 < s < n'); } hasHighS() { const HALF = CURVE.n >> _1n; return this.s > HALF; } normalizeS() { return this.hasHighS() ? new Signature(this.r, mod(-this.s, CURVE.n)) : this; } toDERRawBytes() { return hexToBytes(this.toDERHex()); } toDERHex() { const sHex = sliceDER(numberToHexUnpadded(this.s)); const rHex = sliceDER(numberToHexUnpadded(this.r)); const sHexL = sHex.length / 2; const rHexL = rHex.length / 2; const sLen = numberToHexUnpadded(sHexL); const rLen = numberToHexUnpadded(rHexL); const length = numberToHexUnpadded(rHexL + sHexL + 4); return `30${length}02${rLen}${rHex}02${sLen}${sHex}`; } toRawBytes() { return this.toDERRawBytes(); } toHex() { return this.toDERHex(); } toCompactRawBytes() { return hexToBytes(this.toCompactHex()); } toCompactHex() { return numTo32bStr(this.r) + numTo32bStr(this.s); } } exports.Signature = Signature; function isBytes(a) { return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array'); } function abytes(item) { if (!isBytes(item)) throw new Error('Uint8Array expected'); } function concatBytes(...arrays) { arrays.every(abytes); 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; } const hexes = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0')); function bytesToHex(bytes) { abytes(bytes); let hex = ''; for (let i = 0; i < bytes.length; i++) { hex += hexes[bytes[i]]; } return hex; } exports.bytesToHex = bytesToHex; const asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; function asciiToBase16(ch) { if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); return; } function hexToBytes(hex) { if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex); const hl = hex.length; const al = hl / 2; if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl); const array = new Uint8Array(al); for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) { const n1 = asciiToBase16(hex.charCodeAt(hi)); const n2 = asciiToBase16(hex.charCodeAt(hi + 1)); if (n1 === undefined || n2 === undefined) { const char = hex[hi] + hex[hi + 1]; throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi); } array[ai] = n1 * 16 + n2; } return array; } exports.hexToBytes = hexToBytes; const POW_2_256 = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000'); function numTo32bStr(num) { if (typeof num !== 'bigint') throw new Error('Expected bigint'); if (!(_0n <= num && num < POW_2_256)) throw new Error('Expected number 0 <= n < 2^256'); return num.toString(16).padStart(64, '0'); } function numTo32b(num) { const b = hexToBytes(numTo32bStr(num)); if (b.length !== 32) throw new Error('Error: expected 32 bytes'); return b; } function numberToHexUnpadded(num) { const hex = num.toString(16); return hex.length & 1 ? `0${hex}` : hex; } function hexToNumber(hex) { if (typeof hex !== 'string') { throw new TypeError('hexToNumber: expected string, got ' + typeof hex); } return BigInt(`0x${hex}`); } function bytesToNumber(bytes) { return hexToNumber(bytesToHex(bytes)); } function ensureBytes(hex) { return isBytes(hex) ? Uint8Array.from(hex) : hexToBytes(hex); } function normalizeScalar(num) { if (typeof num === 'number' && Number.isSafeInteger(num) && num > 0) return BigInt(num); if (typeof num === 'bigint' && isWithinCurveOrder(num)) return num; throw new TypeError('Expected valid private scalar: 0 < scalar < curve.n'); } function mod(a, b = CURVE.P) { const result = a % b; return result >= _0n ? result : b + result; } function pow2(x, power) { const { P } = CURVE; let res = x; while (power-- > _0n) { res *= res; res %= P; } return res; } function sqrtMod(x) { const { P } = CURVE; const _6n = BigInt(6); const _11n = BigInt(11); const _22n = BigInt(22); const _23n = BigInt(23); const _44n = BigInt(44); const _88n = BigInt(88); const b2 = (x * x * x) % P; const b3 = (b2 * b2 * x) % P; const b6 = (pow2(b3, _3n) * b3) % P; const b9 = (pow2(b6, _3n) * b3) % P; const b11 = (pow2(b9, _2n) * b2) % P; const b22 = (pow2(b11, _11n) * b11) % P; const b44 = (pow2(b22, _22n) * b22) % P; const b88 = (pow2(b44, _44n) * b44) % P; const b176 = (pow2(b88, _88n) * b88) % P; const b220 = (pow2(b176, _44n) * b44) % P; const b223 = (pow2(b220, _3n) * b3) % P; const t1 = (pow2(b223, _23n) * b22) % P; const t2 = (pow2(t1, _6n) * b2) % P; const rt = pow2(t2, _2n); const xc = (rt * rt) % P; if (xc !== x) throw new Error('Cannot find square root'); return rt; } function invert(number, modulo = CURVE.P) { if (number === _0n || modulo <= _0n) { throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`); } let a = mod(number, modulo); let b = modulo; let x = _0n, y = _1n, u = _1n, v = _0n; while (a !== _0n) { const q = b / a; const r = b % a; const m = x - u * q; const n = y - v * q; b = a, a = r, x = u, y = v, u = m, v = n; } const gcd = b; if (gcd !== _1n) throw new Error('invert: does not exist'); return mod(x, modulo); } function invertBatch(nums, p = CURVE.P) { const scratch = new Array(nums.length); const lastMultiplied = nums.reduce((acc, num, i) => { if (num === _0n) return acc; scratch[i] = acc; return mod(acc * num, p); }, _1n); const inverted = invert(lastMultiplied, p); nums.reduceRight((acc, num, i) => { if (num === _0n) return acc; scratch[i] = mod(acc * scratch[i], p); return mod(acc * num, p); }, inverted); return scratch; } function bits2int_2(bytes) { const delta = bytes.length * 8 - groupLen * 8; const num = bytesToNumber(bytes); return delta > 0 ? num >> BigInt(delta) : num; } function truncateHash(hash, truncateOnly = false) { const h = bits2int_2(hash); if (truncateOnly) return h; const { n } = CURVE; return h >= n ? h - n : h; } let _sha256Sync; let _hmacSha256Sync; class HmacDrbg { constructor(hashLen, qByteLen) { this.hashLen = hashLen; this.qByteLen = qByteLen; if (typeof hashLen !== 'number' || hashLen < 2) throw new Error('hashLen must be a number'); if (typeof qByteLen !== 'number' || qByteLen < 2) throw new Error('qByteLen must be a number'); this.v = new Uint8Array(hashLen).fill(1); this.k = new Uint8Array(hashLen).fill(0); this.counter = 0; } hmac(...values) { return exports.utils.hmacSha256(this.k, ...values); } hmacSync(...values) { return _hmacSha256Sync(this.k, ...values); } checkSync() { if (typeof _hmacSha256Sync !== 'function') throw new ShaError('hmacSha256Sync needs to be set'); } incr() { if (this.counter >= 1000) throw new Error('Tried 1,000 k values for sign(), all were invalid'); this.counter += 1; } async reseed(seed = new Uint8Array()) { this.k = await this.hmac(this.v, Uint8Array.from([0x00]), seed); this.v = await this.hmac(this.v); if (seed.length === 0) return; this.k = await this.hmac(this.v, Uint8Array.from([0x01]), seed); this.v = await this.hmac(this.v); } reseedSync(seed = new Uint8Array()) { this.checkSync(); this.k = this.hmacSync(this.v, Uint8Array.from([0x00]), seed); this.v = this.hmacSync(this.v); if (seed.length === 0) return; this.k = this.hmacSync(this.v, Uint8Array.from([0x01]), seed); this.v = this.hmacSync(this.v); } async generate() { this.incr(); let len = 0; const out = []; while (len < this.qByteLen) { this.v = await this.hmac(this.v); const sl = this.v.slice(); out.push(sl); len += this.v.length; } return concatBytes(...out); } generateSync() { this.checkSync(); this.incr(); let len = 0; const out = []; while (len < this.qByteLen) { this.v = this.hmacSync(this.v); const sl = this.v.slice(); out.push(sl); len += this.v.length; } return concatBytes(...out); } } function isWithinCurveOrder(num) { return _0n < num && num < CURVE.n; } function isValidFieldElement(num) { return _0n < num && num < CURVE.P; } function kmdToSig(kBytes, m, d, lowS = true) { const { n } = CURVE; const k = truncateHash(kBytes, true); if (!isWithinCurveOrder(k)) return; const kinv = invert(k, n); const q = Point.BASE.multiply(k); const r = mod(q.x, n); if (r === _0n) return; const s = mod(kinv * mod(m + d * r, n), n); if (s === _0n) return; let sig = new Signature(r, s); let recovery = (q.x === sig.r ? 0 : 2) | Number(q.y & _1n); if (lowS && sig.hasHighS()) { sig = sig.normalizeS(); recovery ^= 1; } return { sig, recovery }; } function normalizePrivateKey(key) { let num; if (typeof key === 'bigint') { num = key; } else if (typeof key === 'number' && Number.isSafeInteger(key) && key > 0) { num = BigInt(key); } else if (typeof key === 'string') { if (key.length !== 2 * groupLen) throw new Error('Expected 32 bytes of private key'); num = hexToNumber(key); } else if (isBytes(key)) { if (key.length !== groupLen) throw new Error('Expected 32 bytes of private key'); num = bytesToNumber(key); } else { throw new TypeError('Expected valid private key'); } if (!isWithinCurveOrder(num)) throw new Error('Expected private key: 0 < key < n'); return num; } function normalizePublicKey(publicKey) { if (publicKey instanceof Point) { publicKey.assertValidity(); return publicKey; } else { return Point.fromHex(publicKey); } } function normalizeSignature(signature) { if (signature instanceof Signature) { signature.assertValidity(); return signature; } try { return Signature.fromDER(signature); } catch (error) { return Signature.fromCompact(signature); } } function getPublicKey(privateKey, isCompressed = false) { return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed); } exports.getPublicKey = getPublicKey; function recoverPublicKey(msgHash, signature, recovery, isCompressed = false) { return Point.fromSignature(msgHash, signature, recovery).toRawBytes(isCompressed); } exports.recoverPublicKey = recoverPublicKey; function isProbPub(item) { const arr = isBytes(item); const str = typeof item === 'string'; const len = (arr || str) && item.length; if (arr) return len === compressedLen || len === uncompressedLen; if (str) return len === compressedLen * 2 || len === uncompressedLen * 2; if (item instanceof Point) return true; return false; } function getSharedSecret(privateA, publicB, isCompressed = false) { if (isProbPub(privateA)) throw new TypeError('getSharedSecret: first arg must be private key'); if (!isProbPub(publicB)) throw new TypeError('getSharedSecret: second arg must be public key'); const b = normalizePublicKey(publicB); b.assertValidity(); return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed); } exports.getSharedSecret = getSharedSecret; function bits2int(bytes) { const slice = bytes.length > fieldLen ? bytes.slice(0, fieldLen) : bytes; return bytesToNumber(slice); } function bits2octets(bytes) { const z1 = bits2int(bytes); const z2 = mod(z1, CURVE.n); return int2octets(z2 < _0n ? z1 : z2); } function int2octets(num) { return numTo32b(num); } function initSigArgs(msgHash, privateKey, extraEntropy) { if (msgHash == null) throw new Error(`sign: expected valid message hash, not "${msgHash}"`); const h1 = ensureBytes(msgHash); const d = normalizePrivateKey(privateKey); const seedArgs = [int2octets(d), bits2octets(h1)]; if (extraEntropy != null) { if (extraEntropy === true) extraEntropy = exports.utils.randomBytes(fieldLen); const e = ensureBytes(extraEntropy); if (e.length !== fieldLen) throw new Error(`sign: Expected ${fieldLen} bytes of extra data`); seedArgs.push(e); } const seed = concatBytes(...seedArgs); const m = bits2int(h1); return { seed, m, d }; } function finalizeSig(recSig, opts) { const { sig, recovery } = recSig; const { der, recovered } = Object.assign({ canonical: true, der: true }, opts); const hashed = der ? sig.toDERRawBytes() : sig.toCompactRawBytes(); return recovered ? [hashed, recovery] : hashed; } async function sign(msgHash, privKey, opts = {}) { const { seed, m, d } = initSigArgs(msgHash, privKey, opts.extraEntropy); const drbg = new HmacDrbg(hashLen, groupLen); await drbg.reseed(seed); let sig; while (!(sig = kmdToSig(await drbg.generate(), m, d, opts.canonical))) await drbg.reseed(); return finalizeSig(sig, opts); } exports.sign = sign; function signSync(msgHash, privKey, opts = {}) { const { seed, m, d } = initSigArgs(msgHash, privKey, opts.extraEntropy); const drbg = new HmacDrbg(hashLen, groupLen); drbg.reseedSync(seed); let sig; while (!(sig = kmdToSig(drbg.generateSync(), m, d, opts.canonical))) drbg.reseedSync(); return finalizeSig(sig, opts); } exports.signSync = signSync; const vopts = { strict: true }; function verify(signature, msgHash, publicKey, opts = vopts) { let sig; try { sig = normalizeSignature(signature); msgHash = ensureBytes(msgHash); } catch (error) { return false; } const { r, s } = sig; if (opts.strict && sig.hasHighS()) return false; const h = truncateHash(msgHash); let P; try { P = normalizePublicKey(publicKey); } catch (error) { return false; } const { n } = CURVE; const sinv = invert(s, n); const u1 = mod(h * sinv, n); const u2 = mod(r * sinv, n); const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2); if (!R) return false; const v = mod(R.x, n); return v === r; } exports.verify = verify; function schnorrChallengeFinalize(ch) { return mod(bytesToNumber(ch), CURVE.n); } class SchnorrSignature { constructor(r, s) { this.r = r; this.s = s; this.assertValidity(); } static fromHex(hex) { const bytes = ensureBytes(hex); if (bytes.length !== 64) throw new TypeError(`SchnorrSignature.fromHex: expected 64 bytes, not ${bytes.length}`); const r = bytesToNumber(bytes.subarray(0, 32)); const s = bytesToNumber(bytes.subarray(32, 64)); return new SchnorrSignature(r, s); } assertValidity() { const { r, s } = this; if (!isValidFieldElement(r) || !isWithinCurveOrder(s)) throw new Error('Invalid signature'); } toHex() { return numTo32bStr(this.r) + numTo32bStr(this.s); } toRawBytes() { return hexToBytes(this.toHex()); } } function schnorrGetPublicKey(privateKey) { return Point.fromPrivateKey(privateKey).toRawX(); } class InternalSchnorrSignature { constructor(message, privateKey, auxRand = exports.utils.randomBytes()) { if (message == null) throw new TypeError(`sign: Expected valid message, not "${message}"`); this.m = ensureBytes(message); const { x, scalar } = this.getScalar(normalizePrivateKey(privateKey)); this.px = x; this.d = scalar; this.rand = ensureBytes(auxRand); if (this.rand.length !== 32) throw new TypeError('sign: Expected 32 bytes of aux randomness'); } getScalar(priv) { const point = Point.fromPrivateKey(priv); const scalar = point.hasEvenY() ? priv : CURVE.n - priv; return { point, scalar, x: point.toRawX() }; } initNonce(d, t0h) { return numTo32b(d ^ bytesToNumber(t0h)); } finalizeNonce(k0h) { const k0 = mod(bytesToNumber(k0h), CURVE.n); if (k0 === _0n) throw new Error('sign: Creation of signature failed. k is zero'); const { point: R, x: rx, scalar: k } = this.getScalar(k0); return { R, rx, k }; } finalizeSig(R, k, e, d) { return new SchnorrSignature(R.x, mod(k + e * d, CURVE.n)).toRawBytes(); } error() { throw new Error('sign: Invalid signature produced'); } async calc() { const { m, d, px, rand } = this; const tag = exports.utils.taggedHash; const t = this.initNonce(d, await tag(TAGS.aux, rand)); const { R, rx, k } = this.finalizeNonce(await tag(TAGS.nonce, t, px, m)); const e = schnorrChallengeFinalize(await tag(TAGS.challenge, rx, px, m)); const sig = this.finalizeSig(R, k, e, d); if (!(await schnorrVerify(sig, m, px))) this.error(); return sig; } calcSync() { const { m, d, px, rand } = this; const tag = exports.utils.taggedHashSync; const t = this.initNonce(d, tag(TAGS.aux, rand)); const { R, rx, k } = this.finalizeNonce(tag(TAGS.nonce, t, px, m)); const e = schnorrChallengeFinalize(tag(TAGS.challenge, rx, px, m)); const sig = this.finalizeSig(R, k, e, d); if (!schnorrVerifySync(sig, m, px)) this.error(); return sig; } } async function schnorrSign(msg, privKey, auxRand) { return new InternalSchnorrSignature(msg, privKey, auxRand).calc(); } function schnorrSignSync(msg, privKey, auxRand) { return new InternalSchnorrSignature(msg, privKey, auxRand).calcSync(); } function initSchnorrVerify(signature, message, publicKey) { const raw = signature instanceof SchnorrSignature; const sig = raw ? signature : SchnorrSignature.fromHex(signature); if (raw) sig.assertValidity(); return { ...sig, m: ensureBytes(message), P: normalizePublicKey(publicKey), }; } function finalizeSchnorrVerify(r, P, s, e) { const R = Point.BASE.multiplyAndAddUnsafe(P, normalizePrivateKey(s), mod(-e, CURVE.n)); if (!R || !R.hasEvenY() || R.x !== r) return false; return true; } async function schnorrVerify(signature, message, publicKey) { try { const { r, s, m, P } = initSchnorrVerify(signature, message, publicKey); const e = schnorrChallengeFinalize(await exports.utils.taggedHash(TAGS.challenge, numTo32b(r), P.toRawX(), m)); return finalizeSchnorrVerify(r, P, s, e); } catch (error) { return false; } } function schnorrVerifySync(signature, message, publicKey) { try { const { r, s, m, P } = initSchnorrVerify(signature, message, publicKey); const e = schnorrChallengeFinalize(exports.utils.taggedHashSync(TAGS.challenge, numTo32b(r), P.toRawX(), m)); return finalizeSchnorrVerify(r, P, s, e); } catch (error) { if (error instanceof ShaError) throw error; return false; } } exports.schnorr = { Signature: SchnorrSignature, getPublicKey: schnorrGetPublicKey, sign: schnorrSign, verify: schnorrVerify, signSync: schnorrSignSync, verifySync: schnorrVerifySync, }; Point.BASE._setWindowSize(8); const crypto = { node: nodeCrypto, web: typeof self === 'object' && 'crypto' in self ? self.crypto : undefined, }; const TAGS = { challenge: 'BIP0340/challenge', aux: 'BIP0340/aux', nonce: 'BIP0340/nonce', }; const TAGGED_HASH_PREFIXES = {}; exports.utils = { bytesToHex, hexToBytes, concatBytes, mod, invert, isValidPrivateKey(privateKey) { try { normalizePrivateKey(privateKey); return true; } catch (error) { return false; } }, _bigintTo32Bytes: numTo32b, _normalizePrivateKey: normalizePrivateKey, hashToPrivateKey: (hash) => { hash = ensureBytes(hash); const minLen = groupLen + 8; if (hash.length < minLen || hash.length > 1024) { throw new Error(`Expected valid bytes of private key as per FIPS 186`); } const num = mod(bytesToNumber(hash), CURVE.n - _1n) + _1n; return numTo32b(num); }, randomBytes: (bytesLength = 32) => { if (crypto.web) { return crypto.web.getRandomValues(new Uint8Array(bytesLength)); } else if (crypto.node) { const { randomBytes } = crypto.node; return Uint8Array.from(randomBytes(bytesLength)); } else { throw new Error("The environment doesn't have randomBytes function"); } }, randomPrivateKey: () => exports.utils.hashToPrivateKey(exports.utils.randomBytes(groupLen + 8)), precompute(windowSize = 8, point = Point.BASE) { const cached = point === Point.BASE ? point : new Point(point.x, point.y); cached._setWindowSize(windowSize); cached.multiply(_3n); return cached; }, sha256: async (...messages) => { if (crypto.web) { const buffer = await crypto.web.subtle.digest('SHA-256', concatBytes(...messages)); return new Uint8Array(buffer); } else if (crypto.node) { const { createHash } = crypto.node; const hash = createHash('sha256'); messages.forEach((m) => hash.update(m)); return Uint8Array.from(hash.digest()); } else { throw new Error("The environment doesn't have sha256 function"); } }, hmacSha256: async (key, ...messages) => { if (crypto.web) { const ckey = await crypto.web.subtle.importKey('raw', key, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign']); const message = concatBytes(...messages); const buffer = await crypto.web.subtle.sign('HMAC', ckey, message); return new Uint8Array(buffer); } else if (crypto.node) { const { createHmac } = crypto.node; const hash = createHmac('sha256', key); messages.forEach((m) => hash.update(m)); return Uint8Array.from(hash.digest()); } else { throw new Error("The environment doesn't have hmac-sha256 function"); } }, sha256Sync: undefined, hmacSha256Sync: undefined, taggedHash: async (tag, ...messages) => { let tagP = TAGGED_HASH_PREFIXES[tag]; if (tagP === undefined) { const tagH = await exports.utils.sha256(Uint8Array.from(tag, (c) => c.charCodeAt(0))); tagP = concatBytes(tagH, tagH); TAGGED_HASH_PREFIXES[tag] = tagP; } return exports.utils.sha256(tagP, ...messages); }, taggedHashSync: (tag, ...messages) => { if (typeof _sha256Sync !== 'function') throw new ShaError('sha256Sync is undefined, you need to set it'); let tagP = TAGGED_HASH_PREFIXES[tag]; if (tagP === undefined) { const tagH = _sha256Sync(Uint8Array.from(tag, (c) => c.charCodeAt(0))); tagP = concatBytes(tagH, tagH); TAGGED_HASH_PREFIXES[tag] = tagP; } return _sha256Sync(tagP, ...messages); }, _JacobianPoint: JacobianPoint, }; Object.defineProperties(exports.utils, { sha256Sync: { configurable: false, get() { return _sha256Sync; }, set(val) { if (!_sha256Sync) _sha256Sync = val; }, }, hmacSha256Sync: { configurable: false, get() { return _hmacSha256Sync; }, set(val) { if (!_hmacSha256Sync) _hmacSha256Sync = val; }, }, });