Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
fp6_2over3.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3  Implementation of arithmetic in the finite field F[(p^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 FP6_2OVER3_TCC_
11 #define FP6_2OVER3_TCC_
12 #include <libff/algebra/fields/field_utils.hpp>
13 #include <libff/algebra/scalar_multiplication/wnaf.hpp>
14 
15 namespace libff
16 {
17 
18 template<mp_size_t n, const bigint<n> &modulus>
19 Fp3_model<n, modulus> Fp6_2over3_model<n, modulus>::mul_by_non_residue(
20  const Fp3_model<n, modulus> &elem)
21 {
22  return Fp3_model<n, modulus>(
23  non_residue * elem.coeffs[2], elem.coeffs[0], elem.coeffs[1]);
24 }
25 
26 template<mp_size_t n, const bigint<n> &modulus>
27 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::zero()
28 {
29  return Fp6_2over3_model<n, modulus>(my_Fp3::zero(), my_Fp3::zero());
30 }
31 
32 template<mp_size_t n, const bigint<n> &modulus>
33 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::one()
34 {
35  return Fp6_2over3_model<n, modulus>(my_Fp3::one(), my_Fp3::zero());
36 }
37 
38 template<mp_size_t n, const bigint<n> &modulus>
39 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::random_element()
40 {
41  Fp6_2over3_model<n, modulus> r;
42  r.coeffs[0] = my_Fp3::random_element();
43  r.coeffs[1] = my_Fp3::random_element();
44 
45  return r;
46 }
47 
48 template<mp_size_t n, const bigint<n> &modulus>
49 bool Fp6_2over3_model<n, modulus>::operator==(
50  const Fp6_2over3_model<n, modulus> &other) const
51 {
52  return (
53  this->coeffs[0] == other.coeffs[0] &&
54  this->coeffs[1] == other.coeffs[1]);
55 }
56 
57 template<mp_size_t n, const bigint<n> &modulus>
58 bool Fp6_2over3_model<n, modulus>::operator!=(
59  const Fp6_2over3_model<n, modulus> &other) const
60 {
61  return !(operator==(other));
62 }
63 
64 template<mp_size_t n, const bigint<n> &modulus>
65 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::operator+(
66  const Fp6_2over3_model<n, modulus> &other) const
67 {
68  return Fp6_2over3_model<n, modulus>(
69  this->coeffs[0] + other.coeffs[0], this->coeffs[1] + other.coeffs[1]);
70 }
71 
72 template<mp_size_t n, const bigint<n> &modulus>
73 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::operator-(
74  const Fp6_2over3_model<n, modulus> &other) const
75 {
76  return Fp6_2over3_model<n, modulus>(
77  this->coeffs[0] - other.coeffs[0], this->coeffs[1] - other.coeffs[1]);
78 }
79 
80 template<mp_size_t n, const bigint<n> &modulus>
81 Fp6_2over3_model<n, modulus> operator*(
82  const Fp_model<n, modulus> &lhs, const Fp6_2over3_model<n, modulus> &rhs)
83 {
84  return Fp6_2over3_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 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::operator*(
90  const Fp6_2over3_model<n, modulus> &other) const
91 {
92  // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
93  // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba)
94 
95  const my_Fp3 &B = other.coeffs[1], &A = other.coeffs[0],
96  &b = this->coeffs[1], &a = this->coeffs[0];
97  const my_Fp3 aA = a * A;
98  const my_Fp3 bB = b * B;
99  const my_Fp3 beta_bB = Fp6_2over3_model<n, modulus>::mul_by_non_residue(bB);
100 
101  return Fp6_2over3_model<n, modulus>(
102  aA + beta_bB, (a + b) * (A + B) - aA - bB);
103 }
104 
105 template<mp_size_t n, const bigint<n> &modulus>
106 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::mul_by_045(
107  const Fp_model<n, modulus> &ell_0,
108  const Fp_model<n, modulus> &ell_VW,
109  const Fp_model<n, modulus> &ell_VV) const
110 {
111  // OLD
112  // Fp6_2over3_model<n,modulus> a(
113  // my_Fp3(ell_VW, my_Fp::zero(), my_Fp::zero()),
114  // my_Fp3(my_Fp::zero(),
115  // ell_0,
116  // ell_VV));
117  // return (*this) * a;
118 
119  my_Fp z0 = this->coeffs[0].coeffs[0];
120  my_Fp z1 = this->coeffs[0].coeffs[1];
121  my_Fp z2 = this->coeffs[0].coeffs[2];
122  my_Fp z3 = this->coeffs[1].coeffs[0];
123  my_Fp z4 = this->coeffs[1].coeffs[1];
124  my_Fp z5 = this->coeffs[1].coeffs[2];
125 
126  my_Fp x0 = ell_VW;
127  my_Fp x4 = ell_0;
128  my_Fp x5 = ell_VV;
129 
130  my_Fp t0, t1, t2, t3, t4, t5;
131  my_Fp tmp1, tmp2;
132 
133  tmp1 = my_Fp3::non_residue * x4;
134  tmp2 = my_Fp3::non_residue * x5;
135 
136  t0 = x0 * z0 + tmp1 * z4 + tmp2 * z3;
137  t1 = x0 * z1 + tmp1 * z5 + tmp2 * z4;
138  t2 = x0 * z2 + x4 * z3 + tmp2 * z5;
139  t3 = x0 * z3 + tmp1 * z2 + tmp2 * z1;
140  t4 = x0 * z4 + x4 * z0 + tmp2 * z2;
141  t5 = x0 * z5 + x4 * z1 + x5 * z0;
142 
143  return Fp6_2over3_model<n, modulus>(my_Fp3(t0, t1, t2), my_Fp3(t3, t4, t5));
144 }
145 
146 template<mp_size_t n, const bigint<n> &modulus>
147 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::mul_by_2345(
148  const Fp6_2over3_model<n, modulus> &other) const
149 {
150  // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
151  // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba)
152  assert(other.coeffs[0].coeffs[0].is_zero());
153  assert(other.coeffs[0].coeffs[1].is_zero());
154 
155  const my_Fp3 &B = other.coeffs[1], &A = other.coeffs[0],
156  &b = this->coeffs[1], &a = this->coeffs[0];
157  const my_Fp3 aA = my_Fp3(
158  a.coeffs[1] * A.coeffs[2] * non_residue,
159  a.coeffs[2] * A.coeffs[2] * non_residue,
160  a.coeffs[0] * A.coeffs[2]);
161  const my_Fp3 bB = b * B;
162  const my_Fp3 beta_bB = Fp6_2over3_model<n, modulus>::mul_by_non_residue(bB);
163 
164  return Fp6_2over3_model<n, modulus>(
165  aA + beta_bB, (a + b) * (A + B) - aA - bB);
166 }
167 
168 template<mp_size_t n, const bigint<n> &modulus>
169 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::operator-() const
170 {
171  return Fp6_2over3_model<n, modulus>(-this->coeffs[0], -this->coeffs[1]);
172 }
173 
174 template<mp_size_t n, const bigint<n> &modulus>
175 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::squared() const
176 {
177  // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
178  // Pairing-Friendly Fields.pdf; Section 3 (Complex)
179  const my_Fp3 &b = this->coeffs[1], &a = this->coeffs[0];
180  const my_Fp3 ab = a * b;
181 
182  return Fp6_2over3_model<n, modulus>(
183  (a + b) * (a + Fp6_2over3_model<n, modulus>::mul_by_non_residue(b)) -
184  ab - Fp6_2over3_model<n, modulus>::mul_by_non_residue(ab),
185  ab + ab);
186 }
187 
188 template<mp_size_t n, const bigint<n> &modulus>
189 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::inverse() const
190 {
191  // From "High-Speed Software Implementation of the Optimal Ate Pairing over
192  // Barreto-Naehrig Curves"; Algorithm 8
193 
194  const my_Fp3 &b = this->coeffs[1], &a = this->coeffs[0];
195  const my_Fp3 t1 = b.squared();
196  const my_Fp3 t0 =
197  a.squared() - Fp6_2over3_model<n, modulus>::mul_by_non_residue(t1);
198  const my_Fp3 new_t1 = t0.inverse();
199 
200  return Fp6_2over3_model<n, modulus>(a * new_t1, -(b * new_t1));
201 }
202 
203 template<mp_size_t n, const bigint<n> &modulus>
204 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::Frobenius_map(
205  unsigned long power) const
206 {
207  return Fp6_2over3_model<n, modulus>(
208  coeffs[0].Frobenius_map(power),
209  Frobenius_coeffs_c1[power % 6] * coeffs[1].Frobenius_map(power));
210 }
211 
212 template<mp_size_t n, const bigint<n> &modulus>
213 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::unitary_inverse()
214  const
215 {
216  return Fp6_2over3_model<n, modulus>(this->coeffs[0], -this->coeffs[1]);
217 }
218 
219 template<mp_size_t n, const bigint<n> &modulus>
220 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::cyclotomic_squared()
221  const
222 {
223  my_Fp2 a = my_Fp2(coeffs[0].coeffs[0], coeffs[1].coeffs[1]);
224  // my_Fp a_a = c0.coeffs[0]; // a = Fp2([c0[0],c1[1]])
225  // my_Fp a_b = c1.coeffs[1];
226 
227  my_Fp2 b = my_Fp2(coeffs[1].coeffs[0], coeffs[0].coeffs[2]);
228  // my_Fp b_a = c1.coeffs[0]; // b = Fp2([c1[0],c0[2]])
229  // my_Fp b_b = c0.coeffs[2];
230 
231  my_Fp2 c = my_Fp2(coeffs[0].coeffs[1], coeffs[1].coeffs[2]);
232  // my_Fp c_a = c0.coeffs[1]; // c = Fp2([c0[1],c1[2]])
233  // my_Fp c_b = c1.coeffs[2];
234 
235  my_Fp2 asq = a.squared();
236  my_Fp2 bsq = b.squared();
237  my_Fp2 csq = c.squared();
238 
239  // A = vector(3*a^2 - 2*Fp2([vector(a)[0],-vector(a)[1]]))
240  // my_Fp A_a = my_Fp(3l) * asq_a - my_Fp(2l) * a_a;
241  my_Fp A_a = asq.coeffs[0] - a.coeffs[0];
242  A_a = A_a + A_a + asq.coeffs[0];
243  // my_Fp A_b = my_Fp(3l) * asq_b + my_Fp(2l) * a_b;
244  my_Fp A_b = asq.coeffs[1] + a.coeffs[1];
245  A_b = A_b + A_b + asq.coeffs[1];
246 
247  // B = vector(3*Fp2([non_residue*c2[1],c2[0]]) +
248  // 2*Fp2([vector(b)[0],-vector(b)[1]])) my_Fp B_a = my_Fp(3l) *
249  // my_Fp3::non_residue * csq_b + my_Fp(2l) * b_a;
250  my_Fp B_tmp = my_Fp3::non_residue * csq.coeffs[1];
251  my_Fp B_a = B_tmp + b.coeffs[0];
252  B_a = B_a + B_a + B_tmp;
253 
254  // my_Fp B_b = my_Fp(3l) * csq_a - my_Fp(2l) * b_b;
255  my_Fp B_b = csq.coeffs[0] - b.coeffs[1];
256  B_b = B_b + B_b + csq.coeffs[0];
257 
258  // C = vector(3*b^2 - 2*Fp2([vector(c)[0],-vector(c)[1]]))
259  // my_Fp C_a = my_Fp(3l) * bsq_a - my_Fp(2l) * c_a;
260  my_Fp C_a = bsq.coeffs[0] - c.coeffs[0];
261  C_a = C_a + C_a + bsq.coeffs[0];
262  // my_Fp C_b = my_Fp(3l) * bsq_b + my_Fp(2l) * c_b;
263  my_Fp C_b = bsq.coeffs[1] + c.coeffs[1];
264  C_b = C_b + C_b + bsq.coeffs[1];
265 
266  // e0 = Fp3([A[0],C[0],B[1]])
267  // e1 = Fp3([B[0],A[1],C[1]])
268  // fin = Fp6e([e0,e1])
269  // return fin
270 
271  return Fp6_2over3_model<n, modulus>(
272  my_Fp3(A_a, C_a, B_b), my_Fp3(B_a, A_b, C_b));
273 }
274 
275 template<mp_size_t n, const bigint<n> &modulus>
276 template<mp_size_t m>
277 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::cyclotomic_exp(
278  const bigint<m> &exponent) const
279 {
280  Fp6_2over3_model<n, modulus> res = Fp6_2over3_model<n, modulus>::one();
281  Fp6_2over3_model<n, modulus> this_inverse = this->unitary_inverse();
282 
283  bool found_nonzero = false;
284  std::vector<long> NAF = find_wnaf(1, exponent);
285 
286  for (long i = static_cast<long>(NAF.size() - 1); i >= 0; --i) {
287  if (found_nonzero) {
288  res = res.cyclotomic_squared();
289  }
290 
291  if (NAF[i] != 0) {
292  found_nonzero = true;
293 
294  if (NAF[i] > 0) {
295  res = res * (*this);
296  } else {
297  res = res * this_inverse;
298  }
299  }
300  }
301 
302  return res;
303 }
304 
305 template<mp_size_t n, const bigint<n> &modulus>
306 std::ostream &operator<<(
307  std::ostream &out, const Fp6_2over3_model<n, modulus> &el)
308 {
309  out << el.coeffs[0] << OUTPUT_SEPARATOR << el.coeffs[1];
310  return out;
311 }
312 
313 template<mp_size_t n, const bigint<n> &modulus>
314 std::istream &operator>>(std::istream &in, Fp6_2over3_model<n, modulus> &el)
315 {
316  in >> el.coeffs[0] >> el.coeffs[1];
317  return in;
318 }
319 
320 template<mp_size_t n, const bigint<n> &modulus, mp_size_t m>
321 Fp6_2over3_model<n, modulus> operator^(
322  const Fp6_2over3_model<n, modulus> &self, const bigint<m> &exponent)
323 {
324  return power<Fp6_2over3_model<n, modulus>, m>(self, exponent);
325 }
326 
327 template<
328  mp_size_t n,
329  const bigint<n> &modulus,
330  mp_size_t m,
331  const bigint<m> &exp_modulus>
332 Fp6_2over3_model<n, modulus> operator^(
333  const Fp6_2over3_model<n, modulus> &self,
334  const Fp_model<m, exp_modulus> &exponent)
335 {
336  return self ^ (exponent.as_bigint());
337 }
338 
339 } // namespace libff
340 
341 #endif // FP6_2OVER3_TCC_