274ca7c68044c28f1b01556342cc187489492327e989af56e6b41e2bece69d4e.json raw
1 {"ast":null,"code":"/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n// Abelian group utilities\nimport { validateField, nLength } from './modular.js';\nimport { validateObject } from './utils.js';\nconst _0n = BigInt(0);\nconst _1n = BigInt(1);\n// Elliptic curve multiplication of Point by scalar. Fragile.\n// Scalars should always be less than curve order: this should be checked inside of a curve itself.\n// Creates precomputation tables for fast multiplication:\n// - private scalar is split by fixed size windows of W bits\n// - every window point is collected from window's table & added to accumulator\n// - since windows are different, same point inside tables won't be accessed more than once per calc\n// - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)\n// - +1 window is neccessary for wNAF\n// - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication\n// TODO: Research returning 2d JS array of windows, instead of a single window. This would allow\n// windows to be in different memory locations\nexport function wNAF(c, bits) {\n const constTimeNegate = (condition, item) => {\n const neg = item.negate();\n return condition ? neg : item;\n };\n const opts = W => {\n const windows = Math.ceil(bits / W) + 1; // +1, because\n const windowSize = 2 ** (W - 1); // -1 because we skip zero\n return {\n windows,\n windowSize\n };\n };\n return {\n constTimeNegate,\n // non-const time multiplication ladder\n unsafeLadder(elm, n) {\n let p = c.ZERO;\n let d = elm;\n while (n > _0n) {\n if (n & _1n) p = p.add(d);\n d = d.double();\n n >>= _1n;\n }\n return p;\n },\n /**\n * Creates a wNAF precomputation window. Used for caching.\n * Default window size is set by `utils.precompute()` and is equal to 8.\n * Number of precomputed points depends on the curve size:\n * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:\n * - 𝑊 is the window size\n * - 𝑛 is the bitlength of the curve order.\n * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.\n * @returns precomputed point tables flattened to a single array\n */\n precomputeWindow(elm, W) {\n const {\n windows,\n windowSize\n } = opts(W);\n const points = [];\n let p = elm;\n let base = p;\n for (let window = 0; window < windows; window++) {\n base = p;\n points.push(base);\n // =1, because we skip zero\n for (let i = 1; i < windowSize; i++) {\n base = base.add(p);\n points.push(base);\n }\n p = base.double();\n }\n return points;\n },\n /**\n * Implements ec multiplication using precomputed tables and w-ary non-adjacent form.\n * @param W window size\n * @param precomputes precomputed tables\n * @param n scalar (we don't check here, but should be less than curve order)\n * @returns real and fake (for const-time) points\n */\n wNAF(W, precomputes, n) {\n // TODO: maybe check that scalar is less than group order? wNAF behavious is undefined otherwise\n // But need to carefully remove other checks before wNAF. ORDER == bits here\n const {\n windows,\n windowSize\n } = opts(W);\n let p = c.ZERO;\n let f = c.BASE;\n const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc.\n const maxNumber = 2 ** W;\n const shiftBy = BigInt(W);\n for (let window = 0; window < windows; window++) {\n const offset = window * windowSize;\n // Extract W bits.\n let wbits = Number(n & mask);\n // Shift number by W bits.\n n >>= shiftBy;\n // If the bits are bigger than max size, we'll split those.\n // +224 => 256 - 32\n if (wbits > windowSize) {\n wbits -= maxNumber;\n n += _1n;\n }\n // This code was first written with assumption that 'f' and 'p' will never be infinity point:\n // since each addition is multiplied by 2 ** W, it cannot cancel each other. However,\n // there is negate now: it is possible that negated element from low value\n // would be the same as high element, which will create carry into next window.\n // It's not obvious how this can fail, but still worth investigating later.\n // Check if we're onto Zero point.\n // Add random point inside current window to f.\n const offset1 = offset;\n const offset2 = offset + Math.abs(wbits) - 1; // -1 because we skip zero\n const cond1 = window % 2 !== 0;\n const cond2 = wbits < 0;\n if (wbits === 0) {\n // The most important part for const-time getPublicKey\n f = f.add(constTimeNegate(cond1, precomputes[offset1]));\n } else {\n p = p.add(constTimeNegate(cond2, precomputes[offset2]));\n }\n }\n // JIT-compiler should not eliminate f here, since it will later be used in normalizeZ()\n // Even if the variable is still unused, there are some checks which will\n // throw an exception, so compiler needs to prove they won't happen, which is hard.\n // At this point there is a way to F be infinity-point even if p is not,\n // which makes it less const-time: around 1 bigint multiply.\n return {\n p,\n f\n };\n },\n wNAFCached(P, precomputesMap, n, transform) {\n // @ts-ignore\n const W = P._WINDOW_SIZE || 1;\n // Calculate precomputes on a first run, reuse them after\n let comp = precomputesMap.get(P);\n if (!comp) {\n comp = this.precomputeWindow(P, W);\n if (W !== 1) {\n precomputesMap.set(P, transform(comp));\n }\n }\n return this.wNAF(W, comp, n);\n }\n };\n}\nexport function validateBasic(curve) {\n validateField(curve.Fp);\n validateObject(curve, {\n n: 'bigint',\n h: 'bigint',\n Gx: 'field',\n Gy: 'field'\n }, {\n nBitLength: 'isSafeInteger',\n nByteLength: 'isSafeInteger'\n });\n // Set defaults\n return Object.freeze({\n ...nLength(curve.n, curve.nBitLength),\n ...curve,\n ...{\n p: curve.Fp.ORDER\n }\n });\n}\n//# sourceMappingURL=curve.js.map","map":null,"metadata":{},"sourceType":"module","externalDependencies":[]}