x25519, x448: change param from a24 to a. Change Gu to bigint
This commit is contained in:
parent
8b2863aeac
commit
26ebb5dcce
10
README.md
10
README.md
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user