@noble/curves 1.4.2 → 1.5.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 (116) hide show
  1. package/README.md +135 -123
  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 +2 -1
  8. package/abstract/curve.d.ts.map +1 -1
  9. package/abstract/curve.js +22 -7
  10. package/abstract/curve.js.map +1 -1
  11. package/abstract/edwards.d.ts +11 -0
  12. package/abstract/edwards.d.ts.map +1 -1
  13. package/abstract/edwards.js +79 -75
  14. package/abstract/edwards.js.map +1 -1
  15. package/abstract/modular.d.ts +4 -0
  16. package/abstract/modular.d.ts.map +1 -1
  17. package/abstract/modular.js +13 -2
  18. package/abstract/modular.js.map +1 -1
  19. package/abstract/montgomery.d.ts.map +1 -1
  20. package/abstract/montgomery.js +4 -9
  21. package/abstract/montgomery.js.map +1 -1
  22. package/abstract/tower.d.ts +106 -0
  23. package/abstract/tower.d.ts.map +1 -0
  24. package/abstract/tower.js +497 -0
  25. package/abstract/tower.js.map +1 -0
  26. package/abstract/utils.d.ts +17 -0
  27. package/abstract/utils.d.ts.map +1 -1
  28. package/abstract/utils.js +50 -1
  29. package/abstract/utils.js.map +1 -1
  30. package/abstract/weierstrass.d.ts +7 -0
  31. package/abstract/weierstrass.d.ts.map +1 -1
  32. package/abstract/weierstrass.js +88 -72
  33. package/abstract/weierstrass.js.map +1 -1
  34. package/bls12-381.d.ts +1 -65
  35. package/bls12-381.d.ts.map +1 -1
  36. package/bls12-381.js +48 -575
  37. package/bls12-381.js.map +1 -1
  38. package/bn254.d.ts +10 -6
  39. package/bn254.d.ts.map +1 -1
  40. package/bn254.js +207 -10
  41. package/bn254.js.map +1 -1
  42. package/ed25519.d.ts +7 -4
  43. package/ed25519.d.ts.map +1 -1
  44. package/ed25519.js +3 -0
  45. package/ed25519.js.map +1 -1
  46. package/esm/_shortw_utils.d.ts.map +1 -1
  47. package/esm/abstract/bls.d.ts +37 -34
  48. package/esm/abstract/bls.d.ts.map +1 -1
  49. package/esm/abstract/bls.js +168 -116
  50. package/esm/abstract/bls.js.map +1 -1
  51. package/esm/abstract/curve.d.ts +2 -1
  52. package/esm/abstract/curve.d.ts.map +1 -1
  53. package/esm/abstract/curve.js +22 -7
  54. package/esm/abstract/curve.js.map +1 -1
  55. package/esm/abstract/edwards.d.ts +11 -0
  56. package/esm/abstract/edwards.d.ts.map +1 -1
  57. package/esm/abstract/edwards.js +80 -76
  58. package/esm/abstract/edwards.js.map +1 -1
  59. package/esm/abstract/modular.d.ts +4 -0
  60. package/esm/abstract/modular.d.ts.map +1 -1
  61. package/esm/abstract/modular.js +12 -2
  62. package/esm/abstract/modular.js.map +1 -1
  63. package/esm/abstract/montgomery.d.ts.map +1 -1
  64. package/esm/abstract/montgomery.js +5 -10
  65. package/esm/abstract/montgomery.js.map +1 -1
  66. package/esm/abstract/tower.d.ts +106 -0
  67. package/esm/abstract/tower.d.ts.map +1 -0
  68. package/esm/abstract/tower.js +493 -0
  69. package/esm/abstract/tower.js.map +1 -0
  70. package/esm/abstract/utils.d.ts +17 -0
  71. package/esm/abstract/utils.d.ts.map +1 -1
  72. package/esm/abstract/utils.js +44 -0
  73. package/esm/abstract/utils.js.map +1 -1
  74. package/esm/abstract/weierstrass.d.ts +7 -0
  75. package/esm/abstract/weierstrass.d.ts.map +1 -1
  76. package/esm/abstract/weierstrass.js +89 -73
  77. package/esm/abstract/weierstrass.js.map +1 -1
  78. package/esm/bls12-381.d.ts +1 -65
  79. package/esm/bls12-381.d.ts.map +1 -1
  80. package/esm/bls12-381.js +50 -577
  81. package/esm/bls12-381.js.map +1 -1
  82. package/esm/bn254.d.ts +10 -6
  83. package/esm/bn254.d.ts.map +1 -1
  84. package/esm/bn254.js +206 -9
  85. package/esm/bn254.js.map +1 -1
  86. package/esm/ed25519.d.ts +7 -4
  87. package/esm/ed25519.d.ts.map +1 -1
  88. package/esm/ed25519.js +3 -0
  89. package/esm/ed25519.js.map +1 -1
  90. package/esm/p256.d.ts.map +1 -1
  91. package/esm/p384.d.ts.map +1 -1
  92. package/esm/p521.d.ts.map +1 -1
  93. package/esm/secp256k1.d.ts +6 -0
  94. package/esm/secp256k1.d.ts.map +1 -1
  95. package/esm/secp256k1.js +17 -13
  96. package/esm/secp256k1.js.map +1 -1
  97. package/p256.d.ts.map +1 -1
  98. package/p384.d.ts.map +1 -1
  99. package/p521.d.ts.map +1 -1
  100. package/package.json +2 -1
  101. package/secp256k1.d.ts +6 -0
  102. package/secp256k1.d.ts.map +1 -1
  103. package/secp256k1.js +16 -12
  104. package/secp256k1.js.map +1 -1
  105. package/src/abstract/bls.ts +222 -168
  106. package/src/abstract/curve.ts +23 -7
  107. package/src/abstract/edwards.ts +81 -68
  108. package/src/abstract/modular.ts +13 -3
  109. package/src/abstract/montgomery.ts +11 -10
  110. package/src/abstract/tower.ts +604 -0
  111. package/src/abstract/utils.ts +49 -0
  112. package/src/abstract/weierstrass.ts +85 -68
  113. package/src/bls12-381.ts +53 -707
  114. package/src/bn254.ts +224 -9
  115. package/src/ed25519.ts +5 -2
  116. package/src/secp256k1.ts +24 -12
