@noble/curves 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
1
2
  import { CurveFn } from './abstract/bls.js';
2
3
  import * as mod from './abstract/modular.js';
3
4
  declare const Fp: Readonly<mod.Field<bigint> & Required<Pick<mod.Field<bigint>, "isOdd">>>;
package/lib/bls12-381.js CHANGED
@@ -1,7 +1,17 @@
1
1
  "use strict";
2
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.bls12_381 = void 0;
4
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
+ // The pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to:
6
+ // - Construct zk-SNARKs at the 128-bit security
7
+ // - Use threshold signatures, which allows a user to sign lots of messages with one signature and verify them swiftly in a batch, using Boneh-Lynn-Shacham signature scheme.
8
+ // Differences from @noble/bls12-381 1.4:
9
+ // - PointG1 -> G1.Point
10
+ // - PointG2 -> G2.Point
11
+ // - PointG2.fromSignature -> Signature.decode
12
+ // - PointG2.toSignature -> Signature.encode
13
+ // - Fixed Fp2 ORDER
14
+ // - Points now have only two coordinates
5
15
  const sha256_1 = require("@noble/hashes/sha256");
6
16
  const utils_1 = require("@noble/hashes/utils");
7
17
  const bls_js_1 = require("./abstract/bls.js");
@@ -10,13 +20,6 @@ const utils_js_1 = require("./abstract/utils.js");
10
20
  // Types
11
21
  const weierstrass_js_1 = require("./abstract/weierstrass.js");
12
22
  const hash_to_curve_js_1 = require("./abstract/hash-to-curve.js");
13
- // Differences from bls12-381:
14
- // - PointG1 -> G1.Point
15
- // - PointG2 -> G2.Point
16
- // - PointG2.fromSignature -> Signature.decode
17
- // - PointG2.toSignature -> Signature.encode
18
- // - Fixed Fp2 ORDER
19
- // Points now have only two coordinates
20
23
  // CURVE FIELDS
21
24
  // Finite field over p.
22
25
  const Fp = mod.Fp(0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn);
@@ -100,6 +103,8 @@ const Fp2 = {
100
103
  return { c0: Fp.mul(factor, Fp.create(a)), c1: Fp.mul(factor, Fp.create(-b)) };
101
104
  },
