@noble/curves 1.9.0 → 1.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/README.md +78 -34
  2. package/_shortw_utils.d.ts +7 -5
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +2 -8
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +60 -24
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +158 -109
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +44 -9
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +99 -11
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +112 -25
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +141 -92
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/fft.d.ts +122 -0
  19. package/abstract/fft.d.ts.map +1 -0
  20. package/abstract/fft.js +438 -0
  21. package/abstract/fft.js.map +1 -0
  22. package/abstract/hash-to-curve.d.ts +25 -11
  23. package/abstract/hash-to-curve.d.ts.map +1 -1
  24. package/abstract/hash-to-curve.js +17 -14
  25. package/abstract/hash-to-curve.js.map +1 -1
  26. package/abstract/modular.d.ts +28 -17
  27. package/abstract/modular.d.ts.map +1 -1
  28. package/abstract/modular.js +156 -139
  29. package/abstract/modular.js.map +1 -1
  30. package/abstract/montgomery.d.ts +3 -8
  31. package/abstract/montgomery.d.ts.map +1 -1
  32. package/abstract/montgomery.js +73 -93
  33. package/abstract/montgomery.js.map +1 -1
  34. package/abstract/poseidon.d.ts +5 -13
  35. package/abstract/poseidon.d.ts.map +1 -1
  36. package/abstract/poseidon.js +12 -7
  37. package/abstract/poseidon.js.map +1 -1
  38. package/abstract/tower.d.ts +20 -46
  39. package/abstract/tower.d.ts.map +1 -1
  40. package/abstract/tower.js +10 -4
  41. package/abstract/tower.js.map +1 -1
  42. package/abstract/utils.d.ts +1 -115
  43. package/abstract/utils.d.ts.map +1 -1
  44. package/abstract/utils.js +17 -371
  45. package/abstract/utils.js.map +1 -1
  46. package/abstract/weierstrass.d.ts +152 -73
  47. package/abstract/weierstrass.d.ts.map +1 -1
  48. package/abstract/weierstrass.js +487 -404
  49. package/abstract/weierstrass.js.map +1 -1
  50. package/bls12-381.d.ts +2 -0
  51. package/bls12-381.d.ts.map +1 -1
  52. package/bls12-381.js +504 -480
  53. package/bls12-381.js.map +1 -1
  54. package/bn254.d.ts +2 -0
  55. package/bn254.d.ts.map +1 -1
  56. package/bn254.js +44 -32
  57. package/bn254.js.map +1 -1
  58. package/ed25519.d.ts +25 -9
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +89 -65
  61. package/ed25519.js.map +1 -1
  62. package/ed448.d.ts +29 -10
  63. package/ed448.d.ts.map +1 -1
  64. package/ed448.js +116 -81
  65. package/ed448.js.map +1 -1
  66. package/esm/_shortw_utils.d.ts +7 -5
  67. package/esm/_shortw_utils.d.ts.map +1 -1
  68. package/esm/_shortw_utils.js +2 -8
  69. package/esm/_shortw_utils.js.map +1 -1
  70. package/esm/abstract/bls.d.ts +60 -24
  71. package/esm/abstract/bls.d.ts.map +1 -1
  72. package/esm/abstract/bls.js +158 -109
  73. package/esm/abstract/bls.js.map +1 -1
  74. package/esm/abstract/curve.d.ts +44 -9
  75. package/esm/abstract/curve.d.ts.map +1 -1
  76. package/esm/abstract/curve.js +96 -12
  77. package/esm/abstract/curve.js.map +1 -1
  78. package/esm/abstract/edwards.d.ts +112 -25
  79. package/esm/abstract/edwards.d.ts.map +1 -1
  80. package/esm/abstract/edwards.js +141 -94
  81. package/esm/abstract/edwards.js.map +1 -1
  82. package/esm/abstract/fft.d.ts +122 -0
  83. package/esm/abstract/fft.d.ts.map +1 -0
  84. package/esm/abstract/fft.js +425 -0
  85. package/esm/abstract/fft.js.map +1 -0
  86. package/esm/abstract/hash-to-curve.d.ts +25 -11
  87. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  88. package/esm/abstract/hash-to-curve.js +17 -14
  89. package/esm/abstract/hash-to-curve.js.map +1 -1
  90. package/esm/abstract/modular.d.ts +28 -17
  91. package/esm/abstract/modular.d.ts.map +1 -1
  92. package/esm/abstract/modular.js +155 -138
  93. package/esm/abstract/modular.js.map +1 -1
  94. package/esm/abstract/montgomery.d.ts +3 -8
  95. package/esm/abstract/montgomery.d.ts.map +1 -1
  96. package/esm/abstract/montgomery.js +74 -94
  97. package/esm/abstract/montgomery.js.map +1 -1
  98. package/esm/abstract/poseidon.d.ts +5 -13
  99. package/esm/abstract/poseidon.d.ts.map +1 -1
  100. package/esm/abstract/poseidon.js +12 -7
  101. package/esm/abstract/poseidon.js.map +1 -1
  102. package/esm/abstract/tower.d.ts +20 -46
  103. package/esm/abstract/tower.d.ts.map +1 -1
  104. package/esm/abstract/tower.js +10 -4
  105. package/esm/abstract/tower.js.map +1 -1
  106. package/esm/abstract/utils.d.ts +1 -115
  107. package/esm/abstract/utils.d.ts.map +1 -1
  108. package/esm/abstract/utils.js +3 -344
  109. package/esm/abstract/utils.js.map +1 -1
  110. package/esm/abstract/weierstrass.d.ts +152 -73
  111. package/esm/abstract/weierstrass.d.ts.map +1 -1
  112. package/esm/abstract/weierstrass.js +485 -406
  113. package/esm/abstract/weierstrass.js.map +1 -1
  114. package/esm/bls12-381.d.ts +2 -0
  115. package/esm/bls12-381.d.ts.map +1 -1
  116. package/esm/bls12-381.js +503 -479
  117. package/esm/bls12-381.js.map +1 -1
  118. package/esm/bn254.d.ts +2 -0
  119. package/esm/bn254.d.ts.map +1 -1
  120. package/esm/bn254.js +41 -29
  121. package/esm/bn254.js.map +1 -1
  122. package/esm/ed25519.d.ts +25 -9
  123. package/esm/ed25519.d.ts.map +1 -1
  124. package/esm/ed25519.js +84 -60
  125. package/esm/ed25519.js.map +1 -1
  126. package/esm/ed448.d.ts +29 -10
  127. package/esm/ed448.d.ts.map +1 -1
  128. package/esm/ed448.js +113 -78
  129. package/esm/ed448.js.map +1 -1
  130. package/esm/jubjub.d.ts +4 -0
  131. package/esm/jubjub.d.ts.map +1 -1
  132. package/esm/jubjub.js +4 -0
  133. package/esm/jubjub.js.map +1 -1
  134. package/esm/misc.d.ts.map +1 -1
  135. package/esm/misc.js +31 -26
  136. package/esm/misc.js.map +1 -1
  137. package/esm/nist.d.ts +8 -16
  138. package/esm/nist.d.ts.map +1 -1
  139. package/esm/nist.js +87 -97
  140. package/esm/nist.js.map +1 -1
  141. package/esm/p256.d.ts +3 -3
  142. package/esm/p384.d.ts +3 -3
  143. package/esm/p521.d.ts +3 -3
  144. package/esm/pasta.d.ts +4 -0
  145. package/esm/pasta.d.ts.map +1 -1
  146. package/esm/pasta.js +4 -0
  147. package/esm/pasta.js.map +1 -1
  148. package/esm/secp256k1.d.ts +6 -6
  149. package/esm/secp256k1.d.ts.map +1 -1
  150. package/esm/secp256k1.js +44 -41
  151. package/esm/secp256k1.js.map +1 -1
  152. package/esm/utils.d.ts +96 -0
  153. package/esm/utils.d.ts.map +1 -0
  154. package/esm/utils.js +279 -0
  155. package/esm/utils.js.map +1 -0
  156. package/jubjub.d.ts +4 -0
  157. package/jubjub.d.ts.map +1 -1
  158. package/jubjub.js +4 -0
  159. package/jubjub.js.map +1 -1
  160. package/misc.d.ts.map +1 -1
  161. package/misc.js +35 -30
  162. package/misc.js.map +1 -1
  163. package/nist.d.ts +8 -16
  164. package/nist.d.ts.map +1 -1
  165. package/nist.js +87 -97
  166. package/nist.js.map +1 -1
  167. package/p256.d.ts +3 -3
  168. package/p384.d.ts +3 -3
  169. package/p521.d.ts +3 -3
  170. package/package.json +26 -8
  171. package/pasta.d.ts +4 -0
  172. package/pasta.d.ts.map +1 -1
  173. package/pasta.js +4 -0
  174. package/pasta.js.map +1 -1
  175. package/secp256k1.d.ts +6 -6
  176. package/secp256k1.d.ts.map +1 -1
  177. package/secp256k1.js +47 -44
  178. package/secp256k1.js.map +1 -1
  179. package/src/_shortw_utils.ts +5 -15
  180. package/src/abstract/bls.ts +260 -145
  181. package/src/abstract/curve.ts +125 -18
  182. package/src/abstract/edwards.ts +282 -127
  183. package/src/abstract/fft.ts +519 -0
  184. package/src/abstract/hash-to-curve.ts +51 -27
  185. package/src/abstract/modular.ts +156 -143
  186. package/src/abstract/montgomery.ts +81 -111
  187. package/src/abstract/poseidon.ts +22 -18
  188. package/src/abstract/tower.ts +37 -68
  189. package/src/abstract/utils.ts +3 -378
  190. package/src/abstract/weierstrass.ts +752 -461
  191. package/src/bls12-381.ts +542 -507
  192. package/src/bn254.ts +47 -35
  193. package/src/ed25519.ts +104 -76
  194. package/src/ed448.ts +156 -105
  195. package/src/jubjub.ts +4 -0
  196. package/src/misc.ts +39 -34
  197. package/src/nist.ts +138 -126
  198. package/src/p256.ts +3 -3
  199. package/src/p384.ts +3 -3
  200. package/src/p521.ts +3 -3
  201. package/src/pasta.ts +5 -1
  202. package/src/secp256k1.ts +59 -47
  203. package/src/utils.ts +328 -0
  204. package/utils.d.ts +96 -0
  205. package/utils.d.ts.map +1 -0
  206. package/utils.js +313 -0
  207. package/utils.js.map +1 -0
