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 *****************************************************************************/
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>
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)
22 return Fp3_model<n, modulus>(
23 non_residue * elem.coeffs[2], elem.coeffs[0], elem.coeffs[1]);
26 template<mp_size_t n, const bigint<n> &modulus>
27 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::zero()
29 return Fp6_2over3_model<n, modulus>(my_Fp3::zero(), my_Fp3::zero());
32 template<mp_size_t n, const bigint<n> &modulus>
33 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::one()
35 return Fp6_2over3_model<n, modulus>(my_Fp3::one(), my_Fp3::zero());
38 template<mp_size_t n, const bigint<n> &modulus>
39 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::random_element()
41 Fp6_2over3_model<n, modulus> r;
42 r.coeffs[0] = my_Fp3::random_element();
43 r.coeffs[1] = my_Fp3::random_element();
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
53 this->coeffs[0] == other.coeffs[0] &&
54 this->coeffs[1] == other.coeffs[1]);
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
61 return !(operator==(other));
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
68 return Fp6_2over3_model<n, modulus>(
69 this->coeffs[0] + other.coeffs[0], this->coeffs[1] + other.coeffs[1]);
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
76 return Fp6_2over3_model<n, modulus>(
77 this->coeffs[0] - other.coeffs[0], this->coeffs[1] - other.coeffs[1]);
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)
84 return Fp6_2over3_model<n, modulus>(
85 lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
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
92 // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
93 // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba)
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);
101 return Fp6_2over3_model<n, modulus>(
102 aA + beta_bB, (a + b) * (A + B) - aA - bB);
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
112 // Fp6_2over3_model<n,modulus> a(
113 // my_Fp3(ell_VW, my_Fp::zero(), my_Fp::zero()),
114 // my_Fp3(my_Fp::zero(),
117 // return (*this) * a;
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];
130 my_Fp t0, t1, t2, t3, t4, t5;
133 tmp1 = my_Fp3::non_residue * x4;
134 tmp2 = my_Fp3::non_residue * x5;
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;
143 return Fp6_2over3_model<n, modulus>(my_Fp3(t0, t1, t2), my_Fp3(t3, t4, t5));
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
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());
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);
164 return Fp6_2over3_model<n, modulus>(
165 aA + beta_bB, (a + b) * (A + B) - aA - bB);
168 template<mp_size_t n, const bigint<n> &modulus>
169 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::operator-() const
171 return Fp6_2over3_model<n, modulus>(-this->coeffs[0], -this->coeffs[1]);
174 template<mp_size_t n, const bigint<n> &modulus>
175 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::squared() const
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;
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),
188 template<mp_size_t n, const bigint<n> &modulus>
189 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::inverse() const
191 // From "High-Speed Software Implementation of the Optimal Ate Pairing over
192 // Barreto-Naehrig Curves"; Algorithm 8
194 const my_Fp3 &b = this->coeffs[1], &a = this->coeffs[0];
195 const my_Fp3 t1 = b.squared();
197 a.squared() - Fp6_2over3_model<n, modulus>::mul_by_non_residue(t1);
198 const my_Fp3 new_t1 = t0.inverse();
200 return Fp6_2over3_model<n, modulus>(a * new_t1, -(b * new_t1));
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
207 return Fp6_2over3_model<n, modulus>(
208 coeffs[0].Frobenius_map(power),
209 Frobenius_coeffs_c1[power % 6] * coeffs[1].Frobenius_map(power));
212 template<mp_size_t n, const bigint<n> &modulus>
213 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::unitary_inverse()
216 return Fp6_2over3_model<n, modulus>(this->coeffs[0], -this->coeffs[1]);
219 template<mp_size_t n, const bigint<n> &modulus>
220 Fp6_2over3_model<n, modulus> Fp6_2over3_model<n, modulus>::cyclotomic_squared()
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];
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];
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];
235 my_Fp2 asq = a.squared();
236 my_Fp2 bsq = b.squared();
237 my_Fp2 csq = c.squared();
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];
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;
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];
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];
266 // e0 = Fp3([A[0],C[0],B[1]])
267 // e1 = Fp3([B[0],A[1],C[1]])
268 // fin = Fp6e([e0,e1])
271 return Fp6_2over3_model<n, modulus>(
272 my_Fp3(A_a, C_a, B_b), my_Fp3(B_a, A_b, C_b));
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
280 Fp6_2over3_model<n, modulus> res = Fp6_2over3_model<n, modulus>::one();
281 Fp6_2over3_model<n, modulus> this_inverse = this->unitary_inverse();
283 bool found_nonzero = false;
284 std::vector<long> NAF = find_wnaf(1, exponent);
286 for (long i = static_cast<long>(NAF.size() - 1); i >= 0; --i) {
288 res = res.cyclotomic_squared();
292 found_nonzero = true;
297 res = res * this_inverse;
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)
309 out << el.coeffs[0] << OUTPUT_SEPARATOR << el.coeffs[1];
313 template<mp_size_t n, const bigint<n> &modulus>
314 std::istream &operator>>(std::istream &in, Fp6_2over3_model<n, modulus> &el)
316 in >> el.coeffs[0] >> el.coeffs[1];
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)
324 return power<Fp6_2over3_model<n, modulus>, m>(self, exponent);
329 const bigint<n> &modulus,
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)
336 return self ^ (exponent.as_bigint());
341 #endif // FP6_2OVER3_TCC_