x25519, x448: change param from a24 to a. Change Gu to bigint

This commit is contained in:
Paul Miller 2023-02-15 22:07:52 +00:00
parent 8b2863aeac
commit 26ebb5dcce
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B
6 changed files with 22 additions and 25 deletions

@ -445,15 +445,11 @@ import { montgomery } from '@noble/curves/abstract/montgomery';
const x25519 = montgomery({ const x25519 = montgomery({
P: 2n ** 255n - 19n, P: 2n ** 255n - 19n,
a24: 121665n, // TODO: change to a a: 486662n,
Gu: 9n,
montgomeryBits: 255, montgomeryBits: 255,
nByteLength: 32, nByteLength: 32,
Gu: '0900000000000000000000000000000000000000000000000000000000000000', // Optional param
// Optional params
powPminus2: (x: bigint): bigint => {
return mod.pow(x, P - 2, P);
},
adjustScalarBytes(bytes) { adjustScalarBytes(bytes) {
bytes[0] &= 248; bytes[0] &= 248;
bytes[31] &= 127; bytes[31] &= 127;

@ -11,25 +11,25 @@ export type CurveType = {
nByteLength: number; nByteLength: number;
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array;
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array;
a24: bigint; // Related to d, but cannot be derived from it a: bigint;
montgomeryBits: number; montgomeryBits: number;
powPminus2?: (x: bigint) => bigint; powPminus2?: (x: bigint) => bigint;
xyToU?: (x: bigint, y: bigint) => bigint; xyToU?: (x: bigint, y: bigint) => bigint;
Gu: string; Gu: bigint;
}; };
export type CurveFn = { export type CurveFn = {
scalarMult: (scalar: Hex, u: Hex) => Uint8Array; scalarMult: (scalar: Hex, u: Hex) => Uint8Array;
scalarMultBase: (scalar: Hex) => Uint8Array; scalarMultBase: (scalar: Hex) => Uint8Array;
getSharedSecret: (privateKeyA: Hex, publicKeyB: Hex) => Uint8Array; getSharedSecret: (privateKeyA: Hex, publicKeyB: Hex) => Uint8Array;
getPublicKey: (privateKey: Hex) => Uint8Array; getPublicKey: (privateKey: Hex) => Uint8Array;
Gu: string; GuBytes: Uint8Array;
}; };
function validateOpts(curve: CurveType) { function validateOpts(curve: CurveType) {
validateObject( validateObject(
curve, curve,
{ {
a24: 'bigint', a: 'bigint',
}, },
{ {
montgomeryBits: 'isSafeInteger', montgomeryBits: 'isSafeInteger',
@ -37,7 +37,7 @@ function validateOpts(curve: CurveType) {
adjustScalarBytes: 'function', adjustScalarBytes: 'function',
domain: 'function', domain: 'function',
powPminus2: 'function', powPminus2: 'function',
Gu: 'string', Gu: 'bigint',
} }
); );
// Set defaults // Set defaults
@ -49,7 +49,7 @@ function validateOpts(curve: CurveType) {
export function montgomery(curveDef: CurveType): CurveFn { export function montgomery(curveDef: CurveType): CurveFn {
const CURVE = validateOpts(curveDef); const CURVE = validateOpts(curveDef);
const { P } = CURVE; const { P } = CURVE;
const modP = (a: bigint) => mod(a, P); const modP = (n: bigint) => mod(n, P);
const montgomeryBits = CURVE.montgomeryBits; const montgomeryBits = CURVE.montgomeryBits;
const montgomeryBytes = Math.ceil(montgomeryBits / 8); const montgomeryBytes = Math.ceil(montgomeryBits / 8);
const fieldLen = CURVE.nByteLength; const fieldLen = CURVE.nByteLength;
@ -79,6 +79,8 @@ export function montgomery(curveDef: CurveType): CurveFn {
} }
// x25519 from 4 // 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 * @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 // Section 5: Implementations MUST accept non-canonical values and process them as
// if they had been reduced modulo the field prime. // if they had been reduced modulo the field prime.
const k = assertFieldElement(scalar); const k = assertFieldElement(scalar);
// The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519
const a24 = CURVE.a24;
const x_1 = u; const x_1 = u;
let x_2 = _1n; let x_2 = _1n;
let z_2 = _0n; let z_2 = _0n;
@ -170,8 +170,9 @@ export function montgomery(curveDef: CurveType): CurveFn {
return encodeUCoordinate(pu); return encodeUCoordinate(pu);
} }
// Computes public key from private. By doing scalar multiplication of base point. // Computes public key from private. By doing scalar multiplication of base point.
const GuBytes = encodeUCoordinate(CURVE.Gu);
function scalarMultBase(scalar: Hex): Uint8Array { function scalarMultBase(scalar: Hex): Uint8Array {
return scalarMult(scalar, CURVE.Gu); return scalarMult(scalar, GuBytes);
} }
return { return {
@ -179,6 +180,6 @@ export function montgomery(curveDef: CurveType): CurveFn {
scalarMultBase, scalarMultBase,
getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(privateKey, publicKey), getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(privateKey, publicKey),
getPublicKey: (privateKey: Hex): Uint8Array => scalarMultBase(privateKey), getPublicKey: (privateKey: Hex): Uint8Array => scalarMultBase(privateKey),
Gu: CURVE.Gu, GuBytes: GuBytes,
}; };
} }

@ -138,10 +138,10 @@ export const ed25519ph = twistedEdwards({
export const x25519 = montgomery({ export const x25519 = montgomery({
P: ED25519_P, P: ED25519_P,
a24: BigInt('121665'), a: BigInt(486662),
montgomeryBits: 255, // n is 253 bits montgomeryBits: 255, // n is 253 bits
nByteLength: 32, nByteLength: 32,
Gu: '0900000000000000000000000000000000000000000000000000000000000000', Gu: BigInt(9),
powPminus2: (x: bigint): bigint => { powPminus2: (x: bigint): bigint => {
const P = ED25519_P; const P = ED25519_P;
// x^(p-2) aka x^(2^255-21) // x^(p-2) aka x^(2^255-21)

@ -122,11 +122,11 @@ export const ed448 = twistedEdwards(ED448_DEF);
export const ed448ph = twistedEdwards({ ...ED448_DEF, preHash: shake256_64 }); export const ed448ph = twistedEdwards({ ...ED448_DEF, preHash: shake256_64 });
export const x448 = montgomery({ export const x448 = montgomery({
a24: BigInt(39081), a: BigInt(156326),
montgomeryBits: 448, montgomeryBits: 448,
nByteLength: 57, nByteLength: 57,
P: ed448P, P: ed448P,
Gu: '0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', Gu: BigInt(5),
powPminus2: (x: bigint): bigint => { powPminus2: (x: bigint): bigint => {
const P = ed448P; const P = ed448P;
const Pminus3div4 = ed448_pow_Pminus3div4(x); const Pminus3div4 = ed448_pow_Pminus3div4(x);

@ -97,7 +97,7 @@ should('X25519 base point', () => {
const { y } = ed25519ph.ExtendedPoint.BASE; const { y } = ed25519ph.ExtendedPoint.BASE;
const { Fp } = ed25519ph.CURVE; const { Fp } = ed25519ph.CURVE;
const u = Fp.create((y + 1n) * Fp.inv(1n - y)); 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', () => { describe('RFC7748', () => {
@ -128,7 +128,7 @@ describe('RFC7748', () => {
for (let i = 0; i < rfc7748Iter.length; i++) { for (let i = 0; i < rfc7748Iter.length; i++) {
const { scalar, iters } = rfc7748Iter[i]; const { scalar, iters } = rfc7748Iter[i];
should(`scalarMult iteration (${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]; for (let i = 0, u = k; i < iters; i++) [k, u] = [x25519.scalarMult(k, u), k];
deepStrictEqual(hex(k), scalar); deepStrictEqual(hex(k), scalar);
}); });

@ -509,7 +509,7 @@ describe('ed448', () => {
for (let i = 0; i < rfc7748Iter.length; i++) { for (let i = 0; i < rfc7748Iter.length; i++) {
const { scalar, iters } = rfc7748Iter[i]; const { scalar, iters } = rfc7748Iter[i];
should(`RFC7748: scalarMult iteration (${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]; for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(k, u), k];
deepStrictEqual(hex(k), scalar); deepStrictEqual(hex(k), scalar);
}); });
@ -664,7 +664,7 @@ describe('ed448', () => {
// const invX = Fp.invert(x * x); // x² // const invX = Fp.invert(x * x); // x²
const u = Fp.div(Fp.create(y * y), Fp.create(x * x)); // (y²/x²) const u = Fp.div(Fp.create(y * y), Fp.create(x * x)); // (y²/x²)
// const u = Fp.create(y * y * invX); // const u = Fp.create(y * y * invX);
deepStrictEqual(hex(numberToBytesLE(u, 56)), x448.Gu); deepStrictEqual(numberToBytesLE(u, 56), x448.GuBytes);
}); });
}); });