@noble/curves 1.9.1 → 1.9.3

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