Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
fp2.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3  Implementation of arithmetic in the finite field F[p^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 FP2_TCC_
11 #define FP2_TCC_
12 
13 #include <libff/algebra/fields/field_utils.hpp>
14 
15 namespace libff
16 {
17 
18 template<mp_size_t n, const bigint<n> &modulus>
19 bool Fp2_model<n, modulus>::s_initialized = false;
20 
21 template<mp_size_t n, const bigint<n> &modulus>
22 Fp2_model<n, modulus> Fp2_model<n, modulus>::s_zero;
23 
24 template<mp_size_t n, const bigint<n> &modulus>
25 Fp2_model<n, modulus> Fp2_model<n, modulus>::s_one;
26 
27 template<mp_size_t n, const bigint<n> &modulus>
28 void Fp2_model<n, modulus>::static_init()
29 {
30  // This function may be entered several times, in particular where an
31  // individual field is shread between curves.
32  if (s_initialized) {
33  return;
34  }
35 
36  // Initialize s_zero and s_one
37  s_zero = Fp2_model<n, modulus>(my_Fp::zero(), my_Fp::zero());
38  s_one = Fp2_model<n, modulus>(my_Fp::one(), my_Fp::zero());
39  s_initialized = true;
40 }
41 
42 template<mp_size_t n, const bigint<n> &modulus>
43 const Fp2_model<n, modulus> &Fp2_model<n, modulus>::zero()
44 {
45  return s_zero;
46 }
47 
48 template<mp_size_t n, const bigint<n> &modulus>
49 const Fp2_model<n, modulus> &Fp2_model<n, modulus>::one()
50 {
51  return s_one;
52 }
53 
54 template<mp_size_t n, const bigint<n> &modulus>
55 Fp2_model<n, modulus> Fp2_model<n, modulus>::random_element()
56 {
57  Fp2_model<n, modulus> r;
58  r.coeffs[0] = my_Fp::random_element();
59  r.coeffs[1] = my_Fp::random_element();
60 
61  return r;
62 }
63 
64 template<mp_size_t n, const bigint<n> &modulus>
65 bool Fp2_model<n, modulus>::operator==(const Fp2_model<n, modulus> &other) const
66 {
67  return (
68  this->coeffs[0] == other.coeffs[0] &&
69  this->coeffs[1] == other.coeffs[1]);
70 }
71 
72 template<mp_size_t n, const bigint<n> &modulus>
73 bool Fp2_model<n, modulus>::operator!=(const Fp2_model<n, modulus> &other) const
74 {
75  return !(operator==(other));
76 }
77 
78 template<mp_size_t n, const bigint<n> &modulus>
79 Fp2_model<n, modulus> Fp2_model<n, modulus>::operator+(
80  const Fp2_model<n, modulus> &other) const
81 {
82  return Fp2_model<n, modulus>(
83  this->coeffs[0] + other.coeffs[0], this->coeffs[1] + other.coeffs[1]);
84 }
85 
86 template<mp_size_t n, const bigint<n> &modulus>
87 Fp2_model<n, modulus> Fp2_model<n, modulus>::operator-(
88  const Fp2_model<n, modulus> &other) const
89 {
90  return Fp2_model<n, modulus>(
91  this->coeffs[0] - other.coeffs[0], this->coeffs[1] - other.coeffs[1]);
92 }
93 
94 template<mp_size_t n, const bigint<n> &modulus>
95 Fp2_model<n, modulus> operator*(
96  const Fp_model<n, modulus> &lhs, const Fp2_model<n, modulus> &rhs)
97 {
98  return Fp2_model<n, modulus>(lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
99 }
100 
101 template<mp_size_t n, const bigint<n> &modulus>
102 Fp2_model<n, modulus> Fp2_model<n, modulus>::operator*(
103  const Fp2_model<n, modulus> &other) const
104 {
105  /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on
106  * Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */
107  const my_Fp &A = other.coeffs[0], &B = other.coeffs[1],
108  &a = this->coeffs[0], &b = this->coeffs[1];
109  const my_Fp aA = a * A;
110  const my_Fp bB = b * B;
111 
112  return Fp2_model<n, modulus>(
113  aA + non_residue * bB, (a + b) * (A + B) - aA - bB);
114 }
115 
116 template<mp_size_t n, const bigint<n> &modulus>
117 Fp2_model<n, modulus> Fp2_model<n, modulus>::operator-() const
118 {
119  return Fp2_model<n, modulus>(-this->coeffs[0], -this->coeffs[1]);
120 }
121 
122 template<mp_size_t n, const bigint<n> &modulus>
123 Fp2_model<n, modulus> Fp2_model<n, modulus>::squared() const
124 {
125  return squared_complex();
126 }
127 
128 template<mp_size_t n, const bigint<n> &modulus>
129 Fp2_model<n, modulus> Fp2_model<n, modulus>::squared_karatsuba() const
130 {
131  // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
132  // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring)
133  const my_Fp &a = this->coeffs[0], &b = this->coeffs[1];
134  const my_Fp asq = a.squared();
135  const my_Fp bsq = b.squared();
136 
137  return Fp2_model<n, modulus>(
138  asq + non_residue * bsq, (a + b).squared() - asq - bsq);
139 }
140 
141 template<mp_size_t n, const bigint<n> &modulus>
142 Fp2_model<n, modulus> Fp2_model<n, modulus>::squared_complex() const
143 {
144  // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
145  // Pairing-Friendly Fields.pdf; Section 3 (Complex squaring)
146  const my_Fp &a = this->coeffs[0], &b = this->coeffs[1];
147  const my_Fp ab = a * b;
148 
149  return Fp2_model<n, modulus>(
150  (a + b) * (a + non_residue * b) - ab - non_residue * ab, ab + ab);
151 }
152 
153 template<mp_size_t n, const bigint<n> &modulus>
154 Fp2_model<n, modulus> Fp2_model<n, modulus>::inverse() const
155 {
156  const my_Fp &a = this->coeffs[0], &b = this->coeffs[1];
157 
158  // From "High-Speed Software Implementation of the Optimal Ate Pairing over
159  // Barreto-Naehrig Curves"; Algorithm 8
160  const my_Fp t0 = a.squared();
161  const my_Fp t1 = b.squared();
162  const my_Fp t2 = t0 - non_residue * t1;
163  const my_Fp t3 = t2.inverse();
164  const my_Fp c0 = a * t3;
165  const my_Fp c1 = -(b * t3);
166 
167  return Fp2_model<n, modulus>(c0, c1);
168 }
169 
170 template<mp_size_t n, const bigint<n> &modulus>
171 Fp2_model<n, modulus> Fp2_model<n, modulus>::Frobenius_map(
172  unsigned long power) const
173 {
174  return Fp2_model<n, modulus>(
175  coeffs[0], Frobenius_coeffs_c1[power % 2] * coeffs[1]);
176 }
177 
178 template<mp_size_t n, const bigint<n> &modulus>
179 Fp2_model<n, modulus> Fp2_model<n, modulus>::sqrt() const
180 {
181  Fp2_model<n, modulus> one = Fp2_model<n, modulus>::one();
182 
183  size_t v = Fp2_model<n, modulus>::s;
184  Fp2_model<n, modulus> z = Fp2_model<n, modulus>::nqr_to_t;
185  Fp2_model<n, modulus> w = (*this) ^ Fp2_model<n, modulus>::t_minus_1_over_2;
186  Fp2_model<n, modulus> x = (*this) * w;
187  // b = (*this)^t
188  Fp2_model<n, modulus> b = x * w;
189 
190 #if DEBUG
191  // check if square with euler's criterion
192  Fp2_model<n, modulus> check = b;
193  for (size_t i = 0; i < v - 1; ++i) {
194  check = check.squared();
195  }
196  if (check != one) {
197  assert(0);
198  }
199 #endif
200 
201  // compute square root with Tonelli--Shanks (does not terminate if not a
202  // square!)
203 
204  while (b != one) {
205  size_t m = 0;
206  Fp2_model<n, modulus> b2m = b;
207  while (b2m != one) {
208  // invariant: b2m = b^(2^m) after entering this loop
209  b2m = b2m.squared();
210  m += 1;
211  }
212 
213  // w = z^2^(v-m-1)
214  int j = v - m - 1;
215  w = z;
216  while (j > 0) {
217  w = w.squared();
218  --j;
219  }
220 
221  z = w.squared();
222  b = b * z;
223  x = x * w;
224  v = m;
225  }
226 
227  return x;
228 }
229 
230 template<mp_size_t n, const bigint<n> &modulus>
231 template<mp_size_t m>
232 Fp2_model<n, modulus> Fp2_model<n, modulus>::operator^(
233  const bigint<m> &pow) const
234 {
235  return power<Fp2_model<n, modulus>, m>(*this, pow);
236 }
237 
238 template<mp_size_t n, const bigint<n> &modulus>
239 std::ostream &operator<<(std::ostream &out, const Fp2_model<n, modulus> &el)
240 {
241  out << el.coeffs[0] << el.coeffs[1];
242  return out;
243 }
244 
245 template<mp_size_t n, const bigint<n> &modulus>
246 std::istream &operator>>(std::istream &in, Fp2_model<n, modulus> &el)
247 {
248  in >> el.coeffs[0] >> el.coeffs[1];
249  return in;
250 }
251 
252 template<mp_size_t n, const bigint<n> &modulus>
253 std::ostream &operator<<(
254  std::ostream &out, const std::vector<Fp2_model<n, modulus>> &v)
255 {
256  out << v.size() << "\n";
257  for (const Fp2_model<n, modulus> &t : v) {
258  out << t << OUTPUT_NEWLINE;
259  }
260 
261  return out;
262 }
263 
264 template<mp_size_t n, const bigint<n> &modulus>
265 std::istream &operator>>(
266  std::istream &in, std::vector<Fp2_model<n, modulus>> &v)
267 {
268  v.clear();
269 
270  size_t s;
271  in >> s;
272 
273  char b;
274  in.read(&b, 1);
275 
276  v.reserve(s);
277 
278  for (size_t i = 0; i < s; ++i) {
279  Fp2_model<n, modulus> el;
280  in >> el;
281  v.emplace_back(el);
282  }
283 
284  return in;
285 }
286 
287 } // namespace libff
288 
289 #endif // FP2_TCC_