From 11e78aadbfae1cedfb88611ce7fe2d617fee4765 Mon Sep 17 00:00:00 2001 From: Paul Miller Date: Mon, 23 Jan 2023 19:28:01 +0000 Subject: [PATCH] Edwards: prohibit number scalars, only allow bigints --- src/abstract/edwards.ts | 18 ++++++++++++------ src/abstract/utils.ts | 2 +- test/ed25519.test.js | 4 ++-- test/ed448.test.js | 9 ++++----- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/abstract/edwards.ts b/src/abstract/edwards.ts index 0289b71..1291006 100644 --- a/src/abstract/edwards.ts +++ b/src/abstract/edwards.ts @@ -170,16 +170,21 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { * https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates */ class ExtendedPoint implements ExtendedPointType { - constructor(readonly x: bigint, readonly y: bigint, readonly z: bigint, readonly t: bigint) {} + constructor( + readonly x: bigint, + readonly y: bigint, + readonly z = _1n, + readonly t = modP(x * y) + ) {} - static BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy)); - static ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n); + static BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy); + static ZERO = new ExtendedPoint(_0n, _1n); // 0, 1, 1, 0 static fromAffine(p: Point): ExtendedPoint { if (!(p instanceof Point)) { throw new TypeError('ExtendedPoint#fromAffine: expected Point'); } if (p.equals(Point.ZERO)) return ExtendedPoint.ZERO; - return new ExtendedPoint(p.x, p.y, _1n, modP(p.x * p.y)); + return new ExtendedPoint(p.x, p.y); } // Takes a bunch of Jacobian Points but executes only one // invert on all of them. invert is very slow operation, @@ -306,8 +311,9 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { // It's faster, but should only be used when you don't care about // an exposed private key e.g. sig verification. multiplyUnsafe(scalar: number | bigint): ExtendedPoint { - let n = normalizeScalar(scalar, CURVE_ORDER, false); const P0 = ExtendedPoint.ZERO; + if (scalar === _0n) return P0; + let n = normalizeScalar(scalar, CURVE_ORDER, false); if (n === _0n) return P0; if (this.equals(P0) || n === _1n) return this; if (this.equals(ExtendedPoint.BASE)) return this.wNAF(n); @@ -542,7 +548,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { const groupLen = CURVE.nByteLength; // Normalize bigint / number / string to Uint8Array const keyb = - typeof key === 'bigint' || typeof key === 'number' + typeof key === 'bigint' ? ut.numberToBytesLE(normalizeScalar(key, maxGroupElement), groupLen) : key; // Hash private key with curve's hash function to produce uniformingly random input diff --git a/src/abstract/utils.ts b/src/abstract/utils.ts index 2a7baf3..b08025e 100644 --- a/src/abstract/utils.ts +++ b/src/abstract/utils.ts @@ -7,7 +7,7 @@ const _2n = BigInt(2); // We accept hex strings besides Uint8Array for simplicity export type Hex = Uint8Array | string; // Very few implementations accept numbers, we do it to ease learning curve -export type PrivKey = Hex | bigint | number; +export type PrivKey = Hex | bigint; export type CHash = { (message: Uint8Array | string): Uint8Array; blockLen: number; diff --git a/test/ed25519.test.js b/test/ed25519.test.js index f41fc72..cf2b4e7 100644 --- a/test/ed25519.test.js +++ b/test/ed25519.test.js @@ -87,7 +87,7 @@ describe('ed25519', () => { deepStrictEqual(ed.verify(signature, msg, publicKey), true); }); should('not verify signature with wrong public key', () => { - const publicKey = ed.getPublicKey(12); + const publicKey = ed.getPublicKey(12n); const signature = ed.sign(msg, privKey); deepStrictEqual(ed.verify(signature, msg, publicKey), false); }); @@ -104,7 +104,7 @@ describe('ed25519', () => { deepStrictEqual(ed.verify(signature, msg, publicKey), true); }); should('not verify signature with wrong public key', () => { - const publicKey = ed.getPublicKey(12); + const publicKey = ed.getPublicKey(12n); const signature = ed.sign(msg, privKey); deepStrictEqual(ed.verify(signature, msg, publicKey), false); }); diff --git a/test/ed448.test.js b/test/ed448.test.js index 1661ddd..c3fa31a 100644 --- a/test/ed448.test.js +++ b/test/ed448.test.js @@ -382,7 +382,7 @@ describe('ed448', () => { deepStrictEqual(ed.verify(signature, msg, publicKey), true); }); should('not verify signature with wrong public key', () => { - const publicKey = ed.getPublicKey(12); + const publicKey = ed.getPublicKey(12n); const signature = ed.sign(msg, privKey); deepStrictEqual(ed.verify(signature, msg, publicKey), false); }); @@ -392,19 +392,18 @@ describe('ed448', () => { deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false); }); }); - describe('sync methods', () => { should('sign and verify', () => { const publicKey = ed.getPublicKey(privKey); const signature = ed.sign(msg, privKey); deepStrictEqual(ed.verify(signature, msg, publicKey), true); }); - should('not verify signature with wrong public key', async () => { - const publicKey = ed.getPublicKey(12); + should('not verify signature with wrong public key', () => { + const publicKey = ed.getPublicKey(12n); const signature = ed.sign(msg, privKey); deepStrictEqual(ed.verify(signature, msg, publicKey), false); }); - should('not verify signature with wrong hash', async () => { + should('not verify signature with wrong hash', () => { const publicKey = ed.getPublicKey(privKey); const signature = ed.sign(msg, privKey); deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);