UNPKG

xrpl

Version:

A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser

1,160 lines (1,137 loc) 1.21 MB
var xrpl; /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ "../../node_modules/@noble/curves/_shortw_utils.js": /*!*********************************************************!*\ !*** ../../node_modules/@noble/curves/_shortw_utils.js ***! \*********************************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getHash = getHash; exports.createCurve = createCurve; /** * Utilities for short weierstrass curves, combined with noble-hashes. * @module */ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ const hmac_1 = __webpack_require__(/*! @noble/hashes/hmac */ "../../node_modules/@noble/curves/node_modules/@noble/hashes/hmac.js"); const utils_1 = __webpack_require__(/*! @noble/hashes/utils */ "../../node_modules/@noble/curves/node_modules/@noble/hashes/utils.js"); const weierstrass_js_1 = __webpack_require__(/*! ./abstract/weierstrass.js */ "../../node_modules/@noble/curves/abstract/weierstrass.js"); /** connects noble-curves to noble-hashes */ function getHash(hash) { return { hash, hmac: (key, ...msgs) => (0, hmac_1.hmac)(hash, key, (0, utils_1.concatBytes)(...msgs)), randomBytes: utils_1.randomBytes, }; } function createCurve(curveDef, defHash) { const create = (hash) => (0, weierstrass_js_1.weierstrass)({ ...curveDef, ...getHash(hash) }); return { ...create(defHash), create }; } /***/ }), /***/ "../../node_modules/@noble/curves/abstract/curve.js": /*!**********************************************************!*\ !*** ../../node_modules/@noble/curves/abstract/curve.js ***! \**********************************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.wNAF = wNAF; exports.pippenger = pippenger; exports.precomputeMSMUnsafe = precomputeMSMUnsafe; exports.validateBasic = validateBasic; /** * Methods for elliptic curve multiplication by scalars. * Contains wNAF, pippenger * @module */ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ const modular_js_1 = __webpack_require__(/*! ./modular.js */ "../../node_modules/@noble/curves/abstract/modular.js"); const utils_js_1 = __webpack_require__(/*! ./utils.js */ "../../node_modules/@noble/curves/abstract/utils.js"); const _0n = BigInt(0); const _1n = BigInt(1); function constTimeNegate(condition, item) { const neg = item.negate(); return condition ? neg : item; } 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, bits) { validateW(W, bits); const windows = Math.ceil(bits / W) + 1; // +1, because const windowSize = 2 ** (W - 1); // -1 because we skip zero return { windows, windowSize }; } 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); }); } // Since points in different groups cannot be equal (different object constructor), // we can have single place to store precomputes const pointPrecomputes = new WeakMap(); const pointWindowSizes = new WeakMap(); // This allows use make points immutable (nothing changes inside) function getW(P) { return pointWindowSizes.get(P) || 1; } /** * Elliptic curve multiplication of Point by scalar. Fragile. * Scalars should always be less than curve order: this should be checked inside of a curve itself. * Creates precomputation tables for fast multiplication: * - private scalar is split by fixed size windows of W bits * - every window point is collected from window's table & added to accumulator * - since windows are different, same point inside tables won't be accessed more than once per calc * - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar) * - +1 window is neccessary for wNAF * - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication * * @todo Research returning 2d JS array of windows, instead of a single window. * This would allow windows to be in different memory locations */ function wNAF(c, bits) { return { constTimeNegate, hasPrecomputes(elm) { return getW(elm) !== 1; }, // non-const time multiplication ladder unsafeLadder(elm, n, p = c.ZERO) { let d = elm; while (n > _0n) { if (n & _1n) p = p.add(d); d = d.double(); n >>= _1n; } 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); // =1, because we skip zero 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) { // TODO: maybe check that scalar is less than group order? wNAF behavious is undefined otherwise // But need to carefully remove other checks before wNAF. ORDER == bits here const { windows, windowSize } = calcWOpts(W, bits); let p = c.ZERO; let f = c.BASE; const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc. const maxNumber = 2 ** W; const shiftBy = BigInt(W); for (let window = 0; window < windows; window++) { const offset = window * windowSize; // Extract W bits. let wbits = Number(n & mask); // Shift number by W bits. n >>= shiftBy; // If the bits are bigger than max size, we'll split those. // +224 => 256 - 32 if (wbits > windowSize) { wbits -= maxNumber; n += _1n; } // This code was first written with assumption that 'f' and 'p' will never be infinity point: // since each addition is multiplied by 2 ** W, it cannot cancel each other. However, // there is negate now: it is possible that negated element from low value // would be the same as high element, which will create carry into next window. // It's not obvious how this can fail, but still worth investigating later. // Check if we're onto Zero point. // Add random point inside current window to f. const offset1 = offset; const offset2 = offset + Math.abs(wbits) - 1; // -1 because we skip zero const cond1 = window % 2 !== 0; const cond2 = wbits < 0; if (wbits === 0) { // The most important part for const-time getPublicKey f = f.add(constTimeNegate(cond1, precomputes[offset1])); } else { p = p.add(constTimeNegate(cond2, precomputes[offset2])); } } // JIT-compiler should not eliminate f here, since it will later be used in normalizeZ() // Even if the variable is still unused, there are some checks which will // throw an exception, so compiler needs to prove they won't happen, which is hard. // At this point there is a way to F be infinity-point even if p is not, // which makes it less const-time: around 1 bigint multiply. 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 { windows, windowSize } = calcWOpts(W, bits); const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc. const maxNumber = 2 ** W; const shiftBy = BigInt(W); for (let window = 0; window < windows; window++) { const offset = window * windowSize; if (n === _0n) break; // No need to go over empty scalar // Extract W bits. let wbits = Number(n & mask); // Shift number by W bits. n >>= shiftBy; // If the bits are bigger than max size, we'll split those. // +224 => 256 - 32 if (wbits > windowSize) { wbits -= maxNumber; n += _1n; } if (wbits === 0) continue; let curr = precomputes[offset + Math.abs(wbits) - 1]; // -1 because we skip zero if (wbits < 0) curr = curr.negate(); // NOTE: by re-using acc, we can save a lot of additions in case of MSM acc = acc.add(curr); } return acc; }, getPrecomputes(W, P, transform) { // Calculate precomputes on a first run, reuse them after let comp = pointPrecomputes.get(P); if (!comp) { comp = this.precomputeWindow(P, W); if (W !== 1) pointPrecomputes.set(P, transform(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); // For W=1 ladder is ~x2 faster 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); }, }; } /** * Pippenger algorithm for multi-scalar multiplication (MSM, Pa + Qb + Rc + ...). * 30x faster vs naive addition on L=4096, 10x faster with precomputes. * For N=254bit, L=1, it does: 1024 ADD + 254 DBL. For L=5: 1536 ADD + 254 DBL. * Algorithmically constant-time (for same L), even when 1 point + scalar, or when scalar = 0. * @param c Curve Point constructor * @param fieldN field over CURVE.N - important that it's not over CURVE.P * @param points array of L curve points * @param scalars array of L scalars (aka private keys / bigints) */ function pippenger(c, fieldN, points, scalars) { // If we split scalars by some window (let's say 8 bits), every chunk will only // take 256 buckets even if there are 4096 scalars, also re-uses double. // TODO: // - https://eprint.iacr.org/2024/750.pdf // - https://tches.iacr.org/index.php/TCHES/article/view/10287 // 0 is accepted in scalars validateMSMPoints(points, c); validateMSMScalars(scalars, fieldN); if (points.length !== scalars.length) throw new Error('arrays of points and scalars must have equal length'); const zero = c.ZERO; const wbits = (0, utils_js_1.bitLen)(BigInt(points.length)); const windowSize = wbits > 12 ? wbits - 3 : wbits > 4 ? wbits - 2 : wbits ? 2 : 1; // in bits const MASK = (1 << windowSize) - 1; const buckets = new Array(MASK + 1).fill(zero); // +1 for zero array 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 < scalars.length; j++) { const scalar = scalars[j]; const wbits = Number((scalar >> BigInt(i)) & BigInt(MASK)); buckets[wbits] = buckets[wbits].add(points[j]); } let resI = zero; // not using this will do small speed-up, but will lose ct // Skip first bucket, because it is 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; } /** * Precomputed multi-scalar multiplication (MSM, Pa + Qb + Rc + ...). * @param c Curve Point constructor * @param fieldN field over CURVE.N - important that it's not over CURVE.P * @param points array of L curve points * @returns function which multiplies points with scaars */ function precomputeMSMUnsafe(c, fieldN, points, windowSize) { /** * Performance Analysis of Window-based Precomputation * * Base Case (256-bit scalar, 8-bit window): * - Standard precomputation requires: * - 31 additions per scalar × 256 scalars = 7,936 ops * - Plus 255 summary additions = 8,191 total ops * Note: Summary additions can be optimized via accumulator * * Chunked Precomputation Analysis: * - Using 32 chunks requires: * - 255 additions per chunk * - 256 doublings * - Total: (255 × 32) + 256 = 8,416 ops * * Memory Usage Comparison: * Window Size | Standard Points | Chunked Points * ------------|-----------------|--------------- * 4-bit | 520 | 15 * 8-bit | 4,224 | 255 * 10-bit | 13,824 | 1,023 * 16-bit | 557,056 | 65,535 * * Key Advantages: * 1. Enables larger window sizes due to reduced memory overhead * 2. More efficient for smaller scalar counts: * - 16 chunks: (16 × 255) + 256 = 4,336 ops * - ~2x faster than standard 8,191 ops * * Limitations: * - Not suitable for plain precomputes (requires 256 constant doublings) * - Performance degrades with larger scalar counts: * - Optimal for ~256 scalars * - Less efficient for 4096+ scalars (Pippenger preferred) */ validateW(windowSize, fieldN.BITS); validateMSMPoints(points, c); const zero = c.ZERO; const tableSize = 2 ** windowSize - 1; // table size (without zero) const chunks = Math.ceil(fieldN.BITS / windowSize); // chunks of item const MASK = BigInt((1 << windowSize) - 1); const tables = points.map((p) => { const res = []; for (let i = 0, acc = p; i < tableSize; i++) { res.push(acc); acc = acc.add(p); } return res; }); return (scalars) => { validateMSMScalars(scalars, fieldN); if (scalars.length > points.length) throw new Error('array of scalars must be smaller than array of points'); let res = zero; for (let i = 0; i < chunks; i++) { // No need to double if accumulator is still zero. if (res !== zero) for (let j = 0; j < windowSize; j++) res = res.double(); const shiftBy = BigInt(chunks * windowSize - (i + 1) * windowSize); for (let j = 0; j < scalars.length; j++) { const n = scalars[j]; const curr = Number((n >> shiftBy) & MASK); if (!curr) continue; // skip zero scalars chunks res = res.add(tables[j][curr - 1]); } } return res; }; } function validateBasic(curve) { (0, modular_js_1.validateField)(curve.Fp); (0, utils_js_1.validateObject)(curve, { n: 'bigint', h: 'bigint', Gx: 'field', Gy: 'field', }, { nBitLength: 'isSafeInteger', nByteLength: 'isSafeInteger', }); // Set defaults return Object.freeze({ ...(0, modular_js_1.nLength)(curve.n, curve.nBitLength), ...curve, ...{ p: curve.Fp.ORDER }, }); } /***/ }), /***/ "../../node_modules/@noble/curves/abstract/edwards.js": /*!************************************************************!*\ !*** ../../node_modules/@noble/curves/abstract/edwards.js ***! \************************************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.twistedEdwards = twistedEdwards; /** * Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y². * For design rationale of types / exports, see weierstrass module documentation. * @module */ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ const curve_js_1 = __webpack_require__(/*! ./curve.js */ "../../node_modules/@noble/curves/abstract/curve.js"); const modular_js_1 = __webpack_require__(/*! ./modular.js */ "../../node_modules/@noble/curves/abstract/modular.js"); const ut = __webpack_require__(/*! ./utils.js */ "../../node_modules/@noble/curves/abstract/utils.js"); const utils_js_1 = __webpack_require__(/*! ./utils.js */ "../../node_modules/@noble/curves/abstract/utils.js"); // Be friendly to bad ECMAScript parsers by not using bigint literals // prettier-ignore const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _8n = BigInt(8); // verification rule is either zip215 or rfc8032 / nist186-5. Consult fromHex: const VERIFY_DEFAULT = { zip215: true }; function validateOpts(curve) { const opts = (0, curve_js_1.validateBasic)(curve); ut.validateObject(curve, { hash: 'function', a: 'bigint', d: 'bigint', randomBytes: 'function', }, { adjustScalarBytes: 'function', domain: 'function', uvRatio: 'function', mapToCurve: 'function', }); // Set defaults return Object.freeze({ ...opts }); } /** * Creates Twisted Edwards curve with EdDSA signatures. * @example * import { Field } from '@noble/curves/abstract/modular'; * // Before that, define BigInt-s: a, d, p, n, Gx, Gy, h * const curve = twistedEdwards({ a, d, Fp: Field(p), n, Gx, Gy, h }) */ function twistedEdwards(curveDef) { const CURVE = validateOpts(curveDef); const { Fp, n: CURVE_ORDER, prehash: prehash, hash: cHash, randomBytes, nByteLength, h: cofactor, } = CURVE; // Important: // There are some places where Fp.BYTES is used instead of nByteLength. // So far, everything has been tested with curves of Fp.BYTES == nByteLength. // TODO: test and find curves which behave otherwise. const MASK = _2n << (BigInt(nByteLength * 8) - _1n); const modP = Fp.create; // Function overrides const Fn = (0, modular_js_1.Field)(CURVE.n, CURVE.nBitLength); // sqrt(u/v) const uvRatio = CURVE.uvRatio || ((u, v) => { try { return { isValid: true, value: Fp.sqrt(u * Fp.inv(v)) }; } catch (e) { return { isValid: false, value: _0n }; } }); const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes); // NOOP const domain = CURVE.domain || ((data, ctx, phflag) => { (0, utils_js_1.abool)('phflag', phflag); if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported'); return data; }); // NOOP // 0 <= n < MASK // Coordinates larger than Fp.ORDER are allowed for zip215 function aCoordinate(title, n) { ut.aInRange('coordinate ' + title, n, _0n, MASK); } function assertPoint(other) { if (!(other instanceof Point)) throw new Error('ExtendedPoint expected'); } // Converts Extended point to default (x, y) coordinates. // Can accept precomputed Z^-1 - for example, from invertBatch. const toAffineMemo = (0, utils_js_1.memoized)((p, iz) => { const { ex: x, ey: y, ez: z } = p; const is0 = p.is0(); if (iz == null) iz = is0 ? _8n : Fp.inv(z); // 8 was chosen arbitrarily const ax = modP(x * iz); const ay = modP(y * iz); const zz = modP(z * iz); if (is0) return { x: _0n, y: _1n }; if (zz !== _1n) throw new Error('invZ was invalid'); return { x: ax, y: ay }; }); const assertValidMemo = (0, utils_js_1.memoized)((p) => { const { a, d } = CURVE; if (p.is0()) throw new Error('bad point: ZERO'); // TODO: optimize, with vars below? // Equation in affine coordinates: ax² + y² = 1 + dx²y² // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y² const { ex: X, ey: Y, ez: Z, et: T } = p; const X2 = modP(X * X); // X² const Y2 = modP(Y * Y); // Y² const Z2 = modP(Z * Z); // Z² const Z4 = modP(Z2 * Z2); // Z⁴ const aX2 = modP(X2 * a); // aX² const left = modP(Z2 * modP(aX2 + Y2)); // (aX² + Y²)Z² const right = modP(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y² if (left !== right) throw new Error('bad point: equation left != right (1)'); // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T const XY = modP(X * Y); const ZT = modP(Z * T); if (XY !== ZT) throw new Error('bad point: equation left != right (2)'); return true; }); // Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy). // https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates class Point { constructor(ex, ey, ez, et) { this.ex = ex; this.ey = ey; this.ez = ez; this.et = et; aCoordinate('x', ex); aCoordinate('y', ey); aCoordinate('z', ez); aCoordinate('t', et); Object.freeze(this); } get x() { return this.toAffine().x; } get y() { return this.toAffine().y; } static fromAffine(p) { if (p instanceof Point) throw new Error('extended point not allowed'); const { x, y } = p || {}; aCoordinate('x', x); aCoordinate('y', y); return new Point(x, y, _1n, modP(x * y)); } static normalizeZ(points) { const toInv = Fp.invertBatch(points.map((p) => p.ez)); return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine); } // Multiscalar Multiplication static msm(points, scalars) { return (0, curve_js_1.pippenger)(Point, Fn, points, scalars); } // "Private method", don't use it directly _setWindowSize(windowSize) { wnaf.setWindowSize(this, windowSize); } // Not required for fromHex(), which always creates valid points. // Could be useful for fromAffine(). assertValidity() { assertValidMemo(this); } // Compare one point to another. equals(other) { assertPoint(other); const { ex: X1, ey: Y1, ez: Z1 } = this; const { ex: X2, ey: Y2, ez: Z2 } = other; const X1Z2 = modP(X1 * Z2); const X2Z1 = modP(X2 * Z1); const Y1Z2 = modP(Y1 * Z2); const Y2Z1 = modP(Y2 * Z1); return X1Z2 === X2Z1 && Y1Z2 === Y2Z1; } is0() { return this.equals(Point.ZERO); } negate() { // Flips point sign to a negative one (-x, y in affine coords) return new Point(modP(-this.ex), this.ey, this.ez, modP(-this.et)); } // Fast algo for doubling Extended Point. // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd // Cost: 4M + 4S + 1*a + 6add + 1*2. double() { const { a } = CURVE; const { ex: X1, ey: Y1, ez: Z1 } = this; const A = modP(X1 * X1); // A = X12 const B = modP(Y1 * Y1); // B = Y12 const C = modP(_2n * modP(Z1 * Z1)); // C = 2*Z12 const D = modP(a * A); // D = a*A const x1y1 = X1 + Y1; const E = modP(modP(x1y1 * x1y1) - A - B); // E = (X1+Y1)2-A-B const G = D + B; // G = D+B const F = G - C; // F = G-C const H = D - B; // H = D-B const X3 = modP(E * F); // X3 = E*F const Y3 = modP(G * H); // Y3 = G*H const T3 = modP(E * H); // T3 = E*H const Z3 = modP(F * G); // Z3 = F*G return new Point(X3, Y3, Z3, T3); } // Fast algo for adding 2 Extended Points. // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd // Cost: 9M + 1*a + 1*d + 7add. add(other) { assertPoint(other); const { a, d } = CURVE; const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this; const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other; // Faster algo for adding 2 Extended Points when curve's a=-1. // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-4 // Cost: 8M + 8add + 2*2. // Note: It does not check whether the `other` point is valid. if (a === BigInt(-1)) { const A = modP((Y1 - X1) * (Y2 + X2)); const B = modP((Y1 + X1) * (Y2 - X2)); const F = modP(B - A); if (F === _0n) return this.double(); // Same point. Tests say it doesn't affect timing const C = modP(Z1 * _2n * T2); const D = modP(T1 * _2n * Z2); const E = D + C; const G = B + A; const H = D - C; const X3 = modP(E * F); const Y3 = modP(G * H); const T3 = modP(E * H); const Z3 = modP(F * G); return new Point(X3, Y3, Z3, T3); } const A = modP(X1 * X2); // A = X1*X2 const B = modP(Y1 * Y2); // B = Y1*Y2 const C = modP(T1 * d * T2); // C = T1*d*T2 const D = modP(Z1 * Z2); // D = Z1*Z2 const E = modP((X1 + Y1) * (X2 + Y2) - A - B); // E = (X1+Y1)*(X2+Y2)-A-B const F = D - C; // F = D-C const G = D + C; // G = D+C const H = modP(B - a * A); // H = B-a*A const X3 = modP(E * F); // X3 = E*F const Y3 = modP(G * H); // Y3 = G*H const T3 = modP(E * H); // T3 = E*H const Z3 = modP(F * G); // Z3 = F*G return new Point(X3, Y3, Z3, T3); } subtract(other) { return this.add(other.negate()); } wNAF(n) { return wnaf.wNAFCached(this, n, Point.normalizeZ); } // Constant-time multiplication. multiply(scalar) { const n = scalar; ut.aInRange('scalar', n, _1n, CURVE_ORDER); // 1 <= scalar < L const { p, f } = this.wNAF(n); return Point.normalizeZ([p, f])[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. // Does NOT allow scalars higher than CURVE.n. // Accepts optional accumulator to merge with multiply (important for sparse scalars) multiplyUnsafe(scalar, acc = Point.ZERO) { const n = scalar; ut.aInRange('scalar', n, _0n, CURVE_ORDER); // 0 <= scalar < L if (n === _0n) return I; if (this.is0() || n === _1n) return this; return wnaf.wNAFCachedUnsafe(this, n, Point.normalizeZ, acc); } // Checks if point is of small order. // If you add something to small order point, you will have "dirty" // point with torsion component. // Multiplies point by cofactor and checks if the result is 0. isSmallOrder() { return this.multiplyUnsafe(cofactor).is0(); } // Multiplies point by curve order and checks if the result is 0. // Returns `false` is the point is dirty. isTorsionFree() { return wnaf.unsafeLadder(this, CURVE_ORDER).is0(); } // Converts Extended point to default (x, y) coordinates. // Can accept precomputed Z^-1 - for example, from invertBatch. toAffine(iz) { return toAffineMemo(this, iz); } clearCofactor() { const { h: cofactor } = CURVE; if (cofactor === _1n) return this; return this.multiplyUnsafe(cofactor); } // Converts hash string or Uint8Array to Point. // Uses algo from RFC8032 5.1.3. static fromHex(hex, zip215 = false) { const { d, a } = CURVE; const len = Fp.BYTES; hex = (0, utils_js_1.ensureBytes)('pointHex', hex, len); // copy hex to a new array (0, utils_js_1.abool)('zip215', zip215); const normed = hex.slice(); // copy again, we'll manipulate it const lastByte = hex[len - 1]; // select last byte normed[len - 1] = lastByte & ~0x80; // clear last bit const y = ut.bytesToNumberLE(normed); // zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5. // RFC8032 prohibits >= p, but ZIP215 doesn't // zip215=true: 0 <= y < MASK (2^256 for ed25519) // zip215=false: 0 <= y < P (2^255-19 for ed25519) const max = zip215 ? MASK : Fp.ORDER; ut.aInRange('pointHex.y', y, _0n, max); // Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case: // ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a) const y2 = modP(y * y); // denominator is always non-0 mod p. const u = modP(y2 - _1n); // u = y² - 1 const v = modP(d * y2 - a); // v = d y² + 1. let { isValid, value: x } = uvRatio(u, v); // √(u/v) if (!isValid) throw new Error('Point.fromHex: invalid y coordinate'); const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit if (!zip215 && x === _0n && isLastByteOdd) // if x=0 and x_0 = 1, fail throw new Error('Point.fromHex: x=0 and x_0=1'); if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x return Point.fromAffine({ x, y }); } static fromPrivateKey(privKey) { return getExtendedPublicKey(privKey).point; } toRawBytes() { const { x, y } = this.toAffine(); const bytes = ut.numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y) bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y return bytes; // and use the last byte to encode sign of x } toHex() { return ut.bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string. } } Point.BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy)); Point.ZERO = new Point(_0n, _1n, _1n, _0n); // 0, 1, 1, 0 const { BASE: G, ZERO: I } = Point; const wnaf = (0, curve_js_1.wNAF)(Point, nByteLength * 8); function modN(a) { return (0, modular_js_1.mod)(a, CURVE_ORDER); } // Little-endian SHA512 with modulo n function modN_LE(hash) { return modN(ut.bytesToNumberLE(hash)); } /** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */ function getExtendedPublicKey(key) { const len = Fp.BYTES; key = (0, utils_js_1.ensureBytes)('private key', key, len); // Hash private key with curve's hash function to produce uniformingly random input // Check byte lengths: ensure(64, h(ensure(32, key))) const hashed = (0, utils_js_1.ensureBytes)('hashed private key', cHash(key), 2 * len); const head = adjustScalarBytes(hashed.slice(0, len)); // clear first half bits, produce FE const prefix = hashed.slice(len, 2 * len); // second half is called key prefix (5.1.6) const scalar = modN_LE(head); // The actual private scalar const point = G.multiply(scalar); // Point on Edwards curve aka public key const pointBytes = point.toRawBytes(); // Uint8Array representation return { head, prefix, scalar, point, pointBytes }; } // Calculates EdDSA pub key. RFC8032 5.1.5. Privkey is hashed. Use first half with 3 bits cleared function getPublicKey(privKey) { return getExtendedPublicKey(privKey).pointBytes; } // int('LE', SHA512(dom2(F, C) || msgs)) mod N function hashDomainToScalar(context = new Uint8Array(), ...msgs) { const msg = ut.concatBytes(...msgs); return modN_LE(cHash(domain(msg, (0, utils_js_1.ensureBytes)('context', context), !!prehash))); } /** Signs message with privateKey. RFC8032 5.1.6 */ function sign(msg, privKey, options = {}) { msg = (0, utils_js_1.ensureBytes)('message', msg); if (prehash) msg = prehash(msg); // for ed25519ph etc. const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey); const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M) const R = G.multiply(r).toRawBytes(); // R = rG const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M) const s = modN(r + k * scalar); // S = (r + k * s) mod L ut.aInRange('signature.s', s, _0n, CURVE_ORDER); // 0 <= s < l const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES)); return (0, utils_js_1.ensureBytes)('result', res, Fp.BYTES * 2); // 64-byte signature } const verifyOpts = VERIFY_DEFAULT; /** * Verifies EdDSA signature against message and public key. RFC8032 5.1.7. * An extended group equation is checked. */ function verify(sig, msg, publicKey, options = verifyOpts) { const { context, zip215 } = options; const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7. sig = (0, utils_js_1.ensureBytes)('signature', sig, 2 * len); // An extended group equation is checked. msg = (0, utils_js_1.ensureBytes)('message', msg); publicKey = (0, utils_js_1.ensureBytes)('publicKey', publicKey, len); if (zip215 !== undefined) (0, utils_js_1.abool)('zip215', zip215); if (prehash) msg = prehash(msg); // for ed25519ph, etc const s = ut.bytesToNumberLE(sig.slice(len, 2 * len)); let A, R, SB; try { // zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5. // zip215=true: 0 <= y < MASK (2^256 for ed25519) // zip215=false: 0 <= y < P (2^255-19 for ed25519) A = Point.fromHex(publicKey, zip215); R = Point.fromHex(sig.slice(0, len), zip215); SB = G.multiplyUnsafe(s); // 0 <= s < l is done inside } catch (error) { return false; } if (!zip215 && A.isSmallOrder()) return false; const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg); const RkA = R.add(A.multiplyUnsafe(k)); // Extended group equation // [8][S]B = [8]R + [8][k]A' return RkA.subtract(SB).clearCofactor().equals(Point.ZERO); } G._setWindowSize(8); // Enable precomputes. Slows down first publicKey computation by 20ms. const utils = { getExtendedPublicKey, // ed25519 private keys are uniform 32b. No need to check for modulo bias, like in secp256k1. randomPrivateKey: () => randomBytes(Fp.BYTES), /** * We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT * values. This slows down first getPublicKey() by milliseconds (see Speed section), * but allows to speed-up subsequent getPublicKey() calls up to 20x. * @param windowSize 2, 4, 8, 16 */ precompute(windowSize = 8, point = Point.BASE) { point._setWindowSize(windowSize); point.multiply(BigInt(3)); return point; }, }; return { CURVE, getPublicKey, sign, verify, ExtendedPoint: Point, utils, }; } /***/ }), /***/ "../../node_modules/@noble/curves/abstract/hash-to-curve.js": /*!******************************************************************!*\ !*** ../../node_modules/@noble/curves/abstract/hash-to-curve.js ***! \******************************************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.expand_message_xmd = expand_message_xmd; exports.expand_message_xof = expand_message_xof; exports.hash_to_field = hash_to_field; exports.isogenyMap = isogenyMap; exports.createHasher = createHasher; const modular_js_1 = __webpack_require__(/*! ./modular.js */ "../../node_modules/@noble/curves/abstract/modular.js"); const utils_js_1 = __webpack_require__(/*! ./utils.js */ "../../node_modules/@noble/curves/abstract/utils.js"); // Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE. const os2ip = utils_js_1.bytesToNumberBE; // Integer to Octet Stream (numberToBytesBE) function i2osp(value, length) { anum(value); anum(length); if (value < 0 || value >= 1 << (8 * length)) throw new Error('invalid I2OSP input: ' + value); const res = Array.from({ length }).fill(0); for (let i = length - 1; i >= 0; i--) { res[i] = value & 0xff; value >>>= 8; } return new Uint8Array(res); } function strxor(a, b) { const arr = new Uint8Array(a.length); for (let i = 0; i < a.length; i++) { arr[i] = a[i] ^ b[i]; } return arr; } function anum(item) { if (!Number.isSafeInteger(item)) throw new Error('number expected'); } /** * Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits. * [RFC 9380 5.3.1](https://www.rfc-editor.org/rfc/rfc9380#section-5.3.1). */ function expand_message_xmd(msg, DST, lenInBytes, H) { (0, utils_js_1.abytes)(msg); (0, utils_js_1.abytes)(DST); anum(lenInBytes); // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3 if (DST.length > 255) DST = H((0, utils_js_1.concatBytes)((0, utils_js_1.utf8ToBytes)('H2C-OVERSIZE-DST-'), DST)); const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H; const ell = Math.ceil(lenInBytes / b_in_bytes); if (lenInBytes > 65535 || ell > 255) throw new Error('expand_message_xmd: invalid lenInBytes'); const DST_prime = (0, utils_js_1.concatBytes)(DST, i2osp(DST.length, 1)); const Z_pad = i2osp(0, r_in_bytes); const l_i_b_str = i2osp(lenInBytes, 2); // len_in_bytes_str const b = new Array(ell); const b_0 = H((0, utils_js_1.concatBytes)(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime)); b[0] = H((0, utils_js_1.concatBytes)(b_0, i2osp(1, 1), DST_prime)); for (let i = 1; i <= ell; i++) { const args = [strxor(b_0, b[i - 1]), i2osp(i + 1, 1), DST_prime]; b[i] = H((0, utils_js_1.concatBytes)(...args)); } const pseudo_random_bytes = (0, utils_js_1.concatBytes)(...b); return pseudo_random_bytes.slice(0, lenInBytes); } /** * Produces a uniformly random byte string using an extendable-output function (XOF) H. * 1. The collision resistance of H MUST be at least k bits. * 2. H MUST be an XOF that has been proved indifferentiable from * a random oracle under a reasonable cryptographic assumption. * [RFC 9380 5.3.2](https://www.rfc-editor.org/rfc/rfc9380#section-5.3.2). */ function expand_message_xof(msg, DST, lenInBytes, k, H) { (0, utils_js_1.abytes)(msg); (0, utils_js_1.abytes)(DST); anum(lenInBytes); // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3 // DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8)); if (DST.length > 255) { const dkLen = Math.ceil((2 * k) / 8); DST = H.create({ dkLen }).update((0, utils_js_1.utf8ToBytes)('H2C-OVERSIZE-DST-')).update(DST).digest(); } if (lenInBytes > 65535 || DST.length > 255) throw new Error('expand_message_xof: invalid lenInBytes'); return (H.create({ dkLen: lenInBytes }) .update(msg) .update(i2osp(lenInBytes, 2)) // 2. DST_prime = DST || I2OSP(len(DST), 1) .update(DST) .update(i2osp(DST.length, 1)) .digest()); } /** * Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F. * [RFC 9380 5.2](https://www.rfc-editor.org/rfc/rfc9380#section-5.2). * @param msg a byte string containing the message to hash * @param count the number of elements of F to output * @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above * @returns [u_0, ..., u_(count - 1)], a list of field elements. */ function hash_to_field(msg, count, options) { (0, utils_js_1.validateObject)(options, { DST: 'stringOrUint8Array', p: 'bigint', m: 'isSafeInteger', k: 'isSafeInteger', hash: 'hash', }); const { p, k, m, hash, expand, DST: _DST } = options; (0, utils_js_1.abytes)(msg); anum(count); const DST = typeof _DST === 'string' ? (0, utils_js_1.utf8ToBytes)(_DST) : _DST; const log2p = p.toString(2).length; const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above const len_in_bytes = count * m * L; let prb; // pseudo_random_bytes if (expand === 'xmd') { prb = expand_message_xmd(msg, DST, len_in_bytes, hash); } else if (expand === 'xof') { prb = expand_message_xof(msg, DST, len_in_bytes, k, hash); } else if (expand === '_internal_pass') { // for internal tests only prb = msg; } else { throw new Error('expand must be "xmd" or "xof"'); } const u = new Array(count); for (let i = 0; i < count; i++) { const e = new Array(m); for (let j = 0; j < m; j++) { const elm_offset = L * (j + i * m); const tv = prb.subarray(elm_offset, elm_offset + L); e[j] = (0, modular_js_1.mod)(os2ip(tv), p); } u[i] = e; } return u; } function isogenyMap(field, map) { // Make same order as in spec const COEFF = map.map((i) => Array.from(i).reverse()); return (x, y) => { const [xNum, xDen, yNum, yDen] = COEFF.map((val) => val.reduce((acc, i) => field.add(field.mul(acc, x), i))); x = field.div(xNum, xDen); // xNum / xDen y = field.mul(y, field.div(yNum, yDen)); // y * (yNum / yDev) return { x: x, y: y }; }; } /** Creates hash-to-curve methods from EC Point and mapToCurve function. */ function createHasher(Point, mapToCurve, def) { if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined'); return { // Encodes byte string to elliptic curve. // hash_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3 hashToCurve(msg, options) { const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options }); const u0 = Point.fromAffine(mapToCurve(u[0])); const u1 = Point.fromAffine(mapToCurve(u[1])); const P = u0.add(u1).clearCofactor(); P.assertValidity(); return P; }, // Encodes byte string to elliptic curve. // encode_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3 encodeToCurve(msg, options) { const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options }); const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor(); P.assertValidity(); return P; }, // Same as encodeToCurve, but without hash mapToCurve(scalars) { if (!Array.isArray(scalars)) throw new Error('mapToCurve: expected array of bigints'); for (const i of scalars) if (typeof i !== 'bigint') throw new Error('mapToCurve: expected array of bigints'); const P = Point.fromAffine(mapToCurve(scalars)).clearCofactor(); P.assertValidity(); return P; }, }; } /***/ }), /***/ "../../node_modules/@noble/curves/abstract/modular.js": /*!************************************************************!*\ !*** ../../node_modules/@noble/curves/abstract/modular.js ***! \************************************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.isNegativeLE = void 0; exports.mod = mod; exports.pow = pow; exports.pow2 = pow2; exports.invert = invert; exports.tonelliShanks = tonelliShanks; exports.FpSqrt = FpSqrt; exports.validateField = validateField; exports.FpPow = FpPow; exports.FpInvertBatch = FpInvertBatch; exports.FpDiv = FpDiv; exports.FpLegendre = FpLegendre; exports.FpIsSquare = FpIsSquare; exports.nLength = nLength; exports.Field = Field; exports.FpSqrtOdd = FpSqrtOdd; exports.FpSqrtEven = FpSqrtEven; exports.hashToPrivateScalar = hashToPrivateScalar; exports.getFieldBytesLength = getFieldBytesLength; exports.getMinHashLength = getMinHashLength; exports.mapHashToField = mapHashToField; /** * Utils for modular division and finite fields. * A finite field over 11 is integer number operations `mod 11`. * There is no division: it is replaced by modular multiplicative inverse. * @module */ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ const utils_js_1 = __webpack_require__(/*! ./utils.js */ "../../node_modules/@noble/curves/abstract/utils.js"); // prettier-ignore const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3); // prettier-ignore const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8); // prettier-ignore const _9n = /* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16); // Calculates a modulo b function mod(a, b) { const result = a % b; return result >= _0n ? result : b + result; } /** * Efficiently raise num to power and do modular division. * Unsafe in some contexts: uses ladder, so can expose bigint bits. * @todo use field version && remove * @example * pow(2n, 6n, 11n) // 64n % 11n == 9n */ function pow(num, power, modulo) { if (power < _0n) throw new Error('invalid exponent, negatives unsupported'); if (modulo <= _0n) throw new Error('invalid modulus'); if (modulo === _1n) return _0n; let res = _1n; while (power > _0n) { if (power & _1n) res = (res * num) % modulo; num = (num * num) % modulo; power >>= _1n; } return res; } /