@noble/curves 1.9.2 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/README.md +186 -206
  2. package/_shortw_utils.d.ts +1 -0
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +1 -0
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +87 -62
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +170 -163
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +109 -23
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +158 -156
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +124 -70
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +212 -62
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/hash-to-curve.d.ts +8 -4
  19. package/abstract/hash-to-curve.d.ts.map +1 -1
  20. package/abstract/hash-to-curve.js +23 -11
  21. package/abstract/hash-to-curve.js.map +1 -1
  22. package/abstract/modular.d.ts +8 -3
  23. package/abstract/modular.d.ts.map +1 -1
  24. package/abstract/modular.js +79 -35
  25. package/abstract/modular.js.map +1 -1
  26. package/abstract/montgomery.d.ts +17 -4
  27. package/abstract/montgomery.d.ts.map +1 -1
  28. package/abstract/montgomery.js +19 -3
  29. package/abstract/montgomery.js.map +1 -1
  30. package/abstract/tower.d.ts +3 -3
  31. package/abstract/tower.d.ts.map +1 -1
  32. package/abstract/tower.js.map +1 -1
  33. package/abstract/weierstrass.d.ts +142 -116
  34. package/abstract/weierstrass.d.ts.map +1 -1
  35. package/abstract/weierstrass.js +414 -335
  36. package/abstract/weierstrass.js.map +1 -1
  37. package/bls12-381.d.ts.map +1 -1
  38. package/bls12-381.js +4 -4
  39. package/bls12-381.js.map +1 -1
  40. package/ed25519.d.ts +52 -66
  41. package/ed25519.d.ts.map +1 -1
  42. package/ed25519.js +128 -155
  43. package/ed25519.js.map +1 -1
  44. package/ed448.d.ts +57 -58
  45. package/ed448.d.ts.map +1 -1
  46. package/ed448.js +114 -131
  47. package/ed448.js.map +1 -1
  48. package/esm/_shortw_utils.d.ts +1 -0
  49. package/esm/_shortw_utils.d.ts.map +1 -1
  50. package/esm/_shortw_utils.js +1 -0
  51. package/esm/_shortw_utils.js.map +1 -1
  52. package/esm/abstract/bls.d.ts +87 -62
  53. package/esm/abstract/bls.d.ts.map +1 -1
  54. package/esm/abstract/bls.js +171 -164
  55. package/esm/abstract/bls.js.map +1 -1
  56. package/esm/abstract/curve.d.ts +109 -23
  57. package/esm/abstract/curve.d.ts.map +1 -1
  58. package/esm/abstract/curve.js +156 -155
  59. package/esm/abstract/curve.js.map +1 -1
  60. package/esm/abstract/edwards.d.ts +124 -70
  61. package/esm/abstract/edwards.d.ts.map +1 -1
  62. package/esm/abstract/edwards.js +210 -62
  63. package/esm/abstract/edwards.js.map +1 -1
  64. package/esm/abstract/hash-to-curve.d.ts +8 -4
  65. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  66. package/esm/abstract/hash-to-curve.js +22 -11
  67. package/esm/abstract/hash-to-curve.js.map +1 -1
  68. package/esm/abstract/modular.d.ts +8 -3
  69. package/esm/abstract/modular.d.ts.map +1 -1
  70. package/esm/abstract/modular.js +79 -35
  71. package/esm/abstract/modular.js.map +1 -1
  72. package/esm/abstract/montgomery.d.ts +17 -4
  73. package/esm/abstract/montgomery.d.ts.map +1 -1
  74. package/esm/abstract/montgomery.js +19 -3
  75. package/esm/abstract/montgomery.js.map +1 -1
  76. package/esm/abstract/tower.d.ts +3 -3
  77. package/esm/abstract/tower.d.ts.map +1 -1
  78. package/esm/abstract/tower.js.map +1 -1
  79. package/esm/abstract/weierstrass.d.ts +142 -116
  80. package/esm/abstract/weierstrass.d.ts.map +1 -1
  81. package/esm/abstract/weierstrass.js +411 -333
  82. package/esm/abstract/weierstrass.js.map +1 -1
  83. package/esm/bls12-381.d.ts.map +1 -1
  84. package/esm/bls12-381.js +4 -4
  85. package/esm/bls12-381.js.map +1 -1
  86. package/esm/ed25519.d.ts +52 -66
  87. package/esm/ed25519.d.ts.map +1 -1
  88. package/esm/ed25519.js +131 -157
  89. package/esm/ed25519.js.map +1 -1
  90. package/esm/ed448.d.ts +57 -58
  91. package/esm/ed448.d.ts.map +1 -1
  92. package/esm/ed448.js +116 -132
  93. package/esm/ed448.js.map +1 -1
  94. package/esm/index.js +7 -9
  95. package/esm/index.js.map +1 -1
  96. package/esm/jubjub.d.ts +3 -3
  97. package/esm/jubjub.d.ts.map +1 -1
  98. package/esm/jubjub.js +3 -3
  99. package/esm/jubjub.js.map +1 -1
  100. package/esm/misc.d.ts +3 -5
  101. package/esm/misc.d.ts.map +1 -1
  102. package/esm/misc.js +0 -3
  103. package/esm/misc.js.map +1 -1
  104. package/esm/nist.d.ts +0 -6
  105. package/esm/nist.d.ts.map +1 -1
  106. package/esm/nist.js +31 -15
  107. package/esm/nist.js.map +1 -1
  108. package/esm/p256.d.ts +4 -0
  109. package/esm/p256.d.ts.map +1 -1
  110. package/esm/p256.js +4 -0
  111. package/esm/p256.js.map +1 -1
  112. package/esm/p384.d.ts +4 -1
  113. package/esm/p384.d.ts.map +1 -1
  114. package/esm/p384.js +4 -1
  115. package/esm/p384.js.map +1 -1
  116. package/esm/p521.d.ts +4 -0
  117. package/esm/p521.d.ts.map +1 -1
  118. package/esm/p521.js +4 -0
  119. package/esm/p521.js.map +1 -1
  120. package/esm/secp256k1.d.ts +32 -15
  121. package/esm/secp256k1.d.ts.map +1 -1
  122. package/esm/secp256k1.js +72 -67
  123. package/esm/secp256k1.js.map +1 -1
  124. package/esm/utils.d.ts +1 -1
  125. package/esm/utils.js +1 -1
  126. package/index.js +7 -9
  127. package/index.js.map +1 -1
  128. package/jubjub.d.ts +3 -3
  129. package/jubjub.d.ts.map +1 -1
  130. package/jubjub.js +3 -3
  131. package/jubjub.js.map +1 -1
  132. package/misc.d.ts +3 -5
  133. package/misc.d.ts.map +1 -1
  134. package/misc.js +0 -3
  135. package/misc.js.map +1 -1
  136. package/nist.d.ts +0 -6
  137. package/nist.d.ts.map +1 -1
  138. package/nist.js +31 -15
  139. package/nist.js.map +1 -1
  140. package/p256.d.ts +4 -0
  141. package/p256.d.ts.map +1 -1
  142. package/p256.js +4 -0
  143. package/p256.js.map +1 -1
  144. package/p384.d.ts +4 -1
  145. package/p384.d.ts.map +1 -1
  146. package/p384.js +4 -1
  147. package/p384.js.map +1 -1
  148. package/p521.d.ts +4 -0
  149. package/p521.d.ts.map +1 -1
  150. package/p521.js +4 -0
  151. package/p521.js.map +1 -1
  152. package/package.json +4 -2
  153. package/secp256k1.d.ts +32 -15
  154. package/secp256k1.d.ts.map +1 -1
  155. package/secp256k1.js +70 -65
  156. package/secp256k1.js.map +1 -1
  157. package/src/_shortw_utils.ts +1 -0
  158. package/src/abstract/bls.ts +319 -257
  159. package/src/abstract/curve.ts +226 -170
  160. package/src/abstract/edwards.ts +350 -139
  161. package/src/abstract/hash-to-curve.ts +33 -16
  162. package/src/abstract/modular.ts +86 -35
  163. package/src/abstract/montgomery.ts +36 -9
  164. package/src/abstract/tower.ts +4 -4
  165. package/src/abstract/weierstrass.ts +567 -474
  166. package/src/bls12-381.ts +28 -20
  167. package/src/ed25519.ts +161 -179
  168. package/src/ed448.ts +150 -156
  169. package/src/index.ts +7 -9
  170. package/src/jubjub.ts +3 -3
  171. package/src/misc.ts +3 -7
  172. package/src/nist.ts +40 -16
  173. package/src/p256.ts +4 -0
  174. package/src/p384.ts +4 -2
  175. package/src/p521.ts +4 -0
  176. package/src/secp256k1.ts +91 -73
  177. package/src/utils.ts +1 -1
  178. package/utils.d.ts +1 -1
  179. package/utils.js +1 -1
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Methods for elliptic curve multiplication by scalars.
3
- * Contains wNAF, pippenger
3
+ * Contains wNAF, pippenger.
4
4
  * @module
