@noble/curves 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -8
- package/lib/_shortw_utils.d.ts +11 -26
- package/lib/abstract/bls.d.ts +51 -35
- package/lib/abstract/bls.js +77 -139
- package/lib/abstract/{group.d.ts → curve.d.ts} +31 -1
- package/lib/abstract/{group.js → curve.js} +39 -2
- package/lib/abstract/edwards.d.ts +30 -81
- package/lib/abstract/edwards.js +225 -420
- package/lib/abstract/hash-to-curve.d.ts +25 -6
- package/lib/abstract/hash-to-curve.js +40 -12
- package/lib/abstract/modular.d.ts +20 -7
- package/lib/abstract/modular.js +80 -51
- package/lib/abstract/montgomery.js +3 -4
- package/lib/abstract/poseidon.d.ts +29 -0
- package/lib/abstract/poseidon.js +115 -0
- package/lib/abstract/utils.d.ts +5 -34
- package/lib/abstract/utils.js +23 -63
- package/lib/abstract/weierstrass.d.ts +56 -79
- package/lib/abstract/weierstrass.js +509 -641
- package/lib/bls12-381.d.ts +1 -0
- package/lib/bls12-381.js +75 -65
- package/lib/bn.js +1 -1
- package/lib/ed25519.d.ts +7 -5
- package/lib/ed25519.js +87 -84
- package/lib/ed448.d.ts +3 -0
- package/lib/ed448.js +88 -84
- package/lib/esm/abstract/bls.js +77 -139
- package/lib/esm/abstract/{group.js → curve.js} +37 -1
- package/lib/esm/abstract/edwards.js +223 -418
- package/lib/esm/abstract/hash-to-curve.js +38 -11
- package/lib/esm/abstract/modular.js +77 -50
- package/lib/esm/abstract/montgomery.js +4 -7
- package/lib/esm/abstract/poseidon.js +109 -0
- package/lib/esm/abstract/utils.js +21 -59
- package/lib/esm/abstract/weierstrass.js +508 -640
- package/lib/esm/bls12-381.js +86 -76
- package/lib/esm/bn.js +1 -1
- package/lib/esm/ed25519.js +85 -83
- package/lib/esm/ed448.js +86 -83
- package/lib/esm/jubjub.js +6 -5
- package/lib/esm/p256.js +11 -9
- package/lib/esm/p384.js +11 -9
- package/lib/esm/p521.js +13 -12
- package/lib/esm/secp256k1.js +118 -157
- package/lib/esm/stark.js +104 -39
- package/lib/jubjub.d.ts +3 -2
- package/lib/jubjub.js +6 -5
- package/lib/p192.d.ts +22 -52
- package/lib/p224.d.ts +22 -52
- package/lib/p256.d.ts +25 -52
- package/lib/p256.js +13 -10
- package/lib/p384.d.ts +25 -52
- package/lib/p384.js +13 -10
- package/lib/p521.d.ts +25 -52
- package/lib/p521.js +15 -13
- package/lib/secp256k1.d.ts +26 -42
- package/lib/secp256k1.js +118 -157
- package/lib/stark.d.ts +36 -21
- package/lib/stark.js +107 -39
- package/package.json +14 -9
package/lib/abstract/bls.js
CHANGED
|
@@ -1,27 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.bls = void 0;
|
|
4
|
-
|
|
5
|
-
// Barreto-Lynn-Scott Curves. A family of pairing friendly curves, with embedding degree = 12 or 24
|
|
6
|
-
// NOTE: only 12 supported for now
|
|
7
|
-
// Constructed from pair of weierstrass curves, based pairing logic
|
|
8
|
-
const mod = require("./modular.js");
|
|
4
|
+
const modular_js_1 = require("./modular.js");
|
|
9
5
|
const utils_js_1 = require("./utils.js");
|
|
10
|
-
|
|
11
|
-
const utils_js_2 = require("./utils.js");
|
|
12
|
-
const hash_to_curve_js_1 = require("./hash-to-curve.js");
|
|
6
|
+
const htf = require("./hash-to-curve.js");
|
|
13
7
|
const weierstrass_js_1 = require("./weierstrass.js");
|
|
14
8
|
function bls(CURVE) {
|
|
15
9
|
// Fields looks pretty specific for curve, so for now we need to pass them with options
|
|
16
|
-
const Fp = CURVE
|
|
17
|
-
const Fr = CURVE.Fr;
|
|
18
|
-
const Fp2 = CURVE.Fp2;
|
|
19
|
-
const Fp6 = CURVE.Fp6;
|
|
20
|
-
const Fp12 = CURVE.Fp12;
|
|
10
|
+
const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
|
|
21
11
|
const BLS_X_LEN = (0, utils_js_1.bitLen)(CURVE.x);
|
|
12
|
+
const groupLen = 32; // TODO: calculate; hardcoded for now
|
|
22
13
|
// Pre-compute coefficients for sparse multiplication
|
|
23
14
|
// Point addition and point double calculations is reused for coefficients
|
|
24
|
-
function calcPairingPrecomputes(
|
|
15
|
+
function calcPairingPrecomputes(p) {
|
|
16
|
+
const { x, y } = p;
|
|
25
17
|
// prettier-ignore
|
|
26
18
|
const Qx = x, Qy = y, Qz = Fp2.ONE;
|
|
27
19
|
// prettier-ignore
|
|
@@ -29,18 +21,18 @@ function bls(CURVE) {
|
|
|
29
21
|
let ell_coeff = [];
|
|
30
22
|
for (let i = BLS_X_LEN - 2; i >= 0; i--) {
|
|
31
23
|
// Double
|
|
32
|
-
let t0 = Fp2.
|
|
33
|
-
let t1 = Fp2.
|
|
24
|
+
let t0 = Fp2.sqr(Ry); // Ry²
|
|
25
|
+
let t1 = Fp2.sqr(Rz); // Rz²
|
|
34
26
|
let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
|
|
35
27
|
let t3 = Fp2.mul(t2, 3n); // 3 * T2
|
|
36
|
-
let t4 = Fp2.sub(Fp2.sub(Fp2.
|
|
28
|
+
let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
|
|
37
29
|
ell_coeff.push([
|
|
38
30
|
Fp2.sub(t2, t0),
|
|
39
|
-
Fp2.mul(Fp2.
|
|
40
|
-
Fp2.
|
|
31
|
+
Fp2.mul(Fp2.sqr(Rx), 3n),
|
|
32
|
+
Fp2.neg(t4), // -T4
|
|
41
33
|
]);
|
|
42
34
|
Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
|
|
43
|
-
Ry = Fp2.sub(Fp2.
|
|
35
|
+
Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.sqr(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
|
|
44
36
|
Rz = Fp2.mul(t0, t4); // T0 * T4
|
|
45
37
|
if ((0, utils_js_1.bitGet)(CURVE.x, i)) {
|
|
46
38
|
// Addition
|
|
@@ -48,13 +40,13 @@ function bls(CURVE) {
|
|
|
48
40
|
let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
|
|
49
41
|
ell_coeff.push([
|
|
50
42
|
Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)),
|
|
51
|
-
Fp2.
|
|
43
|
+
Fp2.neg(t0),
|
|
52
44
|
t1, // T1
|
|
53
45
|
]);
|
|
54
|
-
let t2 = Fp2.
|
|
46
|
+
let t2 = Fp2.sqr(t1); // T1²
|
|
55
47
|
let t3 = Fp2.mul(t2, t1); // T2 * T1
|
|
56
48
|
let t4 = Fp2.mul(t2, Rx); // T2 * Rx
|
|
57
|
-
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.
|
|
49
|
+
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
|
|
58
50
|
Rx = Fp2.mul(t1, t5); // T1 * T5
|
|
59
51
|
Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
|
|
60
52
|
Rz = Fp2.mul(Rz, t3); // Rz * T3
|
|
@@ -63,175 +55,121 @@ function bls(CURVE) {
|
|
|
63
55
|
return ell_coeff;
|
|
64
56
|
}
|
|
65
57
|
function millerLoop(ell, g1) {
|
|
58
|
+
const { x } = CURVE;
|
|
66
59
|
const Px = g1[0];
|
|
67
60
|
const Py = g1[1];
|
|
68
61
|
let f12 = Fp12.ONE;
|
|
69
62
|
for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
|
|
70
63
|
const E = ell[j];
|
|
71
64
|
f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
|
|
72
|
-
if ((0, utils_js_1.bitGet)(
|
|
65
|
+
if ((0, utils_js_1.bitGet)(x, i)) {
|
|
73
66
|
j += 1;
|
|
74
67
|
const F = ell[j];
|
|
75
68
|
f12 = Fp12.multiplyBy014(f12, F[0], Fp2.mul(F[1], Px), Fp2.mul(F[2], Py));
|
|
76
69
|
}
|
|
77
70
|
if (i !== 0)
|
|
78
|
-
f12 = Fp12.
|
|
71
|
+
f12 = Fp12.sqr(f12);
|
|
79
72
|
}
|
|
80
73
|
return Fp12.conjugate(f12);
|
|
81
74
|
}
|
|
82
|
-
// bls12-381 is a construction of two curves:
|
|
83
|
-
// 1. Fp: (x, y)
|
|
84
|
-
// 2. Fp₂: ((x₁, x₂+i), (y₁, y₂+i)) - (complex numbers)
|
|
85
|
-
//
|
|
86
|
-
// Bilinear Pairing (ate pairing) is used to combine both elements into a paired one:
|
|
87
|
-
// Fp₁₂ = e(Fp, Fp2)
|
|
88
|
-
// where Fp₁₂ = 12-degree polynomial
|
|
89
|
-
// Pairing is used to verify signatures.
|
|
90
|
-
//
|
|
91
|
-
// We are using Fp for private keys (shorter) and Fp2 for signatures (longer).
|
|
92
|
-
// Some projects may prefer to swap this relation, it is not supported for now.
|
|
93
|
-
const htfDefaults = { ...CURVE.htfDefaults };
|
|
94
|
-
function isWithinCurveOrder(num) {
|
|
95
|
-
return 0 < num && num < CURVE.r;
|
|
96
|
-
}
|
|
97
75
|
const utils = {
|
|
98
|
-
hexToBytes:
|
|
99
|
-
bytesToHex:
|
|
100
|
-
|
|
101
|
-
stringToBytes: hash_to_curve_js_1.stringToBytes,
|
|
76
|
+
hexToBytes: utils_js_1.hexToBytes,
|
|
77
|
+
bytesToHex: utils_js_1.bytesToHex,
|
|
78
|
+
stringToBytes: htf.stringToBytes,
|
|
102
79
|
// TODO: do we need to export it here?
|
|
103
|
-
hashToField: (msg, count, options = {}) =>
|
|
104
|
-
expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) =>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
* As per FIPS 186 B.1.1.
|
|
109
|
-
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
110
|
-
* @param hash hash output from sha512, or a similar function
|
|
111
|
-
* @returns valid private key
|
|
112
|
-
*/
|
|
113
|
-
hashToPrivateKey: (hash) => {
|
|
114
|
-
hash = (0, utils_js_1.ensureBytes)(hash);
|
|
115
|
-
if (hash.length < 40 || hash.length > 1024)
|
|
116
|
-
throw new Error('Expected 40-1024 bytes of private key as per FIPS 186');
|
|
117
|
-
// hashToPrivateScalar(hash, CURVE.r)
|
|
118
|
-
// NOTE: doesn't add +/-1
|
|
119
|
-
const num = mod.mod((0, utils_js_1.bytesToNumberBE)(hash), CURVE.r);
|
|
120
|
-
// This should never happen
|
|
121
|
-
if (num === 0n || num === 1n)
|
|
122
|
-
throw new Error('Invalid private key');
|
|
123
|
-
return (0, utils_js_1.numberToBytesBE)(num, 32);
|
|
124
|
-
},
|
|
125
|
-
randomBytes: (bytesLength = 32) => CURVE.randomBytes(bytesLength),
|
|
126
|
-
// NIST SP 800-56A rev 3, section 5.6.1.2.2
|
|
127
|
-
// https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
128
|
-
randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(40)),
|
|
129
|
-
getDSTLabel: () => htfDefaults.DST,
|
|
130
|
-
setDSTLabel(newLabel) {
|
|
131
|
-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3.1
|
|
132
|
-
if (typeof newLabel !== 'string' || newLabel.length > 2048 || newLabel.length === 0) {
|
|
133
|
-
throw new TypeError('Invalid DST');
|
|
134
|
-
}
|
|
135
|
-
htfDefaults.DST = newLabel;
|
|
136
|
-
},
|
|
80
|
+
hashToField: (msg, count, options = {}) => htf.hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }),
|
|
81
|
+
expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => htf.expand_message_xmd(msg, DST, lenInBytes, H),
|
|
82
|
+
hashToPrivateKey: (hash) => Fr.toBytes((0, modular_js_1.hashToPrivateScalar)(hash, CURVE.r)),
|
|
83
|
+
randomBytes: (bytesLength = groupLen) => CURVE.randomBytes(bytesLength),
|
|
84
|
+
randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)),
|
|
137
85
|
};
|
|
138
|
-
function normalizePrivKey(key) {
|
|
139
|
-
let int;
|
|
140
|
-
if (key instanceof Uint8Array && key.length === 32)
|
|
141
|
-
int = (0, utils_js_1.bytesToNumberBE)(key);
|
|
142
|
-
else if (typeof key === 'string' && key.length === 64)
|
|
143
|
-
int = BigInt(`0x${key}`);
|
|
144
|
-
else if (typeof key === 'number' && key > 0 && Number.isSafeInteger(key))
|
|
145
|
-
int = BigInt(key);
|
|
146
|
-
else if (typeof key === 'bigint' && key > 0n)
|
|
147
|
-
int = key;
|
|
148
|
-
else
|
|
149
|
-
throw new TypeError('Expected valid private key');
|
|
150
|
-
int = mod.mod(int, CURVE.r);
|
|
151
|
-
if (!isWithinCurveOrder(int))
|
|
152
|
-
throw new Error('Private key must be 0 < key < CURVE.r');
|
|
153
|
-
return int;
|
|
154
|
-
}
|
|
155
86
|
// Point on G1 curve: (x, y)
|
|
156
87
|
const G1 = (0, weierstrass_js_1.weierstrassPoints)({
|
|
157
88
|
n: Fr.ORDER,
|
|
158
89
|
...CURVE.G1,
|
|
159
90
|
});
|
|
91
|
+
const G1HashToCurve = htf.hashToCurve(G1.ProjectivePoint, CURVE.G1.mapToCurve, {
|
|
92
|
+
...CURVE.htfDefaults,
|
|
93
|
+
...CURVE.G1.htfDefaults,
|
|
94
|
+
});
|
|
160
95
|
function pairingPrecomputes(point) {
|
|
161
96
|
const p = point;
|
|
162
97
|
if (p._PPRECOMPUTES)
|
|
163
98
|
return p._PPRECOMPUTES;
|
|
164
|
-
p._PPRECOMPUTES = calcPairingPrecomputes(
|
|
99
|
+
p._PPRECOMPUTES = calcPairingPrecomputes(point.toAffine());
|
|
165
100
|
return p._PPRECOMPUTES;
|
|
166
101
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
function millerLoopG1(Q, P) {
|
|
173
|
-
return millerLoop(pairingPrecomputes(P), [Q.x, Q.y]);
|
|
174
|
-
}
|
|
102
|
+
// TODO: export
|
|
103
|
+
// function clearPairingPrecomputes(point: G2) {
|
|
104
|
+
// const p = point as G2 & withPairingPrecomputes;
|
|
105
|
+
// p._PPRECOMPUTES = undefined;
|
|
106
|
+
// }
|
|
175
107
|
// Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
|
|
176
108
|
const G2 = (0, weierstrass_js_1.weierstrassPoints)({
|
|
177
109
|
n: Fr.ORDER,
|
|
178
110
|
...CURVE.G2,
|
|
179
111
|
});
|
|
112
|
+
const C = G2.ProjectivePoint; // TODO: fix
|
|
113
|
+
const G2HashToCurve = htf.hashToCurve(C, CURVE.G2.mapToCurve, {
|
|
114
|
+
...CURVE.htfDefaults,
|
|
115
|
+
...CURVE.G2.htfDefaults,
|
|
116
|
+
});
|
|
180
117
|
const { Signature } = CURVE.G2;
|
|
181
118
|
// Calculates bilinear pairing
|
|
182
|
-
function pairing(
|
|
183
|
-
if (
|
|
184
|
-
throw new Error('
|
|
185
|
-
P.assertValidity();
|
|
119
|
+
function pairing(Q, P, withFinalExponent = true) {
|
|
120
|
+
if (Q.equals(G1.ProjectivePoint.ZERO) || P.equals(G2.ProjectivePoint.ZERO))
|
|
121
|
+
throw new Error('pairing is not available for ZERO point');
|
|
186
122
|
Q.assertValidity();
|
|
123
|
+
P.assertValidity();
|
|
187
124
|
// Performance: 9ms for millerLoop and ~14ms for exp.
|
|
188
|
-
const
|
|
125
|
+
const Qa = Q.toAffine();
|
|
126
|
+
const looped = millerLoop(pairingPrecomputes(P), [Qa.x, Qa.y]);
|
|
189
127
|
return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
|
|
190
128
|
}
|
|
191
129
|
function normP1(point) {
|
|
192
|
-
return point instanceof G1.
|
|
130
|
+
return point instanceof G1.ProjectivePoint ? point : G1.ProjectivePoint.fromHex(point);
|
|
193
131
|
}
|
|
194
132
|
function normP2(point) {
|
|
195
|
-
return point instanceof G2.
|
|
133
|
+
return point instanceof G2.ProjectivePoint ? point : Signature.decode(point);
|
|
196
134
|
}
|
|
197
|
-
function normP2Hash(point) {
|
|
198
|
-
return point instanceof G2.
|
|
135
|
+
function normP2Hash(point, htfOpts) {
|
|
136
|
+
return point instanceof G2.ProjectivePoint
|
|
137
|
+
? point
|
|
138
|
+
: G2HashToCurve.hashToCurve(point, htfOpts);
|
|
199
139
|
}
|
|
200
140
|
// Multiplies generator by private key.
|
|
201
141
|
// P = pk x G
|
|
202
142
|
function getPublicKey(privateKey) {
|
|
203
|
-
return G1.
|
|
143
|
+
return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
|
|
204
144
|
}
|
|
205
|
-
function sign(message, privateKey) {
|
|
206
|
-
const msgPoint = normP2Hash(message);
|
|
145
|
+
function sign(message, privateKey, htfOpts) {
|
|
146
|
+
const msgPoint = normP2Hash(message, htfOpts);
|
|
207
147
|
msgPoint.assertValidity();
|
|
208
|
-
const sigPoint = msgPoint.multiply(
|
|
209
|
-
if (message instanceof G2.
|
|
148
|
+
const sigPoint = msgPoint.multiply(G1.normalizePrivateKey(privateKey));
|
|
149
|
+
if (message instanceof G2.ProjectivePoint)
|
|
210
150
|
return sigPoint;
|
|
211
151
|
return Signature.encode(sigPoint);
|
|
212
152
|
}
|
|
213
153
|
// Checks if pairing of public key & hash is equal to pairing of generator & signature.
|
|
214
154
|
// e(P, H(m)) == e(G, S)
|
|
215
|
-
function verify(signature, message, publicKey) {
|
|
155
|
+
function verify(signature, message, publicKey, htfOpts) {
|
|
216
156
|
const P = normP1(publicKey);
|
|
217
|
-
const Hm = normP2Hash(message);
|
|
218
|
-
const G = G1.
|
|
157
|
+
const Hm = normP2Hash(message, htfOpts);
|
|
158
|
+
const G = G1.ProjectivePoint.BASE;
|
|
219
159
|
const S = normP2(signature);
|
|
220
160
|
// Instead of doing 2 exponentiations, we use property of billinear maps
|
|
221
161
|
// and do one exp after multiplying 2 points.
|
|
222
162
|
const ePHm = pairing(P.negate(), Hm, false);
|
|
223
163
|
const eGS = pairing(G, S, false);
|
|
224
164
|
const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
|
|
225
|
-
return Fp12.
|
|
165
|
+
return Fp12.eql(exp, Fp12.ONE);
|
|
226
166
|
}
|
|
227
167
|
function aggregatePublicKeys(publicKeys) {
|
|
228
168
|
if (!publicKeys.length)
|
|
229
169
|
throw new Error('Expected non-empty array');
|
|
230
|
-
const agg = publicKeys
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const aggAffine = agg.toAffine();
|
|
234
|
-
if (publicKeys[0] instanceof G1.Point) {
|
|
170
|
+
const agg = publicKeys.map(normP1).reduce((sum, p) => sum.add(p), G1.ProjectivePoint.ZERO);
|
|
171
|
+
const aggAffine = agg; //.toAffine();
|
|
172
|
+
if (publicKeys[0] instanceof G1.ProjectivePoint) {
|
|
235
173
|
aggAffine.assertValidity();
|
|
236
174
|
return aggAffine;
|
|
237
175
|
}
|
|
@@ -241,11 +179,9 @@ function bls(CURVE) {
|
|
|
241
179
|
function aggregateSignatures(signatures) {
|
|
242
180
|
if (!signatures.length)
|
|
243
181
|
throw new Error('Expected non-empty array');
|
|
244
|
-
const agg = signatures
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const aggAffine = agg.toAffine();
|
|
248
|
-
if (signatures[0] instanceof G2.Point) {
|
|
182
|
+
const agg = signatures.map(normP2).reduce((sum, s) => sum.add(s), G2.ProjectivePoint.ZERO);
|
|
183
|
+
const aggAffine = agg; //.toAffine();
|
|
184
|
+
if (signatures[0] instanceof G2.ProjectivePoint) {
|
|
249
185
|
aggAffine.assertValidity();
|
|
250
186
|
return aggAffine;
|
|
251
187
|
}
|
|
@@ -253,33 +189,34 @@ function bls(CURVE) {
|
|
|
253
189
|
}
|
|
254
190
|
// https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
|
|
255
191
|
// e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
|
|
256
|
-
function verifyBatch(signature, messages, publicKeys) {
|
|
192
|
+
function verifyBatch(signature, messages, publicKeys, htfOpts) {
|
|
193
|
+
// @ts-ignore
|
|
194
|
+
// console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
|
|
257
195
|
if (!messages.length)
|
|
258
196
|
throw new Error('Expected non-empty messages array');
|
|
259
197
|
if (publicKeys.length !== messages.length)
|
|
260
198
|
throw new Error('Pubkey count should equal msg count');
|
|
261
199
|
const sig = normP2(signature);
|
|
262
|
-
const nMessages = messages.map(normP2Hash);
|
|
200
|
+
const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
|
|
263
201
|
const nPublicKeys = publicKeys.map(normP1);
|
|
264
202
|
try {
|
|
265
203
|
const paired = [];
|
|
266
204
|
for (const message of new Set(nMessages)) {
|
|
267
|
-
const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.
|
|
205
|
+
const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.ProjectivePoint.ZERO);
|
|
268
206
|
// const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);
|
|
269
207
|
// Possible to batch pairing for same msg with different groupPublicKey here
|
|
270
208
|
paired.push(pairing(groupPublicKey, message, false));
|
|
271
209
|
}
|
|
272
|
-
paired.push(pairing(G1.
|
|
210
|
+
paired.push(pairing(G1.ProjectivePoint.BASE.negate(), sig, false));
|
|
273
211
|
const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
|
|
274
212
|
const exp = Fp12.finalExponentiate(product);
|
|
275
|
-
return Fp12.
|
|
213
|
+
return Fp12.eql(exp, Fp12.ONE);
|
|
276
214
|
}
|
|
277
215
|
catch {
|
|
278
216
|
return false;
|
|
279
217
|
}
|
|
280
218
|
}
|
|
281
|
-
|
|
282
|
-
G1.Point.BASE._setWindowSize(4);
|
|
219
|
+
G1.ProjectivePoint.BASE._setWindowSize(4);
|
|
283
220
|
return {
|
|
284
221
|
CURVE,
|
|
285
222
|
Fr,
|
|
@@ -292,6 +229,7 @@ function bls(CURVE) {
|
|
|
292
229
|
Signature,
|
|
293
230
|
millerLoop,
|
|
294
231
|
calcPairingPrecomputes,
|
|
232
|
+
hashToCurve: { G1: G1HashToCurve, G2: G2HashToCurve },
|
|
295
233
|
pairing,
|
|
296
234
|
getPublicKey,
|
|
297
235
|
sign,
|
|
@@ -1,15 +1,25 @@
|
|
|
1
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
+
import { Field } from './modular.js';
|
|
3
|
+
export declare type AffinePoint<T> = {
|
|
4
|
+
x: T;
|
|
5
|
+
y: T;
|
|
6
|
+
} & {
|
|
7
|
+
z?: never;
|
|
8
|
+
t?: never;
|
|
9
|
+
};
|
|
1
10
|
export interface Group<T extends Group<T>> {
|
|
2
11
|
double(): T;
|
|
3
12
|
negate(): T;
|
|
4
13
|
add(other: T): T;
|
|
5
14
|
subtract(other: T): T;
|
|
6
15
|
equals(other: T): boolean;
|
|
7
|
-
multiply(scalar:
|
|
16
|
+
multiply(scalar: bigint): T;
|
|
8
17
|
}
|
|
9
18
|
export declare type GroupConstructor<T> = {
|
|
10
19
|
BASE: T;
|
|
11
20
|
ZERO: T;
|
|
12
21
|
};
|
|
22
|
+
export declare type Mapper<T> = (i: T[]) => T[];
|
|
13
23
|
export declare function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number): {
|
|
14
24
|
constTimeNegate: (condition: boolean, item: T) => T;
|
|
15
25
|
unsafeLadder(elm: T, n: bigint): T;
|
|
@@ -31,4 +41,24 @@ export declare function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: n
|
|
|
31
41
|
p: T;
|
|
32
42
|
f: T;
|
|
33
43
|
};
|
|
44
|
+
wNAFCached(P: T, precomputesMap: Map<T, T[]>, n: bigint, transform: Mapper<T>): {
|
|
45
|
+
p: T;
|
|
46
|
+
f: T;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export declare type AbstractCurve<T> = {
|
|
50
|
+
Fp: Field<T>;
|
|
51
|
+
n: bigint;
|
|
52
|
+
nBitLength?: number;
|
|
53
|
+
nByteLength?: number;
|
|
54
|
+
h: bigint;
|
|
55
|
+
hEff?: bigint;
|
|
56
|
+
Gx: T;
|
|
57
|
+
Gy: T;
|
|
58
|
+
wrapPrivateKey?: boolean;
|
|
59
|
+
allowInfinityPoint?: boolean;
|
|
34
60
|
};
|
|
61
|
+
export declare function validateAbsOpts<FP, T>(curve: AbstractCurve<FP> & T): Readonly<{
|
|
62
|
+
readonly nBitLength: number;
|
|
63
|
+
readonly nByteLength: number;
|
|
64
|
+
} & AbstractCurve<FP> & T>;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.wNAF = void 0;
|
|
3
|
+
exports.validateAbsOpts = exports.wNAF = void 0;
|
|
4
4
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
5
|
// Abelian group utilities
|
|
6
|
+
const modular_js_1 = require("./modular.js");
|
|
6
7
|
const _0n = BigInt(0);
|
|
7
8
|
const _1n = BigInt(1);
|
|
8
|
-
//
|
|
9
|
+
// Elliptic curve multiplication of Point by scalar. Complicated and fragile. Uses wNAF method.
|
|
10
|
+
// Windowed method is 10% faster, but takes 2x longer to generate & consumes 2x memory.
|
|
9
11
|
function wNAF(c, bits) {
|
|
10
12
|
const constTimeNegate = (condition, item) => {
|
|
11
13
|
const neg = item.negate();
|
|
@@ -107,6 +109,41 @@ function wNAF(c, bits) {
|
|
|
107
109
|
// which makes it less const-time: around 1 bigint multiply.
|
|
108
110
|
return { p, f };
|
|
109
111
|
},
|
|
112
|
+
wNAFCached(P, precomputesMap, n, transform) {
|
|
113
|
+
// @ts-ignore
|
|
114
|
+
const W = P._WINDOW_SIZE || 1;
|
|
115
|
+
// Calculate precomputes on a first run, reuse them after
|
|
116
|
+
let comp = precomputesMap.get(P);
|
|
117
|
+
if (!comp) {
|
|
118
|
+
comp = this.precomputeWindow(P, W);
|
|
119
|
+
if (W !== 1) {
|
|
120
|
+
precomputesMap.set(P, transform(comp));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return this.wNAF(W, comp, n);
|
|
124
|
+
},
|
|
110
125
|
};
|
|
111
126
|
}
|
|
112
127
|
exports.wNAF = wNAF;
|
|
128
|
+
function validateAbsOpts(curve) {
|
|
129
|
+
(0, modular_js_1.validateField)(curve.Fp);
|
|
130
|
+
for (const i of ['n', 'h']) {
|
|
131
|
+
const val = curve[i];
|
|
132
|
+
if (typeof val !== 'bigint')
|
|
133
|
+
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
|
|
134
|
+
}
|
|
135
|
+
if (!curve.Fp.isValid(curve.Gx))
|
|
136
|
+
throw new Error('Invalid generator X coordinate Fp element');
|
|
137
|
+
if (!curve.Fp.isValid(curve.Gy))
|
|
138
|
+
throw new Error('Invalid generator Y coordinate Fp element');
|
|
139
|
+
for (const i of ['nBitLength', 'nByteLength']) {
|
|
140
|
+
const val = curve[i];
|
|
141
|
+
if (val === undefined)
|
|
142
|
+
continue; // Optional
|
|
143
|
+
if (!Number.isSafeInteger(val))
|
|
144
|
+
throw new Error(`Invalid param ${i}=${val} (${typeof val})`);
|
|
145
|
+
}
|
|
146
|
+
// Set defaults
|
|
147
|
+
return Object.freeze({ ...(0, modular_js_1.nLength)(curve.n, curve.nBitLength), ...curve });
|
|
148
|
+
}
|
|
149
|
+
exports.validateAbsOpts = validateAbsOpts;
|
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import { Group, GroupConstructor } from './group.js';
|
|
5
|
-
import { htfOpts } from './hash-to-curve.js';
|
|
6
|
-
export declare type CHash = {
|
|
7
|
-
(message: Uint8Array | string): Uint8Array;
|
|
8
|
-
blockLen: number;
|
|
9
|
-
outputLen: number;
|
|
10
|
-
create(): any;
|
|
11
|
-
};
|
|
12
|
-
export declare type CurveType = BasicCurve<bigint> & {
|
|
1
|
+
import { FHash, Hex } from './utils.js';
|
|
2
|
+
import { Group, GroupConstructor, AbstractCurve, AffinePoint } from './curve.js';
|
|
3
|
+
export declare type CurveType = AbstractCurve<bigint> & {
|
|
13
4
|
a: bigint;
|
|
14
5
|
d: bigint;
|
|
15
|
-
hash:
|
|
6
|
+
hash: FHash;
|
|
16
7
|
randomBytes: (bytesLength?: number) => Uint8Array;
|
|
17
8
|
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array;
|
|
18
9
|
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array;
|
|
@@ -20,18 +11,13 @@ export declare type CurveType = BasicCurve<bigint> & {
|
|
|
20
11
|
isValid: boolean;
|
|
21
12
|
value: bigint;
|
|
22
13
|
};
|
|
23
|
-
preHash?:
|
|
24
|
-
|
|
25
|
-
htfDefaults?: htfOpts;
|
|
26
|
-
mapToCurve?: (scalar: bigint[]) => {
|
|
27
|
-
x: bigint;
|
|
28
|
-
y: bigint;
|
|
29
|
-
};
|
|
14
|
+
preHash?: FHash;
|
|
15
|
+
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>;
|
|
30
16
|
};
|
|
31
17
|
declare function validateOpts(curve: CurveType): Readonly<{
|
|
32
18
|
readonly nBitLength: number;
|
|
33
19
|
readonly nByteLength: number;
|
|
34
|
-
readonly Fp:
|
|
20
|
+
readonly Fp: import("./modular.js").Field<bigint>;
|
|
35
21
|
readonly n: bigint;
|
|
36
22
|
readonly h: bigint;
|
|
37
23
|
readonly hEff?: bigint | undefined;
|
|
@@ -41,7 +27,7 @@ declare function validateOpts(curve: CurveType): Readonly<{
|
|
|
41
27
|
readonly allowInfinityPoint?: boolean | undefined;
|
|
42
28
|
readonly a: bigint;
|
|
43
29
|
readonly d: bigint;
|
|
44
|
-
readonly hash:
|
|
30
|
+
readonly hash: FHash;
|
|
45
31
|
readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
|
|
46
32
|
readonly adjustScalarBytes?: ((bytes: Uint8Array) => Uint8Array) | undefined;
|
|
47
33
|
readonly domain?: ((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array) | undefined;
|
|
@@ -49,78 +35,41 @@ declare function validateOpts(curve: CurveType): Readonly<{
|
|
|
49
35
|
isValid: boolean;
|
|
50
36
|
value: bigint;
|
|
51
37
|
}) | undefined;
|
|
52
|
-
readonly preHash?:
|
|
53
|
-
readonly
|
|
54
|
-
readonly htfDefaults?: htfOpts | undefined;
|
|
55
|
-
readonly mapToCurve?: ((scalar: bigint[]) => {
|
|
56
|
-
x: bigint;
|
|
57
|
-
y: bigint;
|
|
58
|
-
}) | undefined;
|
|
38
|
+
readonly preHash?: FHash | undefined;
|
|
39
|
+
readonly mapToCurve?: ((scalar: bigint[]) => AffinePoint<bigint>) | undefined;
|
|
59
40
|
}>;
|
|
60
|
-
export interface
|
|
61
|
-
readonly
|
|
62
|
-
readonly
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
new (r: PointType, s: bigint): SignatureType;
|
|
69
|
-
fromHex(hex: Hex): SignatureType;
|
|
70
|
-
};
|
|
71
|
-
export interface ExtendedPointType extends Group<ExtendedPointType> {
|
|
72
|
-
readonly x: bigint;
|
|
73
|
-
readonly y: bigint;
|
|
74
|
-
readonly z: bigint;
|
|
75
|
-
readonly t: bigint;
|
|
76
|
-
multiply(scalar: number | bigint, affinePoint?: PointType): ExtendedPointType;
|
|
77
|
-
multiplyUnsafe(scalar: number | bigint): ExtendedPointType;
|
|
41
|
+
export interface ExtPointType extends Group<ExtPointType> {
|
|
42
|
+
readonly ex: bigint;
|
|
43
|
+
readonly ey: bigint;
|
|
44
|
+
readonly ez: bigint;
|
|
45
|
+
readonly et: bigint;
|
|
46
|
+
assertValidity(): void;
|
|
47
|
+
multiply(scalar: bigint): ExtPointType;
|
|
48
|
+
multiplyUnsafe(scalar: bigint): ExtPointType;
|
|
78
49
|
isSmallOrder(): boolean;
|
|
79
50
|
isTorsionFree(): boolean;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
export interface ExtendedPointConstructor extends GroupConstructor<ExtendedPointType> {
|
|
84
|
-
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtendedPointType;
|
|
85
|
-
fromAffine(p: PointType): ExtendedPointType;
|
|
86
|
-
toAffineBatch(points: ExtendedPointType[]): PointType[];
|
|
87
|
-
normalizeZ(points: ExtendedPointType[]): ExtendedPointType[];
|
|
88
|
-
}
|
|
89
|
-
export interface PointType extends Group<PointType> {
|
|
90
|
-
readonly x: bigint;
|
|
91
|
-
readonly y: bigint;
|
|
92
|
-
_setWindowSize(windowSize: number): void;
|
|
93
|
-
toRawBytes(isCompressed?: boolean): Uint8Array;
|
|
94
|
-
toHex(isCompressed?: boolean): string;
|
|
95
|
-
isTorsionFree(): boolean;
|
|
96
|
-
clearCofactor(): PointType;
|
|
51
|
+
clearCofactor(): ExtPointType;
|
|
52
|
+
toAffine(iz?: bigint): AffinePoint<bigint>;
|
|
97
53
|
}
|
|
98
|
-
export interface
|
|
99
|
-
new (x: bigint, y: bigint):
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
encodeToCurve(msg: Hex, options?: Partial<htfOpts>): PointType;
|
|
54
|
+
export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
|
55
|
+
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
|
|
56
|
+
fromAffine(p: AffinePoint<bigint>): ExtPointType;
|
|
57
|
+
fromHex(hex: Hex): ExtPointType;
|
|
58
|
+
fromPrivateKey(privateKey: Hex): ExtPointType;
|
|
104
59
|
}
|
|
105
|
-
export declare type PubKey = Hex | PointType;
|
|
106
|
-
export declare type SigType = Hex | SignatureType;
|
|
107
60
|
export declare type CurveFn = {
|
|
108
61
|
CURVE: ReturnType<typeof validateOpts>;
|
|
109
|
-
getPublicKey: (privateKey:
|
|
62
|
+
getPublicKey: (privateKey: Hex) => Uint8Array;
|
|
110
63
|
sign: (message: Hex, privateKey: Hex) => Uint8Array;
|
|
111
|
-
verify: (sig:
|
|
112
|
-
|
|
113
|
-
ExtendedPoint: ExtendedPointConstructor;
|
|
114
|
-
Signature: SignatureConstructor;
|
|
64
|
+
verify: (sig: Hex, message: Hex, publicKey: Hex) => boolean;
|
|
65
|
+
ExtendedPoint: ExtPointConstructor;
|
|
115
66
|
utils: {
|
|
116
|
-
mod: (a: bigint) => bigint;
|
|
117
|
-
invert: (number: bigint) => bigint;
|
|
118
67
|
randomPrivateKey: () => Uint8Array;
|
|
119
|
-
getExtendedPublicKey: (key:
|
|
68
|
+
getExtendedPublicKey: (key: Hex) => {
|
|
120
69
|
head: Uint8Array;
|
|
121
70
|
prefix: Uint8Array;
|
|
122
71
|
scalar: bigint;
|
|
123
|
-
point:
|
|
72
|
+
point: ExtPointType;
|
|
124
73
|
pointBytes: Uint8Array;
|
|
125
74
|
};
|
|
126
75
|
};
|