UNPKG

@elizaos/plugin-story

Version:

Story Protocol plugin for elizaOS - enables IP registration, licensing, and terms attachment on Story Protocol

1,646 lines (1,640 loc) 73.5 kB
import { Hash, _validateObject, aInRange, abool, abytes, aexists, ahash, anumber, aoutput, bitLen, bitMask, bytesToHex, bytesToNumberBE, bytesToNumberLE, clean, concatBytes, createHasher, createHmacDrbg, createView, ensureBytes, hexToBytes, inRange, isBytes, isHash, memoized, numberToBytesBE, numberToBytesLE, numberToHexUnpadded, randomBytes, rotr, toBytes, utf8ToBytes } from "./chunk-C32RXCHU.js"; // node_modules/@noble/hashes/esm/_md.js 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(4294967295); 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); } function Chi(a, b, c) { return a & b ^ ~a & c; } function Maj(a, b, c) { return a & b ^ a & c ^ b & c; } var HashMD = class extends Hash { constructor(blockLen, outputLen, padOffset, isLE) { super(); this.finished = false; this.length = 0; this.pos = 0; this.destroyed = false; this.blockLen = blockLen; this.outputLen = outputLen; this.padOffset = padOffset; this.isLE = isLE; this.buffer = new Uint8Array(blockLen); this.view = createView(this.buffer); } update(data) { aexists(this); data = toBytes(data); abytes(data); const { view, buffer, blockLen } = this; const len = data.length; for (let pos = 0; pos < len; ) { const take = Math.min(blockLen - this.pos, len - pos); 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) { aexists(this); aoutput(out, this); this.finished = true; const { buffer, view, blockLen, isLE } = this; let { pos } = this; buffer[pos++] = 128; clean(this.buffer.subarray(pos)); if (this.padOffset > blockLen - pos) { this.process(view, 0); pos = 0; } for (let i = pos; i < blockLen; i++) buffer[i] = 0; setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE); this.process(view, 0); const oview = createView(out); const len = this.outputLen; 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.destroyed = destroyed; to.finished = finished; to.length = length; to.pos = pos; if (length % blockLen) to.buffer.set(buffer); return to; } clone() { return this._cloneInto(); } }; var SHA256_IV = /* @__PURE__ */ Uint32Array.from([ 1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225 ]); // node_modules/@noble/hashes/esm/sha2.js var SHA256_K = /* @__PURE__ */ Uint32Array.from([ 1116352408, 1899447441, 3049323471, 3921009573, 961987163, 1508970993, 2453635748, 2870763221, 3624381080, 310598401, 607225278, 1426881987, 1925078388, 2162078206, 2614888103, 3248222580, 3835390401, 4022224774, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, 2554220882, 2821834349, 2952996808, 3210313671, 3336571891, 3584528711, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, 2177026350, 2456956037, 2730485921, 2820302411, 3259730800, 3345764771, 3516065817, 3600352804, 4094571909, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, 2227730452, 2361852424, 2428436474, 2756734187, 3204031479, 3329325298 ]); var SHA256_W = /* @__PURE__ */ new Uint32Array(64); var SHA256 = class extends HashMD { constructor(outputLen = 32) { super(64, outputLen, 8, false); this.A = SHA256_IV[0] | 0; this.B = SHA256_IV[1] | 0; this.C = SHA256_IV[2] | 0; this.D = SHA256_IV[3] | 0; this.E = SHA256_IV[4] | 0; this.F = SHA256_IV[5] | 0; this.G = SHA256_IV[6] | 0; this.H = SHA256_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) { 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; } 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; } 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() { clean(SHA256_W); } destroy() { this.set(0, 0, 0, 0, 0, 0, 0, 0); clean(this.buffer); } }; var sha256 = /* @__PURE__ */ createHasher(() => new SHA256()); // node_modules/@noble/hashes/esm/hmac.js var HMAC = class extends Hash { constructor(hash, _key) { super(); this.finished = false; this.destroyed = false; ahash(hash); const key = toBytes(_key); this.iHash = hash.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); pad.set(key.length > blockLen ? hash.create().update(key).digest() : key); for (let i = 0; i < pad.length; i++) pad[i] ^= 54; this.iHash.update(pad); this.oHash = hash.create(); for (let i = 0; i < pad.length; i++) pad[i] ^= 54 ^ 92; this.oHash.update(pad); clean(pad); } update(buf) { aexists(this); this.iHash.update(buf); return this; } digestInto(out) { aexists(this); abytes(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) { 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; } clone() { return this._cloneInto(); } destroy() { this.destroyed = true; this.oHash.destroy(); this.iHash.destroy(); } }; var hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest(); hmac.create = (hash, key) => new HMAC(hash, key); // node_modules/@noble/curves/esm/abstract/modular.js var _0n = BigInt(0); var _1n = BigInt(1); var _2n = /* @__PURE__ */ BigInt(2); var _3n = /* @__PURE__ */ BigInt(3); var _4n = /* @__PURE__ */ BigInt(4); var _5n = /* @__PURE__ */ BigInt(5); var _8n = /* @__PURE__ */ BigInt(8); function mod(a, b) { const result = a % b; return result >= _0n ? result : b + result; } function pow2(x, power, modulo) { let res = x; while (power-- > _0n) { res *= res; res %= modulo; } return res; } function invert(number, modulo) { if (number === _0n) throw new Error("invert: expected non-zero number"); if (modulo <= _0n) throw new Error("invert: expected positive modulus, got " + 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 sqrt3mod4(Fp, n) { const p1div4 = (Fp.ORDER + _1n) / _4n; const root = Fp.pow(n, p1div4); if (!Fp.eql(Fp.sqr(root), n)) throw new Error("Cannot find square root"); return root; } function sqrt5mod8(Fp, n) { const p5div8 = (Fp.ORDER - _5n) / _8n; const n2 = Fp.mul(n, _2n); const v = Fp.pow(n2, p5div8); const nv = Fp.mul(n, v); const i = Fp.mul(Fp.mul(nv, _2n), v); const root = Fp.mul(nv, Fp.sub(i, Fp.ONE)); if (!Fp.eql(Fp.sqr(root), n)) throw new Error("Cannot find square root"); return root; } function tonelliShanks(P) { if (P < BigInt(3)) throw new Error("sqrt is not defined for small field"); let Q = P - _1n; let S = 0; while (Q % _2n === _0n) { Q /= _2n; S++; } let Z = _2n; const _Fp = Field(P); while (FpLegendre(_Fp, Z) === 1) { if (Z++ > 1e3) throw new Error("Cannot find square root: probably non-prime P"); } if (S === 1) return sqrt3mod4; let cc = _Fp.pow(Z, Q); const Q1div2 = (Q + _1n) / _2n; return function tonelliSlow(Fp, n) { if (Fp.is0(n)) return n; if (FpLegendre(Fp, n) !== 1) throw new Error("Cannot find square root"); let M = S; let c = Fp.mul(Fp.ONE, cc); let t = Fp.pow(n, Q); let R = Fp.pow(n, Q1div2); while (!Fp.eql(t, Fp.ONE)) { if (Fp.is0(t)) return Fp.ZERO; let i = 1; let t_tmp = Fp.sqr(t); while (!Fp.eql(t_tmp, Fp.ONE)) { i++; t_tmp = Fp.sqr(t_tmp); if (i === M) throw new Error("Cannot find square root"); } const exponent = _1n << BigInt(M - i - 1); const b = Fp.pow(c, exponent); M = i; c = Fp.sqr(b); t = Fp.mul(t, c); R = Fp.mul(R, b); } return R; }; } function FpSqrt(P) { if (P % _4n === _3n) return sqrt3mod4; if (P % _8n === _5n) return sqrt5mod8; return tonelliShanks(P); } var FIELD_FIELDS = [ "create", "isValid", "is0", "neg", "inv", "sqrt", "sqr", "eql", "add", "sub", "mul", "pow", "div", "addN", "subN", "mulN", "sqrN" ]; function validateField(field) { const initial = { ORDER: "bigint", MASK: "bigint", BYTES: "number", BITS: "number" }; const opts = FIELD_FIELDS.reduce((map, val) => { map[val] = "function"; return map; }, initial); _validateObject(field, opts); return field; } function FpPow(Fp, num2, power) { if (power < _0n) throw new Error("invalid exponent, negatives unsupported"); if (power === _0n) return Fp.ONE; if (power === _1n) return num2; let p = Fp.ONE; let d = num2; while (power > _0n) { if (power & _1n) p = Fp.mul(p, d); d = Fp.sqr(d); power >>= _1n; } return p; } function FpInvertBatch(Fp, nums, passZero = false) { const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : void 0); const multipliedAcc = nums.reduce((acc, num2, i) => { if (Fp.is0(num2)) return acc; inverted[i] = acc; return Fp.mul(acc, num2); }, Fp.ONE); const invertedAcc = Fp.inv(multipliedAcc); nums.reduceRight((acc, num2, i) => { if (Fp.is0(num2)) return acc; inverted[i] = Fp.mul(acc, inverted[i]); return Fp.mul(acc, num2); }, invertedAcc); return inverted; } function FpLegendre(Fp, n) { const p1mod2 = (Fp.ORDER - _1n) / _2n; const powered = Fp.pow(n, p1mod2); const yes = Fp.eql(powered, Fp.ONE); const zero = Fp.eql(powered, Fp.ZERO); const no = Fp.eql(powered, Fp.neg(Fp.ONE)); if (!yes && !zero && !no) throw new Error("invalid Legendre symbol result"); return yes ? 1 : zero ? 0 : -1; } function nLength(n, nBitLength) { if (nBitLength !== void 0) anumber(nBitLength); const _nBitLength = nBitLength !== void 0 ? nBitLength : n.toString(2).length; const nByteLength = Math.ceil(_nBitLength / 8); return { nBitLength: _nBitLength, nByteLength }; } function Field(ORDER, bitLenOrOpts, isLE = false, opts = {}) { if (ORDER <= _0n) throw new Error("invalid field: expected ORDER > 0, got " + ORDER); let _nbitLength = void 0; let _sqrt = void 0; if (typeof bitLenOrOpts === "object" && bitLenOrOpts != null) { if (opts.sqrt || isLE) throw new Error("cannot specify opts in two arguments"); const _opts = bitLenOrOpts; if (_opts.BITS) _nbitLength = _opts.BITS; if (_opts.sqrt) _sqrt = _opts.sqrt; if (typeof _opts.isLE === "boolean") isLE = _opts.isLE; } else { if (typeof bitLenOrOpts === "number") _nbitLength = bitLenOrOpts; if (opts.sqrt) _sqrt = opts.sqrt; } const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, _nbitLength); if (BYTES > 2048) throw new Error("invalid field: expected ORDER of <= 2048 bytes"); let sqrtP; const f = Object.freeze({ ORDER, isLE, BITS, BYTES, MASK: bitMask(BITS), ZERO: _0n, ONE: _1n, create: (num2) => mod(num2, ORDER), isValid: (num2) => { if (typeof num2 !== "bigint") throw new Error("invalid field element: expected bigint, got " + typeof num2); return _0n <= num2 && num2 < ORDER; }, is0: (num2) => num2 === _0n, // is valid and invertible isValidNot0: (num2) => !f.is0(num2) && f.isValid(num2), isOdd: (num2) => (num2 & _1n) === _1n, neg: (num2) => mod(-num2, ORDER), eql: (lhs, rhs) => lhs === rhs, sqr: (num2) => mod(num2 * num2, ORDER), add: (lhs, rhs) => mod(lhs + rhs, ORDER), sub: (lhs, rhs) => mod(lhs - rhs, ORDER), mul: (lhs, rhs) => mod(lhs * rhs, ORDER), pow: (num2, power) => FpPow(f, num2, power), div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER), // Same as above, but doesn't normalize sqrN: (num2) => num2 * num2, addN: (lhs, rhs) => lhs + rhs, subN: (lhs, rhs) => lhs - rhs, mulN: (lhs, rhs) => lhs * rhs, inv: (num2) => invert(num2, ORDER), sqrt: _sqrt || ((n) => { if (!sqrtP) sqrtP = FpSqrt(ORDER); return sqrtP(f, n); }), toBytes: (num2) => isLE ? numberToBytesLE(num2, BYTES) : numberToBytesBE(num2, BYTES), fromBytes: (bytes) => { if (bytes.length !== BYTES) throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length); return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes); }, // TODO: we don't need it here, move out to separate fn invertBatch: (lst) => FpInvertBatch(f, lst), // We can't move this out because Fp6, Fp12 implement it // and it's unclear what to return in there. cmov: (a, b, c) => c ? b : a }); return Object.freeze(f); } function getFieldBytesLength(fieldOrder) { if (typeof fieldOrder !== "bigint") throw new Error("field order must be bigint"); const bitLength = fieldOrder.toString(2).length; return Math.ceil(bitLength / 8); } function getMinHashLength(fieldOrder) { const length = getFieldBytesLength(fieldOrder); return length + Math.ceil(length / 2); } function mapHashToField(key, fieldOrder, isLE = false) { const len = key.length; const fieldLen = getFieldBytesLength(fieldOrder); const minLen = getMinHashLength(fieldOrder); if (len < 16 || len < minLen || len > 1024) throw new Error("expected " + minLen + "-1024 bytes of input, got " + len); const num2 = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key); const reduced = mod(num2, fieldOrder - _1n) + _1n; return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen); } // node_modules/@noble/curves/esm/abstract/curve.js var _0n2 = BigInt(0); var _1n2 = BigInt(1); function negateCt(condition, item) { const neg = item.negate(); return condition ? neg : item; } function normalizeZ(c, property, points) { const getz = property === "pz" ? (p) => p.pz : (p) => p.ez; const toInv = FpInvertBatch(c.Fp, points.map(getz)); const affined = points.map((p, i) => p.toAffine(toInv[i])); return affined.map(c.fromAffine); } function validateW(W, bits) { if (!Number.isSafeInteger(W) || W <= 0 || W > bits) throw new Error("invalid window size, expected [1.." + bits + "], got W=" + W); } function calcWOpts(W, scalarBits) { validateW(W, scalarBits); const windows = Math.ceil(scalarBits / W) + 1; const windowSize = 2 ** (W - 1); const maxNumber = 2 ** W; const mask = bitMask(W); const shiftBy = BigInt(W); return { windows, windowSize, mask, maxNumber, shiftBy }; } function calcOffsets(n, window, wOpts) { const { windowSize, mask, maxNumber, shiftBy } = wOpts; let wbits = Number(n & mask); let nextN = n >> shiftBy; if (wbits > windowSize) { wbits -= maxNumber; nextN += _1n2; } const offsetStart = window * windowSize; const offset = offsetStart + Math.abs(wbits) - 1; const isZero = wbits === 0; const isNeg = wbits < 0; const isNegF = window % 2 !== 0; const offsetF = offsetStart; return { nextN, offset, isZero, isNeg, isNegF, offsetF }; } function validateMSMPoints(points, c) { if (!Array.isArray(points)) throw new Error("array expected"); points.forEach((p, i) => { if (!(p instanceof c)) throw new Error("invalid point at index " + i); }); } function validateMSMScalars(scalars, field) { if (!Array.isArray(scalars)) throw new Error("array of scalars expected"); scalars.forEach((s, i) => { if (!field.isValid(s)) throw new Error("invalid scalar at index " + i); }); } var pointPrecomputes = /* @__PURE__ */ new WeakMap(); var pointWindowSizes = /* @__PURE__ */ new WeakMap(); function getW(P) { return pointWindowSizes.get(P) || 1; } function assert0(n) { if (n !== _0n2) throw new Error("invalid wNAF"); } function wNAF(c, bits) { return { constTimeNegate: negateCt, hasPrecomputes(elm) { return getW(elm) !== 1; }, // non-const time multiplication ladder unsafeLadder(elm, n, p = c.ZERO) { let d = elm; while (n > _0n2) { if (n & _1n2) p = p.add(d); d = d.double(); n >>= _1n2; } return p; }, /** * Creates a wNAF precomputation window. Used for caching. * Default window size is set by `utils.precompute()` and is equal to 8. * Number of precomputed points depends on the curve size: * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where: * - 𝑊 is the window size * - 𝑛 is the bitlength of the curve order. * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224. * @param elm Point instance * @param W window size * @returns precomputed point tables flattened to a single array */ precomputeWindow(elm, W) { const { windows, windowSize } = calcWOpts(W, bits); const points = []; let p = elm; let base = p; for (let window = 0; window < windows; window++) { base = p; points.push(base); for (let i = 1; i < windowSize; i++) { base = base.add(p); points.push(base); } p = base.double(); } return points; }, /** * Implements ec multiplication using precomputed tables and w-ary non-adjacent form. * @param W window size * @param precomputes precomputed tables * @param n scalar (we don't check here, but should be less than curve order) * @returns real and fake (for const-time) points */ wNAF(W, precomputes, n) { let p = c.ZERO; let f = c.BASE; const wo = calcWOpts(W, bits); for (let window = 0; window < wo.windows; window++) { const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo); n = nextN; if (isZero) { f = f.add(negateCt(isNegF, precomputes[offsetF])); } else { p = p.add(negateCt(isNeg, precomputes[offset])); } } assert0(n); return { p, f }; }, /** * Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form. * @param W window size * @param precomputes precomputed tables * @param n scalar (we don't check here, but should be less than curve order) * @param acc accumulator point to add result of multiplication * @returns point */ wNAFUnsafe(W, precomputes, n, acc = c.ZERO) { const wo = calcWOpts(W, bits); for (let window = 0; window < wo.windows; window++) { if (n === _0n2) break; const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo); n = nextN; if (isZero) { continue; } else { const item = precomputes[offset]; acc = acc.add(isNeg ? item.negate() : item); } } assert0(n); return acc; }, getPrecomputes(W, P, transform) { let comp = pointPrecomputes.get(P); if (!comp) { comp = this.precomputeWindow(P, W); if (W !== 1) { if (typeof transform === "function") comp = transform(comp); pointPrecomputes.set(P, comp); } } return comp; }, wNAFCached(P, n, transform) { const W = getW(P); return this.wNAF(W, this.getPrecomputes(W, P, transform), n); }, wNAFCachedUnsafe(P, n, transform, prev) { const W = getW(P); if (W === 1) return this.unsafeLadder(P, n, prev); return this.wNAFUnsafe(W, this.getPrecomputes(W, P, transform), n, prev); }, // We calculate precomputes for elliptic curve point multiplication // using windowed method. This specifies window size and // stores precomputed values. Usually only base point would be precomputed. setWindowSize(P, W) { validateW(W, bits); pointWindowSizes.set(P, W); pointPrecomputes.delete(P); } }; } function mulEndoUnsafe(c, point, k1, k2) { let acc = point; let p1 = c.ZERO; let p2 = c.ZERO; while (k1 > _0n2 || k2 > _0n2) { if (k1 & _1n2) p1 = p1.add(acc); if (k2 & _1n2) p2 = p2.add(acc); acc = acc.double(); k1 >>= _1n2; k2 >>= _1n2; } return { p1, p2 }; } function pippenger(c, fieldN, points, scalars) { validateMSMPoints(points, c); validateMSMScalars(scalars, fieldN); const plength = points.length; const slength = scalars.length; if (plength !== slength) throw new Error("arrays of points and scalars must have equal length"); const zero = c.ZERO; const wbits = bitLen(BigInt(plength)); let windowSize = 1; if (wbits > 12) windowSize = wbits - 3; else if (wbits > 4) windowSize = wbits - 2; else if (wbits > 0) windowSize = 2; const MASK = bitMask(windowSize); const buckets = new Array(Number(MASK) + 1).fill(zero); const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize; let sum = zero; for (let i = lastBits; i >= 0; i -= windowSize) { buckets.fill(zero); for (let j = 0; j < slength; j++) { const scalar = scalars[j]; const wbits2 = Number(scalar >> BigInt(i) & MASK); buckets[wbits2] = buckets[wbits2].add(points[j]); } let resI = zero; for (let j = buckets.length - 1, sumI = zero; j > 0; j--) { sumI = sumI.add(buckets[j]); resI = resI.add(sumI); } sum = sum.add(resI); if (i !== 0) for (let j = 0; j < windowSize; j++) sum = sum.double(); } return sum; } function createField(order, field) { if (field) { if (field.ORDER !== order) throw new Error("Field.ORDER must match order: Fp == p, Fn == n"); validateField(field); return field; } else { return Field(order); } } function _createCurveFields(type, CURVE, curveOpts = {}) { if (!CURVE || typeof CURVE !== "object") throw new Error(`expected valid ${type} CURVE object`); for (const p of ["p", "n", "h"]) { const val = CURVE[p]; if (!(typeof val === "bigint" && val > _0n2)) throw new Error(`CURVE.${p} must be positive bigint`); } const Fp = createField(CURVE.p, curveOpts.Fp); const Fn = createField(CURVE.n, curveOpts.Fn); const _b = type === "weierstrass" ? "b" : "d"; const params = ["Gx", "Gy", "a", _b]; for (const p of params) { if (!Fp.isValid(CURVE[p])) throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`); } return { Fp, Fn }; } // node_modules/@noble/curves/esm/abstract/weierstrass.js function validateSigVerOpts(opts) { if (opts.lowS !== void 0) abool("lowS", opts.lowS); if (opts.prehash !== void 0) abool("prehash", opts.prehash); } var DERErr = class extends Error { constructor(m = "") { super(m); } }; var DER = { // asn.1 DER encoding utils Err: DERErr, // Basic building block is TLV (Tag-Length-Value) _tlv: { encode: (tag, data) => { const { Err: E } = DER; if (tag < 0 || tag > 256) throw new E("tlv.encode: wrong tag"); if (data.length & 1) throw new E("tlv.encode: unpadded data"); const dataLen = data.length / 2; const len = numberToHexUnpadded(dataLen); if (len.length / 2 & 128) throw new E("tlv.encode: long form length too big"); const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : ""; const t = numberToHexUnpadded(tag); return t + lenLen + len + data; }, // v - value, l - left bytes (unparsed) decode(tag, data) { const { Err: E } = DER; let pos = 0; if (tag < 0 || tag > 256) throw new E("tlv.encode: wrong tag"); if (data.length < 2 || data[pos++] !== tag) throw new E("tlv.decode: wrong tlv"); const first = data[pos++]; const isLong = !!(first & 128); let length = 0; if (!isLong) length = first; else { const lenLen = first & 127; if (!lenLen) throw new E("tlv.decode(long): indefinite length not supported"); if (lenLen > 4) throw new E("tlv.decode(long): byte length is too big"); const lengthBytes = data.subarray(pos, pos + lenLen); if (lengthBytes.length !== lenLen) throw new E("tlv.decode: length bytes not complete"); if (lengthBytes[0] === 0) throw new E("tlv.decode(long): zero leftmost byte"); for (const b of lengthBytes) length = length << 8 | b; pos += lenLen; if (length < 128) throw new E("tlv.decode(long): not minimal encoding"); } const v = data.subarray(pos, pos + length); if (v.length !== length) throw new E("tlv.decode: wrong value length"); return { v, l: data.subarray(pos + length) }; } }, // https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag, // since we always use positive integers here. It must always be empty: // - add zero byte if exists // - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding) _int: { encode(num2) { const { Err: E } = DER; if (num2 < _0n3) throw new E("integer: negative integers are not allowed"); let hex = numberToHexUnpadded(num2); if (Number.parseInt(hex[0], 16) & 8) hex = "00" + hex; if (hex.length & 1) throw new E("unexpected DER parsing assertion: unpadded hex"); return hex; }, decode(data) { const { Err: E } = DER; if (data[0] & 128) throw new E("invalid signature integer: negative"); if (data[0] === 0 && !(data[1] & 128)) throw new E("invalid signature integer: unnecessary leading zero"); return bytesToNumberBE(data); } }, toSig(hex) { const { Err: E, _int: int, _tlv: tlv } = DER; const data = ensureBytes("signature", hex); const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data); if (seqLeftBytes.length) throw new E("invalid signature: left bytes after parsing"); const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes); const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes); if (sLeftBytes.length) throw new E("invalid signature: left bytes after parsing"); return { r: int.decode(rBytes), s: int.decode(sBytes) }; }, hexFromSig(sig) { const { _tlv: tlv, _int: int } = DER; const rs = tlv.encode(2, int.encode(sig.r)); const ss = tlv.encode(2, int.encode(sig.s)); const seq = rs + ss; return tlv.encode(48, seq); } }; var _0n3 = BigInt(0); var _1n3 = BigInt(1); var _2n2 = BigInt(2); var _3n2 = BigInt(3); var _4n2 = BigInt(4); function _legacyHelperEquat(Fp, a, b) { function weierstrassEquation(x) { const x2 = Fp.sqr(x); const x3 = Fp.mul(x2, x); return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); } return weierstrassEquation; } function _legacyHelperNormPriv(Fn, allowedPrivateKeyLengths, wrapPrivateKey) { const { BYTES: expected } = Fn; function normPrivateKeyToScalar(key) { let num2; if (typeof key === "bigint") { num2 = key; } else { let bytes = ensureBytes("private key", key); if (allowedPrivateKeyLengths) { if (!allowedPrivateKeyLengths.includes(bytes.length * 2)) throw new Error("invalid private key"); const padded = new Uint8Array(expected); padded.set(bytes, padded.length - bytes.length); bytes = padded; } try { num2 = Fn.fromBytes(bytes); } catch (error) { throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`); } } if (wrapPrivateKey) num2 = Fn.create(num2); if (!Fn.isValidNot0(num2)) throw new Error("invalid private key: out of range [1..N-1]"); return num2; } return normPrivateKeyToScalar; } function weierstrassN(CURVE, curveOpts = {}) { const { Fp, Fn } = _createCurveFields("weierstrass", CURVE, curveOpts); const { h: cofactor, n: CURVE_ORDER } = CURVE; _validateObject(curveOpts, {}, { allowInfinityPoint: "boolean", clearCofactor: "function", isTorsionFree: "function", fromBytes: "function", toBytes: "function", endo: "object", wrapPrivateKey: "boolean" }); const { endo } = curveOpts; if (endo) { if (!Fp.is0(CURVE.a) || typeof endo.beta !== "bigint" || typeof endo.splitScalar !== "function") { throw new Error('invalid endo: expected "beta": bigint and "splitScalar": function'); } } function assertCompressionIsSupported() { if (!Fp.isOdd) throw new Error("compression is not supported: Field does not have .isOdd()"); } function pointToBytes2(_c, point, isCompressed) { const { x, y } = point.toAffine(); const bx = Fp.toBytes(x); abool("isCompressed", isCompressed); if (isCompressed) { assertCompressionIsSupported(); const hasEvenY = !Fp.isOdd(y); return concatBytes(pprefix(hasEvenY), bx); } else { return concatBytes(Uint8Array.of(4), bx, Fp.toBytes(y)); } } function pointFromBytes(bytes) { abytes(bytes); const L = Fp.BYTES; const LC = L + 1; const LU = 2 * L + 1; const length = bytes.length; const head = bytes[0]; const tail = bytes.subarray(1); if (length === LC && (head === 2 || head === 3)) { const x = Fp.fromBytes(tail); if (!Fp.isValid(x)) throw new Error("bad point: is not on curve, wrong x"); const y2 = weierstrassEquation(x); let y; try { y = Fp.sqrt(y2); } catch (sqrtError) { const err = sqrtError instanceof Error ? ": " + sqrtError.message : ""; throw new Error("bad point: is not on curve, sqrt error" + err); } assertCompressionIsSupported(); const isYOdd = Fp.isOdd(y); const isHeadOdd = (head & 1) === 1; if (isHeadOdd !== isYOdd) y = Fp.neg(y); return { x, y }; } else if (length === LU && head === 4) { const x = Fp.fromBytes(tail.subarray(L * 0, L * 1)); const y = Fp.fromBytes(tail.subarray(L * 1, L * 2)); if (!isValidXY(x, y)) throw new Error("bad point: is not on curve"); return { x, y }; } else { throw new Error(`bad point: got length ${length}, expected compressed=${LC} or uncompressed=${LU}`); } } const toBytes2 = curveOpts.toBytes || pointToBytes2; const fromBytes = curveOpts.fromBytes || pointFromBytes; const weierstrassEquation = _legacyHelperEquat(Fp, CURVE.a, CURVE.b); function isValidXY(x, y) { const left = Fp.sqr(y); const right = weierstrassEquation(x); return Fp.eql(left, right); } if (!isValidXY(CURVE.Gx, CURVE.Gy)) throw new Error("bad curve params: generator point"); const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n2), _4n2); const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27)); if (Fp.is0(Fp.add(_4a3, _27b2))) throw new Error("bad curve params: a or b"); function acoord(title, n, banZero = false) { if (!Fp.isValid(n) || banZero && Fp.is0(n)) throw new Error(`bad point coordinate ${title}`); return n; } function aprjpoint(other) { if (!(other instanceof Point2)) throw new Error("ProjectivePoint expected"); } const toAffineMemo = memoized((p, iz) => { const { px: x, py: y, pz: z } = p; if (Fp.eql(z, Fp.ONE)) return { x, y }; const is0 = p.is0(); if (iz == null) iz = is0 ? Fp.ONE : Fp.inv(z); const ax = Fp.mul(x, iz); const ay = Fp.mul(y, iz); const zz = Fp.mul(z, iz); if (is0) return { x: Fp.ZERO, y: Fp.ZERO }; if (!Fp.eql(zz, Fp.ONE)) throw new Error("invZ was invalid"); return { x: ax, y: ay }; }); const assertValidMemo = memoized((p) => { if (p.is0()) { if (curveOpts.allowInfinityPoint && !Fp.is0(p.py)) return; throw new Error("bad point: ZERO"); } const { x, y } = p.toAffine(); if (!Fp.isValid(x) || !Fp.isValid(y)) throw new Error("bad point: x or y not field elements"); if (!isValidXY(x, y)) throw new Error("bad point: equation left != right"); if (!p.isTorsionFree()) throw new Error("bad point: not in prime-order subgroup"); return true; }); function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) { k2p = new Point2(Fp.mul(k2p.px, endoBeta), k2p.py, k2p.pz); k1p = negateCt(k1neg, k1p); k2p = negateCt(k2neg, k2p); return k1p.add(k2p); } class Point2 { /** Does NOT validate if the point is valid. Use `.assertValidity()`. */ constructor(px, py, pz) { this.px = acoord("x", px); this.py = acoord("y", py, true); this.pz = acoord("z", pz); Object.freeze(this); } /** Does NOT validate if the point is valid. Use `.assertValidity()`. */ static fromAffine(p) { const { x, y } = p || {}; if (!p || !Fp.isValid(x) || !Fp.isValid(y)) throw new Error("invalid affine point"); if (p instanceof Point2) throw new Error("projective point not allowed"); if (Fp.is0(x) && Fp.is0(y)) return Point2.ZERO; return new Point2(x, y, Fp.ONE); } get x() { return this.toAffine().x; } get y() { return this.toAffine().y; } static normalizeZ(points) { return normalizeZ(Point2, "pz", points); } static fromBytes(bytes) { abytes(bytes); return Point2.fromHex(bytes); } /** Converts hash string or Uint8Array to Point. */ static fromHex(hex) { const P = Point2.fromAffine(fromBytes(ensureBytes("pointHex", hex))); P.assertValidity(); return P; } /** Multiplies generator point by privateKey. */ static fromPrivateKey(privateKey) { const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey); return Point2.BASE.multiply(normPrivateKeyToScalar(privateKey)); } /** Multiscalar Multiplication */ static msm(points, scalars) { return pippenger(Point2, Fn, points, scalars); } /** * * @param windowSize * @param isLazy true will defer table computation until the first multiplication * @returns */ precompute(windowSize = 8, isLazy = true) { wnaf.setWindowSize(this, windowSize); if (!isLazy) this.multiply(_3n2); return this; } /** "Private method", don't use it directly */ _setWindowSize(windowSize) { this.precompute(windowSize); } // TODO: return `this` /** A point on curve is valid if it conforms to equation. */ assertValidity() { assertValidMemo(this); } hasEvenY() { const { y } = this.toAffine(); if (!Fp.isOdd) throw new Error("Field doesn't support isOdd"); return !Fp.isOdd(y); } /** Compare one point to another. */ equals(other) { aprjpoint(other); const { px: X1, py: Y1, pz: Z1 } = this; const { px: X2, py: Y2, pz: Z2 } = other; const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1)); const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1)); return U1 && U2; } /** Flips point to one corresponding to (x, -y) in Affine coordinates. */ negate() { return new Point2(this.px, Fp.neg(this.py), this.pz); } // Renes-Costello-Batina exception-free doubling formula. // There is 30% faster Jacobian formula, but it is not complete. // https://eprint.iacr.org/2015/1060, algorithm 3 // Cost: 8M + 3S + 3*a + 2*b3 + 15add. double() { const { a, b } = CURVE; const b3 = Fp.mul(b, _3n2); const { px: X1, py: Y1, pz: Z1 } = this; let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; let t0 = Fp.mul(X1, X1); let t1 = Fp.mul(Y1, Y1); let t2 = Fp.mul(Z1, Z1); let t3 = Fp.mul(X1, Y1); t3 = Fp.add(t3, t3); Z3 = Fp.mul(X1, Z1); Z3 = Fp.add(Z3, Z3); X3 = Fp.mul(a, Z3); Y3 = Fp.mul(b3, t2); Y3 = Fp.add(X3, Y3); X3 = Fp.sub(t1, Y3); Y3 = Fp.add(t1, Y3); Y3 = Fp.mul(X3, Y3); X3 = Fp.mul(t3, X3); Z3 = Fp.mul(b3, Z3); t2 = Fp.mul(a, t2); t3 = Fp.sub(t0, t2); t3 = Fp.mul(a, t3); t3 = Fp.add(t3, Z3); Z3 = Fp.add(t0, t0); t0 = Fp.add(Z3, t0); t0 = Fp.add(t0, t2); t0 = Fp.mul(t0, t3); Y3 = Fp.add(Y3, t0); t2 = Fp.mul(Y1, Z1); t2 = Fp.add(t2, t2); t0 = Fp.mul(t2, t3); X3 = Fp.sub(X3, t0); Z3 = Fp.mul(t2, t1); Z3 = Fp.add(Z3, Z3); Z3 = Fp.add(Z3, Z3); return new Point2(X3, Y3, Z3); } // Renes-Costello-Batina exception-free addition formula. // There is 30% faster Jacobian formula, but it is not complete. // https://eprint.iacr.org/2015/1060, algorithm 1 // Cost: 12M + 0S + 3*a + 3*b3 + 23add. add(other) { aprjpoint(other); const { px: X1, py: Y1, pz: Z1 } = this; const { px: X2, py: Y2, pz: Z2 } = other; let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; const a = CURVE.a; const b3 = Fp.mul(CURVE.b, _3n2); let t0 = Fp.mul(X1, X2); let t1 = Fp.mul(Y1, Y2); let t2 = Fp.mul(Z1, Z2); let t3 = Fp.add(X1, Y1); let t4 = Fp.add(X2, Y2); t3 = Fp.mul(t3, t4); t4 = Fp.add(t0, t1); t3 = Fp.sub(t3, t4); t4 = Fp.add(X1, Z1); let t5 = Fp.add(X2, Z2); t4 = Fp.mul(t4, t5); t5 = Fp.add(t0, t2); t4 = Fp.sub(t4, t5); t5 = Fp.add(Y1, Z1); X3 = Fp.add(Y2, Z2); t5 = Fp.mul(t5, X3); X3 = Fp.add(t1, t2); t5 = Fp.sub(t5, X3); Z3 = Fp.mul(a, t4); X3 = Fp.mul(b3, t2); Z3 = Fp.add(X3, Z3); X3 = Fp.sub(t1, Z3); Z3 = Fp.add(t1, Z3); Y3 = Fp.mul(X3, Z3); t1 = Fp.add(t0, t0); t1 = Fp.add(t1, t0); t2 = Fp.mul(a, t2); t4 = Fp.mul(b3, t4); t1 = Fp.add(t1, t2); t2 = Fp.sub(t0, t2); t2 = Fp.mul(a, t2); t4 = Fp.add(t4, t2); t0 = Fp.mul(t1, t4); Y3 = Fp.add(Y3, t0); t0 = Fp.mul(t5, t4); X3 = Fp.mul(t3, X3); X3 = Fp.sub(X3, t0); t0 = Fp.mul(t3, t1); Z3 = Fp.mul(t5, Z3); Z3 = Fp.add(Z3, t0); return new Point2(X3, Y3, Z3); } subtract(other) { return this.add(other.negate()); } is0() { return this.equals(Point2.ZERO); } /** * Constant time multiplication. * Uses wNAF method. Windowed method may be 10% faster, * but takes 2x longer to generate and consumes 2x memory. * Uses precomputes when available. * Uses endomorphism for Koblitz curves. * @param scalar by which the point would be multiplied * @returns New point */ multiply(scalar) { const { endo: endo2 } = curveOpts; if (!Fn.isValidNot0(scalar)) throw new Error("invalid scalar: out of range"); let point, fake; const mul = (n) => wnaf.wNAFCached(this, n, Point2.normalizeZ); if (endo2) { const { k1neg, k1, k2neg, k2 } = endo2.splitScalar(scalar); const { p: k1p, f: k1f } = mul(k1); const { p: k2p, f: k2f } = mul(k2); fake = k1f.add(k2f); point = finishEndo(endo2.beta, k1p, k2p, k1neg, k2neg); } else { const { p, f } = mul(scalar); point = p; fake = f; } return Point2.normalizeZ([point, fake])[0]; } /** * Non-constant-time multiplication. Uses double-and-add algorithm. * It's faster, but should only be used when you don't care about * an exposed private key e.g. sig verification, which works over *public* keys. */ multiplyUnsafe(sc) { const { endo: endo2 } = curveOpts; const p = this; if (!Fn.isValid(sc)) throw new Error("invalid scalar: out of range"); if (sc === _0n3 || p.is0()) return Point2.ZERO; if (sc === _1n3) return p; if (wnaf.hasPrecomputes(this)) return this.multiply(sc); if (endo2) { const { k1neg, k1, k2neg, k2 } = endo2.splitScalar(sc); const { p1, p2 } = mulEndoUnsafe(Point2, p, k1, k2); return finishEndo(endo2.beta, p1, p2, k1neg, k2neg); } else { return wnaf.wNAFCachedUnsafe(p, sc); } } multiplyAndAddUnsafe(Q, a, b) { const sum = this.multiplyUnsafe(a).add(Q.multiplyUnsafe(b)); return sum.is0() ? void 0 : sum; } /** * Converts Projective point to affine (x, y) coordinates. * @param invertedZ Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch */ toAffine(invertedZ) { return toAffineMemo(this, invertedZ); } /** * Checks whether Point is free of torsion elements (is in prime subgroup). * Always torsion-free for cofactor=1 curves. */ isTorsionFree() { const { isTorsionFree } = curveOpts; if (cofactor === _1n3) return true; if (isTorsionFree) return isTorsionFree(Point2, this); return wnaf.wNAFCachedUnsafe(this, CURVE_ORDER).is0(); } clearCofactor() { const { clearCofactor } = curveOpts; if (cofactor === _1n3) return this; if (clearCofactor) return clearCofactor(Point2, this); return this.multiplyUnsafe(cofactor); } toBytes(isCompressed = true) { abool("isCompressed", isCompressed); this.assertValidity(); return toBytes2(Point2, this, isCompressed); } /** @deprecated use `toBytes` */ toRawBytes(isCompressed = true) { return this.toBytes(isCompressed); } toHex(isCompressed = true) { return bytesToHex(this.toBytes(isCompressed)); } toString() { return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`; } } Point2.BASE = new Point2(CURVE.Gx, CURVE.Gy, Fp.ONE); Point2.ZERO = new Point2(Fp.ZERO, Fp.ONE, Fp.ZERO); Point2.Fp = Fp; Point2.Fn = Fn; const bits = Fn.BITS; const wnaf = wNAF(Point2, curveOpts.endo ? Math.ceil(bits / 2) : bits); return Point2; } function pprefix(hasEvenY) { return Uint8Array.of(hasEvenY ? 2 : 3); } function ecdsa(Point2, ecdsaOpts, curveOpts = {}) { _validateObject(ecdsaOpts, { hash: "function" }, { hmac: "function", lowS: "boolean", randomBytes: "function", bits2int: "function", bits2int_modN: "function" }); const randomBytes_ = ecdsaOpts.randomBytes || randomBytes; const hmac_ = ecdsaOpts.hmac || ((key, ...msgs) => hmac(ecdsaOpts.hash, key, concatBytes(...msgs))); const { Fp, Fn } = Point2; const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn; function isBiggerThanHalfOrder(number) { const HALF = CURVE_ORDER >> _1n3; return number > HALF; } function normalizeS(s) { return isBiggerThanHalfOrder(s) ? Fn.neg(s) : s; } function aValidRS(title, num2) { if (!Fn.isValidNot0(num2)) throw new Error(`invalid signature ${title}: out of range 1..CURVE.n`); } class Signature { constructor(r, s, recovery) { aValidRS("r", r); aValidRS("s", s); this.r = r; this.s = s; if (recovery != null) this.recovery = recovery; Object.freeze(this); } // pair (bytes of r, bytes of s) static fromCompact(hex) { const L = Fn.BYTES; const b = ensureBytes("compactSignature", hex, L * 2); return new Signature(Fn.fromBytes(b.subarray(0, L)), Fn.fromBytes(b.subarray(L, L * 2))); } // DER encoded ECDSA signature // https://bitcoin.stackexchange.com/questions/57644/what-are-the-parts-of-a-bitcoin-transaction-input-script static fromDER(hex) { const { r, s } = DER.toSig(ensureBytes("DER", hex)); return new Signature(r, s); } /** * @todo remove * @deprecated */ assertValidity() { } addRecoveryBit(recovery) { return new Signature(this.r, this.s, recovery); } // ProjPointType<bigint> recoverPublicKey(msgHash) { const FIELD_ORDER = Fp.ORDER; const { r, s, recovery: rec } = this; if (rec == null || ![0, 1, 2, 3].includes(rec)) throw new Error("recovery id invalid"); const hasCofactor = CURVE_ORDER * _2n2 < FIELD_ORDER; if (hasCofactor && rec > 1) throw new Error("recovery id is ambiguous for h>1 curve"); const radj = rec === 2 || rec === 3 ? r + CURVE_ORDER : r; if (!Fp.isValid(radj)) throw new Error("recovery id 2 or 3 invalid"); const x = Fp.toBytes(radj); const R = Point2.fromHex(concatBytes(pprefix((rec & 1) === 0), x)); const ir = Fn.inv(radj); const h = bits2int_modN(ensureBytes("msgHash", msgHash)); const u1 = Fn.create(-h * ir); const u2 = Fn.create(s * ir); const Q = Point2.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2)); if (Q.is0()) throw new Error("point at infinify"); Q.assertValidity(); return Q; } // Signatures should be low-s, to prevent malleability. hasHighS() { return isBiggerThanHalfOrder(this.s); } normalizeS() { return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this; } toBytes(format) { if (format === "compact") return concatBytes(Fn.toBytes(this.r), Fn.toBytes(this.s)); if (format === "der") return hexToBytes(DER.hexFromSig(this)); throw new Error("invalid format"); } // DER-encoded toDERRawBytes() { return this.toBytes("der"); } toDERHex() { return bytesToHex(this.toBytes("der")); } // padded bytes of r, then padded bytes of s toCompactRawBytes() { return this.toBytes("compact"); } toCompactHex() { return bytesToHex(this.toBytes("compact")); } } const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey); const utils = { isValidPrivateKey(privateKey) { try { normPrivateKeyToScalar(privateKey); return true; } catch (error) { return false; } }, normPrivateKeyToScalar, /** * Produces cryptographically secure private key from random of size * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible. */ randomPrivateKey: () => { const n = CURVE_ORDER; return mapHashToField(randomBytes_(getMinHashLength(n)), n); }, precompute(windowSize = 8, point = Point2.BASE) { return point.precompute(windowSize, false); } }; function getPu