Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
fp12_2over3over2.tcc
Go to the documentation of this file.
1 /** @file
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  *****************************************************************************/
9 
10 #ifndef FP12_2OVER3OVER2_TCC_
11 #define FP12_2OVER3OVER2_TCC_
12 
13 namespace libff
14 {
15 
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)
19 {
20  return Fp6_3over2_model<n, modulus>(
21  non_residue * elt.coeffs[2], elt.coeffs[0], elt.coeffs[1]);
22 }
23 
24 template<mp_size_t n, const bigint<n> &modulus>
25 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::zero()
26 {
27  return Fp12_2over3over2_model<n, modulus>(my_Fp6::zero(), my_Fp6::zero());
28 }
29 
30 template<mp_size_t n, const bigint<n> &modulus>
31 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::one()
32 {
33  return Fp12_2over3over2_model<n, modulus>(my_Fp6::one(), my_Fp6::zero());
34 }
35 
36 template<mp_size_t n, const bigint<n> &modulus>
37 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
38  random_element()
39 {
40  Fp12_2over3over2_model<n, modulus> r;
41  r.coeffs[0] = my_Fp6::random_element();
42  r.coeffs[1] = my_Fp6::random_element();
43 
44  return r;
45 }
46 
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
50 {
51  return (
52  this->coeffs[0] == other.coeffs[0] &&
53  this->coeffs[1] == other.coeffs[1]);
54 }
55 
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
59 {
60  return !(operator==(other));
61 }
62 
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
66 {
67  return Fp12_2over3over2_model<n, modulus>(
68  this->coeffs[0] + other.coeffs[0], this->coeffs[1] + other.coeffs[1]);
69 }
70 
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
74 {
75  return Fp12_2over3over2_model<n, modulus>(
76  this->coeffs[0] - other.coeffs[0], this->coeffs[1] - other.coeffs[1]);
77 }
78 
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)
83 {
84  return Fp12_2over3over2_model<n, modulus>(
85  lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
86 }
87 
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)
92 {
93  return Fp12_2over3over2_model<n, modulus>(
94  lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
95 }
96 
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)
101 {
102  return Fp12_2over3over2_model<n, modulus>(
103  lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
104 }
105 
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
109 {
110  // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
111  // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba)
112 
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;
117 
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);
121 }
122 
123 template<mp_size_t n, const bigint<n> &modulus>
124 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
125 operator-() const
126 {
127  return Fp12_2over3over2_model<n, modulus>(
128  -this->coeffs[0], -this->coeffs[1]);
129 }
130 
131 template<mp_size_t n, const bigint<n> &modulus>
132 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::squared()
133  const
134 {
135  return squared_complex();
136 }
137 
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
141 {
142  // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
143  // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring)
144 
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();
148 
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);
152 }
153 
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
157 {
158  // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
159  // Pairing-Friendly Fields.pdf; Section 3 (Complex squaring)
160 
161  const my_Fp6 &a = this->coeffs[0], &b = this->coeffs[1];
162  const my_Fp6 ab = a * b;
163 
164  return Fp12_2over3over2_model<n, modulus>(
165  (a + b) * (a +
166  Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(b)) -
167  ab - Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(ab),
168  ab + ab);
169 }
170 
171 template<mp_size_t n, const bigint<n> &modulus>
172 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::inverse()
173  const
174 {
175  // From "High-Speed Software Implementation of the Optimal Ate Pairing over
176  // Barreto-Naehrig Curves"; Algorithm 8
177 
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();
181  const my_Fp6 t2 =
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);
186 
187  return Fp12_2over3over2_model<n, modulus>(c0, c1);
188 }
189 
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
193 {
194  return Fp12_2over3over2_model<n, modulus>(
195  coeffs[0].Frobenius_map(power),
196  Frobenius_coeffs_c1[power % 12] * coeffs[1].Frobenius_map(power));
197 }
198 
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
202 {
203  return Fp12_2over3over2_model<n, modulus>(
204  this->coeffs[0], -this->coeffs[1]);
205 }
206 
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
210 {
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];
219 
220  my_Fp2 t0, t1, t2, t3, t4, t5, tmp;
221 
222  // t0 + t1*y = (z0 + z1*y)^2 = a^2
223  tmp = z0 * z1;
224  t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp -
225  my_Fp6::non_residue * tmp;
226  t1 = tmp + tmp;
227  // t2 + t3*y = (z2 + z3*y)^2 = b^2
228  tmp = z2 * z3;
229  t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp -
230  my_Fp6::non_residue * tmp;
231  t3 = tmp + tmp;
232  // t4 + t5*y = (z4 + z5*y)^2 = c^2
233  tmp = z4 * z5;
234  t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp -
235  my_Fp6::non_residue * tmp;
236  t5 = tmp + tmp;
237 
238  // for A
239 
240  // z0 = 3 * t0 - 2 * z0
241  z0 = t0 - z0;
242  z0 = z0 + z0;
243  z0 = z0 + t0;
244  // z1 = 3 * t1 + 2 * z1
245  z1 = t1 + z1;
246  z1 = z1 + z1;
247  z1 = z1 + t1;
248 
249  // for B
250 
251  // z2 = 3 * (xi * t5) + 2 * z2
252  tmp = my_Fp6::non_residue * t5;
253  z2 = tmp + z2;
254  z2 = z2 + z2;
255  z2 = z2 + tmp;
256 
257  // z3 = 3 * t4 - 2 * z3
258  z3 = t4 - z3;
259  z3 = z3 + z3;
260  z3 = z3 + t4;
261 
262  // for C
263 
264  // z4 = 3 * t2 - 2 * z4
265  z4 = t2 - z4;
266  z4 = z4 + z4;
267  z4 = z4 + t2;
268 
269  // z5 = 3 * t3 + 2 * z5
270  z5 = t3 + z5;
271  z5 = z5 + z5;
272  z5 = z5 + t3;
273 
274  return Fp12_2over3over2_model<n, modulus>(
275  my_Fp6(z0, z4, z3), my_Fp6(z2, z1, z5));
276 }
277 
278 template<mp_size_t n, const bigint<n> &modulus>
279 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
280  mul_by_045(
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
284 {
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];
291 
292  my_Fp2 x0 = ell_VW;
293  my_Fp2 x4 = ell_0;
294  my_Fp2 x5 = ell_VV;
295 
296  my_Fp2 t0, t1, t2, t3, t4, t5;
297  my_Fp2 tmp1, tmp2;
298 
299  tmp1 = my_Fp6::non_residue * x4;
300  tmp2 = my_Fp6::non_residue * x5;
301 
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;
308 
309  return Fp12_2over3over2_model<n, modulus>(
310  my_Fp6(t0, t1, t2), my_Fp6(t3, t4, t5));
311 }
312 
313 template<mp_size_t n, const bigint<n> &modulus>
314 Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::
315  mul_by_024(
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
319 {
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())
324  // );
325  // return (*this) * a;
326 
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;
336 
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;
342  my_Fp2 S = z1_x2;
343 
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;
349  S = S + z1_x0;
350  S = S + z5_x4;
351 
352  // out_z2 = z0*x2 + z2*x0 + z3*x4
353  // where:
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;
358  S = S + z3_x4;
359 
360  // out_z3 = z3*x0 + non_residue * (z2*x4 + z4*x2)
361  // where:
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;
366  S = S + z3_x0;
367 
368  // out_z4 = z0*x4 + z4*x0 + non_residue * z5*x2
369  // where:
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;
374  S = S + z5_x2;
375 
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;
381 
382  return Fp12_2over3over2_model<n, modulus>(
383  my_Fp6(out_z0, out_z1, out_z2), my_Fp6(out_z3, out_z4, out_z5));
384 }
385 
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)
389 {
390  return power<Fp12_2over3over2_model<n, modulus>>(self, exponent);
391 }
392 
393 template<
394  mp_size_t n,
395  const bigint<n> &modulus,
396  mp_size_t m,
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)
401 {
402  return self ^ (exponent.as_bigint());
403 }
404 
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
409 {
410  Fp12_2over3over2_model<n, modulus> res =
411  Fp12_2over3over2_model<n, modulus>::one();
412 
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) {
416  if (found_one) {
417  res = res.cyclotomic_squared();
418  }
419 
420  if (exponent.data[i] & (1ul << j)) {
421  found_one = true;
422  res = res * (*this);
423  }
424  }
425  }
426 
427  return res;
428 }
429 
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)
433 {
434  out << el.coeffs[0] << OUTPUT_SEPARATOR << el.coeffs[1];
435  return out;
436 }
437 
438 template<mp_size_t n, const bigint<n> &modulus>
439 std::istream &operator>>(
440  std::istream &in, Fp12_2over3over2_model<n, modulus> &el)
441 {
442  in >> el.coeffs[0] >> el.coeffs[1];
443  return in;
444 }
445 
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)
449 {
450  out << v.size() << "\n";
451  for (const Fp12_2over3over2_model<n, modulus> &t : v) {
452  out << t << OUTPUT_NEWLINE;
453  }
454 
455  return out;
456 }
457 
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)
461 {
462  v.clear();
463 
464  size_t s;
465  in >> s;
466 
467  char b;
468  in.read(&b, 1);
469 
470  v.reserve(s);
471 
472  for (size_t i = 0; i < s; ++i) {
473  Fp12_2over3over2_model<n, modulus> el;
474  in >> el;
475  v.emplace_back(el);
476  }
477 
478  return in;
479 }
480 
481 } // namespace libff
482 
483 #endif // FP12_2OVER3OVER2_TCC_