2 *****************************************************************************
4 Implementation of interfaces for the (extension) field Fp4.
8 *****************************************************************************
9 * @author This file is part of libff, developed by SCIPR Lab
10 * and contributors (see AUTHORS).
11 * @copyright MIT license (see LICENSE file)
12 *****************************************************************************/
17 #include <libff/algebra/fields/field_utils.hpp>
18 #include <libff/algebra/scalar_multiplication/wnaf.hpp>
23 template<mp_size_t n, const bigint<n> &modulus>
24 Fp2_model<n, modulus> Fp4_model<n, modulus>::mul_by_non_residue(
25 const Fp2_model<n, modulus> &elt)
27 return Fp2_model<n, modulus>(non_residue * elt.coeffs[1], elt.coeffs[0]);
30 template<mp_size_t n, const bigint<n> &modulus>
31 Fp4_model<n, modulus> Fp4_model<n, modulus>::zero()
33 return Fp4_model<n, modulus>(my_Fp2::zero(), my_Fp2::zero());
36 template<mp_size_t n, const bigint<n> &modulus>
37 Fp4_model<n, modulus> Fp4_model<n, modulus>::one()
39 return Fp4_model<n, modulus>(my_Fp2::one(), my_Fp2::zero());
42 template<mp_size_t n, const bigint<n> &modulus>
43 Fp4_model<n, modulus> Fp4_model<n, modulus>::random_element()
45 Fp4_model<n, modulus> r;
46 r.coeffs[0] = my_Fp2::random_element();
47 r.coeffs[1] = my_Fp2::random_element();
52 template<mp_size_t n, const bigint<n> &modulus>
53 bool Fp4_model<n, modulus>::operator==(const Fp4_model<n, modulus> &other) const
56 this->coeffs[0] == other.coeffs[0] &&
57 this->coeffs[1] == other.coeffs[1]);
60 template<mp_size_t n, const bigint<n> &modulus>
61 bool Fp4_model<n, modulus>::operator!=(const Fp4_model<n, modulus> &other) const
63 return !(operator==(other));
66 template<mp_size_t n, const bigint<n> &modulus>
67 Fp4_model<n, modulus> Fp4_model<n, modulus>::operator+(
68 const Fp4_model<n, modulus> &other) const
70 return Fp4_model<n, modulus>(
71 this->coeffs[0] + other.coeffs[0], this->coeffs[1] + other.coeffs[1]);
74 template<mp_size_t n, const bigint<n> &modulus>
75 Fp4_model<n, modulus> Fp4_model<n, modulus>::operator-(
76 const Fp4_model<n, modulus> &other) const
78 return Fp4_model<n, modulus>(
79 this->coeffs[0] - other.coeffs[0], this->coeffs[1] - other.coeffs[1]);
82 template<mp_size_t n, const bigint<n> &modulus>
83 Fp4_model<n, modulus> operator*(
84 const Fp_model<n, modulus> &lhs, const Fp4_model<n, modulus> &rhs)
86 return Fp4_model<n, modulus>(lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
89 template<mp_size_t n, const bigint<n> &modulus>
90 Fp4_model<n, modulus> operator*(
91 const Fp2_model<n, modulus> &lhs, const Fp4_model<n, modulus> &rhs)
93 return Fp4_model<n, modulus>(lhs * rhs.coeffs[0], lhs * rhs.coeffs[1]);
96 template<mp_size_t n, const bigint<n> &modulus>
97 Fp4_model<n, modulus> Fp4_model<n, modulus>::operator*(
98 const Fp4_model<n, modulus> &other) const
100 // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
101 // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba)
103 const my_Fp2 &B = other.coeffs[1], &A = other.coeffs[0],
104 &b = this->coeffs[1], &a = this->coeffs[0];
105 const my_Fp2 aA = a * A;
106 const my_Fp2 bB = b * B;
108 const my_Fp2 beta_bB = Fp4_model<n, modulus>::mul_by_non_residue(bB);
109 return Fp4_model<n, modulus>(aA + beta_bB, (a + b) * (A + B) - aA - bB);
112 template<mp_size_t n, const bigint<n> &modulus>
113 Fp4_model<n, modulus> Fp4_model<n, modulus>::mul_by_023(
114 const Fp4_model<n, modulus> &other) const
116 // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
117 // Pairing-Friendly Fields.pdf; Section 3 (Karatsuba)
118 assert(other.coeffs[0].coeffs[1].is_zero());
120 const my_Fp2 &B = other.coeffs[1], &A = other.coeffs[0],
121 &b = this->coeffs[1], &a = this->coeffs[0];
123 my_Fp2(a.coeffs[0] * A.coeffs[0], a.coeffs[1] * A.coeffs[0]);
124 const my_Fp2 bB = b * B;
126 const my_Fp2 beta_bB = Fp4_model<n, modulus>::mul_by_non_residue(bB);
127 return Fp4_model<n, modulus>(aA + beta_bB, (a + b) * (A + B) - aA - bB);
130 template<mp_size_t n, const bigint<n> &modulus>
131 Fp4_model<n, modulus> Fp4_model<n, modulus>::operator-() const
133 return Fp4_model<n, modulus>(-this->coeffs[0], -this->coeffs[1]);
136 template<mp_size_t n, const bigint<n> &modulus>
137 Fp4_model<n, modulus> Fp4_model<n, modulus>::squared() const
139 // Devegili OhEig Scott Dahab --- Multiplication and Squaring on
140 // Pairing-Friendly Fields.pdf; Section 3 (Complex)
142 const my_Fp2 &b = this->coeffs[1], &a = this->coeffs[0];
143 const my_Fp2 ab = a * b;
145 return Fp4_model<n, modulus>(
146 (a + b) * (a + Fp4_model<n, modulus>::mul_by_non_residue(b)) - ab -
147 Fp4_model<n, modulus>::mul_by_non_residue(ab),
151 template<mp_size_t n, const bigint<n> &modulus>
152 Fp4_model<n, modulus> Fp4_model<n, modulus>::inverse() const
154 // From "High-Speed Software Implementation of the Optimal Ate Pairing over
155 // Barreto-Naehrig Curves"; Algorithm 8
156 const my_Fp2 &b = this->coeffs[1], &a = this->coeffs[0];
157 const my_Fp2 t1 = b.squared();
159 a.squared() - Fp4_model<n, modulus>::mul_by_non_residue(t1);
160 const my_Fp2 new_t1 = t0.inverse();
162 return Fp4_model<n, modulus>(a * new_t1, -(b * new_t1));
165 template<mp_size_t n, const bigint<n> &modulus>
166 Fp4_model<n, modulus> Fp4_model<n, modulus>::Frobenius_map(
167 unsigned long power) const
169 return Fp4_model<n, modulus>(
170 coeffs[0].Frobenius_map(power),
171 Frobenius_coeffs_c1[power % 4] * coeffs[1].Frobenius_map(power));
174 template<mp_size_t n, const bigint<n> &modulus>
175 Fp4_model<n, modulus> Fp4_model<n, modulus>::unitary_inverse() const
177 return Fp4_model<n, modulus>(this->coeffs[0], -this->coeffs[1]);
180 template<mp_size_t n, const bigint<n> &modulus>
181 Fp4_model<n, modulus> Fp4_model<n, modulus>::cyclotomic_squared() const
183 const my_Fp2 A = this->coeffs[1].squared();
184 const my_Fp2 B = this->coeffs[1] + this->coeffs[0];
185 const my_Fp2 C = B.squared() - A;
186 // Fp2(A.coeffs[1] * non_residue, A.coeffs[0])
187 const my_Fp2 D = Fp4_model<n, modulus>::mul_by_non_residue(A);
188 const my_Fp2 E = C - D;
189 const my_Fp2 F = D + D + my_Fp2::one();
190 const my_Fp2 G = E - my_Fp2::one();
192 return Fp4_model<n, modulus>(F, G);
195 template<mp_size_t n, const bigint<n> &modulus>
196 template<mp_size_t m>
197 Fp4_model<n, modulus> Fp4_model<n, modulus>::cyclotomic_exp(
198 const bigint<m> &exponent) const
200 Fp4_model<n, modulus> res = Fp4_model<n, modulus>::one();
201 Fp4_model<n, modulus> this_inverse = this->unitary_inverse();
203 bool found_nonzero = false;
204 std::vector<long> NAF = find_wnaf(1, exponent);
206 for (long i = static_cast<long>(NAF.size() - 1); i >= 0; --i) {
208 res = res.cyclotomic_squared();
212 found_nonzero = true;
217 res = res * this_inverse;
225 template<mp_size_t n, const bigint<n> &modulus, mp_size_t m>
226 Fp4_model<n, modulus> operator^(
227 const Fp4_model<n, modulus> &self, const bigint<m> &exponent)
229 return power<Fp4_model<n, modulus>>(self, exponent);
234 const bigint<n> &modulus,
236 const bigint<m> &modulus_p>
237 Fp4_model<n, modulus> operator^(
238 const Fp4_model<n, modulus> &self, const Fp_model<m, modulus_p> &exponent)
240 return self ^ (exponent.as_bigint());
243 template<mp_size_t n, const bigint<n> &modulus>
244 std::ostream &operator<<(std::ostream &out, const Fp4_model<n, modulus> &el)
246 out << el.coeffs[0] << OUTPUT_SEPARATOR << el.coeffs[1];
250 template<mp_size_t n, const bigint<n> &modulus>
251 std::istream &operator>>(std::istream &in, Fp4_model<n, modulus> &el)
253 in >> el.coeffs[0] >> el.coeffs[1];