From 7a34c16c2bbd9d79d4e24fb4ba4d833815ebe671 Mon Sep 17 00:00:00 2001 From: Paul Miller Date: Mon, 26 Dec 2022 05:37:12 +0100 Subject: [PATCH] Add some comments, refactor a bit --- curve-definitions/README.md | 9 +-------- curve-definitions/benchmark/package.json | 1 + curve-definitions/src/ed448.ts | 23 ++++++++++++----------- curve-definitions/src/p521.ts | 3 +++ curve-definitions/src/pasta.ts | 4 ++-- curve-definitions/src/secp256k1.ts | 5 +++-- curve-definitions/test/ed25519.test.js | 2 +- curve-definitions/test/ed448.test.js | 4 ++-- src/bls.ts | 1 + src/edwards.ts | 2 +- src/group.ts | 2 +- src/hashToCurve.ts | 1 + src/modular.ts | 5 +++-- src/montgomery.ts | 3 ++- src/utils.ts | 2 +- src/weierstrass.ts | 2 +- 16 files changed, 36 insertions(+), 33 deletions(-) diff --git a/curve-definitions/README.md b/curve-definitions/README.md index f7593dc..cc4ffd2 100644 --- a/curve-definitions/README.md +++ b/curve-definitions/README.md @@ -7,22 +7,15 @@ Elliptic curves implementations. `@noble/curves` is zero-dependency library for - NIST curves: P192, P224, P256, P384, P521 (ECDSA) - secp256k1 (ECDSA, without Schnorr) - stark curve +- bls12-381 - bn254 -Pairings are not implemented. - ## Usage ```sh npm install micro-curve-definitions ``` -```ts -import * as nist from 'micro-curve-definitions'; - -// P192, P224, P256, P384, P521, bn254 -``` - ## License MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file. diff --git a/curve-definitions/benchmark/package.json b/curve-definitions/benchmark/package.json index 07b4b6b..fa6e2d3 100644 --- a/curve-definitions/benchmark/package.json +++ b/curve-definitions/benchmark/package.json @@ -17,6 +17,7 @@ "dependencies": { "@noble/bls12-381": "^1.4.0", "@noble/ed25519": "^1.7.1", + "@noble/hashes": "^1.1.5", "@noble/secp256k1": "^1.7.0", "@starkware-industries/starkware-crypto-utils": "^0.0.2" } diff --git a/curve-definitions/src/ed448.ts b/curve-definitions/src/ed448.ts index dc2ca7c..76dd4cb 100644 --- a/curve-definitions/src/ed448.ts +++ b/curve-definitions/src/ed448.ts @@ -18,13 +18,14 @@ const ed448P = BigInt( ); // powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4. +// Used for efficient square root calculation. +// ((P-3)/4).toString(2) would produce bits [223x 1, 0, 222x 1] function ed448_pow_Pminus3div4(x: bigint): bigint { const P = ed448P; // prettier-ignore - let [_1n, _2n, _3n, _11n, _22n, _44n, _88n, _223n] = [1, 2, 3, 11, 22, 44, 88, 223] - .map(n => BigInt(n)); - // x ** ((P - 3n)/4n) % P - // [223 of 1, 0, 222 of 1], almost same as secp! + const _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _11n = BigInt(11); + // prettier-ignore + const _22n = BigInt(22), _44n = BigInt(44), _88n = BigInt(88), _223n = BigInt(223); const b2 = (x * x * x) % P; const b3 = (b2 * b2 * x) % P; const b6 = (pow2(b3, _3n, P) * b3) % P; @@ -88,6 +89,7 @@ const ED448_DEF = { data ); }, + // Constant-time ratio of u to v. Allows to combine inversion and square root u/√v. // Uses algo from RFC8032 5.1.3. uvRatio: (u: bigint, v: bigint): { isValid: boolean; value: bigint } => { @@ -97,16 +99,15 @@ const ED448_DEF = { // candidate root x = (u/v)^((p+1)/4). This can be done using the // following trick, to use a single modular powering for both the // inversion of v and the square root: - // (p+1)/4 3 (p-3)/4 - // x = (u/v) = u v (u^5 v^3) (mod p) - const u2v = mod(u * u * v, P); - const u3v = mod(u2v * u, P); // u^2v - const u5v3 = mod(u3v * u2v * v, P); // u^5v^3 + // x = (u/v)^((p+1)/4) = u³v(u⁵v³)^((p-3)/4) (mod p) + const u2v = mod(u * u * v, P); // u²v + const u3v = mod(u2v * u, P); // u³v + const u5v3 = mod(u3v * u2v * v, P); // u⁵v³ const root = ed448_pow_Pminus3div4(u5v3); const x = mod(u3v * root, P); // Verify that root is exists - const x2 = mod(x * x, P); // x^2 - // If v * x^2 = u, the recovered x-coordinate is x. Otherwise, no + const x2 = mod(x * x, P); // x² + // If vx² = u, the recovered x-coordinate is x. Otherwise, no // square root exists, and the decoding fails. return { isValid: mod(x2 * v, P) === u, value: x }; }, diff --git a/curve-definitions/src/p521.ts b/curve-definitions/src/p521.ts index 5cae339..1e7880c 100644 --- a/curve-definitions/src/p521.ts +++ b/curve-definitions/src/p521.ts @@ -21,6 +21,9 @@ export const P521 = createCurve({ Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'), h: BigInt(1), lowS: false, + // P521 keys could be 130, 131, 132 bytes - which doesn't play nicely. + // We ensure all keys are 132 bytes. + // Does not replace validation; invalid keys would still be rejected. normalizePrivateKey(key: PrivKey) { if (typeof key === 'bigint') return key; if (key instanceof Uint8Array) key = bytesToHex(key); diff --git a/curve-definitions/src/pasta.ts b/curve-definitions/src/pasta.ts index 1990ec9..4b02eab 100644 --- a/curve-definitions/src/pasta.ts +++ b/curve-definitions/src/pasta.ts @@ -4,8 +4,8 @@ import { weierstrass } from '@noble/curves/weierstrass'; import { getHash } from './_shortw_utils.js'; import * as mod from '@noble/curves/modular'; -const p = BigInt('0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001'); -const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001'); +export const p = BigInt('0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001'); +export const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001'); // https://neuromancer.sk/std/other/Pallas export const pallas = weierstrass({ diff --git a/curve-definitions/src/secp256k1.ts b/curve-definitions/src/secp256k1.ts index 7733f50..f4cf2ec 100644 --- a/curve-definitions/src/secp256k1.ts +++ b/curve-definitions/src/secp256k1.ts @@ -36,10 +36,11 @@ const divNearest = (a: bigint, b: bigint) => (a + b / _2n) / b; * We are unwrapping the loop and multiplying it bit-by-bit. * (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00] */ -// prettier-ignore function sqrtMod(y: bigint): bigint { const P = secp256k1P; - const _3n = BigInt(3), _6n = BigInt(6), _11n = BigInt(11); const _22n = BigInt(22); + // prettier-ignore + const _3n = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22); + // prettier-ignore const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88); const b2 = (y * y * y) % P; // x^3, 11 const b3 = (b2 * b2 * y) % P; // x^7 diff --git a/curve-definitions/test/ed25519.test.js b/curve-definitions/test/ed25519.test.js index 7fd0563..b792a7d 100644 --- a/curve-definitions/test/ed25519.test.js +++ b/curve-definitions/test/ed25519.test.js @@ -346,7 +346,7 @@ should('ristretto255/should not convert bad bytes encoding', () => { '47cfc5497c53dc8e61c91d17fd626ffb1c49e2bca94eed052281b510b1117a24', 'f1c6165d33367351b0da8f6e4511010c68174a03b6581212c71c0e1d026c3c72', '87260f7a2f12495118360f02c26a470f450dadf34a413d21042b43b9d93e1309', - // These are all bad because they give a nonsquare x^2. + // These are all bad because they give a nonsquare x². '26948d35ca62e643e26a83177332e6b6afeb9d08e4268b650f1f5bbd8d81d371', '4eac077a713c57b4f4397629a4145982c661f48044dd3f96427d40b147d9742f', 'de6a7b00deadc788eb6b6c8d20c0ae96c2f2019078fa604fee5b87d6e989ad7b', diff --git a/curve-definitions/test/ed448.test.js b/curve-definitions/test/ed448.test.js index fdd851a..55937e3 100644 --- a/curve-definitions/test/ed448.test.js +++ b/curve-definitions/test/ed448.test.js @@ -652,8 +652,8 @@ for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) { should('X448 base point', () => { const { x, y } = ed448.Point.BASE; const { P } = ed448.CURVE; - const invX = ed448.utils.invert(x * x, P); // x^2 - const u = ed448.utils.mod(y * y * invX, P); // (y^2/x^2) + const invX = ed448.utils.invert(x * x, P); // x² + const u = ed448.utils.mod(y * y * invX, P); // (y²/x²) deepStrictEqual(hex(numberToBytesLE(u, 56)), x448.Gu); }); diff --git a/src/bls.ts b/src/bls.ts index b0a2c85..8d2ab99 100644 --- a/src/bls.ts +++ b/src/bls.ts @@ -1,3 +1,4 @@ +/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ // Barreto-Lynn-Scott Curves. A family of pairing friendly curves, with embedding degree = 12 or 24 // NOTE: only 12 supported for now // Constructed from pair of weierstrass curves, based pairing logic diff --git a/src/edwards.ts b/src/edwards.ts index b1b3c23..628d5e4 100644 --- a/src/edwards.ts +++ b/src/edwards.ts @@ -1,5 +1,5 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -// Implementation of Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y² +// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y² // Differences from @noble/ed25519 1.7: // 1. Different field element lengths in ed448: diff --git a/src/group.ts b/src/group.ts index 710be5f..d5142f5 100644 --- a/src/group.ts +++ b/src/group.ts @@ -1,4 +1,4 @@ -/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ +/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ // Default group related functions const _0n = BigInt(0); const _1n = BigInt(1); diff --git a/src/hashToCurve.ts b/src/hashToCurve.ts index e54969a..3aa9d12 100644 --- a/src/hashToCurve.ts +++ b/src/hashToCurve.ts @@ -1,3 +1,4 @@ +/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ import { CHash, concatBytes } from './utils.js'; import * as mod from './modular.js'; diff --git a/src/modular.ts b/src/modular.ts index 43ded16..d89e981 100644 --- a/src/modular.ts +++ b/src/modular.ts @@ -1,4 +1,4 @@ -/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ +/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ import * as utils from './utils.js'; // Utilities for modular arithmetics const _0n = BigInt(0); @@ -75,6 +75,7 @@ export function legendre(num: bigint, fieldPrime: bigint): bigint { /** * Calculates square root of a number in a finite field. + * √a mod P */ // TODO: rewrite as generic Fp function && remove bls versions export function sqrt(number: bigint, modulo: bigint): bigint { @@ -85,7 +86,7 @@ export function sqrt(number: bigint, modulo: bigint): bigint { const p1div4 = (P + _1n) / _4n; // P ≡ 3 (mod 4) - // sqrt n = n^((P+1)/4) + // √n = n^((P+1)/4) if (P % _4n === _3n) { // Not all roots possible! // const ORDER = diff --git a/src/montgomery.ts b/src/montgomery.ts index f16ba49..40760ac 100644 --- a/src/montgomery.ts +++ b/src/montgomery.ts @@ -1,3 +1,4 @@ +/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ import * as mod from './modular.js'; import { ensureBytes, @@ -86,7 +87,7 @@ export function montgomery(curveDef: CurveType): CurveFn { // cswap from RFC7748 // NOTE: cswap is not from RFC7748! - /* + /* cswap(swap, x_2, x_3): dummy = mask(swap) AND (x_2 XOR x_3) x_2 = x_2 XOR dummy diff --git a/src/utils.ts b/src/utils.ts index 5690cbf..3940d77 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ +/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ import * as mod from './modular.js'; const _0n = BigInt(0); const _1n = BigInt(1); diff --git a/src/weierstrass.ts b/src/weierstrass.ts index 1ed627d..f36e53f 100644 --- a/src/weierstrass.ts +++ b/src/weierstrass.ts @@ -1,5 +1,5 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -// Implementation of Short Weierstrass curve. The formula is: y² = x³ + ax + b +// Short Weierstrass curve. The formula is: y² = x³ + ax + b // TODO: sync vs async naming // TODO: default randomBytes