@noble/curves 1.9.0 → 1.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/README.md +78 -34
  2. package/_shortw_utils.d.ts +7 -5
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +2 -8
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +60 -24
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +158 -109
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +44 -9
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +99 -11
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +112 -25
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +141 -92
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/fft.d.ts +122 -0
  19. package/abstract/fft.d.ts.map +1 -0
  20. package/abstract/fft.js +438 -0
  21. package/abstract/fft.js.map +1 -0
  22. package/abstract/hash-to-curve.d.ts +25 -11
  23. package/abstract/hash-to-curve.d.ts.map +1 -1
  24. package/abstract/hash-to-curve.js +17 -14
  25. package/abstract/hash-to-curve.js.map +1 -1
  26. package/abstract/modular.d.ts +28 -17
  27. package/abstract/modular.d.ts.map +1 -1
  28. package/abstract/modular.js +156 -139
  29. package/abstract/modular.js.map +1 -1
  30. package/abstract/montgomery.d.ts +3 -8
  31. package/abstract/montgomery.d.ts.map +1 -1
  32. package/abstract/montgomery.js +73 -93
  33. package/abstract/montgomery.js.map +1 -1
  34. package/abstract/poseidon.d.ts +5 -13
  35. package/abstract/poseidon.d.ts.map +1 -1
  36. package/abstract/poseidon.js +12 -7
  37. package/abstract/poseidon.js.map +1 -1
  38. package/abstract/tower.d.ts +20 -46
  39. package/abstract/tower.d.ts.map +1 -1
  40. package/abstract/tower.js +10 -4
  41. package/abstract/tower.js.map +1 -1
  42. package/abstract/utils.d.ts +1 -115
  43. package/abstract/utils.d.ts.map +1 -1
  44. package/abstract/utils.js +17 -371
  45. package/abstract/utils.js.map +1 -1
  46. package/abstract/weierstrass.d.ts +152 -73
  47. package/abstract/weierstrass.d.ts.map +1 -1
  48. package/abstract/weierstrass.js +487 -404
  49. package/abstract/weierstrass.js.map +1 -1
  50. package/bls12-381.d.ts +2 -0
  51. package/bls12-381.d.ts.map +1 -1
  52. package/bls12-381.js +504 -480
  53. package/bls12-381.js.map +1 -1
  54. package/bn254.d.ts +2 -0
  55. package/bn254.d.ts.map +1 -1
  56. package/bn254.js +44 -32
  57. package/bn254.js.map +1 -1
  58. package/ed25519.d.ts +25 -9
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +89 -65
  61. package/ed25519.js.map +1 -1
  62. package/ed448.d.ts +29 -10
  63. package/ed448.d.ts.map +1 -1
  64. package/ed448.js +116 -81
  65. package/ed448.js.map +1 -1
  66. package/esm/_shortw_utils.d.ts +7 -5
  67. package/esm/_shortw_utils.d.ts.map +1 -1
  68. package/esm/_shortw_utils.js +2 -8
  69. package/esm/_shortw_utils.js.map +1 -1
  70. package/esm/abstract/bls.d.ts +60 -24
  71. package/esm/abstract/bls.d.ts.map +1 -1
  72. package/esm/abstract/bls.js +158 -109
  73. package/esm/abstract/bls.js.map +1 -1
  74. package/esm/abstract/curve.d.ts +44 -9
  75. package/esm/abstract/curve.d.ts.map +1 -1
  76. package/esm/abstract/curve.js +96 -12
  77. package/esm/abstract/curve.js.map +1 -1
  78. package/esm/abstract/edwards.d.ts +112 -25
  79. package/esm/abstract/edwards.d.ts.map +1 -1
  80. package/esm/abstract/edwards.js +141 -94
  81. package/esm/abstract/edwards.js.map +1 -1
  82. package/esm/abstract/fft.d.ts +122 -0
  83. package/esm/abstract/fft.d.ts.map +1 -0
  84. package/esm/abstract/fft.js +425 -0
  85. package/esm/abstract/fft.js.map +1 -0
  86. package/esm/abstract/hash-to-curve.d.ts +25 -11
  87. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  88. package/esm/abstract/hash-to-curve.js +17 -14
  89. package/esm/abstract/hash-to-curve.js.map +1 -1
  90. package/esm/abstract/modular.d.ts +28 -17
  91. package/esm/abstract/modular.d.ts.map +1 -1
  92. package/esm/abstract/modular.js +155 -138
  93. package/esm/abstract/modular.js.map +1 -1
  94. package/esm/abstract/montgomery.d.ts +3 -8
  95. package/esm/abstract/montgomery.d.ts.map +1 -1
  96. package/esm/abstract/montgomery.js +74 -94
  97. package/esm/abstract/montgomery.js.map +1 -1
  98. package/esm/abstract/poseidon.d.ts +5 -13
  99. package/esm/abstract/poseidon.d.ts.map +1 -1
  100. package/esm/abstract/poseidon.js +12 -7
  101. package/esm/abstract/poseidon.js.map +1 -1
  102. package/esm/abstract/tower.d.ts +20 -46
  103. package/esm/abstract/tower.d.ts.map +1 -1
  104. package/esm/abstract/tower.js +10 -4
  105. package/esm/abstract/tower.js.map +1 -1
  106. package/esm/abstract/utils.d.ts +1 -115
  107. package/esm/abstract/utils.d.ts.map +1 -1
  108. package/esm/abstract/utils.js +3 -344
  109. package/esm/abstract/utils.js.map +1 -1
  110. package/esm/abstract/weierstrass.d.ts +152 -73
  111. package/esm/abstract/weierstrass.d.ts.map +1 -1
  112. package/esm/abstract/weierstrass.js +485 -406
  113. package/esm/abstract/weierstrass.js.map +1 -1
  114. package/esm/bls12-381.d.ts +2 -0
  115. package/esm/bls12-381.d.ts.map +1 -1
  116. package/esm/bls12-381.js +503 -479
  117. package/esm/bls12-381.js.map +1 -1
  118. package/esm/bn254.d.ts +2 -0
  119. package/esm/bn254.d.ts.map +1 -1
  120. package/esm/bn254.js +41 -29
  121. package/esm/bn254.js.map +1 -1
  122. package/esm/ed25519.d.ts +25 -9
  123. package/esm/ed25519.d.ts.map +1 -1
  124. package/esm/ed25519.js +84 -60
  125. package/esm/ed25519.js.map +1 -1
  126. package/esm/ed448.d.ts +29 -10
  127. package/esm/ed448.d.ts.map +1 -1
  128. package/esm/ed448.js +113 -78
  129. package/esm/ed448.js.map +1 -1
  130. package/esm/jubjub.d.ts +4 -0
  131. package/esm/jubjub.d.ts.map +1 -1
  132. package/esm/jubjub.js +4 -0
  133. package/esm/jubjub.js.map +1 -1
  134. package/esm/misc.d.ts.map +1 -1
  135. package/esm/misc.js +31 -26
  136. package/esm/misc.js.map +1 -1
  137. package/esm/nist.d.ts +8 -16
  138. package/esm/nist.d.ts.map +1 -1
  139. package/esm/nist.js +87 -97
  140. package/esm/nist.js.map +1 -1
  141. package/esm/p256.d.ts +3 -3
  142. package/esm/p384.d.ts +3 -3
  143. package/esm/p521.d.ts +3 -3
  144. package/esm/pasta.d.ts +4 -0
  145. package/esm/pasta.d.ts.map +1 -1
  146. package/esm/pasta.js +4 -0
  147. package/esm/pasta.js.map +1 -1
  148. package/esm/secp256k1.d.ts +6 -6
  149. package/esm/secp256k1.d.ts.map +1 -1
  150. package/esm/secp256k1.js +44 -41
  151. package/esm/secp256k1.js.map +1 -1
  152. package/esm/utils.d.ts +96 -0
  153. package/esm/utils.d.ts.map +1 -0
  154. package/esm/utils.js +279 -0
  155. package/esm/utils.js.map +1 -0
  156. package/jubjub.d.ts +4 -0
  157. package/jubjub.d.ts.map +1 -1
  158. package/jubjub.js +4 -0
  159. package/jubjub.js.map +1 -1
  160. package/misc.d.ts.map +1 -1
  161. package/misc.js +35 -30
  162. package/misc.js.map +1 -1
  163. package/nist.d.ts +8 -16
  164. package/nist.d.ts.map +1 -1
  165. package/nist.js +87 -97
  166. package/nist.js.map +1 -1
  167. package/p256.d.ts +3 -3
  168. package/p384.d.ts +3 -3
  169. package/p521.d.ts +3 -3
  170. package/package.json +26 -8
  171. package/pasta.d.ts +4 -0
  172. package/pasta.d.ts.map +1 -1
  173. package/pasta.js +4 -0
  174. package/pasta.js.map +1 -1
  175. package/secp256k1.d.ts +6 -6
  176. package/secp256k1.d.ts.map +1 -1
  177. package/secp256k1.js +47 -44
  178. package/secp256k1.js.map +1 -1
  179. package/src/_shortw_utils.ts +5 -15
  180. package/src/abstract/bls.ts +260 -145
  181. package/src/abstract/curve.ts +125 -18
  182. package/src/abstract/edwards.ts +282 -127
  183. package/src/abstract/fft.ts +519 -0
  184. package/src/abstract/hash-to-curve.ts +51 -27
  185. package/src/abstract/modular.ts +156 -143
  186. package/src/abstract/montgomery.ts +81 -111
  187. package/src/abstract/poseidon.ts +22 -18
  188. package/src/abstract/tower.ts +37 -68
  189. package/src/abstract/utils.ts +3 -378
  190. package/src/abstract/weierstrass.ts +752 -461
  191. package/src/bls12-381.ts +542 -507
  192. package/src/bn254.ts +47 -35
  193. package/src/ed25519.ts +104 -76
  194. package/src/ed448.ts +156 -105
  195. package/src/jubjub.ts +4 -0
  196. package/src/misc.ts +39 -34
  197. package/src/nist.ts +138 -126
  198. package/src/p256.ts +3 -3
  199. package/src/p384.ts +3 -3
  200. package/src/p521.ts +3 -3
  201. package/src/pasta.ts +5 -1
  202. package/src/secp256k1.ts +59 -47
  203. package/src/utils.ts +328 -0
  204. package/utils.d.ts +96 -0
  205. package/utils.d.ts.map +1 -0
  206. package/utils.js +313 -0
  207. package/utils.js.map +1 -0