102
105
  sqrt: (num) => {
106
+ if (Fp2.equals(num, Fp2.ZERO))
107
+ return Fp2.ZERO; // Algo doesn't handles this case
103
108
  // TODO: Optimize this line. It's extremely slow.
104
109
  // Speeding this up would boost aggregateSignatures.
105
110
  // https://eprint.iacr.org/2012/685.pdf applicable?
package/lib/ed25519.js CHANGED
@@ -225,13 +225,13 @@ const D_MINUS_ONE_SQ = BigInt('4044083434630853685810104246932319082624839914623
225
225
  // Calculates 1/√(number)
226
226
  const invertSqrt = (number) => uvRatio(_1n, number);
227
227
  const MAX_255B = BigInt('0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
228
- const bytes255ToNumberLE = (bytes) => exports.ed25519.utils.mod((0, utils_js_1.bytesToNumberLE)(bytes) & MAX_255B);
228
+ const bytes255ToNumberLE = (bytes) => exports.ed25519.CURVE.Fp.create((0, utils_js_1.bytesToNumberLE)(bytes) & MAX_255B);
229
229
  // Computes Elligator map for Ristretto
230
230
  // https://ristretto.group/formulas/elligator.html
231
231
  function calcElligatorRistrettoMap(r0) {
232
232
  const { d } = exports.ed25519.CURVE;
233
233
  const P = exports.ed25519.CURVE.Fp.ORDER;
234
- const { mod } = exports.ed25519.utils;
234
+ const mod = exports.ed25519.CURVE.Fp.create;
235
235
  const r = mod(SQRT_M1 * r0 * r0); // 1
236
236
  const Ns = mod((r + _1n) * ONE_MINUS_D_SQ); // 2
237
237
  let c = BigInt(-1); // 3
@@ -289,7 +289,7 @@ class RistrettoPoint {
289
289
  hex = (0, utils_js_1.ensureBytes)(hex, 32);
290
290
  const { a, d } = exports.ed25519.CURVE;
291
291
  const P = exports.ed25519.CURVE.Fp.ORDER;
292
- const { mod } = exports.ed25519.utils;
292
+ const mod = exports.ed25519.CURVE.Fp.create;
293
293
  const emsg = 'RistrettoPoint.fromHex: the hex is not valid encoding of RistrettoPoint';
294
294
  const s = bytes255ToNumberLE(hex);
295
295
  // 1. Check that s_bytes is the canonical encoding of a field element, or else abort.
@@ -321,7 +321,7 @@ class RistrettoPoint {
321
321
  toRawBytes() {
322
322
  let { x, y, z, t } = this.ep;
323
323
  const P = exports.ed25519.CURVE.Fp.ORDER;
324
- const { mod } = exports.ed25519.utils;
324
+ const mod = exports.ed25519.CURVE.Fp.create;
325
325
  const u1 = mod(mod(z + y) * mod(z - y)); // 1
326
326
  const u2 = mod(x * y); // 2
327
327
  // Square root always exists
@@ -359,7 +359,7 @@ class RistrettoPoint {
359
359
  assertRstPoint(other);
360
360
  const a = this.ep;
361
361
  const b = other.ep;
362
- const { mod } = exports.ed25519.utils;
362
+ const mod = exports.ed25519.CURVE.Fp.create;
363
363
  // (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)
364
364
  const one = mod(a.x * b.y) === mod(a.y * b.x);
365
365
  const two = mod(a.y * b.y) === mod(a.x * b.x);
package/lib/ed448.js CHANGED
@@ -129,7 +129,8 @@ const ED448_DEF = {
129
129
  d: BigInt('726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018326358'),
130
130
  // Finite field 𝔽p over which we'll do calculations; 2n ** 448n - 2n ** 224n - 1n
131
131
  Fp,
132
- // Subgroup order: how many points ed448 has; 2n**446n - 13818066809895115352007386748515426880336692474882178609894547503885n
132
+ // Subgroup order: how many points curve has;
133
+ // 2n**446n - 13818066809895115352007386748515426880336692474882178609894547503885n
133
134
  n: BigInt('181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779'),
134
135
  nBitLength: 456,
135
136
  // Cofactor
@@ -1,21 +1,11 @@
1
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
- // Barreto-Lynn-Scott Curves. A family of pairing friendly curves, with embedding degree = 12 or 24
3
- // NOTE: only 12 supported for now
4
- // Constructed from pair of weierstrass curves, based pairing logic
5
- import * as mod from './modular.js';
6
- import { ensureBytes, numberToBytesBE, bytesToNumberBE, bitLen, bitGet } from './utils.js';
7
- // Types
8
- import { hexToBytes, bytesToHex } from './utils.js';
9
- import { stringToBytes, hash_to_field, expand_message_xmd } from './hash-to-curve.js';
1
+ import * as ut from './utils.js';
2
+ import { stringToBytes, hash_to_field as hashToField, expand_message_xmd as expandMessageXMD, } from './hash-to-curve.js';
10
3
  import { weierstrassPoints } from './weierstrass.js';
11
4
  export function bls(CURVE) {
12
5
  // Fields looks pretty specific for curve, so for now we need to pass them with options
13
- const Fp = CURVE.Fp;
14
- const Fr = CURVE.Fr;
15
- const Fp2 = CURVE.Fp2;
16
- const Fp6 = CURVE.Fp6;
17
- const Fp12 = CURVE.Fp12;
18
- const BLS_X_LEN = bitLen(CURVE.x);
6
+ const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
7
+ const BLS_X_LEN = ut.bitLen(CURVE.x);
8
+ const groupLen = 32; // TODO: calculate; hardcoded for now
19
9
  // Pre-compute coefficients for sparse multiplication
20
10
  // Point addition and point double calculations is reused for coefficients
21
11
  function calcPairingPrecomputes(x, y) {
@@ -39,7 +29,7 @@ export function bls(CURVE) {
39
29
  Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
40
30
  Ry = Fp2.sub(Fp2.square(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.square(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
41
31
  Rz = Fp2.mul(t0, t4); // T0 * T4
42
- if (bitGet(CURVE.x, i)) {
32
+ if (ut.bitGet(CURVE.x, i)) {
43
33
  // Addition
44
34
  let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
45
35
  let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
@@ -60,13 +50,14 @@ export function bls(CURVE) {
60
50
  return ell_coeff;
61
51
  }
62
52
  function millerLoop(ell, g1) {
53
+ const { x } = CURVE;
63
54
  const Px = g1[0];
64
55
  const Py = g1[1];
65
56
  let f12 = Fp12.ONE;
66
57
  for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
67
58
  const E = ell[j];
68
59
  f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
69
- if (bitGet(CURVE.x, i)) {
60
+ if (ut.bitGet(x, i)) {
70
61
  j += 1;
71
62
  const F = ell[j];
72
63
  f12 = Fp12.multiplyBy014(f12, F[0], Fp2.mul(F[1], Px), Fp2.mul(F[2], Py));
@@ -76,79 +67,25 @@ export function bls(CURVE) {
76
67
  }
77
68
  return Fp12.conjugate(f12);
78
69
  }
79
- // bls12-381 is a construction of two curves:
80
- // 1. Fp: (x, y)
81
- // 2. Fp₂: ((x₁, x₂+i), (y₁, y₂+i)) - (complex numbers)
82
- //
83
- // Bilinear Pairing (ate pairing) is used to combine both elements into a paired one:
84
- // Fp₁₂ = e(Fp, Fp2)
85
- // where Fp₁₂ = 12-degree polynomial
86
- // Pairing is used to verify signatures.
87
- //
88
- // We are using Fp for private keys (shorter) and Fp2 for signatures (longer).
89
- // Some projects may prefer to swap this relation, it is not supported for now.
90
- const htfDefaults = { ...CURVE.htfDefaults };
91
- function isWithinCurveOrder(num) {
92
- return 0 < num && num < CURVE.r;
93
- }
94
70
  const utils = {
95
- hexToBytes: hexToBytes,
96
- bytesToHex: bytesToHex,
97
- mod: mod.mod,
98
- stringToBytes,
71
+ hexToBytes: ut.hexToBytes,
72
+ bytesToHex: ut.bytesToHex,
73
+ stringToBytes: stringToBytes,
99
74
  // TODO: do we need to export it here?
100
- hashToField: (msg, count, options = {}) => hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }),
101
- expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => expand_message_xmd(msg, DST, lenInBytes, H),
102
- /**
103
- * Can take 40 or more bytes of uniform input e.g. from CSPRNG or KDF
104
- * and convert them into private key, with the modulo bias being negligible.
105
- * As per FIPS 186 B.1.1.
106
- * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
107
- * @param hash hash output from sha512, or a similar function
108
- * @returns valid private key
109
- */
110
- hashToPrivateKey: (hash) => {
111
- hash = ensureBytes(hash);
112
- if (hash.length < 40 || hash.length > 1024)
113
- throw new Error('Expected 40-1024 bytes of private key as per FIPS 186');
114
- // hashToPrivateScalar(hash, CURVE.r)
115
- // NOTE: doesn't add +/-1
116
- const num = mod.mod(bytesToNumberBE(hash), CURVE.r);
117
- // This should never happen
118
- if (num === 0n || num === 1n)
119
- throw new Error('Invalid private key');
120
- return numberToBytesBE(num, 32);
121
- },
122
- randomBytes: (bytesLength = 32) => CURVE.randomBytes(bytesLength),
123
- // NIST SP 800-56A rev 3, section 5.6.1.2.2
124
- // https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
125
- randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(40)),
126
- getDSTLabel: () => htfDefaults.DST,
75
+ hashToField: (msg, count, options = {}) => hashToField(msg, count, { ...CURVE.htfDefaults, ...options }),
76
+ expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => expandMessageXMD(msg, DST, lenInBytes, H),
77
+ hashToPrivateKey: (hash) => Fr.toBytes(ut.hashToPrivateScalar(hash, CURVE.r)),
78
+ randomBytes: (bytesLength = groupLen) => CURVE.randomBytes(bytesLength),
79
+ randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)),
80
+ getDSTLabel: () => CURVE.htfDefaults.DST,
127
81
  setDSTLabel(newLabel) {
128
82
  // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3.1
129
83
  if (typeof newLabel !== 'string' || newLabel.length > 2048 || newLabel.length === 0) {
130
84
  throw new TypeError('Invalid DST');
131
85
  }
132
- htfDefaults.DST = newLabel;
86
+ CURVE.htfDefaults.DST = newLabel;
133
87
  },
134
88
  };
135
- function normalizePrivKey(key) {
136
- let int;
137
- if (key instanceof Uint8Array && key.length === 32)
138
- int = bytesToNumberBE(key);
139
- else if (typeof key === 'string' && key.length === 64)
140
- int = BigInt(`0x${key}`);
141
- else if (typeof key === 'number' && key > 0 && Number.isSafeInteger(key))
142
- int = BigInt(key);
143
- else if (typeof key === 'bigint' && key > 0n)
144
- int = key;
145
- else
146
- throw new TypeError('Expected valid private key');
147
- int = mod.mod(int, CURVE.r);
148
- if (!isWithinCurveOrder(int))
149
- throw new Error('Private key must be 0 < key < CURVE.r');
150
- return int;
151
- }
152
89
  // Point on G1 curve: (x, y)
153
90
  const G1 = weierstrassPoints({
154
91
  n: Fr.ORDER,
@@ -202,7 +139,7 @@ export function bls(CURVE) {
202
139
  function sign(message, privateKey) {
203
140
  const msgPoint = normP2Hash(message);
204
141
  msgPoint.assertValidity();
205
- const sigPoint = msgPoint.multiply(normalizePrivKey(privateKey));
142
+ const sigPoint = msgPoint.multiply(G1.normalizePrivateKey(privateKey));
206
143
  if (message instanceof G2.Point)
207
144
  return sigPoint;
208
145
  return Signature.encode(sigPoint);
@@ -1,41 +1,36 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  // Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
3
3
  // Differences from @noble/ed25519 1.7:
4
- // 1. Different field element lengths in ed448:
4
+ // 1. Variable field element lengths between EDDSA/ECDH:
5
5
  // EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
6
6
  // 2. Different addition formula (doubling is same)
7
7
  // 3. uvRatio differs between curves (half-expected, not only pow fn changes)
8
- // 4. Point decompression code is different too (unexpected), now using generalized formula
8
+ // 4. Point decompression code is different (unexpected), now using generalized formula
9
9
  // 5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
10
10
  import * as mod from './modular.js';
11
- import { bytesToHex, concatBytes, ensureBytes, numberToBytesLE, bytesToNumberLE, hashToPrivateScalar, validateOpts as utilOpts, } from './utils.js'; // TODO: import * as u from './utils.js'?
11
+ import * as ut from './utils.js';
12
+ import { ensureBytes } from './utils.js';
12
13
  import { wNAF } from './group.js';
13
- import { hash_to_field, validateHTFOpts } from './hash-to-curve.js';
14
+ import { hash_to_field as hashToField, validateHTFOpts } from './hash-to-curve.js';
14
15
  // Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
15
16
  const _0n = BigInt(0);
16
17
  const _1n = BigInt(1);
17
18
  const _2n = BigInt(2);
18
19
  const _8n = BigInt(8);
19
- // Should be separate from overrides, since overrides can use information about curve (for example nBits)
20
20
  function validateOpts(curve) {
21
- const opts = utilOpts(curve);
22
- if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
21
+ const opts = ut.validateOpts(curve);
22
+ if (typeof opts.hash !== 'function' || !ut.isPositiveInt(opts.hash.outputLen))
23
23
  throw new Error('Invalid hash function');
24
24
  for (const i of ['a', 'd']) {
25
- if (typeof opts[i] !== 'bigint')
26
- throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
25
+ const val = opts[i];
26
+ if (typeof val !== 'bigint')
27
+ throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
27
28
  }
28
29
  for (const fn of ['randomBytes']) {
29
30
  if (typeof opts[fn] !== 'function')
30
31
  throw new Error(`Invalid ${fn} function`);
31
32
  }
32
- for (const fn of [
33
- 'adjustScalarBytes',
34
- 'domain',
35
- 'uvRatio',
36
- 'mapToCurve',
37
- 'clearCofactor',
38
- ]) {
33
+ for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio', 'mapToCurve']) {
39
34
  if (opts[fn] === undefined)
40
35
  continue; // Optional
41
36
  if (typeof opts[fn] !== 'function')
@@ -51,34 +46,27 @@ export function twistedEdwards(curveDef) {
51
46
  const CURVE = validateOpts(curveDef);
52
47
  const Fp = CURVE.Fp;
53
48
  const CURVE_ORDER = CURVE.n;
54
- const fieldLen = Fp.BYTES; // 32 (length of one field element)
55
- if (fieldLen > 2048)
56
- throw new Error('Field lengths over 2048 are not supported');
57
- const groupLen = CURVE.nByteLength;
58
- // (2n ** 256n).toString(16);
59
- const maxGroupElement = _2n ** BigInt(groupLen * 8); // previous POW_2_256
49
+ const maxGroupElement = _2n ** BigInt(CURVE.nByteLength * 8);
60
50
  // Function overrides
61
51
  const { randomBytes } = CURVE;
62
52
  const modP = Fp.create;
63
53
  // sqrt(u/v)
64
- function _uvRatio(u, v) {
65
- try {
66
- const value = Fp.sqrt(u * Fp.invert(v));
67
- return { isValid: true, value };
68
- }
69
- catch (e) {
70
- return { isValid: false, value: _0n };
71
- }
72
- }
73
- const uvRatio = CURVE.uvRatio || _uvRatio;
74
- const _adjustScalarBytes = (bytes) => bytes; // NOOP
75
- const adjustScalarBytes = CURVE.adjustScalarBytes || _adjustScalarBytes;
76
- function _domain(data, ctx, phflag) {
77
- if (ctx.length || phflag)
78
- throw new Error('Contexts/pre-hash are not supported');
79
- return data;
80
- }
81
- const domain = CURVE.domain || _domain; // NOOP
54
+ const uvRatio = CURVE.uvRatio ||
55
+ ((u, v) => {
56
+ try {
57
+ return { isValid: true, value: Fp.sqrt(u * Fp.invert(v)) };
58
+ }
59
+ catch (e) {
60
+ return { isValid: false, value: _0n };
61
+ }
62
+ });
63
+ const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes); // NOOP
64
+ const domain = CURVE.domain ||
65
+ ((data, ctx, phflag) => {
66
+ if (ctx.length || phflag)
67
+ throw new Error('Contexts/pre-hash are not supported');
68
+ return data;
69
+ }); // NOOP
82
70
  /**
83
71
  * Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
84
72
  * Default Point works in affine coordinates: (x, y)
@@ -215,26 +203,28 @@ export function twistedEdwards(curveDef) {
215
203
  // Non-constant-time multiplication. Uses double-and-add algorithm.
216
204
  // It's faster, but should only be used when you don't care about
217
205
  // an exposed private key e.g. sig verification.
218
- // Allows scalar bigger than curve order, but less than 2^256
219
206
  multiplyUnsafe(scalar) {
220
207
  let n = normalizeScalar(scalar, CURVE_ORDER, false);
221
- const G = ExtendedPoint.BASE;
222
208
  const P0 = ExtendedPoint.ZERO;
223
209
  if (n === _0n)
224
210
  return P0;
225
211
  if (this.equals(P0) || n === _1n)
226
212
  return this;
227
- if (this.equals(G))
213
+ if (this.equals(ExtendedPoint.BASE))
228
214
  return this.wNAF(n);
229
215
  return wnaf.unsafeLadder(this, n);
230
216
  }
217
+ // Checks if point is of small order.
218
+ // If you add something to small order point, you will have "dirty"
219
+ // point with torsion component.
231
220
  // Multiplies point by cofactor and checks if the result is 0.
232
221
  isSmallOrder() {
233
222
  return this.multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO);
234
223
  }
235
- // Multiplies point by a very big scalar n and checks if the result is 0.
224
+ // Multiplies point by curve order (very big scalar CURVE.n) and checks if the result is 0.
225
+ // Returns `false` is the point is dirty.
236
226
  isTorsionFree() {
237
- return this.multiplyUnsafe(CURVE_ORDER).equals(ExtendedPoint.ZERO);
227
+ return wnaf.unsafeLadder(this, CURVE_ORDER).equals(ExtendedPoint.ZERO);
238
228
  }
239
229
  // Converts Extended point to default (x, y) coordinates.
240
230
  // Can accept precomputed Z^-1 - for example, from invertBatch.
@@ -253,18 +243,15 @@ export function twistedEdwards(curveDef) {
253
243
  return new Point(ax, ay);
254
244
  }
255
245
  clearCofactor() {
256
- if (CURVE.h === _1n)
257
- return this; // Fast-path
258
- // clear_cofactor(P) := h_eff * P
259
- // hEff = h for ed25519/ed448. Maybe worth moving to params?
260
- if (CURVE.clearCofactor)
261
- return CURVE.clearCofactor(ExtendedPoint, this);
262
- return this.multiplyUnsafe(CURVE.h);
246
+ const { h: cofactor } = CURVE;
247
+ if (cofactor === _1n)
248
+ return this;
249
+ return this.multiplyUnsafe(cofactor);
263
250
  }
264
251
  }
265
252
  ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
266
253
  ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n);
267
- const wnaf = wNAF(ExtendedPoint, groupLen * 8);
254
+ const wnaf = wNAF(ExtendedPoint, CURVE.nByteLength * 8);
268
255
  function assertExtPoint(other) {
269
256
  if (!(other instanceof ExtendedPoint))
270
257
  throw new TypeError('ExtendedPoint expected');
@@ -288,20 +275,21 @@ export function twistedEdwards(curveDef) {
288
275
  // Uses algo from RFC8032 5.1.3.
289
276
  static fromHex(hex, strict = true) {
290
277
  const { d, a } = CURVE;
291
- hex = ensureBytes(hex, fieldLen);
278
+ const len = Fp.BYTES;
279
+ hex = ensureBytes(hex, len);
292
280
  // 1. First, interpret the string as an integer in little-endian
293
281
  // representation. Bit 255 of this number is the least significant
294
282
  // bit of the x-coordinate and denote this value x_0. The
295
283
  // y-coordinate is recovered simply by clearing this bit. If the
296
284
  // resulting value is >= p, decoding fails.
297
285
  const normed = hex.slice();
298
- const lastByte = hex[fieldLen - 1];
299
- normed[fieldLen - 1] = lastByte & ~0x80;
300
- const y = bytesToNumberLE(normed);
286
+ const lastByte = hex[len - 1];
287
+ normed[len - 1] = lastByte & ~0x80;
288
+ const y = ut.bytesToNumberLE(normed);
301
289
  if (strict && y >= Fp.ORDER)
302
290
  throw new Error('Expected 0 < hex < P');
303
291
  if (!strict && y >= maxGroupElement)
304
- throw new Error('Expected 0 < hex < 2**256');
292
+ throw new Error('Expected 0 < hex < CURVE.n');
305
293
  // 2. To recover the x-coordinate, the curve equation implies
306
294
  // Ed25519: x² = (y² - 1) / (d y² + 1) (mod p).
307
295
  // Ed448: x² = (y² - 1) / (d y² - 1) (mod p).
@@ -333,14 +321,16 @@ export function twistedEdwards(curveDef) {
333
321
  // When compressing point, it's enough to only store its y coordinate
334
322
  // and use the last byte to encode sign of x.
335
323
  toRawBytes() {
336
- const bytes = numberToBytesLE(this.y, fieldLen);
337
- bytes[fieldLen - 1] |= this.x & _1n ? 0x80 : 0;
324
+ const bytes = ut.numberToBytesLE(this.y, Fp.BYTES);
325
+ bytes[Fp.BYTES - 1] |= this.x & _1n ? 0x80 : 0;
338
326
  return bytes;
339
327
  }
340
328
  // Same as toRawBytes, but returns string.
341
329
  toHex() {
342
- return bytesToHex(this.toRawBytes());
330
+ return ut.bytesToHex(this.toRawBytes());
343
331
  }
332
+ // Determines if point is in prime-order subgroup.
333
+ // Returns `false` is the point is dirty.
344
334
  isTorsionFree() {
345
335
  return ExtendedPoint.fromAffine(this).isTorsionFree();
346
336
  }
@@ -375,22 +365,22 @@ export function twistedEdwards(curveDef) {
375
365
  // Encodes byte string to elliptic curve
376
366
  // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
377
367
  static hashToCurve(msg, options) {
378
- if (!CURVE.mapToCurve)
368
+ const { mapToCurve, htfDefaults } = CURVE;
369
+ if (!mapToCurve)
379
370
  throw new Error('No mapToCurve defined for curve');
380
- msg = ensureBytes(msg);
381
- const u = hash_to_field(msg, 2, { ...CURVE.htfDefaults, ...options });
382
- const { x: x0, y: y0 } = CURVE.mapToCurve(u[0]);
383
- const { x: x1, y: y1 } = CURVE.mapToCurve(u[1]);
371
+ const u = hashToField(ensureBytes(msg), 2, { ...htfDefaults, ...options });
372
+ const { x: x0, y: y0 } = mapToCurve(u[0]);
373
+ const { x: x1, y: y1 } = mapToCurve(u[1]);
384
374
  const p = new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
385
375
  return p;
386
376
  }
387
377
  // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
388
378
  static encodeToCurve(msg, options) {
389
- if (!CURVE.mapToCurve)
379
+ const { mapToCurve, htfDefaults } = CURVE;
380
+ if (!mapToCurve)
390
381
  throw new Error('No mapToCurve defined for curve');
391
- msg = ensureBytes(msg);
392
- const u = hash_to_field(msg, 1, { ...CURVE.htfDefaults, ...options });
393
- const { x, y } = CURVE.mapToCurve(u[0]);
382
+ const u = hashToField(ensureBytes(msg), 1, { ...htfDefaults, ...options });
383
+ const { x, y } = mapToCurve(u[0]);
394
384
  return new Point(x, y).clearCofactor();
395
385
  }
396
386
  }
@@ -410,9 +400,10 @@ export function twistedEdwards(curveDef) {
410
400
  this.assertValidity();
411
401
  }
412
402
  static fromHex(hex) {
413
- const bytes = ensureBytes(hex, 2 * fieldLen);
414
- const r = Point.fromHex(bytes.slice(0, fieldLen), false);
415
- const s = bytesToNumberLE(bytes.slice(fieldLen, 2 * fieldLen));
403
+ const len = Fp.BYTES;
404
+ const bytes = ensureBytes(hex, 2 * len);
405
+ const r = Point.fromHex(bytes.slice(0, len), false);
406
+ const s = ut.bytesToNumberLE(bytes.slice(len, 2 * len));
416
407
  return new Signature(r, s);
417
408
  }
418
409
  assertValidity() {
@@ -424,15 +415,15 @@ export function twistedEdwards(curveDef) {
424
415
  return this;
425
416
  }
426
417
  toRawBytes() {
427
- return concatBytes(this.r.toRawBytes(), numberToBytesLE(this.s, fieldLen));
418
+ return ut.concatBytes(this.r.toRawBytes(), ut.numberToBytesLE(this.s, Fp.BYTES));
428
419
  }
429
420
  toHex() {
430
- return bytesToHex(this.toRawBytes());
421
+ return ut.bytesToHex(this.toRawBytes());
431
422
  }
432
423
  }
433
424
  // Little-endian SHA512 with modulo n
434
- function modlLE(hash) {
435
- return mod.mod(bytesToNumberLE(hash), CURVE_ORDER);
425
+ function modnLE(hash) {
426
+ return mod.mod(ut.bytesToNumberLE(hash), CURVE_ORDER);
436
427
  }
437
428
  /**
438
429
  * Checks for num to be in range:
@@ -443,7 +434,7 @@ export function twistedEdwards(curveDef) {
443
434
  function normalizeScalar(num, max, strict = true) {
444
435
  if (!max)
445
436
  throw new TypeError('Specify max value');
446
- if (typeof num === 'number' && Number.isSafeInteger(num))
437
+ if (ut.isPositiveInt(num))
447
438
  num = BigInt(num);
448
439
  if (typeof num === 'bigint' && num < max) {
449
440
  if (strict) {
@@ -455,36 +446,30 @@ export function twistedEdwards(curveDef) {
455
446
  return num;
456
447
  }
457
448
  }
458
- throw new TypeError('Expected valid scalar: 0 < scalar < max');
449
+ throw new TypeError(`Expected valid scalar: 0 < scalar < ${max}`);
459
450
  }
460
- function checkPrivateKey(key) {
451
+ /** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
452
+ function getExtendedPublicKey(key) {
453
+ const groupLen = CURVE.nByteLength;
461
454
  // Normalize bigint / number / string to Uint8Array
462
- key =
463
- typeof key === 'bigint' || typeof key === 'number'
464
- ? numberToBytesLE(normalizeScalar(key, maxGroupElement), groupLen)
465
- : ensureBytes(key);
466
- if (key.length !== groupLen)
467
- throw new Error(`Expected ${groupLen} bytes, got ${key.length}`);
468
- return key;
469
- }
470
- // Takes 64 bytes
471
- function getKeyFromHash(hashed) {
472
- // First 32 bytes of 64b uniformingly random input are taken,
473
- // clears 3 bits of it to produce a random field element.
455
+ const keyb = typeof key === 'bigint' || typeof key === 'number'
456
+ ? ut.numberToBytesLE(normalizeScalar(key, maxGroupElement), groupLen)
457
+ : key;
458
+ // Hash private key with curve's hash function to produce uniformingly random input
459
+ // We check byte lengths e.g.: ensureBytes(64, hash(ensureBytes(32, key)))
460
+ const hashed = ensureBytes(CURVE.hash(ensureBytes(keyb, groupLen)), 2 * groupLen);
461
+ // First half's bits are cleared to produce a random field element.
474
462
  const head = adjustScalarBytes(hashed.slice(0, groupLen));
475
- // Second 32 bytes is called key prefix (5.1.6)
463
+ // Second half is called key prefix (5.1.6)
476
464
  const prefix = hashed.slice(groupLen, 2 * groupLen);
477
465
  // The actual private scalar
478
- const scalar = modlLE(head);
466
+ const scalar = modnLE(head);
479
467
  // Point on Edwards curve aka public key
480
468
  const point = Point.BASE.multiply(scalar);
469
+ // Uint8Array representation
481
470
  const pointBytes = point.toRawBytes();
482
471
  return { head, prefix, scalar, point, pointBytes };
483
472
  }
484
- /** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
485
- function getExtendedPublicKey(key) {
486
- return getKeyFromHash(CURVE.hash(checkPrivateKey(key)));
487
- }
488
473
  /**
489
474
  * Calculates ed25519 public key. RFC8032 5.1.5
490
475
  * 1. private key is hashed with sha512, then first 32 bytes are taken from the hash
@@ -496,7 +481,7 @@ export function twistedEdwards(curveDef) {
496
481
  const EMPTY = new Uint8Array();
497
482
  function hashDomainToScalar(message, context = EMPTY) {
498
483
  context = ensureBytes(context);
499
- return modlLE(CURVE.hash(domain(message, context, !!CURVE.preHash)));
484
+ return modnLE(CURVE.hash(domain(message, context, !!CURVE.preHash)));
500
485
  }
501
486
  /** Signs message with privateKey. RFC8032 5.1.6 */
502
487
  function sign(message, privateKey, context) {
@@ -504,9 +489,9 @@ export function twistedEdwards(curveDef) {
504
489
  if (CURVE.preHash)
505
490
  message = CURVE.preHash(message);
506
491
  const { prefix, scalar, pointBytes } = getExtendedPublicKey(privateKey);
507
- const r = hashDomainToScalar(concatBytes(prefix, message), context);
492
+ const r = hashDomainToScalar(ut.concatBytes(prefix, message), context);
508
493
  const R = Point.BASE.multiply(r); // R = rG
509
- const k = hashDomainToScalar(concatBytes(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
494
+ const k = hashDomainToScalar(ut.concatBytes(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
510
495
  const s = mod.mod(r + k * scalar, CURVE_ORDER); // s = r + kp
511
496
  return new Signature(R, s).toRawBytes();
512
497
  }
@@ -545,27 +530,25 @@ export function twistedEdwards(curveDef) {
545
530
  throw new Error(`Wrong signature: ${sig}`);
546
531
  const { r, s } = sig;
547
532
  const SB = ExtendedPoint.BASE.multiplyUnsafe(s);
548
- const k = hashDomainToScalar(concatBytes(r.toRawBytes(), publicKey.toRawBytes(), message), context);
533
+ const k = hashDomainToScalar(ut.concatBytes(r.toRawBytes(), publicKey.toRawBytes(), message), context);
549
534
  const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k);
550
535
  const RkA = ExtendedPoint.fromAffine(r).add(kA);
551
536
  // [8][S]B = [8]R + [8][k]A'
552
- return RkA.subtract(SB).multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO);
537
+ return RkA.subtract(SB).clearCofactor().equals(ExtendedPoint.ZERO);
553
538
  }
554
539
  // Enable precomputes. Slows down first publicKey computation by 20ms.
555
540
  Point.BASE._setWindowSize(8);
556
541
  const utils = {
557
542
  getExtendedPublicKey,
558
- mod: modP,
559
- invert: Fp.invert,
560
543
  /**
561
544
  * Not needed for ed25519 private keys. Needed if you use scalars directly (rare).
562
545
  */
563
- hashToPrivateScalar: (hash) => hashToPrivateScalar(hash, CURVE_ORDER, true),
546
+ hashToPrivateScalar: (hash) => ut.hashToPrivateScalar(hash, CURVE_ORDER, true),
564
547
  /**
565
548
  * ed25519 private keys are uniform 32-bit strings. We do not need to check for
566
549
  * modulo bias like we do in secp256k1 randomPrivateKey()
567
550
  */
568
- randomPrivateKey: () => randomBytes(fieldLen),
551
+ randomPrivateKey: () => randomBytes(Fp.BYTES),
569
552
  /**
570
553
  * We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
571
554
  * values. This slows down first getPublicKey() by milliseconds (see Speed section),