37 using BaseField = Field;
38 using TypeTag =
typename Field::TypeTag;
41 static constexpr size_t kBytes = 2 * Field::kBytes;
42 static constexpr size_t kBits = 2 * Field::kBits;
43 static constexpr size_t kSubFieldBytes = Field::kBytes;
44 static constexpr bool kCharacteristicTwo =
false;
49 bool operator==(
const Elt& y)
const {
return re == y.re && im == y.im; }
50 bool operator!=(
const Elt& y)
const {
return !operator==(y); }
53 explicit Fp2(
const Field& F,
const Scalar& nonresidue)
54 : f_(F), nonresidue_(nonresidue) {
55 if (nonresidue_is_mone) {
56 check(nonresidue == F.mone(),
"nonresidue == F.mone()");
58 check(nonresidue != F.mone(),
"nonresidue != F.mone()");
61 i_ = Elt{f_.zero(), f_.one()};
62 for (uint64_t i = 0; i <
sizeof(k_) /
sizeof(k_[0]); ++i) {
65 khalf_ =
Elt{f_.half(), f_.zero()};
66 kmone_ =
Elt{f_.mone(), f_.zero()};
68 explicit Fp2(
const Field& F) : Fp2(F, F.mone()) {}
70 Fp2(
const Fp2&) =
delete;
71 Fp2& operator=(
const Fp2&) =
delete;
73 const Field& base_field()
const {
return f_; }
75 Scalar real(
const Elt& e)
const {
return e.re; }
76 bool is_real(
const Elt& e)
const {
return e.im == f_.zero(); }
78 void add(
Elt& a,
const Elt& y)
const {
82 void sub(
Elt& a,
const Elt& y)
const {
86 void mul(
Elt& a,
const Elt& y)
const {
87 auto p0 = f_.mulf(a.re, y.re);
88 auto p1 = f_.mulf(a.im, y.im);
89 auto a01 = f_.addf(a.re, a.im);
90 auto y01 = f_.addf(y.re, y.im);
91 if (nonresidue_is_mone) {
92 a.re = f_.subf(p0, p1);
94 a.re = f_.addf(p0, f_.mulf(p1, nonresidue_));
101 void mul(
Elt& a,
const Scalar& y)
const {
105 void neg(
Elt& x)
const {
110 void conj(
Elt& x)
const { f_.neg(x.im); }
111 void invert(
Elt& x)
const {
113 if (nonresidue_is_mone) {
114 denom = f_.addf(f_.mulf(x.re, x.re), f_.mulf(x.im, x.im));
116 denom = f_.subf(f_.mulf(x.re, x.re),
117 f_.mulf(nonresidue_, f_.mulf(x.im, x.im)));
137 Elt mulf(
Elt a,
const Scalar& y)
const {
145 Elt invertf(
Elt a)
const {
154 Elt of_scalar(uint64_t a)
const {
return of_scalar_field(a); }
155 Elt of_scalar(
const Scalar& e)
const {
return of_scalar_field(e); }
157 Elt of_scalar_field(
const Scalar& e)
const {
return Elt{e, f_.zero()}; }
158 Elt of_scalar_field(uint64_t a)
const {
159 return Elt{f_.of_scalar(a), f_.zero()};
161 Elt of_scalar_field(uint64_t ar, uint64_t ai)
const {
162 return Elt{f_.of_scalar(ar), f_.of_scalar(ai)};
166 Elt of_string(
const char (&s)[N])
const {
167 return Elt{f_.of_string(s), f_.zero()};
170 template <
size_t NR,
size_t NI>
171 Elt of_string(
const char (&sr)[NR],
const char (&si)[NI])
const {
172 return Elt{f_.of_string(sr), f_.of_string(si)};
175 std::optional<Elt> of_bytes_field(
const uint8_t ab[])
const {
176 if (
auto re = f_.of_bytes_field(ab)) {
177 if (
auto im = f_.of_bytes_field(ab + Field::kBytes)) {
178 return Elt{re.value(), im.value()};
184 void to_bytes_field(uint8_t ab[],
const Elt& x)
const {
185 f_.to_bytes_field(ab, x.re);
186 f_.to_bytes_field(ab + Field::kBytes, x.im);
189 bool in_subfield(
const Elt& e)
const {
return is_real(e); }
191 std::optional<Elt> of_bytes_subfield(
192 const uint8_t ab[])
const {
193 if (
auto re = f_.of_bytes_subfield(ab)) {
194 return of_scalar(re.value());
199 void to_bytes_subfield(uint8_t ab[],
const Elt& x)
const {
200 check(in_subfield(x),
"x not in subfield");
201 f_.to_bytes_subfield(ab, x.re);
204 const Elt& zero()
const {
return k_[0]; }
205 const Elt& one()
const {
return k_[1]; }
206 const Elt& two()
const {
return k_[2]; }
207 const Elt& half()
const {
return khalf_; }
208 const Elt& mone()
const {
return kmone_; }
209 const Elt& i()
const {
return i_; }
210 Elt poly_evaluation_point(
size_t i)
const {
211 return of_scalar(f_.poly_evaluation_point(i));
213 Elt newton_denominator(
size_t k,
size_t i)
const {
214 return of_scalar(f_.newton_denominator(k, i));