@@ -1,26 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DER = exports.DERErr = void 0;
4
+ exports._legacyHelperEquat = _legacyHelperEquat;
5
+ exports._legacyHelperNormPriv = _legacyHelperNormPriv;
6
+ exports.weierstrassN = weierstrassN;
4
7
  exports.weierstrassPoints = weierstrassPoints;
8
+ exports.ecdsa = ecdsa;
5
9
  exports.weierstrass = weierstrass;
6
10
  exports.SWUFpSqrtRatio = SWUFpSqrtRatio;
7
11
  exports.mapToCurveSimpleSWU = mapToCurveSimpleSWU;
8
12
  /**
9
13
  * Short Weierstrass curve methods. The formula is: y² = x³ + ax + b.
10
14
  *
11
- * ### Parameters
12
- *
13
- * To initialize a weierstrass curve, one needs to pass following params:
14
- *
15
- * * a: formula param
16
- * * b: formula param
17
- * * Fp: finite Field over which we'll do calculations. Can be complex (Fp2, Fp12)
18
- * * n: Curve prime subgroup order, total count of valid points in the field
19
- * * Gx: Base point (x, y) aka generator point x coordinate
20
- * * Gy: ...y coordinate
21
- * * h: cofactor, usually 1. h*n = curve group order (n is only subgroup order)
22
- * * lowS: whether to enable (default) or disable "low-s" non-malleable signatures
23
- *
24
15
  * ### Design rationale for types
25
16
  *
26
17
  * * Interaction between classes from different curves should fail:
@@ -45,45 +36,16 @@ exports.mapToCurveSimpleSWU = mapToCurveSimpleSWU;
45
36
  * @module
46
37
  */
47
38
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
48
- // prettier-ignore
39
+ const hmac_js_1 = require("@noble/hashes/hmac.js");
40
+ const utils_ts_1 = require("../utils.js");
49
41
  const curve_ts_1 = require("./curve.js");
50
- // prettier-ignore
51
42
  const modular_ts_1 = require("./modular.js");
52
- // prettier-ignore
53
- const utils_ts_1 = require("./utils.js");
54
43
  function validateSigVerOpts(opts) {
55
44
  if (opts.lowS !== undefined)
56
45
  (0, utils_ts_1.abool)('lowS', opts.lowS);
57
46
  if (opts.prehash !== undefined)
58
47
  (0, utils_ts_1.abool)('prehash', opts.prehash);
59
48
  }
