| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062 | /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */// Short Weierstrass curve. The formula is: y² = x³ + ax + bimport { validateBasic, wNAF } from './curve.js';import * as mod from './modular.js';import * as ut from './utils.js';import { ensureBytes } from './utils.js';function validatePointOpts(curve) {    const opts = validateBasic(curve);    ut.validateObject(opts, {        a: 'field',        b: 'field',    }, {        allowedPrivateKeyLengths: 'array',        wrapPrivateKey: 'boolean',        isTorsionFree: 'function',        clearCofactor: 'function',        allowInfinityPoint: 'boolean',        fromBytes: 'function',        toBytes: 'function',    });    const { endo, Fp, a } = opts;    if (endo) {        if (!Fp.eql(a, Fp.ZERO)) {            throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');        }        if (typeof endo !== 'object' ||            typeof endo.beta !== 'bigint' ||            typeof endo.splitScalar !== 'function') {            throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');        }    }    return Object.freeze({ ...opts });}// ASN.1 DER encoding utilitiesconst { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;export const DER = {    // asn.1 DER encoding utils    Err: class DERErr extends Error {        constructor(m = '') {            super(m);        }    },    _parseInt(data) {        const { Err: E } = DER;        if (data.length < 2 || data[0] !== 0x02)            throw new E('Invalid signature integer tag');        const len = data[1];        const res = data.subarray(2, len + 2);        if (!len || res.length !== len)            throw new E('Invalid signature integer: wrong 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)        if (res[0] & 0b10000000)            throw new E('Invalid signature integer: negative');        if (res[0] === 0x00 && !(res[1] & 0b10000000))            throw new E('Invalid signature integer: unnecessary leading zero');        return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left    },    toSig(hex) {        // parse DER signature        const { Err: E } = DER;        const data = typeof hex === 'string' ? h2b(hex) : hex;        ut.abytes(data);        let l = data.length;        if (l < 2 || data[0] != 0x30)            throw new E('Invalid signature tag');        if (data[1] !== l - 2)            throw new E('Invalid signature: incorrect length');        const { d: r, l: sBytes } = DER._parseInt(data.subarray(2));        const { d: s, l: rBytesLeft } = DER._parseInt(sBytes);        if (rBytesLeft.length)            throw new E('Invalid signature: left bytes after parsing');        return { r, s };    },    hexFromSig(sig) {        // Add leading zero if first byte has negative bit enabled. More details in '_parseInt'        const slice = (s) => (Number.parseInt(s[0], 16) & 0b1000 ? '00' + s : s);        const h = (num) => {            const hex = num.toString(16);            return hex.length & 1 ? `0${hex}` : hex;        };        const s = slice(h(sig.s));        const r = slice(h(sig.r));        const shl = s.length / 2;        const rhl = r.length / 2;        const sl = h(shl);        const rl = h(rhl);        return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;    },};// Be friendly to bad ECMAScript parsers by not using bigint literals// prettier-ignoreconst _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);export function weierstrassPoints(opts) {    const CURVE = validatePointOpts(opts);    const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ    const toBytes = CURVE.toBytes ||        ((_c, point, _isCompressed) => {            const a = point.toAffine();            return ut.concatBytes(Uint8Array.from([0x04]), Fp.toBytes(a.x), Fp.toBytes(a.y));        });    const fromBytes = CURVE.fromBytes ||        ((bytes) => {            // const head = bytes[0];            const tail = bytes.subarray(1);            // if (head !== 0x04) throw new Error('Only non-compressed encoding is supported');            const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));            const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));            return { x, y };        });    /**     * y² = x³ + ax + b: Short weierstrass curve formula     * @returns y²     */    function weierstrassEquation(x) {        const { a, b } = CURVE;        const x2 = Fp.sqr(x); // x * x        const x3 = Fp.mul(x2, x); // x2 * x        return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b    }    // Validate whether the passed curve params are valid.    // We check if curve equation works for generator point.    // `assertValidity()` won't work: `isTorsionFree()` is not available at this point in bls12-381.    // ProjectivePoint class has not been initialized yet.    if (!Fp.eql(Fp.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx)))        throw new Error('bad generator point: equation left != right');    // Valid group elements reside in range 1..n-1    function isWithinCurveOrder(num) {        return typeof num === 'bigint' && _0n < num && num < CURVE.n;    }    function assertGE(num) {        if (!isWithinCurveOrder(num))            throw new Error('Expected valid bigint: 0 < bigint < curve.n');    }    // Validates if priv key is valid and converts it to bigint.    // Supports options allowedPrivateKeyLengths and wrapPrivateKey.    function normPrivateKeyToScalar(key) {        const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;        if (lengths && typeof key !== 'bigint') {            if (ut.isBytes(key))                key = ut.bytesToHex(key);            // Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes            if (typeof key !== 'string' || !lengths.includes(key.length))                throw new Error('Invalid key');            key = key.padStart(nByteLength * 2, '0');        }        let num;        try {            num =                typeof key === 'bigint'                    ? key                    : ut.bytesToNumberBE(ensureBytes('private key', key, nByteLength));        }        catch (error) {            throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);        }        if (wrapPrivateKey)            num = mod.mod(num, n); // disabled by default, enabled for BLS        assertGE(num); // num in range [1..N-1]        return num;    }    const pointPrecomputes = new Map();    function assertPrjPoint(other) {        if (!(other instanceof Point))            throw new Error('ProjectivePoint expected');    }    /**     * Projective Point works in 3d / projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)     * Default Point works in 2d / affine coordinates: (x, y)     * We're doing calculations in projective, because its operations don't require costly inversion.     */    class Point {        constructor(px, py, pz) {            this.px = px;            this.py = py;            this.pz = pz;            if (px == null || !Fp.isValid(px))                throw new Error('x required');            if (py == null || !Fp.isValid(py))                throw new Error('y required');            if (pz == null || !Fp.isValid(pz))                throw new Error('z required');        }        // Does not validate if the point is on-curve.        // Use fromHex instead, or call assertValidity() later.        static fromAffine(p) {            const { x, y } = p || {};            if (!p || !Fp.isValid(x) || !Fp.isValid(y))                throw new Error('invalid affine point');            if (p instanceof Point)                throw new Error('projective point not allowed');            const is0 = (i) => Fp.eql(i, Fp.ZERO);            // fromAffine(x:0, y:0) would produce (x:0, y:0, z:1), but we need (x:0, y:1, z:0)            if (is0(x) && is0(y))                return Point.ZERO;            return new Point(x, y, Fp.ONE);        }        get x() {            return this.toAffine().x;        }        get y() {            return this.toAffine().y;        }        /**         * Takes a bunch of Projective Points but executes only one         * inversion on all of them. Inversion is very slow operation,         * so this improves performance massively.         * Optimization: converts a list of projective points to a list of identical points with Z=1.         */        static normalizeZ(points) {            const toInv = Fp.invertBatch(points.map((p) => p.pz));            return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);        }        /**         * Converts hash string or Uint8Array to Point.         * @param hex short/long ECDSA hex         */        static fromHex(hex) {            const P = Point.fromAffine(fromBytes(ensureBytes('pointHex', hex)));            P.assertValidity();            return P;        }        // Multiplies generator point by privateKey.        static fromPrivateKey(privateKey) {            return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));        }        // "Private method", don't use it directly        _setWindowSize(windowSize) {            this._WINDOW_SIZE = windowSize;            pointPrecomputes.delete(this);        }        // A point on curve is valid if it conforms to equation.        assertValidity() {            if (this.is0()) {                // (0, 1, 0) aka ZERO is invalid in most contexts.                // In BLS, ZERO can be serialized, so we allow it.                // (0, 0, 0) is wrong representation of ZERO and is always invalid.                if (CURVE.allowInfinityPoint && !Fp.is0(this.py))                    return;                throw new Error('bad point: ZERO');            }            // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`            const { x, y } = this.toAffine();            // Check if x, y are valid field elements            if (!Fp.isValid(x) || !Fp.isValid(y))                throw new Error('bad point: x or y not FE');            const left = Fp.sqr(y); // y²            const right = weierstrassEquation(x); // x³ + ax + b            if (!Fp.eql(left, right))                throw new Error('bad point: equation left != right');            if (!this.isTorsionFree())                throw new Error('bad point: not in prime-order subgroup');        }        hasEvenY() {            const { y } = this.toAffine();            if (Fp.isOdd)                return !Fp.isOdd(y);            throw new Error("Field doesn't support isOdd");        }        /**         * Compare one point to another.         */        equals(other) {            assertPrjPoint(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 Point(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, _3n);            const { px: X1, py: Y1, pz: Z1 } = this;            let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore            let t0 = Fp.mul(X1, X1); // step 1            let t1 = Fp.mul(Y1, Y1);            let t2 = Fp.mul(Z1, Z1);            let t3 = Fp.mul(X1, Y1);            t3 = Fp.add(t3, t3); // step 5            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); // step 10            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); // step 15            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); // step 20            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); // step 25            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); // step 30            Z3 = Fp.add(Z3, Z3);            return new Point(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) {            assertPrjPoint(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; // prettier-ignore            const a = CURVE.a;            const b3 = Fp.mul(CURVE.b, _3n);            let t0 = Fp.mul(X1, X2); // step 1            let t1 = Fp.mul(Y1, Y2);            let t2 = Fp.mul(Z1, Z2);            let t3 = Fp.add(X1, Y1);            let t4 = Fp.add(X2, Y2); // step 5            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); // step 10            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); // step 15            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); // step 20            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); // step 25            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); // step 30            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); // step 35            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); // step 40            return new Point(X3, Y3, Z3);        }        subtract(other) {            return this.add(other.negate());        }        is0() {            return this.equals(Point.ZERO);        }        wNAF(n) {            return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => {                const toInv = Fp.invertBatch(comp.map((p) => p.pz));                return comp.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);            });        }        /**         * 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(n) {            const I = Point.ZERO;            if (n === _0n)                return I;            assertGE(n); // Will throw on 0            if (n === _1n)                return this;            const { endo } = CURVE;            if (!endo)                return wnaf.unsafeLadder(this, n);            // Apply endomorphism            let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);            let k1p = I;            let k2p = I;            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 Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);            return k1p.add(k2p);        }        /**         * 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) {            assertGE(scalar);            let n = scalar;            let point, fake; // Fake point is used to const-time mult            const { endo } = CURVE;            if (endo) {                const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);                let { p: k1p, f: f1p } = this.wNAF(k1);                let { p: k2p, f: f2p } = this.wNAF(k2);                k1p = wnaf.constTimeNegate(k1neg, k1p);                k2p = wnaf.constTimeNegate(k2neg, k2p);                k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);                point = k1p.add(k2p);                fake = f1p.add(f2p);            }            else {                const { p, f } = this.wNAF(n);                point = p;                fake = f;            }            // Normalize `z` for both points, but return only real one            return Point.normalizeZ([point, fake])[0];        }        /**         * Efficiently calculate `aP + bQ`. Unsafe, can expose private key, if used incorrectly.         * Not using Strauss-Shamir trick: precomputation tables are faster.         * The trick could be useful if both P and Q are not G (not in our case).         * @returns non-zero affine point         */        multiplyAndAddUnsafe(Q, a, b) {            const G = Point.BASE; // No Strauss-Shamir trick: we have 10% faster G precomputes            const mul = (P, a // Select faster multiply() method            ) => (a === _0n || a === _1n || !P.equals(G) ? P.multiplyUnsafe(a) : P.multiply(a));            const sum = mul(this, a).add(mul(Q, b));            return sum.is0() ? undefined : sum;        }        // Converts Projective point to affine (x, y) coordinates.        // Can accept precomputed Z^-1 - for example, from invertBatch.        // (x, y, z) ∋ (x=x/z, y=y/z)        toAffine(iz) {            const { px: x, py: y, pz: z } = this;            const is0 = this.is0();            // If invZ was 0, we return zero point. However we still want to execute            // all operations, so we replace invZ with a random number, 1.            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 };        }        isTorsionFree() {            const { h: cofactor, isTorsionFree } = CURVE;            if (cofactor === _1n)                return true; // No subgroups, always torsion-free            if (isTorsionFree)                return isTorsionFree(Point, this);            throw new Error('isTorsionFree() has not been declared for the elliptic curve');        }        clearCofactor() {            const { h: cofactor, clearCofactor } = CURVE;            if (cofactor === _1n)                return this; // Fast-path            if (clearCofactor)                return clearCofactor(Point, this);            return this.multiplyUnsafe(CURVE.h);        }        toRawBytes(isCompressed = true) {            this.assertValidity();            return toBytes(Point, this, isCompressed);        }        toHex(isCompressed = true) {            return ut.bytesToHex(this.toRawBytes(isCompressed));        }    }    Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);    Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);    const _bits = CURVE.nBitLength;    const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);    // Validate if generator point is on curve    return {        CURVE,        ProjectivePoint: Point,        normPrivateKeyToScalar,        weierstrassEquation,        isWithinCurveOrder,    };}function validateOpts(curve) {    const opts = validateBasic(curve);    ut.validateObject(opts, {        hash: 'hash',        hmac: 'function',        randomBytes: 'function',    }, {        bits2int: 'function',        bits2int_modN: 'function',        lowS: 'boolean',    });    return Object.freeze({ lowS: true, ...opts });}export function weierstrass(curveDef) {    const CURVE = validateOpts(curveDef);    const { Fp, n: CURVE_ORDER } = CURVE;    const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32    const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32    function isValidFieldElement(num) {        return _0n < num && num < Fp.ORDER; // 0 is banned since it's not invertible FE    }    function modN(a) {        return mod.mod(a, CURVE_ORDER);    }    function invN(a) {        return mod.invert(a, CURVE_ORDER);    }    const { ProjectivePoint: Point, normPrivateKeyToScalar, weierstrassEquation, isWithinCurveOrder, } = weierstrassPoints({        ...CURVE,        toBytes(_c, point, isCompressed) {            const a = point.toAffine();            const x = Fp.toBytes(a.x);            const cat = ut.concatBytes;            if (isCompressed) {                return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);            }            else {                return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));            }        },        fromBytes(bytes) {            const len = bytes.length;            const head = bytes[0];            const tail = bytes.subarray(1);            // this.assertValidity() is done inside of fromHex            if (len === compressedLen && (head === 0x02 || head === 0x03)) {                const x = ut.bytesToNumberBE(tail);                if (!isValidFieldElement(x))                    throw new Error('Point is not on curve');                const y2 = weierstrassEquation(x); // y² = x³ + ax + b                let y;                try {                    y = Fp.sqrt(y2); // y = y² ^ (p+1)/4                }                catch (sqrtError) {                    const suffix = sqrtError instanceof Error ? ': ' + sqrtError.message : '';                    throw new Error('Point is not on curve' + suffix);                }                const isYOdd = (y & _1n) === _1n;                // ECDSA                const isHeadOdd = (head & 1) === 1;                if (isHeadOdd !== isYOdd)                    y = Fp.neg(y);                return { x, y };            }            else if (len === uncompressedLen && head === 0x04) {                const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));                const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));                return { x, y };            }            else {                throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`);            }        },    });    const numToNByteStr = (num) => ut.bytesToHex(ut.numberToBytesBE(num, CURVE.nByteLength));    function isBiggerThanHalfOrder(number) {        const HALF = CURVE_ORDER >> _1n;        return number > HALF;    }    function normalizeS(s) {        return isBiggerThanHalfOrder(s) ? modN(-s) : s;    }    // slice bytes num    const slcNum = (b, from, to) => ut.bytesToNumberBE(b.slice(from, to));    /**     * ECDSA signature with its (r, s) properties. Supports DER & compact representations.     */    class Signature {        constructor(r, s, recovery) {            this.r = r;            this.s = s;            this.recovery = recovery;            this.assertValidity();        }        // pair (bytes of r, bytes of s)        static fromCompact(hex) {            const l = CURVE.nByteLength;            hex = ensureBytes('compactSignature', hex, l * 2);            return new Signature(slcNum(hex, 0, l), slcNum(hex, l, 2 * l));        }        // 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);        }        assertValidity() {            // can use assertGE here            if (!isWithinCurveOrder(this.r))                throw new Error('r must be 0 < r < CURVE.n');            if (!isWithinCurveOrder(this.s))                throw new Error('s must be 0 < s < CURVE.n');        }        addRecoveryBit(recovery) {            return new Signature(this.r, this.s, recovery);        }        recoverPublicKey(msgHash) {            const { r, s, recovery: rec } = this;            const h = bits2int_modN(ensureBytes('msgHash', msgHash)); // Truncate hash            if (rec == null || ![0, 1, 2, 3].includes(rec))                throw new Error('recovery id invalid');            const radj = rec === 2 || rec === 3 ? r + CURVE.n : r;            if (radj >= Fp.ORDER)                throw new Error('recovery id 2 or 3 invalid');            const prefix = (rec & 1) === 0 ? '02' : '03';            const R = Point.fromHex(prefix + numToNByteStr(radj));            const ir = invN(radj); // r^-1            const u1 = modN(-h * ir); // -hr^-1            const u2 = modN(s * ir); // sr^-1            const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)            if (!Q)                throw new Error('point at infinify'); // unsafe is fine: no priv data leaked            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, modN(-this.s), this.recovery) : this;        }        // DER-encoded        toDERRawBytes() {            return ut.hexToBytes(this.toDERHex());        }        toDERHex() {            return DER.hexFromSig({ r: this.r, s: this.s });        }        // padded bytes of r, then padded bytes of s        toCompactRawBytes() {            return ut.hexToBytes(this.toCompactHex());        }        toCompactHex() {            return numToNByteStr(this.r) + numToNByteStr(this.s);        }    }    const utils = {        isValidPrivateKey(privateKey) {            try {                normPrivateKeyToScalar(privateKey);                return true;            }            catch (error) {                return false;            }        },        normPrivateKeyToScalar: normPrivateKeyToScalar,        /**         * Produces cryptographically secure private key from random of size         * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.         */        randomPrivateKey: () => {            const length = mod.getMinHashLength(CURVE.n);            return mod.mapHashToField(CURVE.randomBytes(length), CURVE.n);        },        /**         * Creates precompute table for an arbitrary EC point. Makes point "cached".         * Allows to massively speed-up `point.multiply(scalar)`.         * @returns cached point         * @example         * const fast = utils.precompute(8, ProjectivePoint.fromHex(someonesPubKey));         * fast.multiply(privKey); // much faster ECDH now         */        precompute(windowSize = 8, point = Point.BASE) {            point._setWindowSize(windowSize);            point.multiply(BigInt(3)); // 3 is arbitrary, just need any number here            return point;        },    };    /**     * Computes public key for a private key. Checks for validity of the private key.     * @param privateKey private key     * @param isCompressed whether to return compact (default), or full key     * @returns Public key, full when isCompressed=false; short when isCompressed=true     */    function getPublicKey(privateKey, isCompressed = true) {        return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);    }    /**     * Quick and dirty check for item being public key. Does not validate hex, or being on-curve.     */    function isProbPub(item) {        const arr = ut.isBytes(item);        const str = typeof item === 'string';        const len = (arr || str) && item.length;        if (arr)            return len === compressedLen || len === uncompressedLen;        if (str)            return len === 2 * compressedLen || len === 2 * uncompressedLen;        if (item instanceof Point)            return true;        return false;    }    /**     * ECDH (Elliptic Curve Diffie Hellman).     * Computes shared public key from private key and public key.     * Checks: 1) private key validity 2) shared key is on-curve.     * Does NOT hash the result.     * @param privateA private key     * @param publicB different public key     * @param isCompressed whether to return compact (default), or full key     * @returns shared public key     */    function getSharedSecret(privateA, publicB, isCompressed = true) {        if (isProbPub(privateA))            throw new Error('first arg must be private key');        if (!isProbPub(publicB))            throw new Error('second arg must be public key');        const b = Point.fromHex(publicB); // check for being on-curve        return b.multiply(normPrivateKeyToScalar(privateA)).toRawBytes(isCompressed);    }    // RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.    // FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.    // bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.    // int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors    const bits2int = CURVE.bits2int ||        function (bytes) {            // For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)            // for some cases, since bytes.length * 8 is not actual bitLength.            const num = ut.bytesToNumberBE(bytes); // check for == u8 done here            const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits            return delta > 0 ? num >> BigInt(delta) : num;        };    const bits2int_modN = CURVE.bits2int_modN ||        function (bytes) {            return modN(bits2int(bytes)); // can't use bytesToNumberBE here        };    // NOTE: pads output with zero as per spec    const ORDER_MASK = ut.bitMask(CURVE.nBitLength);    /**     * Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.     */    function int2octets(num) {        if (typeof num !== 'bigint')            throw new Error('bigint expected');        if (!(_0n <= num && num < ORDER_MASK))            throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);        // works with order, can have different size than numToField!        return ut.numberToBytesBE(num, CURVE.nByteLength);    }    // Steps A, D of RFC6979 3.2    // Creates RFC6979 seed; converts msg/privKey to numbers.    // Used only in sign, not in verify.    // NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.    // Also it can be bigger for P224 + SHA256    function prepSig(msgHash, privateKey, opts = defaultSigOpts) {        if (['recovered', 'canonical'].some((k) => k in opts))            throw new Error('sign() legacy options not supported');        const { hash, randomBytes } = CURVE;        let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default        if (lowS == null)            lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash        msgHash = ensureBytes('msgHash', msgHash);        if (prehash)            msgHash = ensureBytes('prehashed msgHash', hash(msgHash));        // We can't later call bits2octets, since nested bits2int is broken for curves        // with nBitLength % 8 !== 0. Because of that, we unwrap it here as int2octets call.        // const bits2octets = (bits) => int2octets(bits2int_modN(bits))        const h1int = bits2int_modN(msgHash);        const d = normPrivateKeyToScalar(privateKey); // validate private key, convert to bigint        const seedArgs = [int2octets(d), int2octets(h1int)];        // extraEntropy. RFC6979 3.6: additional k' (optional).        if (ent != null && ent !== false) {            // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')            const e = ent === true ? randomBytes(Fp.BYTES) : ent; // generate random bytes OR pass as-is            seedArgs.push(ensureBytes('extraEntropy', e)); // check for being bytes        }        const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2        const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!        // Converts signature params into point w r/s, checks result for validity.        function k2sig(kBytes) {            // RFC 6979 Section 3.2, step 3: k = bits2int(T)            const k = bits2int(kBytes); // Cannot use fields methods, since it is group element            if (!isWithinCurveOrder(k))                return; // Important: all mod() calls here must be done over N            const ik = invN(k); // k^-1 mod n            const q = Point.BASE.multiply(k).toAffine(); // q = Gk            const r = modN(q.x); // r = q.x mod n            if (r === _0n)                return;            // Can use scalar blinding b^-1(bm + bdr) where b ∈ [1,q−1] according to            // https://tches.iacr.org/index.php/TCHES/article/view/7337/6509. We've decided against it:            // a) dependency on CSPRNG b) 15% slowdown c) doesn't really help since bigints are not CT            const s = modN(ik * modN(m + r * d)); // Not using blinding here            if (s === _0n)                return;            let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)            let normS = s;            if (lowS && isBiggerThanHalfOrder(s)) {                normS = normalizeS(s); // if lowS was passed, ensure s is always                recovery ^= 1; // // in the bottom half of N            }            return new Signature(r, normS, recovery); // use normS, not s        }        return { seed, k2sig };    }    const defaultSigOpts = { lowS: CURVE.lowS, prehash: false };    const defaultVerOpts = { lowS: CURVE.lowS, prehash: false };    /**     * Signs message hash with a private key.     * ```     * sign(m, d, k) where     *   (x, y) = G × k     *   r = x mod n     *   s = (m + dr)/k mod n     * ```     * @param msgHash NOT message. msg needs to be hashed to `msgHash`, or use `prehash`.     * @param privKey private key     * @param opts lowS for non-malleable sigs. extraEntropy for mixing randomness into k. prehash will hash first arg.     * @returns signature with recovery param     */    function sign(msgHash, privKey, opts = defaultSigOpts) {        const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.        const C = CURVE;        const drbg = ut.createHmacDrbg(C.hash.outputLen, C.nByteLength, C.hmac);        return drbg(seed, k2sig); // Steps B, C, D, E, F, G    }    // Enable precomputes. Slows down first publicKey computation by 20ms.    Point.BASE._setWindowSize(8);    // utils.precompute(8, ProjectivePoint.BASE)    /**     * Verifies a signature against message hash and public key.     * Rejects lowS signatures by default: to override,     * specify option `{lowS: false}`. Implements section 4.1.4 from https://www.secg.org/sec1-v2.pdf:     *     * ```     * verify(r, s, h, P) where     *   U1 = hs^-1 mod n     *   U2 = rs^-1 mod n     *   R = U1⋅G - U2⋅P     *   mod(R.x, n) == r     * ```     */    function verify(signature, msgHash, publicKey, opts = defaultVerOpts) {        const sg = signature;        msgHash = ensureBytes('msgHash', msgHash);        publicKey = ensureBytes('publicKey', publicKey);        if ('strict' in opts)            throw new Error('options.strict was renamed to lowS');        const { lowS, prehash } = opts;        let _sig = undefined;        let P;        try {            if (typeof sg === 'string' || ut.isBytes(sg)) {                // Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).                // Since DER can also be 2*nByteLength bytes, we check for it first.                try {                    _sig = Signature.fromDER(sg);                }                catch (derError) {                    if (!(derError instanceof DER.Err))                        throw derError;                    _sig = Signature.fromCompact(sg);                }            }            else if (typeof sg === 'object' && typeof sg.r === 'bigint' && typeof sg.s === 'bigint') {                const { r, s } = sg;                _sig = new Signature(r, s);            }            else {                throw new Error('PARSE');            }            P = Point.fromHex(publicKey);        }        catch (error) {            if (error.message === 'PARSE')                throw new Error(`signature must be Signature instance, Uint8Array or hex string`);            return false;        }        if (lowS && _sig.hasHighS())            return false;        if (prehash)            msgHash = CURVE.hash(msgHash);        const { r, s } = _sig;        const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element        const is = invN(s); // s^-1        const u1 = modN(h * is); // u1 = hs^-1 mod n        const u2 = modN(r * is); // u2 = rs^-1 mod n        const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); // R = u1⋅G + u2⋅P        if (!R)            return false;        const v = modN(R.x);        return v === r;    }    return {        CURVE,        getPublicKey,        getSharedSecret,        sign,        verify,        ProjectivePoint: Point,        Signature,        utils,    };}/** * Implementation of the Shallue and van de Woestijne method for any weierstrass curve. * TODO: check if there is a way to merge this with uvRatio in Edwards; move to modular. * b = True and y = sqrt(u / v) if (u / v) is square in F, and * b = False and y = sqrt(Z * (u / v)) otherwise. * @param Fp * @param Z * @returns */export function SWUFpSqrtRatio(Fp, Z) {    // Generic implementation    const q = Fp.ORDER;    let l = _0n;    for (let o = q - _1n; o % _2n === _0n; o /= _2n)        l += _1n;    const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.    // We need 2n ** c1 and 2n ** (c1-1). We can't use **; but we can use <<.    // 2n ** c1 == 2n << (c1-1)    const _2n_pow_c1_1 = _2n << (c1 - _1n - _1n);    const _2n_pow_c1 = _2n_pow_c1_1 * _2n;    const c2 = (q - _1n) / _2n_pow_c1; // 2. c2 = (q - 1) / (2^c1)  # Integer arithmetic    const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2            # Integer arithmetic    const c4 = _2n_pow_c1 - _1n; // 4. c4 = 2^c1 - 1                # Integer arithmetic    const c5 = _2n_pow_c1_1; // 5. c5 = 2^(c1 - 1)                  # Integer arithmetic    const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2    const c7 = Fp.pow(Z, (c2 + _1n) / _2n); // 7. c7 = Z^((c2 + 1) / 2)    let sqrtRatio = (u, v) => {        let tv1 = c6; // 1. tv1 = c6        let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4        let tv3 = Fp.sqr(tv2); // 3. tv3 = tv2^2        tv3 = Fp.mul(tv3, v); // 4. tv3 = tv3 * v        let tv5 = Fp.mul(u, tv3); // 5. tv5 = u * tv3        tv5 = Fp.pow(tv5, c3); // 6. tv5 = tv5^c3        tv5 = Fp.mul(tv5, tv2); // 7. tv5 = tv5 * tv2        tv2 = Fp.mul(tv5, v); // 8. tv2 = tv5 * v        tv3 = Fp.mul(tv5, u); // 9. tv3 = tv5 * u        let tv4 = Fp.mul(tv3, tv2); // 10. tv4 = tv3 * tv2        tv5 = Fp.pow(tv4, c5); // 11. tv5 = tv4^c5        let isQR = Fp.eql(tv5, Fp.ONE); // 12. isQR = tv5 == 1        tv2 = Fp.mul(tv3, c7); // 13. tv2 = tv3 * c7        tv5 = Fp.mul(tv4, tv1); // 14. tv5 = tv4 * tv1        tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)        tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)        // 17. for i in (c1, c1 - 1, ..., 2):        for (let i = c1; i > _1n; i--) {            let tv5 = i - _2n; // 18.    tv5 = i - 2            tv5 = _2n << (tv5 - _1n); // 19.    tv5 = 2^tv5            let tvv5 = Fp.pow(tv4, tv5); // 20.    tv5 = tv4^tv5            const e1 = Fp.eql(tvv5, Fp.ONE); // 21.    e1 = tv5 == 1            tv2 = Fp.mul(tv3, tv1); // 22.    tv2 = tv3 * tv1            tv1 = Fp.mul(tv1, tv1); // 23.    tv1 = tv1 * tv1            tvv5 = Fp.mul(tv4, tv1); // 24.    tv5 = tv4 * tv1            tv3 = Fp.cmov(tv2, tv3, e1); // 25.    tv3 = CMOV(tv2, tv3, e1)            tv4 = Fp.cmov(tvv5, tv4, e1); // 26.    tv4 = CMOV(tv5, tv4, e1)        }        return { isValid: isQR, value: tv3 };    };    if (Fp.ORDER % _4n === _3n) {        // sqrt_ratio_3mod4(u, v)        const c1 = (Fp.ORDER - _3n) / _4n; // 1. c1 = (q - 3) / 4     # Integer arithmetic        const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)        sqrtRatio = (u, v) => {            let tv1 = Fp.sqr(v); // 1. tv1 = v^2            const tv2 = Fp.mul(u, v); // 2. tv2 = u * v            tv1 = Fp.mul(tv1, tv2); // 3. tv1 = tv1 * tv2            let y1 = Fp.pow(tv1, c1); // 4. y1 = tv1^c1            y1 = Fp.mul(y1, tv2); // 5. y1 = y1 * tv2            const y2 = Fp.mul(y1, c2); // 6. y2 = y1 * c2            const tv3 = Fp.mul(Fp.sqr(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v            const isQR = Fp.eql(tv3, u); // 9. isQR = tv3 == u            let y = Fp.cmov(y2, y1, isQR); // 10. y = CMOV(y2, y1, isQR)            return { isValid: isQR, value: y }; // 11. return (isQR, y) isQR ? y : y*c2        };    }    // No curves uses that    // if (Fp.ORDER % _8n === _5n) // sqrt_ratio_5mod8    return sqrtRatio;}/** * Simplified Shallue-van de Woestijne-Ulas Method * https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2 */export function mapToCurveSimpleSWU(Fp, opts) {    mod.validateField(Fp);    if (!Fp.isValid(opts.A) || !Fp.isValid(opts.B) || !Fp.isValid(opts.Z))        throw new Error('mapToCurveSimpleSWU: invalid opts');    const sqrtRatio = SWUFpSqrtRatio(Fp, opts.Z);    if (!Fp.isOdd)        throw new Error('Fp.isOdd is not implemented!');    // Input: u, an element of F.    // Output: (x, y), a point on E.    return (u) => {        // prettier-ignore        let tv1, tv2, tv3, tv4, tv5, tv6, x, y;        tv1 = Fp.sqr(u); // 1.  tv1 = u^2        tv1 = Fp.mul(tv1, opts.Z); // 2.  tv1 = Z * tv1        tv2 = Fp.sqr(tv1); // 3.  tv2 = tv1^2        tv2 = Fp.add(tv2, tv1); // 4.  tv2 = tv2 + tv1        tv3 = Fp.add(tv2, Fp.ONE); // 5.  tv3 = tv2 + 1        tv3 = Fp.mul(tv3, opts.B); // 6.  tv3 = B * tv3        tv4 = Fp.cmov(opts.Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7.  tv4 = CMOV(Z, -tv2, tv2 != 0)        tv4 = Fp.mul(tv4, opts.A); // 8.  tv4 = A * tv4        tv2 = Fp.sqr(tv3); // 9.  tv2 = tv3^2        tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2        tv5 = Fp.mul(tv6, opts.A); // 11. tv5 = A * tv6        tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5        tv2 = Fp.mul(tv2, tv3); // 13. tv2 = tv2 * tv3        tv6 = Fp.mul(tv6, tv4); // 14. tv6 = tv6 * tv4        tv5 = Fp.mul(tv6, opts.B); // 15. tv5 = B * tv6        tv2 = Fp.add(tv2, tv5); // 16. tv2 = tv2 + tv5        x = Fp.mul(tv1, tv3); // 17.   x = tv1 * tv3        const { isValid, value } = sqrtRatio(tv2, tv6); // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)        y = Fp.mul(tv1, u); // 19.   y = tv1 * u  -> Z * u^3 * y1        y = Fp.mul(y, value); // 20.   y = y * y1        x = Fp.cmov(x, tv3, isValid); // 21.   x = CMOV(x, tv3, is_gx1_square)        y = Fp.cmov(y, value, isValid); // 22.   y = CMOV(y, y1, is_gx1_square)        const e1 = Fp.isOdd(u) === Fp.isOdd(y); // 23.  e1 = sgn0(u) == sgn0(y)        y = Fp.cmov(Fp.neg(y), y, e1); // 24.   y = CMOV(-y, y, e1)        x = Fp.div(x, tv4); // 25.   x = x / tv4        return { x, y };    };}//# sourceMappingURL=weierstrass.js.map
 |