@noble/curves 1.9.2 → 1.9.4

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 (179) hide show
  1. package/README.md +186 -206
  2. package/_shortw_utils.d.ts +1 -0
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +1 -0
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +87 -62
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +170 -163
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +109 -23
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +158 -156
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +126 -70
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +212 -62
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/hash-to-curve.d.ts +8 -4
  19. package/abstract/hash-to-curve.d.ts.map +1 -1
  20. package/abstract/hash-to-curve.js +23 -11
  21. package/abstract/hash-to-curve.js.map +1 -1
  22. package/abstract/modular.d.ts +8 -3
  23. package/abstract/modular.d.ts.map +1 -1
  24. package/abstract/modular.js +79 -35
  25. package/abstract/modular.js.map +1 -1
  26. package/abstract/montgomery.d.ts +17 -4
  27. package/abstract/montgomery.d.ts.map +1 -1
  28. package/abstract/montgomery.js +19 -3
  29. package/abstract/montgomery.js.map +1 -1
  30. package/abstract/tower.d.ts +3 -3
  31. package/abstract/tower.d.ts.map +1 -1
  32. package/abstract/tower.js.map +1 -1
  33. package/abstract/weierstrass.d.ts +145 -118
  34. package/abstract/weierstrass.d.ts.map +1 -1
  35. package/abstract/weierstrass.js +415 -336
  36. package/abstract/weierstrass.js.map +1 -1
  37. package/bls12-381.d.ts.map +1 -1
  38. package/bls12-381.js +4 -4
  39. package/bls12-381.js.map +1 -1
  40. package/ed25519.d.ts +52 -66
  41. package/ed25519.d.ts.map +1 -1
  42. package/ed25519.js +128 -155
  43. package/ed25519.js.map +1 -1
  44. package/ed448.d.ts +57 -58
  45. package/ed448.d.ts.map +1 -1
  46. package/ed448.js +114 -131
  47. package/ed448.js.map +1 -1
  48. package/esm/_shortw_utils.d.ts +1 -0
  49. package/esm/_shortw_utils.d.ts.map +1 -1
  50. package/esm/_shortw_utils.js +1 -0
  51. package/esm/_shortw_utils.js.map +1 -1
  52. package/esm/abstract/bls.d.ts +87 -62
  53. package/esm/abstract/bls.d.ts.map +1 -1
  54. package/esm/abstract/bls.js +171 -164
  55. package/esm/abstract/bls.js.map +1 -1
  56. package/esm/abstract/curve.d.ts +109 -23
  57. package/esm/abstract/curve.d.ts.map +1 -1
  58. package/esm/abstract/curve.js +156 -155
  59. package/esm/abstract/curve.js.map +1 -1
  60. package/esm/abstract/edwards.d.ts +126 -70
  61. package/esm/abstract/edwards.d.ts.map +1 -1
  62. package/esm/abstract/edwards.js +210 -62
  63. package/esm/abstract/edwards.js.map +1 -1
  64. package/esm/abstract/hash-to-curve.d.ts +8 -4
  65. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  66. package/esm/abstract/hash-to-curve.js +22 -11
  67. package/esm/abstract/hash-to-curve.js.map +1 -1
  68. package/esm/abstract/modular.d.ts +8 -3
  69. package/esm/abstract/modular.d.ts.map +1 -1
  70. package/esm/abstract/modular.js +79 -35
  71. package/esm/abstract/modular.js.map +1 -1
  72. package/esm/abstract/montgomery.d.ts +17 -4
  73. package/esm/abstract/montgomery.d.ts.map +1 -1
  74. package/esm/abstract/montgomery.js +19 -3
  75. package/esm/abstract/montgomery.js.map +1 -1
  76. package/esm/abstract/tower.d.ts +3 -3
  77. package/esm/abstract/tower.d.ts.map +1 -1
  78. package/esm/abstract/tower.js.map +1 -1
  79. package/esm/abstract/weierstrass.d.ts +145 -118
  80. package/esm/abstract/weierstrass.d.ts.map +1 -1
  81. package/esm/abstract/weierstrass.js +412 -334
  82. package/esm/abstract/weierstrass.js.map +1 -1
  83. package/esm/bls12-381.d.ts.map +1 -1
  84. package/esm/bls12-381.js +4 -4
  85. package/esm/bls12-381.js.map +1 -1
  86. package/esm/ed25519.d.ts +52 -66
  87. package/esm/ed25519.d.ts.map +1 -1
  88. package/esm/ed25519.js +131 -157
  89. package/esm/ed25519.js.map +1 -1
  90. package/esm/ed448.d.ts +57 -58
  91. package/esm/ed448.d.ts.map +1 -1
  92. package/esm/ed448.js +116 -132
  93. package/esm/ed448.js.map +1 -1
  94. package/esm/index.js +7 -9
  95. package/esm/index.js.map +1 -1
  96. package/esm/jubjub.d.ts +3 -3
  97. package/esm/jubjub.d.ts.map +1 -1
  98. package/esm/jubjub.js +3 -3
  99. package/esm/jubjub.js.map +1 -1
  100. package/esm/misc.d.ts +3 -5
  101. package/esm/misc.d.ts.map +1 -1
  102. package/esm/misc.js +0 -3
  103. package/esm/misc.js.map +1 -1
  104. package/esm/nist.d.ts +0 -6
  105. package/esm/nist.d.ts.map +1 -1
  106. package/esm/nist.js +31 -15
  107. package/esm/nist.js.map +1 -1
  108. package/esm/p256.d.ts +4 -0
  109. package/esm/p256.d.ts.map +1 -1
  110. package/esm/p256.js +4 -0
  111. package/esm/p256.js.map +1 -1
  112. package/esm/p384.d.ts +4 -1
  113. package/esm/p384.d.ts.map +1 -1
  114. package/esm/p384.js +4 -1
  115. package/esm/p384.js.map +1 -1
  116. package/esm/p521.d.ts +4 -0
  117. package/esm/p521.d.ts.map +1 -1
  118. package/esm/p521.js +4 -0
  119. package/esm/p521.js.map +1 -1
  120. package/esm/secp256k1.d.ts +32 -15
  121. package/esm/secp256k1.d.ts.map +1 -1
  122. package/esm/secp256k1.js +72 -67
  123. package/esm/secp256k1.js.map +1 -1
  124. package/esm/utils.d.ts +1 -1
  125. package/esm/utils.js +1 -1
  126. package/index.js +7 -9
  127. package/index.js.map +1 -1
  128. package/jubjub.d.ts +3 -3
  129. package/jubjub.d.ts.map +1 -1
  130. package/jubjub.js +3 -3
  131. package/jubjub.js.map +1 -1
  132. package/misc.d.ts +3 -5
  133. package/misc.d.ts.map +1 -1
  134. package/misc.js +0 -3
  135. package/misc.js.map +1 -1
  136. package/nist.d.ts +0 -6
  137. package/nist.d.ts.map +1 -1
  138. package/nist.js +31 -15
  139. package/nist.js.map +1 -1
  140. package/p256.d.ts +4 -0
  141. package/p256.d.ts.map +1 -1
  142. package/p256.js +4 -0
  143. package/p256.js.map +1 -1
  144. package/p384.d.ts +4 -1
  145. package/p384.d.ts.map +1 -1
  146. package/p384.js +4 -1
  147. package/p384.js.map +1 -1
  148. package/p521.d.ts +4 -0
  149. package/p521.d.ts.map +1 -1
  150. package/p521.js +4 -0
  151. package/p521.js.map +1 -1
  152. package/package.json +4 -2
  153. package/secp256k1.d.ts +32 -15
  154. package/secp256k1.d.ts.map +1 -1
  155. package/secp256k1.js +70 -65
  156. package/secp256k1.js.map +1 -1
  157. package/src/_shortw_utils.ts +1 -0
  158. package/src/abstract/bls.ts +319 -257
  159. package/src/abstract/curve.ts +226 -170
  160. package/src/abstract/edwards.ts +352 -139
  161. package/src/abstract/hash-to-curve.ts +33 -16
  162. package/src/abstract/modular.ts +86 -35
  163. package/src/abstract/montgomery.ts +36 -9
  164. package/src/abstract/tower.ts +4 -4
  165. package/src/abstract/weierstrass.ts +570 -476
  166. package/src/bls12-381.ts +28 -20
  167. package/src/ed25519.ts +161 -179
  168. package/src/ed448.ts +150 -156
  169. package/src/index.ts +7 -9
  170. package/src/jubjub.ts +3 -3
  171. package/src/misc.ts +3 -7
  172. package/src/nist.ts +40 -16
  173. package/src/p256.ts +4 -0
  174. package/src/p384.ts +4 -2
  175. package/src/p521.ts +4 -0
  176. package/src/secp256k1.ts +91 -73
  177. package/src/utils.ts +1 -1
  178. package/utils.d.ts +1 -1
  179. package/utils.js +1 -1
