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();
105 for (
size_t i = 1; i < kSubFieldBits; ++i) {
106 beta_[i] = mulf(beta_[i - 1], g);
113 poly_evaluation_points_[0] = zero();
115 for (
size_t i = 1; i < kNPolyEvaluationPoints; ++i) {
116 poly_evaluation_points_[i] = gi;
120 for (
size_t i = 1; i < kNPolyEvaluationPoints; i++) {
121 for (
size_t k = kNPolyEvaluationPoints; k-- > i;) {
123 subf(poly_evaluation_points_[k], poly_evaluation_points_[k - i]);
124 check(dx != zero(),
"dx != zero()");
125 newton_denominators_[k][i] = invertf(dx);
130 GF2_128(
const GF2_128&) =
delete;
131 GF2_128& operator=(
const GF2_128&) =
delete;
135 Elt of_scalar(uint64_t u)
const {
137 for (
size_t k = 0; k < kSubFieldBits; ++k, u >>= 1) {
142 check(u == 0,
"of_scalar(u), too many bits");
146 Elt of_scalar_field(uint64_t n)
const {
147 std::array<uint64_t, 2> u = {n, 0};
148 return of_scalar_field(u);
150 Elt of_scalar_field(
const std::array<uint64_t, 2>& u)
const {
151 return Elt(gf2_128_of_uint64x2(u));
156 std::optional<Elt> of_bytes_field(
const uint8_t ab[],
157 bool base_only =
true)
const {
158 N1 an = N1::of_bytes(ab);
159 return of_scalar_field(an.u64());
162 void to_bytes_field(uint8_t ab[],
const Elt& x)
const {
163 x.unpack().to_bytes(ab);
166 bool in_subfield(
Elt e)
const {
168 return eu.first == N1{};
171 std::optional<Elt> of_bytes_subfield(
172 const uint8_t ab[])
const {
174 for (
size_t i = kSubFieldBytes; i-- > 0;) {
181 void to_bytes_subfield(uint8_t ab[],
const Elt& x)
const {
183 check(eu.first == N1{},
"eu.first == N1{}");
184 uint64_t u = eu.second;
185 for (
size_t i = 0; i < kSubFieldBytes; ++i) {
192 Elt addf(
const Elt& x,
const Elt& y)
const {
193 return Elt{gf2_128_add(x.n, y.n)};
195 Elt subf(
const Elt& x,
const Elt& y)
const {
196 return Elt{gf2_128_add(x.n, y.n)};
198 Elt mulf(
const Elt& x,
const Elt& y)
const {
199 return Elt{gf2_128_mul(x.n, y.n)};
201 Elt negf(
const Elt& x)
const {
return x; }
204 void add(
Elt& a,
const Elt& y)
const { a = addf(a, y); }
205 void sub(
Elt& a,
const Elt& y)
const { a = subf(a, y); }
206 void mul(
Elt& a,
const Elt& y)
const { a = mulf(a, y); }
207 void neg(
Elt& a)
const { }
208 void invert(
Elt& a)
const { a = invertf(a); }
210 Elt zero()
const {
return Elt{}; }
211 Elt one()
const {
return kone_; }
212 Elt mone()
const {
return kone_; }
213 Elt x()
const {
return kx_; }
214 Elt invx()
const {
return kinvx_; }
215 Elt beta(
size_t i)
const {
216 check(i < kSubFieldBits,
"i < kSubFieldBits");
220 Elt poly_evaluation_point(
size_t i)
const {
221 check(i < kNPolyEvaluationPoints,
"i < kNPolyEvaluationPoints");
222 return poly_evaluation_points_[i];
227 Elt newton_denominator(
size_t k,
size_t i)
const {
228 check(k < kNPolyEvaluationPoints,
"k < kNPolyEvaluationPoints");
229 check(i <= k,
"i <= k");
230 check(k != (k - i),
"k != (k - i)");
231 return newton_denominators_[k][i];
234 Elt invertf(
Elt x)
const {
242 N1 bm1ox = kinvx_.unpack();
260 std::swap(am1ox, bm1ox);
276 Elt beta_[kSubFieldBits];
281 N1 u_[kSubFieldBits];
282 uint64_t linv_[kSubFieldBits];
287 size_t ldnz_[kSubFieldBits];
289 Elt poly_evaluation_points_[kNPolyEvaluationPoints];
290 Elt newton_denominators_[kNPolyEvaluationPoints][kNPolyEvaluationPoints];
292 void byinvx(
Elt& u)
const { mul(u, kinvx_); }
294 Elt subfield_generator() {
305 for (
size_t i = kSubFieldLogBits; i < kLogBits; ++i) {
308 for (
size_t j = 0; j < (1u << i); ++j) {
377 for (
size_t i = 0; i < kSubFieldBits; ++i) {
379 u_[i] = beta_[i].unpack();
383 linv_[i] = (
static_cast<uint64_t
>(1) << i);
391 for (
size_t j = 0; rnk < kSubFieldBits && j < kBits; ++j) {
393 for (
size_t i = rnk; i < kSubFieldBits; ++i) {
395 std::swap(u_[rnk], u_[i]);
396 std::swap(linv_[rnk], linv_[i]);
408 for (
size_t i1 = rnk + 1; i1 < kSubFieldBits; ++i1) {
411 linv_[i1] ^= linv_[rnk];
418 check(rnk == kSubFieldBits,
"rnk == kSubFieldBits");
421 std::pair<N1, uint64_t> solve(
const Elt& e)
const {
424 for (
size_t rnk = 0; rnk < kSubFieldBits; ++rnk) {
425 size_t j = ldnz_[rnk];
432 return std::pair(ue, u);