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 }, }, -}); +})