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 *****************************************************************************/
13 #include <libff/algebra/fields/field_utils.hpp>
18 template<mp_size_t n, const bigint<n> &modulus>
19 bool Fp2_model<n, modulus>::s_initialized = false;
21 template<mp_size_t n, const bigint<n> &modulus>
22 Fp2_model<n, modulus> Fp2_model<n, modulus>::s_zero;
24 template<mp_size_t n, const bigint<n> &modulus>
25 Fp2_model<n, modulus> Fp2_model<n, modulus>::s_one;
27 template<mp_size_t n, const bigint<n> &modulus>
28 void Fp2_model<n, modulus>::static_init()
30 // This function may be entered several times, in particular where an
31 // individual field is shread between curves.
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());
42 template<mp_size_t n, const bigint<n> &modulus>
43 const Fp2_model<n, modulus> &Fp2_model<n, modulus>::zero()
48 template<mp_size_t n, const bigint<n> &modulus>
49 const Fp2_model<n, modulus> &Fp2_model<n, modulus>::one()
54 template<mp_size_t n, const bigint<n> &modulus>
55 Fp2_model<n, modulus> Fp2_model<n, modulus>::random_element()
57 Fp2_model<n, modulus> r;
58 r.coeffs[0] = my_Fp::random_element();
59 r.coeffs[1] = my_Fp::random_element();
64 template<mp_size_t n, const bigint<n> &modulus>
65 bool Fp2_model<n, modulus>::operator==(const Fp2_model<n, modulus> &other) const
68 this->coeffs[0] == other.coeffs[0] &&
69 this->coeffs[1] == other.coeffs[1]);
72 template<mp_size_t n, const bigint<n> &modulus>
73 bool Fp2_model<n, modulus>::operator!=(const Fp2_model<n, modulus> &other) const
75 return !(operator==(other));
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
82 return Fp2_model<n, modulus>(
83 this->coeffs[0] + other.coeffs[0], this->coeffs[1] + other.coeffs[1]);
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
90 return Fp2_model<n, modulus>(
91 this->coeffs[0] - other.coeffs[0], this->coeffs[1] - other.coeffs[1]);
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)
98 return Fp2_model<n, modulus>(lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
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
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;
112 return Fp2_model<n, modulus>(
113 aA + non_residue * bB, (a + b) * (A + B) - aA - bB);
116 template<mp_size_t n, const bigint<n> &modulus>
117 Fp2_model<n, modulus> Fp2_model<n, modulus>::operator-() const
119 return Fp2_model<n, modulus>(-this->coeffs[0], -this->coeffs[1]);
122 template<mp_size_t n, const bigint<n> &modulus>
123 Fp2_model<n, modulus> Fp2_model<n, modulus>::squared() const
125 return squared_complex();
128 template<mp_size_t n, const bigint<n> &modulus>
129 Fp2_model<n, modulus> Fp2_model<n, modulus>::squared_karatsuba() const
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();
137 return Fp2_model<n, modulus>(
138 asq + non_residue * bsq, (a + b).squared() - asq - bsq);
141 template<mp_size_t n, const bigint<n> &modulus>
142 Fp2_model<n, modulus> Fp2_model<n, modulus>::squared_complex() const
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;
149 return Fp2_model<n, modulus>(
150 (a + b) * (a + non_residue * b) - ab - non_residue * ab, ab + ab);
153 template<mp_size_t n, const bigint<n> &modulus>
154 Fp2_model<n, modulus> Fp2_model<n, modulus>::inverse() const
156 const my_Fp &a = this->coeffs[0], &b = this->coeffs[1];
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);
167 return Fp2_model<n, modulus>(c0, c1);
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
174 return Fp2_model<n, modulus>(
175 coeffs[0], Frobenius_coeffs_c1[power % 2] * coeffs[1]);
178 template<mp_size_t n, const bigint<n> &modulus>
179 Fp2_model<n, modulus> Fp2_model<n, modulus>::sqrt() const
181 Fp2_model<n, modulus> one = Fp2_model<n, modulus>::one();
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;
188 Fp2_model<n, modulus> b = x * w;
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();
201 // compute square root with Tonelli--Shanks (does not terminate if not a
206 Fp2_model<n, modulus> b2m = b;
208 // invariant: b2m = b^(2^m) after entering this loop
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
235 return power<Fp2_model<n, modulus>, m>(*this, pow);
238 template<mp_size_t n, const bigint<n> &modulus>
239 std::ostream &operator<<(std::ostream &out, const Fp2_model<n, modulus> &el)
241 out << el.coeffs[0] << el.coeffs[1];
245 template<mp_size_t n, const bigint<n> &modulus>
246 std::istream &operator>>(std::istream &in, Fp2_model<n, modulus> &el)
248 in >> el.coeffs[0] >> el.coeffs[1];
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)
256 out << v.size() << "\n";
257 for (const Fp2_model<n, modulus> &t : v) {
258 out << t << OUTPUT_NEWLINE;
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)
278 for (size_t i = 0; i < s; ++i) {
279 Fp2_model<n, modulus> el;