@noble/curves 0.5.0 → 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.
Files changed (50) hide show
  1. package/README.md +62 -14
  2. package/lib/_shortw_utils.d.ts +2 -6
  3. package/lib/abstract/bls.d.ts +17 -8
  4. package/lib/abstract/bls.js +15 -78
  5. package/lib/abstract/edwards.d.ts +7 -16
  6. package/lib/abstract/edwards.js +89 -106
  7. package/lib/abstract/hash-to-curve.d.ts +10 -1
  8. package/lib/abstract/hash-to-curve.js +32 -10
  9. package/lib/abstract/modular.d.ts +8 -17
  10. package/lib/abstract/modular.js +134 -152
  11. package/lib/abstract/montgomery.js +1 -1
  12. package/lib/abstract/utils.d.ts +8 -4
  13. package/lib/abstract/utils.js +22 -14
  14. package/lib/abstract/weierstrass.d.ts +8 -8
  15. package/lib/abstract/weierstrass.js +209 -168
  16. package/lib/bls12-381.d.ts +2 -1
  17. package/lib/bls12-381.js +14 -9
  18. package/lib/ed25519.js +75 -12
  19. package/lib/ed448.js +86 -2
  20. package/lib/esm/abstract/bls.js +19 -82
  21. package/lib/esm/abstract/edwards.js +90 -107
  22. package/lib/esm/abstract/hash-to-curve.js +30 -9
  23. package/lib/esm/abstract/modular.js +128 -148
  24. package/lib/esm/abstract/montgomery.js +2 -4
  25. package/lib/esm/abstract/utils.js +20 -13
  26. package/lib/esm/abstract/weierstrass.js +210 -169
  27. package/lib/esm/bls12-381.js +13 -8
  28. package/lib/esm/ed25519.js +76 -13
  29. package/lib/esm/ed448.js +87 -3
  30. package/lib/esm/jubjub.js +5 -4
  31. package/lib/esm/p256.js +1 -1
  32. package/lib/esm/p384.js +1 -1
  33. package/lib/esm/p521.js +1 -1
  34. package/lib/esm/secp256k1.js +27 -27
  35. package/lib/esm/stark.js +5 -2
  36. package/lib/jubjub.d.ts +1 -0
  37. package/lib/jubjub.js +5 -4
  38. package/lib/p192.d.ts +4 -12
  39. package/lib/p224.d.ts +4 -12
  40. package/lib/p256.d.ts +4 -12
  41. package/lib/p256.js +1 -1
  42. package/lib/p384.d.ts +4 -12
  43. package/lib/p384.js +1 -1
  44. package/lib/p521.d.ts +4 -12
  45. package/lib/p521.js +1 -1
  46. package/lib/secp256k1.d.ts +2 -6
  47. package/lib/secp256k1.js +27 -27
  48. package/lib/stark.d.ts +1 -3
  49. package/lib/stark.js +5 -2
  50. package/package.json +2 -2
@@ -4,14 +4,15 @@
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.twistedEdwards = void 0;
6
6
  // Differences from @noble/ed25519 1.7:
7
- // 1. Different field element lengths in ed448:
7
+ // 1. Variable field element lengths between EDDSA/ECDH:
8
8
  // EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
9
9
  // 2. Different addition formula (doubling is same)
10
10
  // 3. uvRatio differs between curves (half-expected, not only pow fn changes)
11
- // 4. Point decompression code is different too (unexpected), now using generalized formula
11
+ // 4. Point decompression code is different (unexpected), now using generalized formula
12
12
  // 5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
13
13
  const mod = require("./modular.js");
14
- const utils_js_1 = require("./utils.js"); // TODO: import * as u from './utils.js'?
14
+ const ut = require("./utils.js");
15
+ const utils_js_1 = require("./utils.js");
15
16
  const group_js_1 = require("./group.js");
16
17
  const hash_to_curve_js_1 = require("./hash-to-curve.js");
17
18
  // Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