@@ -26,9 +26,40 @@
26
26
  */
27
27
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
28
28
  import { hmac } from '@noble/hashes/hmac.js';
29
- import { _validateObject, abool, abytes, aInRange, bitMask, bytesToHex, bytesToNumberBE, concatBytes, createHmacDrbg, ensureBytes, hexToBytes, inRange, isBytes, memoized, numberToHexUnpadded, randomBytes, } from "../utils.js";
29
+ import { ahash } from '@noble/hashes/utils';
30
+ import { _validateObject, abool, abytes, aInRange, bitLen, bitMask, bytesToHex, bytesToNumberBE, concatBytes, createHmacDrbg, ensureBytes, hexToBytes, inRange, isBytes, memoized, numberToHexUnpadded, randomBytes, } from "../utils.js";
30
31
  import { _createCurveFields, mulEndoUnsafe, negateCt, normalizeZ, pippenger, wNAF, } from "./curve.js";
31
32
  import { Field, FpInvertBatch, getMinHashLength, mapHashToField, validateField, } from "./modular.js";
33
+ // We construct basis in such way that den is always positive and equals n, but num sign depends on basis (not on secret value)
34
+ const divNearest = (num, den) => (num + (num >= 0 ? den : -den) / _2n) / den;
35
+ /**
36
+ * Splits scalar for GLV endomorphism.
37
+ */
38
+ export function _splitEndoScalar(k, basis, n) {
39
+ // Split scalar into two such that part is ~half bits: `abs(part) < sqrt(N)`
40
+ // Since part can be negative, we need to do this on point.
41
+ // TODO: verifyScalar function which consumes lambda
42
+ const [[a1, b1], [a2, b2]] = basis;
43
+ const c1 = divNearest(b2 * k, n);
44
+ const c2 = divNearest(-b1 * k, n);
45
+ // |k1|/|k2| is < sqrt(N), but can be negative.
46
+ // If we do `k1 mod N`, we'll get big scalar (`> sqrt(N)`): so, we do cheaper negation instead.
47
+ let k1 = k - c1 * a1 - c2 * a2;
48
+ let k2 = -c1 * b1 - c2 * b2;
49
+ const k1neg = k1 < _0n;
50
+ const k2neg = k2 < _0n;
51
+ if (k1neg)
52
+ k1 = -k1;
53
+ if (k2neg)
54
+ k2 = -k2;
55
+ // Double check that resulting scalar less than half bits of N: otherwise wNAF will fail.
56
+ // This should only happen on wrong basises. Also, math inside is too complex and I don't trust it.
57
+ const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n; // Half bits of N
58
+ if (k1 < _0n || k1 >= MAX_NUM || k2 < _0n || k2 >= MAX_NUM) {
59
+ throw new Error('splitScalar (endomorphism): failed, k=' + k);
60
+ }
61
+ return { k1neg, k1, k2neg, k2 };
62
+ }
32
63
  function validateSigVerOpts(opts) {
33
64
  if (opts.lowS !== undefined)
34
65
  abool('lowS', opts.lowS);
@@ -167,37 +198,24 @@ export function _legacyHelperEquat(Fp, a, b) {
167
198
  }
168
199
  return weierstrassEquation;
169
200
  }