@@ -4,8 +4,8 @@
4
4
  * @module
5
5
  */
6
6
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
7
- import { type IField, nLength, validateField } from './modular.ts';
8
- import { bitLen, bitMask, validateObject } from './utils.ts';
7
+ import { bitLen, bitMask, validateObject } from '../utils.ts';
8
+ import { Field, FpInvertBatch, type IField, nLength, validateField } from './modular.ts';
9
9
 
10
10
  const _0n = BigInt(0);
11
11
  const _1n = BigInt(1);
@@ -22,19 +22,43 @@ export interface Group<T extends Group<T>> {
22
22
  subtract(other: T): T;
23
23
  equals(other: T): boolean;
24
24
  multiply(scalar: bigint): T;
25
+ toAffine?(invertedZ?: any): AffinePoint<any>;
25
26
  }
26
27
 
27
28
  export type GroupConstructor<T> = {
28
29
  BASE: T;
29
30
  ZERO: T;
30
31
  };
32
+ export type ExtendedGroupConstructor<T> = GroupConstructor<T> & {
33
+ Fp: IField<any>;
34
+ Fn: IField<bigint>;
35
+ fromAffine(ap: AffinePoint<any>): T;
36
+ };
31
37
  export type Mapper<T> = (i: T[]) => T[];
