From d739b0a28697450e7fe46e96e43edfa5446d8885 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 24 Jul 2023 18:50:46 -0400 Subject: [PATCH] fix: patch noble ed25519 to inject @peculiar/webcrypto --- npm-shrinkwrap.json | 78 ++ package.json | 1 + patches/@noble+ed25519+1.7.3.patch | 1670 ++++++++++++++++++++++++++++ 3 files changed, 1749 insertions(+) create mode 100644 patches/@noble+ed25519+1.7.3.patch diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 3aab27f..a0b34c0 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -21,6 +21,7 @@ "@lumeweb/libhyperproxy": "^0.0.2-develop.2", "@lumeweb/libkernel": "0.1.0-develop.27", "@lumeweb/presetter-kernel-module-preset": "^0.1.0-develop.43", + "@peculiar/webcrypto": "^1.4.3", "blockstore-idb": "^1.1.1", "datastore-core": "^9.2.0", "datastore-idb": "^2.1.2", @@ -3943,6 +3944,42 @@ "@octokit/openapi-types": "^18.0.0" } }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.6.tgz", + "integrity": "sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA==", + "dependencies": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@peculiar/webcrypto": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.3.tgz", + "integrity": "sha512-VtaY4spKTdN5LjJ04im/d/joXuvLbQdgy5Z4DXF4MFZhQ+MTrejbNMkfZBp1Bs3O5+bFqnJgyGdPuZQflvIa5A==", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.6", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.2", + "tslib": "^2.5.0", + "webcrypto-core": "^1.7.7" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -5636,6 +5673,19 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, + "node_modules/asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dependencies": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/assert": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", @@ -19524,6 +19574,22 @@ ], "peer": true }, + "node_modules/pvtsutils": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", + "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -23353,6 +23419,18 @@ "node": ">= 8" } }, + "node_modules/webcrypto-core": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.7.tgz", + "integrity": "sha512-7FjigXNsBfopEj+5DV2nhNpfic2vumtjjgPmeDKk45z+MJwXKKfhPB7118Pfzrmh4jqOMST6Ch37iPAHoImg5g==", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.6", + "@peculiar/json-schema": "^1.1.12", + "asn1js": "^3.0.1", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index 983723d..6a04dfd 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@lumeweb/libhyperproxy": "^0.0.2-develop.2", "@lumeweb/libkernel": "0.1.0-develop.27", "@lumeweb/presetter-kernel-module-preset": "^0.1.0-develop.43", + "@peculiar/webcrypto": "^1.4.3", "blockstore-idb": "^1.1.1", "datastore-core": "^9.2.0", "datastore-idb": "^2.1.2", diff --git a/patches/@noble+ed25519+1.7.3.patch b/patches/@noble+ed25519+1.7.3.patch new file mode 100644 index 0000000..c3c3054 --- /dev/null +++ b/patches/@noble+ed25519+1.7.3.patch @@ -0,0 +1,1670 @@ +diff --git a/node_modules/@noble/ed25519/lib/esm/index.js b/node_modules/@noble/ed25519/lib/esm/index.js +index e617211..c3a04be 100644 +--- a/node_modules/@noble/ed25519/lib/esm/index.js ++++ b/node_modules/@noble/ed25519/lib/esm/index.js +@@ -1,10 +1,21 @@ + /*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ +-import * as nodeCrypto from 'crypto'; +-const _0n = BigInt(0); +-const _1n = BigInt(1); +-const _2n = BigInt(2); +-const _8n = BigInt(8); +-const CU_O = BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'); ++import * as nodeCrypto from 'crypto' ++import { Crypto } from "@peculiar/webcrypto"; ++let globalCrypto = self.crypto; ++if (!globalCrypto.subtle) { ++ let subtleCrypto = new Crypto().subtle; ++ Object.defineProperty(globalCrypto, "subtle", { ++ get() { ++ return subtleCrypto; ++ }, ++ }); ++} ++ ++const _0n = BigInt(0) ++const _1n = BigInt(1) ++const _2n = BigInt(2) ++const _8n = BigInt(8) ++const CU_O = BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989') + const CURVE = Object.freeze({ + a: BigInt(-1), + d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'), +@@ -14,808 +25,907 @@ const CURVE = Object.freeze({ + h: BigInt(8), + Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'), + Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'), +-}); +-export { CURVE }; +-const POW_2_256 = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000'); +-const SQRT_M1 = BigInt('19681161376707505956807079304988542015446066515923890162744021073123829784752'); +-const SQRT_D = BigInt('6853475219497561581579357271197624642482790079785650197046958215289687604742'); +-const SQRT_AD_MINUS_ONE = BigInt('25063068953384623474111414158702152701244531502492656460079210482610430750235'); +-const INVSQRT_A_MINUS_D = BigInt('54469307008909316920995813868745141605393597292927456921205312896311721017578'); +-const ONE_MINUS_D_SQ = BigInt('1159843021668779879193775521855586647937357759715417654439879720876111806838'); +-const D_MINUS_ONE_SQ = BigInt('40440834346308536858101042469323190826248399146238708352240133220865137265952'); ++}) ++export { CURVE } ++const POW_2_256 = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000') ++const SQRT_M1 = BigInt('19681161376707505956807079304988542015446066515923890162744021073123829784752') ++const SQRT_D = BigInt('6853475219497561581579357271197624642482790079785650197046958215289687604742') ++const SQRT_AD_MINUS_ONE = BigInt('25063068953384623474111414158702152701244531502492656460079210482610430750235') ++const INVSQRT_A_MINUS_D = BigInt('54469307008909316920995813868745141605393597292927456921205312896311721017578') ++const ONE_MINUS_D_SQ = BigInt('1159843021668779879193775521855586647937357759715417654439879720876111806838') ++const D_MINUS_ONE_SQ = BigInt('40440834346308536858101042469323190826248399146238708352240133220865137265952') ++ + class ExtendedPoint { +- constructor(x, y, z, t) { +- this.x = x; +- this.y = y; +- this.z = z; +- this.t = t; +- } +- static fromAffine(p) { ++ constructor (x, y, z, t) { ++ this.x = x ++ this.y = y ++ this.z = z ++ this.t = t ++ } ++ ++ static fromAffine (p) { + if (!(p instanceof Point)) { +- throw new TypeError('ExtendedPoint#fromAffine: expected Point'); ++ throw new TypeError('ExtendedPoint#fromAffine: expected Point') + } + if (p.equals(Point.ZERO)) +- return ExtendedPoint.ZERO; +- return new ExtendedPoint(p.x, p.y, _1n, mod(p.x * p.y)); +- } +- static toAffineBatch(points) { +- const toInv = invertBatch(points.map((p) => p.z)); +- return points.map((p, i) => p.toAffine(toInv[i])); +- } +- static normalizeZ(points) { +- return this.toAffineBatch(points).map(this.fromAffine); +- } +- equals(other) { +- assertExtPoint(other); +- const { x: X1, y: Y1, z: Z1 } = this; +- const { x: X2, y: Y2, z: Z2 } = other; +- const X1Z2 = mod(X1 * Z2); +- const X2Z1 = mod(X2 * Z1); +- const Y1Z2 = mod(Y1 * Z2); +- const Y2Z1 = mod(Y2 * Z1); +- return X1Z2 === X2Z1 && Y1Z2 === Y2Z1; +- } +- negate() { +- return new ExtendedPoint(mod(-this.x), this.y, this.z, mod(-this.t)); +- } +- double() { +- const { x: X1, y: Y1, z: Z1 } = this; +- const { a } = CURVE; +- const A = mod(X1 * X1); +- const B = mod(Y1 * Y1); +- const C = mod(_2n * mod(Z1 * Z1)); +- const D = mod(a * A); +- const x1y1 = X1 + Y1; +- const E = mod(mod(x1y1 * x1y1) - A - B); +- const G = D + B; +- const F = G - C; +- const H = D - B; +- const X3 = mod(E * F); +- const Y3 = mod(G * H); +- const T3 = mod(E * H); +- const Z3 = mod(F * G); +- return new ExtendedPoint(X3, Y3, Z3, T3); +- } +- add(other) { +- assertExtPoint(other); +- const { x: X1, y: Y1, z: Z1, t: T1 } = this; +- const { x: X2, y: Y2, z: Z2, t: T2 } = other; +- const A = mod((Y1 - X1) * (Y2 + X2)); +- const B = mod((Y1 + X1) * (Y2 - X2)); +- const F = mod(B - A); ++ return ExtendedPoint.ZERO ++ return new ExtendedPoint(p.x, p.y, _1n, mod(p.x * p.y)) ++ } ++ ++ static toAffineBatch (points) { ++ const toInv = invertBatch(points.map((p) => p.z)) ++ return points.map((p, i) => p.toAffine(toInv[i])) ++ } ++ ++ static normalizeZ (points) { ++ return this.toAffineBatch(points).map(this.fromAffine) ++ } ++ ++ equals (other) { ++ assertExtPoint(other) ++ const { x: X1, y: Y1, z: Z1 } = this ++ const { x: X2, y: Y2, z: Z2 } = other ++ const X1Z2 = mod(X1 * Z2) ++ const X2Z1 = mod(X2 * Z1) ++ const Y1Z2 = mod(Y1 * Z2) ++ const Y2Z1 = mod(Y2 * Z1) ++ return X1Z2 === X2Z1 && Y1Z2 === Y2Z1 ++ } ++ ++ negate () { ++ return new ExtendedPoint(mod(-this.x), this.y, this.z, mod(-this.t)) ++ } ++ ++ double () { ++ const { x: X1, y: Y1, z: Z1 } = this ++ const { a } = CURVE ++ const A = mod(X1 * X1) ++ const B = mod(Y1 * Y1) ++ const C = mod(_2n * mod(Z1 * Z1)) ++ const D = mod(a * A) ++ const x1y1 = X1 + Y1 ++ const E = mod(mod(x1y1 * x1y1) - A - B) ++ const G = D + B ++ const F = G - C ++ const H = D - B ++ const X3 = mod(E * F) ++ const Y3 = mod(G * H) ++ const T3 = mod(E * H) ++ const Z3 = mod(F * G) ++ return new ExtendedPoint(X3, Y3, Z3, T3) ++ } ++ ++ add (other) { ++ assertExtPoint(other) ++ const { x: X1, y: Y1, z: Z1, t: T1 } = this ++ const { x: X2, y: Y2, z: Z2, t: T2 } = other ++ const A = mod((Y1 - X1) * (Y2 + X2)) ++ const B = mod((Y1 + X1) * (Y2 - X2)) ++ const F = mod(B - A) + if (F === _0n) +- return this.double(); +- const C = mod(Z1 * _2n * T2); +- const D = mod(T1 * _2n * Z2); +- const E = D + C; +- const G = B + A; +- const H = D - C; +- const X3 = mod(E * F); +- const Y3 = mod(G * H); +- const T3 = mod(E * H); +- const Z3 = mod(F * G); +- return new ExtendedPoint(X3, Y3, Z3, T3); +- } +- subtract(other) { +- return this.add(other.negate()); +- } +- precomputeWindow(W) { +- const windows = 1 + 256 / W; +- const points = []; +- let p = this; +- let base = p; ++ return this.double() ++ const C = mod(Z1 * _2n * T2) ++ const D = mod(T1 * _2n * Z2) ++ const E = D + C ++ const G = B + A ++ const H = D - C ++ const X3 = mod(E * F) ++ const Y3 = mod(G * H) ++ const T3 = mod(E * H) ++ const Z3 = mod(F * G) ++ return new ExtendedPoint(X3, Y3, Z3, T3) ++ } ++ ++ subtract (other) { ++ return this.add(other.negate()) ++ } ++ ++ precomputeWindow (W) { ++ const windows = 1 + 256 / W ++ const points = [] ++ let p = this ++ let base = p + for (let window = 0; window < windows; window++) { +- base = p; +- points.push(base); ++ base = p ++ points.push(base) + for (let i = 1; i < 2 ** (W - 1); i++) { +- base = base.add(p); +- points.push(base); ++ base = base.add(p) ++ points.push(base) + } +- p = base.double(); ++ p = base.double() + } +- return points; ++ return points + } +- wNAF(n, affinePoint) { ++ ++ wNAF (n, affinePoint) { + if (!affinePoint && this.equals(ExtendedPoint.BASE)) +- affinePoint = Point.BASE; +- const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1; ++ affinePoint = Point.BASE ++ const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1 + if (256 % W) { +- throw new Error('Point#wNAF: Invalid precomputation window, must be power of 2'); ++ throw new Error('Point#wNAF: Invalid precomputation window, must be power of 2') + } +- let precomputes = affinePoint && pointPrecomputes.get(affinePoint); ++ let precomputes = affinePoint && pointPrecomputes.get(affinePoint) + if (!precomputes) { +- precomputes = this.precomputeWindow(W); ++ precomputes = this.precomputeWindow(W) + if (affinePoint && W !== 1) { +- precomputes = ExtendedPoint.normalizeZ(precomputes); +- pointPrecomputes.set(affinePoint, precomputes); ++ precomputes = ExtendedPoint.normalizeZ(precomputes) ++ pointPrecomputes.set(affinePoint, precomputes) + } + } +- let p = ExtendedPoint.ZERO; +- let f = ExtendedPoint.BASE; +- const windows = 1 + 256 / W; +- const windowSize = 2 ** (W - 1); +- const mask = BigInt(2 ** W - 1); +- const maxNumber = 2 ** W; +- const shiftBy = BigInt(W); ++ let p = ExtendedPoint.ZERO ++ let f = ExtendedPoint.BASE ++ const windows = 1 + 256 / W ++ const windowSize = 2 ** (W - 1) ++ const mask = BigInt(2 ** W - 1) ++ const maxNumber = 2 ** W ++ const shiftBy = BigInt(W) + for (let window = 0; window < windows; window++) { +- const offset = window * windowSize; +- let wbits = Number(n & mask); +- n >>= shiftBy; ++ const offset = window * windowSize ++ let wbits = Number(n & mask) ++ n >>= shiftBy + if (wbits > windowSize) { +- wbits -= maxNumber; +- n += _1n; ++ wbits -= maxNumber ++ n += _1n + } +- const offset1 = offset; +- const offset2 = offset + Math.abs(wbits) - 1; +- const cond1 = window % 2 !== 0; +- const cond2 = wbits < 0; ++ const offset1 = offset ++ const offset2 = offset + Math.abs(wbits) - 1 ++ const cond1 = window % 2 !== 0 ++ const cond2 = wbits < 0 + if (wbits === 0) { +- f = f.add(constTimeNegate(cond1, precomputes[offset1])); +- } +- else { +- p = p.add(constTimeNegate(cond2, precomputes[offset2])); ++ f = f.add(constTimeNegate(cond1, precomputes[offset1])) ++ } else { ++ p = p.add(constTimeNegate(cond2, precomputes[offset2])) + } + } +- return ExtendedPoint.normalizeZ([p, f])[0]; ++ return ExtendedPoint.normalizeZ([p, f])[0] + } +- multiply(scalar, affinePoint) { +- return this.wNAF(normalizeScalar(scalar, CURVE.l), affinePoint); ++ ++ multiply (scalar, affinePoint) { ++ return this.wNAF(normalizeScalar(scalar, CURVE.l), affinePoint) + } +- multiplyUnsafe(scalar) { +- let n = normalizeScalar(scalar, CURVE.l, false); +- const G = ExtendedPoint.BASE; +- const P0 = ExtendedPoint.ZERO; ++ ++ multiplyUnsafe (scalar) { ++ let n = normalizeScalar(scalar, CURVE.l, false) ++ const G = ExtendedPoint.BASE ++ const P0 = ExtendedPoint.ZERO + if (n === _0n) +- return P0; ++ return P0 + if (this.equals(P0) || n === _1n) +- return this; ++ return this + if (this.equals(G)) +- return this.wNAF(n); +- let p = P0; +- let d = this; ++ return this.wNAF(n) ++ let p = P0 ++ let d = this + while (n > _0n) { + if (n & _1n) +- p = p.add(d); +- d = d.double(); +- n >>= _1n; ++ p = p.add(d) ++ d = d.double() ++ n >>= _1n + } +- return p; ++ return p + } +- isSmallOrder() { +- return this.multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO); ++ ++ isSmallOrder () { ++ return this.multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO) + } +- isTorsionFree() { +- let p = this.multiplyUnsafe(CURVE.l / _2n).double(); ++ ++ isTorsionFree () { ++ let p = this.multiplyUnsafe(CURVE.l / _2n).double() + if (CURVE.l % _2n) +- p = p.add(this); +- return p.equals(ExtendedPoint.ZERO); ++ p = p.add(this) ++ return p.equals(ExtendedPoint.ZERO) + } +- toAffine(invZ) { +- const { x, y, z } = this; +- const is0 = this.equals(ExtendedPoint.ZERO); ++ ++ toAffine (invZ) { ++ const { x, y, z } = this ++ const is0 = this.equals(ExtendedPoint.ZERO) + if (invZ == null) +- invZ = is0 ? _8n : invert(z); +- const ax = mod(x * invZ); +- const ay = mod(y * invZ); +- const zz = mod(z * invZ); ++ invZ = is0 ? _8n : invert(z) ++ const ax = mod(x * invZ) ++ const ay = mod(y * invZ) ++ const zz = mod(z * invZ) + if (is0) +- return Point.ZERO; ++ return Point.ZERO + if (zz !== _1n) +- throw new Error('invZ was invalid'); +- return new Point(ax, ay); ++ throw new Error('invZ was invalid') ++ return new Point(ax, ay) + } +- fromRistrettoBytes() { +- legacyRist(); ++ ++ fromRistrettoBytes () { ++ legacyRist() + } +- toRistrettoBytes() { +- legacyRist(); ++ ++ toRistrettoBytes () { ++ legacyRist() + } +- fromRistrettoHash() { +- legacyRist(); ++ ++ fromRistrettoHash () { ++ legacyRist() + } + } +-ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, mod(CURVE.Gx * CURVE.Gy)); +-ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n); +-function constTimeNegate(condition, item) { +- const neg = item.negate(); +- return condition ? neg : item; ++ ++ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, mod(CURVE.Gx * CURVE.Gy)) ++ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n) ++ ++function constTimeNegate (condition, item) { ++ const neg = item.negate() ++ return condition ? neg : item + } +-function assertExtPoint(other) { ++ ++function assertExtPoint (other) { + if (!(other instanceof ExtendedPoint)) +- throw new TypeError('ExtendedPoint expected'); ++ throw new TypeError('ExtendedPoint expected') + } +-function assertRstPoint(other) { ++ ++function assertRstPoint (other) { + if (!(other instanceof RistrettoPoint)) +- throw new TypeError('RistrettoPoint expected'); ++ throw new TypeError('RistrettoPoint expected') + } +-function legacyRist() { +- throw new Error('Legacy method: switch to RistrettoPoint'); ++ ++function legacyRist () { ++ throw new Error('Legacy method: switch to RistrettoPoint') + } ++ + class RistrettoPoint { +- constructor(ep) { +- this.ep = ep; +- } +- static calcElligatorRistrettoMap(r0) { +- const { d } = CURVE; +- const r = mod(SQRT_M1 * r0 * r0); +- const Ns = mod((r + _1n) * ONE_MINUS_D_SQ); +- let c = BigInt(-1); +- const D = mod((c - d * r) * mod(r + d)); +- let { isValid: Ns_D_is_sq, value: s } = uvRatio(Ns, D); +- let s_ = mod(s * r0); ++ constructor (ep) { ++ this.ep = ep ++ } ++ ++ static calcElligatorRistrettoMap (r0) { ++ const { d } = CURVE ++ const r = mod(SQRT_M1 * r0 * r0) ++ const Ns = mod((r + _1n) * ONE_MINUS_D_SQ) ++ let c = BigInt(-1) ++ const D = mod((c - d * r) * mod(r + d)) ++ let { isValid: Ns_D_is_sq, value: s } = uvRatio(Ns, D) ++ let s_ = mod(s * r0) + if (!edIsNegative(s_)) +- s_ = mod(-s_); ++ s_ = mod(-s_) + if (!Ns_D_is_sq) +- s = s_; ++ s = s_ + if (!Ns_D_is_sq) +- c = r; +- const Nt = mod(c * (r - _1n) * D_MINUS_ONE_SQ - D); +- const s2 = s * s; +- const W0 = mod((s + s) * D); +- const W1 = mod(Nt * SQRT_AD_MINUS_ONE); +- const W2 = mod(_1n - s2); +- const W3 = mod(_1n + s2); +- return new ExtendedPoint(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2)); +- } +- static hashToCurve(hex) { +- hex = ensureBytes(hex, 64); +- const r1 = bytes255ToNumberLE(hex.slice(0, 32)); +- const R1 = this.calcElligatorRistrettoMap(r1); +- const r2 = bytes255ToNumberLE(hex.slice(32, 64)); +- const R2 = this.calcElligatorRistrettoMap(r2); +- return new RistrettoPoint(R1.add(R2)); +- } +- static fromHex(hex) { +- hex = ensureBytes(hex, 32); +- const { a, d } = CURVE; +- const emsg = 'RistrettoPoint.fromHex: the hex is not valid encoding of RistrettoPoint'; +- const s = bytes255ToNumberLE(hex); ++ c = r ++ const Nt = mod(c * (r - _1n) * D_MINUS_ONE_SQ - D) ++ const s2 = s * s ++ const W0 = mod((s + s) * D) ++ const W1 = mod(Nt * SQRT_AD_MINUS_ONE) ++ const W2 = mod(_1n - s2) ++ const W3 = mod(_1n + s2) ++ return new ExtendedPoint(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2)) ++ } ++ ++ static hashToCurve (hex) { ++ hex = ensureBytes(hex, 64) ++ const r1 = bytes255ToNumberLE(hex.slice(0, 32)) ++ const R1 = this.calcElligatorRistrettoMap(r1) ++ const r2 = bytes255ToNumberLE(hex.slice(32, 64)) ++ const R2 = this.calcElligatorRistrettoMap(r2) ++ return new RistrettoPoint(R1.add(R2)) ++ } ++ ++ static fromHex (hex) { ++ hex = ensureBytes(hex, 32) ++ const { a, d } = CURVE ++ const emsg = 'RistrettoPoint.fromHex: the hex is not valid encoding of RistrettoPoint' ++ const s = bytes255ToNumberLE(hex) + if (!equalBytes(numberTo32BytesLE(s), hex) || edIsNegative(s)) +- throw new Error(emsg); +- const s2 = mod(s * s); +- const u1 = mod(_1n + a * s2); +- const u2 = mod(_1n - a * s2); +- const u1_2 = mod(u1 * u1); +- const u2_2 = mod(u2 * u2); +- const v = mod(a * d * u1_2 - u2_2); +- const { isValid, value: I } = invertSqrt(mod(v * u2_2)); +- const Dx = mod(I * u2); +- const Dy = mod(I * Dx * v); +- let x = mod((s + s) * Dx); ++ throw new Error(emsg) ++ const s2 = mod(s * s) ++ const u1 = mod(_1n + a * s2) ++ const u2 = mod(_1n - a * s2) ++ const u1_2 = mod(u1 * u1) ++ const u2_2 = mod(u2 * u2) ++ const v = mod(a * d * u1_2 - u2_2) ++ const { isValid, value: I } = invertSqrt(mod(v * u2_2)) ++ const Dx = mod(I * u2) ++ const Dy = mod(I * Dx * v) ++ let x = mod((s + s) * Dx) + if (edIsNegative(x)) +- x = mod(-x); +- const y = mod(u1 * Dy); +- const t = mod(x * y); ++ x = mod(-x) ++ const y = mod(u1 * Dy) ++ const t = mod(x * y) + if (!isValid || edIsNegative(t) || y === _0n) +- throw new Error(emsg); +- return new RistrettoPoint(new ExtendedPoint(x, y, _1n, t)); +- } +- toRawBytes() { +- let { x, y, z, t } = this.ep; +- const u1 = mod(mod(z + y) * mod(z - y)); +- const u2 = mod(x * y); +- const u2sq = mod(u2 * u2); +- const { value: invsqrt } = invertSqrt(mod(u1 * u2sq)); +- const D1 = mod(invsqrt * u1); +- const D2 = mod(invsqrt * u2); +- const zInv = mod(D1 * D2 * t); +- let D; ++ throw new Error(emsg) ++ return new RistrettoPoint(new ExtendedPoint(x, y, _1n, t)) ++ } ++ ++ toRawBytes () { ++ let { x, y, z, t } = this.ep ++ const u1 = mod(mod(z + y) * mod(z - y)) ++ const u2 = mod(x * y) ++ const u2sq = mod(u2 * u2) ++ const { value: invsqrt } = invertSqrt(mod(u1 * u2sq)) ++ const D1 = mod(invsqrt * u1) ++ const D2 = mod(invsqrt * u2) ++ const zInv = mod(D1 * D2 * t) ++ let D + if (edIsNegative(t * zInv)) { +- let _x = mod(y * SQRT_M1); +- let _y = mod(x * SQRT_M1); +- x = _x; +- y = _y; +- D = mod(D1 * INVSQRT_A_MINUS_D); +- } +- else { +- D = D2; ++ let _x = mod(y * SQRT_M1) ++ let _y = mod(x * SQRT_M1) ++ x = _x ++ y = _y ++ D = mod(D1 * INVSQRT_A_MINUS_D) ++ } else { ++ D = D2 + } + if (edIsNegative(x * zInv)) +- y = mod(-y); +- let s = mod((z - y) * D); ++ y = mod(-y) ++ let s = mod((z - y) * D) + if (edIsNegative(s)) +- s = mod(-s); +- return numberTo32BytesLE(s); +- } +- toHex() { +- return bytesToHex(this.toRawBytes()); +- } +- toString() { +- return this.toHex(); +- } +- equals(other) { +- assertRstPoint(other); +- const a = this.ep; +- const b = other.ep; +- const one = mod(a.x * b.y) === mod(a.y * b.x); +- const two = mod(a.y * b.y) === mod(a.x * b.x); +- return one || two; +- } +- add(other) { +- assertRstPoint(other); +- return new RistrettoPoint(this.ep.add(other.ep)); +- } +- subtract(other) { +- assertRstPoint(other); +- return new RistrettoPoint(this.ep.subtract(other.ep)); +- } +- multiply(scalar) { +- return new RistrettoPoint(this.ep.multiply(scalar)); +- } +- multiplyUnsafe(scalar) { +- return new RistrettoPoint(this.ep.multiplyUnsafe(scalar)); +- } +-} +-RistrettoPoint.BASE = new RistrettoPoint(ExtendedPoint.BASE); +-RistrettoPoint.ZERO = new RistrettoPoint(ExtendedPoint.ZERO); +-const pointPrecomputes = new WeakMap(); ++ s = mod(-s) ++ return numberTo32BytesLE(s) ++ } ++ ++ toHex () { ++ return bytesToHex(this.toRawBytes()) ++ } ++ ++ toString () { ++ return this.toHex() ++ } ++ ++ equals (other) { ++ assertRstPoint(other) ++ const a = this.ep ++ const b = other.ep ++ const one = mod(a.x * b.y) === mod(a.y * b.x) ++ const two = mod(a.y * b.y) === mod(a.x * b.x) ++ return one || two ++ } ++ ++ add (other) { ++ assertRstPoint(other) ++ return new RistrettoPoint(this.ep.add(other.ep)) ++ } ++ ++ subtract (other) { ++ assertRstPoint(other) ++ return new RistrettoPoint(this.ep.subtract(other.ep)) ++ } ++ ++ multiply (scalar) { ++ return new RistrettoPoint(this.ep.multiply(scalar)) ++ } ++ ++ multiplyUnsafe (scalar) { ++ return new RistrettoPoint(this.ep.multiplyUnsafe(scalar)) ++ } ++} ++ ++RistrettoPoint.BASE = new RistrettoPoint(ExtendedPoint.BASE) ++RistrettoPoint.ZERO = new RistrettoPoint(ExtendedPoint.ZERO) ++const pointPrecomputes = new WeakMap() ++ + class Point { +- constructor(x, y) { +- this.x = x; +- this.y = y; +- } +- _setWindowSize(windowSize) { +- this._WINDOW_SIZE = windowSize; +- pointPrecomputes.delete(this); +- } +- static fromHex(hex, strict = true) { +- const { d, P } = CURVE; +- hex = ensureBytes(hex, 32); +- const normed = hex.slice(); +- normed[31] = hex[31] & ~0x80; +- const y = bytesToNumberLE(normed); ++ constructor (x, y) { ++ this.x = x ++ this.y = y ++ } ++ ++ _setWindowSize (windowSize) { ++ this._WINDOW_SIZE = windowSize ++ pointPrecomputes.delete(this) ++ } ++ ++ static fromHex (hex, strict = true) { ++ const { d, P } = CURVE ++ hex = ensureBytes(hex, 32) ++ const normed = hex.slice() ++ normed[31] = hex[31] & ~0x80 ++ const y = bytesToNumberLE(normed) + if (strict && y >= P) +- throw new Error('Expected 0 < hex < P'); ++ throw new Error('Expected 0 < hex < P') + if (!strict && y >= POW_2_256) +- throw new Error('Expected 0 < hex < 2**256'); +- const y2 = mod(y * y); +- const u = mod(y2 - _1n); +- const v = mod(d * y2 + _1n); +- let { isValid, value: x } = uvRatio(u, v); ++ throw new Error('Expected 0 < hex < 2**256') ++ const y2 = mod(y * y) ++ const u = mod(y2 - _1n) ++ const v = mod(d * y2 + _1n) ++ let { isValid, value: x } = uvRatio(u, v) + if (!isValid) +- throw new Error('Point.fromHex: invalid y coordinate'); +- const isXOdd = (x & _1n) === _1n; +- const isLastByteOdd = (hex[31] & 0x80) !== 0; ++ throw new Error('Point.fromHex: invalid y coordinate') ++ const isXOdd = (x & _1n) === _1n ++ const isLastByteOdd = (hex[31] & 0x80) !== 0 + if (isLastByteOdd !== isXOdd) { +- x = mod(-x); ++ x = mod(-x) + } +- return new Point(x, y); ++ return new Point(x, y) + } +- static async fromPrivateKey(privateKey) { +- return (await getExtendedPublicKey(privateKey)).point; ++ ++ static async fromPrivateKey (privateKey) { ++ return (await getExtendedPublicKey(privateKey)).point + } +- toRawBytes() { +- const bytes = numberTo32BytesLE(this.y); +- bytes[31] |= this.x & _1n ? 0x80 : 0; +- return bytes; ++ ++ toRawBytes () { ++ const bytes = numberTo32BytesLE(this.y) ++ bytes[31] |= this.x & _1n ? 0x80 : 0 ++ return bytes + } +- toHex() { +- return bytesToHex(this.toRawBytes()); ++ ++ toHex () { ++ return bytesToHex(this.toRawBytes()) + } +- toX25519() { +- const { y } = this; +- const u = mod((_1n + y) * invert(_1n - y)); +- return numberTo32BytesLE(u); ++ ++ toX25519 () { ++ const { y } = this ++ const u = mod((_1n + y) * invert(_1n - y)) ++ return numberTo32BytesLE(u) + } +- isTorsionFree() { +- return ExtendedPoint.fromAffine(this).isTorsionFree(); ++ ++ isTorsionFree () { ++ return ExtendedPoint.fromAffine(this).isTorsionFree() + } +- equals(other) { +- return this.x === other.x && this.y === other.y; ++ ++ equals (other) { ++ return this.x === other.x && this.y === other.y + } +- negate() { +- return new Point(mod(-this.x), this.y); ++ ++ negate () { ++ return new Point(mod(-this.x), this.y) + } +- add(other) { +- return ExtendedPoint.fromAffine(this).add(ExtendedPoint.fromAffine(other)).toAffine(); ++ ++ add (other) { ++ return ExtendedPoint.fromAffine(this).add(ExtendedPoint.fromAffine(other)).toAffine() + } +- subtract(other) { +- return this.add(other.negate()); ++ ++ subtract (other) { ++ return this.add(other.negate()) + } +- multiply(scalar) { +- return ExtendedPoint.fromAffine(this).multiply(scalar, this).toAffine(); ++ ++ multiply (scalar) { ++ return ExtendedPoint.fromAffine(this).multiply(scalar, this).toAffine() + } + } +-Point.BASE = new Point(CURVE.Gx, CURVE.Gy); +-Point.ZERO = new Point(_0n, _1n); ++ ++Point.BASE = new Point(CURVE.Gx, CURVE.Gy) ++Point.ZERO = new Point(_0n, _1n) ++ + class Signature { +- constructor(r, s) { +- this.r = r; +- this.s = s; +- this.assertValidity(); +- } +- static fromHex(hex) { +- const bytes = ensureBytes(hex, 64); +- const r = Point.fromHex(bytes.slice(0, 32), false); +- const s = bytesToNumberLE(bytes.slice(32, 64)); +- return new Signature(r, s); +- } +- assertValidity() { +- const { r, s } = this; ++ constructor (r, s) { ++ this.r = r ++ this.s = s ++ this.assertValidity() ++ } ++ ++ static fromHex (hex) { ++ const bytes = ensureBytes(hex, 64) ++ const r = Point.fromHex(bytes.slice(0, 32), false) ++ const s = bytesToNumberLE(bytes.slice(32, 64)) ++ return new Signature(r, s) ++ } ++ ++ assertValidity () { ++ const { r, s } = this + if (!(r instanceof Point)) +- throw new Error('Expected Point instance'); +- normalizeScalar(s, CURVE.l, false); +- return this; +- } +- toRawBytes() { +- const u8 = new Uint8Array(64); +- u8.set(this.r.toRawBytes()); +- u8.set(numberTo32BytesLE(this.s), 32); +- return u8; +- } +- toHex() { +- return bytesToHex(this.toRawBytes()); +- } +-} +-export { ExtendedPoint, RistrettoPoint, Point, Signature }; +-function concatBytes(...arrays) { ++ throw new Error('Expected Point instance') ++ normalizeScalar(s, CURVE.l, false) ++ return this ++ } ++ ++ toRawBytes () { ++ const u8 = new Uint8Array(64) ++ u8.set(this.r.toRawBytes()) ++ u8.set(numberTo32BytesLE(this.s), 32) ++ return u8 ++ } ++ ++ toHex () { ++ return bytesToHex(this.toRawBytes()) ++ } ++} ++ ++export { ExtendedPoint, RistrettoPoint, Point, Signature } ++ ++function concatBytes (...arrays) { + if (!arrays.every((a) => a instanceof Uint8Array)) +- throw new Error('Expected Uint8Array list'); ++ throw new Error('Expected Uint8Array list') + if (arrays.length === 1) +- return arrays[0]; +- const length = arrays.reduce((a, arr) => a + arr.length, 0); +- const result = new Uint8Array(length); ++ return arrays[0] ++ const length = arrays.reduce((a, arr) => a + arr.length, 0) ++ const result = new Uint8Array(length) + for (let i = 0, pad = 0; i < arrays.length; i++) { +- const arr = arrays[i]; +- result.set(arr, pad); +- pad += arr.length; ++ const arr = arrays[i] ++ result.set(arr, pad) ++ pad += arr.length + } +- return result; ++ return result + } +-const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0')); +-function bytesToHex(uint8a) { ++ ++const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0')) ++ ++function bytesToHex (uint8a) { + if (!(uint8a instanceof Uint8Array)) +- throw new Error('Uint8Array expected'); +- let hex = ''; ++ throw new Error('Uint8Array expected') ++ let hex = '' + for (let i = 0; i < uint8a.length; i++) { +- hex += hexes[uint8a[i]]; ++ hex += hexes[uint8a[i]] + } +- return hex; ++ return hex + } +-function hexToBytes(hex) { ++ ++function hexToBytes (hex) { + if (typeof hex !== 'string') { +- throw new TypeError('hexToBytes: expected string, got ' + typeof hex); ++ throw new TypeError('hexToBytes: expected string, got ' + typeof hex) + } + if (hex.length % 2) +- throw new Error('hexToBytes: received invalid unpadded hex'); +- const array = new Uint8Array(hex.length / 2); ++ throw new Error('hexToBytes: received invalid unpadded hex') ++ const array = new Uint8Array(hex.length / 2) + for (let i = 0; i < array.length; i++) { +- const j = i * 2; +- const hexByte = hex.slice(j, j + 2); +- const byte = Number.parseInt(hexByte, 16); ++ const j = i * 2 ++ const hexByte = hex.slice(j, j + 2) ++ const byte = Number.parseInt(hexByte, 16) + if (Number.isNaN(byte) || byte < 0) +- throw new Error('Invalid byte sequence'); +- array[i] = byte; ++ throw new Error('Invalid byte sequence') ++ array[i] = byte + } +- return array; ++ return array + } +-function numberTo32BytesBE(num) { +- const length = 32; +- const hex = num.toString(16).padStart(length * 2, '0'); +- return hexToBytes(hex); ++ ++function numberTo32BytesBE (num) { ++ const length = 32 ++ const hex = num.toString(16).padStart(length * 2, '0') ++ return hexToBytes(hex) + } +-function numberTo32BytesLE(num) { +- return numberTo32BytesBE(num).reverse(); ++ ++function numberTo32BytesLE (num) { ++ return numberTo32BytesBE(num).reverse() + } +-function edIsNegative(num) { +- return (mod(num) & _1n) === _1n; ++ ++function edIsNegative (num) { ++ return (mod(num) & _1n) === _1n + } +-function bytesToNumberLE(uint8a) { ++ ++function bytesToNumberLE (uint8a) { + if (!(uint8a instanceof Uint8Array)) +- throw new Error('Expected Uint8Array'); +- return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a).reverse())); +-} +-const MAX_255B = BigInt('0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'); +-function bytes255ToNumberLE(bytes) { +- return mod(bytesToNumberLE(bytes) & MAX_255B); +-} +-function mod(a, b = CURVE.P) { +- const res = a % b; +- return res >= _0n ? res : b + res; +-} +-function invert(number, modulo = CURVE.P) { ++ throw new Error('Expected Uint8Array') ++ return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a).reverse())) ++} ++ ++const MAX_255B = BigInt('0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') ++ ++function bytes255ToNumberLE (bytes) { ++ return mod(bytesToNumberLE(bytes) & MAX_255B) ++} ++ ++function mod (a, b = CURVE.P) { ++ const res = a % b ++ return res >= _0n ? res : b + res ++} ++ ++function invert (number, modulo = CURVE.P) { + if (number === _0n || modulo <= _0n) { +- throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`); ++ throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`) + } +- let a = mod(number, modulo); +- let b = modulo; +- let x = _0n, y = _1n, u = _1n, v = _0n; ++ let a = mod(number, modulo) ++ let b = modulo ++ let x = _0n, y = _1n, u = _1n, v = _0n + while (a !== _0n) { +- const q = b / a; +- const r = b % a; +- const m = x - u * q; +- const n = y - v * q; +- b = a, a = r, x = u, y = v, u = m, v = n; ++ const q = b / a ++ const r = b % a ++ const m = x - u * q ++ const n = y - v * q ++ b = a, a = r, x = u, y = v, u = m, v = n + } +- const gcd = b; ++ const gcd = b + if (gcd !== _1n) +- throw new Error('invert: does not exist'); +- return mod(x, modulo); ++ throw new Error('invert: does not exist') ++ return mod(x, modulo) + } +-function invertBatch(nums, p = CURVE.P) { +- const tmp = new Array(nums.length); ++ ++function invertBatch (nums, p = CURVE.P) { ++ const tmp = new Array(nums.length) + const lastMultiplied = nums.reduce((acc, num, i) => { + if (num === _0n) +- return acc; +- tmp[i] = acc; +- return mod(acc * num, p); +- }, _1n); +- const inverted = invert(lastMultiplied, p); ++ return acc ++ tmp[i] = acc ++ return mod(acc * num, p) ++ }, _1n) ++ const inverted = invert(lastMultiplied, p) + nums.reduceRight((acc, num, i) => { + if (num === _0n) +- return acc; +- tmp[i] = mod(acc * tmp[i], p); +- return mod(acc * num, p); +- }, inverted); +- return tmp; +-} +-function pow2(x, power) { +- const { P } = CURVE; +- let res = x; ++ return acc ++ tmp[i] = mod(acc * tmp[i], p) ++ return mod(acc * num, p) ++ }, inverted) ++ return tmp ++} ++ ++function pow2 (x, power) { ++ const { P } = CURVE ++ let res = x + while (power-- > _0n) { +- res *= res; +- res %= P; +- } +- return res; +-} +-function pow_2_252_3(x) { +- const { P } = CURVE; +- const _5n = BigInt(5); +- const _10n = BigInt(10); +- const _20n = BigInt(20); +- const _40n = BigInt(40); +- const _80n = BigInt(80); +- const x2 = (x * x) % P; +- const b2 = (x2 * x) % P; +- const b4 = (pow2(b2, _2n) * b2) % P; +- const b5 = (pow2(b4, _1n) * x) % P; +- const b10 = (pow2(b5, _5n) * b5) % P; +- const b20 = (pow2(b10, _10n) * b10) % P; +- const b40 = (pow2(b20, _20n) * b20) % P; +- const b80 = (pow2(b40, _40n) * b40) % P; +- const b160 = (pow2(b80, _80n) * b80) % P; +- const b240 = (pow2(b160, _80n) * b80) % P; +- const b250 = (pow2(b240, _10n) * b10) % P; +- const pow_p_5_8 = (pow2(b250, _2n) * x) % P; +- return { pow_p_5_8, b2 }; +-} +-function uvRatio(u, v) { +- const v3 = mod(v * v * v); +- const v7 = mod(v3 * v3 * v); +- const pow = pow_2_252_3(u * v7).pow_p_5_8; +- let x = mod(u * v3 * pow); +- const vx2 = mod(v * x * x); +- const root1 = x; +- const root2 = mod(x * SQRT_M1); +- const useRoot1 = vx2 === u; +- const useRoot2 = vx2 === mod(-u); +- const noRoot = vx2 === mod(-u * SQRT_M1); ++ res *= res ++ res %= P ++ } ++ return res ++} ++ ++function pow_2_252_3 (x) { ++ const { P } = CURVE ++ const _5n = BigInt(5) ++ const _10n = BigInt(10) ++ const _20n = BigInt(20) ++ const _40n = BigInt(40) ++ const _80n = BigInt(80) ++ const x2 = (x * x) % P ++ const b2 = (x2 * x) % P ++ const b4 = (pow2(b2, _2n) * b2) % P ++ const b5 = (pow2(b4, _1n) * x) % P ++ const b10 = (pow2(b5, _5n) * b5) % P ++ const b20 = (pow2(b10, _10n) * b10) % P ++ const b40 = (pow2(b20, _20n) * b20) % P ++ const b80 = (pow2(b40, _40n) * b40) % P ++ const b160 = (pow2(b80, _80n) * b80) % P ++ const b240 = (pow2(b160, _80n) * b80) % P ++ const b250 = (pow2(b240, _10n) * b10) % P ++ const pow_p_5_8 = (pow2(b250, _2n) * x) % P ++ return { pow_p_5_8, b2 } ++} ++ ++function uvRatio (u, v) { ++ const v3 = mod(v * v * v) ++ const v7 = mod(v3 * v3 * v) ++ const pow = pow_2_252_3(u * v7).pow_p_5_8 ++ let x = mod(u * v3 * pow) ++ const vx2 = mod(v * x * x) ++ const root1 = x ++ const root2 = mod(x * SQRT_M1) ++ const useRoot1 = vx2 === u ++ const useRoot2 = vx2 === mod(-u) ++ const noRoot = vx2 === mod(-u * SQRT_M1) + if (useRoot1) +- x = root1; ++ x = root1 + if (useRoot2 || noRoot) +- x = root2; ++ x = root2 + if (edIsNegative(x)) +- x = mod(-x); +- return { isValid: useRoot1 || useRoot2, value: x }; ++ x = mod(-x) ++ return { isValid: useRoot1 || useRoot2, value: x } + } +-function invertSqrt(number) { +- return uvRatio(_1n, number); ++ ++function invertSqrt (number) { ++ return uvRatio(_1n, number) + } +-function modlLE(hash) { +- return mod(bytesToNumberLE(hash), CURVE.l); ++ ++function modlLE (hash) { ++ return mod(bytesToNumberLE(hash), CURVE.l) + } +-function equalBytes(b1, b2) { ++ ++function equalBytes (b1, b2) { + if (b1.length !== b2.length) { +- return false; ++ return false + } + for (let i = 0; i < b1.length; i++) { + if (b1[i] !== b2[i]) { +- return false; ++ return false + } + } +- return true; ++ return true + } +-function ensureBytes(hex, expectedLength) { +- const bytes = hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex); ++ ++function ensureBytes (hex, expectedLength) { ++ const bytes = hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex) + if (typeof expectedLength === 'number' && bytes.length !== expectedLength) +- throw new Error(`Expected ${expectedLength} bytes`); +- return bytes; ++ throw new Error(`Expected ${expectedLength} bytes`) ++ return bytes + } +-function normalizeScalar(num, max, strict = true) { ++ ++function normalizeScalar (num, max, strict = true) { + if (!max) +- throw new TypeError('Specify max value'); ++ throw new TypeError('Specify max value') + if (typeof num === 'number' && Number.isSafeInteger(num)) +- num = BigInt(num); ++ num = BigInt(num) + if (typeof num === 'bigint' && num < max) { + if (strict) { + if (_0n < num) +- return num; +- } +- else { ++ return num ++ } else { + if (_0n <= num) +- return num; ++ return num + } + } +- throw new TypeError('Expected valid scalar: 0 < scalar < max'); ++ throw new TypeError('Expected valid scalar: 0 < scalar < max') + } +-function adjustBytes25519(bytes) { +- bytes[0] &= 248; +- bytes[31] &= 127; +- bytes[31] |= 64; +- return bytes; ++ ++function adjustBytes25519 (bytes) { ++ bytes[0] &= 248 ++ bytes[31] &= 127 ++ bytes[31] |= 64 ++ return bytes + } +-function decodeScalar25519(n) { +- return bytesToNumberLE(adjustBytes25519(ensureBytes(n, 32))); ++ ++function decodeScalar25519 (n) { ++ return bytesToNumberLE(adjustBytes25519(ensureBytes(n, 32))) + } +-function checkPrivateKey(key) { ++ ++function checkPrivateKey (key) { + key = + typeof key === 'bigint' || typeof key === 'number' + ? numberTo32BytesBE(normalizeScalar(key, POW_2_256)) +- : ensureBytes(key); ++ : ensureBytes(key) + if (key.length !== 32) +- throw new Error(`Expected 32 bytes`); +- return key; +-} +-function getKeyFromHash(hashed) { +- const head = adjustBytes25519(hashed.slice(0, 32)); +- const prefix = hashed.slice(32, 64); +- const scalar = modlLE(head); +- const point = Point.BASE.multiply(scalar); +- const pointBytes = point.toRawBytes(); +- return { head, prefix, scalar, point, pointBytes }; +-} +-let _sha512Sync; +-function sha512s(...m) { ++ throw new Error(`Expected 32 bytes`) ++ return key ++} ++ ++function getKeyFromHash (hashed) { ++ const head = adjustBytes25519(hashed.slice(0, 32)) ++ const prefix = hashed.slice(32, 64) ++ const scalar = modlLE(head) ++ const point = Point.BASE.multiply(scalar) ++ const pointBytes = point.toRawBytes() ++ return { head, prefix, scalar, point, pointBytes } ++} ++ ++let _sha512Sync ++ ++function sha512s (...m) { + if (typeof _sha512Sync !== 'function') +- throw new Error('utils.sha512Sync must be set to use sync methods'); +- return _sha512Sync(...m); +-} +-async function getExtendedPublicKey(key) { +- return getKeyFromHash(await utils.sha512(checkPrivateKey(key))); +-} +-function getExtendedPublicKeySync(key) { +- return getKeyFromHash(sha512s(checkPrivateKey(key))); +-} +-export async function getPublicKey(privateKey) { +- return (await getExtendedPublicKey(privateKey)).pointBytes; +-} +-function getPublicKeySync(privateKey) { +- return getExtendedPublicKeySync(privateKey).pointBytes; +-} +-export async function sign(message, privateKey) { +- message = ensureBytes(message); +- const { prefix, scalar, pointBytes } = await getExtendedPublicKey(privateKey); +- const r = modlLE(await utils.sha512(prefix, message)); +- const R = Point.BASE.multiply(r); +- const k = modlLE(await utils.sha512(R.toRawBytes(), pointBytes, message)); +- const s = mod(r + k * scalar, CURVE.l); +- return new Signature(R, s).toRawBytes(); +-} +-function signSync(message, privateKey) { +- message = ensureBytes(message); +- const { prefix, scalar, pointBytes } = getExtendedPublicKeySync(privateKey); +- const r = modlLE(sha512s(prefix, message)); +- const R = Point.BASE.multiply(r); +- const k = modlLE(sha512s(R.toRawBytes(), pointBytes, message)); +- const s = mod(r + k * scalar, CURVE.l); +- return new Signature(R, s).toRawBytes(); +-} +-function prepareVerification(sig, message, publicKey) { +- message = ensureBytes(message); ++ throw new Error('utils.sha512Sync must be set to use sync methods') ++ return _sha512Sync(...m) ++} ++ ++async function getExtendedPublicKey (key) { ++ return getKeyFromHash(await utils.sha512(checkPrivateKey(key))) ++} ++ ++function getExtendedPublicKeySync (key) { ++ return getKeyFromHash(sha512s(checkPrivateKey(key))) ++} ++ ++export async function getPublicKey (privateKey) { ++ return (await getExtendedPublicKey(privateKey)).pointBytes ++} ++ ++function getPublicKeySync (privateKey) { ++ return getExtendedPublicKeySync(privateKey).pointBytes ++} ++ ++export async function sign (message, privateKey) { ++ message = ensureBytes(message) ++ const { prefix, scalar, pointBytes } = await getExtendedPublicKey(privateKey) ++ const r = modlLE(await utils.sha512(prefix, message)) ++ const R = Point.BASE.multiply(r) ++ const k = modlLE(await utils.sha512(R.toRawBytes(), pointBytes, message)) ++ const s = mod(r + k * scalar, CURVE.l) ++ return new Signature(R, s).toRawBytes() ++} ++ ++function signSync (message, privateKey) { ++ message = ensureBytes(message) ++ const { prefix, scalar, pointBytes } = getExtendedPublicKeySync(privateKey) ++ const r = modlLE(sha512s(prefix, message)) ++ const R = Point.BASE.multiply(r) ++ const k = modlLE(sha512s(R.toRawBytes(), pointBytes, message)) ++ const s = mod(r + k * scalar, CURVE.l) ++ return new Signature(R, s).toRawBytes() ++} ++ ++function prepareVerification (sig, message, publicKey) { ++ message = ensureBytes(message) + if (!(publicKey instanceof Point)) +- publicKey = Point.fromHex(publicKey, false); +- const { r, s } = sig instanceof Signature ? sig.assertValidity() : Signature.fromHex(sig); +- const SB = ExtendedPoint.BASE.multiplyUnsafe(s); +- return { r, s, SB, pub: publicKey, msg: message }; +-} +-function finishVerification(publicKey, r, SB, hashed) { +- const k = modlLE(hashed); +- const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k); +- const RkA = ExtendedPoint.fromAffine(r).add(kA); +- return RkA.subtract(SB).multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO); +-} +-export async function verify(sig, message, publicKey) { +- const { r, SB, msg, pub } = prepareVerification(sig, message, publicKey); +- const hashed = await utils.sha512(r.toRawBytes(), pub.toRawBytes(), msg); +- return finishVerification(pub, r, SB, hashed); +-} +-function verifySync(sig, message, publicKey) { +- const { r, SB, msg, pub } = prepareVerification(sig, message, publicKey); +- const hashed = sha512s(r.toRawBytes(), pub.toRawBytes(), msg); +- return finishVerification(pub, r, SB, hashed); +-} ++ publicKey = Point.fromHex(publicKey, false) ++ const { r, s } = sig instanceof Signature ? sig.assertValidity() : Signature.fromHex(sig) ++ const SB = ExtendedPoint.BASE.multiplyUnsafe(s) ++ return { r, s, SB, pub: publicKey, msg: message } ++} ++ ++function finishVerification (publicKey, r, SB, hashed) { ++ const k = modlLE(hashed) ++ const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k) ++ const RkA = ExtendedPoint.fromAffine(r).add(kA) ++ return RkA.subtract(SB).multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO) ++} ++ ++export async function verify (sig, message, publicKey) { ++ const { r, SB, msg, pub } = prepareVerification(sig, message, publicKey) ++ const hashed = await utils.sha512(r.toRawBytes(), pub.toRawBytes(), msg) ++ return finishVerification(pub, r, SB, hashed) ++} ++ ++function verifySync (sig, message, publicKey) { ++ const { r, SB, msg, pub } = prepareVerification(sig, message, publicKey) ++ const hashed = sha512s(r.toRawBytes(), pub.toRawBytes(), msg) ++ return finishVerification(pub, r, SB, hashed) ++} ++ + export const sync = { + getExtendedPublicKey: getExtendedPublicKeySync, + getPublicKey: getPublicKeySync, + sign: signSync, + verify: verifySync, +-}; +-export async function getSharedSecret(privateKey, publicKey) { +- const { head } = await getExtendedPublicKey(privateKey); +- const u = Point.fromHex(publicKey).toX25519(); +- return curve25519.scalarMult(head, u); +-} +-Point.BASE._setWindowSize(8); +-function cswap(swap, x_2, x_3) { +- const dummy = mod(swap * (x_2 - x_3)); +- x_2 = mod(x_2 - dummy); +- x_3 = mod(x_3 + dummy); +- return [x_2, x_3]; +-} +-function montgomeryLadder(pointU, scalar) { +- const { P } = CURVE; +- const u = normalizeScalar(pointU, P); +- const k = normalizeScalar(scalar, P); +- const a24 = BigInt(121665); +- const x_1 = u; +- let x_2 = _1n; +- let z_2 = _0n; +- let x_3 = u; +- let z_3 = _1n; +- let swap = _0n; +- let sw; +- for (let t = BigInt(255 - 1); t >= _0n; t--) { +- const k_t = (k >> t) & _1n; +- swap ^= k_t; +- sw = cswap(swap, x_2, x_3); +- x_2 = sw[0]; +- x_3 = sw[1]; +- sw = cswap(swap, z_2, z_3); +- z_2 = sw[0]; +- z_3 = sw[1]; +- swap = k_t; +- const A = x_2 + z_2; +- const AA = mod(A * A); +- const B = x_2 - z_2; +- const BB = mod(B * B); +- const E = AA - BB; +- const C = x_3 + z_3; +- const D = x_3 - z_3; +- const DA = mod(D * A); +- const CB = mod(C * B); +- const dacb = DA + CB; +- const da_cb = DA - CB; +- x_3 = mod(dacb * dacb); +- z_3 = mod(x_1 * mod(da_cb * da_cb)); +- x_2 = mod(AA * BB); +- z_2 = mod(E * (AA + mod(a24 * E))); +- } +- sw = cswap(swap, x_2, x_3); +- x_2 = sw[0]; +- x_3 = sw[1]; +- sw = cswap(swap, z_2, z_3); +- z_2 = sw[0]; +- z_3 = sw[1]; +- const { pow_p_5_8, b2 } = pow_2_252_3(z_2); +- const xp2 = mod(pow2(pow_p_5_8, BigInt(3)) * b2); +- return mod(x_2 * xp2); +-} +-function encodeUCoordinate(u) { +- return numberTo32BytesLE(mod(u, CURVE.P)); +-} +-function decodeUCoordinate(uEnc) { +- const u = ensureBytes(uEnc, 32); +- u[31] &= 127; +- return bytesToNumberLE(u); + } ++ ++export async function getSharedSecret (privateKey, publicKey) { ++ const { head } = await getExtendedPublicKey(privateKey) ++ const u = Point.fromHex(publicKey).toX25519() ++ return curve25519.scalarMult(head, u) ++} ++ ++Point.BASE._setWindowSize(8) ++ ++function cswap (swap, x_2, x_3) { ++ const dummy = mod(swap * (x_2 - x_3)) ++ x_2 = mod(x_2 - dummy) ++ x_3 = mod(x_3 + dummy) ++ return [x_2, x_3] ++} ++ ++function montgomeryLadder (pointU, scalar) { ++ const { P } = CURVE ++ const u = normalizeScalar(pointU, P) ++ const k = normalizeScalar(scalar, P) ++ const a24 = BigInt(121665) ++ const x_1 = u ++ let x_2 = _1n ++ let z_2 = _0n ++ let x_3 = u ++ let z_3 = _1n ++ let swap = _0n ++ let sw ++ for (let t = BigInt(255 - 1); t >= _0n; t--) { ++ const k_t = (k >> t) & _1n ++ swap ^= k_t ++ sw = cswap(swap, x_2, x_3) ++ x_2 = sw[0] ++ x_3 = sw[1] ++ sw = cswap(swap, z_2, z_3) ++ z_2 = sw[0] ++ z_3 = sw[1] ++ swap = k_t ++ const A = x_2 + z_2 ++ const AA = mod(A * A) ++ const B = x_2 - z_2 ++ const BB = mod(B * B) ++ const E = AA - BB ++ const C = x_3 + z_3 ++ const D = x_3 - z_3 ++ const DA = mod(D * A) ++ const CB = mod(C * B) ++ const dacb = DA + CB ++ const da_cb = DA - CB ++ x_3 = mod(dacb * dacb) ++ z_3 = mod(x_1 * mod(da_cb * da_cb)) ++ x_2 = mod(AA * BB) ++ z_2 = mod(E * (AA + mod(a24 * E))) ++ } ++ sw = cswap(swap, x_2, x_3) ++ x_2 = sw[0] ++ x_3 = sw[1] ++ sw = cswap(swap, z_2, z_3) ++ z_2 = sw[0] ++ z_3 = sw[1] ++ const { pow_p_5_8, b2 } = pow_2_252_3(z_2) ++ const xp2 = mod(pow2(pow_p_5_8, BigInt(3)) * b2) ++ return mod(x_2 * xp2) ++} ++ ++function encodeUCoordinate (u) { ++ return numberTo32BytesLE(mod(u, CURVE.P)) ++} ++ ++function decodeUCoordinate (uEnc) { ++ const u = ensureBytes(uEnc, 32) ++ u[31] &= 127 ++ return bytesToNumberLE(u) ++} ++ + export const curve25519 = { + BASE_POINT_U: '0900000000000000000000000000000000000000000000000000000000000000', +- scalarMult(privateKey, publicKey) { +- const u = decodeUCoordinate(publicKey); +- const p = decodeScalar25519(privateKey); +- const pu = montgomeryLadder(u, p); ++ scalarMult (privateKey, publicKey) { ++ const u = decodeUCoordinate(publicKey) ++ const p = decodeScalar25519(privateKey) ++ const pu = montgomeryLadder(u, p) + if (pu === _0n) +- throw new Error('Invalid private or public key received'); +- return encodeUCoordinate(pu); ++ throw new Error('Invalid private or public key received') ++ return encodeUCoordinate(pu) + }, +- scalarMultBase(privateKey) { +- return curve25519.scalarMult(privateKey, curve25519.BASE_POINT_U); ++ scalarMultBase (privateKey) { ++ return curve25519.scalarMult(privateKey, curve25519.BASE_POINT_U) + }, +-}; ++} + const crypto = { + node: nodeCrypto, + web: typeof self === 'object' && 'crypto' in self ? self.crypto : undefined, +-}; ++} + export const utils = { + bytesToHex, + hexToBytes, +@@ -834,56 +944,52 @@ export const utils = { + 'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa', + ], + hashToPrivateScalar: (hash) => { +- hash = ensureBytes(hash); ++ hash = ensureBytes(hash) + if (hash.length < 40 || hash.length > 1024) +- throw new Error('Expected 40-1024 bytes of private key as per FIPS 186'); +- return mod(bytesToNumberLE(hash), CURVE.l - _1n) + _1n; ++ throw new Error('Expected 40-1024 bytes of private key as per FIPS 186') ++ return mod(bytesToNumberLE(hash), CURVE.l - _1n) + _1n + }, + randomBytes: (bytesLength = 32) => { + if (crypto.web) { +- return crypto.web.getRandomValues(new Uint8Array(bytesLength)); +- } +- else if (crypto.node) { +- const { randomBytes } = crypto.node; +- return new Uint8Array(randomBytes(bytesLength).buffer); +- } +- else { +- throw new Error("The environment doesn't have randomBytes function"); ++ return crypto.web.getRandomValues(new Uint8Array(bytesLength)) ++ } else if (crypto.node) { ++ const { randomBytes } = crypto.node ++ return new Uint8Array(randomBytes(bytesLength).buffer) ++ } else { ++ throw new Error('The environment doesn\'t have randomBytes function') + } + }, + randomPrivateKey: () => { +- return utils.randomBytes(32); ++ return utils.randomBytes(32) + }, + sha512: async (...messages) => { +- const message = concatBytes(...messages); ++ const message = concatBytes(...messages) + if (crypto.web) { +- const buffer = await crypto.web.subtle.digest('SHA-512', message.buffer); +- return new Uint8Array(buffer); +- } +- else if (crypto.node) { +- return Uint8Array.from(crypto.node.createHash('sha512').update(message).digest()); +- } +- else { +- throw new Error("The environment doesn't have sha512 function"); ++ const buffer = await crypto.web.subtle.digest('SHA-512', message.buffer) ++ return new Uint8Array(buffer) ++ } else if (crypto.node) { ++ return Uint8Array.from(crypto.node.createHash('sha512').update(message).digest()) ++ } else { ++ throw new Error('The environment doesn\'t have sha512 function') + } + }, +- precompute(windowSize = 8, point = Point.BASE) { +- const cached = point.equals(Point.BASE) ? point : new Point(point.x, point.y); +- cached._setWindowSize(windowSize); +- cached.multiply(_2n); +- return cached; ++ precompute (windowSize = 8, point = Point.BASE) { ++ const cached = point.equals(Point.BASE) ? point : new Point(point.x, point.y) ++ cached._setWindowSize(windowSize) ++ cached.multiply(_2n) ++ return cached + }, + sha512Sync: undefined, +-}; ++} + Object.defineProperties(utils, { + sha512Sync: { + configurable: false, +- get() { +- return _sha512Sync; ++ get () { ++ return _sha512Sync + }, +- set(val) { ++ set (val) { + if (!_sha512Sync) +- _sha512Sync = val; ++ _sha512Sync = val + }, + }, +-}); ++})