@@ -3,7 +3,7 @@
3
3
  import { AffinePoint, BasicCurve, Group, GroupConstructor, validateBasic, wNAF } from './curve.js';
4
4
  import { mod } from './modular.js';
5
5
  import * as ut from './utils.js';
6
- import { ensureBytes, FHash, Hex } from './utils.js';
6
+ import { ensureBytes, FHash, Hex, memoized, abool } from './utils.js';
7
7
 
8
8
  // Be friendly to bad ECMAScript parsers by not using bigint literals
9
9
  // prettier-ignore
@@ -72,6 +72,10 @@ export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
72
72
  fromPrivateKey(privateKey: Hex): ExtPointType;
73
73
  }
74
74
 
75
+ /**
76
+ * Edwards Curve interface.
77
+ * Main methods: `getPublicKey(priv)`, `sign(msg, priv)`, `verify(sig, msg, pub)`.
78
+ */
75
79
  export type CurveFn = {
76
80
  CURVE: ReturnType<typeof validateOpts>;
77
81
  getPublicKey: (privateKey: Hex) => Uint8Array;
@@ -95,7 +99,13 @@ export type CurveFn = {
95
99
  };
96
100
  };
97
101
 
98
- // It is not generic twisted curve for now, but ed25519/ed448 generic implementation
102
+ /**
103
+ * Creates Twisted Edwards curve with EdDSA signatures.
104
+ * @example
105
+ * import { Field } from '@noble/curves/abstract/modular';
106
+ * // Before that, define BigInt-s: a, d, p, n, Gx, Gy, h
107
+ * const curve = twistedEdwards({ a, d, Fp: Field(p), n, Gx, Gy, h })
108
+ */
99
109
  export function twistedEdwards(curveDef: CurveType): CurveFn {
100
110
  const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
101
111
  const {
@@ -124,25 +134,53 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
124
134
  const domain =
125
135
  CURVE.domain ||
126
136
  ((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
137
+ abool('phflag', phflag);
127
138
  if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
128
139
  return data;
129
140
  }); // NOOP
130
- const inBig = (n: bigint) => typeof n === 'bigint' && _0n < n; // n in [1..]
131
- const inRange = (n: bigint, max: bigint) => inBig(n) && inBig(max) && n < max; // n in [1..max-1]
132
- const in0MaskRange = (n: bigint) => n === _0n || inRange(n, MASK); // n in [0..MASK-1]
133
- function assertInRange(n: bigint, max: bigint) {
134
- // n in [1..max-1]
135
- if (inRange(n, max)) return n;
136
- throw new Error(`Expected valid scalar < ${max}, got ${typeof n} ${n}`);
141
+ // 0 <= n < MASK
142
+ // Coordinates larger than Fp.ORDER are allowed for zip215
143
+ function aCoordinate(title: string, n: bigint) {
144
+ ut.aInRange('coordinate ' + title, n, _0n, MASK);
137
145
  }
138
- function assertGE0(n: bigint) {
139
- // n in [0..CURVE_ORDER-1]
140
- return n === _0n ? n : assertInRange(n, CURVE_ORDER); // GE = prime subgroup, not full group
141
- }
142
- const pointPrecomputes = new Map<Point, Point[]>();
143
- function isPoint(other: unknown) {
146
+
147
+ function assertPoint(other: unknown) {
144
148
  if (!(other instanceof Point)) throw new Error('ExtendedPoint expected');
145
149
  }
150
+ // Converts Extended point to default (x, y) coordinates.
151
+ // Can accept precomputed Z^-1 - for example, from invertBatch.
152
+ const toAffineMemo = memoized((p: Point, iz?: bigint): AffinePoint<bigint> => {
153
+ const { ex: x, ey: y, ez: z } = p;
154
+ const is0 = p.is0();
155
+ if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily
156
+ const ax = modP(x * iz);
157
+ const ay = modP(y * iz);
158
+ const zz = modP(z * iz);
159
+ if (is0) return { x: _0n, y: _1n };
160
+ if (zz !== _1n) throw new Error('invZ was invalid');
161
+ return { x: ax, y: ay };
162
+ });
163
+ const assertValidMemo = memoized((p: Point) => {
164
+ const { a, d } = CURVE;
165
+ if (p.is0()) throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
166
+ // Equation in affine coordinates: ax² + y² = 1 + dx²y²
167
+ // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
168
+ const { ex: X, ey: Y, ez: Z, et: T } = p;
169
+ const X2 = modP(X * X); // X²
170
+ const Y2 = modP(Y * Y); // Y²
171
+ const Z2 = modP(Z * Z); // Z²
172
+ const Z4 = modP(Z2 * Z2); // Z⁴
173
+ const aX2 = modP(X2 * a); // aX²
174
+ const left = modP(Z2 * modP(aX2 + Y2)); // (aX² + Y²)Z²
175
+ const right = modP(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²
176
+ if (left !== right) throw new Error('bad point: equation left != right (1)');
177
+ // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
178
+ const XY = modP(X * Y);
179
+ const ZT = modP(Z * T);
180
+ if (XY !== ZT) throw new Error('bad point: equation left != right (2)');
181
+ return true;
182
+ });
183
+
146
184
  // Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
147
185
  // https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
148
186
  class Point implements ExtPointType {
@@ -155,10 +193,11 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
155
193
  readonly ez: bigint,
156
194
  readonly et: bigint
157
195
  ) {
158
- if (!in0MaskRange(ex)) throw new Error('x required');
159
- if (!in0MaskRange(ey)) throw new Error('y required');
160
- if (!in0MaskRange(ez)) throw new Error('z required');
161
- if (!in0MaskRange(et)) throw new Error('t required');
196
+ aCoordinate('x', ex);
197
+ aCoordinate('y', ey);
198
+ aCoordinate('z', ez);
199
+ aCoordinate('t', et);
200
+ Object.freeze(this);
162
201
  }
163
202
 
164
203
  get x(): bigint {
@@ -171,7 +210,8 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
171
210
  static fromAffine(p: AffinePoint<bigint>): Point {
172
211
  if (p instanceof Point) throw new Error('extended point not allowed');
173
212
  const { x, y } = p || {};
174
- if (!in0MaskRange(x) || !in0MaskRange(y)) throw new Error('invalid affine point');
213
+ aCoordinate('x', x);
214
+ aCoordinate('y', y);
175
215
  return new Point(x, y, _1n, modP(x * y));
176
216
  }
177
217
  static normalizeZ(points: Point[]): Point[] {
@@ -179,41 +219,19 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
179
219
  return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
180
220
  }
181
221
 
182
- // We calculate precomputes for elliptic curve point multiplication
183
- // using windowed method. This specifies window size and
184
- // stores precomputed values. Usually only base point would be precomputed.
185
- _WINDOW_SIZE?: number;
186
-
187
222
  // "Private method", don't use it directly
188
223
  _setWindowSize(windowSize: number) {
189
- this._WINDOW_SIZE = windowSize;
190
- pointPrecomputes.delete(this);
224
+ wnaf.setWindowSize(this, windowSize);
191
225
  }
192
226
  // Not required for fromHex(), which always creates valid points.
193
227
  // Could be useful for fromAffine().
194
228
  assertValidity(): void {
195
- const { a, d } = CURVE;
196
- if (this.is0()) throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
197
- // Equation in affine coordinates: ax² + y² = 1 + dx²y²
198
- // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
199
- const { ex: X, ey: Y, ez: Z, et: T } = this;
200
- const X2 = modP(X * X); // X²
201
- const Y2 = modP(Y * Y); // Y²
202
- const Z2 = modP(Z * Z); // Z²
203
- const Z4 = modP(Z2 * Z2); // Z⁴
204
- const aX2 = modP(X2 * a); // aX²
205
- const left = modP(Z2 * modP(aX2 + Y2)); // (aX² + Y²)Z²
206
- const right = modP(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²
207
- if (left !== right) throw new Error('bad point: equation left != right (1)');
208
- // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
209
- const XY = modP(X * Y);
210
- const ZT = modP(Z * T);
211
- if (XY !== ZT) throw new Error('bad point: equation left != right (2)');
229
+ assertValidMemo(this);
212
230
  }
213
231
 
214
232
  // Compare one point to another.
215
233
  equals(other: Point): boolean {
216
- isPoint(other);
234
+ assertPoint(other);
217
235
  const { ex: X1, ey: Y1, ez: Z1 } = this;
218
236
  const { ex: X2, ey: Y2, ez: Z2 } = other;
219
237
  const X1Z2 = modP(X1 * Z2);
@@ -223,7 +241,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
223
241
  return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
224
242
  }
225
243
 
226
- protected is0(): boolean {
244
+ is0(): boolean {
227
245
  return this.equals(Point.ZERO);
228
246
  }
229
247
 
@@ -258,7 +276,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
258
276
  // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd
259
277
  // Cost: 9M + 1*a + 1*d + 7add.
260
278
  add(other: Point) {
261
- isPoint(other);
279
+ assertPoint(other);
262
280
  const { a, d } = CURVE;
263
281
  const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
264
282
  const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other;
@@ -303,12 +321,14 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
303
321
  }
304
322
 
305
323
  private wNAF(n: bigint): { p: Point; f: Point } {
306
- return wnaf.wNAFCached(this, pointPrecomputes, n, Point.normalizeZ);
324
+ return wnaf.wNAFCached(this, n, Point.normalizeZ);
307
325
  }
308
326
 
309
327
  // Constant-time multiplication.
310
328
  multiply(scalar: bigint): Point {
311
- const { p, f } = this.wNAF(assertInRange(scalar, CURVE_ORDER));
329
+ const n = scalar;
330
+ ut.aInRange('scalar', n, _1n, CURVE_ORDER); // 1 <= scalar < L
331
+ const { p, f } = this.wNAF(n);
312
332
  return Point.normalizeZ([p, f])[0];
313
333
  }
314
334
 
@@ -317,7 +337,8 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
317
337
  // an exposed private key e.g. sig verification.
318
338
  // Does NOT allow scalars higher than CURVE.n.
319
339
  multiplyUnsafe(scalar: bigint): Point {
320
- let n = assertGE0(scalar); // 0 <= scalar < CURVE.n
340
+ const n = scalar;
341
+ ut.aInRange('scalar', n, _0n, CURVE_ORDER); // 0 <= scalar < L
321
342
  if (n === _0n) return I;
322
343
  if (this.equals(I) || n === _1n) return this;
323
344
  if (this.equals(G)) return this.wNAF(n).p;
@@ -341,15 +362,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
341
362
  // Converts Extended point to default (x, y) coordinates.
342
363
  // Can accept precomputed Z^-1 - for example, from invertBatch.
343
364
  toAffine(iz?: bigint): AffinePoint<bigint> {
344
- const { ex: x, ey: y, ez: z } = this;
345
- const is0 = this.is0();
346
- if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily
347
- const ax = modP(x * iz);
348
- const ay = modP(y * iz);
349
- const zz = modP(z * iz);
350
- if (is0) return { x: _0n, y: _1n };
351
- if (zz !== _1n) throw new Error('invZ was invalid');
352
- return { x: ax, y: ay };
365
+ return toAffineMemo(this, iz);
353
366
  }
354
367
 
355
368
  clearCofactor(): Point {
@@ -364,18 +377,17 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
364
377
  const { d, a } = CURVE;
365
378
  const len = Fp.BYTES;
366
379
  hex = ensureBytes('pointHex', hex, len); // copy hex to a new array
380
+ abool('zip215', zip215);
367
381
  const normed = hex.slice(); // copy again, we'll manipulate it
368
382
  const lastByte = hex[len - 1]; // select last byte
369
383
  normed[len - 1] = lastByte & ~0x80; // clear last bit
370
384
  const y = ut.bytesToNumberLE(normed);
371
- if (y === _0n) {
372
- // y=0 is allowed
373
- } else {
374
- // RFC8032 prohibits >= p, but ZIP215 doesn't
375
- if (zip215)
376
- assertInRange(y, MASK); // zip215=true [1..P-1] (2^255-19-1 for ed25519)
377
- else assertInRange(y, Fp.ORDER); // zip215=false [1..MASK-1] (2^256-1 for ed25519)
378
- }
385
+
386
+ // RFC8032 prohibits >= p, but ZIP215 doesn't
387
+ // zip215=true: 0 <= y < MASK (2^256 for ed25519)
388
+ // zip215=false: 0 <= y < P (2^255-19 for ed25519)
389
+ const max = zip215 ? MASK : Fp.ORDER;
390
+ ut.aInRange('pointHex.y', y, _0n, max);
379
391
 
380
392
  // Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
381
393
  // ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)
@@ -451,7 +463,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
451
463
  const R = G.multiply(r).toRawBytes(); // R = rG
452
464
  const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
453
465
  const s = modN(r + k * scalar); // S = (r + k * s) mod L
454
- assertGE0(s); // 0 <= s < l
466
+ ut.aInRange('signature.s', s, _0n, CURVE_ORDER); // 0 <= s < l
455
467
  const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));
456
468
  return ensureBytes('result', res, nByteLength * 2); // 64-byte signature
457
469
  }
@@ -462,6 +474,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
462
474
  const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
463
475
  sig = ensureBytes('signature', sig, 2 * len); // An extended group equation is checked.
464
476
  msg = ensureBytes('message', msg);
477
+ if (zip215 !== undefined) abool('zip215', zip215);
465
478
  if (prehash) msg = prehash(msg); // for ed25519ph, etc
466
479
 
467
480
  const s = ut.bytesToNumberLE(sig.slice(len, 2 * len));
@@ -195,7 +195,6 @@ export function FpSqrt(P: bigint) {
195
195
  // return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
196
196
  // }
197
197
  }
198
-
199
198
  // Other cases: Tonelli-Shanks algorithm
200
199
  return tonelliShanks(P);
201
200
  }
@@ -314,11 +313,19 @@ export function FpDiv<T>(f: IField<T>, lhs: T, rhs: T | bigint): T {
314
313
  return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
315
314
  }
316
315
 
316
+ export function FpLegendre(order: bigint) {
317
+ // (a | p) ≡ 1 if a is a square (mod p), quadratic residue
318
+ // (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
319
+ // (a | p) ≡ 0 if a ≡ 0 (mod p)
320
+ const legendreConst = (order - _1n) / _2n; // Integer arithmetic
321
+ return <T>(f: IField<T>, x: T): T => f.pow(x, legendreConst);
322
+ }
323
+
317
324
  // This function returns True whenever the value x is a square in the field F.
318
325
  export function FpIsSquare<T>(f: IField<T>) {
319
- const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
326
+ const legendre = FpLegendre(f.ORDER);
320
327
  return (x: T): boolean => {
321
- const p = f.pow(x, legendreConst);
328
+ const p = legendre(f, x);
322
329
  return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
323
330
  };
324
331
  }
@@ -339,6 +346,9 @@ type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
339
346
  * * a) denormalized operations like mulN instead of mul
340
347
  * * b) same object shape: never add or remove keys
341
348
  * * c) Object.freeze
349
+ * NOTE: operations don't check 'isValid' for all elements for performance reasons,
350
+ * it is caller responsibility to check this.
351
+ * This is low-level code, please make sure you know what you doing.
342
352
  * @param ORDER prime positive bigint
343
353
  * @param bitLen how many bits the field consumes
344
354
  * @param isLE (def: false) if encoding / decoding should be in little-endian
@@ -1,6 +1,12 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  import { mod, pow } from './modular.js';
3
- import { bytesToNumberLE, ensureBytes, numberToBytesLE, validateObject } from './utils.js';
3
+ import {
4
+ aInRange,
5
+ bytesToNumberLE,
6
+ ensureBytes,
7
+ numberToBytesLE,
8
+ validateObject,
9
+ } from './utils.js';
4
10
 
5
11
  const _0n = BigInt(0);
6
12
  const _1n = BigInt(1);
@@ -75,12 +81,6 @@ export function montgomery(curveDef: CurveType): CurveFn {
75
81
  return [x_2, x_3];
76
82
  }
77
83
 
78
- // Accepts 0 as well
79
- function assertFieldElement(n: bigint): bigint {
80
- if (typeof n === 'bigint' && _0n <= n && n < P) return n;
81
- throw new Error('Expected valid scalar 0 < scalar < CURVE.P');
82
- }
83
-
84
84
  // x25519 from 4
85
85
  // The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519
86
86
  const a24 = (CURVE.a - BigInt(2)) / BigInt(4);
@@ -90,11 +90,12 @@ export function montgomery(curveDef: CurveType): CurveFn {
90
90
  * @param scalar by which the point would be multiplied
91
91
  * @returns new Point on Montgomery curve
92
92
  */
93
- function montgomeryLadder(pointU: bigint, scalar: bigint): bigint {
94
- const u = assertFieldElement(pointU);
93
+ function montgomeryLadder(u: bigint, scalar: bigint): bigint {
94
+ aInRange('u', u, _0n, P);
95
+ aInRange('scalar', scalar, _0n, P);
95
96
  // Section 5: Implementations MUST accept non-canonical values and process them as
96
97
  // if they had been reduced modulo the field prime.
97
- const k = assertFieldElement(scalar);
98
+ const k = scalar;
98
99
  const x_1 = u;
99
100
  let x_2 = _1n;
100
101
  let z_2 = _0n;