32
38
 
33
- function constTimeNegate<T extends Group<T>>(condition: boolean, item: T): T {
39
+ export function negateCt<T extends Group<T>>(condition: boolean, item: T): T {
34
40
  const neg = item.negate();
35
41
  return condition ? neg : item;
36
42
  }
37
43
 
44
+ /**
45
+ * Takes a bunch of Projective Points but executes only one
46
+ * inversion on all of them. Inversion is very slow operation,
47
+ * so this improves performance massively.
48
+ * Optimization: converts a list of projective points to a list of identical points with Z=1.
49
+ */
50
+ export function normalizeZ<T>(
51
+ c: ExtendedGroupConstructor<T>,
52
+ property: 'pz' | 'ez',
53
+ points: T[]
54
+ ): T[] {
55
+ const getz = property === 'pz' ? (p: any) => p.pz : (p: any) => p.ez;
56
+ const toInv = FpInvertBatch(c.Fp, points.map(getz));
57
+ // @ts-ignore
58
+ const affined = points.map((p, i) => p.toAffine(toInv[i]));
59
+ return affined.map(c.fromAffine);
60
+ }
61
+
38
62
  function validateW(W: number, bits: number) {
39
63
  if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
40
64
  throw new Error('invalid window size, expected [1..' + bits + '], got W=' + W);
@@ -107,16 +131,20 @@ function getW(P: any): number {
107
131
  return pointWindowSizes.get(P) || 1;
108
132
  }
109
133
 
134
+ function assert0(n: bigint): void {
135
+ if (n !== _0n) throw new Error('invalid wNAF');
136
+ }
137
+
110
138
  export type IWNAF<T extends Group<T>> = {
111
139
  constTimeNegate: <T extends Group<T>>(condition: boolean, item: T) => T;
112
140
  hasPrecomputes(elm: T): boolean;
113
141
  unsafeLadder(elm: T, n: bigint, p?: T): T;
114
142
  precomputeWindow(elm: T, W: number): Group<T>[];
115
- getPrecomputes(W: number, P: T, transform: Mapper<T>): T[];
143
+ getPrecomputes(W: number, P: T, transform?: Mapper<T>): T[];
116
144
  wNAF(W: number, precomputes: T[], n: bigint): { p: T; f: T };
117
145
  wNAFUnsafe(W: number, precomputes: T[], n: bigint, acc?: T): T;
118
- wNAFCached(P: T, n: bigint, transform: Mapper<T>): { p: T; f: T };
119
- wNAFCachedUnsafe(P: T, n: bigint, transform: Mapper<T>, prev?: T): T;
146
+ wNAFCached(P: T, n: bigint, transform?: Mapper<T>): { p: T; f: T };
147
+ wNAFCachedUnsafe(P: T, n: bigint, transform?: Mapper<T>, prev?: T): T;
120
148
  setWindowSize(P: T, W: number): void;
121
149
  };
122
150
 
@@ -136,7 +164,7 @@ export type IWNAF<T extends Group<T>> = {
136
164
  */
137
165
  export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number): IWNAF<T> {
138
166
  return {
139
- constTimeNegate,
167
+ constTimeNegate: negateCt,
140
168
 
141
169
  hasPrecomputes(elm: T) {
142
170
  return getW(elm) !== 1;
@@ -212,12 +240,13 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number):
212
240
  if (isZero) {
213
241
  // bits are 0: add garbage to fake point
214
242
  // Important part for const-time getPublicKey: add random "noise" point to f.
215
- f = f.add(constTimeNegate(isNegF, precomputes[offsetF]));
243
+ f = f.add(negateCt(isNegF, precomputes[offsetF]));
216
244
  } else {
217
245
  // bits are 1: add to result point
218
- p = p.add(constTimeNegate(isNeg, precomputes[offset]));
246
+ p = p.add(negateCt(isNeg, precomputes[offset]));
219
247
  }
220
248
  }
249
+ assert0(n);
221
250
  // Return both real and fake points: JIT won't eliminate f.
222
251
  // At this point there is a way to F be infinity-point even if p is not,
223
252
  // which makes it less const-time: around 1 bigint multiply.
@@ -247,25 +276,30 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number):
247
276
  acc = acc.add(isNeg ? item.negate() : item); // Re-using acc allows to save adds in MSM
248
277
  }
249
278
  }
