@noble/curves 1.4.2 → 1.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.
Files changed (130) hide show
  1. package/README.md +159 -128
  2. package/_shortw_utils.d.ts.map +1 -1
  3. package/abstract/bls.d.ts +37 -34
  4. package/abstract/bls.d.ts.map +1 -1
  5. package/abstract/bls.js +167 -115
  6. package/abstract/bls.js.map +1 -1
  7. package/abstract/curve.d.ts +14 -1
  8. package/abstract/curve.d.ts.map +1 -1
  9. package/abstract/curve.js +77 -7
  10. package/abstract/curve.js.map +1 -1
  11. package/abstract/edwards.d.ts +12 -0
  12. package/abstract/edwards.d.ts.map +1 -1
  13. package/abstract/edwards.js +84 -75
  14. package/abstract/edwards.js.map +1 -1
  15. package/abstract/hash-to-curve.d.ts.map +1 -1
  16. package/abstract/hash-to-curve.js +4 -2
  17. package/abstract/hash-to-curve.js.map +1 -1
  18. package/abstract/modular.d.ts +4 -0
  19. package/abstract/modular.d.ts.map +1 -1
  20. package/abstract/modular.js +13 -2
  21. package/abstract/modular.js.map +1 -1
  22. package/abstract/montgomery.d.ts.map +1 -1
  23. package/abstract/montgomery.js +4 -9
  24. package/abstract/montgomery.js.map +1 -1
  25. package/abstract/tower.d.ts +107 -0
  26. package/abstract/tower.d.ts.map +1 -0
  27. package/abstract/tower.js +498 -0
  28. package/abstract/tower.js.map +1 -0
  29. package/abstract/utils.d.ts +17 -0
  30. package/abstract/utils.d.ts.map +1 -1
  31. package/abstract/utils.js +50 -1
  32. package/abstract/utils.js.map +1 -1
  33. package/abstract/weierstrass.d.ts +25 -3
  34. package/abstract/weierstrass.d.ts.map +1 -1
  35. package/abstract/weierstrass.js +189 -113
  36. package/abstract/weierstrass.js.map +1 -1
  37. package/bls12-381.d.ts +1 -65
  38. package/bls12-381.d.ts.map +1 -1
  39. package/bls12-381.js +48 -575
  40. package/bls12-381.js.map +1 -1
  41. package/bn254.d.ts +10 -6
  42. package/bn254.d.ts.map +1 -1
  43. package/bn254.js +207 -10
  44. package/bn254.js.map +1 -1
  45. package/ed25519.d.ts +7 -4
  46. package/ed25519.d.ts.map +1 -1
  47. package/ed25519.js +3 -0
  48. package/ed25519.js.map +1 -1
  49. package/esm/_shortw_utils.d.ts.map +1 -1
  50. package/esm/abstract/bls.d.ts +37 -34
  51. package/esm/abstract/bls.d.ts.map +1 -1
  52. package/esm/abstract/bls.js +168 -116
  53. package/esm/abstract/bls.js.map +1 -1
  54. package/esm/abstract/curve.d.ts +14 -1
  55. package/esm/abstract/curve.d.ts.map +1 -1
  56. package/esm/abstract/curve.js +77 -8
  57. package/esm/abstract/curve.js.map +1 -1
  58. package/esm/abstract/edwards.d.ts +12 -0
  59. package/esm/abstract/edwards.d.ts.map +1 -1
  60. package/esm/abstract/edwards.js +87 -78
  61. package/esm/abstract/edwards.js.map +1 -1
  62. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  63. package/esm/abstract/hash-to-curve.js +4 -2
  64. package/esm/abstract/hash-to-curve.js.map +1 -1
  65. package/esm/abstract/modular.d.ts +4 -0
  66. package/esm/abstract/modular.d.ts.map +1 -1
  67. package/esm/abstract/modular.js +12 -2
  68. package/esm/abstract/modular.js.map +1 -1
  69. package/esm/abstract/montgomery.d.ts.map +1 -1
  70. package/esm/abstract/montgomery.js +5 -10
  71. package/esm/abstract/montgomery.js.map +1 -1
  72. package/esm/abstract/tower.d.ts +107 -0
  73. package/esm/abstract/tower.d.ts.map +1 -0
  74. package/esm/abstract/tower.js +494 -0
  75. package/esm/abstract/tower.js.map +1 -0
  76. package/esm/abstract/utils.d.ts +17 -0
  77. package/esm/abstract/utils.d.ts.map +1 -1
  78. package/esm/abstract/utils.js +44 -0
  79. package/esm/abstract/utils.js.map +1 -1
  80. package/esm/abstract/weierstrass.d.ts +25 -3
  81. package/esm/abstract/weierstrass.d.ts.map +1 -1
  82. package/esm/abstract/weierstrass.js +191 -115
  83. package/esm/abstract/weierstrass.js.map +1 -1
  84. package/esm/bls12-381.d.ts +1 -65
  85. package/esm/bls12-381.d.ts.map +1 -1
  86. package/esm/bls12-381.js +50 -577
  87. package/esm/bls12-381.js.map +1 -1
  88. package/esm/bn254.d.ts +10 -6
  89. package/esm/bn254.d.ts.map +1 -1
  90. package/esm/bn254.js +206 -9
  91. package/esm/bn254.js.map +1 -1
  92. package/esm/ed25519.d.ts +7 -4
  93. package/esm/ed25519.d.ts.map +1 -1
  94. package/esm/ed25519.js +3 -0
  95. package/esm/ed25519.js.map +1 -1
  96. package/esm/jubjub.d.ts.map +1 -1
  97. package/esm/jubjub.js +8 -2
  98. package/esm/jubjub.js.map +1 -1
  99. package/esm/p256.d.ts.map +1 -1
  100. package/esm/p384.d.ts.map +1 -1
  101. package/esm/p521.d.ts.map +1 -1
  102. package/esm/secp256k1.d.ts +6 -0
  103. package/esm/secp256k1.d.ts.map +1 -1
  104. package/esm/secp256k1.js +17 -13
  105. package/esm/secp256k1.js.map +1 -1
  106. package/jubjub.d.ts.map +1 -1
  107. package/jubjub.js +8 -2
  108. package/jubjub.js.map +1 -1
  109. package/p256.d.ts.map +1 -1
  110. package/p384.d.ts.map +1 -1
  111. package/p521.d.ts.map +1 -1
  112. package/package.json +27 -19
  113. package/secp256k1.d.ts +6 -0
  114. package/secp256k1.d.ts.map +1 -1
  115. package/secp256k1.js +16 -12
  116. package/secp256k1.js.map +1 -1
  117. package/src/abstract/bls.ts +222 -168
  118. package/src/abstract/curve.ts +80 -8
  119. package/src/abstract/edwards.ts +97 -70
  120. package/src/abstract/hash-to-curve.ts +3 -1
  121. package/src/abstract/modular.ts +13 -3
  122. package/src/abstract/montgomery.ts +11 -10
  123. package/src/abstract/tower.ts +605 -0
  124. package/src/abstract/utils.ts +49 -0
  125. package/src/abstract/weierstrass.ts +179 -104
  126. package/src/bls12-381.ts +53 -707
  127. package/src/bn254.ts +224 -9
  128. package/src/ed25519.ts +5 -2
  129. package/src/jubjub.ts +7 -2
  130. 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
