@noble/curves 2.0.1 → 2.2.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.
- package/README.md +214 -122
- package/abstract/bls.d.ts +299 -16
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +82 -22
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +274 -27
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +177 -23
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +166 -30
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +221 -86
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +322 -10
- package/abstract/fft.d.ts.map +1 -1
- package/abstract/fft.js +154 -12
- package/abstract/fft.js.map +1 -1
- package/abstract/frost.d.ts +293 -0
- package/abstract/frost.d.ts.map +1 -0
- package/abstract/frost.js +704 -0
- package/abstract/frost.js.map +1 -0
- package/abstract/hash-to-curve.d.ts +173 -24
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +170 -31
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +429 -37
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +414 -119
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +83 -12
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +32 -7
- package/abstract/montgomery.js.map +1 -1
- package/abstract/oprf.d.ts +164 -91
- package/abstract/oprf.d.ts.map +1 -1
- package/abstract/oprf.js +88 -29
- package/abstract/oprf.js.map +1 -1
- package/abstract/poseidon.d.ts +138 -7
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +178 -15
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +122 -3
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +323 -139
- package/abstract/tower.js.map +1 -1
- package/abstract/weierstrass.d.ts +339 -76
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +395 -205
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +16 -2
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +199 -209
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +11 -2
- package/bn254.d.ts.map +1 -1
- package/bn254.js +93 -38
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +125 -14
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +202 -40
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +108 -14
- package/ed448.d.ts.map +1 -1
- package/ed448.js +194 -42
- package/ed448.js.map +1 -1
- package/index.js +7 -1
- package/index.js.map +1 -1
- package/misc.d.ts +106 -7
- package/misc.d.ts.map +1 -1
- package/misc.js +141 -32
- package/misc.js.map +1 -1
- package/nist.d.ts +112 -11
- package/nist.d.ts.map +1 -1
- package/nist.js +139 -17
- package/nist.js.map +1 -1
- package/package.json +11 -6
- package/secp256k1.d.ts +92 -15
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +211 -28
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +350 -67
- package/src/abstract/curve.ts +327 -44
- package/src/abstract/edwards.ts +367 -143
- package/src/abstract/fft.ts +369 -36
- package/src/abstract/frost.ts +1092 -0
- package/src/abstract/hash-to-curve.ts +255 -56
- package/src/abstract/modular.ts +591 -144
- package/src/abstract/montgomery.ts +114 -30
- package/src/abstract/oprf.ts +383 -194
- package/src/abstract/poseidon.ts +235 -35
- package/src/abstract/tower.ts +428 -159
- package/src/abstract/weierstrass.ts +710 -312
- package/src/bls12-381.ts +239 -236
- package/src/bn254.ts +107 -46
- package/src/ed25519.ts +227 -55
- package/src/ed448.ts +227 -57
- package/src/index.ts +7 -1
- package/src/misc.ts +154 -35
- package/src/nist.ts +143 -20
- package/src/secp256k1.ts +284 -41
- package/src/utils.ts +583 -81
- package/src/webcrypto.ts +302 -73
- package/utils.d.ts +457 -24
- package/utils.d.ts.map +1 -1
- package/utils.js +410 -53
- package/utils.js.map +1 -1
- package/webcrypto.d.ts +167 -25
- package/webcrypto.d.ts.map +1 -1
- package/webcrypto.js +165 -58
- package/webcrypto.js.map +1 -1
package/src/abstract/curve.ts
CHANGED
|
@@ -4,14 +4,17 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
7
|
-
import { bitLen, bitMask, type Signer } from '../utils.ts';
|
|
7
|
+
import { bitLen, bitMask, validateObject, type Signer, type TArg, type TRet } from '../utils.ts';
|
|
8
8
|
import { Field, FpInvertBatch, validateField, type IField } from './modular.ts';
|
|
9
9
|
|
|
10
10
|
const _0n = /* @__PURE__ */ BigInt(0);
|
|
11
11
|
const _1n = /* @__PURE__ */ BigInt(1);
|
|
12
12
|
|
|
13
|
+
/** Affine point coordinates without projective fields. */
|
|
13
14
|
export type AffinePoint<T> = {
|
|
15
|
+
/** Affine x coordinate. */
|
|
14
16
|
x: T;
|
|
17
|
+
/** Affine y coordinate. */
|
|
15
18
|
y: T;
|
|
16
19
|
} & { Z?: never };
|
|
17
20
|
|
|
@@ -23,48 +26,144 @@ export type AffinePoint<T> = {
|
|
|
23
26
|
// with `any`, because of recursion, `any implements CurvePoint`,
|
|
24
27
|
// but we lose all constrains on methods.
|
|
25
28
|
|
|
26
|
-
/** Base interface for all elliptic
|
|
29
|
+
/** Base interface for all elliptic-curve point instances. */
|
|
27
30
|
export interface CurvePoint<F, P extends CurvePoint<F, P>> {
|
|
28
31
|
/** Affine x coordinate. Different from projective / extended X coordinate. */
|
|
29
32
|
x: F;
|
|
30
33
|
/** Affine y coordinate. Different from projective / extended Y coordinate. */
|
|
31
34
|
y: F;
|
|
35
|
+
/** Projective Z coordinate when the point keeps projective state. */
|
|
32
36
|
Z?: F;
|
|
37
|
+
/**
|
|
38
|
+
* Double the point.
|
|
39
|
+
* @returns Doubled point.
|
|
40
|
+
*/
|
|
33
41
|
double(): P;
|
|
42
|
+
/**
|
|
43
|
+
* Negate the point.
|
|
44
|
+
* @returns Negated point.
|
|
45
|
+
*/
|
|
34
46
|
negate(): P;
|
|
47
|
+
/**
|
|
48
|
+
* Add another point from the same curve.
|
|
49
|
+
* @param other - Point to add.
|
|
50
|
+
* @returns Sum point.
|
|
51
|
+
*/
|
|
35
52
|
add(other: P): P;
|
|
53
|
+
/**
|
|
54
|
+
* Subtract another point from the same curve.
|
|
55
|
+
* @param other - Point to subtract.
|
|
56
|
+
* @returns Difference point.
|
|
57
|
+
*/
|
|
36
58
|
subtract(other: P): P;
|
|
59
|
+
/**
|
|
60
|
+
* Compare two points for equality.
|
|
61
|
+
* @param other - Point to compare.
|
|
62
|
+
* @returns Whether the points are equal.
|
|
63
|
+
*/
|
|
37
64
|
equals(other: P): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Multiply the point by a scalar in constant time.
|
|
67
|
+
* Implementations keep the subgroup-scalar contract strict and may reject
|
|
68
|
+
* `0` instead of returning the identity point.
|
|
69
|
+
* @param scalar - Scalar multiplier.
|
|
70
|
+
* @returns Product point.
|
|
71
|
+
*/
|
|
38
72
|
multiply(scalar: bigint): P;
|
|
73
|
+
/** Assert that the point satisfies the curve equation and subgroup checks. */
|
|
39
74
|
assertValidity(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Map the point into the prime-order subgroup when the curve requires it.
|
|
77
|
+
* @returns Prime-order point.
|
|
78
|
+
*/
|
|
40
79
|
clearCofactor(): P;
|
|
80
|
+
/**
|
|
81
|
+
* Check whether the point is the point at infinity.
|
|
82
|
+
* @returns Whether the point is zero.
|
|
83
|
+
*/
|
|
41
84
|
is0(): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Check whether the point belongs to the prime-order subgroup.
|
|
87
|
+
* @returns Whether the point is torsion-free.
|
|
88
|
+
*/
|
|
42
89
|
isTorsionFree(): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Check whether the point lies in a small torsion subgroup.
|
|
92
|
+
* @returns Whether the point has small order.
|
|
93
|
+
*/
|
|
43
94
|
isSmallOrder(): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Multiply the point by a scalar without constant-time guarantees.
|
|
97
|
+
* Public-scalar callers that need `0` should use this method instead of
|
|
98
|
+
* relying on `multiply(...)` to return the identity point.
|
|
99
|
+
* @param scalar - Scalar multiplier.
|
|
100
|
+
* @returns Product point.
|
|
101
|
+
*/
|
|
44
102
|
multiplyUnsafe(scalar: bigint): P;
|
|
45
103
|
/**
|
|
46
104
|
* Massively speeds up `p.multiply(n)` by using precompute tables (caching). See {@link wNAF}.
|
|
47
|
-
*
|
|
105
|
+
* Cache state lives in internal WeakMaps keyed by point identity, not on the point object.
|
|
106
|
+
* Repeating `precompute(...)` for the same point identity replaces the remembered window size
|
|
107
|
+
* and forces table regeneration for that point.
|
|
108
|
+
* @param windowSize - Precompute window size.
|
|
109
|
+
* @param isLazy - calculate cache now. Default (true) ensures it's deferred to first `multiply()`
|
|
110
|
+
* @returns Same point instance with precompute tables attached.
|
|
48
111
|
*/
|
|
49
112
|
precompute(windowSize?: number, isLazy?: boolean): P;
|
|
50
|
-
/**
|
|
113
|
+
/**
|
|
114
|
+
* Converts point to 2D xy affine coordinates.
|
|
115
|
+
* @param invertedZ - Optional inverted Z coordinate for batch normalization.
|
|
116
|
+
* @returns Affine x/y coordinates.
|
|
117
|
+
*/
|
|
51
118
|
toAffine(invertedZ?: F): AffinePoint<F>;
|
|
119
|
+
/**
|
|
120
|
+
* Encode the point into the curve's canonical byte form.
|
|
121
|
+
* @returns Encoded point bytes.
|
|
122
|
+
*/
|
|
52
123
|
toBytes(): Uint8Array;
|
|
124
|
+
/**
|
|
125
|
+
* Encode the point into the curve's canonical hex form.
|
|
126
|
+
* @returns Encoded point hex.
|
|
127
|
+
*/
|
|
53
128
|
toHex(): string;
|
|
54
129
|
}
|
|
55
130
|
|
|
56
|
-
/** Base interface for
|
|
131
|
+
/** Base interface for elliptic-curve point constructors. */
|
|
57
132
|
export interface CurvePointCons<P extends CurvePoint<any, P>> {
|
|
133
|
+
/**
|
|
134
|
+
* Runtime brand check for points created by this constructor.
|
|
135
|
+
* @param item - Value to test.
|
|
136
|
+
* @returns Whether the value is a point from this constructor.
|
|
137
|
+
*/
|
|
58
138
|
[Symbol.hasInstance]: (item: unknown) => boolean;
|
|
139
|
+
/** Canonical subgroup generator. */
|
|
59
140
|
BASE: P;
|
|
141
|
+
/** Point at infinity. */
|
|
60
142
|
ZERO: P;
|
|
61
143
|
/** Field for basic curve math */
|
|
62
144
|
Fp: IField<P_F<P>>;
|
|
63
145
|
/** Scalar field, for scalars in multiply and others */
|
|
64
146
|
Fn: IField<bigint>;
|
|
65
|
-
/**
|
|
147
|
+
/**
|
|
148
|
+
* Create one point from affine coordinates.
|
|
149
|
+
* Does NOT validate curve, subgroup, or wrapper invariants.
|
|
150
|
+
* Use `.assertValidity()` on adversarial inputs.
|
|
151
|
+
* @param p - Affine point coordinates.
|
|
152
|
+
* @returns Point instance.
|
|
153
|
+
*/
|
|
66
154
|
fromAffine(p: AffinePoint<P_F<P>>): P;
|
|
155
|
+
/**
|
|
156
|
+
* Decode a point from the canonical byte encoding.
|
|
157
|
+
* @param bytes - Encoded point bytes.
|
|
158
|
+
* Implementations MUST treat `bytes` as read-only.
|
|
159
|
+
* @returns Point instance.
|
|
160
|
+
*/
|
|
67
161
|
fromBytes(bytes: Uint8Array): P;
|
|
162
|
+
/**
|
|
163
|
+
* Decode a point from the canonical hex encoding.
|
|
164
|
+
* @param hex - Encoded point hex.
|
|
165
|
+
* @returns Point instance.
|
|
166
|
+
*/
|
|
68
167
|
fromHex(hex: string): P;
|
|
69
168
|
}
|
|
70
169
|
|
|
@@ -79,11 +178,11 @@ export interface CurvePointCons<P extends CurvePoint<any, P>> {
|
|
|
79
178
|
// `function test<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(`
|
|
80
179
|
// if we want type safety around P, otherwise PC_P<PC> will be any
|
|
81
180
|
|
|
82
|
-
/** Returns
|
|
181
|
+
/** Returns the affine field type for a point instance (`P_F<P> == P.F`). */
|
|
83
182
|
export type P_F<P extends CurvePoint<any, P>> = P extends CurvePoint<infer F, P> ? F : never;
|
|
84
|
-
/** Returns
|
|
183
|
+
/** Returns the affine field type for a point constructor (`PC_F<PC> == PC.P.F`). */
|
|
85
184
|
export type PC_F<PC extends CurvePointCons<CurvePoint<any, any>>> = PC['Fp']['ZERO'];
|
|
86
|
-
/** Returns
|
|
185
|
+
/** Returns the point instance type for a point constructor (`PC_P<PC> == PC.P`). */
|
|
87
186
|
export type PC_P<PC extends CurvePointCons<CurvePoint<any, any>>> = PC['ZERO'];
|
|
88
187
|
|
|
89
188
|
// Ugly hack to get proper type inference, because in typescript fails to infer resursively.
|
|
@@ -100,6 +199,7 @@ export type PC_P<PC extends CurvePointCons<CurvePoint<any, any>>> = PC['ZERO'];
|
|
|
100
199
|
// * But generally, we don't want to parametrize `CurvePointCons` over `F`: it will complicate
|
|
101
200
|
// types, making them un-inferable
|
|
102
201
|
// prettier-ignore
|
|
202
|
+
/** Wide point-constructor type used when the concrete curve is not important. */
|
|
103
203
|
export type PC_ANY = CurvePointCons<
|
|
104
204
|
CurvePoint<any,
|
|
105
205
|
CurvePoint<any,
|
|
@@ -114,17 +214,79 @@ export type PC_ANY = CurvePointCons<
|
|
|
114
214
|
>>>>>>>>>
|
|
115
215
|
>;
|
|
116
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Validates the static surface of a point constructor.
|
|
219
|
+
* This is only a cheap sanity check for the constructor hooks and fields consumed by generic
|
|
220
|
+
* factories; it does not certify `BASE`/`ZERO` semantics or prove the curve implementation itself.
|
|
221
|
+
* @param Point - Runtime point constructor.
|
|
222
|
+
* @throws On missing constructor hooks or malformed field metadata. {@link TypeError}
|
|
223
|
+
* @example
|
|
224
|
+
* Check that one point constructor exposes the static hooks generic helpers need.
|
|
225
|
+
*
|
|
226
|
+
* ```ts
|
|
227
|
+
* import { ed25519 } from '@noble/curves/ed25519.js';
|
|
228
|
+
* import { validatePointCons } from '@noble/curves/abstract/curve.js';
|
|
229
|
+
* validatePointCons(ed25519.Point);
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
export function validatePointCons<P extends CurvePoint<any, P>>(Point: CurvePointCons<P>): void {
|
|
233
|
+
const pc = Point as unknown as CurvePointCons<any>;
|
|
234
|
+
if (typeof (pc as unknown) !== 'function') throw new TypeError('Point must be a constructor');
|
|
235
|
+
// validateObject only accepts plain objects, so copy the constructor statics into one bag first.
|
|
236
|
+
validateObject(
|
|
237
|
+
{
|
|
238
|
+
Fp: pc.Fp,
|
|
239
|
+
Fn: pc.Fn,
|
|
240
|
+
fromAffine: pc.fromAffine,
|
|
241
|
+
fromBytes: pc.fromBytes,
|
|
242
|
+
fromHex: pc.fromHex,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
Fp: 'object',
|
|
246
|
+
Fn: 'object',
|
|
247
|
+
fromAffine: 'function',
|
|
248
|
+
fromBytes: 'function',
|
|
249
|
+
fromHex: 'function',
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
validateField(pc.Fp);
|
|
253
|
+
validateField(pc.Fn);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Byte lengths used by one curve implementation. */
|
|
117
257
|
export interface CurveLengths {
|
|
258
|
+
/** Secret-key length in bytes. */
|
|
118
259
|
secretKey?: number;
|
|
260
|
+
/** Compressed public-key length in bytes. */
|
|
119
261
|
publicKey?: number;
|
|
262
|
+
/** Uncompressed public-key length in bytes. */
|
|
120
263
|
publicKeyUncompressed?: number;
|
|
264
|
+
/** Whether public-key encodings include a format prefix byte. */
|
|
121
265
|
publicKeyHasPrefix?: boolean;
|
|
266
|
+
/** Signature length in bytes. */
|
|
122
267
|
signature?: number;
|
|
268
|
+
/** Seed length in bytes when the curve exposes deterministic keygen from seed. */
|
|
123
269
|
seed?: number;
|
|
124
270
|
}
|
|
125
271
|
|
|
272
|
+
/** Reorders or otherwise remaps a batch while preserving its element type. */
|
|
126
273
|
export type Mapper<T> = (i: T[]) => T[];
|
|
127
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Computes both candidates first, but the final selection still branches on `condition`, so this
|
|
277
|
+
* is not a strict constant-time CMOV primitive.
|
|
278
|
+
* @param condition - Whether to negate the point.
|
|
279
|
+
* @param item - Point-like value.
|
|
280
|
+
* @returns Original or negated value.
|
|
281
|
+
* @example
|
|
282
|
+
* Keep the point or return its negation based on one boolean branch.
|
|
283
|
+
*
|
|
284
|
+
* ```ts
|
|
285
|
+
* import { negateCt } from '@noble/curves/abstract/curve.js';
|
|
286
|
+
* import { p256 } from '@noble/curves/nist.js';
|
|
287
|
+
* const maybeNegated = negateCt(true, p256.Point.BASE);
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
128
290
|
export function negateCt<T extends { negate: () => T }>(condition: boolean, item: T): T {
|
|
129
291
|
const neg = item.negate();
|
|
130
292
|
return condition ? neg : item;
|
|
@@ -135,6 +297,18 @@ export function negateCt<T extends { negate: () => T }>(condition: boolean, item
|
|
|
135
297
|
* inversion on all of them. Inversion is very slow operation,
|
|
136
298
|
* so this improves performance massively.
|
|
137
299
|
* Optimization: converts a list of projective points to a list of identical points with Z=1.
|
|
300
|
+
* Input points are left unchanged; the normalized points are returned as fresh instances.
|
|
301
|
+
* @param c - Point constructor.
|
|
302
|
+
* @param points - Projective points.
|
|
303
|
+
* @returns Fresh projective points reconstructed from normalized affine coordinates.
|
|
304
|
+
* @example
|
|
305
|
+
* Batch-normalize projective points with a single shared inversion.
|
|
306
|
+
*
|
|
307
|
+
* ```ts
|
|
308
|
+
* import { normalizeZ } from '@noble/curves/abstract/curve.js';
|
|
309
|
+
* import { p256 } from '@noble/curves/nist.js';
|
|
310
|
+
* const points = normalizeZ(p256.Point, [p256.Point.BASE, p256.Point.BASE.double()]);
|
|
311
|
+
* ```
|
|
138
312
|
*/
|
|
139
313
|
export function normalizeZ<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(
|
|
140
314
|
c: PC,
|
|
@@ -152,7 +326,10 @@ function validateW(W: number, bits: number) {
|
|
|
152
326
|
throw new Error('invalid window size, expected [1..' + bits + '], got W=' + W);
|
|
153
327
|
}
|
|
154
328
|
|
|
155
|
-
/** Internal wNAF opts for specific W and scalarBits
|
|
329
|
+
/** Internal wNAF opts for specific W and scalarBits.
|
|
330
|
+
* Zero digits are skipped, so tables store only the positive half-window and callers reserve one
|
|
331
|
+
* extra carry window.
|
|
332
|
+
*/
|
|
156
333
|
type WOpts = {
|
|
157
334
|
windows: number;
|
|
158
335
|
windowSize: number;
|
|
@@ -188,11 +365,11 @@ function calcOffsets(n: bigint, window: number, wOpts: WOpts) {
|
|
|
188
365
|
nextN += _1n; // +256 (carry)
|
|
189
366
|
}
|
|
190
367
|
const offsetStart = window * windowSize;
|
|
191
|
-
const offset = offsetStart + Math.abs(wbits) - 1; // -1 because we skip zero
|
|
368
|
+
const offset = offsetStart + Math.abs(wbits) - 1; // -1 because we skip zero; ignore when isZero
|
|
192
369
|
const isZero = wbits === 0; // is current window slice a 0?
|
|
193
370
|
const isNeg = wbits < 0; // is current window slice negative?
|
|
194
|
-
const isNegF = window % 2 !== 0; // fake
|
|
195
|
-
const offsetF = offsetStart; // fake
|
|
371
|
+
const isNegF = window % 2 !== 0; // fake branch noise only
|
|
372
|
+
const offsetF = offsetStart; // fake branch noise only
|
|
196
373
|
return { nextN, offset, isZero, isNeg, isNegF, offsetF };
|
|
197
374
|
}
|
|
198
375
|
|
|
@@ -218,10 +395,13 @@ const pointWindowSizes = new WeakMap<any, number>();
|
|
|
218
395
|
function getW(P: any): number {
|
|
219
396
|
// To disable precomputes:
|
|
220
397
|
// return 1;
|
|
398
|
+
// `1` is also the uncached sentinel: use the ladder / non-precomputed path.
|
|
221
399
|
return pointWindowSizes.get(P) || 1;
|
|
222
400
|
}
|
|
223
401
|
|
|
224
402
|
function assert0(n: bigint): void {
|
|
403
|
+
// Internal invariant: a non-zero remainder here means the wNAF window decomposition or loop
|
|
404
|
+
// count is inconsistent, not that the original caller provided a bad scalar.
|
|
225
405
|
if (n !== _0n) throw new Error('invalid wNAF');
|
|
226
406
|
}
|
|
227
407
|
|
|
@@ -240,8 +420,18 @@ function assert0(n: bigint): void {
|
|
|
240
420
|
* - +1 window is neccessary for wNAF
|
|
241
421
|
* - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication
|
|
242
422
|
*
|
|
243
|
-
*
|
|
244
|
-
* This would allow windows to be in different memory locations
|
|
423
|
+
* TODO: research returning a 2d JS array of windows instead of a single window.
|
|
424
|
+
* This would allow windows to be in different memory locations.
|
|
425
|
+
* @param Point - Point constructor.
|
|
426
|
+
* @param bits - Scalar bit length.
|
|
427
|
+
* @example
|
|
428
|
+
* Elliptic curve multiplication of Point by scalar.
|
|
429
|
+
*
|
|
430
|
+
* ```ts
|
|
431
|
+
* import { wNAF } from '@noble/curves/abstract/curve.js';
|
|
432
|
+
* import { p256 } from '@noble/curves/nist.js';
|
|
433
|
+
* const ladder = new wNAF(p256.Point, p256.Point.Fn.BITS);
|
|
434
|
+
* ```
|
|
245
435
|
*/
|
|
246
436
|
export class wNAF<PC extends PC_ANY> {
|
|
247
437
|
private readonly BASE: PC_P<PC>;
|
|
@@ -276,8 +466,8 @@ export class wNAF<PC extends PC_ANY> {
|
|
|
276
466
|
* - 𝑊 is the window size
|
|
277
467
|
* - 𝑛 is the bitlength of the curve order.
|
|
278
468
|
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
|
|
279
|
-
* @param point Point instance
|
|
280
|
-
* @param W window size
|
|
469
|
+
* @param point - Point instance
|
|
470
|
+
* @param W - window size
|
|
281
471
|
* @returns precomputed point tables flattened to a single array
|
|
282
472
|
*/
|
|
283
473
|
private precomputeWindow(point: PC_P<PC>, W: number): PC_P<PC>[] {
|
|
@@ -330,15 +520,16 @@ export class wNAF<PC extends PC_ANY> {
|
|
|
330
520
|
}
|
|
331
521
|
}
|
|
332
522
|
assert0(n);
|
|
333
|
-
// Return both real and fake points
|
|
334
|
-
//
|
|
335
|
-
// which
|
|
523
|
+
// Return both real and fake points so JIT keeps the noise path alive.
|
|
524
|
+
// Known caveat: negate/carry interactions can still drive `f` to infinity even when `p` is not,
|
|
525
|
+
// which weakens the noise path and leaves this only "less const-time" by about one bigint mul.
|
|
336
526
|
return { p, f };
|
|
337
527
|
}
|
|
338
528
|
|
|
339
529
|
/**
|
|
340
|
-
* Implements
|
|
341
|
-
*
|
|
530
|
+
* Implements unsafe EC multiplication using precomputed tables
|
|
531
|
+
* and w-ary non-adjacent form.
|
|
532
|
+
* @param acc - accumulator point to add result of multiplication
|
|
342
533
|
* @returns point
|
|
343
534
|
*/
|
|
344
535
|
private wNAFUnsafe(
|
|
@@ -366,7 +557,8 @@ export class wNAF<PC extends PC_ANY> {
|
|
|
366
557
|
}
|
|
367
558
|
|
|
368
559
|
private getPrecomputes(W: number, point: PC_P<PC>, transform?: Mapper<PC_P<PC>>): PC_P<PC>[] {
|
|
369
|
-
//
|
|
560
|
+
// Cache key is only point identity plus the remembered window size; callers must not reuse the
|
|
561
|
+
// same point with incompatible `transform(...)` layouts and expect a separate cache entry.
|
|
370
562
|
let comp = pointPrecomputes.get(point);
|
|
371
563
|
if (!comp) {
|
|
372
564
|
comp = this.precomputeWindow(point, W) as PC_P<PC>[];
|
|
@@ -411,6 +603,19 @@ export class wNAF<PC extends PC_ANY> {
|
|
|
411
603
|
/**
|
|
412
604
|
* Endomorphism-specific multiplication for Koblitz curves.
|
|
413
605
|
* Cost: 128 dbl, 0-256 adds.
|
|
606
|
+
* @param Point - Point constructor.
|
|
607
|
+
* @param point - Input point.
|
|
608
|
+
* @param k1 - First non-negative absolute scalar chunk.
|
|
609
|
+
* @param k2 - Second non-negative absolute scalar chunk.
|
|
610
|
+
* @returns Partial multiplication results.
|
|
611
|
+
* @example
|
|
612
|
+
* Endomorphism-specific multiplication for Koblitz curves.
|
|
613
|
+
*
|
|
614
|
+
* ```ts
|
|
615
|
+
* import { mulEndoUnsafe } from '@noble/curves/abstract/curve.js';
|
|
616
|
+
* import { secp256k1 } from '@noble/curves/secp256k1.js';
|
|
617
|
+
* const parts = mulEndoUnsafe(secp256k1.Point, secp256k1.Point.BASE, 3n, 5n);
|
|
618
|
+
* ```
|
|
414
619
|
*/
|
|
415
620
|
export function mulEndoUnsafe<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(
|
|
416
621
|
Point: PC,
|
|
@@ -436,10 +641,19 @@ export function mulEndoUnsafe<P extends CurvePoint<any, P>, PC extends CurvePoin
|
|
|
436
641
|
* 30x faster vs naive addition on L=4096, 10x faster than precomputes.
|
|
437
642
|
* For N=254bit, L=1, it does: 1024 ADD + 254 DBL. For L=5: 1536 ADD + 254 DBL.
|
|
438
643
|
* Algorithmically constant-time (for same L), even when 1 point + scalar, or when scalar = 0.
|
|
439
|
-
* @param c Curve Point constructor
|
|
440
|
-
* @param
|
|
441
|
-
* @param
|
|
442
|
-
* @
|
|
644
|
+
* @param c - Curve Point constructor
|
|
645
|
+
* @param points - array of L curve points
|
|
646
|
+
* @param scalars - array of L scalars (aka secret keys / bigints)
|
|
647
|
+
* @returns MSM result point. Empty input is accepted and returns the identity.
|
|
648
|
+
* @throws If the point set, scalar set, or MSM sizing is invalid. {@link Error}
|
|
649
|
+
* @example
|
|
650
|
+
* Pippenger algorithm for multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
|
651
|
+
*
|
|
652
|
+
* ```ts
|
|
653
|
+
* import { pippenger } from '@noble/curves/abstract/curve.js';
|
|
654
|
+
* import { p256 } from '@noble/curves/nist.js';
|
|
655
|
+
* const point = pippenger(p256.Point, [p256.Point.BASE, p256.Point.BASE.double()], [2n, 3n]);
|
|
656
|
+
* ```
|
|
443
657
|
*/
|
|
444
658
|
export function pippenger<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(
|
|
445
659
|
c: PC,
|
|
@@ -489,10 +703,21 @@ export function pippenger<P extends CurvePoint<any, P>, PC extends CurvePointCon
|
|
|
489
703
|
}
|
|
490
704
|
/**
|
|
491
705
|
* Precomputed multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
|
492
|
-
* @param c Curve Point constructor
|
|
493
|
-
* @param
|
|
494
|
-
* @param
|
|
495
|
-
* @returns
|
|
706
|
+
* @param c - Curve Point constructor
|
|
707
|
+
* @param points - array of L curve points
|
|
708
|
+
* @param windowSize - Precompute window size.
|
|
709
|
+
* @returns Function which multiplies points with scalars. The closure accepts
|
|
710
|
+
* `scalars.length <= points.length`, and omitted trailing scalars are treated as zero.
|
|
711
|
+
* @throws If the point set or precompute window is invalid. {@link Error}
|
|
712
|
+
* @example
|
|
713
|
+
* Precomputed multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
|
714
|
+
*
|
|
715
|
+
* ```ts
|
|
716
|
+
* import { precomputeMSMUnsafe } from '@noble/curves/abstract/curve.js';
|
|
717
|
+
* import { p256 } from '@noble/curves/nist.js';
|
|
718
|
+
* const msm = precomputeMSMUnsafe(p256.Point, [p256.Point.BASE], 4);
|
|
719
|
+
* const point = msm([3n]);
|
|
720
|
+
* ```
|
|
496
721
|
*/
|
|
497
722
|
export function precomputeMSMUnsafe<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(
|
|
498
723
|
c: PC,
|
|
@@ -569,35 +794,79 @@ export function precomputeMSMUnsafe<P extends CurvePoint<any, P>, PC extends Cur
|
|
|
569
794
|
};
|
|
570
795
|
}
|
|
571
796
|
|
|
797
|
+
/** Minimal curve parameters needed to construct a Weierstrass or Edwards curve. */
|
|
572
798
|
export type ValidCurveParams<T> = {
|
|
799
|
+
/** Base-field modulus. */
|
|
573
800
|
p: bigint;
|
|
801
|
+
/** Prime subgroup order. */
|
|
574
802
|
n: bigint;
|
|
803
|
+
/** Cofactor. */
|
|
575
804
|
h: bigint;
|
|
805
|
+
/** Curve parameter `a`. */
|
|
576
806
|
a: T;
|
|
807
|
+
/** Weierstrass curve parameter `b`. */
|
|
577
808
|
b?: T;
|
|
809
|
+
/** Edwards curve parameter `d`. */
|
|
578
810
|
d?: T;
|
|
811
|
+
/** Generator x coordinate. */
|
|
579
812
|
Gx: T;
|
|
813
|
+
/** Generator y coordinate. */
|
|
580
814
|
Gy: T;
|
|
581
815
|
};
|
|
582
816
|
|
|
583
|
-
function createField<T>(order: bigint, field?: IField<T
|
|
817
|
+
function createField<T>(order: bigint, field?: TArg<IField<T>>, isLE?: boolean): TRet<IField<T>> {
|
|
584
818
|
if (field) {
|
|
819
|
+
// Reuse supplied field overrides as-is; `isLE` only affects freshly constructed fallback
|
|
820
|
+
// fields, and validateField() below only checks the arithmetic subset, not full byte/cmov
|
|
821
|
+
// behavior.
|
|
585
822
|
if (field.ORDER !== order) throw new Error('Field.ORDER must match order: Fp == p, Fn == n');
|
|
586
823
|
validateField(field);
|
|
587
|
-
return field
|
|
824
|
+
return field as TRet<IField<T>>;
|
|
588
825
|
} else {
|
|
589
|
-
return Field(order, { isLE }) as unknown as IField<T
|
|
826
|
+
return Field(order, { isLE }) as unknown as TRet<IField<T>>;
|
|
590
827
|
}
|
|
591
828
|
}
|
|
592
|
-
|
|
829
|
+
/** Pair of fields used by curve constructors. */
|
|
830
|
+
export type FpFn<T> = {
|
|
831
|
+
/** Base field used for curve coordinates. */
|
|
832
|
+
Fp: IField<T>;
|
|
833
|
+
/** Scalar field used for secret scalars and subgroup arithmetic. */
|
|
834
|
+
Fn: IField<bigint>;
|
|
835
|
+
};
|
|
593
836
|
|
|
594
|
-
/**
|
|
837
|
+
/**
|
|
838
|
+
* Validates basic CURVE shape and field membership, then creates fields.
|
|
839
|
+
* This does not prove that the generator is on-curve, that subgroup/order data are consistent, or
|
|
840
|
+
* that the curve equation itself is otherwise sane.
|
|
841
|
+
* @param type - Curve family.
|
|
842
|
+
* @param CURVE - Curve parameters.
|
|
843
|
+
* @param curveOpts - Optional field overrides:
|
|
844
|
+
* - `Fp` (optional): Optional base-field override.
|
|
845
|
+
* - `Fn` (optional): Optional scalar-field override.
|
|
846
|
+
* @param FpFnLE - Whether field encoding is little-endian.
|
|
847
|
+
* @returns Frozen curve parameters and fields.
|
|
848
|
+
* @throws If the curve parameters or field overrides are invalid. {@link Error}
|
|
849
|
+
* @example
|
|
850
|
+
* Build curve fields from raw constants before constructing a curve instance.
|
|
851
|
+
*
|
|
852
|
+
* ```ts
|
|
853
|
+
* const curve = createCurveFields('weierstrass', {
|
|
854
|
+
* p: 17n,
|
|
855
|
+
* n: 19n,
|
|
856
|
+
* h: 1n,
|
|
857
|
+
* a: 2n,
|
|
858
|
+
* b: 2n,
|
|
859
|
+
* Gx: 5n,
|
|
860
|
+
* Gy: 1n,
|
|
861
|
+
* });
|
|
862
|
+
* ```
|
|
863
|
+
*/
|
|
595
864
|
export function createCurveFields<T>(
|
|
596
865
|
type: 'weierstrass' | 'edwards',
|
|
597
866
|
CURVE: ValidCurveParams<T>,
|
|
598
|
-
curveOpts: Partial<FpFn<T
|
|
867
|
+
curveOpts: TArg<Partial<FpFn<T>>> = {},
|
|
599
868
|
FpFnLE?: boolean
|
|
600
|
-
): FpFn<T> & { CURVE: ValidCurveParams<T> } {
|
|
869
|
+
): TRet<FpFn<T> & { CURVE: ValidCurveParams<T> }> {
|
|
601
870
|
if (FpFnLE === undefined) FpFnLE = type === 'edwards';
|
|
602
871
|
if (!CURVE || typeof CURVE !== 'object') throw new Error(`expected valid ${type} CURVE object`);
|
|
603
872
|
for (const p of ['p', 'n', 'h'] as const) {
|
|
@@ -615,19 +884,33 @@ export function createCurveFields<T>(
|
|
|
615
884
|
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
|
|
616
885
|
}
|
|
617
886
|
CURVE = Object.freeze(Object.assign({}, CURVE));
|
|
618
|
-
return { CURVE, Fp, Fn }
|
|
887
|
+
return { CURVE, Fp, Fn } as TRet<FpFn<T> & { CURVE: ValidCurveParams<T> }>;
|
|
619
888
|
}
|
|
620
889
|
|
|
621
890
|
type KeygenFn = (
|
|
622
891
|
seed?: Uint8Array,
|
|
623
892
|
isCompressed?: boolean
|
|
624
893
|
) => { secretKey: Uint8Array; publicKey: Uint8Array };
|
|
894
|
+
/**
|
|
895
|
+
* @param randomSecretKey - Secret-key generator.
|
|
896
|
+
* @param getPublicKey - Public-key derivation helper.
|
|
897
|
+
* @returns Keypair generator.
|
|
898
|
+
* @example
|
|
899
|
+
* Build a `keygen()` helper from existing secret-key and public-key primitives.
|
|
900
|
+
*
|
|
901
|
+
* ```ts
|
|
902
|
+
* import { createKeygen } from '@noble/curves/abstract/curve.js';
|
|
903
|
+
* import { p256 } from '@noble/curves/nist.js';
|
|
904
|
+
* const keygen = createKeygen(p256.utils.randomSecretKey, p256.getPublicKey);
|
|
905
|
+
* const pair = keygen();
|
|
906
|
+
* ```
|
|
907
|
+
*/
|
|
625
908
|
export function createKeygen(
|
|
626
909
|
randomSecretKey: Function,
|
|
627
|
-
getPublicKey: Signer['getPublicKey']
|
|
628
|
-
): KeygenFn {
|
|
629
|
-
return function keygen(seed?: Uint8Array) {
|
|
630
|
-
const secretKey = randomSecretKey(seed)
|
|
631
|
-
return { secretKey, publicKey: getPublicKey(secretKey) };
|
|
910
|
+
getPublicKey: TArg<Signer['getPublicKey']>
|
|
911
|
+
): TRet<KeygenFn> {
|
|
912
|
+
return function keygen(seed?: TArg<Uint8Array>) {
|
|
913
|
+
const secretKey = randomSecretKey(seed) as TRet<Uint8Array>;
|
|
914
|
+
return { secretKey, publicKey: getPublicKey(secretKey) as TRet<Uint8Array> };
|
|
632
915
|
};
|
|
633
916
|
}
|