279
+ assert0(n);
250
280
  return acc;
251
281
  },
252
282
 
253
- getPrecomputes(W: number, P: T, transform: Mapper<T>): T[] {
283
+ getPrecomputes(W: number, P: T, transform?: Mapper<T>): T[] {
254
284
  // Calculate precomputes on a first run, reuse them after
255
285
  let comp = pointPrecomputes.get(P);
256
286
  if (!comp) {
257
287
  comp = this.precomputeWindow(P, W) as T[];
258
- if (W !== 1) pointPrecomputes.set(P, transform(comp));
288
+ if (W !== 1) {
289
+ // Doing transform outside of if brings 15% perf hit
290
+ if (typeof transform === 'function') comp = transform(comp);
291
+ pointPrecomputes.set(P, comp);
292
+ }
259
293
  }
260
294
  return comp;
261
295
  },
262
296
 
263
- wNAFCached(P: T, n: bigint, transform: Mapper<T>): { p: T; f: T } {
297
+ wNAFCached(P: T, n: bigint, transform?: Mapper<T>): { p: T; f: T } {
264
298
  const W = getW(P);
265
299
  return this.wNAF(W, this.getPrecomputes(W, P, transform), n);
266
300
  },
267
301
 
268
- wNAFCachedUnsafe(P: T, n: bigint, transform: Mapper<T>, prev?: T): T {
302
+ wNAFCachedUnsafe(P: T, n: bigint, transform?: Mapper<T>, prev?: T): T {
269
303
  const W = getW(P);
270
304
  if (W === 1) return this.unsafeLadder(P, n, prev); // For W=1 ladder is ~x2 faster
271
305
  return this.wNAFUnsafe(W, this.getPrecomputes(W, P, transform), n, prev);
@@ -283,6 +317,29 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number):
283
317
  };
284
318
  }
285
319
 
320
+ /**
321
+ * Endomorphism-specific multiplication for Koblitz curves.
322
+ * Cost: 128 dbl, 0-256 adds.
323
+ */
324
+ export function mulEndoUnsafe<T extends Group<T>>(
325
+ c: GroupConstructor<T>,
326
+ point: T,
327
+ k1: bigint,
328
+ k2: bigint
329
+ ): { p1: T; p2: T } {
330
+ let acc = point;
331
+ let p1 = c.ZERO;
332
+ let p2 = c.ZERO;
333
+ while (k1 > _0n || k2 > _0n) {
334
+ if (k1 & _1n) p1 = p1.add(acc);
335
+ if (k2 & _1n) p2 = p2.add(acc);
336
+ acc = acc.double();
337
+ k1 >>= _1n;
338
+ k2 >>= _1n;
339
+ }
340
+ return { p1, p2 };
341
+ }
342
+
286
343
  /**
287
344
  * Pippenger algorithm for multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
288
345
  * 30x faster vs naive addition on L=4096, 10x faster than precomputes.
@@ -307,18 +364,23 @@ export function pippenger<T extends Group<T>>(
307
364
  // 0 is accepted in scalars
308
365
  validateMSMPoints(points, c);
309
366
  validateMSMScalars(scalars, fieldN);
310
- if (points.length !== scalars.length)
311
- throw new Error('arrays of points and scalars must have equal length');
367
+ const plength = points.length;
368
+ const slength = scalars.length;
369
+ if (plength !== slength) throw new Error('arrays of points and scalars must have equal length');
370
+ // if (plength === 0) throw new Error('array must be of length >= 2');
312
371
  const zero = c.ZERO;
313
- const wbits = bitLen(BigInt(points.length));
314
- const windowSize = wbits > 12 ? wbits - 3 : wbits > 4 ? wbits - 2 : wbits ? 2 : 1; // in bits
372
+ const wbits = bitLen(BigInt(plength));
373
+ let windowSize = 1; // bits
374
+ if (wbits > 12) windowSize = wbits - 3;
375
+ else if (wbits > 4) windowSize = wbits - 2;
376
+ else if (wbits > 0) windowSize = 2;
315
377
  const MASK = bitMask(windowSize);
316
378
  const buckets = new Array(Number(MASK) + 1).fill(zero); // +1 for zero array
317
379
  const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize;
318
380
  let sum = zero;
319
381
  for (let i = lastBits; i >= 0; i -= windowSize) {
320
382
  buckets.fill(zero);
321
- for (let j = 0; j < scalars.length; j++) {
383
+ for (let j = 0; j < slength; j++) {
322
384
  const scalar = scalars[j];
323
385
  const wbits = Number((scalar >> BigInt(i)) & MASK);
324
386
  buckets[wbits] = buckets[wbits].add(points[j]);
@@ -432,6 +494,8 @@ export type BasicCurve<T> = {
432
494
  allowInfinityPoint?: boolean; // bls12-381 requires it. ZERO point is valid, but invalid pubkey
433
495
  };
434
496
 
497
+ // TODO: remove
498
+ /** @deprecated */
435
499
  export function validateBasic<FP, T>(
436
500
  curve: BasicCurve<FP> & T
437
501
  ): Readonly<
@@ -464,3 +528,46 @@ export function validateBasic<FP, T>(
464
528
  ...{ p: curve.Fp.ORDER },
465
529
  } as const);
