2 *****************************************************************************
3 Implementation of arithmetic in the finite field F[((p^2)^3)^2].
4 *****************************************************************************
5 * @author This file is part of libff, developed by SCIPR Lab
6 * and contributors (see AUTHORS).
7 * @copyright MIT license (see LICENSE file)
8 *****************************************************************************/
10 #ifndef FP12_2OVER3OVER2_TCC_
11 #define FP12_2OVER3OVER2_TCC_
16 template<mp_size_t n, const bigint<n> &modulus>
17 Fp6_3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
18 mul_by_non_residue(const Fp6_3over2_model<n, modulus> &elt)
20 return Fp6_3over2_model<n, modulus>(
21 non_residue * elt.coeffs[2], elt.coeffs[0], elt.coeffs[1]);
24 template<mp_size_t n, const bigint<n> &modulus>
25 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::zero()
27 return Fp12_2over3over2_model<n, modulus>(my_Fp6::zero(), my_Fp6::zero());
30 template<mp_size_t n, const bigint<n> &modulus>
31 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::one()
33 return Fp12_2over3over2_model<n, modulus>(my_Fp6::one(), my_Fp6::zero());
36 template<mp_size_t n, const bigint<n> &modulus>
37 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
40 Fp12_2over3over2_model<n, modulus> r;
41 r.coeffs[0] = my_Fp6::random_element();
42 r.coeffs[1] = my_Fp6::random_element();
47 template<mp_size_t n, const bigint<n> &modulus>
48 bool Fp12_2over3over2_model<n, modulus>::operator==(
49 const Fp12_2over3over2_model<n, modulus> &other) const
52 this->coeffs[0] == other.coeffs[0] &&
53 this->coeffs[1] == other.coeffs[1]);
56 template<mp_size_t n, const bigint<n> &modulus>
57 bool Fp12_2over3over2_model<n, modulus>::operator!=(
58 const Fp12_2over3over2_model<n, modulus> &other) const
60 return !(operator==(other));
63 template<mp_size_t n, const bigint<n> &modulus>
64 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
65 operator+(const Fp12_2over3over2_model<n, modulus> &other) const
67 return Fp12_2over3over2_model<n, modulus>(
68 this->coeffs[0] + other.coeffs[0], this->coeffs[1] + other.coeffs[1]);
71 template<mp_size_t n, const bigint<n> &modulus>
72 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
73 operator-(const Fp12_2over3over2_model<n, modulus> &other) const
75 return Fp12_2over3over2_model<n, modulus>(
76 this->coeffs[0] - other.coeffs[0], this->coeffs[1] - other.coeffs[1]);
79 template<mp_size_t n, const bigint<n> &modulus>
80 Fp12_2over3over2_model<n, modulus> operator*(
81 const Fp_model<n, modulus> &lhs,
82 const Fp12_2over3over2_model<n, modulus> &rhs)
84 return Fp12_2over3over2_model<n, modulus>(
85 lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
88 template<mp_size_t n, const bigint<n> &modulus>
89 Fp12_2over3over2_model<n, modulus> operator*(
90 const Fp2_model<n, modulus> &lhs,
91 const Fp12_2over3over2_model<n, modulus> &rhs)
93 return Fp12_2over3over2_model<n, modulus>(
94 lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
97 template<mp_size_t n, const bigint<n> &modulus>
98 Fp12_2over3over2_model<n, modulus> operator*(
99 const Fp6_3over2_model<n, modulus> &lhs,
100 const Fp12_2over3over2_model<n, modulus> &rhs)
102 return Fp12_2over3over2_model<n, modulus>(
103 lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
106 template<mp_size_t n, const bigint<n> &modulus>
107 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
108 operator*(const Fp12_2over3over2_model<n, modulus> &other) const
110 // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
111 // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba)
113 const my_Fp6 &A = other.coeffs[0], &B = other.coeffs[1],
114 &a = this->coeffs[0], &b = this->coeffs[1];
115 const my_Fp6 aA = a * A;
116 const my_Fp6 bB = b * B;
118 return Fp12_2over3over2_model<n, modulus>(
119 aA + Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(bB),
120 (a + b) * (A + B) - aA - bB);
123 template<mp_size_t n, const bigint<n> &modulus>
124 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
127 return Fp12_2over3over2_model<n, modulus>(
128 -this->coeffs[0], -this->coeffs[1]);
131 template<mp_size_t n, const bigint<n> &modulus>
132 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::squared()
135 return squared_complex();
138 template<mp_size_t n, const bigint<n> &modulus>
139 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
140 squared_karatsuba() const
142 // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
143 // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring)
145 const my_Fp6 &a = this->coeffs[0], &b = this->coeffs[1];
146 const my_Fp6 asq = a.squared();
147 const my_Fp6 bsq = b.squared();
149 return Fp12_2over3over2_model<n, modulus>(
150 asq + Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(bsq),
151 (a + b).squared() - asq - bsq);
154 template<mp_size_t n, const bigint<n> &modulus>
155 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
156 squared_complex() const
158 // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
159 // Pairing-Friendly Fields.pdf; Section 3 (Complex squaring)
161 const my_Fp6 &a = this->coeffs[0], &b = this->coeffs[1];
162 const my_Fp6 ab = a * b;
164 return Fp12_2over3over2_model<n, modulus>(
166 Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(b)) -
167 ab - Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(ab),
171 template<mp_size_t n, const bigint<n> &modulus>
172 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::inverse()
175 // From "High-Speed Software Implementation of the Optimal Ate Pairing over
176 // Barreto-Naehrig Curves"; Algorithm 8
178 const my_Fp6 &a = this->coeffs[0], &b = this->coeffs[1];
179 const my_Fp6 t0 = a.squared();
180 const my_Fp6 t1 = b.squared();
182 t0 - Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(t1);
183 const my_Fp6 t3 = t2.inverse();
184 const my_Fp6 c0 = a * t3;
185 const my_Fp6 c1 = -(b * t3);
187 return Fp12_2over3over2_model<n, modulus>(c0, c1);
190 template<mp_size_t n, const bigint<n> &modulus>
191 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
192 Frobenius_map(unsigned long power) const
194 return Fp12_2over3over2_model<n, modulus>(
195 coeffs[0].Frobenius_map(power),
196 Frobenius_coeffs_c1[power % 12] * coeffs[1].Frobenius_map(power));
199 template<mp_size_t n, const bigint<n> &modulus>
200 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
201 unitary_inverse() const
203 return Fp12_2over3over2_model<n, modulus>(
204 this->coeffs[0], -this->coeffs[1]);
207 template<mp_size_t n, const bigint<n> &modulus>
208 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
209 cyclotomic_squared() const
211 // OLD: naive implementation
212 // return (*this).squared();
213 my_Fp2 z0 = this->coeffs[0].coeffs[0];
214 my_Fp2 z4 = this->coeffs[0].coeffs[1];
215 my_Fp2 z3 = this->coeffs[0].coeffs[2];
216 my_Fp2 z2 = this->coeffs[1].coeffs[0];
217 my_Fp2 z1 = this->coeffs[1].coeffs[1];
218 my_Fp2 z5 = this->coeffs[1].coeffs[2];
220 my_Fp2 t0, t1, t2, t3, t4, t5, tmp;
222 // t0 + t1*y = (z0 + z1*y)^2 = a^2
224 t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp -
225 my_Fp6::non_residue * tmp;
227 // t2 + t3*y = (z2 + z3*y)^2 = b^2
229 t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp -
230 my_Fp6::non_residue * tmp;
232 // t4 + t5*y = (z4 + z5*y)^2 = c^2
234 t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp -
235 my_Fp6::non_residue * tmp;
240 // z0 = 3 * t0 - 2 * z0
244 // z1 = 3 * t1 + 2 * z1
251 // z2 = 3 * (xi * t5) + 2 * z2
252 tmp = my_Fp6::non_residue * t5;
257 // z3 = 3 * t4 - 2 * z3
264 // z4 = 3 * t2 - 2 * z4
269 // z5 = 3 * t3 + 2 * z5
274 return Fp12_2over3over2_model<n, modulus>(
275 my_Fp6(z0, z4, z3), my_Fp6(z2, z1, z5));
278 template<mp_size_t n, const bigint<n> &modulus>
279 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
281 const Fp2_model<n, modulus> &ell_0,
282 const Fp2_model<n, modulus> &ell_VW,
283 const Fp2_model<n, modulus> &ell_VV) const
285 my_Fp2 z0 = this->coeffs[0].coeffs[0];
286 my_Fp2 z1 = this->coeffs[0].coeffs[1];
287 my_Fp2 z2 = this->coeffs[0].coeffs[2];
288 my_Fp2 z3 = this->coeffs[1].coeffs[0];
289 my_Fp2 z4 = this->coeffs[1].coeffs[1];
290 my_Fp2 z5 = this->coeffs[1].coeffs[2];
296 my_Fp2 t0, t1, t2, t3, t4, t5;
299 tmp1 = my_Fp6::non_residue * x4;
300 tmp2 = my_Fp6::non_residue * x5;
302 t0 = x0 * z0 + tmp1 * z4 + tmp2 * z3;
303 t1 = x0 * z1 + tmp1 * z5 + tmp2 * z4;
304 t2 = x0 * z2 + x4 * z3 + tmp2 * z5;
305 t3 = x0 * z3 + tmp1 * z2 + tmp2 * z1;
306 t4 = x0 * z4 + x4 * z0 + tmp2 * z2;
307 t5 = x0 * z5 + x4 * z1 + x5 * z0;
309 return Fp12_2over3over2_model<n, modulus>(
310 my_Fp6(t0, t1, t2), my_Fp6(t3, t4, t5));
313 template<mp_size_t n, const bigint<n> &modulus>
314 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
316 const Fp2_model<n, modulus> &ell_0,
317 const Fp2_model<n, modulus> &ell_VW,
318 const Fp2_model<n, modulus> &ell_VV) const
320 // OLD: naive implementation
321 // Fp12_2over3over2_model<n,modulus> a(
322 // my_Fp6(ell_0, my_Fp2::zero(), ell_VV),
323 // my_Fp6(my_Fp2::zero(), ell_VW, my_Fp2::zero())
325 // return (*this) * a;
327 const my_Fp2 &z0 = this->coeffs[0].coeffs[0];
328 const my_Fp2 &z1 = this->coeffs[0].coeffs[1];
329 const my_Fp2 &z2 = this->coeffs[0].coeffs[2];
330 const my_Fp2 &z3 = this->coeffs[1].coeffs[0];
331 const my_Fp2 &z4 = this->coeffs[1].coeffs[1];
332 const my_Fp2 &z5 = this->coeffs[1].coeffs[2];
333 const my_Fp2 &x0 = ell_0;
334 const my_Fp2 &x2 = ell_VV;
335 const my_Fp2 &x4 = ell_VW;
337 // out_z0 = z0*x0 + non_residue * ( z1*x2 + z4*x4 )
338 const my_Fp2 z0_x0 = z0 * x0;
339 const my_Fp2 z1_x2 = z1 * x2;
340 const my_Fp2 z4_x4 = z4 * x4;
341 const my_Fp2 out_z0 = my_Fp6::non_residue * (z1_x2 + z4_x4) + z0_x0;
344 // out_z1 = z1*x0 + non_residue * ( z2*x2 + z5*x4 )
345 const my_Fp2 z2_x2 = z2 * x2;
346 const my_Fp2 z5_x4 = z5 * x4;
347 const my_Fp2 z1_x0 = z1 * x0;
348 const my_Fp2 out_z1 = my_Fp6::non_residue * (z5_x4 + z2_x2) + z1_x0;
352 // out_z2 = z0*x2 + z2*x0 + z3*x4
354 // z0*x2 + z2*x0 = (z0 + z2)*(x0 + x2) - z0*x0 - z2*x2
355 const my_Fp2 z0_x2_plus_z2_x0 = (z0 + z2) * (x0 + x2) - z0_x0 - z2_x2;
356 const my_Fp2 z3_x4 = z3 * x4;
357 const my_Fp2 out_z2 = z0_x2_plus_z2_x0 + z3_x4;
360 // out_z3 = z3*x0 + non_residue * (z2*x4 + z4*x2)
362 // z2*x4 + z4*x2 = (z2 + z4)*(x2 + x4) - z2*x2 - z4*x4
363 const my_Fp2 z2_x3_plus_z4_x2 = (z2 + z4) * (x2 + x4) - z2_x2 - z4_x4;
364 const my_Fp2 z3_x0 = z3 * x0;
365 const my_Fp2 out_z3 = my_Fp6::non_residue * z2_x3_plus_z4_x2 + z3_x0;
368 // out_z4 = z0*x4 + z4*x0 + non_residue * z5*x2
370 // z0*x4 + z4*x0 = (z0 + z4)*(x0 + x4) - z0*x0 - z4*x4
371 const my_Fp2 z0_x4_plus_z4_x0 = (z0 + z4) * (x0 + x4) - z0_x0 - z4_x4;
372 const my_Fp2 z5_x2 = z5 * x2;
373 const my_Fp2 out_z4 = my_Fp6::non_residue * z5_x2 + z0_x4_plus_z4_x0;
376 // out_z5 = z1*x4 + z3*x2 + z5*x0
377 // = (z1 + z3 + z5)*(x0 + x2 + x4)
378 // - z1_x0 - z1_x2 - z3_x0 - z3*x4 - z5_x2 - z5*x4
379 // = (z1 + z3 + z5)*(x0 + x2 + x4) - S
380 const my_Fp2 out_z5 = (z1 + z3 + z5) * (x0 + x2 + x4) - S;
382 return Fp12_2over3over2_model<n, modulus>(
383 my_Fp6(out_z0, out_z1, out_z2), my_Fp6(out_z3, out_z4, out_z5));
386 template<mp_size_t n, const bigint<n> &modulus, mp_size_t m>
387 Fp12_2over3over2_model<n, modulus> operator^(
388 const Fp12_2over3over2_model<n, modulus> &self, const bigint<m> &exponent)
390 return power<Fp12_2over3over2_model<n, modulus>>(self, exponent);
395 const bigint<n> &modulus,
397 const bigint<m> &exp_modulus>
398 Fp12_2over3over2_model<n, modulus> operator^(
399 const Fp12_2over3over2_model<n, modulus> &self,
400 const Fp_model<m, exp_modulus> &exponent)
402 return self ^ (exponent.as_bigint());
405 template<mp_size_t n, const bigint<n> &modulus>
406 template<mp_size_t m>
407 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
408 cyclotomic_exp(const bigint<m> &exponent) const
410 Fp12_2over3over2_model<n, modulus> res =
411 Fp12_2over3over2_model<n, modulus>::one();
413 bool found_one = false;
414 for (long i = m - 1; i >= 0; --i) {
415 for (long j = GMP_NUMB_BITS - 1; j >= 0; --j) {
417 res = res.cyclotomic_squared();
420 if (exponent.data[i] & (1ul << j)) {
430 template<mp_size_t n, const bigint<n> &modulus>
431 std::ostream &operator<<(
432 std::ostream &out, const Fp12_2over3over2_model<n, modulus> &el)
434 out << el.coeffs[0] << OUTPUT_SEPARATOR << el.coeffs[1];
438 template<mp_size_t n, const bigint<n> &modulus>
439 std::istream &operator>>(
440 std::istream &in, Fp12_2over3over2_model<n, modulus> &el)
442 in >> el.coeffs[0] >> el.coeffs[1];
446 template<mp_size_t n, const bigint<n> &modulus>
447 std::ostream &operator<<(
448 std::ostream &out, const std::vector<Fp12_2over3over2_model<n, modulus>> &v)
450 out << v.size() << "\n";
451 for (const Fp12_2over3over2_model<n, modulus> &t : v) {
452 out << t << OUTPUT_NEWLINE;
458 template<mp_size_t n, const bigint<n> &modulus>
459 std::istream &operator>>(
460 std::istream &in, std::vector<Fp12_2over3over2_model<n, modulus>> &v)
472 for (size_t i = 0; i < s; ++i) {
473 Fp12_2over3over2_model<n, modulus> el;
483 #endif // FP12_2OVER3OVER2_TCC_