@noble/curves 1.4.2 → 1.6.0

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 (130) hide show
  1. package/README.md +159 -128
  2. package/_shortw_utils.d.ts.map +1 -1
  3. package/abstract/bls.d.ts +37 -34
  4. package/abstract/bls.d.ts.map +1 -1
  5. package/abstract/bls.js +167 -115
  6. package/abstract/bls.js.map +1 -1
  7. package/abstract/curve.d.ts +14 -1
  8. package/abstract/curve.d.ts.map +1 -1
  9. package/abstract/curve.js +77 -7
  10. package/abstract/curve.js.map +1 -1
  11. package/abstract/edwards.d.ts +12 -0
  12. package/abstract/edwards.d.ts.map +1 -1
  13. package/abstract/edwards.js +84 -75
  14. package/abstract/edwards.js.map +1 -1
  15. package/abstract/hash-to-curve.d.ts.map +1 -1
  16. package/abstract/hash-to-curve.js +4 -2
  17. package/abstract/hash-to-curve.js.map +1 -1
  18. package/abstract/modular.d.ts +4 -0
  19. package/abstract/modular.d.ts.map +1 -1
  20. package/abstract/modular.js +13 -2
  21. package/abstract/modular.js.map +1 -1
  22. package/abstract/montgomery.d.ts.map +1 -1
  23. package/abstract/montgomery.js +4 -9
  24. package/abstract/montgomery.js.map +1 -1
  25. package/abstract/tower.d.ts +107 -0
  26. package/abstract/tower.d.ts.map +1 -0
  27. package/abstract/tower.js +498 -0
  28. package/abstract/tower.js.map +1 -0
  29. package/abstract/utils.d.ts +17 -0
  30. package/abstract/utils.d.ts.map +1 -1
  31. package/abstract/utils.js +50 -1
  32. package/abstract/utils.js.map +1 -1
  33. package/abstract/weierstrass.d.ts +25 -3
  34. package/abstract/weierstrass.d.ts.map +1 -1
  35. package/abstract/weierstrass.js +189 -113
  36. package/abstract/weierstrass.js.map +1 -1
  37. package/bls12-381.d.ts +1 -65
  38. package/bls12-381.d.ts.map +1 -1
  39. package/bls12-381.js +48 -575
  40. package/bls12-381.js.map +1 -1
  41. package/bn254.d.ts +10 -6
  42. package/bn254.d.ts.map +1 -1
  43. package/bn254.js +207 -10
  44. package/bn254.js.map +1 -1
  45. package/ed25519.d.ts +7 -4
  46. package/ed25519.d.ts.map +1 -1
  47. package/ed25519.js +3 -0
  48. package/ed25519.js.map +1 -1
  49. package/esm/_shortw_utils.d.ts.map +1 -1
  50. package/esm/abstract/bls.d.ts +37 -34
  51. package/esm/abstract/bls.d.ts.map +1 -1
  52. package/esm/abstract/bls.js +168 -116
  53. package/esm/abstract/bls.js.map +1 -1
  54. package/esm/abstract/curve.d.ts +14 -1
  55. package/esm/abstract/curve.d.ts.map +1 -1
  56. package/esm/abstract/curve.js +77 -8
  57. package/esm/abstract/curve.js.map +1 -1
  58. package/esm/abstract/edwards.d.ts +12 -0
  59. package/esm/abstract/edwards.d.ts.map +1 -1
  60. package/esm/abstract/edwards.js +87 -78
  61. package/esm/abstract/edwards.js.map +1 -1
  62. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  63. package/esm/abstract/hash-to-curve.js +4 -2
  64. package/esm/abstract/hash-to-curve.js.map +1 -1
  65. package/esm/abstract/modular.d.ts +4 -0
  66. package/esm/abstract/modular.d.ts.map +1 -1
  67. package/esm/abstract/modular.js +12 -2
  68. package/esm/abstract/modular.js.map +1 -1
  69. package/esm/abstract/montgomery.d.ts.map +1 -1
  70. package/esm/abstract/montgomery.js +5 -10
  71. package/esm/abstract/montgomery.js.map +1 -1
  72. package/esm/abstract/tower.d.ts +107 -0
  73. package/esm/abstract/tower.d.ts.map +1 -0
  74. package/esm/abstract/tower.js +494 -0
  75. package/esm/abstract/tower.js.map +1 -0
  76. package/esm/abstract/utils.d.ts +17 -0
  77. package/esm/abstract/utils.d.ts.map +1 -1
  78. package/esm/abstract/utils.js +44 -0
  79. package/esm/abstract/utils.js.map +1 -1
  80. package/esm/abstract/weierstrass.d.ts +25 -3
  81. package/esm/abstract/weierstrass.d.ts.map +1 -1
  82. package/esm/abstract/weierstrass.js +191 -115
  83. package/esm/abstract/weierstrass.js.map +1 -1
  84. package/esm/bls12-381.d.ts +1 -65
  85. package/esm/bls12-381.d.ts.map +1 -1
  86. package/esm/bls12-381.js +50 -577
  87. package/esm/bls12-381.js.map +1 -1
  88. package/esm/bn254.d.ts +10 -6
  89. package/esm/bn254.d.ts.map +1 -1
  90. package/esm/bn254.js +206 -9
  91. package/esm/bn254.js.map +1 -1
  92. package/esm/ed25519.d.ts +7 -4
  93. package/esm/ed25519.d.ts.map +1 -1
  94. package/esm/ed25519.js +3 -0
  95. package/esm/ed25519.js.map +1 -1
  96. package/esm/jubjub.d.ts.map +1 -1
  97. package/esm/jubjub.js +8 -2
  98. package/esm/jubjub.js.map +1 -1
  99. package/esm/p256.d.ts.map +1 -1
  100. package/esm/p384.d.ts.map +1 -1
  101. package/esm/p521.d.ts.map +1 -1
  102. package/esm/secp256k1.d.ts +6 -0
  103. package/esm/secp256k1.d.ts.map +1 -1
  104. package/esm/secp256k1.js +17 -13
  105. package/esm/secp256k1.js.map +1 -1
  106. package/jubjub.d.ts.map +1 -1
  107. package/jubjub.js +8 -2
  108. package/jubjub.js.map +1 -1
  109. package/p256.d.ts.map +1 -1
  110. package/p384.d.ts.map +1 -1
  111. package/p521.d.ts.map +1 -1
  112. package/package.json +27 -19
  113. package/secp256k1.d.ts +6 -0
  114. package/secp256k1.d.ts.map +1 -1
  115. package/secp256k1.js +16 -12
  116. package/secp256k1.js.map +1 -1
  117. package/src/abstract/bls.ts +222 -168
  118. package/src/abstract/curve.ts +80 -8
  119. package/src/abstract/edwards.ts +97 -70
  120. package/src/abstract/hash-to-curve.ts +3 -1
  121. package/src/abstract/modular.ts +13 -3
  122. package/src/abstract/montgomery.ts +11 -10
  123. package/src/abstract/tower.ts +605 -0
  124. package/src/abstract/utils.ts +49 -0
  125. package/src/abstract/weierstrass.ts +179 -104
  126. package/src/bls12-381.ts +53 -707
  127. package/src/bn254.ts +224 -9
  128. package/src/ed25519.ts +5 -2
  129. package/src/jubjub.ts +7 -2
  130. package/src/secp256k1.ts +24 -12