- AffinePoint,
21
- mapToCurveSimpleSWU,
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
- // Fp₂ over complex plane
77
- type BigintTuple = [bigint, bigint];
78
- type Fp2 = { c0: bigint; c1: bigint };
79
- const Fp2Add = ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => ({
80
- c0: Fp.add(c0, r0),
81
- c1: Fp.add(c1, r1),
82
- });
83
- const Fp2Subtract = ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => ({
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
- // Sparse multiplication
410
- multiplyBy1: ({ c0, c1, c2 }, b1: Fp2): Fp6 => ({
411
- c0: Fp2.mulByNonresidue(Fp2.mul(c2, b1)),
412
- c1: Fp2.mul(c0, b1),
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
- const FP6_FROBENIUS_COEFFICIENTS_1 = [
437
- [BigInt('0x1'), BigInt('0x0')],
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
- // Finite extension field over irreducible polynominal.
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
- // prettier-ignore
507
- type BigintTwelve = [
508
- bigint, bigint, bigint, bigint, bigint, bigint,
509
- bigint, bigint, bigint, bigint, bigint, bigint
510
- ];
511
- const Fp12Add = ({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12) => ({
512
- c0: Fp6.add(c0, r0),
513
- c1: Fp6.add(c1, r1),
514
- });
515
- const Fp12Subtract = ({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12) => ({
516
- c0: Fp6.sub(c0, r0),
517
- c1: Fp6.sub(c1, r1),
518
- });
519
- const Fp12Multiply = ({ c0, c1 }: Fp12, rhs: Fp12 | bigint) => {
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
- multiplyByFp2: ({ c0, c1 }, rhs: Fp2): Fp12 => ({
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
- _cyclotomicSquare: ({ c0, c1 }): Fp12 => {
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
- let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
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
- _cyclotomicExp(num, n) {
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
- finalExponentiate: (num) => {
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
- const FP12_FROBENIUS_COEFFICIENTS = [
703
- [BigInt('0x1'), BigInt('0x0')],
704
- [
705
- BigInt(
706
- '0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
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 ut_root = Fp6.create({ c0: Fp2.ZERO, c1: Fp2.ONE, c2: Fp2.ZERO });
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<Fp, Fp2, Fp6, Fp12> = bls({
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(bls12_381.params.x).negate(); // [x]P
1129
- const u2P = xP.multiplyUnsafe(bls12_381.params.x); // [u2]P
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(bls12_381.params.x).add(point); // x*P + P
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(bls12_381.params.x).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
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 = bls12_381.params.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
- x: BLS_X, // The BLS parameter x for BLS12-381
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,