@noble/curves 1.9.4 → 1.9.6

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 (124) hide show
  1. package/abstract/bls.d.ts +2 -2
  2. package/abstract/bls.d.ts.map +1 -1
  3. package/abstract/curve.d.ts +47 -46
  4. package/abstract/curve.d.ts.map +1 -1
  5. package/abstract/curve.js +9 -6
  6. package/abstract/curve.js.map +1 -1
  7. package/abstract/edwards.d.ts +41 -33
  8. package/abstract/edwards.d.ts.map +1 -1
  9. package/abstract/edwards.js +166 -170
  10. package/abstract/edwards.js.map +1 -1
  11. package/abstract/modular.d.ts +1 -1
  12. package/abstract/modular.d.ts.map +1 -1
  13. package/abstract/modular.js +4 -4
  14. package/abstract/modular.js.map +1 -1
  15. package/abstract/montgomery.d.ts +2 -6
  16. package/abstract/montgomery.d.ts.map +1 -1
  17. package/abstract/montgomery.js +13 -10
  18. package/abstract/montgomery.js.map +1 -1
  19. package/abstract/tower.d.ts +9 -7
  20. package/abstract/tower.d.ts.map +1 -1
  21. package/abstract/tower.js +569 -357
  22. package/abstract/tower.js.map +1 -1
  23. package/abstract/weierstrass.d.ts +162 -92
  24. package/abstract/weierstrass.d.ts.map +1 -1
  25. package/abstract/weierstrass.js +394 -336
  26. package/abstract/weierstrass.js.map +1 -1
  27. package/bls12-381.d.ts.map +1 -1
  28. package/bls12-381.js +9 -42
  29. package/bls12-381.js.map +1 -1
  30. package/bn254.d.ts.map +1 -1
  31. package/bn254.js +2 -34
  32. package/bn254.js.map +1 -1
  33. package/ed25519.d.ts +15 -15
  34. package/ed25519.d.ts.map +1 -1
  35. package/ed25519.js +51 -48
  36. package/ed25519.js.map +1 -1
  37. package/ed448.d.ts +16 -17
  38. package/ed448.d.ts.map +1 -1
  39. package/ed448.js +67 -48
  40. package/ed448.js.map +1 -1
  41. package/esm/abstract/bls.d.ts +2 -2
  42. package/esm/abstract/bls.d.ts.map +1 -1
  43. package/esm/abstract/curve.d.ts +47 -46
  44. package/esm/abstract/curve.d.ts.map +1 -1
  45. package/esm/abstract/curve.js +9 -6
  46. package/esm/abstract/curve.js.map +1 -1
  47. package/esm/abstract/edwards.d.ts +41 -33
  48. package/esm/abstract/edwards.d.ts.map +1 -1
  49. package/esm/abstract/edwards.js +167 -171
  50. package/esm/abstract/edwards.js.map +1 -1
  51. package/esm/abstract/modular.d.ts +1 -1
  52. package/esm/abstract/modular.d.ts.map +1 -1
  53. package/esm/abstract/modular.js +4 -4
  54. package/esm/abstract/modular.js.map +1 -1
  55. package/esm/abstract/montgomery.d.ts +2 -6
  56. package/esm/abstract/montgomery.d.ts.map +1 -1
  57. package/esm/abstract/montgomery.js +14 -11
  58. package/esm/abstract/montgomery.js.map +1 -1
  59. package/esm/abstract/tower.d.ts +9 -7
  60. package/esm/abstract/tower.d.ts.map +1 -1
  61. package/esm/abstract/tower.js +570 -358
  62. package/esm/abstract/tower.js.map +1 -1
  63. package/esm/abstract/weierstrass.d.ts +162 -92
  64. package/esm/abstract/weierstrass.d.ts.map +1 -1
  65. package/esm/abstract/weierstrass.js +395 -338
  66. package/esm/abstract/weierstrass.js.map +1 -1
  67. package/esm/bls12-381.d.ts.map +1 -1
  68. package/esm/bls12-381.js +10 -43
  69. package/esm/bls12-381.js.map +1 -1
  70. package/esm/bn254.d.ts.map +1 -1
  71. package/esm/bn254.js +3 -35
  72. package/esm/bn254.js.map +1 -1
  73. package/esm/ed25519.d.ts +15 -15
  74. package/esm/ed25519.d.ts.map +1 -1
  75. package/esm/ed25519.js +51 -48
  76. package/esm/ed25519.js.map +1 -1
  77. package/esm/ed448.d.ts +16 -17
  78. package/esm/ed448.d.ts.map +1 -1
  79. package/esm/ed448.js +68 -49
  80. package/esm/ed448.js.map +1 -1
  81. package/esm/misc.js +2 -2
  82. package/esm/misc.js.map +1 -1
  83. package/esm/nist.d.ts +6 -0
  84. package/esm/nist.d.ts.map +1 -1
  85. package/esm/nist.js +6 -0
  86. package/esm/nist.js.map +1 -1
  87. package/esm/secp256k1.d.ts +2 -6
  88. package/esm/secp256k1.d.ts.map +1 -1
  89. package/esm/secp256k1.js +34 -35
  90. package/esm/secp256k1.js.map +1 -1
  91. package/esm/utils.d.ts +14 -0
  92. package/esm/utils.d.ts.map +1 -1
  93. package/esm/utils.js +43 -0
  94. package/esm/utils.js.map +1 -1
  95. package/misc.js +2 -2
  96. package/misc.js.map +1 -1
  97. package/nist.d.ts +6 -0
  98. package/nist.d.ts.map +1 -1
  99. package/nist.js +7 -1
  100. package/nist.js.map +1 -1
  101. package/package.json +2 -2
  102. package/secp256k1.d.ts +2 -6
  103. package/secp256k1.d.ts.map +1 -1
  104. package/secp256k1.js +33 -34
  105. package/secp256k1.js.map +1 -1
  106. package/src/abstract/bls.ts +2 -2
  107. package/src/abstract/curve.ts +131 -68
  108. package/src/abstract/edwards.ts +210 -219
  109. package/src/abstract/modular.ts +4 -4
  110. package/src/abstract/montgomery.ts +16 -16
  111. package/src/abstract/tower.ts +630 -382
  112. package/src/abstract/weierstrass.ts +587 -484
  113. package/src/bls12-381.ts +10 -42
  114. package/src/bn254.ts +3 -34
  115. package/src/ed25519.ts +62 -58
  116. package/src/ed448.ts +74 -77
  117. package/src/misc.ts +2 -2
  118. package/src/nist.ts +7 -0
  119. package/src/secp256k1.ts +35 -36
  120. package/src/utils.ts +48 -0
  121. package/utils.d.ts +14 -0
  122. package/utils.d.ts.map +1 -1
  123. package/utils.js +47 -0
  124. package/utils.js.map +1 -1
@@ -2,13 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DER = exports.DERErr = void 0;
4
4
  exports._splitEndoScalar = _splitEndoScalar;
5
- exports._legacyHelperEquat = _legacyHelperEquat;
6
5
  exports._normFnElement = _normFnElement;
7
6
  exports.weierstrassN = weierstrassN;
8
- exports.weierstrassPoints = weierstrassPoints;
9
7
  exports.SWUFpSqrtRatio = SWUFpSqrtRatio;
