@noble/curves 1.8.2 → 1.9.1
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 +49 -24
- package/abstract/bls.js +1 -1
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +1 -1
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +13 -4
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +17 -3
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +120 -0
- package/abstract/fft.d.ts.map +1 -0
- package/abstract/fft.js +439 -0
- package/abstract/fft.js.map +1 -0
- package/abstract/hash-to-curve.d.ts +10 -5
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +31 -23
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +13 -12
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +158 -158
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +4 -9
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +70 -90
- package/abstract/montgomery.js.map +1 -1
- package/abstract/poseidon.d.ts +39 -2
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +183 -4
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +4 -5
- package/abstract/tower.js.map +1 -1
- package/abstract/utils.d.ts +1 -0
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +2 -0
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +31 -9
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +67 -48
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +9 -23
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +1 -0
- package/bn254.d.ts.map +1 -1
- package/bn254.js +10 -0
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +19 -5
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +29 -18
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +21 -5
- package/ed448.d.ts.map +1 -1
- package/ed448.js +46 -34
- package/ed448.js.map +1 -1
- package/esm/abstract/bls.js +1 -1
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +1 -1
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +13 -4
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +19 -5
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/fft.d.ts +120 -0
- package/esm/abstract/fft.d.ts.map +1 -0
- package/esm/abstract/fft.js +426 -0
- package/esm/abstract/fft.js.map +1 -0
- package/esm/abstract/hash-to-curve.d.ts +10 -5
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +32 -24
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.d.ts +13 -12
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +158 -158
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +4 -9
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +71 -91
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/poseidon.d.ts +39 -2
- package/esm/abstract/poseidon.d.ts.map +1 -1
- package/esm/abstract/poseidon.js +180 -5
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js +4 -5
- package/esm/abstract/tower.js.map +1 -1
- package/esm/abstract/utils.d.ts +1 -0
- package/esm/abstract/utils.d.ts.map +1 -1
- package/esm/abstract/utils.js +2 -0
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +31 -9
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +69 -50
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +9 -23
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.d.ts +1 -0
- package/esm/bn254.d.ts.map +1 -1
- package/esm/bn254.js +10 -0
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.d.ts +19 -5
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +29 -18
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +21 -5
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +47 -35
- package/esm/ed448.js.map +1 -1
- package/esm/jubjub.d.ts +11 -1
- package/esm/jubjub.d.ts.map +1 -1
- package/esm/jubjub.js +11 -1
- package/esm/jubjub.js.map +1 -1
- package/esm/misc.d.ts +8 -2
- package/esm/misc.d.ts.map +1 -1
- package/esm/misc.js +10 -4
- package/esm/misc.js.map +1 -1
- package/esm/nist.d.ts +30 -0
- package/esm/nist.d.ts.map +1 -0
- package/esm/nist.js +121 -0
- package/esm/nist.js.map +1 -0
- package/esm/p256.d.ts +7 -9
- package/esm/p256.d.ts.map +1 -1
- package/esm/p256.js +6 -44
- package/esm/p256.js.map +1 -1
- package/esm/p384.d.ts +9 -10
- package/esm/p384.d.ts.map +1 -1
- package/esm/p384.js +7 -46
- package/esm/p384.js.map +1 -1
- package/esm/p521.d.ts +7 -8
- package/esm/p521.d.ts.map +1 -1
- package/esm/p521.js +6 -46
- package/esm/p521.js.map +1 -1
- package/esm/pasta.d.ts +9 -1
- package/esm/pasta.d.ts.map +1 -1
- package/esm/pasta.js +9 -1
- package/esm/pasta.js.map +1 -1
- package/esm/secp256k1.d.ts +3 -3
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +8 -9
- package/esm/secp256k1.js.map +1 -1
- package/jubjub.d.ts +11 -1
- package/jubjub.d.ts.map +1 -1
- package/jubjub.js +12 -5
- package/jubjub.js.map +1 -1
- package/misc.d.ts +8 -2
- package/misc.d.ts.map +1 -1
- package/misc.js +11 -5
- package/misc.js.map +1 -1
- package/nist.d.ts +30 -0
- package/nist.d.ts.map +1 -0
- package/nist.js +124 -0
- package/nist.js.map +1 -0
- package/p256.d.ts +7 -9
- package/p256.d.ts.map +1 -1
- package/p256.js +5 -49
- package/p256.js.map +1 -1
- package/p384.d.ts +9 -10
- package/p384.d.ts.map +1 -1
- package/p384.js +6 -51
- package/p384.js.map +1 -1
- package/p521.d.ts +7 -8
- package/p521.d.ts.map +1 -1
- package/p521.js +5 -51
- package/p521.js.map +1 -1
- package/package.json +117 -8
- package/pasta.d.ts +9 -1
- package/pasta.d.ts.map +1 -1
- package/pasta.js +9 -3
- package/pasta.js.map +1 -1
- package/secp256k1.d.ts +3 -3
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +9 -10
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +1 -1
- package/src/abstract/curve.ts +11 -6
- package/src/abstract/edwards.ts +26 -12
- package/src/abstract/fft.ts +508 -0
- package/src/abstract/hash-to-curve.ts +44 -36
- package/src/abstract/modular.ts +154 -153
- package/src/abstract/montgomery.ts +78 -109
- package/src/abstract/poseidon.ts +208 -13
- package/src/abstract/tower.ts +4 -5
- package/src/abstract/utils.ts +2 -0
- package/src/abstract/weierstrass.ts +109 -61
- package/src/bls12-381.ts +11 -27
- package/src/bn254.ts +10 -0
- package/src/ed25519.ts +32 -19
- package/src/ed448.ts +91 -75
- package/src/jubjub.ts +12 -5
- package/src/misc.ts +10 -4
- package/src/nist.ts +155 -0
- package/src/p256.ts +6 -50
- package/src/p384.ts +8 -56
- package/src/p521.ts +6 -65
- package/src/pasta.ts +9 -1
- package/src/secp256k1.ts +12 -11
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
*
|
|
8
8
|
* * a: formula param
|
|
9
9
|
* * b: formula param
|
|
10
|
-
* * Fp: finite
|
|
11
|
-
* * n:
|
|
12
|
-
* * Gx: Base point (x, y) aka generator point x coordinate
|
|
10
|
+
* * Fp: finite field of prime characteristic P; may be complex (Fp2). Arithmetics is done in field
|
|
11
|
+
* * n: order of prime subgroup a.k.a total amount of valid curve points
|
|
12
|
+
* * Gx: Base point (x, y) aka generator point. Gx = x coordinate
|
|
13
13
|
* * Gy: ...y coordinate
|
|
14
14
|
* * h: cofactor, usually 1. h*n = curve group order (n is only subgroup order)
|
|
15
15
|
* * lowS: whether to enable (default) or disable "low-s" non-malleable signatures
|
|
@@ -40,25 +40,51 @@
|
|
|
40
40
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
41
41
|
// prettier-ignore
|
|
42
42
|
import {
|
|
43
|
-
type AffinePoint, type BasicCurve, type Group, type GroupConstructor,
|
|
44
43
|
pippenger, validateBasic, wNAF,
|
|
44
|
+
type AffinePoint, type BasicCurve, type Group, type GroupConstructor
|
|
45
45
|
} from './curve.ts';
|
|
46
46
|
// prettier-ignore
|
|
47
47
|
import {
|
|
48
|
-
Field,
|
|
48
|
+
Field,
|
|
49
|
+
FpInvertBatch,
|
|
50
|
+
getMinHashLength, invert, mapHashToField, mod, validateField,
|
|
51
|
+
type IField
|
|
49
52
|
} from './modular.ts';
|
|
50
53
|
// prettier-ignore
|
|
51
54
|
import {
|
|
52
|
-
type CHash, type Hex, type PrivKey,
|
|
53
55
|
aInRange, abool,
|
|
54
56
|
bitMask,
|
|
55
57
|
bytesToHex, bytesToNumberBE, concatBytes, createHmacDrbg, ensureBytes, hexToBytes,
|
|
56
|
-
inRange, isBytes, memoized, numberToBytesBE, numberToHexUnpadded, validateObject
|
|
58
|
+
inRange, isBytes, memoized, numberToBytesBE, numberToHexUnpadded, validateObject,
|
|
59
|
+
type CHash, type Hex, type PrivKey
|
|
57
60
|
} from './utils.ts';
|
|
58
61
|
|
|
59
62
|
export type { AffinePoint };
|
|
60
63
|
type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
|
|
61
|
-
|
|
64
|
+
/**
|
|
65
|
+
* When Weierstrass curve has `a=0`, it becomes Koblitz curve.
|
|
66
|
+
* Koblitz curves allow using **efficiently-computable GLV endomorphism ψ**.
|
|
67
|
+
* Endomorphism uses 2x less RAM, speeds up precomputation by 2x and ECDH / key recovery by 20%.
|
|
68
|
+
* For precomputed wNAF it trades off 1/2 init time & 1/3 ram for 20% perf hit.
|
|
69
|
+
*
|
|
70
|
+
* Endomorphism consists of beta, lambda and splitScalar:
|
|
71
|
+
*
|
|
72
|
+
* 1. GLV endomorphism ψ transforms a point: `P = (x, y) ↦ ψ(P) = (β·x mod p, y)`
|
|
73
|
+
* 2. GLV scalar decomposition transforms a scalar: `k ≡ k₁ + k₂·λ (mod n)`
|
|
74
|
+
* 3. Then these are combined: `k·P = k₁·P + k₂·ψ(P)`
|
|
75
|
+
* 4. Two 128-bit point-by-scalar multiplications + one point addition is faster than
|
|
76
|
+
* one 256-bit multiplication.
|
|
77
|
+
*
|
|
78
|
+
* where
|
|
79
|
+
* * beta: β ∈ Fₚ with β³ = 1, β ≠ 1
|
|
80
|
+
* * lambda: λ ∈ Fₙ with λ³ = 1, λ ≠ 1
|
|
81
|
+
* * splitScalar decomposes k ↦ k₁, k₂, by using reduced basis vectors.
|
|
82
|
+
* Gauss lattice reduction calculates them from initial basis vectors `(n, 0), (-λ, 0)`
|
|
83
|
+
*
|
|
84
|
+
* Check out `test/misc/endomorphism.js` and
|
|
85
|
+
* [gist](https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066).
|
|
86
|
+
*/
|
|
87
|
+
export type EndomorphismOpts = {
|
|
62
88
|
beta: bigint;
|
|
63
89
|
splitScalar: (k: bigint) => { k1neg: boolean; k1: bigint; k2neg: boolean; k2: bigint };
|
|
64
90
|
};
|
|
@@ -70,7 +96,7 @@ export type BasicWCurve<T> = BasicCurve<T> & {
|
|
|
70
96
|
// Optional params
|
|
71
97
|
allowedPrivateKeyLengths?: readonly number[]; // for P521
|
|
72
98
|
wrapPrivateKey?: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
|
|
73
|
-
endo?: EndomorphismOpts;
|
|
99
|
+
endo?: EndomorphismOpts;
|
|
74
100
|
// When a cofactor != 1, there can be an effective methods to:
|
|
75
101
|
// 1. Determine whether a point is torsion-free
|
|
76
102
|
isTorsionFree?: (c: ProjConstructor<T>, point: ProjPointType<T>) => boolean;
|
|
@@ -94,17 +120,16 @@ export interface ProjPointType<T> extends Group<ProjPointType<T>> {
|
|
|
94
120
|
readonly pz: T;
|
|
95
121
|
get x(): T;
|
|
96
122
|
get y(): T;
|
|
97
|
-
multiply(scalar: bigint): ProjPointType<T>;
|
|
98
123
|
toAffine(iz?: T): AffinePoint<T>;
|
|
99
|
-
isTorsionFree(): boolean;
|
|
100
|
-
clearCofactor(): ProjPointType<T>;
|
|
101
|
-
assertValidity(): void;
|
|
102
|
-
hasEvenY(): boolean;
|
|
103
|
-
toRawBytes(isCompressed?: boolean): Uint8Array;
|
|
104
124
|
toHex(isCompressed?: boolean): string;
|
|
125
|
+
toRawBytes(isCompressed?: boolean): Uint8Array;
|
|
105
126
|
|
|
127
|
+
assertValidity(): void;
|
|
128
|
+
hasEvenY(): boolean;
|
|
106
129
|
multiplyUnsafe(scalar: bigint): ProjPointType<T>;
|
|
107
130
|
multiplyAndAddUnsafe(Q: ProjPointType<T>, a: bigint, b: bigint): ProjPointType<T> | undefined;
|
|
131
|
+
isTorsionFree(): boolean;
|
|
132
|
+
clearCofactor(): ProjPointType<T>;
|
|
108
133
|
_setWindowSize(windowSize: number): void;
|
|
109
134
|
}
|
|
110
135
|
// Static methods for 3d XYZ points
|
|
@@ -136,26 +161,26 @@ function validatePointOpts<T>(curve: CurvePointsType<T>): CurvePointsTypeWithLen
|
|
|
136
161
|
b: 'field',
|
|
137
162
|
},
|
|
138
163
|
{
|
|
164
|
+
allowInfinityPoint: 'boolean',
|
|
139
165
|
allowedPrivateKeyLengths: 'array',
|
|
140
|
-
wrapPrivateKey: 'boolean',
|
|
141
|
-
isTorsionFree: 'function',
|
|
142
166
|
clearCofactor: 'function',
|
|
143
|
-
allowInfinityPoint: 'boolean',
|
|
144
167
|
fromBytes: 'function',
|
|
168
|
+
isTorsionFree: 'function',
|
|
145
169
|
toBytes: 'function',
|
|
170
|
+
wrapPrivateKey: 'boolean',
|
|
146
171
|
}
|
|
147
172
|
);
|
|
148
173
|
const { endo, Fp, a } = opts;
|
|
149
174
|
if (endo) {
|
|
150
175
|
if (!Fp.eql(a, Fp.ZERO)) {
|
|
151
|
-
throw new Error('invalid
|
|
176
|
+
throw new Error('invalid endo: CURVE.a must be 0');
|
|
152
177
|
}
|
|
153
178
|
if (
|
|
154
179
|
typeof endo !== 'object' ||
|
|
155
180
|
typeof endo.beta !== 'bigint' ||
|
|
156
181
|
typeof endo.splitScalar !== 'function'
|
|
157
182
|
) {
|
|
158
|
-
throw new Error('invalid
|
|
183
|
+
throw new Error('invalid endo: expected "beta": bigint and "splitScalar": function');
|
|
159
184
|
}
|
|
160
185
|
}
|
|
161
186
|
return Object.freeze({ ...opts } as const);
|
|
@@ -287,6 +312,10 @@ export const DER: IDER = {
|
|
|
287
312
|
},
|
|
288
313
|
};
|
|
289
314
|
|
|
315
|
+
function numToSizedHex(num: bigint, size: number): string {
|
|
316
|
+
return bytesToHex(numberToBytesBE(num, size));
|
|
317
|
+
}
|
|
318
|
+
|
|
290
319
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
291
320
|
// prettier-ignore
|
|
292
321
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
|
|
@@ -320,15 +349,25 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
|
|
|
320
349
|
function weierstrassEquation(x: T): T {
|
|
321
350
|
const { a, b } = CURVE;
|
|
322
351
|
const x2 = Fp.sqr(x); // x * x
|
|
323
|
-
const x3 = Fp.mul(x2, x); //
|
|
324
|
-
return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); //
|
|
352
|
+
const x3 = Fp.mul(x2, x); // x² * x
|
|
353
|
+
return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x³ + a * x + b
|
|
325
354
|
}
|
|
355
|
+
|
|
356
|
+
function isValidXY(x: T, y: T): boolean {
|
|
357
|
+
const left = Fp.sqr(y); // y²
|
|
358
|
+
const right = weierstrassEquation(x); // x³ + ax + b
|
|
359
|
+
return Fp.eql(left, right);
|
|
360
|
+
}
|
|
361
|
+
|
|
326
362
|
// Validate whether the passed curve params are valid.
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
363
|
+
// Test 1: equation y² = x³ + ax + b should work for generator point.
|
|
364
|
+
if (!isValidXY(CURVE.Gx, CURVE.Gy)) throw new Error('bad curve params: generator point');
|
|
365
|
+
|
|
366
|
+
// Test 2: discriminant Δ part should be non-zero: 4a³ + 27b² != 0.
|
|
367
|
+
// Guarantees curve is genus-1, smooth (non-singular).
|
|
368
|
+
const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n), _4n);
|
|
369
|
+
const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27));
|
|
370
|
+
if (Fp.is0(Fp.add(_4a3, _27b2))) throw new Error('bad curve params: a or b');
|
|
332
371
|
|
|
333
372
|
// Valid group elements reside in range 1..n-1
|
|
334
373
|
function isWithinCurveOrder(num: bigint): boolean {
|
|
@@ -369,7 +408,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
|
|
|
369
408
|
|
|
370
409
|
// Converts Projective point to affine (x, y) coordinates.
|
|
371
410
|
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
|
372
|
-
// (
|
|
411
|
+
// (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
|
|
373
412
|
const toAffineMemo = memoized((p: Point, iz?: T): AffinePoint<T> => {
|
|
374
413
|
const { px: x, py: y, pz: z } = p;
|
|
375
414
|
// Fast-path for normalized points
|
|
@@ -399,28 +438,28 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
|
|
|
399
438
|
const { x, y } = p.toAffine();
|
|
400
439
|
// Check if x, y are valid field elements
|
|
401
440
|
if (!Fp.isValid(x) || !Fp.isValid(y)) throw new Error('bad point: x or y not FE');
|
|
402
|
-
|
|
403
|
-
const right = weierstrassEquation(x); // x³ + ax + b
|
|
404
|
-
if (!Fp.eql(left, right)) throw new Error('bad point: equation left != right');
|
|
441
|
+
if (!isValidXY(x, y)) throw new Error('bad point: equation left != right');
|
|
405
442
|
if (!p.isTorsionFree()) throw new Error('bad point: not in prime-order subgroup');
|
|
406
443
|
return true;
|
|
407
444
|
});
|
|
408
445
|
|
|
409
446
|
/**
|
|
410
|
-
* Projective Point works in 3d / projective (homogeneous) coordinates: (
|
|
447
|
+
* Projective Point works in 3d / projective (homogeneous) coordinates: (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
|
|
411
448
|
* Default Point works in 2d / affine coordinates: (x, y)
|
|
412
449
|
* We're doing calculations in projective, because its operations don't require costly inversion.
|
|
413
450
|
*/
|
|
414
451
|
class Point implements ProjPointType<T> {
|
|
452
|
+
// base / generator point
|
|
415
453
|
static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
|
416
|
-
|
|
454
|
+
// zero / infinity / identity point
|
|
455
|
+
static readonly ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); // 0, 1, 0
|
|
417
456
|
readonly px: T;
|
|
418
457
|
readonly py: T;
|
|
419
458
|
readonly pz: T;
|
|
420
459
|
|
|
421
460
|
constructor(px: T, py: T, pz: T) {
|
|
422
461
|
if (px == null || !Fp.isValid(px)) throw new Error('x required');
|
|
423
|
-
if (py == null || !Fp.isValid(py)) throw new Error('y required');
|
|
462
|
+
if (py == null || !Fp.isValid(py) || Fp.is0(py)) throw new Error('y required');
|
|
424
463
|
if (pz == null || !Fp.isValid(pz)) throw new Error('z required');
|
|
425
464
|
this.px = px;
|
|
426
465
|
this.py = py;
|
|
@@ -454,7 +493,10 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
|
|
|
454
493
|
* Optimization: converts a list of projective points to a list of identical points with Z=1.
|
|
455
494
|
*/
|
|
456
495
|
static normalizeZ(points: Point[]): Point[] {
|
|
457
|
-
const toInv =
|
|
496
|
+
const toInv = FpInvertBatch(
|
|
497
|
+
Fp,
|
|
498
|
+
points.map((p) => p.pz)
|
|
499
|
+
);
|
|
458
500
|
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
|
459
501
|
}
|
|
460
502
|
|
|
@@ -617,6 +659,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
|
|
|
617
659
|
is0() {
|
|
618
660
|
return this.equals(Point.ZERO);
|
|
619
661
|
}
|
|
662
|
+
|
|
620
663
|
private wNAF(n: bigint): { p: Point; f: Point } {
|
|
621
664
|
return wnaf.wNAFCached(this, n, Point.normalizeZ);
|
|
622
665
|
}
|
|
@@ -638,6 +681,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
|
|
|
638
681
|
return wnaf.wNAFCachedUnsafe(this, sc, Point.normalizeZ);
|
|
639
682
|
|
|
640
683
|
// Case c: endomorphism
|
|
684
|
+
/** See docs for {@link EndomorphismOpts} */
|
|
641
685
|
let { k1neg, k1, k2neg, k2 } = endo.splitScalar(sc);
|
|
642
686
|
let k1p = I;
|
|
643
687
|
let k2p = I;
|
|
@@ -668,6 +712,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
|
|
|
668
712
|
const { endo, n: N } = CURVE;
|
|
669
713
|
aInRange('scalar', scalar, _1n, N);
|
|
670
714
|
let point: Point, fake: Point; // Fake point is used to const-time mult
|
|
715
|
+
/** See docs for {@link EndomorphismOpts} */
|
|
671
716
|
if (endo) {
|
|
672
717
|
const { k1neg, k1, k2neg, k2 } = endo.splitScalar(scalar);
|
|
673
718
|
let { p: k1p, f: f1p } = this.wNAF(k1);
|
|
@@ -732,9 +777,8 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
|
|
|
732
777
|
return bytesToHex(this.toRawBytes(isCompressed));
|
|
733
778
|
}
|
|
734
779
|
}
|
|
735
|
-
const
|
|
736
|
-
const wnaf = wNAF(Point,
|
|
737
|
-
// Validate if generator point is on curve
|
|
780
|
+
const { endo, nBitLength } = CURVE;
|
|
781
|
+
const wnaf = wNAF(Point, endo ? Math.ceil(nBitLength / 2) : nBitLength);
|
|
738
782
|
return {
|
|
739
783
|
CURVE,
|
|
740
784
|
ProjectivePoint: Point as ProjConstructor<T>,
|
|
@@ -756,7 +800,6 @@ export interface SignatureType {
|
|
|
756
800
|
recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
|
|
757
801
|
toCompactRawBytes(): Uint8Array;
|
|
758
802
|
toCompactHex(): string;
|
|
759
|
-
// DER-encoded
|
|
760
803
|
toDERRawBytes(isCompressed?: boolean): Uint8Array;
|
|
761
804
|
toDERHex(isCompressed?: boolean): string;
|
|
762
805
|
}
|
|
@@ -827,7 +870,7 @@ export type CurveFn = {
|
|
|
827
870
|
*/
|
|
828
871
|
export function weierstrass(curveDef: CurveType): CurveFn {
|
|
829
872
|
const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
|
|
830
|
-
const { Fp, n: CURVE_ORDER } = CURVE;
|
|
873
|
+
const { Fp, n: CURVE_ORDER, nByteLength, nBitLength } = CURVE;
|
|
831
874
|
const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
|
|
832
875
|
const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
|
|
833
876
|
|
|
@@ -890,8 +933,6 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
890
933
|
}
|
|
891
934
|
},
|
|
892
935
|
});
|
|
893
|
-
const numToNByteHex = (num: bigint): string =>
|
|
894
|
-
bytesToHex(numberToBytesBE(num, CURVE.nByteLength));
|
|
895
936
|
|
|
896
937
|
function isBiggerThanHalfOrder(number: bigint) {
|
|
897
938
|
const HALF = CURVE_ORDER >> _1n;
|
|
@@ -922,7 +963,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
922
963
|
|
|
923
964
|
// pair (bytes of r, bytes of s)
|
|
924
965
|
static fromCompact(hex: Hex) {
|
|
925
|
-
const l =
|
|
966
|
+
const l = nByteLength;
|
|
926
967
|
hex = ensureBytes('compactSignature', hex, l * 2);
|
|
927
968
|
return new Signature(slcNum(hex, 0, l), slcNum(hex, l, 2 * l));
|
|
928
969
|
}
|
|
@@ -951,7 +992,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
951
992
|
const radj = rec === 2 || rec === 3 ? r + CURVE.n : r;
|
|
952
993
|
if (radj >= Fp.ORDER) throw new Error('recovery id 2 or 3 invalid');
|
|
953
994
|
const prefix = (rec & 1) === 0 ? '02' : '03';
|
|
954
|
-
const R = Point.fromHex(prefix +
|
|
995
|
+
const R = Point.fromHex(prefix + numToSizedHex(radj, Fp.BYTES));
|
|
955
996
|
const ir = invN(radj); // r^-1
|
|
956
997
|
const u1 = modN(-h * ir); // -hr^-1
|
|
957
998
|
const u2 = modN(s * ir); // sr^-1
|
|
@@ -975,7 +1016,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
975
1016
|
return hexToBytes(this.toDERHex());
|
|
976
1017
|
}
|
|
977
1018
|
toDERHex() {
|
|
978
|
-
return DER.hexFromSig(
|
|
1019
|
+
return DER.hexFromSig(this);
|
|
979
1020
|
}
|
|
980
1021
|
|
|
981
1022
|
// padded bytes of r, then padded bytes of s
|
|
@@ -983,7 +1024,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
983
1024
|
return hexToBytes(this.toCompactHex());
|
|
984
1025
|
}
|
|
985
1026
|
toCompactHex() {
|
|
986
|
-
|
|
1027
|
+
const l = nByteLength;
|
|
1028
|
+
return numToSizedHex(this.r, l) + numToSizedHex(this.s, l);
|
|
987
1029
|
}
|
|
988
1030
|
}
|
|
989
1031
|
type RecoveredSignature = Signature & { recovery: number };
|
|
@@ -1036,14 +1078,19 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
1036
1078
|
/**
|
|
1037
1079
|
* Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
|
|
1038
1080
|
*/
|
|
1039
|
-
function isProbPub(item: PrivKey | PubKey): boolean {
|
|
1040
|
-
|
|
1041
|
-
const str = typeof item === 'string';
|
|
1042
|
-
const len = (arr || str) && (item as Hex).length;
|
|
1043
|
-
if (arr) return len === compressedLen || len === uncompressedLen;
|
|
1044
|
-
if (str) return len === 2 * compressedLen || len === 2 * uncompressedLen;
|
|
1081
|
+
function isProbPub(item: PrivKey | PubKey): boolean | undefined {
|
|
1082
|
+
if (typeof item === 'bigint') return false;
|
|
1045
1083
|
if (item instanceof Point) return true;
|
|
1046
|
-
|
|
1084
|
+
const arr = ensureBytes('key', item);
|
|
1085
|
+
const len = arr.length;
|
|
1086
|
+
const fpl = Fp.BYTES;
|
|
1087
|
+
const compLen = fpl + 1; // e.g. 33 for 32
|
|
1088
|
+
const uncompLen = 2 * fpl + 1; // e.g. 65 for 32
|
|
1089
|
+
if (CURVE.allowedPrivateKeyLengths || nByteLength === compLen) {
|
|
1090
|
+
return undefined;
|
|
1091
|
+
} else {
|
|
1092
|
+
return len === compLen || len === uncompLen;
|
|
1093
|
+
}
|
|
1047
1094
|
}
|
|
1048
1095
|
|
|
1049
1096
|
/**
|
|
@@ -1057,8 +1104,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
1057
1104
|
* @returns shared public key
|
|
1058
1105
|
*/
|
|
1059
1106
|
function getSharedSecret(privateA: PrivKey, publicB: Hex, isCompressed = true): Uint8Array {
|
|
1060
|
-
if (isProbPub(privateA)) throw new Error('first arg must be private key');
|
|
1061
|
-
if (
|
|
1107
|
+
if (isProbPub(privateA) === true) throw new Error('first arg must be private key');
|
|
1108
|
+
if (isProbPub(publicB) === false) throw new Error('second arg must be public key');
|
|
1062
1109
|
const b = Point.fromHex(publicB); // check for being on-curve
|
|
1063
1110
|
return b.multiply(normPrivateKeyToScalar(privateA)).toRawBytes(isCompressed);
|
|
1064
1111
|
}
|
|
@@ -1070,12 +1117,12 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
1070
1117
|
const bits2int =
|
|
1071
1118
|
CURVE.bits2int ||
|
|
1072
1119
|
function (bytes: Uint8Array): bigint {
|
|
1073
|
-
// Our custom check "just in case"
|
|
1120
|
+
// Our custom check "just in case", for protection against DoS
|
|
1074
1121
|
if (bytes.length > 8192) throw new Error('input is too large');
|
|
1075
1122
|
// For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
|
|
1076
1123
|
// for some cases, since bytes.length * 8 is not actual bitLength.
|
|
1077
1124
|
const num = bytesToNumberBE(bytes); // check for == u8 done here
|
|
1078
|
-
const delta = bytes.length * 8 -
|
|
1125
|
+
const delta = bytes.length * 8 - nBitLength; // truncate to nBitLength leftmost bits
|
|
1079
1126
|
return delta > 0 ? num >> BigInt(delta) : num;
|
|
1080
1127
|
};
|
|
1081
1128
|
const bits2int_modN =
|
|
@@ -1084,14 +1131,14 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
1084
1131
|
return modN(bits2int(bytes)); // can't use bytesToNumberBE here
|
|
1085
1132
|
};
|
|
1086
1133
|
// NOTE: pads output with zero as per spec
|
|
1087
|
-
const ORDER_MASK = bitMask(
|
|
1134
|
+
const ORDER_MASK = bitMask(nBitLength);
|
|
1088
1135
|
/**
|
|
1089
1136
|
* Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
|
|
1090
1137
|
*/
|
|
1091
1138
|
function int2octets(num: bigint): Uint8Array {
|
|
1092
|
-
aInRange('num < 2^' +
|
|
1139
|
+
aInRange('num < 2^' + nBitLength, num, _0n, ORDER_MASK);
|
|
1093
1140
|
// works with order, can have different size than numToField!
|
|
1094
|
-
return numberToBytesBE(num,
|
|
1141
|
+
return numberToBytesBE(num, nByteLength);
|
|
1095
1142
|
}
|
|
1096
1143
|
|
|
1097
1144
|
// Steps A, D of RFC6979 3.2
|
|
@@ -1383,7 +1430,8 @@ export function mapToCurveSimpleSWU<T>(
|
|
|
1383
1430
|
y = Fp.cmov(y, value, isValid); // 22. y = CMOV(y, y1, is_gx1_square)
|
|
1384
1431
|
const e1 = Fp.isOdd!(u) === Fp.isOdd!(y); // 23. e1 = sgn0(u) == sgn0(y)
|
|
1385
1432
|
y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
|
|
1386
|
-
|
|
1433
|
+
const tv4_inv = FpInvertBatch(Fp, [tv4], true)[0];
|
|
1434
|
+
x = Fp.mul(x, tv4_inv); // 25. x = x / tv4
|
|
1387
1435
|
return { x, y };
|
|
1388
1436
|
};
|
|
1389
1437
|
}
|
package/src/bls12-381.ts
CHANGED
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
* 3. Curve security level is about 120 bits as per [Barbulescu-Duquesne 2017](https://hal.science/hal-01534101/file/main.pdf)
|
|
29
29
|
* 4. Compatible with specs:
|
|
30
30
|
* [cfrg-pairing-friendly-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
|
31
|
-
* [cfrg-bls-signature-05](https://
|
|
31
|
+
* [cfrg-bls-signature-05](https://www.rfc-editor.org/rfc/draft-irtf-cfrg-bls-signature-05),
|
|
32
32
|
* RFC 9380.
|
|
33
33
|
*
|
|
34
34
|
* ### Params
|
|
35
35
|
* To verify curve parameters, see
|
|
36
|
-
* [pairing-friendly-curves spec](https://
|
|
36
|
+
* [pairing-friendly-curves spec](https://www.rfc-editor.org/rfc/draft-irtf-cfrg-pairing-friendly-curves-11).
|
|
37
37
|
* Basic math is done over finite fields over p.
|
|
38
38
|
* More complicated math is done over polynominal extension fields.
|
|
39
39
|
* To simplify calculations in Fp12, we construct extension tower:
|
|
@@ -70,16 +70,16 @@ import {
|
|
|
70
70
|
bytesToNumberBE,
|
|
71
71
|
concatBytes as concatB,
|
|
72
72
|
ensureBytes,
|
|
73
|
-
type Hex,
|
|
74
73
|
numberToBytesBE,
|
|
74
|
+
type Hex,
|
|
75
75
|
} from './abstract/utils.ts';
|
|
76
76
|
// Types
|
|
77
77
|
import { isogenyMap } from './abstract/hash-to-curve.ts';
|
|
78
78
|
import type { Fp, Fp12, Fp2, Fp6 } from './abstract/tower.ts';
|
|
79
79
|
import { psiFrobenius, tower12 } from './abstract/tower.ts';
|
|
80
80
|
import {
|
|
81
|
-
type AffinePoint,
|
|
82
81
|
mapToCurveSimpleSWU,
|
|
82
|
+
type AffinePoint,
|
|
83
83
|
type ProjPointType,
|
|
84
84
|
} from './abstract/weierstrass.ts';
|
|
85
85
|
|
|
@@ -337,8 +337,7 @@ const G1_SWU = mapToCurveSimpleSWU(Fp, {
|
|
|
337
337
|
Z: Fp.create(BigInt(11)),
|
|
338
338
|
});
|
|
339
339
|
|
|
340
|
-
//
|
|
341
|
-
// Ψ(P) endomorphism
|
|
340
|
+
// GLV endomorphism Ψ(P), for fast cofactor clearing
|
|
342
341
|
const { G2psi, G2psi2 } = psiFrobenius(Fp, Fp2, Fp2.div(Fp2.ONE, Fp2.NONRESIDUE)); // 1/(u+1)
|
|
343
342
|
|
|
344
343
|
// Default hash_to_field options are for hash to G2.
|
|
@@ -476,28 +475,15 @@ export const bls12_381: CurveFn = bls({
|
|
|
476
475
|
// It returns false for shitty points.
|
|
477
476
|
// https://eprint.iacr.org/2021/1130.pdf
|
|
478
477
|
isTorsionFree: (c, point): boolean => {
|
|
479
|
-
//
|
|
480
|
-
const
|
|
478
|
+
// GLV endomorphism ψ(P)
|
|
479
|
+
const beta = BigInt(
|
|
481
480
|
'0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
482
481
|
);
|
|
483
|
-
const phi = new c(Fp.mul(point.px,
|
|
484
|
-
|
|
485
|
-
// todo: unroll
|
|
482
|
+
const phi = new c(Fp.mul(point.px, beta), point.py, point.pz);
|
|
483
|
+
// TODO: unroll
|
|
486
484
|
const xP = point.multiplyUnsafe(BLS_X).negate(); // [x]P
|
|
487
485
|
const u2P = xP.multiplyUnsafe(BLS_X); // [u2]P
|
|
488
486
|
return u2P.equals(phi);
|
|
489
|
-
|
|
490
|
-
// https://eprint.iacr.org/2019/814.pdf
|
|
491
|
-
// (z² − 1)/3
|
|
492
|
-
// const c1 = BigInt('0x396c8c005555e1560000000055555555');
|
|
493
|
-
// const P = this;
|
|
494
|
-
// const S = P.sigma();
|
|
495
|
-
// const Q = S.double();
|
|
496
|
-
// const S2 = S.sigma();
|
|
497
|
-
// // [(z² − 1)/3](2σ(P) − P − σ²(P)) − σ²(P) = O
|
|
498
|
-
// const left = Q.subtract(P).subtract(S2).multiplyUnsafe(c1);
|
|
499
|
-
// const C = left.subtract(S2);
|
|
500
|
-
// return C.isZero();
|
|
501
487
|
},
|
|
502
488
|
// Clear cofactor of G1
|
|
503
489
|
// https://eprint.iacr.org/2019/403
|
|
@@ -627,14 +613,12 @@ export const bls12_381: CurveFn = bls({
|
|
|
627
613
|
// point.isTorsionFree() should return true for valid points
|
|
628
614
|
// It returns false for shitty points.
|
|
629
615
|
// https://eprint.iacr.org/2021/1130.pdf
|
|
616
|
+
// Older version: https://eprint.iacr.org/2019/814.pdf
|
|
630
617
|
isTorsionFree: (c, P): boolean => {
|
|
631
618
|
return P.multiplyUnsafe(BLS_X).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
|
|
632
|
-
// Older version: https://eprint.iacr.org/2019/814.pdf
|
|
633
|
-
// Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
|
|
634
|
-
// return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
|
|
635
619
|
},
|
|
636
620
|
// Maps the point into the prime-order subgroup G2.
|
|
637
|
-
// clear_cofactor_bls12381_g2 from
|
|
621
|
+
// clear_cofactor_bls12381_g2 from RFC 9380.
|
|
638
622
|
// https://eprint.iacr.org/2017/419.pdf
|
|
639
623
|
// prettier-ignore
|
|
640
624
|
clearCofactor: (c, P) => {
|
package/src/bn254.ts
CHANGED
|
@@ -13,6 +13,15 @@ There are huge compatibility issues in the ecosystem:
|
|
|
13
13
|
https://github.com/scipr-lab/libff/blob/a44f482e18b8ac04d034c193bd9d7df7817ad73f/libff/algebra/curves/bn128/bn128_init.cpp#L166-L169
|
|
14
14
|
3. halo2curves bn256 is also incompatible and returns different outputs
|
|
15
15
|
|
|
16
|
+
We don't implement Point methods toHex / toRawBytes.
|
|
17
|
+
To work around this limitation, has to initialize points on their own from BigInts.
|
|
18
|
+
Reason it's not implemented is because [there is no standard](https://github.com/privacy-scaling-explorations/halo2curves/issues/109).
|
|
19
|
+
Points of divergence:
|
|
20
|
+
|
|
21
|
+
- Endianness: LE vs BE (byte-swapped)
|
|
22
|
+
- Flags as first hex bits (similar to BLS) vs no-flags
|
|
23
|
+
- Imaginary part last in G2 vs first (c0, c1 vs c1, c0)
|
|
24
|
+
|
|
16
25
|
The goal of our implementation is to support "Ethereum" variant of the curve,
|
|
17
26
|
because it at least has specs:
|
|
18
27
|
|
|
@@ -239,6 +248,7 @@ export const bn254: BLSCurveFn = bls({
|
|
|
239
248
|
* bn254 weierstrass curve with ECDSA.
|
|
240
249
|
* This is very rare and probably not used anywhere.
|
|
241
250
|
* Instead, you should use G1 / G2, defined above.
|
|
251
|
+
* @deprecated
|
|
242
252
|
*/
|
|
243
253
|
export const bn254_weierstrass: CurveFn = weierstrass({
|
|
244
254
|
a: BigInt(0),
|
package/src/ed25519.ts
CHANGED
|
@@ -13,10 +13,11 @@ import { type CurveFn, type ExtPointType, twistedEdwards } from './abstract/edwa
|
|
|
13
13
|
import {
|
|
14
14
|
createHasher,
|
|
15
15
|
expand_message_xmd,
|
|
16
|
+
type Hasher,
|
|
16
17
|
type htfBasicOpts,
|
|
17
18
|
type HTFMethod,
|
|
18
19
|
} from './abstract/hash-to-curve.ts';
|
|
19
|
-
import { Field, FpSqrtEven, isNegativeLE, mod, pow2 } from './abstract/modular.ts';
|
|
20
|
+
import { Field, FpInvertBatch, FpSqrtEven, isNegativeLE, mod, pow2 } from './abstract/modular.ts';
|
|
20
21
|
import { montgomery, type CurveFn as XCurveFn } from './abstract/montgomery.ts';
|
|
21
22
|
import {
|
|
22
23
|
bytesToHex,
|
|
@@ -178,10 +179,7 @@ export const ed25519ph: CurveFn = /* @__PURE__ */ (() =>
|
|
|
178
179
|
export const x25519: XCurveFn = /* @__PURE__ */ (() =>
|
|
179
180
|
montgomery({
|
|
180
181
|
P: ED25519_P,
|
|
181
|
-
|
|
182
|
-
montgomeryBits: 255, // n is 253 bits
|
|
183
|
-
nByteLength: 32,
|
|
184
|
-
Gu: BigInt(9),
|
|
182
|
+
type: 'x25519',
|
|
185
183
|
powPminus2: (x: bigint): bigint => {
|
|
186
184
|
const P = ED25519_P;
|
|
187
185
|
// x^(p-2) aka x^(2^255-21)
|
|
@@ -289,12 +287,11 @@ function map_to_curve_elligator2_edwards25519(u: bigint) {
|
|
|
289
287
|
xd = Fp.cmov(xd, Fp.ONE, e); // 10. xd = CMOV(xd, 1, e)
|
|
290
288
|
yn = Fp.cmov(yn, Fp.ONE, e); // 11. yn = CMOV(yn, 1, e)
|
|
291
289
|
yd = Fp.cmov(yd, Fp.ONE, e); // 12. yd = CMOV(yd, 1, e)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
return { x: Fp.mul(xn, inv[0]), y: Fp.mul(yn, inv[1]) }; // 13. return (xn, xd, yn, yd)
|
|
290
|
+
const [xd_inv, yd_inv] = FpInvertBatch(Fp, [xd, yd], true); // batch division
|
|
291
|
+
return { x: Fp.mul(xn, xd_inv), y: Fp.mul(yn, yd_inv) }; // 13. return (xn, xd, yn, yd)
|
|
295
292
|
}
|
|
296
293
|
|
|
297
|
-
const
|
|
294
|
+
export const ed25519_hasher: Hasher<bigint> = /* @__PURE__ */ (() =>
|
|
298
295
|
createHasher(
|
|
299
296
|
ed25519.ExtendedPoint,
|
|
300
297
|
(scalars: bigint[]) => map_to_curve_elligator2_edwards25519(scalars[0]),
|
|
@@ -308,8 +305,9 @@ const htf = /* @__PURE__ */ (() =>
|
|
|
308
305
|
hash: sha512,
|
|
309
306
|
}
|
|
310
307
|
))();
|
|
311
|
-
export const hashToCurve: HTFMethod<bigint> = /* @__PURE__ */ (() =>
|
|
312
|
-
export const encodeToCurve: HTFMethod<bigint> = /* @__PURE__ */ (() =>
|
|
308
|
+
export const hashToCurve: HTFMethod<bigint> = /* @__PURE__ */ (() => ed25519_hasher.hashToCurve)();
|
|
309
|
+
export const encodeToCurve: HTFMethod<bigint> = /* @__PURE__ */ (() =>
|
|
310
|
+
ed25519_hasher.encodeToCurve)();
|
|
313
311
|
|
|
314
312
|
function aristp(other: unknown) {
|
|
315
313
|
if (!(other instanceof RistPoint)) throw new Error('RistrettoPoint expected');
|
|
@@ -344,8 +342,11 @@ const bytes255ToNumberLE = (bytes: Uint8Array) =>
|
|
|
344
342
|
|
|
345
343
|
type ExtendedPoint = ExtPointType;
|
|
346
344
|
|
|
347
|
-
|
|
348
|
-
|
|
345
|
+
/**
|
|
346
|
+
* Computes Elligator map for Ristretto255.
|
|
347
|
+
* Described in [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#appendix-B) and on
|
|
348
|
+
* the [website](https://ristretto.group/formulas/elligator.html).
|
|
349
|
+
*/
|
|
349
350
|
function calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
|
|
350
351
|
const { d } = ed25519.CURVE;
|
|
351
352
|
const P = ed25519.CURVE.Fp.ORDER;
|
|
@@ -373,7 +374,7 @@ function calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
|
|
|
373
374
|
* a source of bugs for protocols like ring signatures. Ristretto was created to solve this.
|
|
374
375
|
* Ristretto point operates in X:Y:Z:T extended coordinates like ExtendedPoint,
|
|
375
376
|
* but it should work in its own namespace: do not combine those two.
|
|
376
|
-
* https://
|
|
377
|
+
* See [RFC9496](https://www.rfc-editor.org/rfc/rfc9496).
|
|
377
378
|
*/
|
|
378
379
|
class RistPoint implements Group<RistPoint> {
|
|
379
380
|
static BASE: RistPoint;
|
|
@@ -393,7 +394,8 @@ class RistPoint implements Group<RistPoint> {
|
|
|
393
394
|
* Takes uniform output of 64-byte hash function like sha512 and converts it to `RistrettoPoint`.
|
|
394
395
|
* The hash-to-group operation applies Elligator twice and adds the results.
|
|
395
396
|
* **Note:** this is one-way map, there is no conversion from point to hash.
|
|
396
|
-
* https://
|
|
397
|
+
* Described in [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#appendix-B) and on
|
|
398
|
+
* the [website](https://ristretto.group/formulas/elligator.html).
|
|
397
399
|
* @param hex 64-byte output of a hash function
|
|
398
400
|
*/
|
|
399
401
|
static hashToCurve(hex: Hex): RistPoint {
|
|
@@ -407,7 +409,7 @@ class RistPoint implements Group<RistPoint> {
|
|
|
407
409
|
|
|
408
410
|
/**
|
|
409
411
|
* Converts ristretto-encoded string to ristretto point.
|
|
410
|
-
* https://
|
|
412
|
+
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-decode).
|
|
411
413
|
* @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
|
|
412
414
|
*/
|
|
413
415
|
static fromHex(hex: Hex): RistPoint {
|
|
@@ -444,7 +446,7 @@ class RistPoint implements Group<RistPoint> {
|
|
|
444
446
|
|
|
445
447
|
/**
|
|
446
448
|
* Encodes ristretto point to Uint8Array.
|
|
447
|
-
* https://
|
|
449
|
+
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-encode).
|
|
448
450
|
*/
|
|
449
451
|
toRawBytes(): Uint8Array {
|
|
450
452
|
let { ex: x, ey: y, ez: z, et: t } = this.ep;
|
|
@@ -482,7 +484,10 @@ class RistPoint implements Group<RistPoint> {
|
|
|
482
484
|
return this.toHex();
|
|
483
485
|
}
|
|
484
486
|
|
|
485
|
-
|
|
487
|
+
/**
|
|
488
|
+
* Compares two Ristretto points.
|
|
489
|
+
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-equals).
|
|
490
|
+
*/
|
|
486
491
|
equals(other: RistPoint): boolean {
|
|
487
492
|
aristp(other);
|
|
488
493
|
const { ex: X1, ey: Y1 } = this.ep;
|
|
@@ -520,13 +525,21 @@ class RistPoint implements Group<RistPoint> {
|
|
|
520
525
|
return new RistPoint(this.ep.negate());
|
|
521
526
|
}
|
|
522
527
|
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Wrapper over Edwards Point for ristretto255 from
|
|
531
|
+
* [RFC9496](https://www.rfc-editor.org/rfc/rfc9496).
|
|
532
|
+
*/
|
|
523
533
|
export const RistrettoPoint: typeof RistPoint = /* @__PURE__ */ (() => {
|
|
524
534
|
if (!RistPoint.BASE) RistPoint.BASE = new RistPoint(ed25519.ExtendedPoint.BASE);
|
|
525
535
|
if (!RistPoint.ZERO) RistPoint.ZERO = new RistPoint(ed25519.ExtendedPoint.ZERO);
|
|
526
536
|
return RistPoint;
|
|
527
537
|
})();
|
|
528
538
|
|
|
529
|
-
|
|
539
|
+
/**
|
|
540
|
+
* hash-to-curve for ristretto255.
|
|
541
|
+
* Described in [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#appendix-B).
|
|
542
|
+
*/
|
|
530
543
|
export const hashToRistretto255 = (msg: Uint8Array, options: htfBasicOpts): RistPoint => {
|
|
531
544
|
const d = options.DST;
|
|
532
545
|
const DST = typeof d === 'string' ? utf8ToBytes(d) : d;
|