170
- export function _legacyHelperNormPriv(Fn, allowedPrivateKeyLengths, wrapPrivateKey) {
201
+ export function _normFnElement(Fn, key) {
171
202
  const { BYTES: expected } = Fn;
172
- // Validates if priv key is valid and converts it to bigint.
173
- function normPrivateKeyToScalar(key) {
174
- let num;
175
- if (typeof key === 'bigint') {
176
- num = key;
203
+ let num;
204
+ if (typeof key === 'bigint') {
205
+ num = key;
206
+ }
207
+ else {
208
+ let bytes = ensureBytes('private key', key);
209
+ try {
210
+ num = Fn.fromBytes(bytes);
177
211
  }
178
- else {
179
- let bytes = ensureBytes('private key', key);
180
- if (allowedPrivateKeyLengths) {
181
- if (!allowedPrivateKeyLengths.includes(bytes.length * 2))
182
- throw new Error('invalid private key');
183
- const padded = new Uint8Array(expected);
184
- padded.set(bytes, padded.length - bytes.length);
185
- bytes = padded;
186
- }
187
- try {
188
- num = Fn.fromBytes(bytes);
189
- }
190
- catch (error) {
191
- throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
192
- }
212
+ catch (error) {
213
+ throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
193
214
  }
194
- if (wrapPrivateKey)
195
- num = Fn.create(num); // disabled by default, enabled for BLS
196
- if (!Fn.isValidNot0(num))
197
- throw new Error('invalid private key: out of range [1..N-1]');
198
- return num;
199
215
  }
200
- return normPrivateKeyToScalar;
216
+ if (!Fn.isValidNot0(num))
217
+ throw new Error('invalid private key: out of range [1..N-1]');
218
+ return num;
201
219
  }
202
220
  export function weierstrassN(CURVE, curveOpts = {}) {
203
221
  const { Fp, Fn } = _createCurveFields('weierstrass', CURVE, curveOpts);
@@ -214,10 +232,8 @@ export function weierstrassN(CURVE, curveOpts = {}) {
214
232
  const { endo } = curveOpts;
215
233
  if (endo) {
216
234
  // validateObject(endo, { beta: 'bigint', splitScalar: 'function' });
217
- if (!Fp.is0(CURVE.a) ||
218
- typeof endo.beta !== 'bigint' ||
219
- typeof endo.splitScalar !== 'function') {
220
- throw new Error('invalid endo: expected "beta": bigint and "splitScalar": function');
235
+ if (!Fp.is0(CURVE.a) || typeof endo.beta !== 'bigint' || !Array.isArray(endo.basises)) {
236
+ throw new Error('invalid endo: expected "beta": bigint and "basises": array');
221
237
  }
222
238
  }
223
239
  function assertCompressionIsSupported() {
@@ -309,28 +325,33 @@ export function weierstrassN(CURVE, curveOpts = {}) {
309
325
  if (!(other instanceof Point))
310
326
  throw new Error('ProjectivePoint expected');
311
327
  }
328
+ function splitEndoScalarN(k) {
329
+ if (!endo || !endo.basises)
330
+ throw new Error('no endo');
331
+ return _splitEndoScalar(k, endo.basises, Fn.ORDER);
332
+ }
312
333
  // Memoized toAffine / validity check. They are heavy. Points are immutable.
313
334
  // Converts Projective point to affine (x, y) coordinates.
314
335
  // Can accept precomputed Z^-1 - for example, from invertBatch.
315
336
  // (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
316
337
  const toAffineMemo = memoized((p, iz) => {
317
- const { px: x, py: y, pz: z } = p;
338
+ const { X, Y, Z } = p;
318
339
  // Fast-path for normalized points
319
- if (Fp.eql(z, Fp.ONE))
320
- return { x, y };
340
+ if (Fp.eql(Z, Fp.ONE))
341
+ return { x: X, y: Y };
321
342
  const is0 = p.is0();
322
343
  // If invZ was 0, we return zero point. However we still want to execute
323
344
  // all operations, so we replace invZ with a random number, 1.
324
345
  if (iz == null)
325
- iz = is0 ? Fp.ONE : Fp.inv(z);
326
- const ax = Fp.mul(x, iz);
327
- const ay = Fp.mul(y, iz);
328
- const zz = Fp.mul(z, iz);
346
+ iz = is0 ? Fp.ONE : Fp.inv(Z);
347
+ const x = Fp.mul(X, iz);
348
+ const y = Fp.mul(Y, iz);
349
+ const zz = Fp.mul(Z, iz);
329
350
  if (is0)
330
351
  return { x: Fp.ZERO, y: Fp.ZERO };
331
352
  if (!Fp.eql(zz, Fp.ONE))
332
353
  throw new Error('invZ was invalid');
333
- return { x: ax, y: ay };
354
+ return { x, y };
334
355
  });
335
356
  // NOTE: on exception this will crash 'cached' and no value will be set.
336
357
  // Otherwise true will be return
@@ -339,7 +360,7 @@ export function weierstrassN(CURVE, curveOpts = {}) {
339
360
  // (0, 1, 0) aka ZERO is invalid in most contexts.
340
361
  // In BLS, ZERO can be serialized, so we allow it.
341
362
  // (0, 0, 0) is invalid representation of ZERO.
342
- if (curveOpts.allowInfinityPoint && !Fp.is0(p.py))
363
+ if (curveOpts.allowInfinityPoint && !Fp.is0(p.Y))
343
364
  return;
344
365
  throw new Error('bad point: ZERO');
345
366
  }
@@ -354,7 +375,7 @@ export function weierstrassN(CURVE, curveOpts = {}) {
354
375
  return true;
355
376
  });
356
377
  function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
357
- k2p = new Point(Fp.mul(k2p.px, endoBeta), k2p.py, k2p.pz);
378
+ k2p = new Point(Fp.mul(k2p.X, endoBeta), k2p.Y, k2p.Z);
358
379
  k1p = negateCt(k1neg, k1p);
359
380
  k2p = negateCt(k2neg, k2p);
360
381
  return k1p.add(k2p);
@@ -366,10 +387,10 @@ export function weierstrassN(CURVE, curveOpts = {}) {
366
387
  */
367
388
  class Point {
368
389
  /** Does NOT validate if the point is valid. Use `.assertValidity()`. */
369
- constructor(px, py, pz) {
370
- this.px = acoord('x', px);
371
- this.py = acoord('y', py, true);
372
- this.pz = acoord('z', pz);
390
+ constructor(X, Y, Z) {
391
+ this.X = acoord('x', X);
392
+ this.Y = acoord('y', Y, true);
393
+ this.Z = acoord('z', Z);
373
394
  Object.freeze(this);
374
395
  }
375
396
  /** Does NOT validate if the point is valid. Use `.assertValidity()`. */
@@ -390,8 +411,18 @@ export function weierstrassN(CURVE, curveOpts = {}) {
390
411
  get y() {
391
412
  return this.toAffine().y;
392
413
  }
414
+ // TODO: remove
415
+ get px() {
416
+ return this.X;
417
+ }
418
+ get py() {
419
+ return this.X;
420
+ }
421
+ get pz() {
422
+ return this.Z;
423
+ }
393
424
  static normalizeZ(points) {
394
- return normalizeZ(Point, 'pz', points);
425
+ return normalizeZ(Point, points);
395
426
  }
396
427
  static fromBytes(bytes) {
397
428
  abytes(bytes);
@@ -405,13 +436,15 @@ export function weierstrassN(CURVE, curveOpts = {}) {
405
436
  }
406
437
  /** Multiplies generator point by privateKey. */
407
438
  static fromPrivateKey(privateKey) {
408
- const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey);
409
- return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
439
+ return Point.BASE.multiply(_normFnElement(Fn, privateKey));
410
440
  }
411
- /** Multiscalar Multiplication */
441
+ // TODO: remove
412
442
  static msm(points, scalars) {
413
443
  return pippenger(Point, Fn, points, scalars);
414
444
  }
445
+ _setWindowSize(windowSize) {
446
+ this.precompute(windowSize);
447
+ }
415
448
  /**
416
449
  *
417
450
  * @param windowSize
@@ -419,15 +452,11 @@ export function weierstrassN(CURVE, curveOpts = {}) {
419
452
  * @returns
420
453
  */
421
454
  precompute(windowSize = 8, isLazy = true) {
422
- wnaf.setWindowSize(this, windowSize);
455
+ wnaf.createCache(this, windowSize);
423
456
  if (!isLazy)
424
457
  this.multiply(_3n); // random number
425
458
  return this;
426
459
  }
427
- /** "Private method", don't use it directly */
428
- _setWindowSize(windowSize) {
429
- this.precompute(windowSize);
430
- }
431
460
  // TODO: return `this`
432
461
  /** A point on curve is valid if it conforms to equation. */
433
462
  assertValidity() {
@@ -442,15 +471,15 @@ export function weierstrassN(CURVE, curveOpts = {}) {
442
471
  /** Compare one point to another. */
443
472
  equals(other) {
444
473
  aprjpoint(other);
445
- const { px: X1, py: Y1, pz: Z1 } = this;
446
- const { px: X2, py: Y2, pz: Z2 } = other;
474
+ const { X: X1, Y: Y1, Z: Z1 } = this;
475
+ const { X: X2, Y: Y2, Z: Z2 } = other;
447
476
  const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
448
477
  const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
449
478
  return U1 && U2;
450
479
  }
451
480
  /** Flips point to one corresponding to (x, -y) in Affine coordinates. */
452
481
  negate() {
453
- return new Point(this.px, Fp.neg(this.py), this.pz);
482
+ return new Point(this.X, Fp.neg(this.Y), this.Z);
454
483
  }
455
484
  // Renes-Costello-Batina exception-free doubling formula.
456
485
  // There is 30% faster Jacobian formula, but it is not complete.
@@ -459,7 +488,7 @@ export function weierstrassN(CURVE, curveOpts = {}) {
459
488
  double() {
460
489
  const { a, b } = CURVE;
461
490
  const b3 = Fp.mul(b, _3n);
462
- const { px: X1, py: Y1, pz: Z1 } = this;
491
+ const { X: X1, Y: Y1, Z: Z1 } = this;
463
492
  let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
464
493
  let t0 = Fp.mul(X1, X1); // step 1
465
494
  let t1 = Fp.mul(Y1, Y1);
@@ -500,8 +529,8 @@ export function weierstrassN(CURVE, curveOpts = {}) {
500
529
  // Cost: 12M + 0S + 3*a + 3*b3 + 23add.
501
530
  add(other) {
502
531
  aprjpoint(other);
503
- const { px: X1, py: Y1, pz: Z1 } = this;
504
- const { px: X2, py: Y2, pz: Z2 } = other;
532
+ const { X: X1, Y: Y1, Z: Z1 } = this;
533
+ const { X: X2, Y: Y2, Z: Z2 } = other;
505
534
  let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
506
535
  const a = CURVE.a;
507
536
  const b3 = Fp.mul(CURVE.b, _3n);
@@ -567,10 +596,10 @@ export function weierstrassN(CURVE, curveOpts = {}) {
567
596
  if (!Fn.isValidNot0(scalar))
568
597
  throw new Error('invalid scalar: out of range'); // 0 is invalid
569
598
  let point, fake; // Fake point is used to const-time mult
570
- const mul = (n) => wnaf.wNAFCached(this, n, Point.normalizeZ);
599
+ const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p));
571
600
  /** See docs for {@link EndomorphismOpts} */
572
601
  if (endo) {
573
- const { k1neg, k1, k2neg, k2 } = endo.splitScalar(scalar);
602
+ const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar);
574
603
  const { p: k1p, f: k1f } = mul(k1);
575
604
  const { p: k2p, f: k2f } = mul(k2);
576
605
  fake = k1f.add(k2f);
@@ -582,12 +611,12 @@ export function weierstrassN(CURVE, curveOpts = {}) {
582
611
  fake = f;
583
612
  }
584
613
  // Normalize `z` for both points, but return only real one
585
- return Point.normalizeZ([point, fake])[0];
614
+ return normalizeZ(Point, [point, fake])[0];
586
615
  }
587
616
  /**
588
617
  * Non-constant-time multiplication. Uses double-and-add algorithm.
589
618
  * It's faster, but should only be used when you don't care about
590
- * an exposed private key e.g. sig verification, which works over *public* keys.
619
+ * an exposed secret key e.g. sig verification, which works over *public* keys.
591
620
  */
592
621
  multiplyUnsafe(sc) {
593
622
  const { endo } = curveOpts;
@@ -598,16 +627,15 @@ export function weierstrassN(CURVE, curveOpts = {}) {
598
627
  return Point.ZERO;
599
628
  if (sc === _1n)
600
629
  return p; // fast-path
601
- if (wnaf.hasPrecomputes(this))
630
+ if (wnaf.hasCache(this))
602
631
  return this.multiply(sc);
603
632
  if (endo) {
604
- const { k1neg, k1, k2neg, k2 } = endo.splitScalar(sc);
605
- // `wNAFCachedUnsafe` is 30% slower
606
- const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2);
633
+ const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc);
634
+ const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2); // 30% faster vs wnaf.unsafe
607
635
  return finishEndo(endo.beta, p1, p2, k1neg, k2neg);
608
636
  }
609
637
  else {
610
- return wnaf.wNAFCachedUnsafe(p, sc);
638
+ return wnaf.unsafe(p, sc);
611
639
  }
612
640
  }
613
641
  multiplyAndAddUnsafe(Q, a, b) {
@@ -631,7 +659,7 @@ export function weierstrassN(CURVE, curveOpts = {}) {
631
659
  return true;
632
660
  if (isTorsionFree)
633
661
  return isTorsionFree(Point, this);
634
- return wnaf.wNAFCachedUnsafe(this, CURVE_ORDER).is0();
662
+ return wnaf.unsafe(this, CURVE_ORDER).is0();
635
663
  }
636
664
  clearCofactor() {
637
665
  const { clearCofactor } = curveOpts;
@@ -641,6 +669,10 @@ export function weierstrassN(CURVE, curveOpts = {}) {
641
669
  return clearCofactor(Point, this);
642
670
  return this.multiplyUnsafe(cofactor);
643
671
  }
672
+ isSmallOrder() {
673
+ // can we use this.clearCofactor()?
674
+ return this.multiplyUnsafe(cofactor).is0();
675
+ }
644
676
  toBytes(isCompressed = true) {
645
677
  abool('isCompressed', isCompressed);
646
678
  this.assertValidity();
@@ -665,11 +697,12 @@ export function weierstrassN(CURVE, curveOpts = {}) {
665
697
  Point.Fp = Fp;
666
698
  Point.Fn = Fn;
667
699
  const bits = Fn.BITS;
668
- const wnaf = wNAF(Point, curveOpts.endo ? Math.ceil(bits / 2) : bits);
700
+ const wnaf = new wNAF(Point, curveOpts.endo ? Math.ceil(bits / 2) : bits);
669
701
  return Point;
670
702
  }
671
703
  // _legacyWeierstrass
672
- /** @deprecated use `weierstrassN` */
704
+ // TODO: remove
705
+ /** @deprecated use `weierstrass` in newer releases */
673
706
  export function weierstrassPoints(c) {
674
707
  const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
675
708
  const Point = weierstrassN(CURVE, curveOpts);
@@ -679,8 +712,136 @@ export function weierstrassPoints(c) {
679
712
  function pprefix(hasEvenY) {
680
713
  return Uint8Array.of(hasEvenY ? 0x02 : 0x03);
681
714
  }
682
- export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
683
- _validateObject(ecdsaOpts, { hash: 'function' }, {
715
+ /**
716
+ * Implementation of the Shallue and van de Woestijne method for any weierstrass curve.
717
+ * TODO: check if there is a way to merge this with uvRatio in Edwards; move to modular.
718
+ * b = True and y = sqrt(u / v) if (u / v) is square in F, and
719
+ * b = False and y = sqrt(Z * (u / v)) otherwise.
720
+ * @param Fp
721
+ * @param Z
722
+ * @returns
723
+ */
724
+ export function SWUFpSqrtRatio(Fp, Z) {
725
+ // Generic implementation
726
+ const q = Fp.ORDER;
727
+ let l = _0n;
728
+ for (let o = q - _1n; o % _2n === _0n; o /= _2n)
729
+ l += _1n;
730
+ const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
731
+ // We need 2n ** c1 and 2n ** (c1-1). We can't use **; but we can use <<.
732
+ // 2n ** c1 == 2n << (c1-1)
733
+ const _2n_pow_c1_1 = _2n << (c1 - _1n - _1n);
734
+ const _2n_pow_c1 = _2n_pow_c1_1 * _2n;
735
+ const c2 = (q - _1n) / _2n_pow_c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
736
+ const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
737
+ const c4 = _2n_pow_c1 - _1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
738
+ const c5 = _2n_pow_c1_1; // 5. c5 = 2^(c1 - 1) # Integer arithmetic
739
+ const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2
740
+ const c7 = Fp.pow(Z, (c2 + _1n) / _2n); // 7. c7 = Z^((c2 + 1) / 2)
741
+ let sqrtRatio = (u, v) => {
742
+ let tv1 = c6; // 1. tv1 = c6
743
+ let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
744
+ let tv3 = Fp.sqr(tv2); // 3. tv3 = tv2^2
745
+ tv3 = Fp.mul(tv3, v); // 4. tv3 = tv3 * v
746
+ let tv5 = Fp.mul(u, tv3); // 5. tv5 = u * tv3
747
+ tv5 = Fp.pow(tv5, c3); // 6. tv5 = tv5^c3
748
+ tv5 = Fp.mul(tv5, tv2); // 7. tv5 = tv5 * tv2
749
+ tv2 = Fp.mul(tv5, v); // 8. tv2 = tv5 * v
750
+ tv3 = Fp.mul(tv5, u); // 9. tv3 = tv5 * u
751
+ let tv4 = Fp.mul(tv3, tv2); // 10. tv4 = tv3 * tv2
752
+ tv5 = Fp.pow(tv4, c5); // 11. tv5 = tv4^c5
753
+ let isQR = Fp.eql(tv5, Fp.ONE); // 12. isQR = tv5 == 1
754
+ tv2 = Fp.mul(tv3, c7); // 13. tv2 = tv3 * c7
755
+ tv5 = Fp.mul(tv4, tv1); // 14. tv5 = tv4 * tv1
756
+ tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)
757
+ tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
758
+ // 17. for i in (c1, c1 - 1, ..., 2):
759
+ for (let i = c1; i > _1n; i--) {
760
+ let tv5 = i - _2n; // 18. tv5 = i - 2
761
+ tv5 = _2n << (tv5 - _1n); // 19. tv5 = 2^tv5
762
+ let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
763
+ const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
764
+ tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
765
+ tv1 = Fp.mul(tv1, tv1); // 23. tv1 = tv1 * tv1
766
+ tvv5 = Fp.mul(tv4, tv1); // 24. tv5 = tv4 * tv1
767
+ tv3 = Fp.cmov(tv2, tv3, e1); // 25. tv3 = CMOV(tv2, tv3, e1)
768
+ tv4 = Fp.cmov(tvv5, tv4, e1); // 26. tv4 = CMOV(tv5, tv4, e1)
769
+ }
770
+ return { isValid: isQR, value: tv3 };
771
+ };
772
+ if (Fp.ORDER % _4n === _3n) {
773
+ // sqrt_ratio_3mod4(u, v)
774
+ const c1 = (Fp.ORDER - _3n) / _4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
775
+ const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
776
+ sqrtRatio = (u, v) => {
777
+ let tv1 = Fp.sqr(v); // 1. tv1 = v^2
778
+ const tv2 = Fp.mul(u, v); // 2. tv2 = u * v
779
+ tv1 = Fp.mul(tv1, tv2); // 3. tv1 = tv1 * tv2
780
+ let y1 = Fp.pow(tv1, c1); // 4. y1 = tv1^c1
781
+ y1 = Fp.mul(y1, tv2); // 5. y1 = y1 * tv2
782
+ const y2 = Fp.mul(y1, c2); // 6. y2 = y1 * c2
783
+ const tv3 = Fp.mul(Fp.sqr(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
784
+ const isQR = Fp.eql(tv3, u); // 9. isQR = tv3 == u
785
+ let y = Fp.cmov(y2, y1, isQR); // 10. y = CMOV(y2, y1, isQR)
786
+ return { isValid: isQR, value: y }; // 11. return (isQR, y) isQR ? y : y*c2
787
+ };
788
+ }
789
+ // No curves uses that
790
+ // if (Fp.ORDER % _8n === _5n) // sqrt_ratio_5mod8
791
+ return sqrtRatio;
792
+ }
793
+ /**
794
+ * Simplified Shallue-van de Woestijne-Ulas Method
795
+ * https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2
796
+ */
797
+ export function mapToCurveSimpleSWU(Fp, opts) {
798
+ validateField(Fp);
799
+ const { A, B, Z } = opts;
800
+ if (!Fp.isValid(A) || !Fp.isValid(B) || !Fp.isValid(Z))
801
+ throw new Error('mapToCurveSimpleSWU: invalid opts');
802
+ const sqrtRatio = SWUFpSqrtRatio(Fp, Z);
803
+ if (!Fp.isOdd)
804
+ throw new Error('Field does not have .isOdd()');
805
+ // Input: u, an element of F.
806
+ // Output: (x, y), a point on E.
807
+ return (u) => {
808
+ // prettier-ignore
809
+ let tv1, tv2, tv3, tv4, tv5, tv6, x, y;
810
+ tv1 = Fp.sqr(u); // 1. tv1 = u^2
811
+ tv1 = Fp.mul(tv1, Z); // 2. tv1 = Z * tv1
812
+ tv2 = Fp.sqr(tv1); // 3. tv2 = tv1^2
813
+ tv2 = Fp.add(tv2, tv1); // 4. tv2 = tv2 + tv1
814
+ tv3 = Fp.add(tv2, Fp.ONE); // 5. tv3 = tv2 + 1
815
+ tv3 = Fp.mul(tv3, B); // 6. tv3 = B * tv3
816
+ tv4 = Fp.cmov(Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
817
+ tv4 = Fp.mul(tv4, A); // 8. tv4 = A * tv4
818
+ tv2 = Fp.sqr(tv3); // 9. tv2 = tv3^2
819
+ tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2
820
+ tv5 = Fp.mul(tv6, A); // 11. tv5 = A * tv6
821
+ tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5
822
+ tv2 = Fp.mul(tv2, tv3); // 13. tv2 = tv2 * tv3
823
+ tv6 = Fp.mul(tv6, tv4); // 14. tv6 = tv6 * tv4
824
+ tv5 = Fp.mul(tv6, B); // 15. tv5 = B * tv6
825
+ tv2 = Fp.add(tv2, tv5); // 16. tv2 = tv2 + tv5
826
+ x = Fp.mul(tv1, tv3); // 17. x = tv1 * tv3
827
+ const { isValid, value } = sqrtRatio(tv2, tv6); // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
828
+ y = Fp.mul(tv1, u); // 19. y = tv1 * u -> Z * u^3 * y1
829
+ y = Fp.mul(y, value); // 20. y = y * y1
830
+ x = Fp.cmov(x, tv3, isValid); // 21. x = CMOV(x, tv3, is_gx1_square)
831
+ y = Fp.cmov(y, value, isValid); // 22. y = CMOV(y, y1, is_gx1_square)
832
+ const e1 = Fp.isOdd(u) === Fp.isOdd(y); // 23. e1 = sgn0(u) == sgn0(y)
833
+ y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
834
+ const tv4_inv = FpInvertBatch(Fp, [tv4], true)[0];
835
+ x = Fp.mul(x, tv4_inv); // 25. x = x / tv4
836
+ return { x, y };
837
+ };
838
+ }
839
+ /**
840
+ * Creates ECDSA for given elliptic curve Point and hash function.
841
+ */
842
+ export function ecdsa(Point, hash, ecdsaOpts = {}) {
843
+ ahash(hash);
844
+ _validateObject(ecdsaOpts, {}, {
684
845
  hmac: 'function',
685
846
  lowS: 'boolean',
686
847
  randomBytes: 'function',
@@ -689,9 +850,17 @@ export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
689
850
  });
690
851
  const randomBytes_ = ecdsaOpts.randomBytes || randomBytes;
691
852
  const hmac_ = ecdsaOpts.hmac ||
692
- ((key, ...msgs) => hmac(ecdsaOpts.hash, key, concatBytes(...msgs)));
853
+ ((key, ...msgs) => hmac(hash, key, concatBytes(...msgs)));
693
854
  const { Fp, Fn } = Point;
694
855
  const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
856
+ const seedLen = getMinHashLength(CURVE_ORDER);
857
+ const lengths = {
858
+ secret: Fn.BYTES,
859
+ public: 1 + Fp.BYTES,
860
+ publicUncompressed: 1 + 2 * Fp.BYTES,
861
+ signature: 2 * Fn.BYTES,
862
+ seed: seedLen,
863
+ };
695
864
  function isBiggerThanHalfOrder(number) {
696
865
  const HALF = CURVE_ORDER >> _1n;
697
866
  return number > HALF;
@@ -716,23 +885,24 @@ export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
716
885
  this.recovery = recovery;
717
886
  Object.freeze(this);
718
887
  }
719
- // pair (bytes of r, bytes of s)
720
- static fromCompact(hex) {
721
- const L = Fn.BYTES;
722
- const b = ensureBytes('compactSignature', hex, L * 2);
723
- return new Signature(Fn.fromBytes(b.subarray(0, L)), Fn.fromBytes(b.subarray(L, L * 2)));
888
+ static fromBytes(bytes, format = 'compact') {
889
+ if (format === 'compact') {
890
+ const L = Fn.BYTES;
891
+ abytes(bytes, L * 2);
892
+ const r = bytes.subarray(0, L);
893
+ const s = bytes.subarray(L, L * 2);
894
+ return new Signature(Fn.fromBytes(r), Fn.fromBytes(s));
895
+ }
896
+ if (format === 'der') {
897
+ abytes(bytes);
898
+ const { r, s } = DER.toSig(bytes);
899
+ return new Signature(r, s);
900
+ }
901
+ throw new Error('invalid format');
724
902
  }
725
- // DER encoded ECDSA signature
726
- // https://bitcoin.stackexchange.com/questions/57644/what-are-the-parts-of-a-bitcoin-transaction-input-script
727
- static fromDER(hex) {
728
- const { r, s } = DER.toSig(ensureBytes('DER', hex));
729
- return new Signature(r, s);
903
+ static fromHex(hex, format) {
904
+ return this.fromBytes(hexToBytes(hex), format);
730
905
  }
731
- /**
732
- * @todo remove
733
- * @deprecated
734
- */
735
- assertValidity() { }
736
906
  addRecoveryBit(recovery) {
737
907
  return new Signature(this.r, this.s, recovery);
738
908
  }
@@ -776,21 +946,30 @@ export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
776
946
  normalizeS() {
777
947
  return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this;
778
948
  }
779
- toBytes(format) {
949
+ toBytes(format = 'compact') {
780
950
  if (format === 'compact')
781
951
  return concatBytes(Fn.toBytes(this.r), Fn.toBytes(this.s));
782
952
  if (format === 'der')
783
953
  return hexToBytes(DER.hexFromSig(this));
784
954
  throw new Error('invalid format');
785
955
  }
786
- // DER-encoded
956
+ toHex(format) {
957
+ return bytesToHex(this.toBytes(format));
958
+ }
959
+ // TODO: remove
960
+ assertValidity() { }
961
+ static fromCompact(hex) {
962
+ return Signature.fromBytes(ensureBytes('sig', hex), 'compact');
963
+ }
964
+ static fromDER(hex) {
965
+ return Signature.fromBytes(ensureBytes('sig', hex), 'der');
966
+ }
787
967
  toDERRawBytes() {
788
968
  return this.toBytes('der');
789
969
  }
790
970
  toDERHex() {
791
971
  return bytesToHex(this.toBytes('der'));
792
972
  }
793
- // padded bytes of r, then padded bytes of s
794
973
  toCompactRawBytes() {
795
974
  return this.toBytes('compact');
796
975
  }
@@ -798,76 +977,85 @@ export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
798
977
  return bytesToHex(this.toBytes('compact'));
799
978
  }
800
979
  }
801
- const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey);
802
- const utils = {
803
- isValidPrivateKey(privateKey) {
804
- try {
805
- normPrivateKeyToScalar(privateKey);
806
- return true;
807
- }
808
- catch (error) {
980
+ function isValidSecretKey(privateKey) {
981
+ try {
982
+ return !!_normFnElement(Fn, privateKey);
983
+ }
984
+ catch (error) {
985
+ return false;
986
+ }
987
+ }
988
+ function isValidPublicKey(publicKey, isCompressed) {
989
+ try {
990
+ const l = publicKey.length;
991
+ if (isCompressed === true && l !== lengths.public)
809
992
  return false;
810
- }
811
- },
812
- normPrivateKeyToScalar: normPrivateKeyToScalar,
813
- /**
814
- * Produces cryptographically secure private key from random of size
815
- * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
816
- */
817
- randomPrivateKey: () => {
818
- const n = CURVE_ORDER;
819
- return mapHashToField(randomBytes_(getMinHashLength(n)), n);
820
- },
993
+ if (isCompressed === false && l !== lengths.publicUncompressed)
994
+ return false;
995
+ return !!Point.fromBytes(publicKey);
996
+ }
997
+ catch (error) {
998
+ return false;
999
+ }
1000
+ }
1001
+ /**
1002
+ * Produces cryptographically secure secret key from random of size
1003
+ * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
1004
+ */
1005
+ function randomSecretKey(seed = randomBytes_(seedLen)) {
1006
+ return mapHashToField(seed, CURVE_ORDER);
1007
+ }
1008
+ const utils = {
1009
+ isValidSecretKey,
1010
+ isValidPublicKey,
1011
+ randomSecretKey,
1012
+ // TODO: remove
1013
+ isValidPrivateKey: isValidSecretKey,
1014
+ randomPrivateKey: randomSecretKey,
1015
+ normPrivateKeyToScalar: (key) => _normFnElement(Fn, key),
821
1016
  precompute(windowSize = 8, point = Point.BASE) {
822
1017
  return point.precompute(windowSize, false);
823
1018
  },
824
1019
  };
825
1020
  /**
826
- * Computes public key for a private key. Checks for validity of the private key.
827
- * @param privateKey private key
1021
+ * Computes public key for a secret key. Checks for validity of the secret key.
828
1022
  * @param isCompressed whether to return compact (default), or full key
829
1023
  * @returns Public key, full when isCompressed=false; short when isCompressed=true
830
1024
  */
831
- function getPublicKey(privateKey, isCompressed = true) {
832
- return Point.fromPrivateKey(privateKey).toBytes(isCompressed);
1025
+ function getPublicKey(secretKey, isCompressed = true) {
1026
+ return Point.BASE.multiply(_normFnElement(Fn, secretKey)).toBytes(isCompressed);
833
1027
  }
834
1028
  /**
835
1029
  * Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
836
1030
  */
837
1031
  function isProbPub(item) {
1032
+ // TODO: remove
838
1033
  if (typeof item === 'bigint')
839
1034
  return false;
1035
+ // TODO: remove
840
1036
  if (item instanceof Point)
841
1037
  return true;
842
- const arr = ensureBytes('key', item);
843
- const length = arr.length;
844
- const L = Fp.BYTES;
845
- const LC = L + 1; // e.g. 33 for 32
846
- const LU = 2 * L + 1; // e.g. 65 for 32
847
- if (curveOpts.allowedPrivateKeyLengths || Fn.BYTES === LC) {
1038
+ if (Fn.allowedLengths || lengths.secret === lengths.public)
848
1039
  return undefined;
849
- }
850
- else {
851
- return length === LC || length === LU;
852
- }
1040
+ const l = ensureBytes('key', item).length;
1041
+ return l === lengths.public || l === lengths.publicUncompressed;
853
1042
  }
854
1043
  /**
855
1044
  * ECDH (Elliptic Curve Diffie Hellman).
856
- * Computes shared public key from private key and public key.
857
- * Checks: 1) private key validity 2) shared key is on-curve.
1045
+ * Computes shared public key from secret key A and public key B.
1046
+ * Checks: 1) secret key validity 2) shared key is on-curve.
858
1047
  * Does NOT hash the result.
859
- * @param privateA private key
860
- * @param publicB different public key
861
1048
  * @param isCompressed whether to return compact (default), or full key
862
1049
  * @returns shared public key
863
1050
  */
864
- function getSharedSecret(privateA, publicB, isCompressed = true) {
865
- if (isProbPub(privateA) === true)
1051
+ function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
1052
+ if (isProbPub(secretKeyA) === true)
866
1053
  throw new Error('first arg must be private key');
867
- if (isProbPub(publicB) === false)
1054
+ if (isProbPub(publicKeyB) === false)
868
1055
  throw new Error('second arg must be public key');
869
- const b = Point.fromHex(publicB); // check for being on-curve
870
- return b.multiply(normPrivateKeyToScalar(privateA)).toBytes(isCompressed);
1056
+ const s = _normFnElement(Fn, secretKeyA);
1057
+ const b = Point.fromHex(publicKeyB); // checks for being on-curve
1058
+ return b.multiply(s).toBytes(isCompressed);
871
1059
  }
872
1060
  // RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
873
1061
  // FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
@@ -906,7 +1094,6 @@ export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
906
1094
  function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
907
1095
  if (['recovered', 'canonical'].some((k) => k in opts))
908
1096
  throw new Error('sign() legacy options not supported');
909
- const { hash } = ecdsaOpts;
910
1097
  let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
911
1098
  if (lowS == null)
912
1099
  lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
@@ -918,17 +1105,21 @@ export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
918
1105
  // with fnBits % 8 !== 0. Because of that, we unwrap it here as int2octets call.
919
1106
  // const bits2octets = (bits) => int2octets(bits2int_modN(bits))
920
1107
  const h1int = bits2int_modN(msgHash);
921
- const d = normPrivateKeyToScalar(privateKey); // validate private key, convert to bigint
1108
+ const d = _normFnElement(Fn, privateKey); // validate secret key, convert to bigint
922
1109
  const seedArgs = [int2octets(d), int2octets(h1int)];
923
1110
  // extraEntropy. RFC6979 3.6: additional k' (optional).
924
1111
  if (ent != null && ent !== false) {
925
1112
  // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
926
- const e = ent === true ? randomBytes_(Fp.BYTES) : ent; // generate random bytes OR pass as-is
1113
+ const e = ent === true ? randomBytes_(lengths.secret) : ent; // gen random bytes OR pass as-is
927
1114
  seedArgs.push(ensureBytes('extraEntropy', e)); // check for being bytes
928
1115
  }
929
1116
  const seed = concatBytes(...seedArgs); // Step D of RFC6979 3.2
930
1117
  const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
931
1118
  // Converts signature params into point w r/s, checks result for validity.
1119
+ // To transform k => Signature:
1120
+ // q = k⋅G
1121
+ // r = q.x mod n
1122
+ // s = k^-1(m + rd) mod n
932
1123
  // Can use scalar blinding b^-1(bm + bdr) where b ∈ [1,q−1] according to
933
1124
  // https://tches.iacr.org/index.php/TCHES/article/view/7337/6509. We've decided against it:
934
1125
  // a) dependency on CSPRNG b) 15% slowdown c) doesn't really help since bigints are not CT
@@ -939,7 +1130,7 @@ export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
939
1130
  if (!Fn.isValidNot0(k))
940
1131
  return; // Valid scalars (including k) must be in 1..N-1
941
1132
  const ik = Fn.inv(k); // k^-1 mod n
942
- const q = Point.BASE.multiply(k).toAffine(); // q = Gk
1133
+ const q = Point.BASE.multiply(k).toAffine(); // q = k⋅G
943
1134
  const r = Fn.create(q.x); // r = q.x mod n
944
1135
  if (r === _0n)
945
1136
  return;
@@ -959,21 +1150,17 @@ export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
959
1150
  const defaultSigOpts = { lowS: ecdsaOpts.lowS, prehash: false };
960
1151
  const defaultVerOpts = { lowS: ecdsaOpts.lowS, prehash: false };
961
1152
  /**
962
- * Signs message hash with a private key.
1153
+ * Signs message hash with a secret key.
963
1154
  * ```
964
1155
  * sign(m, d, k) where
965
1156
  * (x, y) = G × k
966
1157
  * r = x mod n
967
1158
  * s = (m + dr)/k mod n
968
1159
  * ```
969
- * @param msgHash NOT message. msg needs to be hashed to `msgHash`, or use `prehash`.
970
- * @param privKey private key
971
- * @param opts lowS for non-malleable sigs. extraEntropy for mixing randomness into k. prehash will hash first arg.
972
- * @returns signature with recovery param
973
1160
  */
974
- function sign(msgHash, privKey, opts = defaultSigOpts) {
975
- const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
976
- const drbg = createHmacDrbg(ecdsaOpts.hash.outputLen, Fn.BYTES, hmac_);
1161
+ function sign(msgHash, secretKey, opts = defaultSigOpts) {
1162
+ const { seed, k2sig } = prepSig(msgHash, secretKey, opts); // Steps A, D of RFC6979 3.2.
1163
+ const drbg = createHmacDrbg(hash.outputLen, Fn.BYTES, hmac_);
977
1164
  return drbg(seed, k2sig); // Steps B, C, D, E, F, G
978
1165
  }
979
1166
  // Enable precomputes. Slows down first publicKey computation by 20ms.
@@ -1001,88 +1188,98 @@ export function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
1001
1188
  // TODO: remove
1002
1189
  if ('strict' in opts)
1003
1190
  throw new Error('options.strict was renamed to lowS');
1004
- if (format !== undefined && !['compact', 'der', 'js'].includes(format))
1005
- throw new Error('format must be "compact", "der" or "js"');
1006
- const isHex = typeof sg === 'string' || isBytes(sg);
1007
- const isObj = !isHex &&
1008
- !format &&
1009
- typeof sg === 'object' &&
1010
- sg !== null &&
1011
- typeof sg.r === 'bigint' &&
1012
- typeof sg.s === 'bigint';
1013
- if (!isHex && !isObj)
1014
- throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
1015
1191
  let _sig = undefined;
1016
1192
  let P;
1017
- // deduce signature format
1018
- try {
1019
- // if (format === 'js') {
1020
- // if (sg != null && !isBytes(sg)) _sig = new Signature(sg.r, sg.s);
1021
- // } else if (format === 'compact') {
1022
- // _sig = Signature.fromCompact(sg);
1023
- // } else if (format === 'der') {
1024
- // _sig = Signature.fromDER(sg);
1025
- // } else {
1026
- // throw new Error('invalid format');
1027
- // }
1193
+ if (format === undefined) {
1194
+ // Try to deduce format
1195
+ const isHex = typeof sg === 'string' || isBytes(sg);
1196
+ const isObj = !isHex &&
1197
+ sg !== null &&
1198
+ typeof sg === 'object' &&
1199
+ typeof sg.r === 'bigint' &&
1200
+ typeof sg.s === 'bigint';
1201
+ if (!isHex && !isObj)
1202
+ throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
1028
1203
  if (isObj) {
1029
- if (format === undefined || format === 'js') {
1030
- _sig = new Signature(sg.r, sg.s);
1031
- }
1032
- else {
1033
- throw new Error('invalid format');
1034
- }
1204
+ _sig = new Signature(sg.r, sg.s);
1035
1205
  }
1036
- if (isHex) {
1206
+ else if (isHex) {
1037
1207
  // TODO: remove this malleable check
1038
1208
  // Signature can be represented in 2 ways: compact (2*Fn.BYTES) & DER (variable-length).
1039
1209
  // Since DER can also be 2*Fn.BYTES bytes, we check for it first.
1040
1210
  try {
1041
- if (format !== 'compact')
1042
- _sig = Signature.fromDER(sg);
1211
+ _sig = Signature.fromDER(sg);
1043
1212
  }
1044
1213
  catch (derError) {
1045
1214
  if (!(derError instanceof DER.Err))
1046
1215
  throw derError;
1047
1216
  }
1048
- if (!_sig && format !== 'der')
1049
- _sig = Signature.fromCompact(sg);
1217
+ if (!_sig) {
1218
+ try {
1219
+ _sig = Signature.fromCompact(sg);
1220
+ }
1221
+ catch (error) {
1222
+ return false;
1223
+ }
1224
+ }
1050
1225
  }
1051
- P = Point.fromHex(publicKey);
1052
1226
  }
1053
- catch (error) {
1054
- return false;
1227
+ else {
1228
+ if (format === 'compact' || format === 'der') {
1229
+ if (typeof sg !== 'string' && !isBytes(sg))
1230
+ throw new Error('"der" / "compact" format expects Uint8Array signature');
1231
+ _sig = Signature.fromBytes(ensureBytes('sig', sg), format);
1232
+ }
1233
+ else if (format === 'js') {
1234
+ if (!(sg instanceof Signature))
1235
+ throw new Error('"js" format expects Signature instance');
1236
+ _sig = sg;
1237
+ }
1238
+ else {
1239
+ throw new Error('format must be "compact", "der" or "js"');
1240
+ }
1055
1241
  }
1056
1242
  if (!_sig)
1057
1243
  return false;
1058
- if (lowS && _sig.hasHighS())
1059
- return false;
1060
- // todo: optional.hash => hash
1061
- if (prehash)
1062
- msgHash = ecdsaOpts.hash(msgHash);
1063
- const { r, s } = _sig;
1064
- const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
1065
- const is = Fn.inv(s); // s^-1
1066
- const u1 = Fn.create(h * is); // u1 = hs^-1 mod n
1067
- const u2 = Fn.create(r * is); // u2 = rs^-1 mod n
1068
- const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
1069
- if (R.is0())
1244
+ try {
1245
+ P = Point.fromHex(publicKey);
1246
+ if (lowS && _sig.hasHighS())
1247
+ return false;
1248
+ // todo: optional.hash => hash
1249
+ if (prehash)
1250
+ msgHash = hash(msgHash);
1251
+ const { r, s } = _sig;
1252
+ const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
1253
+ const is = Fn.inv(s); // s^-1
1254
+ const u1 = Fn.create(h * is); // u1 = hs^-1 mod n
1255
+ const u2 = Fn.create(r * is); // u2 = rs^-1 mod n
1256
+ const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
1257
+ if (R.is0())
1258
+ return false;
1259
+ const v = Fn.create(R.x); // v = r.x mod n
1260
+ return v === r;
1261
+ }
1262
+ catch (e) {
1070
1263
  return false;
1071
- const v = Fn.create(R.x); // v = r.x mod n
1072
- return v === r;
1264
+ }
1265
+ }
1266
+ function keygen(seed) {
1267
+ const secretKey = utils.randomSecretKey(seed);
1268
+ return { secretKey, publicKey: getPublicKey(secretKey) };
1073
1269
  }
1074
- // TODO: clarify API for cloning .clone({hash: sha512}) ? .createWith({hash: sha512})?
1075
- // const clone = (hash: CHash): ECDSA => ecdsa(Point, { ...ecdsaOpts, ...getHash(hash) }, curveOpts);
1076
1270
  return Object.freeze({
1271
+ keygen,
1077
1272
  getPublicKey,
1078
- getSharedSecret,
1079
1273
  sign,
1080
1274
  verify,
1275
+ getSharedSecret,
1081
1276
  utils,
1082
1277
  Point,
1083
1278
  Signature,
1279
+ info: { type: 'weierstrass', lengths, publicKeyHasPrefix: true },
1084
1280
  });
1085
1281
  }
1282
+ // TODO: remove
1086
1283
  function _weierstrass_legacy_opts_to_new(c) {
1087
1284
  const CURVE = {
1088
1285
  a: c.a,
@@ -1094,14 +1291,19 @@ function _weierstrass_legacy_opts_to_new(c) {
1094
1291
  Gy: c.Gy,
1095
1292
  };
1096
1293
  const Fp = c.Fp;
1097
- const Fn = Field(CURVE.n, c.nBitLength);
1294
+ let allowedLengths = c.allowedPrivateKeyLengths
1295
+ ? Array.from(new Set(c.allowedPrivateKeyLengths.map((l) => Math.ceil(l / 2))))
1296
+ : undefined;
1297
+ const Fn = Field(CURVE.n, {
1298
+ BITS: c.nBitLength,
1299
+ allowedLengths: allowedLengths,
1300
+ modOnDecode: c.wrapPrivateKey,
1301
+ });
1098
1302
  const curveOpts = {
1099
1303
  Fp,
1100
1304
  Fn,
1101
- allowedPrivateKeyLengths: c.allowedPrivateKeyLengths,
1102
1305
  allowInfinityPoint: c.allowInfinityPoint,
1103
1306
  endo: c.endo,
1104
- wrapPrivateKey: c.wrapPrivateKey,
1105
1307
  isTorsionFree: c.isTorsionFree,
1106
1308
  clearCofactor: c.clearCofactor,
1107
1309
  fromBytes: c.fromBytes,
@@ -1112,15 +1314,15 @@ function _weierstrass_legacy_opts_to_new(c) {
1112
1314
  function _ecdsa_legacy_opts_to_new(c) {
1113
1315
  const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
1114
1316
  const ecdsaOpts = {
1115
- hash: c.hash,
1116
1317
  hmac: c.hmac,
1117
1318
  randomBytes: c.randomBytes,
1118
1319
  lowS: c.lowS,
1119
1320
  bits2int: c.bits2int,
1120
1321
  bits2int_modN: c.bits2int_modN,
1121
1322
  };
1122
- return { CURVE, curveOpts, ecdsaOpts };
1323
+ return { CURVE, curveOpts, hash: c.hash, ecdsaOpts };
1123
1324
  }
1325
+ // TODO: remove
1124
1326
  function _weierstrass_new_output_to_legacy(c, Point) {
1125
1327
  const { Fp, Fn } = Point;
1126
1328
  // TODO: remove
@@ -1128,16 +1330,16 @@ function _weierstrass_new_output_to_legacy(c, Point) {
1128
1330
  return inRange(num, _1n, Fn.ORDER);
1129
1331
  }
1130
1332
  const weierstrassEquation = _legacyHelperEquat(Fp, c.a, c.b);
1131
- const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, c.allowedPrivateKeyLengths, c.wrapPrivateKey);
1132
1333
  return Object.assign({}, {
1133
1334
  CURVE: c,
1134
1335
  Point: Point,
1135
1336
  ProjectivePoint: Point,
1136
- normPrivateKeyToScalar,
1337
+ normPrivateKeyToScalar: (key) => _normFnElement(Fn, key),
1137
1338
  weierstrassEquation,
1138
1339
  isWithinCurveOrder,
1139
1340
  });
1140
1341
  }
1342
+ // TODO: remove
1141
1343
  function _ecdsa_new_output_to_legacy(c, ecdsa) {
1142
1344
  return Object.assign({}, ecdsa, {
1143
1345
  ProjectivePoint: ecdsa.Point,
@@ -1146,133 +1348,9 @@ function _ecdsa_new_output_to_legacy(c, ecdsa) {
1146
1348
  }
1147
1349
  // _ecdsa_legacy
1148
1350
  export function weierstrass(c) {
1149
- const { CURVE, curveOpts, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
1351
+ const { CURVE, curveOpts, hash, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
1150
1352
  const Point = weierstrassN(CURVE, curveOpts);
1151
- const signs = ecdsa(Point, ecdsaOpts, curveOpts);
1353
+ const signs = ecdsa(Point, hash, ecdsaOpts);
1152
1354
  return _ecdsa_new_output_to_legacy(c, signs);
1153
1355
  }
1154
- /**
1155
- * Implementation of the Shallue and van de Woestijne method for any weierstrass curve.
1156
- * TODO: check if there is a way to merge this with uvRatio in Edwards; move to modular.
1157
- * b = True and y = sqrt(u / v) if (u / v) is square in F, and
1158
- * b = False and y = sqrt(Z * (u / v)) otherwise.
1159
- * @param Fp
1160
- * @param Z
1161
- * @returns
1162
- */
1163
- export function SWUFpSqrtRatio(Fp, Z) {
1164
- // Generic implementation
1165
- const q = Fp.ORDER;
1166
- let l = _0n;
1167
- for (let o = q - _1n; o % _2n === _0n; o /= _2n)
1168
- l += _1n;
1169
- const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
1170
- // We need 2n ** c1 and 2n ** (c1-1). We can't use **; but we can use <<.
1171
- // 2n ** c1 == 2n << (c1-1)
1172
- const _2n_pow_c1_1 = _2n << (c1 - _1n - _1n);
1173
- const _2n_pow_c1 = _2n_pow_c1_1 * _2n;
1174
- const c2 = (q - _1n) / _2n_pow_c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
1175
- const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
1176
- const c4 = _2n_pow_c1 - _1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
1177
- const c5 = _2n_pow_c1_1; // 5. c5 = 2^(c1 - 1) # Integer arithmetic
1178
- const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2
1179
- const c7 = Fp.pow(Z, (c2 + _1n) / _2n); // 7. c7 = Z^((c2 + 1) / 2)
1180
- let sqrtRatio = (u, v) => {
1181
- let tv1 = c6; // 1. tv1 = c6
1182
- let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
1183
- let tv3 = Fp.sqr(tv2); // 3. tv3 = tv2^2
1184
- tv3 = Fp.mul(tv3, v); // 4. tv3 = tv3 * v
1185
- let tv5 = Fp.mul(u, tv3); // 5. tv5 = u * tv3
1186
- tv5 = Fp.pow(tv5, c3); // 6. tv5 = tv5^c3
1187
- tv5 = Fp.mul(tv5, tv2); // 7. tv5 = tv5 * tv2
1188
- tv2 = Fp.mul(tv5, v); // 8. tv2 = tv5 * v
1189
- tv3 = Fp.mul(tv5, u); // 9. tv3 = tv5 * u
1190
- let tv4 = Fp.mul(tv3, tv2); // 10. tv4 = tv3 * tv2
1191
- tv5 = Fp.pow(tv4, c5); // 11. tv5 = tv4^c5
1192
- let isQR = Fp.eql(tv5, Fp.ONE); // 12. isQR = tv5 == 1
1193
- tv2 = Fp.mul(tv3, c7); // 13. tv2 = tv3 * c7
1194
- tv5 = Fp.mul(tv4, tv1); // 14. tv5 = tv4 * tv1
1195
- tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)
1196
- tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
1197
- // 17. for i in (c1, c1 - 1, ..., 2):
1198
- for (let i = c1; i > _1n; i--) {
1199
- let tv5 = i - _2n; // 18. tv5 = i - 2
1200
- tv5 = _2n << (tv5 - _1n); // 19. tv5 = 2^tv5
1201
- let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
1202
- const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
1203
- tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
1204
- tv1 = Fp.mul(tv1, tv1); // 23. tv1 = tv1 * tv1
1205
- tvv5 = Fp.mul(tv4, tv1); // 24. tv5 = tv4 * tv1
1206
- tv3 = Fp.cmov(tv2, tv3, e1); // 25. tv3 = CMOV(tv2, tv3, e1)
1207
- tv4 = Fp.cmov(tvv5, tv4, e1); // 26. tv4 = CMOV(tv5, tv4, e1)
1208
- }
1209
- return { isValid: isQR, value: tv3 };
1210
- };
1211
- if (Fp.ORDER % _4n === _3n) {
1212
- // sqrt_ratio_3mod4(u, v)
1213
- const c1 = (Fp.ORDER - _3n) / _4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
1214
- const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
1215
- sqrtRatio = (u, v) => {
1216
- let tv1 = Fp.sqr(v); // 1. tv1 = v^2
1217
- const tv2 = Fp.mul(u, v); // 2. tv2 = u * v
1218
- tv1 = Fp.mul(tv1, tv2); // 3. tv1 = tv1 * tv2
1219
- let y1 = Fp.pow(tv1, c1); // 4. y1 = tv1^c1
1220
- y1 = Fp.mul(y1, tv2); // 5. y1 = y1 * tv2
1221
- const y2 = Fp.mul(y1, c2); // 6. y2 = y1 * c2
1222
- const tv3 = Fp.mul(Fp.sqr(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
1223
- const isQR = Fp.eql(tv3, u); // 9. isQR = tv3 == u
1224
- let y = Fp.cmov(y2, y1, isQR); // 10. y = CMOV(y2, y1, isQR)
1225
- return { isValid: isQR, value: y }; // 11. return (isQR, y) isQR ? y : y*c2
1226
- };
1227
- }
1228
- // No curves uses that
1229
- // if (Fp.ORDER % _8n === _5n) // sqrt_ratio_5mod8
1230
- return sqrtRatio;
1231
- }
1232
- /**
1233
- * Simplified Shallue-van de Woestijne-Ulas Method
1234
- * https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2
1235
- */
1236
- export function mapToCurveSimpleSWU(Fp, opts) {
1237
- validateField(Fp);
1238
- const { A, B, Z } = opts;
1239
- if (!Fp.isValid(A) || !Fp.isValid(B) || !Fp.isValid(Z))
1240
- throw new Error('mapToCurveSimpleSWU: invalid opts');
1241
- const sqrtRatio = SWUFpSqrtRatio(Fp, Z);
1242
- if (!Fp.isOdd)
1243
- throw new Error('Field does not have .isOdd()');
1244
- // Input: u, an element of F.
1245
- // Output: (x, y), a point on E.
1246
- return (u) => {
1247
- // prettier-ignore
1248
- let tv1, tv2, tv3, tv4, tv5, tv6, x, y;
1249
- tv1 = Fp.sqr(u); // 1. tv1 = u^2
1250
- tv1 = Fp.mul(tv1, Z); // 2. tv1 = Z * tv1
1251
- tv2 = Fp.sqr(tv1); // 3. tv2 = tv1^2
1252
- tv2 = Fp.add(tv2, tv1); // 4. tv2 = tv2 + tv1
1253
- tv3 = Fp.add(tv2, Fp.ONE); // 5. tv3 = tv2 + 1
1254
- tv3 = Fp.mul(tv3, B); // 6. tv3 = B * tv3
1255
- tv4 = Fp.cmov(Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
1256
- tv4 = Fp.mul(tv4, A); // 8. tv4 = A * tv4
1257
- tv2 = Fp.sqr(tv3); // 9. tv2 = tv3^2
1258
- tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2
1259
- tv5 = Fp.mul(tv6, A); // 11. tv5 = A * tv6
1260
- tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5
1261
- tv2 = Fp.mul(tv2, tv3); // 13. tv2 = tv2 * tv3
1262
- tv6 = Fp.mul(tv6, tv4); // 14. tv6 = tv6 * tv4
1263
- tv5 = Fp.mul(tv6, B); // 15. tv5 = B * tv6
1264
- tv2 = Fp.add(tv2, tv5); // 16. tv2 = tv2 + tv5
1265
- x = Fp.mul(tv1, tv3); // 17. x = tv1 * tv3
1266
- const { isValid, value } = sqrtRatio(tv2, tv6); // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
1267
- y = Fp.mul(tv1, u); // 19. y = tv1 * u -> Z * u^3 * y1
1268
- y = Fp.mul(y, value); // 20. y = y * y1
1269
- x = Fp.cmov(x, tv3, isValid); // 21. x = CMOV(x, tv3, is_gx1_square)
1270
- y = Fp.cmov(y, value, isValid); // 22. y = CMOV(y, y1, is_gx1_square)
1271
- const e1 = Fp.isOdd(u) === Fp.isOdd(y); // 23. e1 = sgn0(u) == sgn0(y)
1272
- y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
1273
- const tv4_inv = FpInvertBatch(Fp, [tv4], true)[0];
1274
- x = Fp.mul(x, tv4_inv); // 25. x = x / tv4
1275
- return { x, y };
1276
- };
1277
- }
1278
1356
  //# sourceMappingURL=weierstrass.js.map