60
- function validatePointOpts(curve) {
61
- const opts = (0, curve_ts_1.validateBasic)(curve);
62
- (0, utils_ts_1.validateObject)(opts, {
63
- a: 'field',
64
- b: 'field',
65
- }, {
66
- allowedPrivateKeyLengths: 'array',
67
- wrapPrivateKey: 'boolean',
68
- isTorsionFree: 'function',
69
- clearCofactor: 'function',
70
- allowInfinityPoint: 'boolean',
71
- fromBytes: 'function',
72
- toBytes: 'function',
73
- });
74
- const { endo, Fp, a } = opts;
75
- if (endo) {
76
- if (!Fp.eql(a, Fp.ZERO)) {
77
- throw new Error('invalid endomorphism, can only be defined for Koblitz curves that have a=0');
78
- }
79
- if (typeof endo !== 'object' ||
80
- typeof endo.beta !== 'bigint' ||
81
- typeof endo.splitScalar !== 'function') {
82
- throw new Error('invalid endomorphism, expected beta: bigint and splitScalar: function');
83
- }
84
- }
85
- return Object.freeze({ ...opts });
86
- }
87
49
  class DERErr extends Error {
88
50
  constructor(m = '') {
89
51
  super(m);
@@ -204,71 +166,157 @@ exports.DER = {
204
166
  // Be friendly to bad ECMAScript parsers by not using bigint literals
205
167
  // prettier-ignore
206
168
  const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
207
- function weierstrassPoints(opts) {
208
- const CURVE = validatePointOpts(opts);
209
- const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
210
- const Fn = (0, modular_ts_1.Field)(CURVE.n, CURVE.nBitLength);
211
- const toBytes = CURVE.toBytes ||
212
- ((_c, point, _isCompressed) => {
213
- const a = point.toAffine();
214
- return (0, utils_ts_1.concatBytes)(Uint8Array.from([0x04]), Fp.toBytes(a.x), Fp.toBytes(a.y));
215
- });
216
- const fromBytes = CURVE.fromBytes ||
217
- ((bytes) => {
218
- // const head = bytes[0];
219
- const tail = bytes.subarray(1);
220
- // if (head !== 0x04) throw new Error('Only non-compressed encoding is supported');
221
- const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
222
- const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
223
- return { x, y };
224
- });
169
+ // TODO: remove
170
+ function _legacyHelperEquat(Fp, a, b) {
225
171
  /**
226
172
  * y² = x³ + ax + b: Short weierstrass curve formula. Takes x, returns y².
227
173
  * @returns y²
228
174
  */
229
175
  function weierstrassEquation(x) {
230
- const { a, b } = CURVE;
231
176
  const x2 = Fp.sqr(x); // x * x
232
- const x3 = Fp.mul(x2, x); // x2 * x
233
- return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b
234
- }
235
- // Validate whether the passed curve params are valid.
236
- // We check if curve equation works for generator point.
237
- // `assertValidity()` won't work: `isTorsionFree()` is not available at this point in bls12-381.
238
- // ProjectivePoint class has not been initialized yet.
239
- if (!Fp.eql(Fp.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx)))
240
- throw new Error('bad generator point: equation left != right');
241
- // Valid group elements reside in range 1..n-1
242
- function isWithinCurveOrder(num) {
243
- return (0, utils_ts_1.inRange)(num, _1n, CURVE.n);
177
+ const x3 = Fp.mul(x2, x); // * x
178
+ return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // + a * x + b
244
179
  }
180
+ return weierstrassEquation;
181
+ }
182
+ function _legacyHelperNormPriv(Fn, allowedPrivateKeyLengths, wrapPrivateKey) {
183
+ const { BYTES: expected } = Fn;
245
184
  // Validates if priv key is valid and converts it to bigint.
246
- // Supports options allowedPrivateKeyLengths and wrapPrivateKey.
247
185
  function normPrivateKeyToScalar(key) {
248
- const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n: N } = CURVE;
249
- if (lengths && typeof key !== 'bigint') {
250
- if ((0, utils_ts_1.isBytes)(key))
251
- key = (0, utils_ts_1.bytesToHex)(key);
252
- // Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
253
- if (typeof key !== 'string' || !lengths.includes(key.length))
254
- throw new Error('invalid private key');
255
- key = key.padStart(nByteLength * 2, '0');
256
- }
257
186
  let num;
258
- try {
259
- num =
260
- typeof key === 'bigint'
261
- ? key
262
- : (0, utils_ts_1.bytesToNumberBE)((0, utils_ts_1.ensureBytes)('private key', key, nByteLength));
187
+ if (typeof key === 'bigint') {
188
+ num = key;
263
189
  }
264
- catch (error) {
265
- throw new Error('invalid private key, expected hex or ' + nByteLength + ' bytes, got ' + typeof key);
190
+ else {
191
+ let bytes = (0, utils_ts_1.ensureBytes)('private key', key);
192
+ if (allowedPrivateKeyLengths) {
193
+ if (!allowedPrivateKeyLengths.includes(bytes.length * 2))
194
+ throw new Error('invalid private key');
195
+ const padded = new Uint8Array(expected);
196
+ padded.set(bytes, padded.length - bytes.length);
197
+ bytes = padded;
198
+ }
199
+ try {
200
+ num = Fn.fromBytes(bytes);
201
+ }
202
+ catch (error) {
203
+ throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
204
+ }
266
205
  }
267
206
  if (wrapPrivateKey)
268
- num = (0, modular_ts_1.mod)(num, N); // disabled by default, enabled for BLS
269
- (0, utils_ts_1.aInRange)('private key', num, _1n, N); // num in range [1..N-1]
207
+ num = Fn.create(num); // disabled by default, enabled for BLS
208
+ if (!Fn.isValidNot0(num))
209
+ throw new Error('invalid private key: out of range [1..N-1]');
270
210
  return num;
271
211
  }
212
+ return normPrivateKeyToScalar;
213
+ }
214
+ function weierstrassN(CURVE, curveOpts = {}) {
215
+ const { Fp, Fn } = (0, curve_ts_1._createCurveFields)('weierstrass', CURVE, curveOpts);
216
+ const { h: cofactor, n: CURVE_ORDER } = CURVE;
217
+ (0, utils_ts_1._validateObject)(curveOpts, {}, {
218
+ allowInfinityPoint: 'boolean',
219
+ clearCofactor: 'function',
220
+ isTorsionFree: 'function',
221
+ fromBytes: 'function',
222
+ toBytes: 'function',
223
+ endo: 'object',
224
+ wrapPrivateKey: 'boolean',
225
+ });
226
+ const { endo } = curveOpts;
227
+ if (endo) {
228
+ // validateObject(endo, { beta: 'bigint', splitScalar: 'function' });
229
+ if (!Fp.is0(CURVE.a) ||
230
+ typeof endo.beta !== 'bigint' ||
231
+ typeof endo.splitScalar !== 'function') {
232
+ throw new Error('invalid endo: expected "beta": bigint and "splitScalar": function');
233
+ }
234
+ }
235
+ function assertCompressionIsSupported() {
236
+ if (!Fp.isOdd)
237
+ throw new Error('compression is not supported: Field does not have .isOdd()');
238
+ }
239
+ // Implements IEEE P1363 point encoding
240
+ function pointToBytes(_c, point, isCompressed) {
241
+ const { x, y } = point.toAffine();
242
+ const bx = Fp.toBytes(x);
243
+ (0, utils_ts_1.abool)('isCompressed', isCompressed);
244
+ if (isCompressed) {
245
+ assertCompressionIsSupported();
246
+ const hasEvenY = !Fp.isOdd(y);
247
+ return (0, utils_ts_1.concatBytes)(pprefix(hasEvenY), bx);
248
+ }
249
+ else {
250
+ return (0, utils_ts_1.concatBytes)(Uint8Array.of(0x04), bx, Fp.toBytes(y));
251
+ }
252
+ }
253
+ function pointFromBytes(bytes) {
254
+ (0, utils_ts_1.abytes)(bytes);
255
+ const L = Fp.BYTES;
256
+ const LC = L + 1; // length compressed, e.g. 33 for 32-byte field
257
+ const LU = 2 * L + 1; // length uncompressed, e.g. 65 for 32-byte field
258
+ const length = bytes.length;
259
+ const head = bytes[0];
260
+ const tail = bytes.subarray(1);
261
+ // No actual validation is done here: use .assertValidity()
262
+ if (length === LC && (head === 0x02 || head === 0x03)) {
263
+ const x = Fp.fromBytes(tail);
264
+ if (!Fp.isValid(x))
265
+ throw new Error('bad point: is not on curve, wrong x');
266
+ const y2 = weierstrassEquation(x); // y² = x³ + ax + b
267
+ let y;
268
+ try {
269
+ y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
270
+ }
271
+ catch (sqrtError) {
272
+ const err = sqrtError instanceof Error ? ': ' + sqrtError.message : '';
273
+ throw new Error('bad point: is not on curve, sqrt error' + err);
274
+ }
275
+ assertCompressionIsSupported();
276
+ const isYOdd = Fp.isOdd(y); // (y & _1n) === _1n;
277
+ const isHeadOdd = (head & 1) === 1; // ECDSA-specific
278
+ if (isHeadOdd !== isYOdd)
279
+ y = Fp.neg(y);
280
+ return { x, y };
281
+ }
282
+ else if (length === LU && head === 0x04) {
283
+ // TODO: more checks
284
+ const x = Fp.fromBytes(tail.subarray(L * 0, L * 1));
285
+ const y = Fp.fromBytes(tail.subarray(L * 1, L * 2));
286
+ if (!isValidXY(x, y))
287
+ throw new Error('bad point: is not on curve');
288
+ return { x, y };
289
+ }
290
+ else {
291
+ throw new Error(`bad point: got length ${length}, expected compressed=${LC} or uncompressed=${LU}`);
292
+ }
293
+ }
294
+ const toBytes = curveOpts.toBytes || pointToBytes;
295
+ const fromBytes = curveOpts.fromBytes || pointFromBytes;
296
+ const weierstrassEquation = _legacyHelperEquat(Fp, CURVE.a, CURVE.b);
297
+ // TODO: move top-level
298
+ /** Checks whether equation holds for given x, y: y² == x³ + ax + b */
299
+ function isValidXY(x, y) {
300
+ const left = Fp.sqr(y); // y²
301
+ const right = weierstrassEquation(x); // x³ + ax + b
302
+ return Fp.eql(left, right);
303
+ }
304
+ // Validate whether the passed curve params are valid.
305
+ // Test 1: equation y² = x³ + ax + b should work for generator point.
306
+ if (!isValidXY(CURVE.Gx, CURVE.Gy))
307
+ throw new Error('bad curve params: generator point');
308
+ // Test 2: discriminant Δ part should be non-zero: 4a³ + 27b² != 0.
309
+ // Guarantees curve is genus-1, smooth (non-singular).
310
+ const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n), _4n);
311
+ const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27));
312
+ if (Fp.is0(Fp.add(_4a3, _27b2)))
313
+ throw new Error('bad curve params: a or b');
314
+ /** Asserts coordinate is valid: 0 <= n < Fp.ORDER. */
315
+ function acoord(title, n, banZero = false) {
316
+ if (!Fp.isValid(n) || (banZero && Fp.is0(n)))
317
+ throw new Error(`bad point coordinate ${title}`);
318
+ return n;
319
+ }
272
320
  function aprjpoint(other) {
273
321
  if (!(other instanceof Point))
274
322
  throw new Error('ProjectivePoint expected');
@@ -276,7 +324,7 @@ function weierstrassPoints(opts) {
276
324
  // Memoized toAffine / validity check. They are heavy. Points are immutable.
277
325
  // Converts Projective point to affine (x, y) coordinates.
278
326
  // Can accept precomputed Z^-1 - for example, from invertBatch.
279
- // (x, y, z) ∋ (x=x/z, y=y/z)
327
+ // (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
280
328
  const toAffineMemo = (0, utils_ts_1.memoized)((p, iz) => {
281
329
  const { px: x, py: y, pz: z } = p;
282
330
  // Fast-path for normalized points
@@ -303,52 +351,48 @@ function weierstrassPoints(opts) {
303
351
  // (0, 1, 0) aka ZERO is invalid in most contexts.
304
352
  // In BLS, ZERO can be serialized, so we allow it.
305
353
  // (0, 0, 0) is invalid representation of ZERO.
306
- if (CURVE.allowInfinityPoint && !Fp.is0(p.py))
354
+ if (curveOpts.allowInfinityPoint && !Fp.is0(p.py))
307
355
  return;
308
356
  throw new Error('bad point: ZERO');
309
357
  }
310
358
  // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
311
359
  const { x, y } = p.toAffine();
312
- // Check if x, y are valid field elements
313
360
  if (!Fp.isValid(x) || !Fp.isValid(y))
314
- throw new Error('bad point: x or y not FE');
315
- const left = Fp.sqr(y); // y²
316
- const right = weierstrassEquation(x); // x³ + ax + b
317
- if (!Fp.eql(left, right))
361
+ throw new Error('bad point: x or y not field elements');
362
+ if (!isValidXY(x, y))
318
363
  throw new Error('bad point: equation left != right');
319
364
  if (!p.isTorsionFree())
320
365
  throw new Error('bad point: not in prime-order subgroup');
321
366
  return true;
322
367
  });
368
+ function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
369
+ k2p = new Point(Fp.mul(k2p.px, endoBeta), k2p.py, k2p.pz);
370
+ k1p = (0, curve_ts_1.negateCt)(k1neg, k1p);
371
+ k2p = (0, curve_ts_1.negateCt)(k2neg, k2p);
372
+ return k1p.add(k2p);
373
+ }
323
374
  /**
324
- * Projective Point works in 3d / projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
325
- * Default Point works in 2d / affine coordinates: (x, y)
375
+ * Projective Point works in 3d / projective (homogeneous) coordinates:(X, Y, Z) ∋ (x=X/Z, y=Y/Z).
376
+ * Default Point works in 2d / affine coordinates: (x, y).
326
377
  * We're doing calculations in projective, because its operations don't require costly inversion.
327
378
  */
328
379
  class Point {
380
+ /** Does NOT validate if the point is valid. Use `.assertValidity()`. */
329
381
  constructor(px, py, pz) {
330
- if (px == null || !Fp.isValid(px))
331
- throw new Error('x required');
332
- if (py == null || !Fp.isValid(py) || Fp.is0(py))
333
- throw new Error('y required');
334
- if (pz == null || !Fp.isValid(pz))
335
- throw new Error('z required');
336
- this.px = px;
337
- this.py = py;
338
- this.pz = pz;
382
+ this.px = acoord('x', px);
383
+ this.py = acoord('y', py, true);
384
+ this.pz = acoord('z', pz);
339
385
  Object.freeze(this);
340
386
  }
341
- // Does not validate if the point is on-curve.
342
- // Use fromHex instead, or call assertValidity() later.
387
+ /** Does NOT validate if the point is valid. Use `.assertValidity()`. */
343
388
  static fromAffine(p) {
344
389
  const { x, y } = p || {};
345
390
  if (!p || !Fp.isValid(x) || !Fp.isValid(y))
346
391
  throw new Error('invalid affine point');
347
392
  if (p instanceof Point)
348
393
  throw new Error('projective point not allowed');
349
- const is0 = (i) => Fp.eql(i, Fp.ZERO);
350
- // fromAffine(x:0, y:0) would produce (x:0, y:0, z:1), but we need (x:0, y:1, z:0)
351
- if (is0(x) && is0(y))
394
+ // (0, 0) would've produced (0, 0, 1) - instead, we need (0, 1, 0)
395
+ if (Fp.is0(x) && Fp.is0(y))
352
396
  return Point.ZERO;
353
397
  return new Point(x, y, Fp.ONE);
354
398
  }
@@ -358,50 +402,56 @@ function weierstrassPoints(opts) {
358
402
  get y() {
359
403
  return this.toAffine().y;
360
404
  }
361
- /**
362
- * Takes a bunch of Projective Points but executes only one
363
- * inversion on all of them. Inversion is very slow operation,
364
- * so this improves performance massively.
365
- * Optimization: converts a list of projective points to a list of identical points with Z=1.
366
- */
367
405
  static normalizeZ(points) {
368
- const toInv = (0, modular_ts_1.FpInvertBatch)(Fp, points.map((p) => p.pz));
369
- return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
406
+ return (0, curve_ts_1.normalizeZ)(Point, 'pz', points);
370
407
  }
371
- /**
372
- * Converts hash string or Uint8Array to Point.
373
- * @param hex short/long ECDSA hex
374
- */
408
+ static fromBytes(bytes) {
409
+ (0, utils_ts_1.abytes)(bytes);
410
+ return Point.fromHex(bytes);
411
+ }
412
+ /** Converts hash string or Uint8Array to Point. */
375
413
  static fromHex(hex) {
376
414
  const P = Point.fromAffine(fromBytes((0, utils_ts_1.ensureBytes)('pointHex', hex)));
377
415
  P.assertValidity();
378
416
  return P;
379
417
  }
380
- // Multiplies generator point by privateKey.
418
+ /** Multiplies generator point by privateKey. */
381
419
  static fromPrivateKey(privateKey) {
420
+ const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey);
382
421
  return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
383
422
  }
384
- // Multiscalar Multiplication
423
+ /** Multiscalar Multiplication */
385
424
  static msm(points, scalars) {
386
425
  return (0, curve_ts_1.pippenger)(Point, Fn, points, scalars);
387
426
  }
388
- // "Private method", don't use it directly
389
- _setWindowSize(windowSize) {
427
+ /**
428
+ *
429
+ * @param windowSize
430
+ * @param isLazy true will defer table computation until the first multiplication
431
+ * @returns
432
+ */
433
+ precompute(windowSize = 8, isLazy = true) {
390
434
  wnaf.setWindowSize(this, windowSize);
435
+ if (!isLazy)
436
+ this.multiply(_3n); // random number
437
+ return this;
391
438
  }
392
- // A point on curve is valid if it conforms to equation.
439
+ /** "Private method", don't use it directly */
440
+ _setWindowSize(windowSize) {
441
+ this.precompute(windowSize);
442
+ }
443
+ // TODO: return `this`
444
+ /** A point on curve is valid if it conforms to equation. */
393
445
  assertValidity() {
394
446
  assertValidMemo(this);
395
447
  }
396
448
  hasEvenY() {
397
449
  const { y } = this.toAffine();
398
- if (Fp.isOdd)
399
- return !Fp.isOdd(y);
400
- throw new Error("Field doesn't support isOdd");
450
+ if (!Fp.isOdd)
451
+ throw new Error("Field doesn't support isOdd");
452
+ return !Fp.isOdd(y);
401
453
  }
402
- /**
403
- * Compare one point to another.
404
- */
454
+ /** Compare one point to another. */
405
455
  equals(other) {
406
456
  aprjpoint(other);
407
457
  const { px: X1, py: Y1, pz: Z1 } = this;
@@ -410,9 +460,7 @@ function weierstrassPoints(opts) {
410
460
  const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
411
461
  return U1 && U2;
412
462
  }
413
- /**
414
- * Flips point to one corresponding to (x, -y) in Affine coordinates.
415
- */
463
+ /** Flips point to one corresponding to (x, -y) in Affine coordinates. */
416
464
  negate() {
417
465
  return new Point(this.px, Fp.neg(this.py), this.pz);
418
466
  }
@@ -517,46 +565,6 @@ function weierstrassPoints(opts) {
517
565
  is0() {
518
566
  return this.equals(Point.ZERO);
519
567
  }
520
- wNAF(n) {
521
- return wnaf.wNAFCached(this, n, Point.normalizeZ);
522
- }
523
- /**
524
- * Non-constant-time multiplication. Uses double-and-add algorithm.
525
- * It's faster, but should only be used when you don't care about
526
- * an exposed private key e.g. sig verification, which works over *public* keys.
527
- */
528
- multiplyUnsafe(sc) {
529
- const { endo, n: N } = CURVE;
530
- (0, utils_ts_1.aInRange)('scalar', sc, _0n, N);
531
- const I = Point.ZERO;
532
- if (sc === _0n)
533
- return I;
534
- if (this.is0() || sc === _1n)
535
- return this;
536
- // Case a: no endomorphism. Case b: has precomputes.
537
- if (!endo || wnaf.hasPrecomputes(this))
538
- return wnaf.wNAFCachedUnsafe(this, sc, Point.normalizeZ);
539
- // Case c: endomorphism
540
- let { k1neg, k1, k2neg, k2 } = endo.splitScalar(sc);
541
- let k1p = I;
542
- let k2p = I;
543
- let d = this;
544
- while (k1 > _0n || k2 > _0n) {
545
- if (k1 & _1n)
546
- k1p = k1p.add(d);
547
- if (k2 & _1n)
548
- k2p = k2p.add(d);
549
- d = d.double();
550
- k1 >>= _1n;
551
- k2 >>= _1n;
552
- }
553
- if (k1neg)
554
- k1p = k1p.negate();
555
- if (k2neg)
556
- k2p = k2p.negate();
557
- k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
558
- return k1p.add(k2p);
559
- }
560
568
  /**
561
569
  * Constant time multiplication.
562
570
  * Uses wNAF method. Windowed method may be 10% faster,
@@ -567,21 +575,21 @@ function weierstrassPoints(opts) {
567
575
  * @returns New point
568
576
  */
569
577
  multiply(scalar) {
570
- const { endo, n: N } = CURVE;
571
- (0, utils_ts_1.aInRange)('scalar', scalar, _1n, N);
578
+ const { endo } = curveOpts;
579
+ if (!Fn.isValidNot0(scalar))
580
+ throw new Error('invalid scalar: out of range'); // 0 is invalid
572
581
  let point, fake; // Fake point is used to const-time mult
582
+ const mul = (n) => wnaf.wNAFCached(this, n, Point.normalizeZ);
583
+ /** See docs for {@link EndomorphismOpts} */
573
584
  if (endo) {
574
585
  const { k1neg, k1, k2neg, k2 } = endo.splitScalar(scalar);
575
- let { p: k1p, f: f1p } = this.wNAF(k1);
576
- let { p: k2p, f: f2p } = this.wNAF(k2);
577
- k1p = wnaf.constTimeNegate(k1neg, k1p);
578
- k2p = wnaf.constTimeNegate(k2neg, k2p);
579
- k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
580
- point = k1p.add(k2p);
581
- fake = f1p.add(f2p);
586
+ const { p: k1p, f: k1f } = mul(k1);
587
+ const { p: k2p, f: k2f } = mul(k2);
588
+ fake = k1f.add(k2f);
589
+ point = finishEndo(endo.beta, k1p, k2p, k1neg, k2neg);
582
590
  }
583
591
  else {
584
- const { p, f } = this.wNAF(scalar);
592
+ const { p, f } = mul(scalar);
585
593
  point = p;
586
594
  fake = f;
587
595
  }
@@ -589,161 +597,131 @@ function weierstrassPoints(opts) {
589
597
  return Point.normalizeZ([point, fake])[0];
590
598
  }
591
599
  /**
592
- * Efficiently calculate `aP + bQ`. Unsafe, can expose private key, if used incorrectly.
593
- * Not using Strauss-Shamir trick: precomputation tables are faster.
594
- * The trick could be useful if both P and Q are not G (not in our case).
595
- * @returns non-zero affine point
600
+ * Non-constant-time multiplication. Uses double-and-add algorithm.
601
+ * It's faster, but should only be used when you don't care about
602
+ * an exposed private key e.g. sig verification, which works over *public* keys.
596
603
  */
604
+ multiplyUnsafe(sc) {
605
+ const { endo } = curveOpts;
606
+ const p = this;
607
+ if (!Fn.isValid(sc))
608
+ throw new Error('invalid scalar: out of range'); // 0 is valid
609
+ if (sc === _0n || p.is0())
610
+ return Point.ZERO;
611
+ if (sc === _1n)
612
+ return p; // fast-path
613
+ if (wnaf.hasPrecomputes(this))
614
+ return this.multiply(sc);
615
+ if (endo) {
616
+ const { k1neg, k1, k2neg, k2 } = endo.splitScalar(sc);
617
+ // `wNAFCachedUnsafe` is 30% slower
618
+ const { p1, p2 } = (0, curve_ts_1.mulEndoUnsafe)(Point, p, k1, k2);
619
+ return finishEndo(endo.beta, p1, p2, k1neg, k2neg);
620
+ }
621
+ else {
622
+ return wnaf.wNAFCachedUnsafe(p, sc);
623
+ }
624
+ }
597
625
  multiplyAndAddUnsafe(Q, a, b) {
598
- const G = Point.BASE; // No Strauss-Shamir trick: we have 10% faster G precomputes
599
- const mul = (P, a // Select faster multiply() method
600
- ) => (a === _0n || a === _1n || !P.equals(G) ? P.multiplyUnsafe(a) : P.multiply(a));
601
- const sum = mul(this, a).add(mul(Q, b));
626
+ const sum = this.multiplyUnsafe(a).add(Q.multiplyUnsafe(b));
602
627
  return sum.is0() ? undefined : sum;
603
628
  }
604
- // Converts Projective point to affine (x, y) coordinates.
605
- // Can accept precomputed Z^-1 - for example, from invertBatch.
606
- // (x, y, z) (x=x/z, y=y/z)
607
- toAffine(iz) {
608
- return toAffineMemo(this, iz);
629
+ /**
630
+ * Converts Projective point to affine (x, y) coordinates.
631
+ * @param invertedZ Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch
632
+ */
633
+ toAffine(invertedZ) {
634
+ return toAffineMemo(this, invertedZ);
609
635
  }
636
+ /**
637
+ * Checks whether Point is free of torsion elements (is in prime subgroup).
638
+ * Always torsion-free for cofactor=1 curves.
639
+ */
610
640
  isTorsionFree() {
611
- const { h: cofactor, isTorsionFree } = CURVE;
641
+ const { isTorsionFree } = curveOpts;
612
642
  if (cofactor === _1n)
613
- return true; // No subgroups, always torsion-free
643
+ return true;
614
644
  if (isTorsionFree)
615
645
  return isTorsionFree(Point, this);
616
- throw new Error('isTorsionFree() has not been declared for the elliptic curve');
646
+ return wnaf.wNAFCachedUnsafe(this, CURVE_ORDER).is0();
617
647
  }
618
648
  clearCofactor() {
619
- const { h: cofactor, clearCofactor } = CURVE;
649
+ const { clearCofactor } = curveOpts;
620
650
  if (cofactor === _1n)
621
651
  return this; // Fast-path
622
652
  if (clearCofactor)
623
653
  return clearCofactor(Point, this);
624
- return this.multiplyUnsafe(CURVE.h);
654
+ return this.multiplyUnsafe(cofactor);
625
655
  }
626
- toRawBytes(isCompressed = true) {
656
+ toBytes(isCompressed = true) {
627
657
  (0, utils_ts_1.abool)('isCompressed', isCompressed);
628
658
  this.assertValidity();
629
659
  return toBytes(Point, this, isCompressed);
630
660
  }
661
+ /** @deprecated use `toBytes` */
662
+ toRawBytes(isCompressed = true) {
663
+ return this.toBytes(isCompressed);
664
+ }
631
665
  toHex(isCompressed = true) {
632
- (0, utils_ts_1.abool)('isCompressed', isCompressed);
633
- return (0, utils_ts_1.bytesToHex)(this.toRawBytes(isCompressed));
666
+ return (0, utils_ts_1.bytesToHex)(this.toBytes(isCompressed));
667
+ }
668
+ toString() {
669
+ return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
634
670
  }
635
671
  }
672
+ // base / generator point
636
673
  Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
674
+ // zero / infinity / identity point
637
675
  Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); // 0, 1, 0
638
- const _bits = CURVE.nBitLength;
639
- const wnaf = (0, curve_ts_1.wNAF)(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
640
- return {
641
- CURVE,
642
- ProjectivePoint: Point,
643
- normPrivateKeyToScalar,
644
- weierstrassEquation,
645
- isWithinCurveOrder,
646
- };
676
+ // fields
677
+ Point.Fp = Fp;
678
+ Point.Fn = Fn;
679
+ const bits = Fn.BITS;
680
+ const wnaf = (0, curve_ts_1.wNAF)(Point, curveOpts.endo ? Math.ceil(bits / 2) : bits);
681
+ return Point;
682
+ }
683
+ // _legacyWeierstrass
684
+ /** @deprecated use `weierstrassN` */
685
+ function weierstrassPoints(c) {
686
+ const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
687
+ const Point = weierstrassN(CURVE, curveOpts);
688
+ return _weierstrass_new_output_to_legacy(c, Point);
689
+ }
690
+ // Points start with byte 0x02 when y is even; otherwise 0x03
691
+ function pprefix(hasEvenY) {
692
+ return Uint8Array.of(hasEvenY ? 0x02 : 0x03);
647
693
  }
648
- function validateOpts(curve) {
649
- const opts = (0, curve_ts_1.validateBasic)(curve);
650
- (0, utils_ts_1.validateObject)(opts, {
651
- hash: 'hash',
694
+ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
695
+ (0, utils_ts_1._validateObject)(ecdsaOpts, { hash: 'function' }, {
652
696
  hmac: 'function',
697
+ lowS: 'boolean',
653
698
  randomBytes: 'function',
654
- }, {
655
699
  bits2int: 'function',
656
700
  bits2int_modN: 'function',
657
- lowS: 'boolean',
658
701
  });
659
- return Object.freeze({ lowS: true, ...opts });
660
- }
661
- /**
662
- * Creates short weierstrass curve and ECDSA signature methods for it.
663
- * @example
664
- * import { Field } from '@noble/curves/abstract/modular';
665
- * // Before that, define BigInt-s: a, b, p, n, Gx, Gy
666
- * const curve = weierstrass({ a, b, Fp: Field(p), n, Gx, Gy, h: 1n })
667
- */
668
- function weierstrass(curveDef) {
669
- const CURVE = validateOpts(curveDef);
670
- const { Fp, n: CURVE_ORDER } = CURVE;
671
- const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
672
- const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
673
- function modN(a) {
674
- return (0, modular_ts_1.mod)(a, CURVE_ORDER);
675
- }
676
- function invN(a) {
677
- return (0, modular_ts_1.invert)(a, CURVE_ORDER);
678
- }
679
- const { ProjectivePoint: Point, normPrivateKeyToScalar, weierstrassEquation, isWithinCurveOrder, } = weierstrassPoints({
680
- ...CURVE,
681
- toBytes(_c, point, isCompressed) {
682
- const a = point.toAffine();
683
- const x = Fp.toBytes(a.x);
684
- const cat = utils_ts_1.concatBytes;
685
- (0, utils_ts_1.abool)('isCompressed', isCompressed);
686
- if (isCompressed) {
687
- return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
688
- }
689
- else {
690
- return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));
691
- }
692
- },
693
- fromBytes(bytes) {
694
- const len = bytes.length;
695
- const head = bytes[0];
696
- const tail = bytes.subarray(1);
697
- // this.assertValidity() is done inside of fromHex
698
- if (len === compressedLen && (head === 0x02 || head === 0x03)) {
699
- const x = (0, utils_ts_1.bytesToNumberBE)(tail);
700
- if (!(0, utils_ts_1.inRange)(x, _1n, Fp.ORDER))
701
- throw new Error('Point is not on curve');
702
- const y2 = weierstrassEquation(x); // y² = x³ + ax + b
703
- let y;
704
- try {
705
- y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
706
- }
707
- catch (sqrtError) {
708
- const suffix = sqrtError instanceof Error ? ': ' + sqrtError.message : '';
709
- throw new Error('Point is not on curve' + suffix);
710
- }
711
- const isYOdd = (y & _1n) === _1n;
712
- // ECDSA
713
- const isHeadOdd = (head & 1) === 1;
714
- if (isHeadOdd !== isYOdd)
715
- y = Fp.neg(y);
716
- return { x, y };
717
- }
718
- else if (len === uncompressedLen && head === 0x04) {
719
- const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
720
- const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
721
- return { x, y };
722
- }
723
- else {
724
- const cl = compressedLen;
725
- const ul = uncompressedLen;
726
- throw new Error('invalid Point, expected length of ' + cl + ', or uncompressed ' + ul + ', got ' + len);
727
- }
728
- },
729
- });
730
- const numToNByteHex = (num) => (0, utils_ts_1.bytesToHex)((0, utils_ts_1.numberToBytesBE)(num, CURVE.nByteLength));
702
+ const randomBytes_ = ecdsaOpts.randomBytes || utils_ts_1.randomBytes;
703
+ const hmac_ = ecdsaOpts.hmac ||
704
+ ((key, ...msgs) => (0, hmac_js_1.hmac)(ecdsaOpts.hash, key, (0, utils_ts_1.concatBytes)(...msgs)));
705
+ const { Fp, Fn } = Point;
706
+ const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
731
707
  function isBiggerThanHalfOrder(number) {
732
708
  const HALF = CURVE_ORDER >> _1n;
733
709
  return number > HALF;
734
710
  }
735
711
  function normalizeS(s) {
736
- return isBiggerThanHalfOrder(s) ? modN(-s) : s;
712
+ return isBiggerThanHalfOrder(s) ? Fn.neg(s) : s;
713
+ }
714
+ function aValidRS(title, num) {
715
+ if (!Fn.isValidNot0(num))
716
+ throw new Error(`invalid signature ${title}: out of range 1..CURVE.n`);
737
717
  }
738
- // slice bytes num
739
- const slcNum = (b, from, to) => (0, utils_ts_1.bytesToNumberBE)(b.slice(from, to));
740
718
  /**
741
719
  * ECDSA signature with its (r, s) properties. Supports DER & compact representations.
742
720
  */
743
721
  class Signature {
744
722
  constructor(r, s, recovery) {
745
- (0, utils_ts_1.aInRange)('r', r, _1n, CURVE_ORDER); // r in [1..N]
746
- (0, utils_ts_1.aInRange)('s', s, _1n, CURVE_ORDER); // s in [1..N]
723
+ aValidRS('r', r); // r in [1..N-1]
724
+ aValidRS('s', s); // s in [1..N-1]
747
725
  this.r = r;
748
726
  this.s = s;
749
727
  if (recovery != null)
@@ -752,9 +730,9 @@ function weierstrass(curveDef) {
752
730
  }
753
731
  // pair (bytes of r, bytes of s)
754
732
  static fromCompact(hex) {
755
- const l = CURVE.nByteLength;
756
- hex = (0, utils_ts_1.ensureBytes)('compactSignature', hex, l * 2);
757
- return new Signature(slcNum(hex, 0, l), slcNum(hex, l, 2 * l));
733
+ const L = Fn.BYTES;
734
+ const b = (0, utils_ts_1.ensureBytes)('compactSignature', hex, L * 2);
735
+ return new Signature(Fn.fromBytes(b.subarray(0, L)), Fn.fromBytes(b.subarray(L, L * 2)));
758
736
  }
759
737
  // DER encoded ECDSA signature
760
738
  // https://bitcoin.stackexchange.com/questions/57644/what-are-the-parts-of-a-bitcoin-transaction-input-script
@@ -770,22 +748,36 @@ function weierstrass(curveDef) {
770
748
  addRecoveryBit(recovery) {
771
749
  return new Signature(this.r, this.s, recovery);
772
750
  }
751
+ // ProjPointType<bigint>
773
752
  recoverPublicKey(msgHash) {
753
+ const FIELD_ORDER = Fp.ORDER;
774
754
  const { r, s, recovery: rec } = this;
775
- const h = bits2int_modN((0, utils_ts_1.ensureBytes)('msgHash', msgHash)); // Truncate hash
776
755
  if (rec == null || ![0, 1, 2, 3].includes(rec))
777
756
  throw new Error('recovery id invalid');
778
- const radj = rec === 2 || rec === 3 ? r + CURVE.n : r;
779
- if (radj >= Fp.ORDER)
757
+ // ECDSA recovery is hard for cofactor > 1 curves.
758
+ // In sign, `r = q.x mod n`, and here we recover q.x from r.
759
+ // While recovering q.x >= n, we need to add r+n for cofactor=1 curves.
760
+ // However, for cofactor>1, r+n may not get q.x:
761
+ // r+n*i would need to be done instead where i is unknown.
762
+ // To easily get i, we either need to:
763
+ // a. increase amount of valid recid values (4, 5...); OR
764
+ // b. prohibit non-prime-order signatures (recid > 1).
765
+ const hasCofactor = CURVE_ORDER * _2n < FIELD_ORDER;
766
+ if (hasCofactor && rec > 1)
767
+ throw new Error('recovery id is ambiguous for h>1 curve');
768
+ const radj = rec === 2 || rec === 3 ? r + CURVE_ORDER : r;
769
+ if (!Fp.isValid(radj))
780
770
  throw new Error('recovery id 2 or 3 invalid');
781
- const prefix = (rec & 1) === 0 ? '02' : '03';
782
- const R = Point.fromHex(prefix + numToNByteHex(radj));
783
- const ir = invN(radj); // r^-1
784
- const u1 = modN(-h * ir); // -hr^-1
785
- const u2 = modN(s * ir); // sr^-1
786
- const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
787
- if (!Q)
788
- throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
771
+ const x = Fp.toBytes(radj);
772
+ const R = Point.fromHex((0, utils_ts_1.concatBytes)(pprefix((rec & 1) === 0), x));
773
+ const ir = Fn.inv(radj); // r^-1
774
+ const h = bits2int_modN((0, utils_ts_1.ensureBytes)('msgHash', msgHash)); // Truncate hash
775
+ const u1 = Fn.create(-h * ir); // -hr^-1
776
+ const u2 = Fn.create(s * ir); // sr^-1
777
+ // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1). unsafe is fine: there is no private data.
778
+ const Q = Point.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2));
779
+ if (Q.is0())
780
+ throw new Error('point at infinify');
789
781
  Q.assertValidity();
790
782
  return Q;
791
783
  }
@@ -794,23 +786,31 @@ function weierstrass(curveDef) {
794
786
  return isBiggerThanHalfOrder(this.s);
795
787
  }
796
788
  normalizeS() {
797
- return this.hasHighS() ? new Signature(this.r, modN(-this.s), this.recovery) : this;
789
+ return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this;
790
+ }
791
+ toBytes(format) {
792
+ if (format === 'compact')
793
+ return (0, utils_ts_1.concatBytes)(Fn.toBytes(this.r), Fn.toBytes(this.s));
794
+ if (format === 'der')
795
+ return (0, utils_ts_1.hexToBytes)(exports.DER.hexFromSig(this));
796
+ throw new Error('invalid format');
798
797
  }
799
798
  // DER-encoded
800
799
  toDERRawBytes() {
801
- return (0, utils_ts_1.hexToBytes)(this.toDERHex());
800
+ return this.toBytes('der');
802
801
  }
803
802
  toDERHex() {
804
- return exports.DER.hexFromSig(this);
803
+ return (0, utils_ts_1.bytesToHex)(this.toBytes('der'));
805
804
  }
806
805
  // padded bytes of r, then padded bytes of s
807
806
  toCompactRawBytes() {
808
- return (0, utils_ts_1.hexToBytes)(this.toCompactHex());
807
+ return this.toBytes('compact');
809
808
  }
810
809
  toCompactHex() {
811
- return numToNByteHex(this.r) + numToNByteHex(this.s);
810
+ return (0, utils_ts_1.bytesToHex)(this.toBytes('compact'));
812
811
  }
813
812
  }
813
+ const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey);
814
814
  const utils = {
815
815
  isValidPrivateKey(privateKey) {
816
816
  try {
@@ -827,21 +827,11 @@ function weierstrass(curveDef) {
827
827
  * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
828
828
  */
829
829
  randomPrivateKey: () => {
830
- const length = (0, modular_ts_1.getMinHashLength)(CURVE.n);
831
- return (0, modular_ts_1.mapHashToField)(CURVE.randomBytes(length), CURVE.n);
830
+ const n = CURVE_ORDER;
831
+ return (0, modular_ts_1.mapHashToField)(randomBytes_((0, modular_ts_1.getMinHashLength)(n)), n);
832
832
  },
833
- /**
834
- * Creates precompute table for an arbitrary EC point. Makes point "cached".
835
- * Allows to massively speed-up `point.multiply(scalar)`.
836
- * @returns cached point
837
- * @example
838
- * const fast = utils.precompute(8, ProjectivePoint.fromHex(someonesPubKey));
839
- * fast.multiply(privKey); // much faster ECDH now
840
- */
841
833
  precompute(windowSize = 8, point = Point.BASE) {
842
- point._setWindowSize(windowSize);
843
- point.multiply(BigInt(3)); // 3 is arbitrary, just need any number here
844
- return point;
834
+ return point.precompute(windowSize, false);
845
835
  },
846
836
  };
847
837
  /**
@@ -851,22 +841,27 @@ function weierstrass(curveDef) {
851
841
  * @returns Public key, full when isCompressed=false; short when isCompressed=true
852
842
  */
853
843
  function getPublicKey(privateKey, isCompressed = true) {
854
- return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);
844
+ return Point.fromPrivateKey(privateKey).toBytes(isCompressed);
855
845
  }
856
846
  /**
857
847
  * Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
858
848
  */
859
849
  function isProbPub(item) {
860
- const arr = (0, utils_ts_1.isBytes)(item);
861
- const str = typeof item === 'string';
862
- const len = (arr || str) && item.length;
863
- if (arr)
864
- return len === compressedLen || len === uncompressedLen;
865
- if (str)
866
- return len === 2 * compressedLen || len === 2 * uncompressedLen;
850
+ if (typeof item === 'bigint')
851
+ return false;
867
852
  if (item instanceof Point)
868
853
  return true;
869
- return false;
854
+ const arr = (0, utils_ts_1.ensureBytes)('key', item);
855
+ const length = arr.length;
856
+ const L = Fp.BYTES;
857
+ const LC = L + 1; // e.g. 33 for 32
858
+ const LU = 2 * L + 1; // e.g. 65 for 32
859
+ if (curveOpts.allowedPrivateKeyLengths || Fn.BYTES === LC) {
860
+ return undefined;
861
+ }
862
+ else {
863
+ return length === LC || length === LU;
864
+ }
870
865
  }
871
866
  /**
872
867
  * ECDH (Elliptic Curve Diffie Hellman).
@@ -879,41 +874,41 @@ function weierstrass(curveDef) {
879
874
  * @returns shared public key
880
875
  */
881
876
  function getSharedSecret(privateA, publicB, isCompressed = true) {
882
- if (isProbPub(privateA))
877
+ if (isProbPub(privateA) === true)
883
878
  throw new Error('first arg must be private key');
884
- if (!isProbPub(publicB))
879
+ if (isProbPub(publicB) === false)
885
880
  throw new Error('second arg must be public key');
886
881
  const b = Point.fromHex(publicB); // check for being on-curve
887
- return b.multiply(normPrivateKeyToScalar(privateA)).toRawBytes(isCompressed);
882
+ return b.multiply(normPrivateKeyToScalar(privateA)).toBytes(isCompressed);
888
883
  }
889
884
  // RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
890
885
  // FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
891
886
  // bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
892
887
  // int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
893
- const bits2int = CURVE.bits2int ||
888
+ const bits2int = ecdsaOpts.bits2int ||
894
889
  function (bytes) {
895
- // Our custom check "just in case"
890
+ // Our custom check "just in case", for protection against DoS
896
891
  if (bytes.length > 8192)
897
892
  throw new Error('input is too large');
898
893
  // For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
899
894
  // for some cases, since bytes.length * 8 is not actual bitLength.
900
895
  const num = (0, utils_ts_1.bytesToNumberBE)(bytes); // check for == u8 done here
901
- const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits
896
+ const delta = bytes.length * 8 - fnBits; // truncate to nBitLength leftmost bits
902
897
  return delta > 0 ? num >> BigInt(delta) : num;
903
898
  };
904
- const bits2int_modN = CURVE.bits2int_modN ||
899
+ const bits2int_modN = ecdsaOpts.bits2int_modN ||
905
900
  function (bytes) {
906
- return modN(bits2int(bytes)); // can't use bytesToNumberBE here
901
+ return Fn.create(bits2int(bytes)); // can't use bytesToNumberBE here
907
902
  };
908
903
  // NOTE: pads output with zero as per spec
909
- const ORDER_MASK = (0, utils_ts_1.bitMask)(CURVE.nBitLength);
904
+ const ORDER_MASK = (0, utils_ts_1.bitMask)(fnBits);
910
905
  /**
911
906
  * Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
912
907
  */
913
908
  function int2octets(num) {
914
- (0, utils_ts_1.aInRange)('num < 2^' + CURVE.nBitLength, num, _0n, ORDER_MASK);
915
- // works with order, can have different size than numToField!
916
- return (0, utils_ts_1.numberToBytesBE)(num, CURVE.nByteLength);
909
+ // IMPORTANT: the check ensures working for case `Fn.BYTES != Fn.BITS * 8`
910
+ (0, utils_ts_1.aInRange)('num < 2^' + fnBits, num, _0n, ORDER_MASK);
911
+ return Fn.toBytes(num);
917
912
  }
918
913
  // Steps A, D of RFC6979 3.2
919
914
  // Creates RFC6979 seed; converts msg/privKey to numbers.
@@ -923,7 +918,7 @@ function weierstrass(curveDef) {
923
918
  function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
924
919
  if (['recovered', 'canonical'].some((k) => k in opts))
925
920
  throw new Error('sign() legacy options not supported');
926
- const { hash, randomBytes } = CURVE;
921
+ const { hash } = ecdsaOpts;
927
922
  let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
928
923
  if (lowS == null)
929
924
  lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
@@ -932,7 +927,7 @@ function weierstrass(curveDef) {
932
927
  if (prehash)
933
928
  msgHash = (0, utils_ts_1.ensureBytes)('prehashed msgHash', hash(msgHash));
934
929
  // We can't later call bits2octets, since nested bits2int is broken for curves
935
- // with nBitLength % 8 !== 0. Because of that, we unwrap it here as int2octets call.
930
+ // with fnBits % 8 !== 0. Because of that, we unwrap it here as int2octets call.
936
931
  // const bits2octets = (bits) => int2octets(bits2int_modN(bits))
937
932
  const h1int = bits2int_modN(msgHash);
938
933
  const d = normPrivateKeyToScalar(privateKey); // validate private key, convert to bigint
@@ -940,26 +935,27 @@ function weierstrass(curveDef) {
940
935
  // extraEntropy. RFC6979 3.6: additional k' (optional).
941
936
  if (ent != null && ent !== false) {
942
937
  // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
943
- const e = ent === true ? randomBytes(Fp.BYTES) : ent; // generate random bytes OR pass as-is
938
+ const e = ent === true ? randomBytes_(Fp.BYTES) : ent; // generate random bytes OR pass as-is
944
939
  seedArgs.push((0, utils_ts_1.ensureBytes)('extraEntropy', e)); // check for being bytes
945
940
  }
946
941
  const seed = (0, utils_ts_1.concatBytes)(...seedArgs); // Step D of RFC6979 3.2
947
942
  const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
948
943
  // Converts signature params into point w r/s, checks result for validity.
944
+ // Can use scalar blinding b^-1(bm + bdr) where b ∈ [1,q−1] according to
945
+ // https://tches.iacr.org/index.php/TCHES/article/view/7337/6509. We've decided against it:
946
+ // a) dependency on CSPRNG b) 15% slowdown c) doesn't really help since bigints are not CT
949
947
  function k2sig(kBytes) {
950
948
  // RFC 6979 Section 3.2, step 3: k = bits2int(T)
949
+ // Important: all mod() calls here must be done over N
951
950
  const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
952
- if (!isWithinCurveOrder(k))
953
- return; // Important: all mod() calls here must be done over N
954
- const ik = invN(k); // k^-1 mod n
951
+ if (!Fn.isValidNot0(k))
952
+ return; // Valid scalars (including k) must be in 1..N-1
953
+ const ik = Fn.inv(k); // k^-1 mod n
955
954
  const q = Point.BASE.multiply(k).toAffine(); // q = Gk
956
- const r = modN(q.x); // r = q.x mod n
955
+ const r = Fn.create(q.x); // r = q.x mod n
957
956
  if (r === _0n)
958
957
  return;
959
- // Can use scalar blinding b^-1(bm + bdr) where b [1,q−1] according to
960
- // https://tches.iacr.org/index.php/TCHES/article/view/7337/6509. We've decided against it:
961
- // a) dependency on CSPRNG b) 15% slowdown c) doesn't really help since bigints are not CT
962
- const s = modN(ik * modN(m + r * d)); // Not using blinding here
958
+ const s = Fn.create(ik * Fn.create(m + r * d)); // Not using blinding here, see comment above
963
959
  if (s === _0n)
964
960
  return;
965
961
  let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
@@ -972,8 +968,8 @@ function weierstrass(curveDef) {
972
968
  }
973
969
  return { seed, k2sig };
974
970
  }
975
- const defaultSigOpts = { lowS: CURVE.lowS, prehash: false };
976
- const defaultVerOpts = { lowS: CURVE.lowS, prehash: false };
971
+ const defaultSigOpts = { lowS: ecdsaOpts.lowS, prehash: false };
972
+ const defaultVerOpts = { lowS: ecdsaOpts.lowS, prehash: false };
977
973
  /**
978
974
  * Signs message hash with a private key.
979
975
  * ```
@@ -989,13 +985,11 @@ function weierstrass(curveDef) {
989
985
  */
990
986
  function sign(msgHash, privKey, opts = defaultSigOpts) {
991
987
  const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
992
- const C = CURVE;
993
- const drbg = (0, utils_ts_1.createHmacDrbg)(C.hash.outputLen, C.nByteLength, C.hmac);
988
+ const drbg = (0, utils_ts_1.createHmacDrbg)(ecdsaOpts.hash.outputLen, Fn.BYTES, hmac_);
994
989
  return drbg(seed, k2sig); // Steps B, C, D, E, F, G
995
990
  }
996
991
  // Enable precomputes. Slows down first publicKey computation by 20ms.
997
- Point.BASE._setWindowSize(8);
998
- // utils.precompute(8, ProjectivePoint.BASE)
992
+ Point.BASE.precompute(8);
999
993
  /**
1000
994
  * Verifies a signature against message hash and public key.
1001
995
  * Rejects lowS signatures by default: to override,
@@ -1013,13 +1007,14 @@ function weierstrass(curveDef) {
1013
1007
  const sg = signature;
1014
1008
  msgHash = (0, utils_ts_1.ensureBytes)('msgHash', msgHash);
1015
1009
  publicKey = (0, utils_ts_1.ensureBytes)('publicKey', publicKey);
1016
- const { lowS, prehash, format } = opts;
1017
- // Verify opts, deduce signature format
1010
+ // Verify opts
1018
1011
  validateSigVerOpts(opts);
1012
+ const { lowS, prehash, format } = opts;
1013
+ // TODO: remove
1019
1014
  if ('strict' in opts)
1020
1015
  throw new Error('options.strict was renamed to lowS');
1021
- if (format !== undefined && format !== 'compact' && format !== 'der')
1022
- throw new Error('format must be compact or der');
1016
+ if (format !== undefined && !['compact', 'der', 'js'].includes(format))
1017
+ throw new Error('format must be "compact", "der" or "js"');
1023
1018
  const isHex = typeof sg === 'string' || (0, utils_ts_1.isBytes)(sg);
1024
1019
  const isObj = !isHex &&
1025
1020
  !format &&
@@ -1031,12 +1026,29 @@ function weierstrass(curveDef) {
1031
1026
  throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
1032
1027
  let _sig = undefined;
1033
1028
  let P;
1029
+ // deduce signature format
1034
1030
  try {
1035
- if (isObj)
1036
- _sig = new Signature(sg.r, sg.s);
1031
+ // if (format === 'js') {
1032
+ // if (sg != null && !isBytes(sg)) _sig = new Signature(sg.r, sg.s);
1033
+ // } else if (format === 'compact') {
1034
+ // _sig = Signature.fromCompact(sg);
1035
+ // } else if (format === 'der') {
1036
+ // _sig = Signature.fromDER(sg);
1037
+ // } else {
1038
+ // throw new Error('invalid format');
1039
+ // }
1040
+ if (isObj) {
1041
+ if (format === undefined || format === 'js') {
1042
+ _sig = new Signature(sg.r, sg.s);
1043
+ }
1044
+ else {
1045
+ throw new Error('invalid format');
1046
+ }
1047
+ }
1037
1048
  if (isHex) {
1038
- // Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
1039
- // Since DER can also be 2*nByteLength bytes, we check for it first.
1049
+ // TODO: remove this malleable check
1050
+ // Signature can be represented in 2 ways: compact (2*Fn.BYTES) & DER (variable-length).
1051
+ // Since DER can also be 2*Fn.BYTES bytes, we check for it first.
1040
1052
  try {
1041
1053
  if (format !== 'compact')
1042
1054
  _sig = Signature.fromDER(sg);
@@ -1057,29 +1069,99 @@ function weierstrass(curveDef) {
1057
1069
  return false;
1058
1070
  if (lowS && _sig.hasHighS())
1059
1071
  return false;
1072
+ // todo: optional.hash => hash
1060
1073
  if (prehash)
1061
- msgHash = CURVE.hash(msgHash);
1074
+ msgHash = ecdsaOpts.hash(msgHash);
1062
1075
  const { r, s } = _sig;
1063
1076
  const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
1064
- const is = invN(s); // s^-1
1065
- const u1 = modN(h * is); // u1 = hs^-1 mod n
1066
- const u2 = modN(r * is); // u2 = rs^-1 mod n
1067
- const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); // R = u1⋅G + u2⋅P
1068
- if (!R)
1077
+ const is = Fn.inv(s); // s^-1
1078
+ const u1 = Fn.create(h * is); // u1 = hs^-1 mod n
1079
+ const u2 = Fn.create(r * is); // u2 = rs^-1 mod n
1080
+ const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
1081
+ if (R.is0())
1069
1082
  return false;
1070
- const v = modN(R.x);
1083
+ const v = Fn.create(R.x); // v = r.x mod n
1071
1084
  return v === r;
1072
1085
  }
1073
- return {
1074
- CURVE,
1086
+ // TODO: clarify API for cloning .clone({hash: sha512}) ? .createWith({hash: sha512})?
1087
+ // const clone = (hash: CHash): ECDSA => ecdsa(Point, { ...ecdsaOpts, ...getHash(hash) }, curveOpts);
1088
+ return Object.freeze({
1075
1089
  getPublicKey,
1076
1090
  getSharedSecret,
1077
1091
  sign,
1078
1092
  verify,
1079
- ProjectivePoint: Point,
1080
- Signature,
1081
1093
  utils,
1094
+ Point,
1095
+ Signature,
1096
+ });
1097
+ }
1098
+ function _weierstrass_legacy_opts_to_new(c) {
1099
+ const CURVE = {
1100
+ a: c.a,
1101
+ b: c.b,
1102
+ p: c.Fp.ORDER,
1103
+ n: c.n,
1104
+ h: c.h,
1105
+ Gx: c.Gx,
1106
+ Gy: c.Gy,
1107
+ };
1108
+ const Fp = c.Fp;
1109
+ const Fn = (0, modular_ts_1.Field)(CURVE.n, c.nBitLength);
1110
+ const curveOpts = {
1111
+ Fp,
1112
+ Fn,
1113
+ allowedPrivateKeyLengths: c.allowedPrivateKeyLengths,
1114
+ allowInfinityPoint: c.allowInfinityPoint,
1115
+ endo: c.endo,
1116
+ wrapPrivateKey: c.wrapPrivateKey,
1117
+ isTorsionFree: c.isTorsionFree,
1118
+ clearCofactor: c.clearCofactor,
1119
+ fromBytes: c.fromBytes,
1120
+ toBytes: c.toBytes,
1082
1121
  };
1122
+ return { CURVE, curveOpts };
1123
+ }
1124
+ function _ecdsa_legacy_opts_to_new(c) {
1125
+ const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
1126
+ const ecdsaOpts = {
1127
+ hash: c.hash,
1128
+ hmac: c.hmac,
1129
+ randomBytes: c.randomBytes,
1130
+ lowS: c.lowS,
1131
+ bits2int: c.bits2int,
1132
+ bits2int_modN: c.bits2int_modN,
1133
+ };
1134
+ return { CURVE, curveOpts, ecdsaOpts };
1135
+ }
1136
+ function _weierstrass_new_output_to_legacy(c, Point) {
1137
+ const { Fp, Fn } = Point;
1138
+ // TODO: remove
1139
+ function isWithinCurveOrder(num) {
1140
+ return (0, utils_ts_1.inRange)(num, _1n, Fn.ORDER);
1141
+ }
1142
+ const weierstrassEquation = _legacyHelperEquat(Fp, c.a, c.b);
1143
+ const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, c.allowedPrivateKeyLengths, c.wrapPrivateKey);
1144
+ return Object.assign({}, {
1145
+ CURVE: c,
1146
+ Point: Point,
1147
+ ProjectivePoint: Point,
1148
+ normPrivateKeyToScalar,
1149
+ weierstrassEquation,
1150
+ isWithinCurveOrder,
1151
+ });
1152
+ }
1153
+ function _ecdsa_new_output_to_legacy(c, ecdsa) {
1154
+ return Object.assign({}, ecdsa, {
1155
+ ProjectivePoint: ecdsa.Point,
1156
+ CURVE: c,
1157
+ });
1158
+ }
1159
+ // _ecdsa_legacy
1160
+ function weierstrass(c) {
1161
+ const { CURVE, curveOpts, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
1162
+ const Point = weierstrassN(CURVE, curveOpts);
1163
+ const signs = ecdsa(Point, ecdsaOpts, curveOpts);
1164
+ return _ecdsa_new_output_to_legacy(c, signs);
1083
1165
  }
1084
1166
  /**
1085
1167
  * Implementation of the Shallue and van de Woestijne method for any weierstrass curve.
@@ -1165,31 +1247,32 @@ function SWUFpSqrtRatio(Fp, Z) {
1165
1247
  */
1166
1248
  function mapToCurveSimpleSWU(Fp, opts) {
1167
1249
  (0, modular_ts_1.validateField)(Fp);
1168
- if (!Fp.isValid(opts.A) || !Fp.isValid(opts.B) || !Fp.isValid(opts.Z))
1250
+ const { A, B, Z } = opts;
1251
+ if (!Fp.isValid(A) || !Fp.isValid(B) || !Fp.isValid(Z))
1169
1252
  throw new Error('mapToCurveSimpleSWU: invalid opts');
1170
- const sqrtRatio = SWUFpSqrtRatio(Fp, opts.Z);
1253
+ const sqrtRatio = SWUFpSqrtRatio(Fp, Z);
1171
1254
  if (!Fp.isOdd)
1172
- throw new Error('Fp.isOdd is not implemented!');
1255
+ throw new Error('Field does not have .isOdd()');
1173
1256
  // Input: u, an element of F.
1174
1257
  // Output: (x, y), a point on E.
1175
1258
  return (u) => {
1176
1259
  // prettier-ignore
1177
1260
  let tv1, tv2, tv3, tv4, tv5, tv6, x, y;
1178
1261
  tv1 = Fp.sqr(u); // 1. tv1 = u^2
1179
- tv1 = Fp.mul(tv1, opts.Z); // 2. tv1 = Z * tv1
1262
+ tv1 = Fp.mul(tv1, Z); // 2. tv1 = Z * tv1
1180
1263
  tv2 = Fp.sqr(tv1); // 3. tv2 = tv1^2
1181
1264
  tv2 = Fp.add(tv2, tv1); // 4. tv2 = tv2 + tv1
1182
1265
  tv3 = Fp.add(tv2, Fp.ONE); // 5. tv3 = tv2 + 1
1183
- tv3 = Fp.mul(tv3, opts.B); // 6. tv3 = B * tv3
1184
- tv4 = Fp.cmov(opts.Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
1185
- tv4 = Fp.mul(tv4, opts.A); // 8. tv4 = A * tv4
1266
+ tv3 = Fp.mul(tv3, B); // 6. tv3 = B * tv3
1267
+ tv4 = Fp.cmov(Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
1268
+ tv4 = Fp.mul(tv4, A); // 8. tv4 = A * tv4
1186
1269
  tv2 = Fp.sqr(tv3); // 9. tv2 = tv3^2
1187
1270
  tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2
1188
- tv5 = Fp.mul(tv6, opts.A); // 11. tv5 = A * tv6
1271
+ tv5 = Fp.mul(tv6, A); // 11. tv5 = A * tv6
1189
1272
  tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5
1190
1273
  tv2 = Fp.mul(tv2, tv3); // 13. tv2 = tv2 * tv3
1191
1274
  tv6 = Fp.mul(tv6, tv4); // 14. tv6 = tv6 * tv4
1192
- tv5 = Fp.mul(tv6, opts.B); // 15. tv5 = B * tv6
1275
+ tv5 = Fp.mul(tv6, B); // 15. tv5 = B * tv6
1193
1276
  tv2 = Fp.add(tv2, tv5); // 16. tv2 = tv2 + tv5
1194
1277
  x = Fp.mul(tv1, tv3); // 17. x = tv1 * tv3
1195
1278
  const { isValid, value } = sqrtRatio(tv2, tv6); // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)