@noble/curves 0.9.0 → 1.0.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 +197 -99
- package/abstract/bls.d.ts +43 -31
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +37 -28
- package/abstract/bls.js.map +1 -1
- package/abstract/edwards.d.ts +6 -2
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +37 -26
- package/abstract/edwards.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +1 -1
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +3 -2
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.js +1 -1
- package/abstract/modular.js.map +1 -1
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +2 -2
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +23 -0
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +44 -31
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +161 -162
- package/bls12-381.js.map +1 -1
- package/{bn.d.ts → bn254.d.ts} +1 -1
- package/bn254.d.ts.map +1 -0
- package/{bn.js → bn254.js} +1 -1
- package/bn254.js.map +1 -0
- package/ed25519.d.ts +9 -0
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +23 -9
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +9 -0
- package/ed448.d.ts.map +1 -1
- package/ed448.js +19 -18
- package/ed448.js.map +1 -1
- package/esm/abstract/bls.js +37 -28
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/edwards.js +37 -26
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.js +3 -2
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.js +1 -1
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/utils.js +2 -2
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.js +36 -23
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.js +162 -163
- package/esm/bls12-381.js.map +1 -1
- package/esm/{bn.js → bn254.js} +1 -1
- package/esm/bn254.js.map +1 -0
- package/esm/ed25519.js +21 -8
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.js +17 -17
- package/esm/ed448.js.map +1 -1
- package/esm/p256.js +5 -6
- package/esm/p256.js.map +1 -1
- package/esm/p384.js +10 -12
- package/esm/p384.js.map +1 -1
- package/esm/p521.js +22 -18
- package/esm/p521.js.map +1 -1
- package/esm/secp256k1.js +1 -1
- package/esm/secp256k1.js.map +1 -1
- package/p256.d.ts +1 -1
- package/p256.d.ts.map +1 -1
- package/p256.js +6 -7
- package/p256.js.map +1 -1
- package/p384.d.ts +1 -1
- package/p384.d.ts.map +1 -1
- package/p384.js +11 -13
- package/p384.js.map +1 -1
- package/p521.d.ts +1 -1
- package/p521.d.ts.map +1 -1
- package/p521.js +23 -19
- package/p521.js.map +1 -1
- package/package.json +5 -8
- package/secp256k1.js +1 -1
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +83 -61
- package/src/abstract/edwards.ts +49 -24
- package/src/abstract/hash-to-curve.ts +4 -3
- package/src/abstract/modular.ts +1 -1
- package/src/abstract/utils.ts +2 -2
- package/src/abstract/weierstrass.ts +36 -23
- package/src/bls12-381.ts +252 -171
- package/src/ed25519.ts +23 -9
- package/src/ed448.ts +18 -17
- package/src/p256.ts +15 -19
- package/src/p384.ts +17 -21
- package/src/p521.ts +34 -22
- package/src/secp256k1.ts +1 -1
- package/bn.d.ts.map +0 -1
- package/bn.js.map +0 -1
- package/esm/bn.js.map +0 -1
- /package/src/{bn.ts → bn254.ts} +0 -0
package/src/bls12-381.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
//
|
|
8
8
|
// The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
|
|
9
9
|
// Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
|
|
10
|
-
// [pairing-curves-
|
|
10
|
+
// [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
|
11
11
|
// [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
|
|
12
12
|
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12).
|
|
13
13
|
//
|
|
@@ -27,24 +27,6 @@
|
|
|
27
27
|
// - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
|
|
28
28
|
// Filecoin uses little endian byte arrays for private keys -
|
|
29
29
|
// so ensure to reverse byte order if you'll use it with FIL.
|
|
30
|
-
//
|
|
31
|
-
// ### Resources
|
|
32
|
-
// - [BLS12-381 for the rest of us](https://hackmd.io/@benjaminion/bls12-381)
|
|
33
|
-
// - [Key concepts of pairings](https://medium.com/@alonmuroch_65570/bls-signatures-part-2-key-concepts-of-pairings-27a8a9533d0c)
|
|
34
|
-
// - Pairing over bls12-381:
|
|
35
|
-
// [part 1](https://research.nccgroup.com/2020/07/06/pairing-over-bls12-381-part-1-fields/),
|
|
36
|
-
// [part 2](https://research.nccgroup.com/2020/07/13/pairing-over-bls12-381-part-2-curves/),
|
|
37
|
-
// [part 3](https://research.nccgroup.com/2020/08/13/pairing-over-bls12-381-part-3-pairing/)
|
|
38
|
-
// - [Estimating the bit security of pairing-friendly curves](https://research.nccgroup.com/2022/02/03/estimating-the-bit-security-of-pairing-friendly-curves/)
|
|
39
|
-
//
|
|
40
|
-
// ### Differences from @noble/bls12-381 1.4
|
|
41
|
-
// - PointG1 -> G1.Point
|
|
42
|
-
// - PointG2 -> G2.Point
|
|
43
|
-
// - PointG2.fromSignature -> Signature.decode
|
|
44
|
-
// - PointG2.toSignature -> Signature.encode
|
|
45
|
-
// - Fixed Fp2 ORDER
|
|
46
|
-
// - Points now have only two coordinates
|
|
47
|
-
|
|
48
30
|
import { sha256 } from '@noble/hashes/sha256';
|
|
49
31
|
import { randomBytes } from '@noble/hashes/utils';
|
|
50
32
|
import { bls, CurveFn } from './abstract/bls.js';
|
|
@@ -59,6 +41,7 @@ import {
|
|
|
59
41
|
bitGet,
|
|
60
42
|
Hex,
|
|
61
43
|
bitMask,
|
|
44
|
+
bytesToHex,
|
|
62
45
|
} from './abstract/utils.js';
|
|
63
46
|
// Types
|
|
64
47
|
import {
|
|
@@ -69,16 +52,23 @@ import {
|
|
|
69
52
|
} from './abstract/weierstrass.js';
|
|
70
53
|
import { isogenyMap } from './abstract/hash-to-curve.js';
|
|
71
54
|
|
|
55
|
+
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
56
|
+
// prettier-ignore
|
|
57
|
+
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
|
|
58
|
+
// prettier-ignore
|
|
59
|
+
const _8n = BigInt(8), _16n = BigInt(16);
|
|
60
|
+
|
|
72
61
|
// CURVE FIELDS
|
|
73
62
|
// Finite field over p.
|
|
74
|
-
const Fp =
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
63
|
+
const Fp = mod.Field(
|
|
64
|
+
BigInt(
|
|
65
|
+
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
|
|
66
|
+
)
|
|
67
|
+
);
|
|
78
68
|
type Fp = bigint;
|
|
79
69
|
// Finite field over r.
|
|
80
70
|
// This particular field is not used anywhere in bls12-381, but it is still useful.
|
|
81
|
-
const Fr = mod.Field(
|
|
71
|
+
const Fr = mod.Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
|
|
82
72
|
|
|
83
73
|
// Fp₂ over complex plane
|
|
84
74
|
type BigintTuple = [bigint, bigint];
|
|
@@ -121,8 +111,9 @@ type Fp2Utils = {
|
|
|
121
111
|
// h2q
|
|
122
112
|
// NOTE: ORDER was wrong!
|
|
123
113
|
const FP2_ORDER =
|
|
124
|
-
|
|
125
|
-
|
|
114
|
+
BigInt(
|
|
115
|
+
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
|
|
116
|
+
) ** _2n;
|
|
126
117
|
|
|
127
118
|
const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|
128
119
|
ORDER: FP2_ORDER,
|
|
@@ -175,7 +166,7 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|
|
175
166
|
// https://github.com/zkcrypto/bls12_381/blob/080eaa74ec0e394377caa1ba302c8c121df08b07/src/fp2.rs#L250
|
|
176
167
|
// https://github.com/supranational/blst/blob/aae0c7d70b799ac269ff5edf29d8191dbd357876/src/exp2.c#L1
|
|
177
168
|
// Inspired by https://github.com/dalek-cryptography/curve25519-dalek/blob/17698df9d4c834204f83a3574143abacb4fc81a5/src/field.rs#L99
|
|
178
|
-
const candidateSqrt = Fp2.pow(num, (Fp2.ORDER +
|
|
169
|
+
const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + _8n) / _16n);
|
|
179
170
|
const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this);
|
|
180
171
|
const R = FP2_ROOTS_OF_UNITY;
|
|
181
172
|
const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check));
|
|
@@ -193,10 +184,10 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|
|
193
184
|
// Same as sgn0_fp2 in draft-irtf-cfrg-hash-to-curve-16
|
|
194
185
|
isOdd: (x: Fp2) => {
|
|
195
186
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
196
|
-
const sign_0 = x0 %
|
|
197
|
-
const zero_0 = x0 ===
|
|
198
|
-
const sign_1 = x1 %
|
|
199
|
-
return BigInt(sign_0 || (zero_0 && sign_1)) ==
|
|
187
|
+
const sign_0 = x0 % _2n;
|
|
188
|
+
const zero_0 = x0 === _0n;
|
|
189
|
+
const sign_1 = x1 % _2n;
|
|
190
|
+
return BigInt(sign_0 || (zero_0 && sign_1)) == _1n;
|
|
200
191
|
},
|
|
201
192
|
// Bytes util
|
|
202
193
|
fromBytes(b: Uint8Array): Fp2 {
|
|
@@ -216,8 +207,8 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|
|
216
207
|
// multiply by u + 1
|
|
217
208
|
mulByNonresidue: ({ c0, c1 }) => ({ c0: Fp.sub(c0, c1), c1: Fp.add(c0, c1) }),
|
|
218
209
|
multiplyByB: ({ c0, c1 }) => {
|
|
219
|
-
let t0 = Fp.mul(c0,
|
|
220
|
-
let t1 = Fp.mul(c1,
|
|
210
|
+
let t0 = Fp.mul(c0, _4n); // 4 * c0
|
|
211
|
+
let t1 = Fp.mul(c1, _4n); // 4 * c1
|
|
221
212
|
// (T0-T1) + (T0+T1)*i
|
|
222
213
|
return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) };
|
|
223
214
|
},
|
|
@@ -234,33 +225,36 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|
|
234
225
|
// Finite extension field over irreducible polynominal.
|
|
235
226
|
// Fp(u) / (u² - β) where β = -1
|
|
236
227
|
const FP2_FROBENIUS_COEFFICIENTS = [
|
|
237
|
-
|
|
238
|
-
|
|
228
|
+
BigInt('0x1'),
|
|
229
|
+
BigInt(
|
|
230
|
+
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
|
|
231
|
+
),
|
|
239
232
|
].map((item) => Fp.create(item));
|
|
240
233
|
|
|
241
234
|
// For Fp2 roots of unity.
|
|
242
|
-
const rv1 =
|
|
243
|
-
|
|
235
|
+
const rv1 = BigInt(
|
|
236
|
+
'0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
|
|
237
|
+
);
|
|
244
238
|
// const ev1 =
|
|
245
|
-
//
|
|
239
|
+
// BigInt('0x699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90');
|
|
246
240
|
// const ev2 =
|
|
247
|
-
//
|
|
241
|
+
// BigInt('0x8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5');
|
|
248
242
|
// const ev3 =
|
|
249
|
-
//
|
|
243
|
+
// BigInt('0xab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17');
|
|
250
244
|
// const ev4 =
|
|
251
|
-
//
|
|
245
|
+
// BigInt('0xaa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1');
|
|
252
246
|
|
|
253
247
|
// Eighth roots of unity, used for computing square roots in Fp2.
|
|
254
248
|
// To verify or re-calculate:
|
|
255
249
|
// Array(8).fill(new Fp2([1n, 1n])).map((fp2, k) => fp2.pow(Fp2.ORDER * BigInt(k) / 8n))
|
|
256
250
|
const FP2_ROOTS_OF_UNITY = [
|
|
257
|
-
[
|
|
251
|
+
[_1n, _0n],
|
|
258
252
|
[rv1, -rv1],
|
|
259
|
-
[
|
|
253
|
+
[_0n, _1n],
|
|
260
254
|
[rv1, rv1],
|
|
261
|
-
[-
|
|
255
|
+
[-_1n, _0n],
|
|
262
256
|
[-rv1, rv1],
|
|
263
|
-
[
|
|
257
|
+
[_0n, -_1n],
|
|
264
258
|
[-rv1, -rv1],
|
|
265
259
|
].map((pair) => Fp2.fromBigTuple(pair));
|
|
266
260
|
// eta values, used for computing sqrt(g(X1(t)))
|
|
@@ -314,8 +308,8 @@ const Fp6Multiply = ({ c0, c1, c2 }: Fp6, rhs: Fp6 | bigint) => {
|
|
|
314
308
|
};
|
|
315
309
|
const Fp6Square = ({ c0, c1, c2 }: Fp6) => {
|
|
316
310
|
let t0 = Fp2.sqr(c0); // c0²
|
|
317
|
-
let t1 = Fp2.mul(Fp2.mul(c0, c1),
|
|
318
|
-
let t3 = Fp2.mul(Fp2.mul(c1, c2),
|
|
311
|
+
let t1 = Fp2.mul(Fp2.mul(c0, c1), _2n); // 2 * c0 * c1
|
|
312
|
+
let t3 = Fp2.mul(Fp2.mul(c1, c2), _2n); // 2 * c1 * c2
|
|
319
313
|
let t4 = Fp2.sqr(c2); // c2²
|
|
320
314
|
return {
|
|
321
315
|
c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0
|
|
@@ -440,46 +434,64 @@ const Fp6: mod.IField<Fp6> & Fp6Utils = {
|
|
|
440
434
|
};
|
|
441
435
|
|
|
442
436
|
const FP6_FROBENIUS_COEFFICIENTS_1 = [
|
|
443
|
-
[
|
|
437
|
+
[BigInt('0x1'), BigInt('0x0')],
|
|
444
438
|
[
|
|
445
|
-
|
|
446
|
-
|
|
439
|
+
BigInt('0x0'),
|
|
440
|
+
BigInt(
|
|
441
|
+
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
442
|
+
),
|
|
447
443
|
],
|
|
448
444
|
[
|
|
449
|
-
|
|
450
|
-
|
|
445
|
+
BigInt(
|
|
446
|
+
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
447
|
+
),
|
|
448
|
+
BigInt('0x0'),
|
|
451
449
|
],
|
|
452
|
-
[
|
|
450
|
+
[BigInt('0x0'), BigInt('0x1')],
|
|
453
451
|
[
|
|
454
|
-
|
|
455
|
-
|
|
452
|
+
BigInt(
|
|
453
|
+
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
454
|
+
),
|
|
455
|
+
BigInt('0x0'),
|
|
456
456
|
],
|
|
457
457
|
[
|
|
458
|
-
|
|
459
|
-
|
|
458
|
+
BigInt('0x0'),
|
|
459
|
+
BigInt(
|
|
460
|
+
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
461
|
+
),
|
|
460
462
|
],
|
|
461
463
|
].map((pair) => Fp2.fromBigTuple(pair));
|
|
462
464
|
const FP6_FROBENIUS_COEFFICIENTS_2 = [
|
|
463
|
-
[
|
|
465
|
+
[BigInt('0x1'), BigInt('0x0')],
|
|
464
466
|
[
|
|
465
|
-
|
|
466
|
-
|
|
467
|
+
BigInt(
|
|
468
|
+
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
|
|
469
|
+
),
|
|
470
|
+
BigInt('0x0'),
|
|
467
471
|
],
|
|
468
472
|
[
|
|
469
|
-
|
|
470
|
-
|
|
473
|
+
BigInt(
|
|
474
|
+
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
475
|
+
),
|
|
476
|
+
BigInt('0x0'),
|
|
471
477
|
],
|
|
472
478
|
[
|
|
473
|
-
|
|
474
|
-
|
|
479
|
+
BigInt(
|
|
480
|
+
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
|
|
481
|
+
),
|
|
482
|
+
BigInt('0x0'),
|
|
475
483
|
],
|
|
476
484
|
[
|
|
477
|
-
|
|
478
|
-
|
|
485
|
+
BigInt(
|
|
486
|
+
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
487
|
+
),
|
|
488
|
+
BigInt('0x0'),
|
|
479
489
|
],
|
|
480
490
|
[
|
|
481
|
-
|
|
482
|
-
|
|
491
|
+
BigInt(
|
|
492
|
+
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
|
|
493
|
+
),
|
|
494
|
+
BigInt('0x0'),
|
|
483
495
|
],
|
|
484
496
|
].map((pair) => Fp2.fromBigTuple(pair));
|
|
485
497
|
|
|
@@ -488,7 +500,7 @@ const FP6_FROBENIUS_COEFFICIENTS_2 = [
|
|
|
488
500
|
// Fp₆(w) / (w² - γ) where γ = v
|
|
489
501
|
type Fp12 = { c0: Fp6; c1: Fp6 };
|
|
490
502
|
// The BLS parameter x for BLS12-381
|
|
491
|
-
const BLS_X =
|
|
503
|
+
const BLS_X = BigInt('0xd201000000010000');
|
|
492
504
|
const BLS_X_LEN = bitLen(BLS_X);
|
|
493
505
|
|
|
494
506
|
// prettier-ignore
|
|
@@ -646,14 +658,14 @@ const Fp12: mod.IField<Fp12> & Fp12Utils = {
|
|
|
646
658
|
let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
|
|
647
659
|
return {
|
|
648
660
|
c0: Fp6.create({
|
|
649
|
-
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0),
|
|
650
|
-
c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1),
|
|
651
|
-
c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2),
|
|
661
|
+
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
|
|
662
|
+
c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1) + T5
|
|
663
|
+
c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
|
|
652
664
|
}), // 2 * (T7 - c0c2) + T7
|
|
653
665
|
c1: Fp6.create({
|
|
654
|
-
c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0),
|
|
655
|
-
c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1),
|
|
656
|
-
c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2),
|
|
666
|
+
c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
|
|
667
|
+
c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
|
|
668
|
+
c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
|
|
657
669
|
}),
|
|
658
670
|
}; // 2 * (T6 + c1c2) + T6
|
|
659
671
|
},
|
|
@@ -688,50 +700,84 @@ const Fp12: mod.IField<Fp12> & Fp12Utils = {
|
|
|
688
700
|
},
|
|
689
701
|
};
|
|
690
702
|
const FP12_FROBENIUS_COEFFICIENTS = [
|
|
691
|
-
[
|
|
703
|
+
[BigInt('0x1'), BigInt('0x0')],
|
|
692
704
|
[
|
|
693
|
-
|
|
694
|
-
|
|
705
|
+
BigInt(
|
|
706
|
+
'0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
|
|
707
|
+
),
|
|
708
|
+
BigInt(
|
|
709
|
+
'0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
|
|
710
|
+
),
|
|
695
711
|
],
|
|
696
712
|
[
|
|
697
|
-
|
|
698
|
-
|
|
713
|
+
BigInt(
|
|
714
|
+
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
|
|
715
|
+
),
|
|
716
|
+
BigInt('0x0'),
|
|
699
717
|
],
|
|
700
718
|
[
|
|
701
|
-
|
|
702
|
-
|
|
719
|
+
BigInt(
|
|
720
|
+
'0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
|
|
721
|
+
),
|
|
722
|
+
BigInt(
|
|
723
|
+
'0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
|
|
724
|
+
),
|
|
703
725
|
],
|
|
704
726
|
[
|
|
705
|
-
|
|
706
|
-
|
|
727
|
+
BigInt(
|
|
728
|
+
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
729
|
+
),
|
|
730
|
+
BigInt('0x0'),
|
|
707
731
|
],
|
|
708
732
|
[
|
|
709
|
-
|
|
710
|
-
|
|
733
|
+
BigInt(
|
|
734
|
+
'0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
|
|
735
|
+
),
|
|
736
|
+
BigInt(
|
|
737
|
+
'0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
|
|
738
|
+
),
|
|
711
739
|
],
|
|
712
740
|
[
|
|
713
|
-
|
|
714
|
-
|
|
741
|
+
BigInt(
|
|
742
|
+
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
|
|
743
|
+
),
|
|
744
|
+
BigInt('0x0'),
|
|
715
745
|
],
|
|
716
746
|
[
|
|
717
|
-
|
|
718
|
-
|
|
747
|
+
BigInt(
|
|
748
|
+
'0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
|
|
749
|
+
),
|
|
750
|
+
BigInt(
|
|
751
|
+
'0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
|
|
752
|
+
),
|
|
719
753
|
],
|
|
720
754
|
[
|
|
721
|
-
|
|
722
|
-
|
|
755
|
+
BigInt(
|
|
756
|
+
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
757
|
+
),
|
|
758
|
+
BigInt('0x0'),
|
|
723
759
|
],
|
|
724
760
|
[
|
|
725
|
-
|
|
726
|
-
|
|
761
|
+
BigInt(
|
|
762
|
+
'0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
|
|
763
|
+
),
|
|
764
|
+
BigInt(
|
|
765
|
+
'0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
|
|
766
|
+
),
|
|
727
767
|
],
|
|
728
768
|
[
|
|
729
|
-
|
|
730
|
-
|
|
769
|
+
BigInt(
|
|
770
|
+
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
|
|
771
|
+
),
|
|
772
|
+
BigInt('0x0'),
|
|
731
773
|
],
|
|
732
774
|
[
|
|
733
|
-
|
|
734
|
-
|
|
775
|
+
BigInt(
|
|
776
|
+
'0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
|
|
777
|
+
),
|
|
778
|
+
BigInt(
|
|
779
|
+
'0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
|
|
780
|
+
),
|
|
735
781
|
],
|
|
736
782
|
].map((n) => Fp2.fromBigTuple(n));
|
|
737
783
|
// END OF CURVE FIELDS
|
|
@@ -887,19 +933,23 @@ const isogenyMapG1 = isogenyMap(
|
|
|
887
933
|
|
|
888
934
|
// SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
|
|
889
935
|
const G2_SWU = mapToCurveSimpleSWU(Fp2, {
|
|
890
|
-
A: Fp2.create({ c0: Fp.create(
|
|
891
|
-
B: Fp2.create({ c0: Fp.create(
|
|
892
|
-
Z: Fp2.create({ c0: Fp.create(-
|
|
936
|
+
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
|
|
937
|
+
B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
|
|
938
|
+
Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
|
|
893
939
|
});
|
|
894
940
|
// Optimized SWU Map - Fp to G1
|
|
895
941
|
const G1_SWU = mapToCurveSimpleSWU(Fp, {
|
|
896
942
|
A: Fp.create(
|
|
897
|
-
|
|
943
|
+
BigInt(
|
|
944
|
+
'0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d'
|
|
945
|
+
)
|
|
898
946
|
),
|
|
899
947
|
B: Fp.create(
|
|
900
|
-
|
|
948
|
+
BigInt(
|
|
949
|
+
'0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0'
|
|
950
|
+
)
|
|
901
951
|
),
|
|
902
|
-
Z: Fp.create(
|
|
952
|
+
Z: Fp.create(BigInt(11)),
|
|
903
953
|
});
|
|
904
954
|
|
|
905
955
|
// Endomorphisms (for fast cofactor clearing)
|
|
@@ -922,8 +972,9 @@ function G2psi(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
|
|
|
922
972
|
}
|
|
923
973
|
// Ψ²(P) endomorphism
|
|
924
974
|
// 1 / F2(2)^((p-1)/3) in GF(p²)
|
|
925
|
-
const PSI2_C1 =
|
|
926
|
-
|
|
975
|
+
const PSI2_C1 = BigInt(
|
|
976
|
+
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
977
|
+
);
|
|
927
978
|
|
|
928
979
|
function psi2(x: Fp2, y: Fp2): [Fp2, Fp2] {
|
|
929
980
|
return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)];
|
|
@@ -974,7 +1025,23 @@ const C_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
|
|
|
974
1025
|
const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
|
|
975
1026
|
const S_BIT_POS = Fp.BITS + 2; // S_bit, sign bit for serialization flag
|
|
976
1027
|
// Compressed point of infinity
|
|
977
|
-
const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(
|
|
1028
|
+
const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(_0n, I_BIT_POS, true), S_BIT_POS, true)); // set compressed & point-at-infinity bits
|
|
1029
|
+
|
|
1030
|
+
function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
|
|
1031
|
+
// NOTE: by some reasons it was missed in bls12-381, looks like bug
|
|
1032
|
+
point.assertValidity();
|
|
1033
|
+
const len = Fp.BYTES;
|
|
1034
|
+
if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
|
|
1035
|
+
return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
|
1036
|
+
const { x, y } = point.toAffine();
|
|
1037
|
+
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
1038
|
+
const { re: y0, im: y1 } = Fp2.reim(y);
|
|
1039
|
+
const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
|
|
1040
|
+
const aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
|
|
1041
|
+
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
|
1042
|
+
const z2 = x0;
|
|
1043
|
+
return concatB(numberToBytesBE(z1, len), numberToBytesBE(z2, len));
|
|
1044
|
+
}
|
|
978
1045
|
|
|
979
1046
|
// To verify curve parameters, see pairing-friendly-curves spec:
|
|
980
1047
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09
|
|
@@ -988,26 +1055,30 @@ const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(0n, I_BIT_POS, true), S_BIT_POS
|
|
|
988
1055
|
// Here goes constants && point encoding format
|
|
989
1056
|
export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
990
1057
|
// Fields
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1058
|
+
fields: {
|
|
1059
|
+
Fp,
|
|
1060
|
+
Fp2,
|
|
1061
|
+
Fp6,
|
|
1062
|
+
Fp12,
|
|
1063
|
+
Fr,
|
|
1064
|
+
},
|
|
998
1065
|
// G1 is the order-q subgroup of E1(Fp) : y² = x³ + 4, #E1(Fp) = h1q, where
|
|
999
1066
|
// characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
|
|
1000
1067
|
G1: {
|
|
1001
1068
|
Fp,
|
|
1002
1069
|
// cofactor; (z - 1)²/3
|
|
1003
|
-
h:
|
|
1070
|
+
h: BigInt('0x396c8c005555e1568c00aaab0000aaab'),
|
|
1004
1071
|
// generator's coordinates
|
|
1005
1072
|
// x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
|
|
1006
1073
|
// y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
|
|
1007
|
-
Gx:
|
|
1008
|
-
|
|
1074
|
+
Gx: BigInt(
|
|
1075
|
+
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
|
1076
|
+
),
|
|
1077
|
+
Gy: BigInt(
|
|
1078
|
+
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
|
1079
|
+
),
|
|
1009
1080
|
a: Fp.ZERO,
|
|
1010
|
-
b:
|
|
1081
|
+
b: _4n,
|
|
1011
1082
|
htfDefaults: { ...htfDefaults, m: 1 },
|
|
1012
1083
|
wrapPrivateKey: true,
|
|
1013
1084
|
allowInfinityPoint: true,
|
|
@@ -1017,18 +1088,19 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1017
1088
|
// https://eprint.iacr.org/2021/1130.pdf
|
|
1018
1089
|
isTorsionFree: (c, point): boolean => {
|
|
1019
1090
|
// φ endomorphism
|
|
1020
|
-
const cubicRootOfUnityModP =
|
|
1021
|
-
|
|
1091
|
+
const cubicRootOfUnityModP = BigInt(
|
|
1092
|
+
'0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
1093
|
+
);
|
|
1022
1094
|
const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
|
|
1023
1095
|
|
|
1024
1096
|
// todo: unroll
|
|
1025
|
-
const xP = point.multiplyUnsafe(bls12_381.
|
|
1026
|
-
const u2P = xP.multiplyUnsafe(bls12_381.
|
|
1097
|
+
const xP = point.multiplyUnsafe(bls12_381.params.x).negate(); // [x]P
|
|
1098
|
+
const u2P = xP.multiplyUnsafe(bls12_381.params.x); // [u2]P
|
|
1027
1099
|
return u2P.equals(phi);
|
|
1028
1100
|
|
|
1029
1101
|
// https://eprint.iacr.org/2019/814.pdf
|
|
1030
1102
|
// (z² − 1)/3
|
|
1031
|
-
// const c1 =
|
|
1103
|
+
// const c1 = BigInt('0x396c8c005555e1560000000055555555');
|
|
1032
1104
|
// const P = this;
|
|
1033
1105
|
// const S = P.sigma();
|
|
1034
1106
|
// const Q = S.double();
|
|
@@ -1042,31 +1114,33 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1042
1114
|
// https://eprint.iacr.org/2019/403
|
|
1043
1115
|
clearCofactor: (c, point) => {
|
|
1044
1116
|
// return this.multiplyUnsafe(CURVE.h);
|
|
1045
|
-
return point.multiplyUnsafe(bls12_381.
|
|
1117
|
+
return point.multiplyUnsafe(bls12_381.params.x).add(point); // x*P + P
|
|
1046
1118
|
},
|
|
1047
1119
|
mapToCurve: (scalars: bigint[]) => {
|
|
1048
1120
|
const { x, y } = G1_SWU(Fp.create(scalars[0]));
|
|
1049
1121
|
return isogenyMapG1(x, y);
|
|
1050
1122
|
},
|
|
1051
1123
|
fromBytes: (bytes: Uint8Array): AffinePoint<Fp> => {
|
|
1124
|
+
bytes = bytes.slice();
|
|
1052
1125
|
if (bytes.length === 48) {
|
|
1126
|
+
// TODO: Fp.bytes
|
|
1053
1127
|
const P = Fp.ORDER;
|
|
1054
1128
|
const compressedValue = bytesToNumberBE(bytes);
|
|
1055
1129
|
const bflag = bitGet(compressedValue, I_BIT_POS);
|
|
1056
1130
|
// Zero
|
|
1057
|
-
if (bflag ===
|
|
1131
|
+
if (bflag === _1n) return { x: _0n, y: _0n };
|
|
1058
1132
|
const x = Fp.create(compressedValue & Fp.MASK);
|
|
1059
|
-
const right = Fp.add(Fp.pow(x,
|
|
1133
|
+
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
|
|
1060
1134
|
let y = Fp.sqrt(right);
|
|
1061
1135
|
if (!y) throw new Error('Invalid compressed G1 point');
|
|
1062
1136
|
const aflag = bitGet(compressedValue, C_BIT_POS);
|
|
1063
|
-
if ((y *
|
|
1137
|
+
if ((y * _2n) / P !== aflag) y = Fp.neg(y);
|
|
1064
1138
|
return { x: Fp.create(x), y: Fp.create(y) };
|
|
1065
1139
|
} else if (bytes.length === 96) {
|
|
1066
1140
|
// Check if the infinity flag is set
|
|
1067
1141
|
if ((bytes[0] & (1 << 6)) !== 0) return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
|
|
1068
|
-
const x = bytesToNumberBE(bytes.
|
|
1069
|
-
const y = bytesToNumberBE(bytes.
|
|
1142
|
+
const x = bytesToNumberBE(bytes.subarray(0, Fp.BYTES));
|
|
1143
|
+
const y = bytesToNumberBE(bytes.subarray(Fp.BYTES));
|
|
1070
1144
|
return { x: Fp.create(x), y: Fp.create(y) };
|
|
1071
1145
|
} else {
|
|
1072
1146
|
throw new Error('Invalid point G1, expected 48/96 bytes');
|
|
@@ -1079,7 +1153,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1079
1153
|
if (isZero) return COMPRESSED_ZERO.slice();
|
|
1080
1154
|
const P = Fp.ORDER;
|
|
1081
1155
|
let num;
|
|
1082
|
-
num = bitSet(x, C_BIT_POS, Boolean((y *
|
|
1156
|
+
num = bitSet(x, C_BIT_POS, Boolean((y * _2n) / P)); // set aflag
|
|
1083
1157
|
num = bitSet(num, S_BIT_POS, true);
|
|
1084
1158
|
return numberToBytesBE(num, Fp.BYTES);
|
|
1085
1159
|
} else {
|
|
@@ -1100,21 +1174,33 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1100
1174
|
G2: {
|
|
1101
1175
|
Fp: Fp2,
|
|
1102
1176
|
// cofactor
|
|
1103
|
-
h:
|
|
1177
|
+
h: BigInt(
|
|
1178
|
+
'0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5'
|
|
1179
|
+
),
|
|
1104
1180
|
Gx: Fp2.fromBigTuple([
|
|
1105
|
-
|
|
1106
|
-
|
|
1181
|
+
BigInt(
|
|
1182
|
+
'0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8'
|
|
1183
|
+
),
|
|
1184
|
+
BigInt(
|
|
1185
|
+
'0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e'
|
|
1186
|
+
),
|
|
1107
1187
|
]),
|
|
1108
1188
|
// y =
|
|
1109
1189
|
// 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,
|
|
1110
1190
|
// 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
|
|
1111
1191
|
Gy: Fp2.fromBigTuple([
|
|
1112
|
-
|
|
1113
|
-
|
|
1192
|
+
BigInt(
|
|
1193
|
+
'0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801'
|
|
1194
|
+
),
|
|
1195
|
+
BigInt(
|
|
1196
|
+
'0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be'
|
|
1197
|
+
),
|
|
1114
1198
|
]),
|
|
1115
1199
|
a: Fp2.ZERO,
|
|
1116
|
-
b: Fp2.fromBigTuple([4n,
|
|
1117
|
-
hEff:
|
|
1200
|
+
b: Fp2.fromBigTuple([4n, _4n]),
|
|
1201
|
+
hEff: BigInt(
|
|
1202
|
+
'0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'
|
|
1203
|
+
),
|
|
1118
1204
|
htfDefaults: { ...htfDefaults },
|
|
1119
1205
|
wrapPrivateKey: true,
|
|
1120
1206
|
allowInfinityPoint: true,
|
|
@@ -1127,7 +1213,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1127
1213
|
// It returns false for shitty points.
|
|
1128
1214
|
// https://eprint.iacr.org/2021/1130.pdf
|
|
1129
1215
|
isTorsionFree: (c, P): boolean => {
|
|
1130
|
-
return P.multiplyUnsafe(bls12_381.
|
|
1216
|
+
return P.multiplyUnsafe(bls12_381.params.x).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
|
|
1131
1217
|
// Older version: https://eprint.iacr.org/2019/814.pdf
|
|
1132
1218
|
// Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
|
|
1133
1219
|
// return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
|
|
@@ -1137,7 +1223,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1137
1223
|
// https://eprint.iacr.org/2017/419.pdf
|
|
1138
1224
|
// prettier-ignore
|
|
1139
1225
|
clearCofactor: (c, P) => {
|
|
1140
|
-
const
|
|
1226
|
+
const x = bls12_381.params.x;
|
|
1141
1227
|
let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
|
|
1142
1228
|
let t2 = G2psi(c, P); // Ψ(P)
|
|
1143
1229
|
let t3 = P.double(); // 2P
|
|
@@ -1151,6 +1237,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1151
1237
|
return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
|
|
1152
1238
|
},
|
|
1153
1239
|
fromBytes: (bytes: Uint8Array): AffinePoint<Fp2> => {
|
|
1240
|
+
bytes = bytes.slice();
|
|
1154
1241
|
const m_byte = bytes[0] & 0xe0;
|
|
1155
1242
|
if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
|
|
1156
1243
|
throw new Error('Invalid encoding flag: ' + m_byte);
|
|
@@ -1161,7 +1248,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1161
1248
|
const L = Fp.BYTES;
|
|
1162
1249
|
const slc = (b: Uint8Array, from: number, to?: number) => bytesToNumberBE(b.slice(from, to));
|
|
1163
1250
|
if (bytes.length === 96 && bitC) {
|
|
1164
|
-
const
|
|
1251
|
+
const b = bls12_381.params.G2b;
|
|
1165
1252
|
const P = Fp.ORDER;
|
|
1166
1253
|
|
|
1167
1254
|
bytes[0] = bytes[0] & 0x1f; // clear flags
|
|
@@ -1175,9 +1262,9 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1175
1262
|
const x_1 = slc(bytes, 0, L);
|
|
1176
1263
|
const x_0 = slc(bytes, L, 2 * L);
|
|
1177
1264
|
const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
|
|
1178
|
-
const right = Fp2.add(Fp2.pow(x,
|
|
1265
|
+
const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
|
|
1179
1266
|
let y = Fp2.sqrt(right);
|
|
1180
|
-
const Y_bit = y.c1 ===
|
|
1267
|
+
const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
|
|
1181
1268
|
y = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y);
|
|
1182
1269
|
return { x, y };
|
|
1183
1270
|
} else if (bytes.length === 192 && !bitC) {
|
|
@@ -1195,31 +1282,31 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1195
1282
|
}
|
|
1196
1283
|
},
|
|
1197
1284
|
toBytes: (c, point, isCompressed) => {
|
|
1285
|
+
const { BYTES: len, ORDER: P } = Fp;
|
|
1198
1286
|
const isZero = point.equals(c.ZERO);
|
|
1199
1287
|
const { x, y } = point.toAffine();
|
|
1200
1288
|
if (isCompressed) {
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
const flag = Boolean(y.c1 === 0n ? (y.c0 * 2n) / P : (y.c1 * 2n) / P);
|
|
1289
|
+
if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
|
1290
|
+
const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
|
|
1204
1291
|
// set compressed & sign bits (looks like different offsets than for G1/Fp?)
|
|
1205
1292
|
let x_1 = bitSet(x.c1, C_BIT_POS, flag);
|
|
1206
1293
|
x_1 = bitSet(x_1, S_BIT_POS, true);
|
|
1207
|
-
return concatB(numberToBytesBE(x_1,
|
|
1294
|
+
return concatB(numberToBytesBE(x_1, len), numberToBytesBE(x.c0, len));
|
|
1208
1295
|
} else {
|
|
1209
|
-
if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 *
|
|
1296
|
+
if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 * len - 1)); // bytes[0] |= 1 << 6;
|
|
1210
1297
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
1211
1298
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
|
1212
1299
|
return concatB(
|
|
1213
|
-
numberToBytesBE(x1,
|
|
1214
|
-
numberToBytesBE(x0,
|
|
1215
|
-
numberToBytesBE(y1,
|
|
1216
|
-
numberToBytesBE(y0,
|
|
1300
|
+
numberToBytesBE(x1, len),
|
|
1301
|
+
numberToBytesBE(x0, len),
|
|
1302
|
+
numberToBytesBE(y1, len),
|
|
1303
|
+
numberToBytesBE(y0, len)
|
|
1217
1304
|
);
|
|
1218
1305
|
}
|
|
1219
1306
|
},
|
|
1220
1307
|
Signature: {
|
|
1221
1308
|
// TODO: Optimize, it's very slow because of sqrt.
|
|
1222
|
-
|
|
1309
|
+
fromHex(hex: Hex): ProjPointType<Fp2> {
|
|
1223
1310
|
hex = ensureBytes('signatureHex', hex);
|
|
1224
1311
|
const P = Fp.ORDER;
|
|
1225
1312
|
const half = hex.length / 2;
|
|
@@ -1229,12 +1316,12 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1229
1316
|
const z2 = bytesToNumberBE(hex.slice(half));
|
|
1230
1317
|
// Indicates the infinity point
|
|
1231
1318
|
const bflag1 = bitGet(z1, I_BIT_POS);
|
|
1232
|
-
if (bflag1 ===
|
|
1319
|
+
if (bflag1 === _1n) return bls12_381.G2.ProjectivePoint.ZERO;
|
|
1233
1320
|
|
|
1234
1321
|
const x1 = Fp.create(z1 & Fp.MASK);
|
|
1235
1322
|
const x2 = Fp.create(z2);
|
|
1236
1323
|
const x = Fp2.create({ c0: x2, c1: x1 });
|
|
1237
|
-
const y2 = Fp2.add(Fp2.pow(x,
|
|
1324
|
+
const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.params.G2b); // y² = x³ + 4
|
|
1238
1325
|
// The slow part
|
|
1239
1326
|
let y = Fp2.sqrt(y2);
|
|
1240
1327
|
if (!y) throw new Error('Failed to find a square root');
|
|
@@ -1243,31 +1330,25 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1243
1330
|
// If y1 happens to be zero, then use the bit of y0
|
|
1244
1331
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
|
1245
1332
|
const aflag1 = bitGet(z1, 381);
|
|
1246
|
-
const isGreater = y1 >
|
|
1247
|
-
const isZero = y1 ===
|
|
1333
|
+
const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
|
|
1334
|
+
const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
|
|
1248
1335
|
if (isGreater || isZero) y = Fp2.neg(y);
|
|
1249
1336
|
const point = bls12_381.G2.ProjectivePoint.fromAffine({ x, y });
|
|
1250
1337
|
point.assertValidity();
|
|
1251
1338
|
return point;
|
|
1252
1339
|
},
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
const a = point.toAffine();
|
|
1259
|
-
const { re: x0, im: x1 } = Fp2.reim(a.x);
|
|
1260
|
-
const { re: y0, im: y1 } = Fp2.reim(a.y);
|
|
1261
|
-
const tmp = y1 > 0n ? y1 * 2n : y0 * 2n;
|
|
1262
|
-
const aflag1 = Boolean((tmp / Fp.ORDER) & 1n);
|
|
1263
|
-
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
|
1264
|
-
const z2 = x0;
|
|
1265
|
-
return concatB(numberToBytesBE(z1, Fp.BYTES), numberToBytesBE(z2, Fp.BYTES));
|
|
1340
|
+
toRawBytes(point: ProjPointType<Fp2>) {
|
|
1341
|
+
return signatureG2ToRawBytes(point);
|
|
1342
|
+
},
|
|
1343
|
+
toHex(point: ProjPointType<Fp2>) {
|
|
1344
|
+
return bytesToHex(signatureG2ToRawBytes(point));
|
|
1266
1345
|
},
|
|
1267
1346
|
},
|
|
1268
1347
|
},
|
|
1269
|
-
|
|
1270
|
-
|
|
1348
|
+
params: {
|
|
1349
|
+
x: BLS_X, // The BLS parameter x for BLS12-381
|
|
1350
|
+
r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
|
|
1351
|
+
},
|
|
1271
1352
|
htfDefaults,
|
|
1272
1353
|
hash: sha256,
|
|
1273
1354
|
randomBytes,
|