@noble/curves 1.9.1 → 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.
- package/README.md +238 -227
- package/_shortw_utils.d.ts +8 -5
- package/_shortw_utils.d.ts.map +1 -1
- package/_shortw_utils.js +3 -8
- package/_shortw_utils.js.map +1 -1
- package/abstract/bls.d.ts +123 -62
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +219 -163
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +142 -21
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +224 -143
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +190 -49
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +322 -136
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +12 -10
- package/abstract/fft.d.ts.map +1 -1
- package/abstract/fft.js +12 -13
- package/abstract/fft.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +31 -13
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +34 -19
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +31 -13
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +125 -52
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +18 -5
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +23 -6
- package/abstract/montgomery.js.map +1 -1
- package/abstract/poseidon.d.ts +5 -13
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +12 -7
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +23 -49
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +9 -3
- package/abstract/tower.js.map +1 -1
- package/abstract/utils.d.ts +1 -115
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +17 -371
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +206 -124
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +747 -604
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +2 -0
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +504 -466
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +2 -0
- package/bn254.d.ts.map +1 -1
- package/bn254.js +44 -32
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +55 -66
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +172 -186
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +60 -57
- package/ed448.d.ts.map +1 -1
- package/ed448.js +172 -166
- package/ed448.js.map +1 -1
- package/esm/_shortw_utils.d.ts +8 -5
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/_shortw_utils.js +3 -8
- package/esm/_shortw_utils.js.map +1 -1
- package/esm/abstract/bls.d.ts +123 -62
- package/esm/abstract/bls.d.ts.map +1 -1
- package/esm/abstract/bls.js +220 -164
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +142 -21
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +219 -143
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +190 -49
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +320 -138
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/fft.d.ts +12 -10
- package/esm/abstract/fft.d.ts.map +1 -1
- package/esm/abstract/fft.js +10 -11
- package/esm/abstract/fft.js.map +1 -1
- package/esm/abstract/hash-to-curve.d.ts +31 -13
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +33 -19
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.d.ts +31 -13
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +124 -51
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +18 -5
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +23 -6
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/poseidon.d.ts +5 -13
- package/esm/abstract/poseidon.d.ts.map +1 -1
- package/esm/abstract/poseidon.js +12 -7
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/tower.d.ts +23 -49
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js +9 -3
- package/esm/abstract/tower.js.map +1 -1
- package/esm/abstract/utils.d.ts +1 -115
- package/esm/abstract/utils.d.ts.map +1 -1
- package/esm/abstract/utils.js +3 -344
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +206 -124
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +743 -605
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts +2 -0
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +503 -465
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.d.ts +2 -0
- package/esm/bn254.d.ts.map +1 -1
- package/esm/bn254.js +41 -29
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.d.ts +55 -66
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +170 -183
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +60 -57
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +169 -162
- package/esm/ed448.js.map +1 -1
- package/esm/index.js +7 -9
- package/esm/index.js.map +1 -1
- package/esm/jubjub.d.ts +3 -3
- package/esm/jubjub.d.ts.map +1 -1
- package/esm/jubjub.js +3 -3
- package/esm/jubjub.js.map +1 -1
- package/esm/misc.d.ts +3 -5
- package/esm/misc.d.ts.map +1 -1
- package/esm/misc.js +31 -29
- package/esm/misc.js.map +1 -1
- package/esm/nist.d.ts +7 -22
- package/esm/nist.d.ts.map +1 -1
- package/esm/nist.js +106 -101
- package/esm/nist.js.map +1 -1
- package/esm/p256.d.ts +7 -3
- package/esm/p256.d.ts.map +1 -1
- package/esm/p256.js +4 -0
- package/esm/p256.js.map +1 -1
- package/esm/p384.d.ts +7 -4
- package/esm/p384.d.ts.map +1 -1
- package/esm/p384.js +4 -1
- package/esm/p384.js.map +1 -1
- package/esm/p521.d.ts +7 -3
- package/esm/p521.d.ts.map +1 -1
- package/esm/p521.js +4 -0
- package/esm/p521.js.map +1 -1
- package/esm/secp256k1.d.ts +38 -21
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +112 -104
- package/esm/secp256k1.js.map +1 -1
- package/esm/utils.d.ts +96 -0
- package/esm/utils.d.ts.map +1 -0
- package/esm/utils.js +279 -0
- package/esm/utils.js.map +1 -0
- package/index.js +7 -9
- package/index.js.map +1 -1
- package/jubjub.d.ts +3 -3
- package/jubjub.d.ts.map +1 -1
- package/jubjub.js +3 -3
- package/jubjub.js.map +1 -1
- package/misc.d.ts +3 -5
- package/misc.d.ts.map +1 -1
- package/misc.js +35 -33
- package/misc.js.map +1 -1
- package/nist.d.ts +7 -22
- package/nist.d.ts.map +1 -1
- package/nist.js +106 -101
- package/nist.js.map +1 -1
- package/p256.d.ts +7 -3
- package/p256.d.ts.map +1 -1
- package/p256.js +4 -0
- package/p256.js.map +1 -1
- package/p384.d.ts +7 -4
- package/p384.d.ts.map +1 -1
- package/p384.js +4 -1
- package/p384.js.map +1 -1
- package/p521.d.ts +7 -3
- package/p521.d.ts.map +1 -1
- package/p521.js +4 -0
- package/p521.js.map +1 -1
- package/package.json +17 -6
- package/secp256k1.d.ts +38 -21
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +112 -104
- package/secp256k1.js.map +1 -1
- package/src/_shortw_utils.ts +6 -15
- package/src/abstract/bls.ts +428 -251
- package/src/abstract/curve.ts +307 -149
- package/src/abstract/edwards.ts +555 -203
- package/src/abstract/fft.ts +30 -19
- package/src/abstract/hash-to-curve.ts +75 -34
- package/src/abstract/modular.ts +131 -59
- package/src/abstract/montgomery.ts +44 -15
- package/src/abstract/poseidon.ts +22 -18
- package/src/abstract/tower.ts +40 -71
- package/src/abstract/utils.ts +3 -378
- package/src/abstract/weierstrass.ts +1086 -746
- package/src/bls12-381.ts +549 -490
- package/src/bn254.ts +47 -35
- package/src/ed25519.ts +214 -216
- package/src/ed448.ts +251 -220
- package/src/index.ts +7 -9
- package/src/jubjub.ts +3 -3
- package/src/misc.ts +41 -40
- package/src/nist.ts +161 -126
- package/src/p256.ts +7 -3
- package/src/p384.ts +7 -5
- package/src/p521.ts +7 -3
- package/src/secp256k1.ts +145 -115
- package/src/utils.ts +328 -0
- package/utils.d.ts +96 -0
- package/utils.d.ts.map +1 -0
- package/utils.js +313 -0
- package/utils.js.map +1 -0
package/src/abstract/curve.ts
CHANGED
|
@@ -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 {
|
|
8
|
-
import {
|
|
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;
|
|
@@ -22,19 +24,102 @@ export interface Group<T extends Group<T>> {
|
|
|
22
24
|
subtract(other: T): T;
|
|
23
25
|
equals(other: T): boolean;
|
|
24
26
|
multiply(scalar: bigint): T;
|
|
27
|
+
toAffine?(invertedZ?: any): AffinePoint<any>;
|
|
25
28
|
}
|
|
26
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
|
+
}
|
|
27
88
|
export type GroupConstructor<T> = {
|
|
28
89
|
BASE: T;
|
|
29
90
|
ZERO: T;
|
|
30
91
|
};
|
|
92
|
+
/** @deprecated */
|
|
93
|
+
export type ExtendedGroupConstructor<T> = GroupConstructor<T> & {
|
|
94
|
+
Fp: IField<any>;
|
|
95
|
+
Fn: IField<bigint>;
|
|
96
|
+
fromAffine(ap: AffinePoint<any>): T;
|
|
97
|
+
};
|
|
31
98
|
export type Mapper<T> = (i: T[]) => T[];
|
|
32
99
|
|
|
33
|
-
function
|
|
100
|
+
export function negateCt<T extends { negate: () => T }>(condition: boolean, item: T): T {
|
|
34
101
|
const neg = item.negate();
|
|
35
102
|
return condition ? neg : item;
|
|
36
103
|
}
|
|
37
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Takes a bunch of Projective Points but executes only one
|
|
107
|
+
* inversion on all of them. Inversion is very slow operation,
|
|
108
|
+
* so this improves performance massively.
|
|
109
|
+
* Optimization: converts a list of projective points to a list of identical points with Z=1.
|
|
110
|
+
*/
|
|
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])));
|
|
121
|
+
}
|
|
122
|
+
|
|
38
123
|
function validateW(W: number, bits: number) {
|
|
39
124
|
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
|
40
125
|
throw new Error('invalid window size, expected [1..' + bits + '], got W=' + W);
|
|
@@ -104,24 +189,21 @@ const pointPrecomputes = new WeakMap<any, any[]>();
|
|
|
104
189
|
const pointWindowSizes = new WeakMap<any, number>();
|
|
105
190
|
|
|
106
191
|
function getW(P: any): number {
|
|
192
|
+
// To disable precomputes:
|
|
193
|
+
// return 1;
|
|
107
194
|
return pointWindowSizes.get(P) || 1;
|
|
108
195
|
}
|
|
109
196
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
unsafeLadder(elm: T, n: bigint, p?: T): T;
|
|
114
|
-
precomputeWindow(elm: T, W: number): Group<T>[];
|
|
115
|
-
getPrecomputes(W: number, P: T, transform: Mapper<T>): T[];
|
|
116
|
-
wNAF(W: number, precomputes: T[], n: bigint): { p: T; f: T };
|
|
117
|
-
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;
|
|
120
|
-
setWindowSize(P: T, W: number): void;
|
|
121
|
-
};
|
|
197
|
+
function assert0(n: bigint): void {
|
|
198
|
+
if (n !== _0n) throw new Error('invalid wNAF');
|
|
199
|
+
}
|
|
122
200
|
|
|
123
201
|
/**
|
|
124
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
|
+
*
|
|
125
207
|
* Scalars should always be less than curve order: this should be checked inside of a curve itself.
|
|
126
208
|
* Creates precomputation tables for fast multiplication:
|
|
127
209
|
* - private scalar is split by fixed size windows of W bits
|
|
@@ -134,153 +216,183 @@ export type IWNAF<T extends Group<T>> = {
|
|
|
134
216
|
* @todo Research returning 2d JS array of windows, instead of a single window.
|
|
135
217
|
* This would allow windows to be in different memory locations
|
|
136
218
|
*/
|
|
137
|
-
export
|
|
138
|
-
|
|
139
|
-
|
|
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;
|
|
140
224
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
+
}
|
|
144
232
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
+
}
|
|
155
243
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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);
|
|
175
267
|
points.push(base);
|
|
176
|
-
// i=1, bc we skip 0
|
|
177
|
-
for (let i = 1; i < windowSize; i++) {
|
|
178
|
-
base = base.add(p);
|
|
179
|
-
points.push(base);
|
|
180
|
-
}
|
|
181
|
-
p = base.double();
|
|
182
268
|
}
|
|
183
|
-
|
|
184
|
-
}
|
|
269
|
+
p = base.double();
|
|
270
|
+
}
|
|
271
|
+
return points;
|
|
272
|
+
}
|
|
185
273
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
//
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
f = f.add(constTimeNegate(isNegF, precomputes[offsetF]));
|
|
216
|
-
} else {
|
|
217
|
-
// bits are 1: add to result point
|
|
218
|
-
p = p.add(constTimeNegate(isNeg, precomputes[offset]));
|
|
219
|
-
}
|
|
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]));
|
|
220
303
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
+
}
|
|
226
311
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
} else {
|
|
246
|
-
const item = precomputes[offset];
|
|
247
|
-
acc = acc.add(isNeg ? item.negate() : item); // Re-using acc allows to save adds in MSM
|
|
248
|
-
}
|
|
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
|
|
249
330
|
}
|
|
250
|
-
|
|
251
|
-
|
|
331
|
+
}
|
|
332
|
+
assert0(n);
|
|
333
|
+
return acc;
|
|
334
|
+
}
|
|
252
335
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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);
|
|
259
345
|
}
|
|
260
|
-
|
|
261
|
-
|
|
346
|
+
}
|
|
347
|
+
return comp;
|
|
348
|
+
}
|
|
262
349
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
+
}
|
|
267
354
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
+
}
|
|
273
360
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
+
}
|
|
277
369
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
370
|
+
hasCache(elm: P): boolean {
|
|
371
|
+
return getW(elm) !== 1;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Endomorphism-specific multiplication for Koblitz curves.
|
|
377
|
+
* Cost: 128 dbl, 0-256 adds.
|
|
378
|
+
*/
|
|
379
|
+
export function mulEndoUnsafe<T extends Group<T>>(
|
|
380
|
+
Point: GroupConstructor<T>,
|
|
381
|
+
point: T,
|
|
382
|
+
k1: bigint,
|
|
383
|
+
k2: bigint
|
|
384
|
+
): { p1: T; p2: T } {
|
|
385
|
+
let acc = point;
|
|
386
|
+
let p1 = Point.ZERO;
|
|
387
|
+
let p2 = Point.ZERO;
|
|
388
|
+
while (k1 > _0n || k2 > _0n) {
|
|
389
|
+
if (k1 & _1n) p1 = p1.add(acc);
|
|
390
|
+
if (k2 & _1n) p2 = p2.add(acc);
|
|
391
|
+
acc = acc.double();
|
|
392
|
+
k1 >>= _1n;
|
|
393
|
+
k2 >>= _1n;
|
|
394
|
+
}
|
|
395
|
+
return { p1, p2 };
|
|
284
396
|
}
|
|
285
397
|
|
|
286
398
|
/**
|
|
@@ -291,7 +403,7 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number):
|
|
|
291
403
|
* @param c Curve Point constructor
|
|
292
404
|
* @param fieldN field over CURVE.N - important that it's not over CURVE.P
|
|
293
405
|
* @param points array of L curve points
|
|
294
|
-
* @param scalars array of L scalars (aka
|
|
406
|
+
* @param scalars array of L scalars (aka secret keys / bigints)
|
|
295
407
|
*/
|
|
296
408
|
export function pippenger<T extends Group<T>>(
|
|
297
409
|
c: GroupConstructor<T>,
|
|
@@ -421,6 +533,7 @@ export function precomputeMSMUnsafe<T extends Group<T>>(
|
|
|
421
533
|
};
|
|
422
534
|
}
|
|
423
535
|
|
|
536
|
+
// TODO: remove
|
|
424
537
|
/**
|
|
425
538
|
* Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok.
|
|
426
539
|
* Though generator can be different (Fp2 / Fp6 for BLS).
|
|
@@ -437,6 +550,8 @@ export type BasicCurve<T> = {
|
|
|
437
550
|
allowInfinityPoint?: boolean; // bls12-381 requires it. ZERO point is valid, but invalid pubkey
|
|
438
551
|
};
|
|
439
552
|
|
|
553
|
+
// TODO: remove
|
|
554
|
+
/** @deprecated */
|
|
440
555
|
export function validateBasic<FP, T>(
|
|
441
556
|
curve: BasicCurve<FP> & T
|
|
442
557
|
): Readonly<
|
|
@@ -469,3 +584,46 @@ export function validateBasic<FP, T>(
|
|
|
469
584
|
...{ p: curve.Fp.ORDER },
|
|
470
585
|
} as const);
|
|
471
586
|
}
|
|
587
|
+
|
|
588
|
+
export type ValidCurveParams<T> = {
|
|
589
|
+
a: T;
|
|
590
|
+
p: bigint;
|
|
591
|
+
n: bigint;
|
|
592
|
+
h: bigint;
|
|
593
|
+
Gx: T;
|
|
594
|
+
Gy: T;
|
|
595
|
+
} & ({ b: T } | { d: T });
|
|
596
|
+
|
|
597
|
+
function createField<T>(order: bigint, field?: IField<T>): IField<T> {
|
|
598
|
+
if (field) {
|
|
599
|
+
if (field.ORDER !== order) throw new Error('Field.ORDER must match order: Fp == p, Fn == n');
|
|
600
|
+
validateField(field);
|
|
601
|
+
return field;
|
|
602
|
+
} else {
|
|
603
|
+
return Field(order) as unknown as IField<T>;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
export type FpFn<T> = { Fp: IField<T>; Fn: IField<bigint> };
|
|
607
|
+
/** Validates CURVE opts and creates fields */
|
|
608
|
+
export function _createCurveFields<T>(
|
|
609
|
+
type: 'weierstrass' | 'edwards',
|
|
610
|
+
CURVE: ValidCurveParams<T>,
|
|
611
|
+
curveOpts: Partial<FpFn<T>> = {}
|
|
612
|
+
): FpFn<T> {
|
|
613
|
+
if (!CURVE || typeof CURVE !== 'object') throw new Error(`expected valid ${type} CURVE object`);
|
|
614
|
+
for (const p of ['p', 'n', 'h'] as const) {
|
|
615
|
+
const val = CURVE[p];
|
|
616
|
+
if (!(typeof val === 'bigint' && val > _0n))
|
|
617
|
+
throw new Error(`CURVE.${p} must be positive bigint`);
|
|
618
|
+
}
|
|
619
|
+
const Fp = createField(CURVE.p, curveOpts.Fp);
|
|
620
|
+
const Fn = createField(CURVE.n, curveOpts.Fn);
|
|
621
|
+
const _b: 'b' | 'd' = type === 'weierstrass' ? 'b' : 'd';
|
|
622
|
+
const params = ['Gx', 'Gy', 'a', _b] as const;
|
|
623
|
+
for (const p of params) {
|
|
624
|
+
// @ts-ignore
|
|
625
|
+
if (!Fp.isValid(CURVE[p]))
|
|
626
|
+
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
|
|
627
|
+
}
|
|
628
|
+
return { Fp, Fn };
|
|
629
|
+
}
|