@@ -19,26 +20,20 @@ const _0n = BigInt(0);
19
20
  const _1n = BigInt(1);
20
21
  const _2n = BigInt(2);
21
22
  const _8n = BigInt(8);
22
- // Should be separate from overrides, since overrides can use information about curve (for example nBits)
23
23
  function validateOpts(curve) {
24
- const opts = (0, utils_js_1.validateOpts)(curve);
25
- if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
24
+ const opts = ut.validateOpts(curve);
25
+ if (typeof opts.hash !== 'function' || !ut.isPositiveInt(opts.hash.outputLen))
26
26
  throw new Error('Invalid hash function');
27
27
  for (const i of ['a', 'd']) {
28
- if (typeof opts[i] !== 'bigint')
29
- throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
28
+ const val = opts[i];
29
+ if (typeof val !== 'bigint')
30
+ throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
30
31
  }
31
32
  for (const fn of ['randomBytes']) {
32
33
  if (typeof opts[fn] !== 'function')
33
34
  throw new Error(`Invalid ${fn} function`);
34
35
  }
35
- for (const fn of [
36
- 'adjustScalarBytes',
37
- 'domain',
38
- 'uvRatio',
39
- 'mapToCurve',
40
- 'clearCofactor',
41
- ]) {
36
+ for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio', 'mapToCurve']) {
42
37
  if (opts[fn] === undefined)
43
38
  continue; // Optional
44
39
  if (typeof opts[fn] !== 'function')
@@ -54,34 +49,27 @@ function twistedEdwards(curveDef) {
54
49
  const CURVE = validateOpts(curveDef);
55
50
  const Fp = CURVE.Fp;
56
51
  const CURVE_ORDER = CURVE.n;
57
- const fieldLen = Fp.BYTES; // 32 (length of one field element)
58
- if (fieldLen > 2048)
59
- throw new Error('Field lengths over 2048 are not supported');
60
- const groupLen = CURVE.nByteLength;
61
- // (2n ** 256n).toString(16);
62
- const maxGroupElement = _2n ** BigInt(groupLen * 8); // previous POW_2_256
52
+ const maxGroupElement = _2n ** BigInt(CURVE.nByteLength * 8);
63
53
  // Function overrides
64
54
  const { randomBytes } = CURVE;
65
55
  const modP = Fp.create;
66
56
  // sqrt(u/v)
67
- function _uvRatio(u, v) {
68
- try {
69
- const value = Fp.sqrt(u * Fp.invert(v));
70
- return { isValid: true, value };
71
- }
72
- catch (e) {
73
- return { isValid: false, value: _0n };
74
- }
75
- }
76
- const uvRatio = CURVE.uvRatio || _uvRatio;
77
- const _adjustScalarBytes = (bytes) => bytes; // NOOP
78
- const adjustScalarBytes = CURVE.adjustScalarBytes || _adjustScalarBytes;
79
- function _domain(data, ctx, phflag) {
80
- if (ctx.length || phflag)
81
- throw new Error('Contexts/pre-hash are not supported');
82
- return data;
83
- }
84
- const domain = CURVE.domain || _domain; // NOOP
57
+ const uvRatio = CURVE.uvRatio ||
58
+ ((u, v) => {
59
+ try {
60
+ return { isValid: true, value: Fp.sqrt(u * Fp.invert(v)) };
61
+ }
62
+ catch (e) {
63
+ return { isValid: false, value: _0n };
64
+ }
65
+ });
66
+ const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes); // NOOP
67
+ const domain = CURVE.domain ||
68
+ ((data, ctx, phflag) => {
69
+ if (ctx.length || phflag)
70
+ throw new Error('Contexts/pre-hash are not supported');
71
+ return data;
72
+ }); // NOOP
85
73
  /**
86
74
  * Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
87
75
  * Default Point works in affine coordinates: (x, y)
@@ -218,26 +206,28 @@ function twistedEdwards(curveDef) {
218
206
  // Non-constant-time multiplication. Uses double-and-add algorithm.
219
207
  // It's faster, but should only be used when you don't care about
220
208
  // an exposed private key e.g. sig verification.
221
- // Allows scalar bigger than curve order, but less than 2^256
222
209
  multiplyUnsafe(scalar) {
223
210
  let n = normalizeScalar(scalar, CURVE_ORDER, false);
224
- const G = ExtendedPoint.BASE;
225
211
  const P0 = ExtendedPoint.ZERO;
226
212
  if (n === _0n)
227
213
  return P0;
228
214
  if (this.equals(P0) || n === _1n)
229
215
  return this;
230
- if (this.equals(G))
216
+ if (this.equals(ExtendedPoint.BASE))
231
217
  return this.wNAF(n);
232
218
  return wnaf.unsafeLadder(this, n);
233
219
  }
220
+ // Checks if point is of small order.
221
+ // If you add something to small order point, you will have "dirty"
222
+ // point with torsion component.
234
223
  // Multiplies point by cofactor and checks if the result is 0.
235
224
  isSmallOrder() {
236
225
  return this.multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO);
237
226
  }
238
- // Multiplies point by a very big scalar n and checks if the result is 0.
227
+ // Multiplies point by curve order (very big scalar CURVE.n) and checks if the result is 0.
228
+ // Returns `false` is the point is dirty.
239
229
  isTorsionFree() {
240
- return this.multiplyUnsafe(CURVE_ORDER).equals(ExtendedPoint.ZERO);
230
+ return wnaf.unsafeLadder(this, CURVE_ORDER).equals(ExtendedPoint.ZERO);
241
231
  }
242
232
  // Converts Extended point to default (x, y) coordinates.
243
233
  // Can accept precomputed Z^-1 - for example, from invertBatch.
@@ -256,18 +246,15 @@ function twistedEdwards(curveDef) {
256
246
  return new Point(ax, ay);
257
247
  }
258
248
  clearCofactor() {
259
- if (CURVE.h === _1n)
260
- return this; // Fast-path
261
- // clear_cofactor(P) := h_eff * P
262
- // hEff = h for ed25519/ed448. Maybe worth moving to params?
263
- if (CURVE.clearCofactor)
264
- return CURVE.clearCofactor(ExtendedPoint, this);
265
- return this.multiplyUnsafe(CURVE.h);
249
+ const { h: cofactor } = CURVE;
250
+ if (cofactor === _1n)
251
+ return this;
252
+ return this.multiplyUnsafe(cofactor);
266
253
  }
267
254
  }
268
255
  ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
269
256
  ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n);
270
- const wnaf = (0, group_js_1.wNAF)(ExtendedPoint, groupLen * 8);
257
+ const wnaf = (0, group_js_1.wNAF)(ExtendedPoint, CURVE.nByteLength * 8);
271
258
  function assertExtPoint(other) {
272
259
  if (!(other instanceof ExtendedPoint))
273
260
  throw new TypeError('ExtendedPoint expected');
@@ -291,20 +278,21 @@ function twistedEdwards(curveDef) {
291
278
  // Uses algo from RFC8032 5.1.3.
292
279
  static fromHex(hex, strict = true) {
293
280
  const { d, a } = CURVE;
294
- hex = (0, utils_js_1.ensureBytes)(hex, fieldLen);
281
+ const len = Fp.BYTES;
282
+ hex = (0, utils_js_1.ensureBytes)(hex, len);
295
283
  // 1. First, interpret the string as an integer in little-endian
296
284
  // representation. Bit 255 of this number is the least significant
297
285
  // bit of the x-coordinate and denote this value x_0. The
298
286
  // y-coordinate is recovered simply by clearing this bit. If the
299
287
  // resulting value is >= p, decoding fails.
300
288
  const normed = hex.slice();
301
- const lastByte = hex[fieldLen - 1];
302
- normed[fieldLen - 1] = lastByte & ~0x80;
303
- const y = (0, utils_js_1.bytesToNumberLE)(normed);
289
+ const lastByte = hex[len - 1];
290
+ normed[len - 1] = lastByte & ~0x80;
291
+ const y = ut.bytesToNumberLE(normed);
304
292
  if (strict && y >= Fp.ORDER)
305
293
  throw new Error('Expected 0 < hex < P');
306
294
  if (!strict && y >= maxGroupElement)
307
- throw new Error('Expected 0 < hex < 2**256');
295
+ throw new Error('Expected 0 < hex < CURVE.n');
308
296
  // 2. To recover the x-coordinate, the curve equation implies
309
297
  // Ed25519: x² = (y² - 1) / (d y² + 1) (mod p).
310
298
  // Ed448: x² = (y² - 1) / (d y² - 1) (mod p).
@@ -336,14 +324,16 @@ function twistedEdwards(curveDef) {
336
324
  // When compressing point, it's enough to only store its y coordinate
337
325
  // and use the last byte to encode sign of x.
338
326
  toRawBytes() {
339
- const bytes = (0, utils_js_1.numberToBytesLE)(this.y, fieldLen);
340
- bytes[fieldLen - 1] |= this.x & _1n ? 0x80 : 0;
327
+ const bytes = ut.numberToBytesLE(this.y, Fp.BYTES);
328
+ bytes[Fp.BYTES - 1] |= this.x & _1n ? 0x80 : 0;
341
329
  return bytes;
342
330
  }
343
331
  // Same as toRawBytes, but returns string.
344
332
  toHex() {
345
- return (0, utils_js_1.bytesToHex)(this.toRawBytes());
333
+ return ut.bytesToHex(this.toRawBytes());
346
334
  }
335
+ // Determines if point is in prime-order subgroup.
336
+ // Returns `false` is the point is dirty.
347
337
  isTorsionFree() {
348
338
  return ExtendedPoint.fromAffine(this).isTorsionFree();
349
339
  }
@@ -378,22 +368,22 @@ function twistedEdwards(curveDef) {
378
368
  // Encodes byte string to elliptic curve
379
369
  // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
380
370
  static hashToCurve(msg, options) {
381
- if (!CURVE.mapToCurve)
371
+ const { mapToCurve, htfDefaults } = CURVE;
372
+ if (!mapToCurve)
382
373
  throw new Error('No mapToCurve defined for curve');
383
- msg = (0, utils_js_1.ensureBytes)(msg);
384
- const u = (0, hash_to_curve_js_1.hash_to_field)(msg, 2, { ...CURVE.htfDefaults, ...options });
385
- const { x: x0, y: y0 } = CURVE.mapToCurve(u[0]);
386
- const { x: x1, y: y1 } = CURVE.mapToCurve(u[1]);
374
+ const u = (0, hash_to_curve_js_1.hash_to_field)((0, utils_js_1.ensureBytes)(msg), 2, { ...htfDefaults, ...options });
375
+ const { x: x0, y: y0 } = mapToCurve(u[0]);
376
+ const { x: x1, y: y1 } = mapToCurve(u[1]);
387
377
  const p = new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
388
378
  return p;
389
379
  }
390
380
  // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
391
381
  static encodeToCurve(msg, options) {
392
- if (!CURVE.mapToCurve)
382
+ const { mapToCurve, htfDefaults } = CURVE;
383
+ if (!mapToCurve)
393
384
  throw new Error('No mapToCurve defined for curve');
394
- msg = (0, utils_js_1.ensureBytes)(msg);
395
- const u = (0, hash_to_curve_js_1.hash_to_field)(msg, 1, { ...CURVE.htfDefaults, ...options });
396
- const { x, y } = CURVE.mapToCurve(u[0]);
385
+ const u = (0, hash_to_curve_js_1.hash_to_field)((0, utils_js_1.ensureBytes)(msg), 1, { ...htfDefaults, ...options });
386
+ const { x, y } = mapToCurve(u[0]);
397
387
  return new Point(x, y).clearCofactor();
398
388
  }
399
389
  }
@@ -413,9 +403,10 @@ function twistedEdwards(curveDef) {
413
403
  this.assertValidity();
414
404
  }
415
405
  static fromHex(hex) {
416
- const bytes = (0, utils_js_1.ensureBytes)(hex, 2 * fieldLen);
417
- const r = Point.fromHex(bytes.slice(0, fieldLen), false);
418
- const s = (0, utils_js_1.bytesToNumberLE)(bytes.slice(fieldLen, 2 * fieldLen));
406
+ const len = Fp.BYTES;
407
+ const bytes = (0, utils_js_1.ensureBytes)(hex, 2 * len);
408
+ const r = Point.fromHex(bytes.slice(0, len), false);
409
+ const s = ut.bytesToNumberLE(bytes.slice(len, 2 * len));
419
410
  return new Signature(r, s);
420
411
  }
421
412
  assertValidity() {
@@ -427,15 +418,15 @@ function twistedEdwards(curveDef) {
427
418
  return this;
428
419
  }
429
420
  toRawBytes() {
430
- return (0, utils_js_1.concatBytes)(this.r.toRawBytes(), (0, utils_js_1.numberToBytesLE)(this.s, fieldLen));
421
+ return ut.concatBytes(this.r.toRawBytes(), ut.numberToBytesLE(this.s, Fp.BYTES));
431
422
  }
432
423
  toHex() {
433
- return (0, utils_js_1.bytesToHex)(this.toRawBytes());
424
+ return ut.bytesToHex(this.toRawBytes());
434
425
  }
435
426
  }
436
427
  // Little-endian SHA512 with modulo n
437
- function modlLE(hash) {
438
- return mod.mod((0, utils_js_1.bytesToNumberLE)(hash), CURVE_ORDER);
428
+ function modnLE(hash) {
429
+ return mod.mod(ut.bytesToNumberLE(hash), CURVE_ORDER);
439
430
  }
440
431
  /**
441
432
  * Checks for num to be in range:
@@ -446,7 +437,7 @@ function twistedEdwards(curveDef) {
446
437
  function normalizeScalar(num, max, strict = true) {
447
438
  if (!max)
448
439
  throw new TypeError('Specify max value');
449
- if (typeof num === 'number' && Number.isSafeInteger(num))
440
+ if (ut.isPositiveInt(num))
450
441
  num = BigInt(num);
451
442
  if (typeof num === 'bigint' && num < max) {
452
443
  if (strict) {
@@ -458,36 +449,30 @@ function twistedEdwards(curveDef) {
458
449
  return num;
459
450
  }
460
451
  }
461
- throw new TypeError('Expected valid scalar: 0 < scalar < max');
452
+ throw new TypeError(`Expected valid scalar: 0 < scalar < ${max}`);
462
453
  }
463
- function checkPrivateKey(key) {
454
+ /** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
455
+ function getExtendedPublicKey(key) {
456
+ const groupLen = CURVE.nByteLength;
464
457
  // Normalize bigint / number / string to Uint8Array
465
- key =
466
- typeof key === 'bigint' || typeof key === 'number'
467
- ? (0, utils_js_1.numberToBytesLE)(normalizeScalar(key, maxGroupElement), groupLen)
468
- : (0, utils_js_1.ensureBytes)(key);
469
- if (key.length !== groupLen)
470
- throw new Error(`Expected ${groupLen} bytes, got ${key.length}`);
471
- return key;
472
- }
473
- // Takes 64 bytes
474
- function getKeyFromHash(hashed) {
475
- // First 32 bytes of 64b uniformingly random input are taken,
476
- // clears 3 bits of it to produce a random field element.
458
+ const keyb = typeof key === 'bigint' || typeof key === 'number'
459
+ ? ut.numberToBytesLE(normalizeScalar(key, maxGroupElement), groupLen)
460
+ : key;
461
+ // Hash private key with curve's hash function to produce uniformingly random input
462
+ // We check byte lengths e.g.: ensureBytes(64, hash(ensureBytes(32, key)))
463
+ const hashed = (0, utils_js_1.ensureBytes)(CURVE.hash((0, utils_js_1.ensureBytes)(keyb, groupLen)), 2 * groupLen);
464
+ // First half's bits are cleared to produce a random field element.
477
465
  const head = adjustScalarBytes(hashed.slice(0, groupLen));
478
- // Second 32 bytes is called key prefix (5.1.6)
466
+ // Second half is called key prefix (5.1.6)
479
467
  const prefix = hashed.slice(groupLen, 2 * groupLen);
480
468
  // The actual private scalar
481
- const scalar = modlLE(head);
469
+ const scalar = modnLE(head);
482
470
  // Point on Edwards curve aka public key
483
471
  const point = Point.BASE.multiply(scalar);
472
+ // Uint8Array representation
484
473
  const pointBytes = point.toRawBytes();
485
474
  return { head, prefix, scalar, point, pointBytes };
486
475
  }
487
- /** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
488
- function getExtendedPublicKey(key) {
489
- return getKeyFromHash(CURVE.hash(checkPrivateKey(key)));
490
- }
491
476
  /**
492
477
  * Calculates ed25519 public key. RFC8032 5.1.5
493
478
  * 1. private key is hashed with sha512, then first 32 bytes are taken from the hash
@@ -499,7 +484,7 @@ function twistedEdwards(curveDef) {
499
484
  const EMPTY = new Uint8Array();
500
485
  function hashDomainToScalar(message, context = EMPTY) {
501
486
  context = (0, utils_js_1.ensureBytes)(context);
502
- return modlLE(CURVE.hash(domain(message, context, !!CURVE.preHash)));
487
+ return modnLE(CURVE.hash(domain(message, context, !!CURVE.preHash)));
503
488
  }
504
489
  /** Signs message with privateKey. RFC8032 5.1.6 */
505
490
  function sign(message, privateKey, context) {
@@ -507,9 +492,9 @@ function twistedEdwards(curveDef) {
507
492
  if (CURVE.preHash)
508
493
  message = CURVE.preHash(message);
509
494
  const { prefix, scalar, pointBytes } = getExtendedPublicKey(privateKey);
510
- const r = hashDomainToScalar((0, utils_js_1.concatBytes)(prefix, message), context);
495
+ const r = hashDomainToScalar(ut.concatBytes(prefix, message), context);
511
496
  const R = Point.BASE.multiply(r); // R = rG
512
- const k = hashDomainToScalar((0, utils_js_1.concatBytes)(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
497
+ const k = hashDomainToScalar(ut.concatBytes(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
513
498
  const s = mod.mod(r + k * scalar, CURVE_ORDER); // s = r + kp
514
499
  return new Signature(R, s).toRawBytes();
515
500
  }
@@ -548,27 +533,25 @@ function twistedEdwards(curveDef) {
548
533
  throw new Error(`Wrong signature: ${sig}`);
549
534
  const { r, s } = sig;
550
535
  const SB = ExtendedPoint.BASE.multiplyUnsafe(s);
551
- const k = hashDomainToScalar((0, utils_js_1.concatBytes)(r.toRawBytes(), publicKey.toRawBytes(), message), context);
536
+ const k = hashDomainToScalar(ut.concatBytes(r.toRawBytes(), publicKey.toRawBytes(), message), context);
552
537
  const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k);
553
538
  const RkA = ExtendedPoint.fromAffine(r).add(kA);
554
539
  // [8][S]B = [8]R + [8][k]A'
555
- return RkA.subtract(SB).multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO);
540
+ return RkA.subtract(SB).clearCofactor().equals(ExtendedPoint.ZERO);
556
541
  }
557
542
  // Enable precomputes. Slows down first publicKey computation by 20ms.
558
543
  Point.BASE._setWindowSize(8);
559
544
  const utils = {
560
545
  getExtendedPublicKey,
561
- mod: modP,
562
- invert: Fp.invert,
563
546
  /**
564
547
  * Not needed for ed25519 private keys. Needed if you use scalars directly (rare).
565
548
  */
566
- hashToPrivateScalar: (hash) => (0, utils_js_1.hashToPrivateScalar)(hash, CURVE_ORDER, true),
549
+ hashToPrivateScalar: (hash) => ut.hashToPrivateScalar(hash, CURVE_ORDER, true),
567
550
  /**
568
551
  * ed25519 private keys are uniform 32-bit strings. We do not need to check for
569
552
  * modulo bias like we do in secp256k1 randomPrivateKey()
570
553
  */
571
- randomPrivateKey: () => randomBytes(fieldLen),
554
+ randomPrivateKey: () => randomBytes(Fp.BYTES),
572
555
  /**
573
556
  * We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
574
557
  * values. This slows down first getPublicKey() by milliseconds (see Speed section),
@@ -6,12 +6,21 @@ export declare type htfOpts = {
6
6
  p: bigint;
7
7
  m: number;
8
8
  k: number;
9
- expand: boolean;
9
+ expand?: 'xmd' | 'xof';
10
10
  hash: CHash;
11
11
  };
12
12
  export declare function validateHTFOpts(opts: htfOpts): void;
13
13
  export declare function stringToBytes(str: string): Uint8Array;
14
14
  export declare function expand_message_xmd(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash): Uint8Array;
15
+ export declare function expand_message_xof(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, k: number, H: CHash): Uint8Array;
16
+ /**
17
+ * Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
18
+ * https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
19
+ * @param msg a byte string containing the message to hash
20
+ * @param count the number of elements of F to output
21
+ * @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
22
+ * @returns [u_0, ..., u_(count - 1)], a list of field elements.
23
+ */
15
24
  export declare function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
16
25
  export declare function isogenyMap<T, F extends mod.Field<T>>(field: F, map: [T[], T[], T[], T[]]): (x: T, y: T) => {
17
26
  x: T;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isogenyMap = exports.hash_to_field = exports.expand_message_xmd = exports.stringToBytes = exports.validateHTFOpts = void 0;
3
+ exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = exports.validateHTFOpts = void 0;
4
4
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
5
  const utils_js_1 = require("./utils.js");
6
6
  const mod = require("./modular.js");
@@ -13,7 +13,7 @@ function validateHTFOpts(opts) {
13
13
  throw new Error('Invalid htf/m');
14
14
  if (typeof opts.k !== 'number')
15
15
  throw new Error('Invalid htf/k');
16
- if (typeof opts.expand !== 'boolean')
16
+ if (opts.expand !== 'xmd' && opts.expand !== 'xof' && opts.expand !== undefined)
17
17
  throw new Error('Invalid htf/expand');
18
18
  if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
19
19
  throw new Error('Invalid htf/hash function');
@@ -81,13 +81,32 @@ function expand_message_xmd(msg, DST, lenInBytes, H) {
81
81
  return pseudo_random_bytes.slice(0, lenInBytes);
82
82
  }
83
83
  exports.expand_message_xmd = expand_message_xmd;
84
- // hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
85
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
86
- // Inputs:
87
- // msg - a byte string containing the message to hash.
88
- // count - the number of elements of F to output.
89
- // Outputs:
90
- // [u_0, ..., u_(count - 1)], a list of field elements.
84
+ function expand_message_xof(msg, DST, lenInBytes, k, H) {
85
+ // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3
86
+ // DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
87
+ if (DST.length > 255) {
88
+ const dkLen = Math.ceil((2 * k) / 8);
89
+ DST = H.create({ dkLen }).update(stringToBytes('H2C-OVERSIZE-DST-')).update(DST).digest();
90
+ }
91
+ if (lenInBytes > 65535 || DST.length > 255)
92
+ throw new Error('expand_message_xof: invalid lenInBytes');
93
+ return (H.create({ dkLen: lenInBytes })
94
+ .update(msg)
95
+ .update(i2osp(lenInBytes, 2))
96
+ // 2. DST_prime = DST || I2OSP(len(DST), 1)
97
+ .update(DST)
98
+ .update(i2osp(DST.length, 1))
99
+ .digest());
100
+ }
101
+ exports.expand_message_xof = expand_message_xof;
102
+ /**
103
+ * Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
104
+ * https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
105
+ * @param msg a byte string containing the message to hash
106
+ * @param count the number of elements of F to output
107
+ * @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
108
+ * @returns [u_0, ..., u_(count - 1)], a list of field elements.
109
+ */
91
110
  function hash_to_field(msg, count, options) {
92
111
  // if options is provided but incomplete, fill any missing fields with the
93
112
  // value in hftDefaults (ie hash to G2).
@@ -96,9 +115,12 @@ function hash_to_field(msg, count, options) {
96
115
  const len_in_bytes = count * options.m * L;
97
116
  const DST = stringToBytes(options.DST);
98
117
  let pseudo_random_bytes = msg;
99
- if (options.expand) {
118
+ if (options.expand === 'xmd') {
100
119
  pseudo_random_bytes = expand_message_xmd(msg, DST, len_in_bytes, options.hash);
101
120
  }
121
+ else if (options.expand === 'xof') {
122
+ pseudo_random_bytes = expand_message_xof(msg, DST, len_in_bytes, options.k, options.hash);
123
+ }
102
124
  const u = new Array(count);
103
125
  for (let i = 0; i < count; i++) {
104
126
  const e = new Array(options.m);
@@ -8,18 +8,8 @@ export declare function mod(a: bigint, b: bigint): bigint;
8
8
  export declare function pow(num: bigint, power: bigint, modulo: bigint): bigint;
9
9
  export declare function pow2(x: bigint, power: bigint, modulo: bigint): bigint;
10
10
  export declare function invert(number: bigint, modulo: bigint): bigint;
11
- /**
12
- * Calculates Legendre symbol (a | p), which denotes the value of a^((p-1)/2) (mod p).
13
- * * (a | p) ≡ 1 if a is a square (mod p)
14
- * * (a | p) ≡ -1 if a is not a square (mod p)
15
- * * (a | p) ≡ 0 if a ≡ 0 (mod p)
16
- */
17
- export declare function legendre(num: bigint, fieldPrime: bigint): bigint;
18
- /**
19
- * Calculates square root of a number in a finite field.
20
- * √a mod P
21
- */
22
- export declare function sqrt(number: bigint, modulo: bigint): bigint;
11
+ export declare function tonelliShanks(P: bigint): <T>(Fp: Field<T>, n: T) => T;
12
+ export declare function FpSqrt(P: bigint): <T>(Fp: Field<T>, n: T) => T;
23
13
  export declare const isNegativeLE: (num: bigint, modulo: bigint) => boolean;
24
14
  export interface Field<T> {
25
15
  ORDER: bigint;
@@ -57,8 +47,9 @@ export declare function validateField<T>(field: Field<T>): void;
57
47
  export declare function FpPow<T>(f: Field<T>, num: T, power: bigint): T;
58
48
  export declare function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[];
59
49
  export declare function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T;
60
- export declare function Fp(ORDER: bigint, bitLen?: number, isLE?: boolean, redef?: Partial<Field<bigint>>): Readonly<Field<bigint>>;
61
- export declare function FpSqrt<T>(Fp: Field<T>): {
62
- sqrt: (x: T) => T;
63
- isSquare: (x: T) => boolean;
64
- };
50
+ export declare function FpIsSquare<T>(f: Field<T>): (x: T) => boolean;
51
+ declare type FpField = Field<bigint> & Required<Pick<Field<bigint>, 'isOdd'>>;
52
+ export declare function Fp(ORDER: bigint, bitLen?: number, isLE?: boolean, redef?: Partial<Field<bigint>>): Readonly<FpField>;
53
+ export declare function FpSqrtOdd<T>(Fp: Field<T>, elm: T): T;
54
+ export declare function FpSqrtEven<T>(Fp: Field<T>, elm: T): T;
55
+ export {};