10
8
  exports.mapToCurveSimpleSWU = mapToCurveSimpleSWU;
9
+ exports.ecdh = ecdh;
11
10
  exports.ecdsa = ecdsa;
11
+ exports.weierstrassPoints = weierstrassPoints;
12
+ exports._legacyHelperEquat = _legacyHelperEquat;
12
13
  exports.weierstrass = weierstrass;
13
14
  /**
14
15
  * Short Weierstrass curve methods. The formula is: y² = x³ + ax + b.
@@ -72,11 +73,22 @@ function _splitEndoScalar(k, basis, n) {
72
73
  }
73
74
  return { k1neg, k1, k2neg, k2 };
74
75
  }
75
- function validateSigVerOpts(opts) {
76
- if (opts.lowS !== undefined)
77
- (0, utils_ts_1.abool)('lowS', opts.lowS);
78
- if (opts.prehash !== undefined)
79
- (0, utils_ts_1.abool)('prehash', opts.prehash);
76
+ function validateSigFormat(format) {
77
+ if (!['compact', 'recovered', 'der'].includes(format))
78
+ throw new Error('Signature format must be "compact", "recovered", or "der"');
79
+ return format;
80
+ }
81
+ function validateSigOpts(opts, def) {
82
+ const optsn = {};
83
+ for (let optName of Object.keys(def)) {
84
+ // @ts-ignore
85
+ optsn[optName] = opts[optName] === undefined ? def[optName] : opts[optName];
86
+ }
87
+ (0, utils_ts_1._abool2)(optsn.lowS, 'lowS');
88
+ (0, utils_ts_1._abool2)(optsn.prehash, 'prehash');
89
+ if (optsn.format !== undefined)
90
+ validateSigFormat(optsn.format);
91
+ return optsn;
80
92
  }
81
93
  class DERErr extends Error {
82
94
  constructor(m = '') {
@@ -198,19 +210,6 @@ exports.DER = {
198
210
  // Be friendly to bad ECMAScript parsers by not using bigint literals
199
211
  // prettier-ignore
200
212
  const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
201
- // TODO: remove
202
- function _legacyHelperEquat(Fp, a, b) {
203
- /**
204
- * y² = x³ + ax + b: Short weierstrass curve formula. Takes x, returns y².
205
- * @returns y²
206
- */
207
- function weierstrassEquation(x) {
208
- const x2 = Fp.sqr(x); // x * x
209
- const x3 = Fp.mul(x2, x); // x² * x
210
- return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x³ + a * x + b
211
- }
212
- return weierstrassEquation;
213
- }
214
213
  function _normFnElement(Fn, key) {
215
214
  const { BYTES: expected } = Fn;
216
215
  let num;
@@ -230,10 +229,29 @@ function _normFnElement(Fn, key) {
230
229
  throw new Error('invalid private key: out of range [1..N-1]');
231
230
  return num;
232
231
  }
233
- function weierstrassN(CURVE, curveOpts = {}) {
234
- const { Fp, Fn } = (0, curve_ts_1._createCurveFields)('weierstrass', CURVE, curveOpts);
232
+ /**
233
+ * Creates weierstrass Point constructor, based on specified curve options.
234
+ *
235
+ * @example
236
+ ```js
237
+ const opts = {
238
+ p: BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'),
239
+ n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
240
+ h: BigInt(1),
241
+ a: BigInt('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc'),
242
+ b: BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b'),
243
+ Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
244
+ Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
245
+ };
246
+ const p256_Point = weierstrass(opts);
247
+ ```
248
+ */
249
+ function weierstrassN(params, extraOpts = {}) {
250
+ const validated = (0, curve_ts_1._createCurveFields)('weierstrass', params, extraOpts);
251
+ const { Fp, Fn } = validated;
252
+ let CURVE = validated.CURVE;
235
253
  const { h: cofactor, n: CURVE_ORDER } = CURVE;
236
- (0, utils_ts_1._validateObject)(curveOpts, {}, {
254
+ (0, utils_ts_1._validateObject)(extraOpts, {}, {
237
255
  allowInfinityPoint: 'boolean',
238
256
  clearCofactor: 'function',
239
257
  isTorsionFree: 'function',
@@ -242,13 +260,14 @@ function weierstrassN(CURVE, curveOpts = {}) {
242
260
  endo: 'object',
243
261
  wrapPrivateKey: 'boolean',
244
262
  });
245
- const { endo } = curveOpts;
263
+ const { endo } = extraOpts;
246
264
  if (endo) {
247
265
  // validateObject(endo, { beta: 'bigint', splitScalar: 'function' });
248
266
  if (!Fp.is0(CURVE.a) || typeof endo.beta !== 'bigint' || !Array.isArray(endo.basises)) {
249
267
  throw new Error('invalid endo: expected "beta": bigint and "basises": array');
250
268
  }
251
269
  }
270
+ const lengths = getWLengths(Fp, Fn);
252
271
  function assertCompressionIsSupported() {
253
272
  if (!Fp.isOdd)
254
273
  throw new Error('compression is not supported: Field does not have .isOdd()');
@@ -257,7 +276,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
257
276
  function pointToBytes(_c, point, isCompressed) {
258
277
  const { x, y } = point.toAffine();
259
278
  const bx = Fp.toBytes(x);
260
- (0, utils_ts_1.abool)('isCompressed', isCompressed);
279
+ (0, utils_ts_1._abool2)(isCompressed, 'isCompressed');
261
280
  if (isCompressed) {
262
281
  assertCompressionIsSupported();
263
282
  const hasEvenY = !Fp.isOdd(y);
@@ -268,15 +287,13 @@ function weierstrassN(CURVE, curveOpts = {}) {
268
287
  }
269
288
  }
270
289
  function pointFromBytes(bytes) {
271
- (0, utils_ts_1.abytes)(bytes);
272
- const L = Fp.BYTES;
273
- const LC = L + 1; // length compressed, e.g. 33 for 32-byte field
274
- const LU = 2 * L + 1; // length uncompressed, e.g. 65 for 32-byte field
290
+ (0, utils_ts_1._abytes2)(bytes, undefined, 'Point');
291
+ const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths; // e.g. for 32-byte: 33, 65
275
292
  const length = bytes.length;
276
293
  const head = bytes[0];
277
294
  const tail = bytes.subarray(1);
278
295
  // No actual validation is done here: use .assertValidity()
279
- if (length === LC && (head === 0x02 || head === 0x03)) {
296
+ if (length === comp && (head === 0x02 || head === 0x03)) {
280
297
  const x = Fp.fromBytes(tail);
281
298
  if (!Fp.isValid(x))
282
299
  throw new Error('bad point: is not on curve, wrong x');
@@ -296,21 +313,26 @@ function weierstrassN(CURVE, curveOpts = {}) {
296
313
  y = Fp.neg(y);
297
314
  return { x, y };
298
315
  }
299
- else if (length === LU && head === 0x04) {
316
+ else if (length === uncomp && head === 0x04) {
300
317
  // TODO: more checks
301
- const x = Fp.fromBytes(tail.subarray(L * 0, L * 1));
302
- const y = Fp.fromBytes(tail.subarray(L * 1, L * 2));
318
+ const L = Fp.BYTES;
319
+ const x = Fp.fromBytes(tail.subarray(0, L));
320
+ const y = Fp.fromBytes(tail.subarray(L, L * 2));
303
321
  if (!isValidXY(x, y))
304
322
  throw new Error('bad point: is not on curve');
305
323
  return { x, y };
306
324
  }
307
325
  else {
308
- throw new Error(`bad point: got length ${length}, expected compressed=${LC} or uncompressed=${LU}`);
326
+ throw new Error(`bad point: got length ${length}, expected compressed=${comp} or uncompressed=${uncomp}`);
309
327
  }
310
328
  }
311
- const toBytes = curveOpts.toBytes || pointToBytes;
312
- const fromBytes = curveOpts.fromBytes || pointFromBytes;
313
- const weierstrassEquation = _legacyHelperEquat(Fp, CURVE.a, CURVE.b);
329
+ const encodePoint = extraOpts.toBytes || pointToBytes;
330
+ const decodePoint = extraOpts.fromBytes || pointFromBytes;
331
+ function weierstrassEquation(x) {
332
+ const x2 = Fp.sqr(x); // x * x
333
+ const x3 = Fp.mul(x2, x); // x² * x
334
+ return Fp.add(Fp.add(x3, Fp.mul(x, CURVE.a)), CURVE.b); // x³ + a * x + b
335
+ }
314
336
  // TODO: move top-level
315
337
  /** Checks whether equation holds for given x, y: y² == x³ + ax + b */
316
338
  function isValidXY(x, y) {
@@ -373,7 +395,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
373
395
  // (0, 1, 0) aka ZERO is invalid in most contexts.
374
396
  // In BLS, ZERO can be serialized, so we allow it.
375
397
  // (0, 0, 0) is invalid representation of ZERO.
376
- if (curveOpts.allowInfinityPoint && !Fp.is0(p.Y))
398
+ if (extraOpts.allowInfinityPoint && !Fp.is0(p.Y))
377
399
  return;
378
400
  throw new Error('bad point: ZERO');
379
401
  }
@@ -406,6 +428,9 @@ function weierstrassN(CURVE, curveOpts = {}) {
406
428
  this.Z = acoord('z', Z);
407
429
  Object.freeze(this);
408
430
  }
431
+ static CURVE() {
432
+ return CURVE;
433
+ }
409
434
  /** Does NOT validate if the point is valid. Use `.assertValidity()`. */
410
435
  static fromAffine(p) {
411
436
  const { x, y } = p || {};
@@ -418,45 +443,19 @@ function weierstrassN(CURVE, curveOpts = {}) {
418
443
  return Point.ZERO;
419
444
  return new Point(x, y, Fp.ONE);
420
445
  }
421
- get x() {
422
- return this.toAffine().x;
423
- }
424
- get y() {
425
- return this.toAffine().y;
426
- }
427
- // TODO: remove
428
- get px() {
429
- return this.X;
430
- }
431
- get py() {
432
- return this.X;
433
- }
434
- get pz() {
435
- return this.Z;
436
- }
437
- static normalizeZ(points) {
438
- return (0, curve_ts_1.normalizeZ)(Point, points);
439
- }
440
446
  static fromBytes(bytes) {
441
- (0, utils_ts_1.abytes)(bytes);
442
- return Point.fromHex(bytes);
443
- }
444
- /** Converts hash string or Uint8Array to Point. */
445
- static fromHex(hex) {
446
- const P = Point.fromAffine(fromBytes((0, utils_ts_1.ensureBytes)('pointHex', hex)));
447
+ const P = Point.fromAffine(decodePoint((0, utils_ts_1._abytes2)(bytes, undefined, 'point')));
447
448
  P.assertValidity();
448
449
  return P;
449
450
  }
450
- /** Multiplies generator point by privateKey. */
451
- static fromPrivateKey(privateKey) {
452
- return Point.BASE.multiply(_normFnElement(Fn, privateKey));
451
+ static fromHex(hex) {
452
+ return Point.fromBytes((0, utils_ts_1.ensureBytes)('pointHex', hex));
453
453
  }
454
- // TODO: remove
455
- static msm(points, scalars) {
456
- return (0, curve_ts_1.pippenger)(Point, Fn, points, scalars);
454
+ get x() {
455
+ return this.toAffine().x;
457
456
  }
458
- _setWindowSize(windowSize) {
459
- this.precompute(windowSize);
457
+ get y() {
458
+ return this.toAffine().y;
460
459
  }
461
460
  /**
462
461
  *
@@ -605,7 +604,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
605
604
  * @returns New point
606
605
  */
607
606
  multiply(scalar) {
608
- const { endo } = curveOpts;
607
+ const { endo } = extraOpts;
609
608
  if (!Fn.isValidNot0(scalar))
610
609
  throw new Error('invalid scalar: out of range'); // 0 is invalid
611
610
  let point, fake; // Fake point is used to const-time mult
@@ -632,7 +631,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
632
631
  * an exposed secret key e.g. sig verification, which works over *public* keys.
633
632
  */
634
633
  multiplyUnsafe(sc) {
635
- const { endo } = curveOpts;
634
+ const { endo } = extraOpts;
636
635
  const p = this;
637
636
  if (!Fn.isValid(sc))
638
637
  throw new Error('invalid scalar: out of range'); // 0 is valid
@@ -667,7 +666,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
667
666
  * Always torsion-free for cofactor=1 curves.
668
667
  */
669
668
  isTorsionFree() {
670
- const { isTorsionFree } = curveOpts;
669
+ const { isTorsionFree } = extraOpts;
671
670
  if (cofactor === _1n)
672
671
  return true;
673
672
  if (isTorsionFree)
@@ -675,7 +674,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
675
674
  return wnaf.unsafe(this, CURVE_ORDER).is0();
676
675
  }
677
676
  clearCofactor() {
678
- const { clearCofactor } = curveOpts;
677
+ const { clearCofactor } = extraOpts;
679
678
  if (cofactor === _1n)
680
679
  return this; // Fast-path
681
680
  if (clearCofactor)
@@ -687,13 +686,9 @@ function weierstrassN(CURVE, curveOpts = {}) {
687
686
  return this.multiplyUnsafe(cofactor).is0();
688
687
  }
689
688
  toBytes(isCompressed = true) {
690
- (0, utils_ts_1.abool)('isCompressed', isCompressed);
689
+ (0, utils_ts_1._abool2)(isCompressed, 'isCompressed');
691
690
  this.assertValidity();
692
- return toBytes(Point, this, isCompressed);
693
- }
694
- /** @deprecated use `toBytes` */
695
- toRawBytes(isCompressed = true) {
696
- return this.toBytes(isCompressed);
691
+ return encodePoint(Point, this, isCompressed);
697
692
  }
698
693
  toHex(isCompressed = true) {
699
694
  return (0, utils_ts_1.bytesToHex)(this.toBytes(isCompressed));
@@ -701,26 +696,45 @@ function weierstrassN(CURVE, curveOpts = {}) {
701
696
  toString() {
702
697
  return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
703
698
  }
699
+ // TODO: remove
700
+ get px() {
701
+ return this.X;
702
+ }
703
+ get py() {
704
+ return this.X;
705
+ }
706
+ get pz() {
707
+ return this.Z;
708
+ }
709
+ toRawBytes(isCompressed = true) {
710
+ return this.toBytes(isCompressed);
711
+ }
712
+ _setWindowSize(windowSize) {
713
+ this.precompute(windowSize);
714
+ }
715
+ static normalizeZ(points) {
716
+ return (0, curve_ts_1.normalizeZ)(Point, points);
717
+ }
718
+ static msm(points, scalars) {
719
+ return (0, curve_ts_1.pippenger)(Point, Fn, points, scalars);
720
+ }
721
+ static fromPrivateKey(privateKey) {
722
+ return Point.BASE.multiply(_normFnElement(Fn, privateKey));
723
+ }
704
724
  }
705
725
  // base / generator point
706
726
  Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
707
727
  // zero / infinity / identity point
708
728
  Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); // 0, 1, 0
709
- // fields
729
+ // math field
710
730
  Point.Fp = Fp;
731
+ // scalar field
711
732
  Point.Fn = Fn;
712
733
  const bits = Fn.BITS;
713
- const wnaf = new curve_ts_1.wNAF(Point, curveOpts.endo ? Math.ceil(bits / 2) : bits);
734
+ const wnaf = new curve_ts_1.wNAF(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits);
735
+ Point.BASE.precompute(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
714
736
  return Point;
715
737
  }
716
- // _legacyWeierstrass
717
- // TODO: remove
718
- /** @deprecated use `weierstrass` in newer releases */
719
- function weierstrassPoints(c) {
720
- const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
721
- const Point = weierstrassN(CURVE, curveOpts);
722
- return _weierstrass_new_output_to_legacy(c, Point);
723
- }
724
738
  // Points start with byte 0x02 when y is even; otherwise 0x03
725
739
  function pprefix(hasEvenY) {
726
740
  return Uint8Array.of(hasEvenY ? 0x02 : 0x03);
@@ -849,8 +863,124 @@ function mapToCurveSimpleSWU(Fp, opts) {
849
863
  return { x, y };
850
864
  };
851
865
  }
866
+ function getWLengths(Fp, Fn) {
867
+ return {
868
+ secretKey: Fn.BYTES,
869
+ publicKey: 1 + Fp.BYTES,
870
+ publicKeyUncompressed: 1 + 2 * Fp.BYTES,
871
+ publicKeyHasPrefix: true,
872
+ signature: 2 * Fn.BYTES,
873
+ };
874
+ }
875
+ /**
876
+ * Sometimes users only need getPublicKey, getSharedSecret, and secret key handling.
877
+ * This helper ensures no signature functionality is present. Less code, smaller bundle size.
878
+ */
879
+ function ecdh(Point, ecdhOpts = {}) {
880
+ const { Fn } = Point;
881
+ const randomBytes_ = ecdhOpts.randomBytes || utils_ts_1.randomBytes;
882
+ const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed: (0, modular_ts_1.getMinHashLength)(Fn.ORDER) });
883
+ function isValidSecretKey(secretKey) {
884
+ try {
885
+ return !!_normFnElement(Fn, secretKey);
886
+ }
887
+ catch (error) {
888
+ return false;
889
+ }
890
+ }
891
+ function isValidPublicKey(publicKey, isCompressed) {
892
+ const { publicKey: comp, publicKeyUncompressed } = lengths;
893
+ try {
894
+ const l = publicKey.length;
895
+ if (isCompressed === true && l !== comp)
896
+ return false;
897
+ if (isCompressed === false && l !== publicKeyUncompressed)
898
+ return false;
899
+ return !!Point.fromBytes(publicKey);
900
+ }
901
+ catch (error) {
902
+ return false;
903
+ }
904
+ }
905
+ /**
906
+ * Produces cryptographically secure secret key from random of size
907
+ * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
908
+ */
909
+ function randomSecretKey(seed = randomBytes_(lengths.seed)) {
910
+ return (0, modular_ts_1.mapHashToField)((0, utils_ts_1._abytes2)(seed, lengths.seed, 'seed'), Fn.ORDER);
911
+ }
912
+ /**
913
+ * Computes public key for a secret key. Checks for validity of the secret key.
914
+ * @param isCompressed whether to return compact (default), or full key
915
+ * @returns Public key, full when isCompressed=false; short when isCompressed=true
916
+ */
917
+ function getPublicKey(secretKey, isCompressed = true) {
918
+ return Point.BASE.multiply(_normFnElement(Fn, secretKey)).toBytes(isCompressed);
919
+ }
920
+ function keygen(seed) {
921
+ const secretKey = randomSecretKey(seed);
922
+ return { secretKey, publicKey: getPublicKey(secretKey) };
923
+ }
924
+ /**
925
+ * Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
926
+ */
927
+ function isProbPub(item) {
928
+ if (typeof item === 'bigint')
929
+ return false;
930
+ if (item instanceof Point)
931
+ return true;
932
+ const { secretKey, publicKey, publicKeyUncompressed } = lengths;
933
+ if (Fn.allowedLengths || secretKey === publicKey)
934
+ return undefined;
935
+ const l = (0, utils_ts_1.ensureBytes)('key', item).length;
936
+ return l === publicKey || l === publicKeyUncompressed;
937
+ }
938
+ /**
939
+ * ECDH (Elliptic Curve Diffie Hellman).
940
+ * Computes shared public key from secret key A and public key B.
941
+ * Checks: 1) secret key validity 2) shared key is on-curve.
942
+ * Does NOT hash the result.
943
+ * @param isCompressed whether to return compact (default), or full key
944
+ * @returns shared public key
945
+ */
946
+ function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
947
+ if (isProbPub(secretKeyA) === true)
948
+ throw new Error('first arg must be private key');
949
+ if (isProbPub(publicKeyB) === false)
950
+ throw new Error('second arg must be public key');
951
+ const s = _normFnElement(Fn, secretKeyA);
952
+ const b = Point.fromHex(publicKeyB); // checks for being on-curve
953
+ return b.multiply(s).toBytes(isCompressed);
954
+ }
955
+ const utils = {
956
+ isValidSecretKey,
957
+ isValidPublicKey,
958
+ randomSecretKey,
959
+ // TODO: remove
960
+ isValidPrivateKey: isValidSecretKey,
961
+ randomPrivateKey: randomSecretKey,
962
+ normPrivateKeyToScalar: (key) => _normFnElement(Fn, key),
963
+ precompute(windowSize = 8, point = Point.BASE) {
964
+ return point.precompute(windowSize, false);
965
+ },
966
+ };
967
+ return Object.freeze({ getPublicKey, getSharedSecret, keygen, Point, utils, lengths });
968
+ }
852
969
  /**
853
- * Creates ECDSA for given elliptic curve Point and hash function.
970
+ * Creates ECDSA signing interface for given elliptic curve `Point` and `hash` function.
971
+ * We need `hash` for 2 features:
972
+ * 1. Message prehash-ing. NOT used if `sign` / `verify` are called with `prehash: false`
973
+ * 2. k generation in `sign`, using HMAC-drbg(hash)
974
+ *
975
+ * ECDSAOpts are only rarely needed.
976
+ *
977
+ * @example
978
+ * ```js
979
+ * const p256_Point = weierstrass(...);
980
+ * const p256_sha256 = ecdsa(p256_Point, sha256);
981
+ * const p256_sha224 = ecdsa(p256_Point, sha224);
982
+ * const p256_sha224_r = ecdsa(p256_Point, sha224, { randomBytes: (length) => { ... } });
983
+ * ```
854
984
  */
855
985
  function ecdsa(Point, hash, ecdsaOpts = {}) {
856
986
  (0, utils_1.ahash)(hash);
@@ -861,57 +991,61 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
861
991
  bits2int: 'function',
862
992
  bits2int_modN: 'function',
863
993
  });
864
- const randomBytes_ = ecdsaOpts.randomBytes || utils_ts_1.randomBytes;
865
- const hmac_ = ecdsaOpts.hmac ||
994
+ const randomBytes = ecdsaOpts.randomBytes || utils_ts_1.randomBytes;
995
+ const hmac = ecdsaOpts.hmac ||
866
996
  ((key, ...msgs) => (0, hmac_js_1.hmac)(hash, key, (0, utils_ts_1.concatBytes)(...msgs)));
867
997
  const { Fp, Fn } = Point;
868
998
  const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
869
- const seedLen = (0, modular_ts_1.getMinHashLength)(CURVE_ORDER);
870
- const lengths = {
871
- secret: Fn.BYTES,
872
- public: 1 + Fp.BYTES,
873
- publicUncompressed: 1 + 2 * Fp.BYTES,
874
- signature: 2 * Fn.BYTES,
875
- seed: seedLen,
999
+ const { keygen, getPublicKey, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
1000
+ const defaultSigOpts = {
1001
+ prehash: false,
1002
+ lowS: typeof ecdsaOpts.lowS === 'boolean' ? ecdsaOpts.lowS : false,
1003
+ format: undefined, //'compact' as ECDSASigFormat,
1004
+ extraEntropy: false,
876
1005
  };
1006
+ const defaultSigOpts_format = 'compact';
877
1007
  function isBiggerThanHalfOrder(number) {
878
1008
  const HALF = CURVE_ORDER >> _1n;
879
1009
  return number > HALF;
880
1010
  }
881
- function normalizeS(s) {
882
- return isBiggerThanHalfOrder(s) ? Fn.neg(s) : s;
883
- }
884
- function aValidRS(title, num) {
1011
+ function validateRS(title, num) {
885
1012
  if (!Fn.isValidNot0(num))
886
- throw new Error(`invalid signature ${title}: out of range 1..CURVE.n`);
1013
+ throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`);
1014
+ return num;
1015
+ }
1016
+ function validateSigLength(bytes, format) {
1017
+ validateSigFormat(format);
1018
+ const size = lengths.signature;
1019
+ const sizer = format === 'compact' ? size : format === 'recovered' ? size + 1 : undefined;
1020
+ return (0, utils_ts_1._abytes2)(bytes, sizer, `${format} signature`);
887
1021
  }
888
1022
  /**
889
- * ECDSA signature with its (r, s) properties. Supports DER & compact representations.
1023
+ * ECDSA signature with its (r, s) properties. Supports compact, recovered & DER representations.
890
1024
  */
891
1025
  class Signature {
892
1026
  constructor(r, s, recovery) {
893
- aValidRS('r', r); // r in [1..N-1]
894
- aValidRS('s', s); // s in [1..N-1]
895
- this.r = r;
896
- this.s = s;
1027
+ this.r = validateRS('r', r); // r in [1..N-1];
1028
+ this.s = validateRS('s', s); // s in [1..N-1];
897
1029
  if (recovery != null)
898
1030
  this.recovery = recovery;
899
1031
  Object.freeze(this);
900
1032
  }
901
- static fromBytes(bytes, format = 'compact') {
902
- if (format === 'compact') {
903
- const L = Fn.BYTES;
904
- (0, utils_ts_1.abytes)(bytes, L * 2);
905
- const r = bytes.subarray(0, L);
906
- const s = bytes.subarray(L, L * 2);
907
- return new Signature(Fn.fromBytes(r), Fn.fromBytes(s));
908
- }
1033
+ static fromBytes(bytes, format = defaultSigOpts_format) {
1034
+ validateSigLength(bytes, format);
1035
+ let recid;
909
1036
  if (format === 'der') {
910
- (0, utils_ts_1.abytes)(bytes);
911
- const { r, s } = exports.DER.toSig(bytes);
1037
+ const { r, s } = exports.DER.toSig((0, utils_ts_1._abytes2)(bytes));
912
1038
  return new Signature(r, s);
913
1039
  }
914
- throw new Error('invalid format');
1040
+ if (format === 'recovered') {
1041
+ recid = bytes[0];
1042
+ format = 'compact';
1043
+ bytes = bytes.subarray(1);
1044
+ }
1045
+ const L = Fn.BYTES;
1046
+ const r = bytes.subarray(0, L);
1047
+ const s = bytes.subarray(L, L * 2);
1048
+ return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid);
915
1049
  }
916
1050
  static fromHex(hex, format) {
917
1051
  return this.fromBytes((0, utils_ts_1.hexToBytes)(hex), format);
@@ -919,8 +1053,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
919
1053
  addRecoveryBit(recovery) {
920
1054
  return new Signature(this.r, this.s, recovery);
921
1055
  }
922
- // ProjPointType<bigint>
923
- recoverPublicKey(msgHash) {
1056
+ recoverPublicKey(messageHash) {
924
1057
  const FIELD_ORDER = Fp.ORDER;
925
1058
  const { r, s, recovery: rec } = this;
926
1059
  if (rec == null || ![0, 1, 2, 3].includes(rec))
@@ -940,9 +1073,9 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
940
1073
  if (!Fp.isValid(radj))
941
1074
  throw new Error('recovery id 2 or 3 invalid');
942
1075
  const x = Fp.toBytes(radj);
943
- const R = Point.fromHex((0, utils_ts_1.concatBytes)(pprefix((rec & 1) === 0), x));
1076
+ const R = Point.fromBytes((0, utils_ts_1.concatBytes)(pprefix((rec & 1) === 0), x));
944
1077
  const ir = Fn.inv(radj); // r^-1
945
- const h = bits2int_modN((0, utils_ts_1.ensureBytes)('msgHash', msgHash)); // Truncate hash
1078
+ const h = bits2int_modN((0, utils_ts_1.ensureBytes)('msgHash', messageHash)); // Truncate hash
946
1079
  const u1 = Fn.create(-h * ir); // -hr^-1
947
1080
  const u2 = Fn.create(s * ir); // sr^-1
948
1081
  // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1). unsafe is fine: there is no private data.
@@ -956,15 +1089,18 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
956
1089
  hasHighS() {
957
1090
  return isBiggerThanHalfOrder(this.s);
958
1091
  }
959
- normalizeS() {
960
- return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this;
961
- }
962
- toBytes(format = 'compact') {
963
- if (format === 'compact')
964
- return (0, utils_ts_1.concatBytes)(Fn.toBytes(this.r), Fn.toBytes(this.s));
1092
+ toBytes(format = defaultSigOpts_format) {
1093
+ validateSigFormat(format);
965
1094
  if (format === 'der')
966
1095
  return (0, utils_ts_1.hexToBytes)(exports.DER.hexFromSig(this));
967
- throw new Error('invalid format');
1096
+ const r = Fn.toBytes(this.r);
1097
+ const s = Fn.toBytes(this.s);
1098
+ if (format === 'recovered') {
1099
+ if (this.recovery == null)
1100
+ throw new Error('recovery bit must be present');
1101
+ return (0, utils_ts_1.concatBytes)(Uint8Array.of(this.recovery), r, s);
1102
+ }
1103
+ return (0, utils_ts_1.concatBytes)(r, s);
968
1104
  }
969
1105
  toHex(format) {
970
1106
  return (0, utils_ts_1.bytesToHex)(this.toBytes(format));
@@ -977,6 +1113,9 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
977
1113
  static fromDER(hex) {
978
1114
  return Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', hex), 'der');
979
1115
  }
1116
+ normalizeS() {
1117
+ return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this;
1118
+ }
980
1119
  toDERRawBytes() {
981
1120
  return this.toBytes('der');
982
1121
  }
@@ -990,92 +1129,12 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
990
1129
  return (0, utils_ts_1.bytesToHex)(this.toBytes('compact'));
991
1130
  }
992
1131
  }
993
- function isValidSecretKey(privateKey) {
994
- try {
995
- return !!_normFnElement(Fn, privateKey);
996
- }
997
- catch (error) {
998
- return false;
999
- }
1000
- }
1001
- function isValidPublicKey(publicKey, isCompressed) {
1002
- try {
1003
- const l = publicKey.length;
1004
- if (isCompressed === true && l !== lengths.public)
1005
- return false;
1006
- if (isCompressed === false && l !== lengths.publicUncompressed)
1007
- return false;
1008
- return !!Point.fromBytes(publicKey);
1009
- }
1010
- catch (error) {
1011
- return false;
1012
- }
1013
- }
1014
- /**
1015
- * Produces cryptographically secure secret key from random of size
1016
- * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
1017
- */
1018
- function randomSecretKey(seed = randomBytes_(seedLen)) {
1019
- return (0, modular_ts_1.mapHashToField)(seed, CURVE_ORDER);
1020
- }
1021
- const utils = {
1022
- isValidSecretKey,
1023
- isValidPublicKey,
1024
- randomSecretKey,
1025
- // TODO: remove
1026
- isValidPrivateKey: isValidSecretKey,
1027
- randomPrivateKey: randomSecretKey,
1028
- normPrivateKeyToScalar: (key) => _normFnElement(Fn, key),
1029
- precompute(windowSize = 8, point = Point.BASE) {
1030
- return point.precompute(windowSize, false);
1031
- },
1032
- };
1033
- /**
1034
- * Computes public key for a secret key. Checks for validity of the secret key.
1035
- * @param isCompressed whether to return compact (default), or full key
1036
- * @returns Public key, full when isCompressed=false; short when isCompressed=true
1037
- */
1038
- function getPublicKey(secretKey, isCompressed = true) {
1039
- return Point.BASE.multiply(_normFnElement(Fn, secretKey)).toBytes(isCompressed);
1040
- }
1041
- /**
1042
- * Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
1043
- */
1044
- function isProbPub(item) {
1045
- // TODO: remove
1046
- if (typeof item === 'bigint')
1047
- return false;
1048
- // TODO: remove
1049
- if (item instanceof Point)
1050
- return true;
1051
- if (Fn.allowedLengths || lengths.secret === lengths.public)
1052
- return undefined;
1053
- const l = (0, utils_ts_1.ensureBytes)('key', item).length;
1054
- return l === lengths.public || l === lengths.publicUncompressed;
1055
- }
1056
- /**
1057
- * ECDH (Elliptic Curve Diffie Hellman).
1058
- * Computes shared public key from secret key A and public key B.
1059
- * Checks: 1) secret key validity 2) shared key is on-curve.
1060
- * Does NOT hash the result.
1061
- * @param isCompressed whether to return compact (default), or full key
1062
- * @returns shared public key
1063
- */
1064
- function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
1065
- if (isProbPub(secretKeyA) === true)
1066
- throw new Error('first arg must be private key');
1067
- if (isProbPub(publicKeyB) === false)
1068
- throw new Error('second arg must be public key');
1069
- const s = _normFnElement(Fn, secretKeyA);
1070
- const b = Point.fromHex(publicKeyB); // checks for being on-curve
1071
- return b.multiply(s).toBytes(isCompressed);
1072
- }
1073
1132
  // RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
1074
1133
  // FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
1075
1134
  // bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
1076
1135
  // int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
1077
1136
  const bits2int = ecdsaOpts.bits2int ||
1078
- function (bytes) {
1137
+ function bits2int_def(bytes) {
1079
1138
  // Our custom check "just in case", for protection against DoS
1080
1139
  if (bytes.length > 8192)
1081
1140
  throw new Error('input is too large');
@@ -1086,44 +1145,45 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
1086
1145
  return delta > 0 ? num >> BigInt(delta) : num;
1087
1146
  };
1088
1147
  const bits2int_modN = ecdsaOpts.bits2int_modN ||
1089
- function (bytes) {
1148
+ function bits2int_modN_def(bytes) {
1090
1149
  return Fn.create(bits2int(bytes)); // can't use bytesToNumberBE here
1091
1150
  };
1092
- // NOTE: pads output with zero as per spec
1151
+ // Pads output with zero as per spec
1093
1152
  const ORDER_MASK = (0, utils_ts_1.bitMask)(fnBits);
1094
- /**
1095
- * Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
1096
- */
1153
+ /** Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`. */
1097
1154
  function int2octets(num) {
1098
1155
  // IMPORTANT: the check ensures working for case `Fn.BYTES != Fn.BITS * 8`
1099
1156
  (0, utils_ts_1.aInRange)('num < 2^' + fnBits, num, _0n, ORDER_MASK);
1100
1157
  return Fn.toBytes(num);
1101
1158
  }
1102
- // Steps A, D of RFC6979 3.2
1103
- // Creates RFC6979 seed; converts msg/privKey to numbers.
1104
- // Used only in sign, not in verify.
1105
- // NOTE: we cannot assume here that msgHash has same amount of bytes as curve order,
1106
- // this will be invalid at least for P521. Also it can be bigger for P224 + SHA256
1107
- function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
1159
+ function validateMsgAndHash(message, prehash) {
1160
+ (0, utils_ts_1._abytes2)(message, undefined, 'message');
1161
+ return prehash ? (0, utils_ts_1._abytes2)(hash(message), undefined, 'prehashed message') : message;
1162
+ }
1163
+ /**
1164
+ * Steps A, D of RFC6979 3.2.
1165
+ * Creates RFC6979 seed; converts msg/privKey to numbers.
1166
+ * Used only in sign, not in verify.
1167
+ *
1168
+ * Warning: we cannot assume here that message has same amount of bytes as curve order,
1169
+ * this will be invalid at least for P521. Also it can be bigger for P224 + SHA256.
1170
+ */
1171
+ function prepSig(message, privateKey, opts) {
1108
1172
  if (['recovered', 'canonical'].some((k) => k in opts))
1109
1173
  throw new Error('sign() legacy options not supported');
1110
- let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
1111
- if (lowS == null)
1112
- lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
1113
- msgHash = (0, utils_ts_1.ensureBytes)('msgHash', msgHash);
1114
- validateSigVerOpts(opts);
1115
- if (prehash)
1116
- msgHash = (0, utils_ts_1.ensureBytes)('prehashed msgHash', hash(msgHash));
1174
+ const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts);
1175
+ message = validateMsgAndHash(message, prehash); // RFC6979 3.2 A: h1 = H(m)
1117
1176
  // We can't later call bits2octets, since nested bits2int is broken for curves
1118
1177
  // with fnBits % 8 !== 0. Because of that, we unwrap it here as int2octets call.
1119
1178
  // const bits2octets = (bits) => int2octets(bits2int_modN(bits))
1120
- const h1int = bits2int_modN(msgHash);
1179
+ const h1int = bits2int_modN(message);
1121
1180
  const d = _normFnElement(Fn, privateKey); // validate secret key, convert to bigint
1122
1181
  const seedArgs = [int2octets(d), int2octets(h1int)];
1123
1182
  // extraEntropy. RFC6979 3.6: additional k' (optional).
1124
- if (ent != null && ent !== false) {
1183
+ if (extraEntropy != null && extraEntropy !== false) {
1125
1184
  // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
1126
- const e = ent === true ? randomBytes_(lengths.secret) : ent; // gen random bytes OR pass as-is
1185
+ // gen random bytes OR pass as-is
1186
+ const e = extraEntropy === true ? randomBytes(lengths.secretKey) : extraEntropy;
1127
1187
  seedArgs.push((0, utils_ts_1.ensureBytes)('extraEntropy', e)); // check for being bytes
1128
1188
  }
1129
1189
  const seed = (0, utils_ts_1.concatBytes)(...seedArgs); // Step D of RFC6979 3.2
@@ -1139,7 +1199,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
1139
1199
  function k2sig(kBytes) {
1140
1200
  // RFC 6979 Section 3.2, step 3: k = bits2int(T)
1141
1201
  // Important: all mod() calls here must be done over N
1142
- const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
1202
+ const k = bits2int(kBytes); // mod n, not mod p
1143
1203
  if (!Fn.isValidNot0(k))
1144
1204
  return; // Valid scalars (including k) must be in 1..N-1
1145
1205
  const ik = Fn.inv(k); // k^-1 mod n
@@ -1153,120 +1213,100 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
1153
1213
  let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
1154
1214
  let normS = s;
1155
1215
  if (lowS && isBiggerThanHalfOrder(s)) {
1156
- normS = normalizeS(s); // if lowS was passed, ensure s is always
1216
+ normS = Fn.neg(s); // if lowS was passed, ensure s is always
1157
1217
  recovery ^= 1; // // in the bottom half of N
1158
1218
  }
1159
1219
  return new Signature(r, normS, recovery); // use normS, not s
1160
1220
  }
1161
1221
  return { seed, k2sig };
1162
1222
  }
1163
- const defaultSigOpts = { lowS: ecdsaOpts.lowS, prehash: false };
1164
- const defaultVerOpts = { lowS: ecdsaOpts.lowS, prehash: false };
1165
1223
  /**
1166
1224
  * Signs message hash with a secret key.
1225
+ *
1167
1226
  * ```
1168
- * sign(m, d, k) where
1227
+ * sign(m, d) where
1228
+ * k = rfc6979_hmac_drbg(m, d)
1169
1229
  * (x, y) = G × k
1170
1230
  * r = x mod n
1171
- * s = (m + dr)/k mod n
1231
+ * s = (m + dr) / k mod n
1172
1232
  * ```
1173
1233
  */
1174
- function sign(msgHash, secretKey, opts = defaultSigOpts) {
1175
- const { seed, k2sig } = prepSig(msgHash, secretKey, opts); // Steps A, D of RFC6979 3.2.
1176
- const drbg = (0, utils_ts_1.createHmacDrbg)(hash.outputLen, Fn.BYTES, hmac_);
1177
- return drbg(seed, k2sig); // Steps B, C, D, E, F, G
1234
+ function sign(message, secretKey, opts = {}) {
1235
+ message = (0, utils_ts_1.ensureBytes)('message', message);
1236
+ const { seed, k2sig } = prepSig(message, secretKey, opts); // Steps A, D of RFC6979 3.2.
1237
+ const drbg = (0, utils_ts_1.createHmacDrbg)(hash.outputLen, Fn.BYTES, hmac);
1238
+ const sig = drbg(seed, k2sig); // Steps B, C, D, E, F, G
1239
+ return sig;
1240
+ }
1241
+ function tryParsingSig(sg) {
1242
+ // Try to deduce format
1243
+ let sig = undefined;
1244
+ const isHex = typeof sg === 'string' || (0, utils_ts_1.isBytes)(sg);
1245
+ const isObj = !isHex &&
1246
+ sg !== null &&
1247
+ typeof sg === 'object' &&
1248
+ typeof sg.r === 'bigint' &&
1249
+ typeof sg.s === 'bigint';
1250
+ if (!isHex && !isObj)
1251
+ throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
1252
+ if (isObj) {
1253
+ sig = new Signature(sg.r, sg.s);
1254
+ }
1255
+ else if (isHex) {
1256
+ try {
1257
+ sig = Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', sg), 'der');
1258
+ }
1259
+ catch (derError) {
1260
+ if (!(derError instanceof exports.DER.Err))
1261
+ throw derError;
1262
+ }
1263
+ if (!sig) {
1264
+ try {
1265
+ sig = Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', sg), 'compact');
1266
+ }
1267
+ catch (error) {
1268
+ return false;
1269
+ }
1270
+ }
1271
+ }
1272
+ if (!sig)
1273
+ return false;
1274
+ return sig;
1178
1275
  }
1179
- // Enable precomputes. Slows down first publicKey computation by 20ms.
1180
- Point.BASE.precompute(8);
1181
1276
  /**
1182
- * Verifies a signature against message hash and public key.
1183
- * Rejects lowS signatures by default: to override,
1184
- * specify option `{lowS: false}`. Implements section 4.1.4 from https://www.secg.org/sec1-v2.pdf:
1277
+ * Verifies a signature against message and public key.
1278
+ * Rejects lowS signatures by default: see {@link ECDSAVerifyOpts}.
1279
+ * Implements section 4.1.4 from https://www.secg.org/sec1-v2.pdf:
1185
1280
  *
1186
1281
  * ```
1187
1282
  * verify(r, s, h, P) where
1188
- * U1 = hs^-1 mod n
1189
- * U2 = rs^-1 mod n
1190
- * R = U1⋅G - U2⋅P
1283
+ * u1 = hs^-1 mod n
1284
+ * u2 = rs^-1 mod n
1285
+ * R = u1⋅G + u2⋅P
1191
1286
  * mod(R.x, n) == r
1192
1287
  * ```
1193
1288
  */
1194
- function verify(signature, msgHash, publicKey, opts = defaultVerOpts) {
1195
- const sg = signature;
1196
- msgHash = (0, utils_ts_1.ensureBytes)('msgHash', msgHash);
1289
+ function verify(signature, message, publicKey, opts = {}) {
1290
+ const { lowS, prehash, format } = validateSigOpts(opts, defaultSigOpts);
1197
1291
  publicKey = (0, utils_ts_1.ensureBytes)('publicKey', publicKey);
1198
- // Verify opts
1199
- validateSigVerOpts(opts);
1200
- const { lowS, prehash, format } = opts;
1201
- // TODO: remove
1292
+ message = validateMsgAndHash((0, utils_ts_1.ensureBytes)('message', message), prehash);
1202
1293
  if ('strict' in opts)
1203
1294
  throw new Error('options.strict was renamed to lowS');
1204
- let _sig = undefined;
1205
- let P;
1206
- if (format === undefined) {
1207
- // Try to deduce format
1208
- const isHex = typeof sg === 'string' || (0, utils_ts_1.isBytes)(sg);
1209
- const isObj = !isHex &&
1210
- sg !== null &&
1211
- typeof sg === 'object' &&
1212
- typeof sg.r === 'bigint' &&
1213
- typeof sg.s === 'bigint';
1214
- if (!isHex && !isObj)
1215
- throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
1216
- if (isObj) {
1217
- _sig = new Signature(sg.r, sg.s);
1218
- }
1219
- else if (isHex) {
1220
- // TODO: remove this malleable check
1221
- // Signature can be represented in 2 ways: compact (2*Fn.BYTES) & DER (variable-length).
1222
- // Since DER can also be 2*Fn.BYTES bytes, we check for it first.
1223
- try {
1224
- _sig = Signature.fromDER(sg);
1225
- }
1226
- catch (derError) {
1227
- if (!(derError instanceof exports.DER.Err))
1228
- throw derError;
1229
- }
1230
- if (!_sig) {
1231
- try {
1232
- _sig = Signature.fromCompact(sg);
1233
- }
1234
- catch (error) {
1235
- return false;
1236
- }
1237
- }
1238
- }
1239
- }
1240
- else {
1241
- if (format === 'compact' || format === 'der') {
1242
- if (typeof sg !== 'string' && !(0, utils_ts_1.isBytes)(sg))
1243
- throw new Error('"der" / "compact" format expects Uint8Array signature');
1244
- _sig = Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', sg), format);
1245
- }
1246
- else if (format === 'js') {
1247
- if (!(sg instanceof Signature))
1248
- throw new Error('"js" format expects Signature instance');
1249
- _sig = sg;
1250
- }
1251
- else {
1252
- throw new Error('format must be "compact", "der" or "js"');
1253
- }
1254
- }
1255
- if (!_sig)
1295
+ const sig = format === undefined
1296
+ ? tryParsingSig(signature)
1297
+ : Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', signature), format);
1298
+ if (sig === false)
1256
1299
  return false;
1257
1300
  try {
1258
- P = Point.fromHex(publicKey);
1259
- if (lowS && _sig.hasHighS())
1301
+ const P = Point.fromBytes(publicKey);
1302
+ if (lowS && sig.hasHighS())
1260
1303
  return false;
1261
- // todo: optional.hash => hash
1262
- if (prehash)
1263
- msgHash = hash(msgHash);
1264
- const { r, s } = _sig;
1265
- const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
1266
- const is = Fn.inv(s); // s^-1
1304
+ const { r, s } = sig;
1305
+ const h = bits2int_modN(message); // mod n, not mod p
1306
+ const is = Fn.inv(s); // s^-1 mod n
1267
1307
  const u1 = Fn.create(h * is); // u1 = hs^-1 mod n
1268
1308
  const u2 = Fn.create(r * is); // u2 = rs^-1 mod n
1269
- const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
1309
+ const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2)); // u1⋅G + u2⋅P
1270
1310
  if (R.is0())
1271
1311
  return false;
1272
1312
  const v = Fn.create(R.x); // v = r.x mod n
@@ -1276,23 +1316,31 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
1276
1316
  return false;
1277
1317
  }
1278
1318
  }
1279
- function keygen(seed) {
1280
- const secretKey = utils.randomSecretKey(seed);
1281
- return { secretKey, publicKey: getPublicKey(secretKey) };
1319
+ function recoverPublicKey(signature, message, opts = {}) {
1320
+ const { prehash } = validateSigOpts(opts, defaultSigOpts);
1321
+ message = validateMsgAndHash(message, prehash);
1322
+ return Signature.fromBytes(signature, 'recovered').recoverPublicKey(message).toBytes();
1282
1323
  }
1283
1324
  return Object.freeze({
1284
1325
  keygen,
1285
1326
  getPublicKey,
1286
- sign,
1287
- verify,
1288
1327
  getSharedSecret,
1289
1328
  utils,
1329
+ lengths,
1290
1330
  Point,
1331
+ sign,
1332
+ verify,
1333
+ recoverPublicKey,
1291
1334
  Signature,
1292
- info: { type: 'weierstrass', lengths, publicKeyHasPrefix: true },
1335
+ hash,
1293
1336
  });
1294
1337
  }
1295
- // TODO: remove
1338
+ /** @deprecated use `weierstrass` in newer releases */
1339
+ function weierstrassPoints(c) {
1340
+ const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
1341
+ const Point = weierstrassN(CURVE, curveOpts);
1342
+ return _weierstrass_new_output_to_legacy(c, Point);
1343
+ }
1296
1344
  function _weierstrass_legacy_opts_to_new(c) {
1297
1345
  const CURVE = {
1298
1346
  a: c.a,
@@ -1310,7 +1358,7 @@ function _weierstrass_legacy_opts_to_new(c) {
1310
1358
  const Fn = (0, modular_ts_1.Field)(CURVE.n, {
1311
1359
  BITS: c.nBitLength,
1312
1360
  allowedLengths: allowedLengths,
1313
- modOnDecode: c.wrapPrivateKey,
1361
+ modFromBytes: c.wrapPrivateKey,
1314
1362
  });
1315
1363
  const curveOpts = {
1316
1364
  Fp,
@@ -1335,10 +1383,20 @@ function _ecdsa_legacy_opts_to_new(c) {
1335
1383
  };
1336
1384
  return { CURVE, curveOpts, hash: c.hash, ecdsaOpts };
1337
1385
  }
1338
- // TODO: remove
1386
+ function _legacyHelperEquat(Fp, a, b) {
1387
+ /**
1388
+ * y² = x³ + ax + b: Short weierstrass curve formula. Takes x, returns y².
1389
+ * @returns y²
1390
+ */
1391
+ function weierstrassEquation(x) {
1392
+ const x2 = Fp.sqr(x); // x * x
1393
+ const x3 = Fp.mul(x2, x); // x² * x
1394
+ return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x³ + a * x + b
1395
+ }
1396
+ return weierstrassEquation;
1397
+ }
1339
1398
  function _weierstrass_new_output_to_legacy(c, Point) {
1340
1399
  const { Fp, Fn } = Point;
1341
- // TODO: remove
1342
1400
  function isWithinCurveOrder(num) {
1343
1401
  return (0, utils_ts_1.inRange)(num, _1n, Fn.ORDER);
1344
1402
  }
@@ -1352,11 +1410,11 @@ function _weierstrass_new_output_to_legacy(c, Point) {
1352
1410
  isWithinCurveOrder,
1353
1411
  });
1354
1412
  }
1355
- // TODO: remove
1356
- function _ecdsa_new_output_to_legacy(c, ecdsa) {
1357
- return Object.assign({}, ecdsa, {
1358
- ProjectivePoint: ecdsa.Point,
1359
- CURVE: c,
1413
+ function _ecdsa_new_output_to_legacy(c, _ecdsa) {
1414
+ const Point = _ecdsa.Point;
1415
+ return Object.assign({}, _ecdsa, {
1416
+ ProjectivePoint: Point,
1417
+ CURVE: Object.assign({}, c, (0, modular_ts_1.nLength)(Point.Fn.ORDER, Point.Fn.BITS)),
1360
1418
  });
1361
1419
  }
1362
1420
  // _ecdsa_legacy