37 static constexpr size_t k1 = 1;
44 using N = gf2_128_elt_t;
50 static constexpr size_t kNPolyEvaluationPoints = 6;
51 static constexpr size_t kLogBits = 7;
52 static constexpr size_t kBits = k1 << kLogBits;
53 static constexpr size_t kBytes = kBits / 8u;
55 static constexpr size_t kSubFieldLogBits = subfield_log_bits;
56 static constexpr size_t kSubFieldBits = k1 << kSubFieldLogBits;
57 static constexpr size_t kSubFieldBytes = kSubFieldBits / 8u;
59 static_assert(kBits == 8u * kBytes);
60 static_assert(kSubFieldBits == 8u * kSubFieldBytes);
61 static constexpr bool kCharacteristicTwo =
true;
67 explicit Elt(N n_) : n(n_) {}
72 bool operator==(
const Elt& y)
const {
return unpack() == y.unpack(); }
73 bool operator!=(
const Elt& y)
const {
return !operator==(y); }
76 uint8_t operator[](
size_t i)
const {
77 auto n1 = uint64x2_of_gf2_128(n);
79 return static_cast<uint8_t
>((n1[0] >> i) & 0x1);
81 return static_cast<uint8_t
>((n1[1] >> (i - 64)) & 0x1);
87 N1 unpack()
const {
return N1(uint64x2_of_gf2_128(n)); }
91 kone_ = of_scalar_field(0b1);
92 kx_ = of_scalar_field(0b10);
95 std::array<uint64_t, 2> invx = {
96 (1ull << 6) | (1ull << 1) | (1ull << 0),
99 kinvx_ = of_scalar_field(invx);
101 Elt g = subfield_generator();
107 for (
size_t i = 1; i < kSubFieldBits; ++i) {
108 beta_[i] = mulf(beta_[i - 1], g);
115 poly_evaluation_points_[0] = zero();
117 for (
size_t i = 1; i < kNPolyEvaluationPoints; ++i) {
118 poly_evaluation_points_[i] = gi;
122 for (
size_t i = 1; i < kNPolyEvaluationPoints; i++) {
123 for (
size_t k = kNPolyEvaluationPoints; k-- > i;) {
125 subf(poly_evaluation_points_[k], poly_evaluation_points_[k - i]);
126 check(dx != zero(),
"dx != zero()");
127 newton_denominators_[k][i] = invertf(dx);
133 for (
size_t i = 0; i < kSubFieldBits; ++i) {
134 counter_beta_[i] = cgi;
139 GF2_128(
const GF2_128&) =
delete;
140 GF2_128& operator=(
const GF2_128&) =
delete;
144 Elt of_scalar(uint64_t u)
const {
146 for (
size_t k = 0; k < kSubFieldBits; ++k, u >>= 1) {
151 check(u == 0,
"of_scalar(u), too many bits");
155 Elt of_scalar_field(uint64_t n)
const {
156 std::array<uint64_t, 2> u = {n, 0};
157 return of_scalar_field(u);
159 Elt of_scalar_field(
const std::array<uint64_t, 2>& u)
const {
160 return Elt(gf2_128_of_uint64x2(u));
165 std::optional<Elt> of_bytes_field(
const uint8_t ab[],
166 bool base_only =
true)
const {
167 N1 an = N1::of_bytes(ab);
168 return of_scalar_field(an.u64());
171 void to_bytes_field(uint8_t ab[],
const Elt& x)
const {
172 x.unpack().to_bytes(ab);
175 bool in_subfield(
Elt e)
const {
177 return eu.first == N1{};
180 std::optional<Elt> of_bytes_subfield(
181 const uint8_t ab[])
const {
183 for (
size_t i = kSubFieldBytes; i-- > 0;) {
190 void to_bytes_subfield(uint8_t ab[],
const Elt& x)
const {
192 check(eu.first == N1{},
"eu.first == N1{}");
193 uint64_t u = eu.second;
194 for (
size_t i = 0; i < kSubFieldBytes; ++i) {
201 Elt addf(
const Elt& x,
const Elt& y)
const {
202 return Elt{gf2_128_add(x.n, y.n)};
204 Elt subf(
const Elt& x,
const Elt& y)
const {
205 return Elt{gf2_128_add(x.n, y.n)};
207 Elt mulf(
const Elt& x,
const Elt& y)
const {
208 return Elt{gf2_128_mul(x.n, y.n)};
210 Elt negf(
const Elt& x)
const {
return x; }
213 void add(
Elt& a,
const Elt& y)
const { a = addf(a, y); }
214 void sub(
Elt& a,
const Elt& y)
const { a = subf(a, y); }
215 void mul(
Elt& a,
const Elt& y)
const { a = mulf(a, y); }
216 void neg(
Elt& a)
const { }
217 void invert(
Elt& a)
const { a = invertf(a); }
219 Elt zero()
const {
return Elt{}; }
220 Elt one()
const {
return kone_; }
221 Elt mone()
const {
return kone_; }
222 Elt x()
const {
return kx_; }
223 Elt invx()
const {
return kinvx_; }
224 Elt g()
const {
return kg_; }
225 Elt invg()
const {
return kinvg_; }
226 Elt beta(
size_t i)
const {
227 check(i < kSubFieldBits,
"i < kSubFieldBits");
231 Elt poly_evaluation_point(
size_t i)
const {
232 check(i < kNPolyEvaluationPoints,
"i < kNPolyEvaluationPoints");
233 return poly_evaluation_points_[i];
238 Elt newton_denominator(
size_t k,
size_t i)
const {
239 check(k < kNPolyEvaluationPoints,
"k < kNPolyEvaluationPoints");
240 check(i <= k,
"i <= k");
241 check(k != (k - i),
"k != (k - i)");
242 return newton_denominators_[k][i];
245 Elt invertf(
Elt x)
const {
253 N1 bm1ox = kinvx_.unpack();
271 std::swap(am1ox, bm1ox);
288 bool operator==(
const CElt& y)
const {
return e == y.e; }
289 bool operator!=(
const CElt& y)
const {
return !operator==(y); }
291 CElt as_counter(uint64_t a)
const {
293 check((a + 1u) != 0,
"as_counter() arg too large");
294 check(((a + 1u) >> kSubFieldBits) == 0,
"as_counter() arg too large");
296 for (
size_t i = 0; i < kSubFieldBits; ++i) {
298 mul(r, counter_beta(i));
303 Elt counter_beta(
size_t i)
const {
304 check(i < kSubFieldBits,
"i < kSubFieldBits");
305 return counter_beta_[i];
311 Elt znz_indicator(
const CElt& celt)
const {
return subf(celt.e, one()); }
319 Elt beta_[kSubFieldBits];
321 Elt counter_beta_[kSubFieldBits];
326 N1 u_[kSubFieldBits];
327 uint64_t linv_[kSubFieldBits];
332 size_t ldnz_[kSubFieldBits];
334 Elt poly_evaluation_points_[kNPolyEvaluationPoints];
335 Elt newton_denominators_[kNPolyEvaluationPoints][kNPolyEvaluationPoints];
337 void byinvx(
Elt& u)
const { mul(u, kinvx_); }
339 Elt subfield_generator() {
350 for (
size_t i = kSubFieldLogBits; i < kLogBits; ++i) {
353 for (
size_t j = 0; j < (1u << i); ++j) {
422 for (
size_t i = 0; i < kSubFieldBits; ++i) {
424 u_[i] = beta_[i].unpack();
428 linv_[i] = (
static_cast<uint64_t
>(1) << i);
436 for (
size_t j = 0; rnk < kSubFieldBits && j < kBits; ++j) {
438 for (
size_t i = rnk; i < kSubFieldBits; ++i) {
440 std::swap(u_[rnk], u_[i]);
441 std::swap(linv_[rnk], linv_[i]);
453 for (
size_t i1 = rnk + 1; i1 < kSubFieldBits; ++i1) {
456 linv_[i1] ^= linv_[rnk];
463 check(rnk == kSubFieldBits,
"rnk == kSubFieldBits");
466 std::pair<N1, uint64_t> solve(
const Elt& e)
const {
469 for (
size_t rnk = 0; rnk < kSubFieldBits; ++rnk) {
470 size_t j = ldnz_[rnk];
477 return std::pair(ue, u);