@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
@@ -1,9 +1,15 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  // Short Weierstrass curve. The formula is: y² = x³ + ax + b
3
- import { validateBasic, wNAF } from './curve.js';
3
+ import { validateBasic, wNAF, pippenger, } from './curve.js';
4
4
  import * as mod from './modular.js';
5
5
  import * as ut from './utils.js';
6
- import { ensureBytes } from './utils.js';
6
+ import { ensureBytes, memoized, abool } from './utils.js';
7
+ function validateSigVerOpts(opts) {
8
+ if (opts.lowS !== undefined)
9
+ abool('lowS', opts.lowS);
10
+ if (opts.prehash !== undefined)
11
+ abool('prehash', opts.prehash);
12
+ }
7
13
  function validatePointOpts(curve) {
8
14
  const opts = validateBasic(curve);
9
15
  ut.validateObject(opts, {
@@ -31,8 +37,14 @@ function validatePointOpts(curve) {
31
37
  }
32
38
  return Object.freeze({ ...opts });
33
39
  }
34
- // ASN.1 DER encoding utilities
35
40
  const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
41
+ /**
42
+ * ASN.1 DER encoding utilities. ASN is very complex & fragile. Format:
43
+ *
44
+ * [0x30 (SEQUENCE), bytelength, 0x02 (INTEGER), intLength, R, 0x02 (INTEGER), intLength, S]
45
+ *
46
+ * Docs: https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/, https://luca.ntop.org/Teaching/Appunti/asn1.html
47
+ */
36
48
  export const DER = {
37
49
  // asn.1 DER encoding utils
38
50
  Err: class DERErr extends Error {
@@ -40,54 +52,103 @@ export const DER = {
40
52
  super(m);
41
53
  }
42
54
  },
43
- _parseInt(data) {
44
- const { Err: E } = DER;
45
- if (data.length < 2 || data[0] !== 0x02)
46
- throw new E('Invalid signature integer tag');
47
- const len = data[1];
48
- const res = data.subarray(2, len + 2);
49
- if (!len || res.length !== len)
50
- throw new E('Invalid signature integer: wrong length');
51
- // https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
52
- // since we always use positive integers here. It must always be empty:
53
- // - add zero byte if exists
54
- // - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
55
- if (res[0] & 0b10000000)
56
- throw new E('Invalid signature integer: negative');
57
- if (res[0] === 0x00 && !(res[1] & 0b10000000))
58
- throw new E('Invalid signature integer: unnecessary leading zero');
59
- return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
55
+ // Basic building block is TLV (Tag-Length-Value)
56
+ _tlv: {
57
+ encode: (tag, data) => {
58
+ const { Err: E } = DER;
59
+ if (tag < 0 || tag > 256)
60
+ throw new E('tlv.encode: wrong tag');
61
+ if (data.length & 1)
62
+ throw new E('tlv.encode: unpadded data');
63
+ const dataLen = data.length / 2;
64
+ const len = ut.numberToHexUnpadded(dataLen);
65
+ if ((len.length / 2) & 128)
66
+ throw new E('tlv.encode: long form length too big');
67
+ // length of length with long form flag
68
+ const lenLen = dataLen > 127 ? ut.numberToHexUnpadded((len.length / 2) | 128) : '';
69
+ return `${ut.numberToHexUnpadded(tag)}${lenLen}${len}${data}`;
70
+ },
71
+ // v - value, l - left bytes (unparsed)
72
+ decode(tag, data) {
73
+ const { Err: E } = DER;
74
+ let pos = 0;
75
+ if (tag < 0 || tag > 256)
76
+ throw new E('tlv.encode: wrong tag');
77
+ if (data.length < 2 || data[pos++] !== tag)
78
+ throw new E('tlv.decode: wrong tlv');
79
+ const first = data[pos++];
80
+ const isLong = !!(first & 128); // First bit of first length byte is flag for short/long form
81
+ let length = 0;
82
+ if (!isLong)
83
+ length = first;
84
+ else {
85
+ // Long form: [longFlag(1bit), lengthLength(7bit), length (BE)]
86
+ const lenLen = first & 127;
87
+ if (!lenLen)
88
+ throw new E('tlv.decode(long): indefinite length not supported');
89
+ if (lenLen > 4)
90
+ throw new E('tlv.decode(long): byte length is too big'); // this will overflow u32 in js
91
+ const lengthBytes = data.subarray(pos, pos + lenLen);
92
+ if (lengthBytes.length !== lenLen)
93
+ throw new E('tlv.decode: length bytes not complete');
94
+ if (lengthBytes[0] === 0)
95
+ throw new E('tlv.decode(long): zero leftmost byte');
96
+ for (const b of lengthBytes)
97
+ length = (length << 8) | b;
98
+ pos += lenLen;
99
+ if (length < 128)
100
+ throw new E('tlv.decode(long): not minimal encoding');
101
+ }
102
+ const v = data.subarray(pos, pos + length);
103
+ if (v.length !== length)
104
+ throw new E('tlv.decode: wrong value length');
105
+ return { v, l: data.subarray(pos + length) };
106
+ },
107
+ },
108
+ // https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
109
+ // since we always use positive integers here. It must always be empty:
110
+ // - add zero byte if exists
111
+ // - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
112
+ _int: {
113
+ encode(num) {
114
+ const { Err: E } = DER;
115
+ if (num < _0n)
116
+ throw new E('integer: negative integers are not allowed');
117
+ let hex = ut.numberToHexUnpadded(num);
118
+ // Pad with zero byte if negative flag is present
119
+ if (Number.parseInt(hex[0], 16) & 0b1000)
120
+ hex = '00' + hex;
121
+ if (hex.length & 1)
122
+ throw new E('unexpected assertion');
123
+ return hex;
124
+ },
125
+ decode(data) {
126
+ const { Err: E } = DER;
127
+ if (data[0] & 128)
128
+ throw new E('Invalid signature integer: negative');
129
+ if (data[0] === 0x00 && !(data[1] & 128))
130
+ throw new E('Invalid signature integer: unnecessary leading zero');
131
+ return b2n(data);
132
+ },
60
133
  },
61
134
  toSig(hex) {
62
135
  // parse DER signature
63
- const { Err: E } = DER;
136
+ const { Err: E, _int: int, _tlv: tlv } = DER;
64
137
  const data = typeof hex === 'string' ? h2b(hex) : hex;
65
138
  ut.abytes(data);
66
- let l = data.length;
67
- if (l < 2 || data[0] != 0x30)
68
- throw new E('Invalid signature tag');
69
- if (data[1] !== l - 2)
70
- throw new E('Invalid signature: incorrect length');
71
- const { d: r, l: sBytes } = DER._parseInt(data.subarray(2));
72
- const { d: s, l: rBytesLeft } = DER._parseInt(sBytes);
73
- if (rBytesLeft.length)
139
+ const { v: seqBytes, l: seqLeftBytes } = tlv.decode(0x30, data);
140
+ if (seqLeftBytes.length)
141
+ throw new E('Invalid signature: left bytes after parsing');
142
+ const { v: rBytes, l: rLeftBytes } = tlv.decode(0x02, seqBytes);
143
+ const { v: sBytes, l: sLeftBytes } = tlv.decode(0x02, rLeftBytes);
144
+ if (sLeftBytes.length)
74
145
  throw new E('Invalid signature: left bytes after parsing');
75
- return { r, s };
146
+ return { r: int.decode(rBytes), s: int.decode(sBytes) };
76
147
  },
77
148
  hexFromSig(sig) {
78
- // Add leading zero if first byte has negative bit enabled. More details in '_parseInt'
79
- const slice = (s) => (Number.parseInt(s[0], 16) & 0b1000 ? '00' + s : s);
80
- const h = (num) => {
81
- const hex = num.toString(16);
82
- return hex.length & 1 ? `0${hex}` : hex;
83
- };
84
- const s = slice(h(sig.s));
85
- const r = slice(h(sig.r));
86
- const shl = s.length / 2;
87
- const rhl = r.length / 2;
88
- const sl = h(shl);
89
- const rl = h(rhl);
90
- return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;
149
+ const { _tlv: tlv, _int: int } = DER;
150
+ const seq = `${tlv.encode(0x02, int.encode(sig.r))}${tlv.encode(0x02, int.encode(sig.s))}`;
151
+ return tlv.encode(0x30, seq);
91
152
  },
92
153
  };
93
154
  // Be friendly to bad ECMAScript parsers by not using bigint literals
@@ -96,6 +157,7 @@ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n =
96
157
  export function weierstrassPoints(opts) {
97
158
  const CURVE = validatePointOpts(opts);
98
159
  const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
160
+ const Fn = mod.Field(CURVE.n, CURVE.nBitLength);
99
161
  const toBytes = CURVE.toBytes ||
100
162
  ((_c, point, _isCompressed) => {
101
163
  const a = point.toAffine();
@@ -128,16 +190,12 @@ export function weierstrassPoints(opts) {
128
190
  throw new Error('bad generator point: equation left != right');
129
191
  // Valid group elements reside in range 1..n-1
130
192
  function isWithinCurveOrder(num) {
131
- return typeof num === 'bigint' && _0n < num && num < CURVE.n;
132
- }
133
- function assertGE(num) {
134
- if (!isWithinCurveOrder(num))
135
- throw new Error('Expected valid bigint: 0 < bigint < curve.n');
193
+ return ut.inRange(num, _1n, CURVE.n);
136
194
  }
137
195
  // Validates if priv key is valid and converts it to bigint.
138
196
  // Supports options allowedPrivateKeyLengths and wrapPrivateKey.
139
197
  function normPrivateKeyToScalar(key) {
140
- const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
198
+ const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n: N } = CURVE;
141
199
  if (lengths && typeof key !== 'bigint') {
142
200
  if (ut.isBytes(key))
143
201
  key = ut.bytesToHex(key);
@@ -157,15 +215,61 @@ export function weierstrassPoints(opts) {
157
215
  throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
158
216
  }
159
217
  if (wrapPrivateKey)
160
- num = mod.mod(num, n); // disabled by default, enabled for BLS
161
- assertGE(num); // num in range [1..N-1]
218
+ num = mod.mod(num, N); // disabled by default, enabled for BLS
219
+ ut.aInRange('private key', num, _1n, N); // num in range [1..N-1]
162
220
  return num;
163
221
  }
164
- const pointPrecomputes = new Map();
165
222
  function assertPrjPoint(other) {
166
223
  if (!(other instanceof Point))
167
224
  throw new Error('ProjectivePoint expected');
168
225
  }
226
+ // Memoized toAffine / validity check. They are heavy. Points are immutable.
227
+ // Converts Projective point to affine (x, y) coordinates.
228
+ // Can accept precomputed Z^-1 - for example, from invertBatch.
229
+ // (x, y, z) ∋ (x=x/z, y=y/z)
230
+ const toAffineMemo = memoized((p, iz) => {
231
+ const { px: x, py: y, pz: z } = p;
232
+ // Fast-path for normalized points
233
+ if (Fp.eql(z, Fp.ONE))
234
+ return { x, y };
235
+ const is0 = p.is0();
236
+ // If invZ was 0, we return zero point. However we still want to execute
237
+ // all operations, so we replace invZ with a random number, 1.
238
+ if (iz == null)
239
+ iz = is0 ? Fp.ONE : Fp.inv(z);
240
+ const ax = Fp.mul(x, iz);
241
+ const ay = Fp.mul(y, iz);
242
+ const zz = Fp.mul(z, iz);
243
+ if (is0)
244
+ return { x: Fp.ZERO, y: Fp.ZERO };
245
+ if (!Fp.eql(zz, Fp.ONE))
246
+ throw new Error('invZ was invalid');
247
+ return { x: ax, y: ay };
248
+ });
249
+ // NOTE: on exception this will crash 'cached' and no value will be set.
250
+ // Otherwise true will be return
251
+ const assertValidMemo = memoized((p) => {
252
+ if (p.is0()) {
253
+ // (0, 1, 0) aka ZERO is invalid in most contexts.
254
+ // In BLS, ZERO can be serialized, so we allow it.
255
+ // (0, 0, 0) is wrong representation of ZERO and is always invalid.
256
+ if (CURVE.allowInfinityPoint && !Fp.is0(p.py))
257
+ return;
258
+ throw new Error('bad point: ZERO');
259
+ }
260
+ // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
261
+ const { x, y } = p.toAffine();
262
+ // Check if x, y are valid field elements
263
+ if (!Fp.isValid(x) || !Fp.isValid(y))
264
+ throw new Error('bad point: x or y not FE');
265
+ const left = Fp.sqr(y); // y²
266
+ const right = weierstrassEquation(x); // x³ + ax + b
267
+ if (!Fp.eql(left, right))
268
+ throw new Error('bad point: equation left != right');
269
+ if (!p.isTorsionFree())
270
+ throw new Error('bad point: not in prime-order subgroup');
271
+ return true;
272
+ });
169
273
  /**
170
274
  * Projective Point works in 3d / projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
171
275
  * Default Point works in 2d / affine coordinates: (x, y)
@@ -182,6 +286,7 @@ export function weierstrassPoints(opts) {
182
286
  throw new Error('y required');
183
287
  if (pz == null || !Fp.isValid(pz))
184
288
  throw new Error('z required');
289
+ Object.freeze(this);
185
290
  }
186
291
  // Does not validate if the point is on-curve.
187
292
  // Use fromHex instead, or call assertValidity() later.
@@ -226,32 +331,17 @@ export function weierstrassPoints(opts) {
226
331
  static fromPrivateKey(privateKey) {
227
332
  return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
228
333
  }
334
+ // Multiscalar Multiplication
335
+ static msm(points, scalars) {
336
+ return pippenger(Point, Fn, points, scalars);
337
+ }
229
338
  // "Private method", don't use it directly
230
339
  _setWindowSize(windowSize) {
231
- this._WINDOW_SIZE = windowSize;
232
- pointPrecomputes.delete(this);
340
+ wnaf.setWindowSize(this, windowSize);
233
341
  }
234
342
  // A point on curve is valid if it conforms to equation.
235
343
  assertValidity() {
236
- if (this.is0()) {
237
- // (0, 1, 0) aka ZERO is invalid in most contexts.
238
- // In BLS, ZERO can be serialized, so we allow it.
239
- // (0, 0, 0) is wrong representation of ZERO and is always invalid.
240
- if (CURVE.allowInfinityPoint && !Fp.is0(this.py))
241
- return;
242
- throw new Error('bad point: ZERO');
243
- }
244
- // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
245
- const { x, y } = this.toAffine();
246
- // Check if x, y are valid field elements
247
- if (!Fp.isValid(x) || !Fp.isValid(y))
248
- throw new Error('bad point: x or y not FE');
249
- const left = Fp.sqr(y); // y²
250
- const right = weierstrassEquation(x); // x³ + ax + b
251
- if (!Fp.eql(left, right))
252
- throw new Error('bad point: equation left != right');
253
- if (!this.isTorsionFree())
254
- throw new Error('bad point: not in prime-order subgroup');
344
+ assertValidMemo(this);
255
345
  }
256
346
  hasEvenY() {
257
347
  const { y } = this.toAffine();
@@ -378,28 +468,25 @@ export function weierstrassPoints(opts) {
378
468
  return this.equals(Point.ZERO);
379
469
  }
380
470
  wNAF(n) {
381
- return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => {
382
- const toInv = Fp.invertBatch(comp.map((p) => p.pz));
383
- return comp.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
384
- });
471
+ return wnaf.wNAFCached(this, n, Point.normalizeZ);
385
472
  }
386
473
  /**
387
474
  * Non-constant-time multiplication. Uses double-and-add algorithm.
388
475
  * It's faster, but should only be used when you don't care about
389
476
  * an exposed private key e.g. sig verification, which works over *public* keys.
390
477
  */
391
- multiplyUnsafe(n) {
478
+ multiplyUnsafe(sc) {
479
+ ut.aInRange('scalar', sc, _0n, CURVE.n);
392
480
  const I = Point.ZERO;
393
- if (n === _0n)
481
+ if (sc === _0n)
394
482
  return I;
395
- assertGE(n); // Will throw on 0
396
- if (n === _1n)
483
+ if (sc === _1n)
397
484
  return this;
398
485
  const { endo } = CURVE;
399
486
  if (!endo)
400
- return wnaf.unsafeLadder(this, n);
487
+ return wnaf.unsafeLadder(this, sc);
401
488
  // Apply endomorphism
402
- let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
489
+ let { k1neg, k1, k2neg, k2 } = endo.splitScalar(sc);
403
490
  let k1p = I;
404
491
  let k2p = I;
405
492
  let d = this;
@@ -429,12 +516,11 @@ export function weierstrassPoints(opts) {
429
516
  * @returns New point
430
517
  */
431
518
  multiply(scalar) {
432
- assertGE(scalar);
433
- let n = scalar;
519
+ const { endo, n: N } = CURVE;
520
+ ut.aInRange('scalar', scalar, _1n, N);
434
521
  let point, fake; // Fake point is used to const-time mult
435
- const { endo } = CURVE;
436
522
  if (endo) {
437
- const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
523
+ const { k1neg, k1, k2neg, k2 } = endo.splitScalar(scalar);
438
524
  let { p: k1p, f: f1p } = this.wNAF(k1);
439
525
  let { p: k2p, f: f2p } = this.wNAF(k2);
440
526
  k1p = wnaf.constTimeNegate(k1neg, k1p);
@@ -444,7 +530,7 @@ export function weierstrassPoints(opts) {
444
530
  fake = f1p.add(f2p);
445
531
  }
446
532
  else {
447
- const { p, f } = this.wNAF(n);
533
+ const { p, f } = this.wNAF(scalar);
448
534
  point = p;
449
535
  fake = f;
450
536
  }
@@ -468,20 +554,7 @@ export function weierstrassPoints(opts) {
468
554
  // Can accept precomputed Z^-1 - for example, from invertBatch.
469
555
  // (x, y, z) ∋ (x=x/z, y=y/z)
470
556
  toAffine(iz) {
471
- const { px: x, py: y, pz: z } = this;
472
- const is0 = this.is0();
473
- // If invZ was 0, we return zero point. However we still want to execute
474
- // all operations, so we replace invZ with a random number, 1.
475
- if (iz == null)
476
- iz = is0 ? Fp.ONE : Fp.inv(z);
477
- const ax = Fp.mul(x, iz);
478
- const ay = Fp.mul(y, iz);
479
- const zz = Fp.mul(z, iz);
480
- if (is0)
481
- return { x: Fp.ZERO, y: Fp.ZERO };
482
- if (!Fp.eql(zz, Fp.ONE))
483
- throw new Error('invZ was invalid');
484
- return { x: ax, y: ay };
557
+ return toAffineMemo(this, iz);
485
558
  }
486
559
  isTorsionFree() {
487
560
  const { h: cofactor, isTorsionFree } = CURVE;
@@ -500,10 +573,12 @@ export function weierstrassPoints(opts) {
500
573
  return this.multiplyUnsafe(CURVE.h);
501
574
  }
502
575
  toRawBytes(isCompressed = true) {
576
+ abool('isCompressed', isCompressed);
503
577
  this.assertValidity();
504
578
  return toBytes(Point, this, isCompressed);
505
579
  }
506
580
  toHex(isCompressed = true) {
581
+ abool('isCompressed', isCompressed);
507
582
  return ut.bytesToHex(this.toRawBytes(isCompressed));
508
583
  }
509
584
  }
@@ -533,14 +608,18 @@ function validateOpts(curve) {
533
608
  });
534
609
  return Object.freeze({ lowS: true, ...opts });
535
610
  }
611
+ /**
612
+ * Creates short weierstrass curve and ECDSA signature methods for it.
613
+ * @example
614
+ * import { Field } from '@noble/curves/abstract/modular';
615
+ * // Before that, define BigInt-s: a, b, p, n, Gx, Gy
616
+ * const curve = weierstrass({ a, b, Fp: Field(p), n, Gx, Gy, h: 1n })
617
+ */
536
618
  export function weierstrass(curveDef) {
537
619
  const CURVE = validateOpts(curveDef);
538
620
  const { Fp, n: CURVE_ORDER } = CURVE;
539
621
  const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
540
622
  const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
541
- function isValidFieldElement(num) {
542
- return _0n < num && num < Fp.ORDER; // 0 is banned since it's not invertible FE
543
- }
544
623
  function modN(a) {
545
624
  return mod.mod(a, CURVE_ORDER);
546
625
  }
@@ -553,6 +632,7 @@ export function weierstrass(curveDef) {
553
632
  const a = point.toAffine();
554
633
  const x = Fp.toBytes(a.x);
555
634
  const cat = ut.concatBytes;
635
+ abool('isCompressed', isCompressed);
556
636
  if (isCompressed) {
557
637
  return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
558
638
  }
@@ -567,7 +647,7 @@ export function weierstrass(curveDef) {
567
647
  // this.assertValidity() is done inside of fromHex
568
648
  if (len === compressedLen && (head === 0x02 || head === 0x03)) {
569
649
  const x = ut.bytesToNumberBE(tail);
570
- if (!isValidFieldElement(x))
650
+ if (!ut.inRange(x, _1n, Fp.ORDER))
571
651
  throw new Error('Point is not on curve');
572
652
  const y2 = weierstrassEquation(x); // y² = x³ + ax + b
573
653
  let y;
@@ -628,11 +708,8 @@ export function weierstrass(curveDef) {
628
708
  return new Signature(r, s);
629
709
  }
630
710
  assertValidity() {
631
- // can use assertGE here
632
- if (!isWithinCurveOrder(this.r))
633
- throw new Error('r must be 0 < r < CURVE.n');
634
- if (!isWithinCurveOrder(this.s))
635
- throw new Error('s must be 0 < s < CURVE.n');
711
+ ut.aInRange('r', this.r, _1n, CURVE_ORDER); // r in [1..N]
712
+ ut.aInRange('s', this.s, _1n, CURVE_ORDER); // s in [1..N]
636
713
  }
637
714
  addRecoveryBit(recovery) {
638
715
  return new Signature(this.r, this.s, recovery);
@@ -775,10 +852,7 @@ export function weierstrass(curveDef) {
775
852
  * Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
776
853
  */
777
854
  function int2octets(num) {
778
- if (typeof num !== 'bigint')
779
- throw new Error('bigint expected');
780
- if (!(_0n <= num && num < ORDER_MASK))
781
- throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
855
+ ut.aInRange(`num < 2^${CURVE.nBitLength}`, num, _0n, ORDER_MASK);
782
856
  // works with order, can have different size than numToField!
783
857
  return ut.numberToBytesBE(num, CURVE.nByteLength);
784
858
  }
@@ -795,6 +869,7 @@ export function weierstrass(curveDef) {
795
869
  if (lowS == null)
796
870
  lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
797
871
  msgHash = ensureBytes('msgHash', msgHash);
872
+ validateSigVerOpts(opts);
798
873
  if (prehash)
799
874
  msgHash = ensureBytes('prehashed msgHash', hash(msgHash));
800
875
  // We can't later call bits2octets, since nested bits2int is broken for curves
@@ -881,6 +956,7 @@ export function weierstrass(curveDef) {
881
956
  publicKey = ensureBytes('publicKey', publicKey);
882
957
  if ('strict' in opts)
883
958
  throw new Error('options.strict was renamed to lowS');
959
+ validateSigVerOpts(opts);
884
960
  const { lowS, prehash } = opts;
885
961
  let _sig = undefined;
886
962
  let P;