5
5
  */
6
6
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
7
- import { bitLen, bitMask, validateObject } from '../utils.ts';
8
- import { Field, FpInvertBatch, type IField, nLength, validateField } from './modular.ts';
7
+ import { bitLen, bitMask, validateObject, type Hex } from '../utils.ts';
8
+ import { Field, FpInvertBatch, nLength, validateField, type IField } from './modular.ts';
9
9
 
10
10
  const _0n = BigInt(0);
11
11
  const _1n = BigInt(1);
@@ -15,6 +15,8 @@ export type AffinePoint<T> = {
15
15
  y: T;
16
16
  } & { z?: never; t?: never };
17
17
 
18
+ // This was initialy do this way to re-use montgomery ladder in field (add->mul,double->sqr), but
19
+ // that didn't happen and there is probably not much reason to have separate Group like this?
18
20
  export interface Group<T extends Group<T>> {
19
21
  double(): T;
20
22
  negate(): T;
@@ -25,10 +27,69 @@ export interface Group<T extends Group<T>> {
25
27
  toAffine?(invertedZ?: any): AffinePoint<any>;
26
28
  }
27
29
 
30
+ // We can't "abstract out" coordinates (X, Y, Z; and T in Edwards): argument names of constructor
31
+ // are not accessible. See Typescript gh-56093, gh-41594.
32
+
33
+ /** Base interface for all elliptic curve Points. */
34
+ export interface CurvePoint<F, P extends CurvePoint<F, P>> extends Group<P> {
35
+ /** Affine x coordinate. Different from projective / extended X coordinate. */
36
+ x: F;
37
+ /** Affine y coordinate. Different from projective / extended Y coordinate. */
38
+ y: F;
39
+ Z?: F;
40
+ assertValidity(): void;
41
+ clearCofactor(): P;
42
+ is0(): boolean;
43
+ isTorsionFree(): boolean;
44
+ isSmallOrder(): boolean;
45
+ multiplyUnsafe(scalar: bigint): P;
46
+ /**
47
+ * Massively speeds up `p.multiply(n)` by using precompute tables (caching). See {@link wNAF}.
48
+ * @param isLazy calculate cache now. Default (true) ensures it's deferred to first `multiply()`
49
+ */
50
+ precompute(windowSize?: number, isLazy?: boolean): P;
51
+ /** Converts point to 2D xy affine coordinates */
52
+ toAffine(invertedZ?: F): AffinePoint<F>;
53
+ toBytes(): Uint8Array;
54
+ toHex(): string;
55
+ }
56
+
57
+ /** Base interface for all elliptic curve Point constructors. */
58
+ export interface CurvePointCons<F, P extends CurvePoint<F, P>> extends GroupConstructor<P> {
59
+ BASE: P;
60
+ ZERO: P;
61
+ /** Field for basic curve math */
62
+ Fp: IField<F>;
63
+ /** Scalar field, for scalars in multiply and others */
64
+ Fn: IField<bigint>;
65
+ /** Creates point from x, y. Does NOT validate if the point is valid. Use `.assertValidity()`. */
66
+ fromAffine(p: AffinePoint<F>): P;
67
+ fromBytes(bytes: Uint8Array): P;
68
+ fromHex(hex: Hex): P;
69
+ }
70
+
71
+ // Type inference helpers
72
+ // PC - PointConstructor, P - Point, Fp - Field element
73
+ export type GetPointConsF<PC> = PC extends CurvePointCons<infer F, any> ? F : never;
74
+ export type GetPointConsPoint<PC> = PC extends CurvePointCons<any, infer P> ? P : never;
75
+
76
+ // More like SigAlgorithmInfo, not CurveInfo
77
+ export interface CurveInfo {
78
+ type: 'weierstrass' | 'edwards' | 'montgomery';
79
+ publicKeyHasPrefix?: boolean;
80
+ lengths: {
81
+ secret: number;
82
+ public: number;
83
+ publicUncompressed?: number;
84
+ signature: number;
85
+ seed: number;
86
+ };
87
+ }
28
88
  export type GroupConstructor<T> = {
29
89
  BASE: T;
30
90
  ZERO: T;
31
91
  };
92
+ /** @deprecated */
32
93
  export type ExtendedGroupConstructor<T> = GroupConstructor<T> & {
33
94
  Fp: IField<any>;
34
95
  Fn: IField<bigint>;
@@ -36,7 +97,7 @@ export type ExtendedGroupConstructor<T> = GroupConstructor<T> & {
36
97
  };
37
98
  export type Mapper<T> = (i: T[]) => T[];
38
99
 
39
- export function negateCt<T extends Group<T>>(condition: boolean, item: T): T {
100
+ export function negateCt<T extends { negate: () => T }>(condition: boolean, item: T): T {
40
101
  const neg = item.negate();
41
102
  return condition ? neg : item;
42
103
  }
@@ -47,16 +108,16 @@ export function negateCt<T extends Group<T>>(condition: boolean, item: T): T {
47
108
  * so this improves performance massively.
48
109
  * Optimization: converts a list of projective points to a list of identical points with Z=1.
49
110
  */
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);
111
+ export function normalizeZ<
112
+ PC extends CurvePointCons<any, any>,
113
+ F = GetPointConsF<PC>,
114
+ P extends CurvePoint<F, P> = GetPointConsPoint<PC>,
115
+ >(c: CurvePointCons<F, P>, points: P[]): P[] {
116
+ const invertedZs = FpInvertBatch(
117
+ c.Fp,
118
+ points.map((p) => p.Z!)
119
+ );
120
+ return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i])));
60
121
  }