@@ -11,6 +11,12 @@ const curve_js_1 = require("./curve.js");
11
11
  const mod = require("./modular.js");
12
12
  const ut = require("./utils.js");
13
13
  const utils_js_1 = require("./utils.js");
14
+ function validateSigVerOpts(opts) {
15
+ if (opts.lowS !== undefined)
16
+ (0, utils_js_1.abool)('lowS', opts.lowS);
17
+ if (opts.prehash !== undefined)
18
+ (0, utils_js_1.abool)('prehash', opts.prehash);
19
+ }
14
20
  function validatePointOpts(curve) {
15
21
  const opts = (0, curve_js_1.validateBasic)(curve);
16
22
  ut.validateObject(opts, {
@@ -38,8 +44,14 @@ function validatePointOpts(curve) {
38
44
  }
39
45
  return Object.freeze({ ...opts });
40
46
  }
41
- // ASN.1 DER encoding utilities
42
47
  const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
48
+ /**
49
+ * ASN.1 DER encoding utilities. ASN is very complex & fragile. Format:
50
+ *
51
+ * [0x30 (SEQUENCE), bytelength, 0x02 (INTEGER), intLength, R, 0x02 (INTEGER), intLength, S]
52
+ *
53
+ * Docs: https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/, https://luca.ntop.org/Teaching/Appunti/asn1.html
54
+ */
43
55
  exports.DER = {
44
56
  // asn.1 DER encoding utils
45
57
  Err: class DERErr extends Error {
@@ -47,54 +59,103 @@ exports.DER = {
47
59
  super(m);
48
60
  }
49
61
  },
50
- _parseInt(data) {
51
- const { Err: E } = exports.DER;
52
- if (data.length < 2 || data[0] !== 0x02)
53
- throw new E('Invalid signature integer tag');
54
- const len = data[1];
55
- const res = data.subarray(2, len + 2);
56
- if (!len || res.length !== len)
57
- throw new E('Invalid signature integer: wrong length');
58
- // https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
59
- // since we always use positive integers here. It must always be empty:
60
- // - add zero byte if exists
61
- // - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
62
- if (res[0] & 0b10000000)
63
- throw new E('Invalid signature integer: negative');
64
- if (res[0] === 0x00 && !(res[1] & 0b10000000))
65
- throw new E('Invalid signature integer: unnecessary leading zero');
66
- return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
62
+ // Basic building block is TLV (Tag-Length-Value)
63
+ _tlv: {
64
+ encode: (tag, data) => {
65
+ const { Err: E } = exports.DER;
66
+ if (tag < 0 || tag > 256)
67
+ throw new E('tlv.encode: wrong tag');
68
+ if (data.length & 1)
69
+ throw new E('tlv.encode: unpadded data');
70
+ const dataLen = data.length / 2;
71
+ const len = ut.numberToHexUnpadded(dataLen);
72
+ if ((len.length / 2) & 128)
73
+ throw new E('tlv.encode: long form length too big');
74
+ // length of length with long form flag
75
+ const lenLen = dataLen > 127 ? ut.numberToHexUnpadded((len.length / 2) | 128) : '';
76
+ return `${ut.numberToHexUnpadded(tag)}${lenLen}${len}${data}`;
77
+ },
78
+ // v - value, l - left bytes (unparsed)
79
+ decode(tag, data) {
80
+ const { Err: E } = exports.DER;
81
+ let pos = 0;
82
+ if (tag < 0 || tag > 256)
83
+ throw new E('tlv.encode: wrong tag');
84
+ if (data.length < 2 || data[pos++] !== tag)
85
+ throw new E('tlv.decode: wrong tlv');
86
+ const first = data[pos++];
87
+ const isLong = !!(first & 128); // First bit of first length byte is flag for short/long form
88
+ let length = 0;
89
+ if (!isLong)
90
+ length = first;
91
+ else {
92
+ // Long form: [longFlag(1bit), lengthLength(7bit), length (BE)]
93
+ const lenLen = first & 127;
94
+ if (!lenLen)
95
+ throw new E('tlv.decode(long): indefinite length not supported');
96
+ if (lenLen > 4)
97
+ throw new E('tlv.decode(long): byte length is too big'); // this will overflow u32 in js
98
+ const lengthBytes = data.subarray(pos, pos + lenLen);
99
+ if (lengthBytes.length !== lenLen)
100
+ throw new E('tlv.decode: length bytes not complete');
101
+ if (lengthBytes[0] === 0)
102
+ throw new E('tlv.decode(long): zero leftmost byte');
103
+ for (const b of lengthBytes)
104
+ length = (length << 8) | b;
105
+ pos += lenLen;
106
+ if (length < 128)
107
+ throw new E('tlv.decode(long): not minimal encoding');
108
+ }
109
+ const v = data.subarray(pos, pos + length);
110
+ if (v.length !== length)
111
+ throw new E('tlv.decode: wrong value length');
112
+ return { v, l: data.subarray(pos + length) };
113
+ },
114
+ },
115
+ // https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
116
+ // since we always use positive integers here. It must always be empty:
117
+ // - add zero byte if exists
118
+ // - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
119
+ _int: {
120
+ encode(num) {
121
+ const { Err: E } = exports.DER;
122
+ if (num < _0n)
123
+ throw new E('integer: negative integers are not allowed');
124
+ let hex = ut.numberToHexUnpadded(num);
125
+ // Pad with zero byte if negative flag is present
126
+ if (Number.parseInt(hex[0], 16) & 0b1000)
127
+ hex = '00' + hex;
128
+ if (hex.length & 1)
129
+ throw new E('unexpected assertion');
130
+ return hex;
131
+ },
132
+ decode(data) {
133
+ const { Err: E } = exports.DER;
134
+ if (data[0] & 128)
135
+ throw new E('Invalid signature integer: negative');
136
+ if (data[0] === 0x00 && !(data[1] & 128))
137
+ throw new E('Invalid signature integer: unnecessary leading zero');
138
+ return b2n(data);
139
+ },
67
140
  },
68
141
  toSig(hex) {
69
142
  // parse DER signature
70
- const { Err: E } = exports.DER;
143
+ const { Err: E, _int: int, _tlv: tlv } = exports.DER;
71
144
  const data = typeof hex === 'string' ? h2b(hex) : hex;
72
145
  ut.abytes(data);
73
- let l = data.length;
74
- if (l < 2 || data[0] != 0x30)
75
- throw new E('Invalid signature tag');
76
- if (data[1] !== l - 2)
77
- throw new E('Invalid signature: incorrect length');
78
- const { d: r, l: sBytes } = exports.DER._parseInt(data.subarray(2));
79
- const { d: s, l: rBytesLeft } = exports.DER._parseInt(sBytes);
80
- if (rBytesLeft.length)
146
+ const { v: seqBytes, l: seqLeftBytes } = tlv.decode(0x30, data);
147
+ if (seqLeftBytes.length)
148
+ throw new E('Invalid signature: left bytes after parsing');
149
+ const { v: rBytes, l: rLeftBytes } = tlv.decode(0x02, seqBytes);
150
+ const { v: sBytes, l: sLeftBytes } = tlv.decode(0x02, rLeftBytes);
151
+ if (sLeftBytes.length)
81
152
  throw new E('Invalid signature: left bytes after parsing');
82
- return { r, s };
153
+ return { r: int.decode(rBytes), s: int.decode(sBytes) };
83
154
  },
84
155
  hexFromSig(sig) {
85
- // Add leading zero if first byte has negative bit enabled. More details in '_parseInt'
86
- const slice = (s) => (Number.parseInt(s[0], 16) & 0b1000 ? '00' + s : s);
87
- const h = (num) => {
88
- const hex = num.toString(16);
89
- return hex.length & 1 ? `0${hex}` : hex;
90
- };
91
- const s = slice(h(sig.s));
92
- const r = slice(h(sig.r));
93
- const shl = s.length / 2;
94
- const rhl = r.length / 2;
95
- const sl = h(shl);
96
- const rl = h(rhl);
97
- return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;
156
+ const { _tlv: tlv, _int: int } = exports.DER;
157
+ const seq = `${tlv.encode(0x02, int.encode(sig.r))}${tlv.encode(0x02, int.encode(sig.s))}`;
158
+ return tlv.encode(0x30, seq);
98
159
  },
99
160
  };
100
161
  // Be friendly to bad ECMAScript parsers by not using bigint literals
@@ -103,6 +164,7 @@ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n =
103
164
  function weierstrassPoints(opts) {
104
165
  const CURVE = validatePointOpts(opts);
105
166
  const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
167
+ const Fn = mod.Field(CURVE.n, CURVE.nBitLength);
106
168
  const toBytes = CURVE.toBytes ||
107
169
  ((_c, point, _isCompressed) => {
108
170
  const a = point.toAffine();
@@ -135,16 +197,12 @@ function weierstrassPoints(opts) {
135
197
  throw new Error('bad generator point: equation left != right');
136
198
  // Valid group elements reside in range 1..n-1
137
199
  function isWithinCurveOrder(num) {
138
- return typeof num === 'bigint' && _0n < num && num < CURVE.n;
139
- }
140
- function assertGE(num) {
141
- if (!isWithinCurveOrder(num))
142
- throw new Error('Expected valid bigint: 0 < bigint < curve.n');
200
+ return ut.inRange(num, _1n, CURVE.n);
143
201
  }
144
202
  // Validates if priv key is valid and converts it to bigint.
145
203
  // Supports options allowedPrivateKeyLengths and wrapPrivateKey.
146
204
  function normPrivateKeyToScalar(key) {
147
- const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
205
+ const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n: N } = CURVE;
148
206
  if (lengths && typeof key !== 'bigint') {
149
207
  if (ut.isBytes(key))
150
208
  key = ut.bytesToHex(key);
@@ -164,15 +222,61 @@ function weierstrassPoints(opts) {
164
222
  throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
165
223
  }
166
224
  if (wrapPrivateKey)
167
- num = mod.mod(num, n); // disabled by default, enabled for BLS
168
- assertGE(num); // num in range [1..N-1]
225
+ num = mod.mod(num, N); // disabled by default, enabled for BLS
226
+ ut.aInRange('private key', num, _1n, N); // num in range [1..N-1]
169
227
  return num;
170
228
  }
171
- const pointPrecomputes = new Map();
172
229
  function assertPrjPoint(other) {
173
230
  if (!(other instanceof Point))
174
231
  throw new Error('ProjectivePoint expected');
175
232
  }
233
+ // Memoized toAffine / validity check. They are heavy. Points are immutable.
234
+ // Converts Projective point to affine (x, y) coordinates.
235
+ // Can accept precomputed Z^-1 - for example, from invertBatch.
236
+ // (x, y, z) ∋ (x=x/z, y=y/z)
237
+ const toAffineMemo = (0, utils_js_1.memoized)((p, iz) => {
238
+ const { px: x, py: y, pz: z } = p;
239
+ // Fast-path for normalized points
240
+ if (Fp.eql(z, Fp.ONE))
241
+ return { x, y };
242
+ const is0 = p.is0();
243
+ // If invZ was 0, we return zero point. However we still want to execute
244
+ // all operations, so we replace invZ with a random number, 1.
245
+ if (iz == null)
246
+ iz = is0 ? Fp.ONE : Fp.inv(z);
247
+ const ax = Fp.mul(x, iz);
248
+ const ay = Fp.mul(y, iz);
249
+ const zz = Fp.mul(z, iz);
250
+ if (is0)
251
+ return { x: Fp.ZERO, y: Fp.ZERO };
252
+ if (!Fp.eql(zz, Fp.ONE))
253
+ throw new Error('invZ was invalid');
254
+ return { x: ax, y: ay };
255
+ });
256
+ // NOTE: on exception this will crash 'cached' and no value will be set.
257
+ // Otherwise true will be return
258
+ const assertValidMemo = (0, utils_js_1.memoized)((p) => {
259
+ if (p.is0()) {
260
+ // (0, 1, 0) aka ZERO is invalid in most contexts.
261
+ // In BLS, ZERO can be serialized, so we allow it.
262
+ // (0, 0, 0) is wrong representation of ZERO and is always invalid.
263
+ if (CURVE.allowInfinityPoint && !Fp.is0(p.py))
264
+ return;
265
+ throw new Error('bad point: ZERO');
266
+ }
267
+ // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
268
+ const { x, y } = p.toAffine();
269
+ // Check if x, y are valid field elements
270
+ if (!Fp.isValid(x) || !Fp.isValid(y))
271
+ throw new Error('bad point: x or y not FE');
272
+ const left = Fp.sqr(y); // y²
273
+ const right = weierstrassEquation(x); // x³ + ax + b
274
+ if (!Fp.eql(left, right))
275
+ throw new Error('bad point: equation left != right');
276
+ if (!p.isTorsionFree())
277
+ throw new Error('bad point: not in prime-order subgroup');
278
+ return true;
279
+ });
176
280
  /**
177
281
  * Projective Point works in 3d / projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
178
282
  * Default Point works in 2d / affine coordinates: (x, y)
@@ -189,6 +293,7 @@ function weierstrassPoints(opts) {
189
293
  throw new Error('y required');
190
294
  if (pz == null || !Fp.isValid(pz))
191
295
  throw new Error('z required');
296
+ Object.freeze(this);
192
297
  }
193
298
  // Does not validate if the point is on-curve.
194
299
  // Use fromHex instead, or call assertValidity() later.
@@ -233,32 +338,17 @@ function weierstrassPoints(opts) {
233
338
  static fromPrivateKey(privateKey) {
234
339
  return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
235
340
  }
341
+ // Multiscalar Multiplication
342
+ static msm(points, scalars) {
343
+ return (0, curve_js_1.pippenger)(Point, Fn, points, scalars);
344
+ }
236
345
  // "Private method", don't use it directly
237
346
  _setWindowSize(windowSize) {
238
- this._WINDOW_SIZE = windowSize;
239
- pointPrecomputes.delete(this);
347
+ wnaf.setWindowSize(this, windowSize);
240
348
  }
241
349
  // A point on curve is valid if it conforms to equation.
242
350
  assertValidity() {
243
- if (this.is0()) {
244
- // (0, 1, 0) aka ZERO is invalid in most contexts.
245
- // In BLS, ZERO can be serialized, so we allow it.
246
- // (0, 0, 0) is wrong representation of ZERO and is always invalid.
247
- if (CURVE.allowInfinityPoint && !Fp.is0(this.py))
248
- return;
249
- throw new Error('bad point: ZERO');
250
- }
251
- // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
252
- const { x, y } = this.toAffine();
253
- // Check if x, y are valid field elements
254
- if (!Fp.isValid(x) || !Fp.isValid(y))
255
- throw new Error('bad point: x or y not FE');
256
- const left = Fp.sqr(y); // y²
257
- const right = weierstrassEquation(x); // x³ + ax + b
258
- if (!Fp.eql(left, right))
259
- throw new Error('bad point: equation left != right');
260
- if (!this.isTorsionFree())
261
- throw new Error('bad point: not in prime-order subgroup');
351
+ assertValidMemo(this);
262
352
  }
263
353
  hasEvenY() {
264
354
  const { y } = this.toAffine();
@@ -385,28 +475,25 @@ function weierstrassPoints(opts) {
385
475
  return this.equals(Point.ZERO);
386
476
  }
387
477
  wNAF(n) {
388
- return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => {
389
- const toInv = Fp.invertBatch(comp.map((p) => p.pz));
390
- return comp.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
391
- });
478
+ return wnaf.wNAFCached(this, n, Point.normalizeZ);
392
479
  }
393
480
  /**
394
481
  * Non-constant-time multiplication. Uses double-and-add algorithm.
395
482
  * It's faster, but should only be used when you don't care about
396
483
  * an exposed private key e.g. sig verification, which works over *public* keys.
397
484
  */
398
- multiplyUnsafe(n) {
485
+ multiplyUnsafe(sc) {
486
+ ut.aInRange('scalar', sc, _0n, CURVE.n);
399
487
  const I = Point.ZERO;
400
- if (n === _0n)
488
+ if (sc === _0n)
401
489
  return I;
402
- assertGE(n); // Will throw on 0
403
- if (n === _1n)
490
+ if (sc === _1n)
404
491
  return this;
405
492
  const { endo } = CURVE;
406
493
  if (!endo)
407
- return wnaf.unsafeLadder(this, n);
494
+ return wnaf.unsafeLadder(this, sc);
408
495
  // Apply endomorphism
409
- let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
496
+ let { k1neg, k1, k2neg, k2 } = endo.splitScalar(sc);
410
497
  let k1p = I;
411
498
  let k2p = I;
412
499
  let d = this;
@@ -436,12 +523,11 @@ function weierstrassPoints(opts) {
436
523
  * @returns New point
437
524
  */
438
525
  multiply(scalar) {
439
- assertGE(scalar);
440
- let n = scalar;
526
+ const { endo, n: N } = CURVE;
527
+ ut.aInRange('scalar', scalar, _1n, N);
441
528
  let point, fake; // Fake point is used to const-time mult
442
- const { endo } = CURVE;
443
529
  if (endo) {
444
- const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
530
+ const { k1neg, k1, k2neg, k2 } = endo.splitScalar(scalar);
445
531
  let { p: k1p, f: f1p } = this.wNAF(k1);
446
532
  let { p: k2p, f: f2p } = this.wNAF(k2);
447
533
  k1p = wnaf.constTimeNegate(k1neg, k1p);
@@ -451,7 +537,7 @@ function weierstrassPoints(opts) {
451
537
  fake = f1p.add(f2p);
452
538
  }
453
539
  else {
454
- const { p, f } = this.wNAF(n);
540
+ const { p, f } = this.wNAF(scalar);
455
541
  point = p;
456
542
  fake = f;
457
543
  }
@@ -475,20 +561,7 @@ function weierstrassPoints(opts) {
475
561
  // Can accept precomputed Z^-1 - for example, from invertBatch.
476
562
  // (x, y, z) ∋ (x=x/z, y=y/z)
477
563
  toAffine(iz) {
478
- const { px: x, py: y, pz: z } = this;
479
- const is0 = this.is0();
480
- // If invZ was 0, we return zero point. However we still want to execute
481
- // all operations, so we replace invZ with a random number, 1.
482
- if (iz == null)
483
- iz = is0 ? Fp.ONE : Fp.inv(z);
484
- const ax = Fp.mul(x, iz);
485
- const ay = Fp.mul(y, iz);
486
- const zz = Fp.mul(z, iz);
487
- if (is0)
488
- return { x: Fp.ZERO, y: Fp.ZERO };
489
- if (!Fp.eql(zz, Fp.ONE))
490
- throw new Error('invZ was invalid');
491
- return { x: ax, y: ay };
564
+ return toAffineMemo(this, iz);
492
565
  }
493
566
  isTorsionFree() {
494
567
  const { h: cofactor, isTorsionFree } = CURVE;
@@ -507,10 +580,12 @@ function weierstrassPoints(opts) {
507
580
  return this.multiplyUnsafe(CURVE.h);
508
581
  }
509
582
  toRawBytes(isCompressed = true) {
583
+ (0, utils_js_1.abool)('isCompressed', isCompressed);
510
584
  this.assertValidity();
511
585
  return toBytes(Point, this, isCompressed);
512
586
  }
513
587
  toHex(isCompressed = true) {
588
+ (0, utils_js_1.abool)('isCompressed', isCompressed);
514
589
  return ut.bytesToHex(this.toRawBytes(isCompressed));
515
590
  }
516
591
  }
@@ -540,14 +615,18 @@ function validateOpts(curve) {
540
615
  });
541
616
  return Object.freeze({ lowS: true, ...opts });
542
617
  }
618
+ /**
619
+ * Creates short weierstrass curve and ECDSA signature methods for it.
620
+ * @example
621
+ * import { Field } from '@noble/curves/abstract/modular';
622
+ * // Before that, define BigInt-s: a, b, p, n, Gx, Gy
623
+ * const curve = weierstrass({ a, b, Fp: Field(p), n, Gx, Gy, h: 1n })
624
+ */
543
625
  function weierstrass(curveDef) {
544
626
  const CURVE = validateOpts(curveDef);
545
627
  const { Fp, n: CURVE_ORDER } = CURVE;
546
628
  const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
547
629
  const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
548
- function isValidFieldElement(num) {
549
- return _0n < num && num < Fp.ORDER; // 0 is banned since it's not invertible FE
550
- }
551
630
  function modN(a) {
552
631
  return mod.mod(a, CURVE_ORDER);
553
632
  }
@@ -560,6 +639,7 @@ function weierstrass(curveDef) {
560
639
  const a = point.toAffine();
561
640
  const x = Fp.toBytes(a.x);
562
641
  const cat = ut.concatBytes;
642
+ (0, utils_js_1.abool)('isCompressed', isCompressed);
563
643
  if (isCompressed) {
564
644
  return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
565
645
  }
@@ -574,7 +654,7 @@ function weierstrass(curveDef) {
574
654
  // this.assertValidity() is done inside of fromHex
575
655
  if (len === compressedLen && (head === 0x02 || head === 0x03)) {
576
656
  const x = ut.bytesToNumberBE(tail);
577
- if (!isValidFieldElement(x))
657
+ if (!ut.inRange(x, _1n, Fp.ORDER))
578
658
  throw new Error('Point is not on curve');
579
659
  const y2 = weierstrassEquation(x); // y² = x³ + ax + b
580
660
  let y;
@@ -635,11 +715,8 @@ function weierstrass(curveDef) {
635
715
  return new Signature(r, s);
636
716
  }
637
717
  assertValidity() {
638
- // can use assertGE here
639
- if (!isWithinCurveOrder(this.r))
640
- throw new Error('r must be 0 < r < CURVE.n');
641
- if (!isWithinCurveOrder(this.s))
642
- throw new Error('s must be 0 < s < CURVE.n');
718
+ ut.aInRange('r', this.r, _1n, CURVE_ORDER); // r in [1..N]
719
+ ut.aInRange('s', this.s, _1n, CURVE_ORDER); // s in [1..N]
643
720
  }
644
721
  addRecoveryBit(recovery) {
645
722
  return new Signature(this.r, this.s, recovery);
@@ -782,10 +859,7 @@ function weierstrass(curveDef) {
782
859
  * Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
783
860
  */
784
861
  function int2octets(num) {
785
- if (typeof num !== 'bigint')
786
- throw new Error('bigint expected');
787
- if (!(_0n <= num && num < ORDER_MASK))
788
- throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
862
+ ut.aInRange(`num < 2^${CURVE.nBitLength}`, num, _0n, ORDER_MASK);
789
863
  // works with order, can have different size than numToField!
790
864
  return ut.numberToBytesBE(num, CURVE.nByteLength);
791
865
  }
@@ -802,6 +876,7 @@ function weierstrass(curveDef) {
802
876
  if (lowS == null)
803
877
  lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
804
878
  msgHash = (0, utils_js_1.ensureBytes)('msgHash', msgHash);
879
+ validateSigVerOpts(opts);
805
880
  if (prehash)
806
881
  msgHash = (0, utils_js_1.ensureBytes)('prehashed msgHash', hash(msgHash));
807
882
  // We can't later call bits2octets, since nested bits2int is broken for curves
@@ -888,6 +963,7 @@ function weierstrass(curveDef) {
888
963
  publicKey = (0, utils_js_1.ensureBytes)('publicKey', publicKey);
889
964
  if ('strict' in opts)
890
965
  throw new Error('options.strict was renamed to lowS');
966
+ validateSigVerOpts(opts);
891
967
  const { lowS, prehash } = opts;
892
968
  let _sig = undefined;
893
969
  let P;