@noble/curves 1.4.2 → 1.5.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 +135 -123
- package/_shortw_utils.d.ts.map +1 -1
- package/abstract/bls.d.ts +37 -34
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +167 -115
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +2 -1
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +22 -7
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +11 -0
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +79 -75
- package/abstract/edwards.js.map +1 -1
- package/abstract/modular.d.ts +4 -0
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +13 -2
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +4 -9
- package/abstract/montgomery.js.map +1 -1
- package/abstract/tower.d.ts +106 -0
- package/abstract/tower.d.ts.map +1 -0
- package/abstract/tower.js +497 -0
- package/abstract/tower.js.map +1 -0
- package/abstract/utils.d.ts +17 -0
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +50 -1
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +7 -0
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +88 -72
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +1 -65
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +48 -575
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +10 -6
- package/bn254.d.ts.map +1 -1
- package/bn254.js +207 -10
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +7 -4
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +3 -0
- package/ed25519.js.map +1 -1
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/abstract/bls.d.ts +37 -34
- package/esm/abstract/bls.d.ts.map +1 -1
- package/esm/abstract/bls.js +168 -116
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +2 -1
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +22 -7
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +11 -0
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +80 -76
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/modular.d.ts +4 -0
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +12 -2
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +5 -10
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/tower.d.ts +106 -0
- package/esm/abstract/tower.d.ts.map +1 -0
- package/esm/abstract/tower.js +493 -0
- package/esm/abstract/tower.js.map +1 -0
- package/esm/abstract/utils.d.ts +17 -0
- package/esm/abstract/utils.d.ts.map +1 -1
- package/esm/abstract/utils.js +44 -0
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +7 -0
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +89 -73
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts +1 -65
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +50 -577
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.d.ts +10 -6
- package/esm/bn254.d.ts.map +1 -1
- package/esm/bn254.js +206 -9
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.d.ts +7 -4
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +3 -0
- package/esm/ed25519.js.map +1 -1
- package/esm/p256.d.ts.map +1 -1
- package/esm/p384.d.ts.map +1 -1
- package/esm/p521.d.ts.map +1 -1
- package/esm/secp256k1.d.ts +6 -0
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +17 -13
- package/esm/secp256k1.js.map +1 -1
- package/p256.d.ts.map +1 -1
- package/p384.d.ts.map +1 -1
- package/p521.d.ts.map +1 -1
- package/package.json +2 -1
- package/secp256k1.d.ts +6 -0
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +16 -12
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +222 -168
- package/src/abstract/curve.ts +23 -7
- package/src/abstract/edwards.ts +81 -68
- package/src/abstract/modular.ts +13 -3
- package/src/abstract/montgomery.ts +11 -10
- package/src/abstract/tower.ts +604 -0
- package/src/abstract/utils.ts +49 -0
- package/src/abstract/weierstrass.ts +85 -68
- package/src/bls12-381.ts +53 -707
- package/src/bn254.ts +224 -9
- package/src/ed25519.ts +5 -2
- package/src/secp256k1.ts +24 -12
package/src/bls12-381.ts
CHANGED
|
@@ -6,7 +6,6 @@ import * as mod from './abstract/modular.js';
|
|
|
6
6
|
import {
|
|
7
7
|
bitGet,
|
|
8
8
|
bitLen,
|
|
9
|
-
bitMask,
|
|
10
9
|
bytesToHex,
|
|
11
10
|
bytesToNumberBE,
|
|
12
11
|
concatBytes as concatB,
|
|
@@ -16,12 +15,9 @@ import {
|
|
|
16
15
|
} from './abstract/utils.js';
|
|
17
16
|
// Types
|
|
18
17
|
import { isogenyMap } from './abstract/hash-to-curve.js';
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
ProjConstructor,
|
|
23
|
-
ProjPointType,
|
|
24
|
-
} from './abstract/weierstrass.js';
|
|
18
|
+
import { AffinePoint, mapToCurveSimpleSWU, ProjPointType } from './abstract/weierstrass.js';
|
|
19
|
+
import { tower12, psiFrobenius } from './abstract/tower.js';
|
|
20
|
+
import type { Fp, Fp2, Fp6, Fp12 } from './abstract/tower.js';
|
|
25
21
|
|
|
26
22
|
/*
|
|
27
23
|
bls12-381 is pairing-friendly Barreto-Lynn-Scott elliptic curve construction allowing to:
|
|
@@ -59,603 +55,56 @@ bls12-381 is pairing-friendly Barreto-Lynn-Scott elliptic curve construction all
|
|
|
59
55
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
60
56
|
// prettier-ignore
|
|
61
57
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
|
|
62
|
-
// prettier-ignore
|
|
63
|
-
const _8n = BigInt(8), _16n = BigInt(16);
|
|
64
|
-
|
|
65
|
-
// CURVE FIELDS
|
|
66
|
-
// Finite field over p.
|
|
67
|
-
const Fp_raw = BigInt(
|
|
68
|
-
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
|
|
69
|
-
);
|
|
70
|
-
const Fp = mod.Field(Fp_raw);
|
|
71
|
-
type Fp = bigint;
|
|
72
|
-
// Finite field over r.
|
|
73
|
-
// This particular field is not used anywhere in bls12-381, but it is still useful.
|
|
74
|
-
const Fr = mod.Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
|
|
75
58
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
c0: Fp.sub(c0, r0),
|
|
85
|
-
c1: Fp.sub(c1, r1),
|
|
86
|
-
});
|
|
87
|
-
const Fp2Multiply = ({ c0, c1 }: Fp2, rhs: Fp2) => {
|
|
88
|
-
if (typeof rhs === 'bigint') return { c0: Fp.mul(c0, rhs), c1: Fp.mul(c1, rhs) };
|
|
89
|
-
// (a+bi)(c+di) = (ac−bd) + (ad+bc)i
|
|
90
|
-
const { c0: r0, c1: r1 } = rhs;
|
|
91
|
-
let t1 = Fp.mul(c0, r0); // c0 * o0
|
|
92
|
-
let t2 = Fp.mul(c1, r1); // c1 * o1
|
|
93
|
-
// (T1 - T2) + ((c0 + c1) * (r0 + r1) - (T1 + T2))*i
|
|
94
|
-
const o0 = Fp.sub(t1, t2);
|
|
95
|
-
const o1 = Fp.sub(Fp.mul(Fp.add(c0, c1), Fp.add(r0, r1)), Fp.add(t1, t2));
|
|
96
|
-
return { c0: o0, c1: o1 };
|
|
97
|
-
};
|
|
98
|
-
const Fp2Square = ({ c0, c1 }: Fp2) => {
|
|
99
|
-
const a = Fp.add(c0, c1);
|
|
100
|
-
const b = Fp.sub(c0, c1);
|
|
101
|
-
const c = Fp.add(c0, c0);
|
|
102
|
-
return { c0: Fp.mul(a, b), c1: Fp.mul(c, c1) };
|
|
103
|
-
};
|
|
104
|
-
type Fp2Utils = {
|
|
105
|
-
fromBigTuple: (tuple: BigintTuple | bigint[]) => Fp2;
|
|
106
|
-
reim: (num: Fp2) => { re: bigint; im: bigint };
|
|
107
|
-
mulByNonresidue: (num: Fp2) => Fp2;
|
|
108
|
-
multiplyByB: (num: Fp2) => Fp2;
|
|
109
|
-
frobeniusMap(num: Fp2, power: number): Fp2;
|
|
110
|
-
};
|
|
111
|
-
// G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
|
|
112
|
-
// where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
|
|
113
|
-
// G² - 1
|
|
114
|
-
// h2q
|
|
115
|
-
// NOTE: ORDER was wrong!
|
|
116
|
-
const FP2_ORDER = Fp_raw * Fp_raw;
|
|
117
|
-
|
|
118
|
-
const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|
119
|
-
ORDER: FP2_ORDER,
|
|
120
|
-
BITS: bitLen(FP2_ORDER),
|
|
121
|
-
BYTES: Math.ceil(bitLen(FP2_ORDER) / 8),
|
|
122
|
-
MASK: bitMask(bitLen(FP2_ORDER)),
|
|
123
|
-
ZERO: { c0: Fp.ZERO, c1: Fp.ZERO },
|
|
124
|
-
ONE: { c0: Fp.ONE, c1: Fp.ZERO },
|
|
125
|
-
create: (num) => num,
|
|
126
|
-
isValid: ({ c0, c1 }) => typeof c0 === 'bigint' && typeof c1 === 'bigint',
|
|
127
|
-
is0: ({ c0, c1 }) => Fp.is0(c0) && Fp.is0(c1),
|
|
128
|
-
eql: ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => Fp.eql(c0, r0) && Fp.eql(c1, r1),
|
|
129
|
-
neg: ({ c0, c1 }) => ({ c0: Fp.neg(c0), c1: Fp.neg(c1) }),
|
|
130
|
-
pow: (num, power) => mod.FpPow(Fp2, num, power),
|
|
131
|
-
invertBatch: (nums) => mod.FpInvertBatch(Fp2, nums),
|
|
132
|
-
// Normalized
|
|
133
|
-
add: Fp2Add,
|
|
134
|
-
sub: Fp2Subtract,
|
|
135
|
-
mul: Fp2Multiply,
|
|
136
|
-
sqr: Fp2Square,
|
|
137
|
-
// NonNormalized stuff
|
|
138
|
-
addN: Fp2Add,
|
|
139
|
-
subN: Fp2Subtract,
|
|
140
|
-
mulN: Fp2Multiply,
|
|
141
|
-
sqrN: Fp2Square,
|
|
142
|
-
// Why inversion for bigint inside Fp instead of Fp2? it is even used in that context?
|
|
143
|
-
div: (lhs, rhs) => Fp2.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp2.inv(rhs)),
|
|
144
|
-
inv: ({ c0: a, c1: b }) => {
|
|
145
|
-
// We wish to find the multiplicative inverse of a nonzero
|
|
146
|
-
// element a + bu in Fp2. We leverage an identity
|
|
147
|
-
//
|
|
148
|
-
// (a + bu)(a - bu) = a² + b²
|
|
149
|
-
//
|
|
150
|
-
// which holds because u² = -1. This can be rewritten as
|
|
151
|
-
//
|
|
152
|
-
// (a + bu)(a - bu)/(a² + b²) = 1
|
|
153
|
-
//
|
|
154
|
-
// because a² + b² = 0 has no nonzero solutions for (a, b).
|
|
155
|
-
// This gives that (a - bu)/(a² + b²) is the inverse
|
|
156
|
-
// of (a + bu). Importantly, this can be computing using
|
|
157
|
-
// only a single inversion in Fp.
|
|
158
|
-
const factor = Fp.inv(Fp.create(a * a + b * b));
|
|
159
|
-
return { c0: Fp.mul(factor, Fp.create(a)), c1: Fp.mul(factor, Fp.create(-b)) };
|
|
160
|
-
},
|
|
161
|
-
sqrt: (num) => {
|
|
162
|
-
if (Fp2.eql(num, Fp2.ZERO)) return Fp2.ZERO; // Algo doesn't handles this case
|
|
163
|
-
// TODO: Optimize this line. It's extremely slow.
|
|
164
|
-
// Speeding this up would boost aggregateSignatures.
|
|
165
|
-
// https://eprint.iacr.org/2012/685.pdf applicable?
|
|
166
|
-
// https://github.com/zkcrypto/bls12_381/blob/080eaa74ec0e394377caa1ba302c8c121df08b07/src/fp2.rs#L250
|
|
167
|
-
// https://github.com/supranational/blst/blob/aae0c7d70b799ac269ff5edf29d8191dbd357876/src/exp2.c#L1
|
|
168
|
-
// Inspired by https://github.com/dalek-cryptography/curve25519-dalek/blob/17698df9d4c834204f83a3574143abacb4fc81a5/src/field.rs#L99
|
|
169
|
-
const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + _8n) / _16n);
|
|
170
|
-
const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this);
|
|
171
|
-
const R = FP2_ROOTS_OF_UNITY;
|
|
172
|
-
const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check));
|
|
173
|
-
if (!divisor) throw new Error('No root');
|
|
174
|
-
const index = R.indexOf(divisor);
|
|
175
|
-
const root = R[index / 2];
|
|
176
|
-
if (!root) throw new Error('Invalid root');
|
|
177
|
-
const x1 = Fp2.div(candidateSqrt, root);
|
|
178
|
-
const x2 = Fp2.neg(x1);
|
|
179
|
-
const { re: re1, im: im1 } = Fp2.reim(x1);
|
|
180
|
-
const { re: re2, im: im2 } = Fp2.reim(x2);
|
|
181
|
-
if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
|
|
182
|
-
return x2;
|
|
183
|
-
},
|
|
184
|
-
// Same as sgn0_m_eq_2 in RFC 9380
|
|
185
|
-
isOdd: (x: Fp2) => {
|
|
186
|
-
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
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;
|
|
191
|
-
},
|
|
192
|
-
// Bytes util
|
|
193
|
-
fromBytes(b: Uint8Array): Fp2 {
|
|
194
|
-
if (b.length !== Fp2.BYTES) throw new Error(`fromBytes wrong length=${b.length}`);
|
|
195
|
-
return { c0: Fp.fromBytes(b.subarray(0, Fp.BYTES)), c1: Fp.fromBytes(b.subarray(Fp.BYTES)) };
|
|
196
|
-
},
|
|
197
|
-
toBytes: ({ c0, c1 }) => concatB(Fp.toBytes(c0), Fp.toBytes(c1)),
|
|
198
|
-
cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({
|
|
199
|
-
c0: Fp.cmov(c0, r0, c),
|
|
200
|
-
c1: Fp.cmov(c1, r1, c),
|
|
201
|
-
}),
|
|
202
|
-
// Specific utils
|
|
203
|
-
// toString() {
|
|
204
|
-
// return `Fp2(${this.c0} + ${this.c1}×i)`;
|
|
205
|
-
// }
|
|
206
|
-
reim: ({ c0, c1 }) => ({ re: c0, im: c1 }),
|
|
207
|
-
// multiply by u + 1
|
|
208
|
-
mulByNonresidue: ({ c0, c1 }) => ({ c0: Fp.sub(c0, c1), c1: Fp.add(c0, c1) }),
|
|
209
|
-
multiplyByB: ({ c0, c1 }) => {
|
|
210
|
-
let t0 = Fp.mul(c0, _4n); // 4 * c0
|
|
211
|
-
let t1 = Fp.mul(c1, _4n); // 4 * c1
|
|
212
|
-
// (T0-T1) + (T0+T1)*i
|
|
213
|
-
return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) };
|
|
214
|
-
},
|
|
215
|
-
fromBigTuple: (tuple: BigintTuple | bigint[]) => {
|
|
216
|
-
if (tuple.length !== 2) throw new Error('Invalid tuple');
|
|
217
|
-
const fps = tuple.map((n) => Fp.create(n)) as [Fp, Fp];
|
|
218
|
-
return { c0: fps[0], c1: fps[1] };
|
|
219
|
-
},
|
|
220
|
-
frobeniusMap: ({ c0, c1 }, power: number): Fp2 => ({
|
|
221
|
-
c0,
|
|
222
|
-
c1: Fp.mul(c1, FP2_FROBENIUS_COEFFICIENTS[power % 2]),
|
|
223
|
-
}),
|
|
224
|
-
};
|
|
225
|
-
// Finite extension field over irreducible polynominal.
|
|
226
|
-
// Fp(u) / (u² - β) where β = -1
|
|
227
|
-
const FP2_FROBENIUS_COEFFICIENTS = [
|
|
228
|
-
BigInt('0x1'),
|
|
229
|
-
BigInt(
|
|
230
|
-
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
|
|
231
|
-
),
|
|
232
|
-
].map((item) => Fp.create(item));
|
|
233
|
-
|
|
234
|
-
// For Fp2 roots of unity.
|
|
235
|
-
const rv1 = BigInt(
|
|
236
|
-
'0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
|
|
237
|
-
);
|
|
238
|
-
// const ev1 =
|
|
239
|
-
// BigInt('0x699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90');
|
|
240
|
-
// const ev2 =
|
|
241
|
-
// BigInt('0x8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5');
|
|
242
|
-
// const ev3 =
|
|
243
|
-
// BigInt('0xab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17');
|
|
244
|
-
// const ev4 =
|
|
245
|
-
// BigInt('0xaa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1');
|
|
246
|
-
|
|
247
|
-
// Eighth roots of unity, used for computing square roots in Fp2.
|
|
248
|
-
// To verify or re-calculate:
|
|
249
|
-
// Array(8).fill(new Fp2([1n, 1n])).map((fp2, k) => fp2.pow(Fp2.ORDER * BigInt(k) / 8n))
|
|
250
|
-
const FP2_ROOTS_OF_UNITY = [
|
|
251
|
-
[_1n, _0n],
|
|
252
|
-
[rv1, -rv1],
|
|
253
|
-
[_0n, _1n],
|
|
254
|
-
[rv1, rv1],
|
|
255
|
-
[-_1n, _0n],
|
|
256
|
-
[-rv1, rv1],
|
|
257
|
-
[_0n, -_1n],
|
|
258
|
-
[-rv1, -rv1],
|
|
259
|
-
].map((pair) => Fp2.fromBigTuple(pair));
|
|
260
|
-
// eta values, used for computing sqrt(g(X1(t)))
|
|
261
|
-
// const FP2_ETAs = [
|
|
262
|
-
// [ev1, ev2],
|
|
263
|
-
// [-ev2, ev1],
|
|
264
|
-
// [ev3, ev4],
|
|
265
|
-
// [-ev4, ev3],
|
|
266
|
-
// ].map((pair) => Fp2.fromBigTuple(pair));
|
|
267
|
-
|
|
268
|
-
// Finite extension field over irreducible polynominal.
|
|
269
|
-
// Fp2(v) / (v³ - ξ) where ξ = u + 1
|
|
270
|
-
type BigintSix = [bigint, bigint, bigint, bigint, bigint, bigint];
|
|
271
|
-
type Fp6 = { c0: Fp2; c1: Fp2; c2: Fp2 };
|
|
272
|
-
const Fp6Add = ({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6) => ({
|
|
273
|
-
c0: Fp2.add(c0, r0),
|
|
274
|
-
c1: Fp2.add(c1, r1),
|
|
275
|
-
c2: Fp2.add(c2, r2),
|
|
276
|
-
});
|
|
277
|
-
const Fp6Subtract = ({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6) => ({
|
|
278
|
-
c0: Fp2.sub(c0, r0),
|
|
279
|
-
c1: Fp2.sub(c1, r1),
|
|
280
|
-
c2: Fp2.sub(c2, r2),
|
|
281
|
-
});
|
|
282
|
-
const Fp6Multiply = ({ c0, c1, c2 }: Fp6, rhs: Fp6 | bigint) => {
|
|
283
|
-
if (typeof rhs === 'bigint') {
|
|
284
|
-
return {
|
|
285
|
-
c0: Fp2.mul(c0, rhs),
|
|
286
|
-
c1: Fp2.mul(c1, rhs),
|
|
287
|
-
c2: Fp2.mul(c2, rhs),
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
const { c0: r0, c1: r1, c2: r2 } = rhs;
|
|
291
|
-
const t0 = Fp2.mul(c0, r0); // c0 * o0
|
|
292
|
-
const t1 = Fp2.mul(c1, r1); // c1 * o1
|
|
293
|
-
const t2 = Fp2.mul(c2, r2); // c2 * o2
|
|
294
|
-
return {
|
|
295
|
-
// t0 + (c1 + c2) * (r1 * r2) - (T1 + T2) * (u + 1)
|
|
296
|
-
c0: Fp2.add(
|
|
297
|
-
t0,
|
|
298
|
-
Fp2.mulByNonresidue(Fp2.sub(Fp2.mul(Fp2.add(c1, c2), Fp2.add(r1, r2)), Fp2.add(t1, t2)))
|
|
299
|
-
),
|
|
300
|
-
// (c0 + c1) * (r0 + r1) - (T0 + T1) + T2 * (u + 1)
|
|
301
|
-
c1: Fp2.add(
|
|
302
|
-
Fp2.sub(Fp2.mul(Fp2.add(c0, c1), Fp2.add(r0, r1)), Fp2.add(t0, t1)),
|
|
303
|
-
Fp2.mulByNonresidue(t2)
|
|
304
|
-
),
|
|
305
|
-
// T1 + (c0 + c2) * (r0 + r2) - T0 + T2
|
|
306
|
-
c2: Fp2.sub(Fp2.add(t1, Fp2.mul(Fp2.add(c0, c2), Fp2.add(r0, r2))), Fp2.add(t0, t2)),
|
|
307
|
-
};
|
|
308
|
-
};
|
|
309
|
-
const Fp6Square = ({ c0, c1, c2 }: Fp6) => {
|
|
310
|
-
let t0 = Fp2.sqr(c0); // c0²
|
|
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
|
|
313
|
-
let t4 = Fp2.sqr(c2); // c2²
|
|
314
|
-
return {
|
|
315
|
-
c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0
|
|
316
|
-
c1: Fp2.add(Fp2.mulByNonresidue(t4), t1), // T4 * (u + 1) + T1
|
|
317
|
-
// T1 + (c0 - c1 + c2)² + T3 - T0 - T4
|
|
318
|
-
c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
|
|
319
|
-
};
|
|
320
|
-
};
|
|
321
|
-
type Fp6Utils = {
|
|
322
|
-
fromBigSix: (tuple: BigintSix) => Fp6;
|
|
323
|
-
mulByNonresidue: (num: Fp6) => Fp6;
|
|
324
|
-
frobeniusMap(num: Fp6, power: number): Fp6;
|
|
325
|
-
multiplyBy1(num: Fp6, b1: Fp2): Fp6;
|
|
326
|
-
multiplyBy01(num: Fp6, b0: Fp2, b1: Fp2): Fp6;
|
|
327
|
-
multiplyByFp2(lhs: Fp6, rhs: Fp2): Fp6;
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
const Fp6: mod.IField<Fp6> & Fp6Utils = {
|
|
331
|
-
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
332
|
-
BITS: 3 * Fp2.BITS,
|
|
333
|
-
BYTES: 3 * Fp2.BYTES,
|
|
334
|
-
MASK: bitMask(3 * Fp2.BITS),
|
|
335
|
-
ZERO: { c0: Fp2.ZERO, c1: Fp2.ZERO, c2: Fp2.ZERO },
|
|
336
|
-
ONE: { c0: Fp2.ONE, c1: Fp2.ZERO, c2: Fp2.ZERO },
|
|
337
|
-
create: (num) => num,
|
|
338
|
-
isValid: ({ c0, c1, c2 }) => Fp2.isValid(c0) && Fp2.isValid(c1) && Fp2.isValid(c2),
|
|
339
|
-
is0: ({ c0, c1, c2 }) => Fp2.is0(c0) && Fp2.is0(c1) && Fp2.is0(c2),
|
|
340
|
-
neg: ({ c0, c1, c2 }) => ({ c0: Fp2.neg(c0), c1: Fp2.neg(c1), c2: Fp2.neg(c2) }),
|
|
341
|
-
eql: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) =>
|
|
342
|
-
Fp2.eql(c0, r0) && Fp2.eql(c1, r1) && Fp2.eql(c2, r2),
|
|
343
|
-
sqrt: () => {
|
|
344
|
-
throw new Error('Not implemented');
|
|
345
|
-
},
|
|
346
|
-
// Do we need division by bigint at all? Should be done via order:
|
|
347
|
-
div: (lhs, rhs) => Fp6.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp6.inv(rhs)),
|
|
348
|
-
pow: (num, power) => mod.FpPow(Fp6, num, power),
|
|
349
|
-
invertBatch: (nums) => mod.FpInvertBatch(Fp6, nums),
|
|
350
|
-
// Normalized
|
|
351
|
-
add: Fp6Add,
|
|
352
|
-
sub: Fp6Subtract,
|
|
353
|
-
mul: Fp6Multiply,
|
|
354
|
-
sqr: Fp6Square,
|
|
355
|
-
// NonNormalized stuff
|
|
356
|
-
addN: Fp6Add,
|
|
357
|
-
subN: Fp6Subtract,
|
|
358
|
-
mulN: Fp6Multiply,
|
|
359
|
-
sqrN: Fp6Square,
|
|
360
|
-
|
|
361
|
-
inv: ({ c0, c1, c2 }) => {
|
|
362
|
-
let t0 = Fp2.sub(Fp2.sqr(c0), Fp2.mulByNonresidue(Fp2.mul(c2, c1))); // c0² - c2 * c1 * (u + 1)
|
|
363
|
-
let t1 = Fp2.sub(Fp2.mulByNonresidue(Fp2.sqr(c2)), Fp2.mul(c0, c1)); // c2² * (u + 1) - c0 * c1
|
|
364
|
-
let t2 = Fp2.sub(Fp2.sqr(c1), Fp2.mul(c0, c2)); // c1² - c0 * c2
|
|
365
|
-
// 1/(((c2 * T1 + c1 * T2) * v) + c0 * T0)
|
|
366
|
-
let t4 = Fp2.inv(
|
|
367
|
-
Fp2.add(Fp2.mulByNonresidue(Fp2.add(Fp2.mul(c2, t1), Fp2.mul(c1, t2))), Fp2.mul(c0, t0))
|
|
368
|
-
);
|
|
369
|
-
return { c0: Fp2.mul(t4, t0), c1: Fp2.mul(t4, t1), c2: Fp2.mul(t4, t2) };
|
|
370
|
-
},
|
|
371
|
-
// Bytes utils
|
|
372
|
-
fromBytes: (b: Uint8Array): Fp6 => {
|
|
373
|
-
if (b.length !== Fp6.BYTES) throw new Error(`fromBytes wrong length=${b.length}`);
|
|
374
|
-
return {
|
|
375
|
-
c0: Fp2.fromBytes(b.subarray(0, Fp2.BYTES)),
|
|
376
|
-
c1: Fp2.fromBytes(b.subarray(Fp2.BYTES, 2 * Fp2.BYTES)),
|
|
377
|
-
c2: Fp2.fromBytes(b.subarray(2 * Fp2.BYTES)),
|
|
378
|
-
};
|
|
379
|
-
},
|
|
380
|
-
toBytes: ({ c0, c1, c2 }): Uint8Array =>
|
|
381
|
-
concatB(Fp2.toBytes(c0), Fp2.toBytes(c1), Fp2.toBytes(c2)),
|
|
382
|
-
cmov: ({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6, c) => ({
|
|
383
|
-
c0: Fp2.cmov(c0, r0, c),
|
|
384
|
-
c1: Fp2.cmov(c1, r1, c),
|
|
385
|
-
c2: Fp2.cmov(c2, r2, c),
|
|
386
|
-
}),
|
|
387
|
-
// Utils
|
|
388
|
-
// fromTriple(triple: [Fp2, Fp2, Fp2]) {
|
|
389
|
-
// return new Fp6(...triple);
|
|
390
|
-
// }
|
|
391
|
-
// toString() {
|
|
392
|
-
// return `Fp6(${this.c0} + ${this.c1} * v, ${this.c2} * v^2)`;
|
|
393
|
-
// }
|
|
394
|
-
fromBigSix: (t: BigintSix): Fp6 => {
|
|
395
|
-
if (!Array.isArray(t) || t.length !== 6) throw new Error('Invalid Fp6 usage');
|
|
396
|
-
return {
|
|
397
|
-
c0: Fp2.fromBigTuple(t.slice(0, 2)),
|
|
398
|
-
c1: Fp2.fromBigTuple(t.slice(2, 4)),
|
|
399
|
-
c2: Fp2.fromBigTuple(t.slice(4, 6)),
|
|
400
|
-
};
|
|
401
|
-
},
|
|
402
|
-
frobeniusMap: ({ c0, c1, c2 }, power: number) => ({
|
|
403
|
-
c0: Fp2.frobeniusMap(c0, power),
|
|
404
|
-
c1: Fp2.mul(Fp2.frobeniusMap(c1, power), FP6_FROBENIUS_COEFFICIENTS_1[power % 6]),
|
|
405
|
-
c2: Fp2.mul(Fp2.frobeniusMap(c2, power), FP6_FROBENIUS_COEFFICIENTS_2[power % 6]),
|
|
406
|
-
}),
|
|
407
|
-
mulByNonresidue: ({ c0, c1, c2 }) => ({ c0: Fp2.mulByNonresidue(c2), c1: c0, c2: c1 }),
|
|
59
|
+
/*
|
|
60
|
+
Embedding degree (k): 12
|
|
61
|
+
Seed (X): -15132376222941642752
|
|
62
|
+
Fr: (x⁴-x²+1)
|
|
63
|
+
Fp: ((x-1)² ⋅ r(x)/3+x)
|
|
64
|
+
(E/Fp): Y²=X³+4
|
|
65
|
+
(Eₜ/Fp²): Y² = X³+4(u+1) (M-type twist)
|
|
66
|
+
Ate loop size: X
|
|
408
67
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
c2: Fp2.mul(c1, b1),
|
|
414
|
-
}),
|
|
415
|
-
// Sparse multiplication
|
|
416
|
-
multiplyBy01({ c0, c1, c2 }, b0: Fp2, b1: Fp2): Fp6 {
|
|
417
|
-
let t0 = Fp2.mul(c0, b0); // c0 * b0
|
|
418
|
-
let t1 = Fp2.mul(c1, b1); // c1 * b1
|
|
419
|
-
return {
|
|
420
|
-
// ((c1 + c2) * b1 - T1) * (u + 1) + T0
|
|
421
|
-
c0: Fp2.add(Fp2.mulByNonresidue(Fp2.sub(Fp2.mul(Fp2.add(c1, c2), b1), t1)), t0),
|
|
422
|
-
// (b0 + b1) * (c0 + c1) - T0 - T1
|
|
423
|
-
c1: Fp2.sub(Fp2.sub(Fp2.mul(Fp2.add(b0, b1), Fp2.add(c0, c1)), t0), t1),
|
|
424
|
-
// (c0 + c2) * b0 - T0 + T1
|
|
425
|
-
c2: Fp2.add(Fp2.sub(Fp2.mul(Fp2.add(c0, c2), b0), t0), t1),
|
|
426
|
-
};
|
|
427
|
-
},
|
|
68
|
+
Towers:
|
|
69
|
+
- Fp²[u] = Fp/u²+1
|
|
70
|
+
- Fp⁶[v] = Fp²/v³-1-u
|
|
71
|
+
- Fp¹²[w] = Fp⁶/w²-v
|
|
428
72
|
|
|
429
|
-
multiplyByFp2: ({ c0, c1, c2 }, rhs: Fp2): Fp6 => ({
|
|
430
|
-
c0: Fp2.mul(c0, rhs),
|
|
431
|
-
c1: Fp2.mul(c1, rhs),
|
|
432
|
-
c2: Fp2.mul(c2, rhs),
|
|
433
|
-
}),
|
|
434
|
-
};
|
|
435
73
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
[
|
|
439
|
-
BigInt('0x0'),
|
|
440
|
-
BigInt(
|
|
441
|
-
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
442
|
-
),
|
|
443
|
-
],
|
|
444
|
-
[
|
|
445
|
-
BigInt(
|
|
446
|
-
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
447
|
-
),
|
|
448
|
-
BigInt('0x0'),
|
|
449
|
-
],
|
|
450
|
-
[BigInt('0x0'), BigInt('0x1')],
|
|
451
|
-
[
|
|
452
|
-
BigInt(
|
|
453
|
-
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
454
|
-
),
|
|
455
|
-
BigInt('0x0'),
|
|
456
|
-
],
|
|
457
|
-
[
|
|
458
|
-
BigInt('0x0'),
|
|
459
|
-
BigInt(
|
|
460
|
-
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
461
|
-
),
|
|
462
|
-
],
|
|
463
|
-
].map((pair) => Fp2.fromBigTuple(pair));
|
|
464
|
-
const FP6_FROBENIUS_COEFFICIENTS_2 = [
|
|
465
|
-
[BigInt('0x1'), BigInt('0x0')],
|
|
466
|
-
[
|
|
467
|
-
BigInt(
|
|
468
|
-
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
|
|
469
|
-
),
|
|
470
|
-
BigInt('0x0'),
|
|
471
|
-
],
|
|
472
|
-
[
|
|
473
|
-
BigInt(
|
|
474
|
-
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
475
|
-
),
|
|
476
|
-
BigInt('0x0'),
|
|
477
|
-
],
|
|
478
|
-
[
|
|
479
|
-
BigInt(
|
|
480
|
-
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
|
|
481
|
-
),
|
|
482
|
-
BigInt('0x0'),
|
|
483
|
-
],
|
|
484
|
-
[
|
|
485
|
-
BigInt(
|
|
486
|
-
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
487
|
-
),
|
|
488
|
-
BigInt('0x0'),
|
|
489
|
-
],
|
|
490
|
-
[
|
|
491
|
-
BigInt(
|
|
492
|
-
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
|
|
493
|
-
),
|
|
494
|
-
BigInt('0x0'),
|
|
495
|
-
],
|
|
496
|
-
].map((pair) => Fp2.fromBigTuple(pair));
|
|
74
|
+
TODO: BLS & BN Fp/Fr can be constructed from seed.
|
|
75
|
+
*/
|
|
497
76
|
|
|
498
|
-
//
|
|
499
|
-
// Fp₁₂ = Fp₆² => Fp₂³
|
|
500
|
-
// Fp₆(w) / (w² - γ) where γ = v
|
|
501
|
-
type Fp12 = { c0: Fp6; c1: Fp6 };
|
|
502
|
-
// The BLS parameter x for BLS12-381
|
|
77
|
+
// The BLS parameter x (seed) for BLS12-381. NOTE: it is negative!
|
|
503
78
|
const BLS_X = BigInt('0xd201000000010000');
|
|
504
79
|
const BLS_X_LEN = bitLen(BLS_X);
|
|
505
80
|
|
|
506
|
-
//
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
if (typeof rhs === 'bigint') return { c0: Fp6.mul(c0, rhs), c1: Fp6.mul(c1, rhs) };
|
|
521
|
-
let { c0: r0, c1: r1 } = rhs;
|
|
522
|
-
let t1 = Fp6.mul(c0, r0); // c0 * r0
|
|
523
|
-
let t2 = Fp6.mul(c1, r1); // c1 * r1
|
|
524
|
-
return {
|
|
525
|
-
c0: Fp6.add(t1, Fp6.mulByNonresidue(t2)), // T1 + T2 * v
|
|
526
|
-
// (c0 + c1) * (r0 + r1) - (T1 + T2)
|
|
527
|
-
c1: Fp6.sub(Fp6.mul(Fp6.add(c0, c1), Fp6.add(r0, r1)), Fp6.add(t1, t2)),
|
|
528
|
-
};
|
|
529
|
-
};
|
|
530
|
-
const Fp12Square = ({ c0, c1 }: Fp12) => {
|
|
531
|
-
let ab = Fp6.mul(c0, c1); // c0 * c1
|
|
532
|
-
return {
|
|
533
|
-
// (c1 * v + c0) * (c0 + c1) - AB - AB * v
|
|
534
|
-
c0: Fp6.sub(
|
|
535
|
-
Fp6.sub(Fp6.mul(Fp6.add(Fp6.mulByNonresidue(c1), c0), Fp6.add(c0, c1)), ab),
|
|
536
|
-
Fp6.mulByNonresidue(ab)
|
|
537
|
-
),
|
|
538
|
-
c1: Fp6.add(ab, ab),
|
|
539
|
-
}; // AB + AB
|
|
540
|
-
};
|
|
541
|
-
function Fp4Square(a: Fp2, b: Fp2): { first: Fp2; second: Fp2 } {
|
|
542
|
-
const a2 = Fp2.sqr(a);
|
|
543
|
-
const b2 = Fp2.sqr(b);
|
|
544
|
-
return {
|
|
545
|
-
first: Fp2.add(Fp2.mulByNonresidue(b2), a2), // b² * Nonresidue + a²
|
|
546
|
-
second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
type Fp12Utils = {
|
|
550
|
-
fromBigTwelve: (t: BigintTwelve) => Fp12;
|
|
551
|
-
frobeniusMap(num: Fp12, power: number): Fp12;
|
|
552
|
-
multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
|
553
|
-
multiplyByFp2(lhs: Fp12, rhs: Fp2): Fp12;
|
|
554
|
-
conjugate(num: Fp12): Fp12;
|
|
555
|
-
finalExponentiate(num: Fp12): Fp12;
|
|
556
|
-
_cyclotomicSquare(num: Fp12): Fp12;
|
|
557
|
-
_cyclotomicExp(num: Fp12, n: bigint): Fp12;
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
const Fp12: mod.IField<Fp12> & Fp12Utils = {
|
|
561
|
-
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
562
|
-
BITS: 2 * Fp2.BITS,
|
|
563
|
-
BYTES: 2 * Fp2.BYTES,
|
|
564
|
-
MASK: bitMask(2 * Fp2.BITS),
|
|
565
|
-
ZERO: { c0: Fp6.ZERO, c1: Fp6.ZERO },
|
|
566
|
-
ONE: { c0: Fp6.ONE, c1: Fp6.ZERO },
|
|
567
|
-
create: (num) => num,
|
|
568
|
-
isValid: ({ c0, c1 }) => Fp6.isValid(c0) && Fp6.isValid(c1),
|
|
569
|
-
is0: ({ c0, c1 }) => Fp6.is0(c0) && Fp6.is0(c1),
|
|
570
|
-
neg: ({ c0, c1 }) => ({ c0: Fp6.neg(c0), c1: Fp6.neg(c1) }),
|
|
571
|
-
eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp6.eql(c0, r0) && Fp6.eql(c1, r1),
|
|
572
|
-
sqrt: () => {
|
|
573
|
-
throw new Error('Not implemented');
|
|
574
|
-
},
|
|
575
|
-
inv: ({ c0, c1 }) => {
|
|
576
|
-
let t = Fp6.inv(Fp6.sub(Fp6.sqr(c0), Fp6.mulByNonresidue(Fp6.sqr(c1)))); // 1 / (c0² - c1² * v)
|
|
577
|
-
return { c0: Fp6.mul(c0, t), c1: Fp6.neg(Fp6.mul(c1, t)) }; // ((C0 * T) * T) + (-C1 * T) * w
|
|
578
|
-
},
|
|
579
|
-
div: (lhs, rhs) =>
|
|
580
|
-
Fp12.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp12.inv(rhs)),
|
|
581
|
-
pow: (num, power) => mod.FpPow(Fp12, num, power),
|
|
582
|
-
invertBatch: (nums) => mod.FpInvertBatch(Fp12, nums),
|
|
583
|
-
// Normalized
|
|
584
|
-
add: Fp12Add,
|
|
585
|
-
sub: Fp12Subtract,
|
|
586
|
-
mul: Fp12Multiply,
|
|
587
|
-
sqr: Fp12Square,
|
|
588
|
-
// NonNormalized stuff
|
|
589
|
-
addN: Fp12Add,
|
|
590
|
-
subN: Fp12Subtract,
|
|
591
|
-
mulN: Fp12Multiply,
|
|
592
|
-
sqrN: Fp12Square,
|
|
593
|
-
|
|
594
|
-
// Bytes utils
|
|
595
|
-
fromBytes: (b: Uint8Array): Fp12 => {
|
|
596
|
-
if (b.length !== Fp12.BYTES) throw new Error(`fromBytes wrong length=${b.length}`);
|
|
597
|
-
return {
|
|
598
|
-
c0: Fp6.fromBytes(b.subarray(0, Fp6.BYTES)),
|
|
599
|
-
c1: Fp6.fromBytes(b.subarray(Fp6.BYTES)),
|
|
600
|
-
};
|
|
601
|
-
},
|
|
602
|
-
toBytes: ({ c0, c1 }): Uint8Array => concatB(Fp6.toBytes(c0), Fp6.toBytes(c1)),
|
|
603
|
-
cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({
|
|
604
|
-
c0: Fp6.cmov(c0, r0, c),
|
|
605
|
-
c1: Fp6.cmov(c1, r1, c),
|
|
606
|
-
}),
|
|
607
|
-
// Utils
|
|
608
|
-
// toString() {
|
|
609
|
-
// return `Fp12(${this.c0} + ${this.c1} * w)`;
|
|
610
|
-
// },
|
|
611
|
-
// fromTuple(c: [Fp6, Fp6]) {
|
|
612
|
-
// return new Fp12(...c);
|
|
613
|
-
// }
|
|
614
|
-
fromBigTwelve: (t: BigintTwelve): Fp12 => ({
|
|
615
|
-
c0: Fp6.fromBigSix(t.slice(0, 6) as BigintSix),
|
|
616
|
-
c1: Fp6.fromBigSix(t.slice(6, 12) as BigintSix),
|
|
617
|
-
}),
|
|
618
|
-
// Raises to q**i -th power
|
|
619
|
-
frobeniusMap(lhs, power: number) {
|
|
620
|
-
const r0 = Fp6.frobeniusMap(lhs.c0, power);
|
|
621
|
-
const { c0, c1, c2 } = Fp6.frobeniusMap(lhs.c1, power);
|
|
622
|
-
const coeff = FP12_FROBENIUS_COEFFICIENTS[power % 12];
|
|
623
|
-
return {
|
|
624
|
-
c0: r0,
|
|
625
|
-
c1: Fp6.create({
|
|
626
|
-
c0: Fp2.mul(c0, coeff),
|
|
627
|
-
c1: Fp2.mul(c1, coeff),
|
|
628
|
-
c2: Fp2.mul(c2, coeff),
|
|
629
|
-
}),
|
|
630
|
-
};
|
|
631
|
-
},
|
|
632
|
-
// Sparse multiplication
|
|
633
|
-
multiplyBy014: ({ c0, c1 }, o0: Fp2, o1: Fp2, o4: Fp2) => {
|
|
634
|
-
let t0 = Fp6.multiplyBy01(c0, o0, o1);
|
|
635
|
-
let t1 = Fp6.multiplyBy1(c1, o4);
|
|
636
|
-
return {
|
|
637
|
-
c0: Fp6.add(Fp6.mulByNonresidue(t1), t0), // T1 * v + T0
|
|
638
|
-
// (c1 + c0) * [o0, o1+o4] - T0 - T1
|
|
639
|
-
c1: Fp6.sub(Fp6.sub(Fp6.multiplyBy01(Fp6.add(c1, c0), o0, Fp2.add(o1, o4)), t0), t1),
|
|
640
|
-
};
|
|
81
|
+
// CURVE FIELDS
|
|
82
|
+
const { Fp, Fp2, Fp6, Fp4Square, Fp12 } = tower12({
|
|
83
|
+
// Order of Fp
|
|
84
|
+
ORDER: BigInt(
|
|
85
|
+
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
|
|
86
|
+
),
|
|
87
|
+
// Finite extension field over irreducible polynominal.
|
|
88
|
+
// Fp(u) / (u² - β) where β = -1
|
|
89
|
+
FP2_NONRESIDUE: [_1n, _1n],
|
|
90
|
+
Fp2mulByB: ({ c0, c1 }) => {
|
|
91
|
+
const t0 = Fp.mul(c0, _4n); // 4 * c0
|
|
92
|
+
const t1 = Fp.mul(c1, _4n); // 4 * c1
|
|
93
|
+
// (T0-T1) + (T0+T1)*i
|
|
94
|
+
return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) };
|
|
641
95
|
},
|
|
642
|
-
|
|
643
|
-
c0: Fp6.multiplyByFp2(c0, rhs),
|
|
644
|
-
c1: Fp6.multiplyByFp2(c1, rhs),
|
|
645
|
-
}),
|
|
646
|
-
conjugate: ({ c0, c1 }): Fp12 => ({ c0, c1: Fp6.neg(c1) }),
|
|
647
|
-
|
|
96
|
+
// Fp12
|
|
648
97
|
// A cyclotomic group is a subgroup of Fp^n defined by
|
|
649
98
|
// GΦₙ(p) = {α ∈ Fpⁿ : α^Φₙ(p) = 1}
|
|
650
99
|
// The result of any pairing is in a cyclotomic subgroup
|
|
651
100
|
// https://eprint.iacr.org/2009/565.pdf
|
|
652
|
-
|
|
101
|
+
Fp12cyclotomicSquare: ({ c0, c1 }): Fp12 => {
|
|
653
102
|
const { c0: c0c0, c1: c0c1, c2: c0c2 } = c0;
|
|
654
103
|
const { c0: c1c0, c1: c1c1, c2: c1c2 } = c1;
|
|
655
104
|
const { first: t3, second: t4 } = Fp4Square(c0c0, c1c1);
|
|
656
105
|
const { first: t5, second: t6 } = Fp4Square(c1c0, c0c2);
|
|
657
106
|
const { first: t7, second: t8 } = Fp4Square(c0c1, c1c2);
|
|
658
|
-
|
|
107
|
+
const t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
|
|
659
108
|
return {
|
|
660
109
|
c0: Fp6.create({
|
|
661
110
|
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
|
|
@@ -669,7 +118,7 @@ const Fp12: mod.IField<Fp12> & Fp12Utils = {
|
|
|
669
118
|
}),
|
|
670
119
|
}; // 2 * (T6 + c1c2) + T6
|
|
671
120
|
},
|
|
672
|
-
|
|
121
|
+
Fp12cyclotomicExp(num, n) {
|
|
673
122
|
let z = Fp12.ONE;
|
|
674
123
|
for (let i = BLS_X_LEN - 1; i >= 0; i--) {
|
|
675
124
|
z = Fp12._cyclotomicSquare(z);
|
|
@@ -679,7 +128,7 @@ const Fp12: mod.IField<Fp12> & Fp12Utils = {
|
|
|
679
128
|
},
|
|
680
129
|
// https://eprint.iacr.org/2010/354.pdf
|
|
681
130
|
// https://eprint.iacr.org/2009/565.pdf
|
|
682
|
-
|
|
131
|
+
Fp12finalExponentiate: (num) => {
|
|
683
132
|
const x = BLS_X;
|
|
684
133
|
// this^(q⁶) / this
|
|
685
134
|
const t0 = Fp12.div(Fp12.frobeniusMap(num, 6), num);
|
|
@@ -698,88 +147,12 @@ const Fp12: mod.IField<Fp12> & Fp12Utils = {
|
|
|
698
147
|
// (t2 * t5)^(q²) * (t4 * t1)^(q³) * (t6 * t1.conj)^(q^1) * t7 * t3.conj * t1
|
|
699
148
|
return Fp12.mul(Fp12.mul(Fp12.mul(t2_t5_pow_q2, t4_t1_pow_q3), t6_t1c_pow_q1), t7_t3c_t1);
|
|
700
149
|
},
|
|
701
|
-
};
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
),
|
|
708
|
-
BigInt(
|
|
709
|
-
'0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
|
|
710
|
-
),
|
|
711
|
-
],
|
|
712
|
-
[
|
|
713
|
-
BigInt(
|
|
714
|
-
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
|
|
715
|
-
),
|
|
716
|
-
BigInt('0x0'),
|
|
717
|
-
],
|
|
718
|
-
[
|
|
719
|
-
BigInt(
|
|
720
|
-
'0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
|
|
721
|
-
),
|
|
722
|
-
BigInt(
|
|
723
|
-
'0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
|
|
724
|
-
),
|
|
725
|
-
],
|
|
726
|
-
[
|
|
727
|
-
BigInt(
|
|
728
|
-
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
|
729
|
-
),
|
|
730
|
-
BigInt('0x0'),
|
|
731
|
-
],
|
|
732
|
-
[
|
|
733
|
-
BigInt(
|
|
734
|
-
'0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
|
|
735
|
-
),
|
|
736
|
-
BigInt(
|
|
737
|
-
'0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
|
|
738
|
-
),
|
|
739
|
-
],
|
|
740
|
-
[
|
|
741
|
-
BigInt(
|
|
742
|
-
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
|
|
743
|
-
),
|
|
744
|
-
BigInt('0x0'),
|
|
745
|
-
],
|
|
746
|
-
[
|
|
747
|
-
BigInt(
|
|
748
|
-
'0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
|
|
749
|
-
),
|
|
750
|
-
BigInt(
|
|
751
|
-
'0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
|
|
752
|
-
),
|
|
753
|
-
],
|
|
754
|
-
[
|
|
755
|
-
BigInt(
|
|
756
|
-
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
757
|
-
),
|
|
758
|
-
BigInt('0x0'),
|
|
759
|
-
],
|
|
760
|
-
[
|
|
761
|
-
BigInt(
|
|
762
|
-
'0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
|
|
763
|
-
),
|
|
764
|
-
BigInt(
|
|
765
|
-
'0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
|
|
766
|
-
),
|
|
767
|
-
],
|
|
768
|
-
[
|
|
769
|
-
BigInt(
|
|
770
|
-
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
|
|
771
|
-
),
|
|
772
|
-
BigInt('0x0'),
|
|
773
|
-
],
|
|
774
|
-
[
|
|
775
|
-
BigInt(
|
|
776
|
-
'0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
|
|
777
|
-
),
|
|
778
|
-
BigInt(
|
|
779
|
-
'0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
|
|
780
|
-
),
|
|
781
|
-
],
|
|
782
|
-
].map((n) => Fp2.fromBigTuple(n));
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Finite field over r.
|
|
153
|
+
// This particular field is not used anywhere in bls12-381, but it is still useful.
|
|
154
|
+
const Fr = mod.Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
|
|
155
|
+
|
|
783
156
|
// END OF CURVE FIELDS
|
|
784
157
|
|
|
785
158
|
// HashToCurve
|
|
@@ -953,36 +326,7 @@ const G1_SWU = mapToCurveSimpleSWU(Fp, {
|
|
|
953
326
|
|
|
954
327
|
// Endomorphisms (for fast cofactor clearing)
|
|
955
328
|
// Ψ(P) endomorphism
|
|
956
|
-
const
|
|
957
|
-
const wsq = Fp12.create({ c0: ut_root, c1: Fp6.ZERO });
|
|
958
|
-
const wcu = Fp12.create({ c0: Fp6.ZERO, c1: ut_root });
|
|
959
|
-
const [wsq_inv, wcu_inv] = Fp12.invertBatch([wsq, wcu]);
|
|
960
|
-
function psi(x: Fp2, y: Fp2): [Fp2, Fp2] {
|
|
961
|
-
// Untwist Fp2->Fp12 && frobenius(1) && twist back
|
|
962
|
-
const x2 = Fp12.mul(Fp12.frobeniusMap(Fp12.multiplyByFp2(wsq_inv, x), 1), wsq).c0.c0;
|
|
963
|
-
const y2 = Fp12.mul(Fp12.frobeniusMap(Fp12.multiplyByFp2(wcu_inv, y), 1), wcu).c0.c0;
|
|
964
|
-
return [x2, y2];
|
|
965
|
-
}
|
|
966
|
-
// Ψ endomorphism
|
|
967
|
-
function G2psi(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
|
|
968
|
-
const affine = P.toAffine();
|
|
969
|
-
const p = psi(affine.x, affine.y);
|
|
970
|
-
return new c(p[0], p[1], Fp2.ONE);
|
|
971
|
-
}
|
|
972
|
-
// Ψ²(P) endomorphism
|
|
973
|
-
// 1 / F2(2)^((p-1)/3) in GF(p²)
|
|
974
|
-
const PSI2_C1 = BigInt(
|
|
975
|
-
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
|
976
|
-
);
|
|
977
|
-
|
|
978
|
-
function psi2(x: Fp2, y: Fp2): [Fp2, Fp2] {
|
|
979
|
-
return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)];
|
|
980
|
-
}
|
|
981
|
-
function G2psi2(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
|
|
982
|
-
const affine = P.toAffine();
|
|
983
|
-
const p = psi2(affine.x, affine.y);
|
|
984
|
-
return new c(p[0], p[1], Fp2.ONE);
|
|
985
|
-
}
|
|
329
|
+
const { G2psi, G2psi2 } = psiFrobenius(Fp, Fp2, Fp2.div(Fp2.ONE, Fp2.NONRESIDUE)); // 1/(u+1)
|
|
986
330
|
|
|
987
331
|
// Default hash_to_field options are for hash to G2.
|
|
988
332
|
//
|
|
@@ -1084,7 +428,7 @@ function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
|
|
|
1084
428
|
// Fp₂(v) / (v³ - ξ) where ξ = u + 1
|
|
1085
429
|
// Fp₆(w) / (w² - γ) where γ = v
|
|
1086
430
|
// Here goes constants && point encoding format
|
|
1087
|
-
export const bls12_381: CurveFn
|
|
431
|
+
export const bls12_381: CurveFn = bls({
|
|
1088
432
|
// Fields
|
|
1089
433
|
fields: {
|
|
1090
434
|
Fp,
|
|
@@ -1125,8 +469,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1125
469
|
const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
|
|
1126
470
|
|
|
1127
471
|
// todo: unroll
|
|
1128
|
-
const xP = point.multiplyUnsafe(
|
|
1129
|
-
const u2P = xP.multiplyUnsafe(
|
|
472
|
+
const xP = point.multiplyUnsafe(BLS_X).negate(); // [x]P
|
|
473
|
+
const u2P = xP.multiplyUnsafe(BLS_X); // [u2]P
|
|
1130
474
|
return u2P.equals(phi);
|
|
1131
475
|
|
|
1132
476
|
// https://eprint.iacr.org/2019/814.pdf
|
|
@@ -1145,7 +489,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1145
489
|
// https://eprint.iacr.org/2019/403
|
|
1146
490
|
clearCofactor: (_c, point) => {
|
|
1147
491
|
// return this.multiplyUnsafe(CURVE.h);
|
|
1148
|
-
return point.multiplyUnsafe(
|
|
492
|
+
return point.multiplyUnsafe(BLS_X).add(point); // x*P + P
|
|
1149
493
|
},
|
|
1150
494
|
mapToCurve: (scalars: bigint[]) => {
|
|
1151
495
|
const { x, y } = G1_SWU(Fp.create(scalars[0]));
|
|
@@ -1270,7 +614,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1270
614
|
// It returns false for shitty points.
|
|
1271
615
|
// https://eprint.iacr.org/2021/1130.pdf
|
|
1272
616
|
isTorsionFree: (c, P): boolean => {
|
|
1273
|
-
return P.multiplyUnsafe(
|
|
617
|
+
return P.multiplyUnsafe(BLS_X).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
|
|
1274
618
|
// Older version: https://eprint.iacr.org/2019/814.pdf
|
|
1275
619
|
// Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
|
|
1276
620
|
// return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
|
|
@@ -1280,7 +624,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1280
624
|
// https://eprint.iacr.org/2017/419.pdf
|
|
1281
625
|
// prettier-ignore
|
|
1282
626
|
clearCofactor: (c, P) => {
|
|
1283
|
-
const x =
|
|
627
|
+
const x = BLS_X;
|
|
1284
628
|
let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
|
|
1285
629
|
let t2 = G2psi(c, P); // Ψ(P)
|
|
1286
630
|
let t3 = P.double(); // 2P
|
|
@@ -1401,8 +745,10 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1401
745
|
},
|
|
1402
746
|
},
|
|
1403
747
|
params: {
|
|
1404
|
-
|
|
748
|
+
ateLoopSize: BLS_X, // The BLS parameter x for BLS12-381
|
|
1405
749
|
r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
|
|
750
|
+
xNegative: true,
|
|
751
|
+
twistType: 'multiplicative',
|
|
1406
752
|
},
|
|
1407
753
|
htfDefaults,
|
|
1408
754
|
hash: sha256,
|