@noble/curves 1.9.0 → 1.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -34
- package/_shortw_utils.d.ts +7 -5
- package/_shortw_utils.d.ts.map +1 -1
- package/_shortw_utils.js +2 -8
- package/_shortw_utils.js.map +1 -1
- package/abstract/bls.d.ts +60 -24
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +158 -109
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +44 -9
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +99 -11
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +112 -25
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +141 -92
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +122 -0
- package/abstract/fft.d.ts.map +1 -0
- package/abstract/fft.js +438 -0
- package/abstract/fft.js.map +1 -0
- package/abstract/hash-to-curve.d.ts +25 -11
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +17 -14
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +28 -17
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +156 -139
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +3 -8
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +73 -93
- 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 +20 -46
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +10 -4
- 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 +152 -73
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +487 -404
- 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 -480
- 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 +25 -9
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +89 -65
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +29 -10
- package/ed448.d.ts.map +1 -1
- package/ed448.js +116 -81
- package/ed448.js.map +1 -1
- package/esm/_shortw_utils.d.ts +7 -5
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/_shortw_utils.js +2 -8
- package/esm/_shortw_utils.js.map +1 -1
- package/esm/abstract/bls.d.ts +60 -24
- package/esm/abstract/bls.d.ts.map +1 -1
- package/esm/abstract/bls.js +158 -109
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +44 -9
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +96 -12
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +112 -25
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +141 -94
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/fft.d.ts +122 -0
- package/esm/abstract/fft.d.ts.map +1 -0
- package/esm/abstract/fft.js +425 -0
- package/esm/abstract/fft.js.map +1 -0
- package/esm/abstract/hash-to-curve.d.ts +25 -11
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +17 -14
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.d.ts +28 -17
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +155 -138
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +3 -8
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +74 -94
- 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 +20 -46
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js +10 -4
- 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 +152 -73
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +485 -406
- 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 -479
- 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 +25 -9
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +84 -60
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +29 -10
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +113 -78
- package/esm/ed448.js.map +1 -1
- package/esm/jubjub.d.ts +4 -0
- package/esm/jubjub.d.ts.map +1 -1
- package/esm/jubjub.js +4 -0
- package/esm/jubjub.js.map +1 -1
- package/esm/misc.d.ts.map +1 -1
- package/esm/misc.js +31 -26
- package/esm/misc.js.map +1 -1
- package/esm/nist.d.ts +8 -16
- package/esm/nist.d.ts.map +1 -1
- package/esm/nist.js +87 -97
- package/esm/nist.js.map +1 -1
- package/esm/p256.d.ts +3 -3
- package/esm/p384.d.ts +3 -3
- package/esm/p521.d.ts +3 -3
- package/esm/pasta.d.ts +4 -0
- package/esm/pasta.d.ts.map +1 -1
- package/esm/pasta.js +4 -0
- package/esm/pasta.js.map +1 -1
- package/esm/secp256k1.d.ts +6 -6
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +44 -41
- 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/jubjub.d.ts +4 -0
- package/jubjub.d.ts.map +1 -1
- package/jubjub.js +4 -0
- package/jubjub.js.map +1 -1
- package/misc.d.ts.map +1 -1
- package/misc.js +35 -30
- package/misc.js.map +1 -1
- package/nist.d.ts +8 -16
- package/nist.d.ts.map +1 -1
- package/nist.js +87 -97
- package/nist.js.map +1 -1
- package/p256.d.ts +3 -3
- package/p384.d.ts +3 -3
- package/p521.d.ts +3 -3
- package/package.json +26 -8
- package/pasta.d.ts +4 -0
- package/pasta.d.ts.map +1 -1
- package/pasta.js +4 -0
- package/pasta.js.map +1 -1
- package/secp256k1.d.ts +6 -6
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +47 -44
- package/secp256k1.js.map +1 -1
- package/src/_shortw_utils.ts +5 -15
- package/src/abstract/bls.ts +260 -145
- package/src/abstract/curve.ts +125 -18
- package/src/abstract/edwards.ts +282 -127
- package/src/abstract/fft.ts +519 -0
- package/src/abstract/hash-to-curve.ts +51 -27
- package/src/abstract/modular.ts +156 -143
- package/src/abstract/montgomery.ts +81 -111
- package/src/abstract/poseidon.ts +22 -18
- package/src/abstract/tower.ts +37 -68
- package/src/abstract/utils.ts +3 -378
- package/src/abstract/weierstrass.ts +752 -461
- package/src/bls12-381.ts +542 -507
- package/src/bn254.ts +47 -35
- package/src/ed25519.ts +104 -76
- package/src/ed448.ts +156 -105
- package/src/jubjub.ts +4 -0
- package/src/misc.ts +39 -34
- package/src/nist.ts +138 -126
- package/src/p256.ts +3 -3
- package/src/p384.ts +3 -3
- package/src/p521.ts +3 -3
- package/src/pasta.ts +5 -1
- package/src/secp256k1.ts +59 -47
- 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
|
@@ -5,29 +5,26 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
|
-
import { Field, mod } from './modular.ts';
|
|
9
8
|
import {
|
|
9
|
+
_validateObject,
|
|
10
10
|
aInRange,
|
|
11
11
|
bytesToNumberLE,
|
|
12
12
|
ensureBytes,
|
|
13
13
|
numberToBytesLE,
|
|
14
|
-
|
|
15
|
-
} from '
|
|
14
|
+
randomBytes,
|
|
15
|
+
} from '../utils.ts';
|
|
16
|
+
import { mod } from './modular.ts';
|
|
16
17
|
|
|
17
18
|
const _0n = BigInt(0);
|
|
18
19
|
const _1n = BigInt(1);
|
|
20
|
+
const _2n = BigInt(2);
|
|
19
21
|
type Hex = string | Uint8Array;
|
|
20
22
|
|
|
21
23
|
export type CurveType = {
|
|
22
24
|
P: bigint; // finite field prime
|
|
23
|
-
|
|
24
|
-
adjustScalarBytes
|
|
25
|
-
|
|
26
|
-
a: bigint;
|
|
27
|
-
montgomeryBits: number;
|
|
28
|
-
powPminus2?: (x: bigint) => bigint;
|
|
29
|
-
xyToU?: (x: bigint, y: bigint) => bigint;
|
|
30
|
-
Gu: bigint;
|
|
25
|
+
type: 'x25519' | 'x448';
|
|
26
|
+
adjustScalarBytes: (bytes: Uint8Array) => Uint8Array;
|
|
27
|
+
powPminus2: (x: bigint) => bigint;
|
|
31
28
|
randomBytes?: (bytesLength?: number) => Uint8Array;
|
|
32
29
|
};
|
|
33
30
|
|
|
@@ -41,67 +38,88 @@ export type CurveFn = {
|
|
|
41
38
|
};
|
|
42
39
|
|
|
43
40
|
function validateOpts(curve: CurveType) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
montgomeryBits: 'isSafeInteger',
|
|
51
|
-
nByteLength: 'isSafeInteger',
|
|
52
|
-
adjustScalarBytes: 'function',
|
|
53
|
-
domain: 'function',
|
|
54
|
-
powPminus2: 'function',
|
|
55
|
-
Gu: 'bigint',
|
|
56
|
-
}
|
|
57
|
-
);
|
|
58
|
-
// Set defaults
|
|
41
|
+
_validateObject(curve, {
|
|
42
|
+
adjustScalarBytes: 'function',
|
|
43
|
+
powPminus2: 'function',
|
|
44
|
+
});
|
|
59
45
|
return Object.freeze({ ...curve } as const);
|
|
60
46
|
}
|
|
61
47
|
|
|
62
|
-
// Uses only one coordinate instead of two
|
|
63
48
|
export function montgomery(curveDef: CurveType): CurveFn {
|
|
64
49
|
const CURVE = validateOpts(curveDef);
|
|
65
|
-
const { P } = CURVE;
|
|
66
|
-
const
|
|
50
|
+
const { P, type, adjustScalarBytes, powPminus2, randomBytes: rand } = CURVE;
|
|
51
|
+
const is25519 = type === 'x25519';
|
|
52
|
+
if (!is25519 && type !== 'x448') throw new Error('invalid type');
|
|
53
|
+
const randomBytes_ = rand || randomBytes;
|
|
54
|
+
|
|
55
|
+
const montgomeryBits = is25519 ? 255 : 448;
|
|
56
|
+
const fieldLen = is25519 ? 32 : 56;
|
|
57
|
+
const Gu = is25519 ? BigInt(9) : BigInt(5);
|
|
58
|
+
// RFC 7748 #5:
|
|
59
|
+
// The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519 and
|
|
60
|
+
// (156326 - 2) / 4 = 39081 for curve448/X448
|
|
61
|
+
// const a = is25519 ? 156326n : 486662n;
|
|
62
|
+
const a24 = is25519 ? BigInt(121665) : BigInt(39081);
|
|
63
|
+
// RFC: x25519 "the resulting integer is of the form 2^254 plus
|
|
64
|
+
// eight times a value between 0 and 2^251 - 1 (inclusive)"
|
|
65
|
+
// x448: "2^447 plus four times a value between 0 and 2^445 - 1 (inclusive)"
|
|
66
|
+
const minScalar = is25519 ? _2n ** BigInt(254) : _2n ** BigInt(447);
|
|
67
|
+
const maxAdded = is25519
|
|
68
|
+
? BigInt(8) * _2n ** BigInt(251) - _1n
|
|
69
|
+
: BigInt(4) * _2n ** BigInt(445) - _1n;
|
|
70
|
+
const maxScalar = minScalar + maxAdded + _1n; // (inclusive)
|
|
67
71
|
const modP = (n: bigint) => mod(n, P);
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
const GuBytes = encodeU(Gu);
|
|
73
|
+
function encodeU(u: bigint): Uint8Array {
|
|
74
|
+
return numberToBytesLE(modP(u), fieldLen);
|
|
75
|
+
}
|
|
76
|
+
function decodeU(u: Hex): bigint {
|
|
77
|
+
const _u = ensureBytes('u coordinate', u, fieldLen);
|
|
78
|
+
// RFC: When receiving such an array, implementations of X25519
|
|
79
|
+
// (but not X448) MUST mask the most significant bit in the final byte.
|
|
80
|
+
if (is25519) _u[31] &= 127; // 0b0111_1111
|
|
81
|
+
// RFC: Implementations MUST accept non-canonical values and process them as
|
|
82
|
+
// if they had been reduced modulo the field prime. The non-canonical
|
|
83
|
+
// values are 2^255 - 19 through 2^255 - 1 for X25519 and 2^448 - 2^224
|
|
84
|
+
// - 1 through 2^448 - 1 for X448.
|
|
85
|
+
return modP(bytesToNumberLE(_u));
|
|
86
|
+
}
|
|
87
|
+
function decodeScalar(scalar: Hex): bigint {
|
|
88
|
+
return bytesToNumberLE(adjustScalarBytes(ensureBytes('scalar', scalar, fieldLen)));
|
|
89
|
+
}
|
|
90
|
+
function scalarMult(scalar: Hex, u: Hex): Uint8Array {
|
|
91
|
+
const pu = montgomeryLadder(decodeU(u), decodeScalar(scalar));
|
|
92
|
+
// Some public keys are useless, of low-order. Curve author doesn't think
|
|
93
|
+
// it needs to be validated, but we do it nonetheless.
|
|
94
|
+
// https://cr.yp.to/ecdh.html#validate
|
|
95
|
+
if (pu === _0n) throw new Error('invalid private or public key received');
|
|
96
|
+
return encodeU(pu);
|
|
97
|
+
}
|
|
98
|
+
// Computes public key from private. By doing scalar multiplication of base point.
|
|
99
|
+
function scalarMultBase(scalar: Hex): Uint8Array {
|
|
100
|
+
return scalarMult(scalar, GuBytes);
|
|
101
|
+
}
|
|
73
102
|
|
|
74
|
-
// cswap from RFC7748
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
x_3 = x_3 XOR dummy
|
|
80
|
-
Return (x_2, x_3)
|
|
81
|
-
Where mask(swap) is the all-1 or all-0 word of the same length as x_2
|
|
82
|
-
and x_3, computed, e.g., as mask(swap) = 0 - swap.
|
|
83
|
-
*/
|
|
84
|
-
function cswap(swap: bigint, x_2: bigint, x_3: bigint): [bigint, bigint] {
|
|
103
|
+
// cswap from RFC7748 "example code"
|
|
104
|
+
function cswap(swap: bigint, x_2: bigint, x_3: bigint): { x_2: bigint; x_3: bigint } {
|
|
105
|
+
// dummy = mask(swap) AND (x_2 XOR x_3)
|
|
106
|
+
// Where mask(swap) is the all-1 or all-0 word of the same length as x_2
|
|
107
|
+
// and x_3, computed, e.g., as mask(swap) = 0 - swap.
|
|
85
108
|
const dummy = modP(swap * (x_2 - x_3));
|
|
86
|
-
x_2 = modP(x_2 - dummy);
|
|
87
|
-
x_3 = modP(x_3 + dummy);
|
|
88
|
-
return
|
|
109
|
+
x_2 = modP(x_2 - dummy); // x_2 = x_2 XOR dummy
|
|
110
|
+
x_3 = modP(x_3 + dummy); // x_3 = x_3 XOR dummy
|
|
111
|
+
return { x_2, x_3 };
|
|
89
112
|
}
|
|
90
113
|
|
|
91
|
-
// x25519 from 4
|
|
92
|
-
// The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519
|
|
93
|
-
const a24 = (CURVE.a - BigInt(2)) / BigInt(4);
|
|
94
114
|
/**
|
|
95
|
-
*
|
|
115
|
+
* Montgomery x-only multiplication ladder.
|
|
96
116
|
* @param pointU u coordinate (x) on Montgomery Curve 25519
|
|
97
117
|
* @param scalar by which the point would be multiplied
|
|
98
118
|
* @returns new Point on Montgomery curve
|
|
99
119
|
*/
|
|
100
120
|
function montgomeryLadder(u: bigint, scalar: bigint): bigint {
|
|
101
121
|
aInRange('u', u, _0n, P);
|
|
102
|
-
aInRange('scalar', scalar,
|
|
103
|
-
// Section 5: Implementations MUST accept non-canonical values and process them as
|
|
104
|
-
// if they had been reduced modulo the field prime.
|
|
122
|
+
aInRange('scalar', scalar, minScalar, maxScalar);
|
|
105
123
|
const k = scalar;
|
|
106
124
|
const x_1 = u;
|
|
107
125
|
let x_2 = _1n;
|
|
@@ -109,16 +127,11 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|
|
109
127
|
let x_3 = u;
|
|
110
128
|
let z_3 = _1n;
|
|
111
129
|
let swap = _0n;
|
|
112
|
-
let sw: [bigint, bigint];
|
|
113
130
|
for (let t = BigInt(montgomeryBits - 1); t >= _0n; t--) {
|
|
114
131
|
const k_t = (k >> t) & _1n;
|
|
115
132
|
swap ^= k_t;
|
|
116
|
-
|
|
117
|
-
x_2 =
|
|
118
|
-
x_3 = sw[1];
|
|
119
|
-
sw = cswap(swap, z_2, z_3);
|
|
120
|
-
z_2 = sw[0];
|
|
121
|
-
z_3 = sw[1];
|
|
133
|
+
({ x_2, x_3 } = cswap(swap, x_2, x_3));
|
|
134
|
+
({ x_2: z_2, x_3: z_3 } = cswap(swap, z_2, z_3));
|
|
122
135
|
swap = k_t;
|
|
123
136
|
|
|
124
137
|
const A = x_2 + z_2;
|
|
@@ -137,53 +150,10 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|
|
137
150
|
x_2 = modP(AA * BB);
|
|
138
151
|
z_2 = modP(E * (AA + modP(a24 * E)));
|
|
139
152
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
// (z_2, z_3) = cswap(swap, z_2, z_3)
|
|
145
|
-
sw = cswap(swap, z_2, z_3);
|
|
146
|
-
z_2 = sw[0];
|
|
147
|
-
z_3 = sw[1];
|
|
148
|
-
// z_2^(p - 2)
|
|
149
|
-
const z2 = powPminus2(z_2);
|
|
150
|
-
// Return x_2 * (z_2^(p - 2))
|
|
151
|
-
return modP(x_2 * z2);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function encodeUCoordinate(u: bigint): Uint8Array {
|
|
155
|
-
return numberToBytesLE(modP(u), montgomeryBytes);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function decodeUCoordinate(uEnc: Hex): bigint {
|
|
159
|
-
// Section 5: When receiving such an array, implementations of X25519
|
|
160
|
-
// MUST mask the most significant bit in the final byte.
|
|
161
|
-
const u = ensureBytes('u coordinate', uEnc, montgomeryBytes);
|
|
162
|
-
if (fieldLen === 32) u[31] &= 127; // 0b0111_1111
|
|
163
|
-
return bytesToNumberLE(u);
|
|
164
|
-
}
|
|
165
|
-
function decodeScalar(n: Hex): bigint {
|
|
166
|
-
const bytes = ensureBytes('scalar', n);
|
|
167
|
-
const len = bytes.length;
|
|
168
|
-
if (len !== montgomeryBytes && len !== fieldLen) {
|
|
169
|
-
let valid = '' + montgomeryBytes + ' or ' + fieldLen;
|
|
170
|
-
throw new Error('invalid scalar, expected ' + valid + ' bytes, got ' + len);
|
|
171
|
-
}
|
|
172
|
-
return bytesToNumberLE(adjustScalarBytes(bytes));
|
|
173
|
-
}
|
|
174
|
-
function scalarMult(scalar: Hex, u: Hex): Uint8Array {
|
|
175
|
-
const pointU = decodeUCoordinate(u);
|
|
176
|
-
const _scalar = decodeScalar(scalar);
|
|
177
|
-
const pu = montgomeryLadder(pointU, _scalar);
|
|
178
|
-
// The result was not contributory
|
|
179
|
-
// https://cr.yp.to/ecdh.html#validate
|
|
180
|
-
if (pu === _0n) throw new Error('invalid private or public key received');
|
|
181
|
-
return encodeUCoordinate(pu);
|
|
182
|
-
}
|
|
183
|
-
// Computes public key from private. By doing scalar multiplication of base point.
|
|
184
|
-
const GuBytes = encodeUCoordinate(CURVE.Gu);
|
|
185
|
-
function scalarMultBase(scalar: Hex): Uint8Array {
|
|
186
|
-
return scalarMult(scalar, GuBytes);
|
|
153
|
+
({ x_2, x_3 } = cswap(swap, x_2, x_3));
|
|
154
|
+
({ x_2: z_2, x_3: z_3 } = cswap(swap, z_2, z_3));
|
|
155
|
+
const z2 = powPminus2(z_2); // `Fp.pow(x, P - _2n)` is much slower equivalent
|
|
156
|
+
return modP(x_2 * z2); // Return x_2 * (z_2^(p - 2))
|
|
187
157
|
}
|
|
188
158
|
|
|
189
159
|
return {
|
|
@@ -191,7 +161,7 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|
|
191
161
|
scalarMultBase,
|
|
192
162
|
getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(privateKey, publicKey),
|
|
193
163
|
getPublicKey: (privateKey: Hex): Uint8Array => scalarMultBase(privateKey),
|
|
194
|
-
utils: { randomPrivateKey: () =>
|
|
195
|
-
GuBytes: GuBytes,
|
|
164
|
+
utils: { randomPrivateKey: () => randomBytes_(fieldLen) },
|
|
165
|
+
GuBytes: GuBytes.slice(),
|
|
196
166
|
};
|
|
197
167
|
}
|
package/src/abstract/poseidon.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
10
|
+
import { _validateObject, bitGet } from '../utils.ts';
|
|
10
11
|
import { FpInvertBatch, FpPow, type IField, validateField } from './modular.ts';
|
|
11
|
-
import { bitGet } from './utils.ts';
|
|
12
12
|
|
|
13
13
|
// Grain LFSR (Linear-Feedback Shift Register): https://eprint.iacr.org/2009/109.pdf
|
|
14
14
|
function grainLFSR(state: number[]): () => boolean {
|
|
@@ -41,20 +41,28 @@ export type PoseidonBasicOpts = {
|
|
|
41
41
|
isSboxInverse?: boolean;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
function
|
|
44
|
+
function assertValidPosOpts(opts: PoseidonBasicOpts) {
|
|
45
45
|
const { Fp, roundsFull } = opts;
|
|
46
46
|
validateField(Fp);
|
|
47
|
+
_validateObject(
|
|
48
|
+
opts,
|
|
49
|
+
{
|
|
50
|
+
t: 'number',
|
|
51
|
+
roundsFull: 'number',
|
|
52
|
+
roundsPartial: 'number',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
isSboxInverse: 'boolean',
|
|
56
|
+
}
|
|
57
|
+
);
|
|
47
58
|
for (const i of ['t', 'roundsFull', 'roundsPartial'] as const) {
|
|
48
|
-
if (
|
|
49
|
-
throw new Error('invalid number ' + i);
|
|
59
|
+
if (!Number.isSafeInteger(opts[i]) || opts[i] < 1) throw new Error('invalid number ' + i);
|
|
50
60
|
}
|
|
51
|
-
if (opts.isSboxInverse !== undefined && typeof opts.isSboxInverse !== 'boolean')
|
|
52
|
-
throw new Error(`Poseidon: invalid param isSboxInverse=${opts.isSboxInverse}`);
|
|
53
61
|
if (roundsFull & 1) throw new Error('roundsFull is not even' + roundsFull);
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
function poseidonGrain(opts: PoseidonBasicOpts) {
|
|
57
|
-
|
|
65
|
+
assertValidPosOpts(opts);
|
|
58
66
|
const { Fp } = opts;
|
|
59
67
|
const state = Array(80).fill(1);
|
|
60
68
|
let pos = 0;
|
|
@@ -140,7 +148,7 @@ export function validateOpts(opts: PoseidonOpts): Readonly<{
|
|
|
140
148
|
sboxPower?: number;
|
|
141
149
|
reversePartialPowIdx?: boolean; // Hack for stark
|
|
142
150
|
}> {
|
|
143
|
-
|
|
151
|
+
assertValidPosOpts(opts);
|
|
144
152
|
const { Fp, mds, reversePartialPowIdx: rev, roundConstants: rc } = opts;
|
|
145
153
|
const { roundsFull, roundsPartial, sboxPower, t } = opts;
|
|
146
154
|
|
|
@@ -196,12 +204,13 @@ export function splitConstants(rc: bigint[], t: number): bigint[][] {
|
|
|
196
204
|
return res;
|
|
197
205
|
}
|
|
198
206
|
|
|
199
|
-
|
|
200
|
-
export function poseidon(opts: PoseidonOpts): {
|
|
207
|
+
export type PoseidonFn = {
|
|
201
208
|
(values: bigint[]): bigint[];
|
|
202
209
|
// For verification in tests
|
|
203
210
|
roundConstants: bigint[][];
|
|
204
|
-
}
|
|
211
|
+
};
|
|
212
|
+
/** Poseidon NTT-friendly hash. */
|
|
213
|
+
export function poseidon(opts: PoseidonOpts): PoseidonFn {
|
|
205
214
|
const _opts = validateOpts(opts);
|
|
206
215
|
const { Fp, mds, roundConstants, rounds: totalRounds, roundsPartial, sboxFn, t } = _opts;
|
|
207
216
|
const halfRoundsFull = _opts.roundsFull / 2;
|
|
@@ -242,17 +251,12 @@ export class PoseidonSponge {
|
|
|
242
251
|
private Fp: IField<bigint>;
|
|
243
252
|
readonly rate: number;
|
|
244
253
|
readonly capacity: number;
|
|
245
|
-
readonly hash:
|
|
254
|
+
readonly hash: PoseidonFn;
|
|
246
255
|
private state: bigint[]; // [...capacity, ...rate]
|
|
247
256
|
private pos = 0;
|
|
248
257
|
private isAbsorbing = true;
|
|
249
258
|
|
|
250
|
-
constructor(
|
|
251
|
-
Fp: IField<bigint>,
|
|
252
|
-
rate: number,
|
|
253
|
-
capacity: number,
|
|
254
|
-
hash: ReturnType<typeof poseidon>
|
|
255
|
-
) {
|
|
259
|
+
constructor(Fp: IField<bigint>, rate: number, capacity: number, hash: PoseidonFn) {
|
|
256
260
|
this.Fp = Fp;
|
|
257
261
|
this.hash = hash;
|
|
258
262
|
this.rate = rate;
|
package/src/abstract/tower.ts
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
12
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
13
|
+
import { bitLen, bitMask, concatBytes, notImplemented } from '../utils.ts';
|
|
13
14
|
import * as mod from './modular.ts';
|
|
14
|
-
import { bitLen, bitMask, concatBytes, notImplemented } from './utils.ts';
|
|
15
15
|
import type { ProjConstructor, ProjPointType } from './weierstrass.ts';
|
|
16
16
|
|
|
17
17
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
@@ -34,19 +34,33 @@ export type BigintTwelve = [
|
|
|
34
34
|
];
|
|
35
35
|
|
|
36
36
|
export type Fp2Bls = mod.IField<Fp2> & {
|
|
37
|
-
reim: (num: Fp2) => { re: Fp; im: Fp };
|
|
38
|
-
mulByB: (num: Fp2) => Fp2;
|
|
39
37
|
frobeniusMap(num: Fp2, power: number): Fp2;
|
|
40
38
|
fromBigTuple(num: [bigint, bigint]): Fp2;
|
|
39
|
+
mulByB: (num: Fp2) => Fp2;
|
|
40
|
+
mulByNonresidue: (num: Fp2) => Fp2;
|
|
41
|
+
reim: (num: Fp2) => { re: Fp; im: Fp };
|
|
42
|
+
NONRESIDUE: Fp2;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type Fp6Bls = mod.IField<Fp6> & {
|
|
46
|
+
frobeniusMap(num: Fp6, power: number): Fp6;
|
|
47
|
+
fromBigSix: (tuple: BigintSix) => Fp6;
|
|
48
|
+
mul1(num: Fp6, b1: Fp2): Fp6;
|
|
49
|
+
mul01(num: Fp6, b0: Fp2, b1: Fp2): Fp6;
|
|
50
|
+
mulByFp2(lhs: Fp6, rhs: Fp2): Fp6;
|
|
51
|
+
mulByNonresidue: (num: Fp6) => Fp6;
|
|
41
52
|
};
|
|
42
53
|
|
|
43
54
|
export type Fp12Bls = mod.IField<Fp12> & {
|
|
44
55
|
frobeniusMap(num: Fp12, power: number): Fp12;
|
|
56
|
+
fromBigTwelve: (t: BigintTwelve) => Fp12;
|
|
45
57
|
mul014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
|
46
58
|
mul034(num: Fp12, o0: Fp2, o3: Fp2, o4: Fp2): Fp12;
|
|
59
|
+
mulByFp2(lhs: Fp12, rhs: Fp2): Fp12;
|
|
47
60
|
conjugate(num: Fp12): Fp12;
|
|
48
61
|
finalExponentiate(num: Fp12): Fp12;
|
|
49
|
-
|
|
62
|
+
_cyclotomicSquare(num: Fp12): Fp12;
|
|
63
|
+
_cyclotomicExp(num: Fp12, n: bigint): Fp12;
|
|
50
64
|
};
|
|
51
65
|
|
|
52
66
|
function calcFrobeniusCoefficients<T>(
|
|
@@ -88,7 +102,7 @@ export function psiFrobenius(
|
|
|
88
102
|
PSI2_X: Fp2;
|
|
89
103
|
PSI2_Y: Fp2;
|
|
90
104
|
} {
|
|
91
|
-
//
|
|
105
|
+
// GLV endomorphism Ψ(P)
|
|
92
106
|
const PSI_X = Fp2.pow(base, (Fp.ORDER - _1n) / _3n); // u^((p-1)/3)
|
|
93
107
|
const PSI_Y = Fp2.pow(base, (Fp.ORDER - _1n) / _2n); // u^((p-1)/2)
|
|
94
108
|
function psi(x: Fp2, y: Fp2): [Fp2, Fp2] {
|
|
@@ -134,34 +148,10 @@ export type Tower12Opts = {
|
|
|
134
148
|
|
|
135
149
|
export function tower12(opts: Tower12Opts): {
|
|
136
150
|
Fp: Readonly<mod.IField<bigint> & Required<Pick<mod.IField<bigint>, 'isOdd'>>>;
|
|
137
|
-
Fp2:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
reim: (num: Fp2) => { re: bigint; im: bigint };
|
|
141
|
-
mulByNonresidue: (num: Fp2) => Fp2;
|
|
142
|
-
mulByB: (num: Fp2) => Fp2;
|
|
143
|
-
frobeniusMap(num: Fp2, power: number): Fp2;
|
|
144
|
-
};
|
|
145
|
-
Fp6: mod.IField<Fp6> & {
|
|
146
|
-
fromBigSix: (tuple: BigintSix) => Fp6;
|
|
147
|
-
mulByNonresidue: (num: Fp6) => Fp6;
|
|
148
|
-
frobeniusMap(num: Fp6, power: number): Fp6;
|
|
149
|
-
mul1(num: Fp6, b1: Fp2): Fp6;
|
|
150
|
-
mul01(num: Fp6, b0: Fp2, b1: Fp2): Fp6;
|
|
151
|
-
mulByFp2(lhs: Fp6, rhs: Fp2): Fp6;
|
|
152
|
-
};
|
|
151
|
+
Fp2: Fp2Bls;
|
|
152
|
+
Fp6: Fp6Bls;
|
|
153
|
+
Fp12: Fp12Bls;
|
|
153
154
|
Fp4Square: (a: Fp2, b: Fp2) => { first: Fp2; second: Fp2 };
|
|
154
|
-
Fp12: mod.IField<Fp12> & {
|
|
155
|
-
fromBigTwelve: (t: BigintTwelve) => Fp12;
|
|
156
|
-
frobeniusMap(num: Fp12, power: number): Fp12;
|
|
157
|
-
mul014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
|
158
|
-
mul034(num: Fp12, o0: Fp2, o3: Fp2, o4: Fp2): Fp12;
|
|
159
|
-
mulByFp2(lhs: Fp12, rhs: Fp2): Fp12;
|
|
160
|
-
conjugate(num: Fp12): Fp12;
|
|
161
|
-
finalExponentiate(num: Fp12): Fp12;
|
|
162
|
-
_cyclotomicSquare(num: Fp12): Fp12;
|
|
163
|
-
_cyclotomicExp(num: Fp12, n: bigint): Fp12;
|
|
164
|
-
};
|
|
165
155
|
} {
|
|
166
156
|
const { ORDER } = opts;
|
|
167
157
|
// Fp
|
|
@@ -196,23 +186,19 @@ export function tower12(opts: Tower12Opts): {
|
|
|
196
186
|
const c = Fp.add(c0, c0);
|
|
197
187
|
return { c0: Fp.mul(a, b), c1: Fp.mul(c, c1) };
|
|
198
188
|
};
|
|
199
|
-
type Fp2Utils = {
|
|
200
|
-
NONRESIDUE: Fp2;
|
|
201
|
-
fromBigTuple: (tuple: BigintTuple | bigint[]) => Fp2;
|
|
202
|
-
reim: (num: Fp2) => { re: bigint; im: bigint };
|
|
203
|
-
mulByNonresidue: (num: Fp2) => Fp2;
|
|
204
|
-
mulByB: (num: Fp2) => Fp2;
|
|
205
|
-
frobeniusMap(num: Fp2, power: number): Fp2;
|
|
206
|
-
};
|
|
207
189
|
const Fp2fromBigTuple = (tuple: BigintTuple | bigint[]) => {
|
|
208
190
|
if (tuple.length !== 2) throw new Error('invalid tuple');
|
|
209
191
|
const fps = tuple.map((n) => Fp.create(n)) as [Fp, Fp];
|
|
210
192
|
return { c0: fps[0], c1: fps[1] };
|
|
211
193
|
};
|
|
212
194
|
|
|
195
|
+
function isValidC(num: bigint, ORDER: bigint) {
|
|
196
|
+
return typeof num === 'bigint' && _0n <= num && num < ORDER;
|
|
197
|
+
}
|
|
198
|
+
|
|
213
199
|
const FP2_ORDER = ORDER * ORDER;
|
|
214
200
|
const Fp2Nonresidue = Fp2fromBigTuple(opts.FP2_NONRESIDUE);
|
|
215
|
-
const Fp2:
|
|
201
|
+
const Fp2: Fp2Bls = {
|
|
216
202
|
ORDER: FP2_ORDER,
|
|
217
203
|
isLE: Fp.isLE,
|
|
218
204
|
NONRESIDUE: Fp2Nonresidue,
|
|
@@ -222,8 +208,9 @@ export function tower12(opts: Tower12Opts): {
|
|
|
222
208
|
ZERO: { c0: Fp.ZERO, c1: Fp.ZERO },
|
|
223
209
|
ONE: { c0: Fp.ONE, c1: Fp.ZERO },
|
|
224
210
|
create: (num) => num,
|
|
225
|
-
isValid: ({ c0, c1 }) =>
|
|
211
|
+
isValid: ({ c0, c1 }) => isValidC(c0, FP2_ORDER) && isValidC(c1, FP2_ORDER),
|
|
226
212
|
is0: ({ c0, c1 }) => Fp.is0(c0) && Fp.is0(c1),
|
|
213
|
+
isValidNot0: (num) => !Fp2.is0(num) && Fp2.isValid(num),
|
|
227
214
|
eql: ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => Fp.eql(c0, r0) && Fp.eql(c1, r1),
|
|
228
215
|
neg: ({ c0, c1 }) => ({ c0: Fp.neg(c0), c1: Fp.neg(c1) }),
|
|
229
216
|
pow: (num, power) => mod.FpPow(Fp2, num, power),
|
|
@@ -361,15 +348,6 @@ export function tower12(opts: Tower12Opts): {
|
|
|
361
348
|
c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
|
|
362
349
|
};
|
|
363
350
|
};
|
|
364
|
-
type Fp6Utils = {
|
|
365
|
-
fromBigSix: (tuple: BigintSix) => Fp6;
|
|
366
|
-
mulByNonresidue: (num: Fp6) => Fp6;
|
|
367
|
-
frobeniusMap(num: Fp6, power: number): Fp6;
|
|
368
|
-
mul1(num: Fp6, b1: Fp2): Fp6;
|
|
369
|
-
mul01(num: Fp6, b0: Fp2, b1: Fp2): Fp6;
|
|
370
|
-
mulByFp2(lhs: Fp6, rhs: Fp2): Fp6;
|
|
371
|
-
};
|
|
372
|
-
|
|
373
351
|
const [FP6_FROBENIUS_COEFFICIENTS_1, FP6_FROBENIUS_COEFFICIENTS_2] = calcFrobeniusCoefficients(
|
|
374
352
|
Fp2,
|
|
375
353
|
Fp2Nonresidue,
|
|
@@ -379,7 +357,7 @@ export function tower12(opts: Tower12Opts): {
|
|
|
379
357
|
3
|
|
380
358
|
);
|
|
381
359
|
|
|
382
|
-
const Fp6:
|
|
360
|
+
const Fp6: Fp6Bls = {
|
|
383
361
|
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
384
362
|
isLE: Fp2.isLE,
|
|
385
363
|
BITS: 3 * Fp2.BITS,
|
|
@@ -390,6 +368,7 @@ export function tower12(opts: Tower12Opts): {
|
|
|
390
368
|
create: (num) => num,
|
|
391
369
|
isValid: ({ c0, c1, c2 }) => Fp2.isValid(c0) && Fp2.isValid(c1) && Fp2.isValid(c2),
|
|
392
370
|
is0: ({ c0, c1, c2 }) => Fp2.is0(c0) && Fp2.is0(c1) && Fp2.is0(c2),
|
|
371
|
+
isValidNot0: (num) => !Fp6.is0(num) && Fp6.isValid(num),
|
|
393
372
|
neg: ({ c0, c1, c2 }) => ({ c0: Fp2.neg(c0), c1: Fp2.neg(c1), c2: Fp2.neg(c2) }),
|
|
394
373
|
eql: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) =>
|
|
395
374
|
Fp2.eql(c0, r0) && Fp2.eql(c1, r1) && Fp2.eql(c2, r2),
|
|
@@ -439,9 +418,9 @@ export function tower12(opts: Tower12Opts): {
|
|
|
439
418
|
fromBigSix: (t: BigintSix): Fp6 => {
|
|
440
419
|
if (!Array.isArray(t) || t.length !== 6) throw new Error('invalid Fp6 usage');
|
|
441
420
|
return {
|
|
442
|
-
c0: Fp2.fromBigTuple(t.slice(0, 2)),
|
|
443
|
-
c1: Fp2.fromBigTuple(t.slice(2, 4)),
|
|
444
|
-
c2: Fp2.fromBigTuple(t.slice(4, 6)),
|
|
421
|
+
c0: Fp2.fromBigTuple(t.slice(0, 2) as BigintTuple),
|
|
422
|
+
c1: Fp2.fromBigTuple(t.slice(2, 4) as BigintTuple),
|
|
423
|
+
c2: Fp2.fromBigTuple(t.slice(4, 6) as BigintTuple),
|
|
445
424
|
};
|
|
446
425
|
},
|
|
447
426
|
frobeniusMap: ({ c0, c1, c2 }, power: number) => ({
|
|
@@ -524,19 +503,8 @@ export function tower12(opts: Tower12Opts): {
|
|
|
524
503
|
second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
|
|
525
504
|
};
|
|
526
505
|
}
|
|
527
|
-
type Fp12Utils = {
|
|
528
|
-
fromBigTwelve: (t: BigintTwelve) => Fp12;
|
|
529
|
-
frobeniusMap(num: Fp12, power: number): Fp12;
|
|
530
|
-
mul014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
|
531
|
-
mul034(num: Fp12, o0: Fp2, o3: Fp2, o4: Fp2): Fp12;
|
|
532
|
-
mulByFp2(lhs: Fp12, rhs: Fp2): Fp12;
|
|
533
|
-
conjugate(num: Fp12): Fp12;
|
|
534
|
-
finalExponentiate(num: Fp12): Fp12;
|
|
535
|
-
_cyclotomicSquare(num: Fp12): Fp12;
|
|
536
|
-
_cyclotomicExp(num: Fp12, n: bigint): Fp12;
|
|
537
|
-
};
|
|
538
506
|
|
|
539
|
-
const Fp12:
|
|
507
|
+
const Fp12: Fp12Bls = {
|
|
540
508
|
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
541
509
|
isLE: Fp6.isLE,
|
|
542
510
|
BITS: 2 * Fp6.BITS,
|
|
@@ -547,6 +515,7 @@ export function tower12(opts: Tower12Opts): {
|
|
|
547
515
|
create: (num) => num,
|
|
548
516
|
isValid: ({ c0, c1 }) => Fp6.isValid(c0) && Fp6.isValid(c1),
|
|
549
517
|
is0: ({ c0, c1 }) => Fp6.is0(c0) && Fp6.is0(c1),
|
|
518
|
+
isValidNot0: (num) => !Fp12.is0(num) && Fp12.isValid(num),
|
|
550
519
|
neg: ({ c0, c1 }) => ({ c0: Fp6.neg(c0), c1: Fp6.neg(c1) }),
|
|
551
520
|
eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp6.eql(c0, r0) && Fp6.eql(c1, r1),
|
|
552
521
|
sqrt: notImplemented,
|
|
@@ -646,5 +615,5 @@ export function tower12(opts: Tower12Opts): {
|
|
|
646
615
|
finalExponentiate: opts.Fp12finalExponentiate,
|
|
647
616
|
};
|
|
648
617
|
|
|
649
|
-
return { Fp, Fp2, Fp6,
|
|
618
|
+
return { Fp, Fp2, Fp6, Fp12, Fp4Square };
|
|
650
619
|
}
|