41 using limb_t =
typename N::limb_t;
44 static constexpr size_t kU64 = N::kU64;
45 static constexpr size_t kBytes = N::kBytes;
46 static constexpr size_t kSubFieldBytes = kBytes;
47 static constexpr size_t kBits = N::kBits;
48 static constexpr size_t kLimbs = N::kLimbs;
50 static constexpr bool kCharacteristicTwo =
false;
51 static constexpr size_t kNPolyEvaluationPoints = 6;
57 bool operator==(
const Elt& y)
const {
return n == y.n; }
58 bool operator!=(
const Elt& y)
const {
return !operator==(y); }
61 explicit FpGeneric(
const N& modulus) : m_(modulus), negm_(N{}) {
68 raw_half_ =
Elt{raw_half};
70 mprime_ = -inv_mod_b(m_.limb_[0]);
72 for (
size_t bits = 2 * kBits; bits > 0; bits--) {
73 add(rsquare_, rsquare_);
76 for (uint64_t i = 0; i <
sizeof(k_) /
sizeof(k_[0]); ++i) {
81 mul0(k_[i], rsquare_);
85 half_ = invertf(k_[2]);
87 for (
size_t i = 0; i < kNPolyEvaluationPoints; ++i) {
88 poly_evaluation_points_[i] = of_scalar(i);
90 inv_small_scalars_[i] = zero();
92 inv_small_scalars_[i] = invertf(poly_evaluation_points_[i]);
97 explicit FpGeneric(
const StaticString s) : FpGeneric(N(s)) {}
100 explicit FpGeneric(
const char (&s)[LEN]) : FpGeneric(N(s)) {}
104 explicit FpGeneric() : FpGeneric(N(OPS::kModulus)) {}
106 FpGeneric(
const FpGeneric&) =
delete;
107 FpGeneric& operator=(
const FpGeneric&) =
delete;
110 Elt of_string(
const char (&s)[N])
const {
111 return of_charp(&s[0]);
114 Elt of_string(
const StaticString& s)
const {
return of_charp(s.as_pointer); }
116 std::optional<Elt> of_untrusted_string(
const char* s)
const {
117 auto maybe = N::of_untrusted_string(s);
118 if (maybe.has_value() && maybe.value() < m_) {
119 return to_montgomery(maybe.value());
126 void add(
Elt& a,
const Elt& y)
const {
128 limb_t aa = a.n.limb_[0], yy = y.n.limb_[0], mm = m_.limb_[0];
129 a.n.limb_[0] = addcmovc(aa - mm, yy, aa + yy);
131 limb_t ah = add_limb(kLimbs, a.n.limb_, y.n.limb_);
132 maybe_minus_m(a.n.limb_, ah);
137 void sub(
Elt& a,
const Elt& y)
const {
139 a.n.limb_[0] = sub_sysdep(a.n.limb_[0], y.n.limb_[0], m_.limb_[0]);
141 limb_t ah = sub_limb(kLimbs, a.n.limb_, y.n.limb_);
142 maybe_plus_m(a.n.limb_, ah);
147 void mul(
Elt& x,
const Elt& y)
const {
149 if (x == zero() || y == one()) {
152 if (y == zero() || x == one()) {
161 void neg(
Elt& x)
const {
168 void invert(
Elt& x)
const { x = invertf(x); }
190 Elt invertf(
Elt x)
const {
191 N a = from_montgomery(x);
196 if ((a.limb_[0] & 0x1u) == 0) {
213 N from_montgomery_reference(
const Elt& x)
const {
221 N from_montgomery(
const Elt& x)
const {
222 limb_t a[2 * kLimbs + 1];
223 mov(kLimbs, a, x.n.limb_);
224 a[kLimbs] = zero_limb<limb_t>();
225 for (
size_t i = 0; i < kLimbs; ++i) {
226 a[i + kLimbs + 1] = zero_limb<limb_t>();
227 OPS::reduction_step(&a[i], mprime_, m_);
229 maybe_minus_m(a + kLimbs, a[2 * kLimbs]);
231 mov(kLimbs, r.limb_, a + kLimbs);
235 Elt to_montgomery(
const N& xn)
const {
241 bool in_subfield(
const Elt& e)
const {
return true; }
247 Elt of_scalar(uint64_t a)
const {
return of_scalar_field(a); }
249 Elt of_scalar_field(uint64_t a)
const {
return of_scalar_field(N(a)); }
250 Elt of_scalar_field(
const std::array<uint64_t, W64>& a)
const {
251 return of_scalar_field(N(a));
253 Elt of_scalar_field(
const N& a)
const {
254 check(a < m_,
"of_scalar must be less than m");
255 return to_montgomery(a);
258 std::optional<Elt> of_bytes_field(
const uint8_t ab[])
const {
259 N an = N::of_bytes(ab);
261 return to_montgomery(an);
267 void to_bytes_field(uint8_t ab[],
const Elt& x)
const {
268 from_montgomery(x).to_bytes(ab);
271 std::optional<Elt> of_bytes_subfield(
const uint8_t ab[])
const {
272 return of_bytes_field(ab);
275 void to_bytes_subfield(uint8_t ab[],
const Elt& x)
const {
276 to_bytes_field(ab, x);
279 const Elt& zero()
const {
return k_[0]; }
280 const Elt& one()
const {
return k_[1]; }
281 const Elt& two()
const {
return k_[2]; }
282 const Elt& half()
const {
return half_; }
283 const Elt& mone()
const {
return mone_; }
285 Elt poly_evaluation_point(
size_t i)
const {
286 check(i < kNPolyEvaluationPoints,
"i < kNPolyEvaluationPoints");
287 return poly_evaluation_points_[i];
292 Elt newton_denominator(
size_t k,
size_t i)
const {
293 check(k < kNPolyEvaluationPoints,
"k < kNPolyEvaluationPoints");
294 check(i <= k,
"i <= k");
295 check(k != (k - i),
"k != (k - i)");
296 return inv_small_scalars_[ i];
300 void maybe_minus_m(limb_t a[kLimbs], limb_t ah)
const {
302 mov(kLimbs, a1, negm_.limb_);
303 limb_t ah1 = add_limb(kLimbs, a1, a);
304 cmovne(kLimbs, a, ah, ah1, a1);
306 void maybe_plus_m(limb_t a[kLimbs], limb_t ah)
const {
309 (void)add_limb(kLimbs, a1, m_.limb_);
310 cmovnz(kLimbs, a, ah, a1);
313 void byhalf(
Elt& a)
const {
314 if (a.n.shiftr(1) != 0) {
323 void mul0(
Elt& x,
const Elt& y)
const {
324 limb_t a[2 * kLimbs + 1];
325 mulstep<true>(a, x.n.limb_[0], y.n.limb_);
326 for (
size_t i = 1; i < kLimbs; ++i) {
327 mulstep<false>(a + i, x.n.limb_[i], y.n.limb_);
329 maybe_minus_m(a + kLimbs, a[2 * kLimbs]);
330 mov(kLimbs, x.n.limb_, a + kLimbs);
333 template <
bool first>
334 inline void mulstep(limb_t* a, limb_t x,
const limb_t y[kLimbs])
const {
341 a[2] = zero_limb<limb_t>();
342 check(first,
"mulstep template must be have first=true for 1 limb");
343 mulhl(1, a, a + 1, x, y);
344 OPS::reduction_step(a, mprime_, m_);
346 limb_t l[kLimbs], h[kLimbs];
347 a[kLimbs + 1] = zero_limb<limb_t>();
349 a[kLimbs] = zero_limb<limb_t>();
350 mulhl(kLimbs, a, h, x, y);
352 mulhl(kLimbs, l, h, x, y);
353 accum(kLimbs + 1, a, kLimbs, l);
355 accum(kLimbs + 1, a + 1, kLimbs, h);
356 OPS::reduction_step(a, mprime_, m_);
363 Elt of_charp(
const char* s)
const {
365 Elt base = of_scalar(10);
366 if (s[0] ==
'0' && (s[1] ==
'x' || s[1] ==
'X')) {
368 base = of_scalar(16);
372 Elt d = of_scalar(digit(*s));
387 Elt poly_evaluation_points_[kNPolyEvaluationPoints];
388 Elt inv_small_scalars_[kNPolyEvaluationPoints];