| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 | "use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.wNAF = wNAF;exports.validateBasic = validateBasic;/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */// Abelian group utilitiesconst modular_js_1 = require("./modular.js");const utils_js_1 = require("./utils.js");const _0n = BigInt(0);const _1n = BigInt(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 locationsfunction wNAF(c, bits) {    const constTimeNegate = (condition, item) => {        const neg = item.negate();        return condition ? neg : item;    };    const opts = (W) => {        const windows = Math.ceil(bits / W) + 1; // +1, because        const windowSize = 2 ** (W - 1); // -1 because we skip zero        return { windows, windowSize };    };    return {        constTimeNegate,        // non-const time multiplication ladder        unsafeLadder(elm, n) {            let 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.         * @returns precomputed point tables flattened to a single array         */        precomputeWindow(elm, W) {            const { windows, windowSize } = opts(W);            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 } = opts(W);            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 };        },        wNAFCached(P, precomputesMap, n, transform) {            // @ts-ignore            const W = P._WINDOW_SIZE || 1;            // Calculate precomputes on a first run, reuse them after            let comp = precomputesMap.get(P);            if (!comp) {                comp = this.precomputeWindow(P, W);                if (W !== 1) {                    precomputesMap.set(P, transform(comp));                }            }            return this.wNAF(W, comp, n);        },    };}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 },    });}//# sourceMappingURL=curve.js.map
 |