61
122
 
62
123
  function validateW(W: number, bits: number) {
@@ -128,6 +189,8 @@ const pointPrecomputes = new WeakMap<any, any[]>();
128
189
  const pointWindowSizes = new WeakMap<any, number>();
129
190
 
130
191
  function getW(P: any): number {
192
+ // To disable precomputes:
193
+ // return 1;
131
194
  return pointWindowSizes.get(P) || 1;
132
195
  }
133
196
 
@@ -135,21 +198,12 @@ function assert0(n: bigint): void {
135
198
  if (n !== _0n) throw new Error('invalid wNAF');
136
199
  }
137
200
 
138
- export type IWNAF<T extends Group<T>> = {
139
- constTimeNegate: <T extends Group<T>>(condition: boolean, item: T) => T;
140
- hasPrecomputes(elm: T): boolean;
141
- unsafeLadder(elm: T, n: bigint, p?: T): T;
142
- precomputeWindow(elm: T, W: number): Group<T>[];
143
- getPrecomputes(W: number, P: T, transform?: Mapper<T>): T[];
144
- wNAF(W: number, precomputes: T[], n: bigint): { p: T; f: T };
145
- wNAFUnsafe(W: number, precomputes: T[], n: bigint, acc?: 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;
148
- setWindowSize(P: T, W: number): void;
149
- };
150
-
151
201
  /**
152
202
  * Elliptic curve multiplication of Point by scalar. Fragile.
203
+ * Table generation takes **30MB of ram and 10ms on high-end CPU**,
204
+ * but may take much longer on slow devices. Actual generation will happen on
205
+ * first call of `multiply()`. By default, `BASE` point is precomputed.
206
+ *
153
207
  * Scalars should always be less than curve order: this should be checked inside of a curve itself.
154
208
  * Creates precomputation tables for fast multiplication:
155
209
  * - private scalar is split by fixed size windows of W bits
@@ -162,159 +216,160 @@ export type IWNAF<T extends Group<T>> = {
162
216
  * @todo Research returning 2d JS array of windows, instead of a single window.
163
217
  * This would allow windows to be in different memory locations
164
218
  */
165
- export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number): IWNAF<T> {
166
- return {
167
- constTimeNegate: negateCt,
168
-
169
- hasPrecomputes(elm: T) {
170
- return getW(elm) !== 1;
171
- },
219
+ export class wNAF<F, P extends CurvePoint<F, P>> {
220
+ private readonly BASE: P;
221
+ private readonly ZERO: P;
222
+ private readonly Fn: CurvePointCons<F, P>['Fn'];
223
+ readonly bits: number;
224
+
225
+ // Parametrized with a given Point class (not individual point)
226
+ constructor(Point: CurvePointCons<F, P>, bits: number) {
227
+ this.BASE = Point.BASE;
228
+ this.ZERO = Point.ZERO;
229
+ this.Fn = Point.Fn;
230
+ this.bits = bits;
231
+ }
172
232
 
173
- // non-const time multiplication ladder
174
- unsafeLadder(elm: T, n: bigint, p = c.ZERO) {
175
- let d: T = elm;
176
- while (n > _0n) {
177
- if (n & _1n) p = p.add(d);
178
- d = d.double();
179
- n >>= _1n;
180
- }
181
- return p;
182
- },
233
+ // non-const time multiplication ladder
234
+ _unsafeLadder(elm: P, n: bigint, p: P = this.ZERO): P {
235
+ let d: P = elm;
236
+ while (n > _0n) {
237
+ if (n & _1n) p = p.add(d);
238
+ d = d.double();
239
+ n >>= _1n;
240
+ }
241
+ return p;
242
+ }
183
243
 
184
- /**
185
- * Creates a wNAF precomputation window. Used for caching.
186
- * Default window size is set by `utils.precompute()` and is equal to 8.
187
- * Number of precomputed points depends on the curve size:
188
- * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
189
- * - 𝑊 is the window size
190
- * - 𝑛 is the bitlength of the curve order.
191
- * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
192
- * @param elm Point instance
193
- * @param W window size
194
- * @returns precomputed point tables flattened to a single array
195
- */
196
- precomputeWindow(elm: T, W: number): Group<T>[] {
197
- const { windows, windowSize } = calcWOpts(W, bits);
198
- const points: T[] = [];
199
- let p: T = elm;
200
- let base = p;
201
- for (let window = 0; window < windows; window++) {
202
- base = p;
244
+ /**
245
+ * Creates a wNAF precomputation window. Used for caching.
246
+ * Default window size is set by `utils.precompute()` and is equal to 8.
247
+ * Number of precomputed points depends on the curve size:
248
+ * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
249
+ * - 𝑊 is the window size
250
+ * - 𝑛 is the bitlength of the curve order.
251
+ * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
252
+ * @param point Point instance
253
+ * @param W window size
254
+ * @returns precomputed point tables flattened to a single array
255
+ */
256
+ private precomputeWindow(point: P, W: number): Group<P>[] {
257
+ const { windows, windowSize } = calcWOpts(W, this.bits);
258
+ const points: P[] = [];
259
+ let p: P = point;
260
+ let base = p;
261
+ for (let window = 0; window < windows; window++) {
262
+ base = p;
263
+ points.push(base);
264
+ // i=1, bc we skip 0
265
+ for (let i = 1; i < windowSize; i++) {
266
+ base = base.add(p);
203
267
  points.push(base);
204
- // i=1, bc we skip 0
205
- for (let i = 1; i < windowSize; i++) {
206
- base = base.add(p);
207
- points.push(base);
208
- }
209
- p = base.double();
210
268
  }
211
- return points;
212
- },
269
+ p = base.double();
270
+ }
271
+ return points;
272
+ }
213
273
 
214
- /**
215
- * Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
216
- * @param W window size
217
- * @param precomputes precomputed tables
218
- * @param n scalar (we don't check here, but should be less than curve order)
219
- * @returns real and fake (for const-time) points
220
- */
221
- wNAF(W: number, precomputes: T[], n: bigint): { p: T; f: T } {
222
- // Smaller version:
223
- // https://github.com/paulmillr/noble-secp256k1/blob/47cb1669b6e506ad66b35fe7d76132ae97465da2/index.ts#L502-L541
224
- // TODO: check the scalar is less than group order?
225
- // wNAF behavior is undefined otherwise. But have to carefully remove
226
- // other checks before wNAF. ORDER == bits here.
227
- // Accumulators
228
- let p = c.ZERO;
229
- let f = c.BASE;
230
- // This code was first written with assumption that 'f' and 'p' will never be infinity point:
231
- // since each addition is multiplied by 2 ** W, it cannot cancel each other. However,
232
- // there is negate now: it is possible that negated element from low value
233
- // would be the same as high element, which will create carry into next window.
234
- // It's not obvious how this can fail, but still worth investigating later.
235
- const wo = calcWOpts(W, bits);
236
- for (let window = 0; window < wo.windows; window++) {
237
- // (n === _0n) is handled and not early-exited. isEven and offsetF are used for noise
238
- const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
239
- n = nextN;
240
- if (isZero) {
241
- // bits are 0: add garbage to fake point
242
- // Important part for const-time getPublicKey: add random "noise" point to f.
243
- f = f.add(negateCt(isNegF, precomputes[offsetF]));
244
- } else {
245
- // bits are 1: add to result point
246
- p = p.add(negateCt(isNeg, precomputes[offset]));
247
- }
274
+ /**
275
+ * Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
276
+ * More compact implementation:
277
+ * https://github.com/paulmillr/noble-secp256k1/blob/47cb1669b6e506ad66b35fe7d76132ae97465da2/index.ts#L502-L541
278
+ * @returns real and fake (for const-time) points
279
+ */
280
+ private wNAF(W: number, precomputes: P[], n: bigint): { p: P; f: P } {
281
+ // Scalar should be smaller than field order
282
+ if (!this.Fn.isValid(n)) throw new Error('invalid scalar');
283
+ // Accumulators
284
+ let p = this.ZERO;
285
+ let f = this.BASE;
286
+ // This code was first written with assumption that 'f' and 'p' will never be infinity point:
287
+ // since each addition is multiplied by 2 ** W, it cannot cancel each other. However,
288
+ // there is negate now: it is possible that negated element from low value
289
+ // would be the same as high element, which will create carry into next window.
290
+ // It's not obvious how this can fail, but still worth investigating later.
291
+ const wo = calcWOpts(W, this.bits);
292
+ for (let window = 0; window < wo.windows; window++) {
293
+ // (n === _0n) is handled and not early-exited. isEven and offsetF are used for noise
294
+ const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
295
+ n = nextN;
296
+ if (isZero) {
297
+ // bits are 0: add garbage to fake point
298
+ // Important part for const-time getPublicKey: add random "noise" point to f.
299
+ f = f.add(negateCt(isNegF, precomputes[offsetF]));
300
+ } else {
301
+ // bits are 1: add to result point
302
+ p = p.add(negateCt(isNeg, precomputes[offset]));
248
303
  }
249
- assert0(n);
250
- // Return both real and fake points: JIT won't eliminate f.
251
- // At this point there is a way to F be infinity-point even if p is not,
252
- // which makes it less const-time: around 1 bigint multiply.
253
- return { p, f };
254
- },
304
+ }
305
+ assert0(n);
306
+ // Return both real and fake points: JIT won't eliminate f.
307
+ // At this point there is a way to F be infinity-point even if p is not,
308
+ // which makes it less const-time: around 1 bigint multiply.
309
+ return { p, f };
310
+ }
255
311
 
256
- /**
257
- * Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
258
- * @param W window size
259
- * @param precomputes precomputed tables
260
- * @param n scalar (we don't check here, but should be less than curve order)
261
- * @param acc accumulator point to add result of multiplication
262
- * @returns point
263
- */
264
- wNAFUnsafe(W: number, precomputes: T[], n: bigint, acc: T = c.ZERO): T {
265
- const wo = calcWOpts(W, bits);
266
- for (let window = 0; window < wo.windows; window++) {
267
- if (n === _0n) break; // Early-exit, skip 0 value
268
- const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
269
- n = nextN;
270
- if (isZero) {
271
- // Window bits are 0: skip processing.
272
- // Move to next window.
273
- continue;
274
- } else {
275
- const item = precomputes[offset];
276
- acc = acc.add(isNeg ? item.negate() : item); // Re-using acc allows to save adds in MSM
277
- }
312
+ /**
313
+ * Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
314
+ * @param acc accumulator point to add result of multiplication
315
+ * @returns point
316
+ */
317
+ private wNAFUnsafe(W: number, precomputes: P[], n: bigint, acc: P = this.ZERO): P {
318
+ const wo = calcWOpts(W, this.bits);
319
+ for (let window = 0; window < wo.windows; window++) {
320
+ if (n === _0n) break; // Early-exit, skip 0 value
321
+ const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
322
+ n = nextN;
323
+ if (isZero) {
324
+ // Window bits are 0: skip processing.
325
+ // Move to next window.
326
+ continue;
327
+ } else {
328
+ const item = precomputes[offset];
329
+ acc = acc.add(isNeg ? item.negate() : item); // Re-using acc allows to save adds in MSM
278
330
  }
279
- assert0(n);
280
- return acc;
281
- },
331
+ }
332
+ assert0(n);
333
+ return acc;
334
+ }
282
335
 
283
- getPrecomputes(W: number, P: T, transform?: Mapper<T>): T[] {
284
- // Calculate precomputes on a first run, reuse them after
285
- let comp = pointPrecomputes.get(P);
286
- if (!comp) {
287
- comp = this.precomputeWindow(P, W) as T[];
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
- }
336
+ private getPrecomputes(W: number, point: P, transform?: Mapper<P>): P[] {
337
+ // Calculate precomputes on a first run, reuse them after
338
+ let comp = pointPrecomputes.get(point);
339
+ if (!comp) {
340
+ comp = this.precomputeWindow(point, W) as P[];
341
+ if (W !== 1) {
342
+ // Doing transform outside of if brings 15% perf hit
343
+ if (typeof transform === 'function') comp = transform(comp);
344
+ pointPrecomputes.set(point, comp);
293
345
  }
294
- return comp;
295
- },
346
+ }
347
+ return comp;
348
+ }
296
349
 
297
- wNAFCached(P: T, n: bigint, transform?: Mapper<T>): { p: T; f: T } {
298
- const W = getW(P);
299
- return this.wNAF(W, this.getPrecomputes(W, P, transform), n);
300
- },
350
+ cached(point: P, scalar: bigint, transform?: Mapper<P>): { p: P; f: P } {
351
+ const W = getW(point);
352
+ return this.wNAF(W, this.getPrecomputes(W, point, transform), scalar);
353
+ }
301
354
 
302
- wNAFCachedUnsafe(P: T, n: bigint, transform?: Mapper<T>, prev?: T): T {
303
- const W = getW(P);
304
- if (W === 1) return this.unsafeLadder(P, n, prev); // For W=1 ladder is ~x2 faster
305
- return this.wNAFUnsafe(W, this.getPrecomputes(W, P, transform), n, prev);
306
- },
355
+ unsafe(point: P, scalar: bigint, transform?: Mapper<P>, prev?: P): P {
356
+ const W = getW(point);
357
+ if (W === 1) return this._unsafeLadder(point, scalar, prev); // For W=1 ladder is ~x2 faster
358
+ return this.wNAFUnsafe(W, this.getPrecomputes(W, point, transform), scalar, prev);
359
+ }
307
360
 
308
- // We calculate precomputes for elliptic curve point multiplication
309
- // using windowed method. This specifies window size and
310
- // stores precomputed values. Usually only base point would be precomputed.
361
+ // We calculate precomputes for elliptic curve point multiplication
362
+ // using windowed method. This specifies window size and
363
+ // stores precomputed values. Usually only base point would be precomputed.
364
+ createCache(P: P, W: number): void {
365
+ validateW(W, this.bits);
366
+ pointWindowSizes.set(P, W);
367
+ pointPrecomputes.delete(P);
368
+ }
311
369
 
312
- setWindowSize(P: T, W: number) {
313
- validateW(W, bits);
314
- pointWindowSizes.set(P, W);
315
- pointPrecomputes.delete(P);
316
- },
317
- };
370
+ hasCache(elm: P): boolean {
371
+ return getW(elm) !== 1;
372
+ }
318
373
  }
319
374
 
320
375
  /**
@@ -322,14 +377,14 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number):
322
377
  * Cost: 128 dbl, 0-256 adds.
323
378
  */
324
379
  export function mulEndoUnsafe<T extends Group<T>>(
325
- c: GroupConstructor<T>,
380
+ Point: GroupConstructor<T>,
326
381
  point: T,
327
382
  k1: bigint,
328
383
  k2: bigint
329
384
  ): { p1: T; p2: T } {
330
385
  let acc = point;
331
- let p1 = c.ZERO;
332
- let p2 = c.ZERO;
386
+ let p1 = Point.ZERO;
387
+ let p2 = Point.ZERO;
333
388
  while (k1 > _0n || k2 > _0n) {
334
389
  if (k1 & _1n) p1 = p1.add(acc);
335
390
  if (k2 & _1n) p2 = p2.add(acc);
@@ -348,7 +403,7 @@ export function mulEndoUnsafe<T extends Group<T>>(
348
403
  * @param c Curve Point constructor
349
404
  * @param fieldN field over CURVE.N - important that it's not over CURVE.P
350
405
  * @param points array of L curve points
351
- * @param scalars array of L scalars (aka private keys / bigints)
406
+ * @param scalars array of L scalars (aka secret keys / bigints)
352
407
  */
353
408
  export function pippenger<T extends Group<T>>(
354
409
  c: GroupConstructor<T>,
@@ -478,6 +533,7 @@ export function precomputeMSMUnsafe<T extends Group<T>>(
478
533
  };
479
534
  }
480
535
 
536
+ // TODO: remove
481
537
  /**
482
538
  * Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok.
483
539
  * Though generator can be different (Fp2 / Fp6 for BLS).