466
530
  }
531
+
532
+ export type ValidCurveParams<T> = {
533
+ a: T;
534
+ p: bigint;
535
+ n: bigint;
536
+ h: bigint;
537
+ Gx: T;
538
+ Gy: T;
539
+ } & ({ b: T } | { d: T });
540
+
541
+ function createField<T>(order: bigint, field?: IField<T>): IField<T> {
542
+ if (field) {
543
+ if (field.ORDER !== order) throw new Error('Field.ORDER must match order: Fp == p, Fn == n');
544
+ validateField(field);
545
+ return field;
546
+ } else {
547
+ return Field(order) as unknown as IField<T>;
548
+ }
549
+ }
550
+ export type FpFn<T> = { Fp: IField<T>; Fn: IField<bigint> };
551
+ /** Validates CURVE opts and creates fields */
552
+ export function _createCurveFields<T>(
553
+ type: 'weierstrass' | 'edwards',
554
+ CURVE: ValidCurveParams<T>,
555
+ curveOpts: Partial<FpFn<T>> = {}
556
+ ): FpFn<T> {
557
+ if (!CURVE || typeof CURVE !== 'object') throw new Error(`expected valid ${type} CURVE object`);
558
+ for (const p of ['p', 'n', 'h'] as const) {
559
+ const val = CURVE[p];
560
+ if (!(typeof val === 'bigint' && val > _0n))
561
+ throw new Error(`CURVE.${p} must be positive bigint`);
562
+ }
563
+ const Fp = createField(CURVE.p, curveOpts.Fp);
564
+ const Fn = createField(CURVE.n, curveOpts.Fn);
565
+ const _b: 'b' | 'd' = type === 'weierstrass' ? 'b' : 'd';
566
+ const params = ['Gx', 'Gy', 'a', _b] as const;
567
+ for (const p of params) {
568
+ // @ts-ignore
569
+ if (!Fp.isValid(CURVE[p]))
570
+ throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
571
+ }
572
+ return { Fp, Fn };
573
+ }