diff --git a/README.md b/README.md index 580c2b2..a087295 100644 --- a/README.md +++ b/README.md @@ -445,15 +445,11 @@ import { montgomery } from '@noble/curves/abstract/montgomery'; const x25519 = montgomery({ P: 2n ** 255n - 19n, - a24: 121665n, // TODO: change to a + a: 486662n, + Gu: 9n, montgomeryBits: 255, nByteLength: 32, - Gu: '0900000000000000000000000000000000000000000000000000000000000000', - - // Optional params - powPminus2: (x: bigint): bigint => { - return mod.pow(x, P - 2, P); - }, + // Optional param adjustScalarBytes(bytes) { bytes[0] &= 248; bytes[31] &= 127; diff --git a/src/abstract/montgomery.ts b/src/abstract/montgomery.ts index d959c5f..e85b388 100644 --- a/src/abstract/montgomery.ts +++ b/src/abstract/montgomery.ts @@ -11,25 +11,25 @@ export type CurveType = { nByteLength: number; adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; - a24: bigint; // Related to d, but cannot be derived from it + a: bigint; montgomeryBits: number; powPminus2?: (x: bigint) => bigint; xyToU?: (x: bigint, y: bigint) => bigint; - Gu: string; + Gu: bigint; }; export type CurveFn = { scalarMult: (scalar: Hex, u: Hex) => Uint8Array; scalarMultBase: (scalar: Hex) => Uint8Array; getSharedSecret: (privateKeyA: Hex, publicKeyB: Hex) => Uint8Array; getPublicKey: (privateKey: Hex) => Uint8Array; - Gu: string; + GuBytes: Uint8Array; }; function validateOpts(curve: CurveType) { validateObject( curve, { - a24: 'bigint', + a: 'bigint', }, { montgomeryBits: 'isSafeInteger', @@ -37,7 +37,7 @@ function validateOpts(curve: CurveType) { adjustScalarBytes: 'function', domain: 'function', powPminus2: 'function', - Gu: 'string', + Gu: 'bigint', } ); // Set defaults @@ -49,7 +49,7 @@ function validateOpts(curve: CurveType) { export function montgomery(curveDef: CurveType): CurveFn { const CURVE = validateOpts(curveDef); const { P } = CURVE; - const modP = (a: bigint) => mod(a, P); + const modP = (n: bigint) => mod(n, P); const montgomeryBits = CURVE.montgomeryBits; const montgomeryBytes = Math.ceil(montgomeryBits / 8); const fieldLen = CURVE.nByteLength; @@ -79,6 +79,8 @@ export function montgomery(curveDef: CurveType): CurveFn { } // x25519 from 4 + // The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519 + const a24 = (CURVE.a - BigInt(2)) / BigInt(4); /** * * @param pointU u coordinate (x) on Montgomery Curve 25519 @@ -90,8 +92,6 @@ export function montgomery(curveDef: CurveType): CurveFn { // Section 5: Implementations MUST accept non-canonical values and process them as // if they had been reduced modulo the field prime. const k = assertFieldElement(scalar); - // The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519 - const a24 = CURVE.a24; const x_1 = u; let x_2 = _1n; let z_2 = _0n; @@ -170,8 +170,9 @@ export function montgomery(curveDef: CurveType): CurveFn { return encodeUCoordinate(pu); } // Computes public key from private. By doing scalar multiplication of base point. + const GuBytes = encodeUCoordinate(CURVE.Gu); function scalarMultBase(scalar: Hex): Uint8Array { - return scalarMult(scalar, CURVE.Gu); + return scalarMult(scalar, GuBytes); } return { @@ -179,6 +180,6 @@ export function montgomery(curveDef: CurveType): CurveFn { scalarMultBase, getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(privateKey, publicKey), getPublicKey: (privateKey: Hex): Uint8Array => scalarMultBase(privateKey), - Gu: CURVE.Gu, + GuBytes: GuBytes, }; } diff --git a/src/ed25519.ts b/src/ed25519.ts index 19ab4c8..584e241 100644 --- a/src/ed25519.ts +++ b/src/ed25519.ts @@ -138,10 +138,10 @@ export const ed25519ph = twistedEdwards({ export const x25519 = montgomery({ P: ED25519_P, - a24: BigInt('121665'), + a: BigInt(486662), montgomeryBits: 255, // n is 253 bits nByteLength: 32, - Gu: '0900000000000000000000000000000000000000000000000000000000000000', + Gu: BigInt(9), powPminus2: (x: bigint): bigint => { const P = ED25519_P; // x^(p-2) aka x^(2^255-21) diff --git a/src/ed448.ts b/src/ed448.ts index 2954c41..97c73d4 100644 --- a/src/ed448.ts +++ b/src/ed448.ts @@ -122,11 +122,11 @@ export const ed448 = twistedEdwards(ED448_DEF); export const ed448ph = twistedEdwards({ ...ED448_DEF, preHash: shake256_64 }); export const x448 = montgomery({ - a24: BigInt(39081), + a: BigInt(156326), montgomeryBits: 448, nByteLength: 57, P: ed448P, - Gu: '0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + Gu: BigInt(5), powPminus2: (x: bigint): bigint => { const P = ed448P; const Pminus3div4 = ed448_pow_Pminus3div4(x); diff --git a/test/ed25519-addons.test.js b/test/ed25519-addons.test.js index c128194..e3f2e51 100644 --- a/test/ed25519-addons.test.js +++ b/test/ed25519-addons.test.js @@ -97,7 +97,7 @@ should('X25519 base point', () => { const { y } = ed25519ph.ExtendedPoint.BASE; const { Fp } = ed25519ph.CURVE; const u = Fp.create((y + 1n) * Fp.inv(1n - y)); - deepStrictEqual(hex(numberToBytesLE(u, 32)), x25519.Gu); + deepStrictEqual(numberToBytesLE(u, 32), x25519.GuBytes); }); describe('RFC7748', () => { @@ -128,7 +128,7 @@ describe('RFC7748', () => { for (let i = 0; i < rfc7748Iter.length; i++) { const { scalar, iters } = rfc7748Iter[i]; should(`scalarMult iteration (${i})`, () => { - let k = x25519.Gu; + let k = x25519.GuBytes; for (let i = 0, u = k; i < iters; i++) [k, u] = [x25519.scalarMult(k, u), k]; deepStrictEqual(hex(k), scalar); }); diff --git a/test/ed448.test.js b/test/ed448.test.js index 08b74b7..f892cad 100644 --- a/test/ed448.test.js +++ b/test/ed448.test.js @@ -509,7 +509,7 @@ describe('ed448', () => { for (let i = 0; i < rfc7748Iter.length; i++) { const { scalar, iters } = rfc7748Iter[i]; should(`RFC7748: scalarMult iteration (${i})`, () => { - let k = x448.Gu; + let k = x448.GuBytes; for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(k, u), k]; deepStrictEqual(hex(k), scalar); }); @@ -664,7 +664,7 @@ describe('ed448', () => { // const invX = Fp.invert(x * x); // x² const u = Fp.div(Fp.create(y * y), Fp.create(x * x)); // (y²/x²) // const u = Fp.create(y * y * invX); - deepStrictEqual(hex(numberToBytesLE(u, 56)), x448.Gu); + deepStrictEqual(numberToBytesLE(u, 56), x448.GuBytes); }); });