8#include <botan/internal/curve448_gf.h>
10#include <botan/internal/ct_utils.h>
11#include <botan/internal/loadstor.h>
12#include <botan/internal/mp_asmi.h>
13#include <botan/internal/mp_core.h>
27void reduce_after_add(std::span<uint64_t, WORDS_448> h_3, std::span<const uint64_t, 8> h_1) {
28 std::array<uint64_t, 8> h_2;
31 constexpr uint64_t zero = 0;
53 h_3[3] = h_2[3] + (h_2[7] << 32) +
carry;
66void reduce_after_mul(std::span<uint64_t, WORDS_448> out, std::span<const uint64_t, 14> in) {
67 std::array<uint64_t, 8> r;
68 std::array<uint64_t, 8> s;
69 std::array<uint64_t, 8> t_0;
70 std::array<uint64_t, 8> h_1;
98 t_0[0] = (in[0 + 11] << 32) | (in[0 + 10] >> 32);
99 t_0[1] = (in[1 + 11] << 32) | (in[1 + 10] >> 32);
100 t_0[2] = (in[2 + 11] << 32) | (in[2 + 10] >> 32);
102 t_0[3] = (in[7] << 32) | (in[13] >> 32);
104 t_0[4] = (in[4 + 4] << 32) | (in[4 + 3] >> 32);
105 t_0[5] = (in[5 + 4] << 32) | (in[5 + 3] >> 32);
106 t_0[6] = (in[6 + 4] << 32) | (in[6 + 3] >> 32);
116 h_1[7] = s[7] +
carry;
118 reduce_after_add(out, h_1);
124void gf_mul_a24(std::span<uint64_t, WORDS_448> out, std::span<const uint64_t, WORDS_448> a) {
125 constexpr uint64_t A24 = 39081;
126 std::array<uint64_t, 8> ws;
136 reduce_after_add(out, ws);
139void gf_mul(std::span<uint64_t, WORDS_448> out,
140 std::span<const uint64_t, WORDS_448> a,
141 std::span<const uint64_t, WORDS_448> b) {
142 std::array<uint64_t, 14> ws;
144 reduce_after_mul(out, ws);
147void gf_square(std::span<uint64_t, WORDS_448> out, std::span<const uint64_t, WORDS_448> a) {
148 std::array<uint64_t, 14> ws;
150 reduce_after_mul(out, ws);
153void gf_add(std::span<uint64_t, WORDS_448> out,
154 std::span<const uint64_t, WORDS_448> a,
155 std::span<const uint64_t, WORDS_448> b) {
156 std::array<uint64_t, WORDS_448 + 1> ws;
168 reduce_after_add(out, ws);
176void gf_sub(std::span<uint64_t, WORDS_448> out,
177 std::span<const uint64_t, WORDS_448> a,
178 std::span<const uint64_t, WORDS_448> b) {
179 std::array<uint64_t, WORDS_448> h_0;
180 std::array<uint64_t, WORDS_448> h_1;
183 h_0[0] =
word_sub(a[0], b[0], &borrow);
184 h_0[1] =
word_sub(a[1], b[1], &borrow);
185 h_0[2] =
word_sub(a[2], b[2], &borrow);
186 h_0[3] =
word_sub(a[3], b[3], &borrow);
187 h_0[4] =
word_sub(a[4], b[4], &borrow);
188 h_0[5] =
word_sub(a[5], b[5], &borrow);
189 h_0[6] =
word_sub(a[6], b[6], &borrow);
190 uint64_t delta = borrow;
191 uint64_t delta_p = delta << 32;
194 constexpr uint64_t zero = 0;
196 h_1[0] =
word_sub(h_0[0], delta, &borrow);
197 h_1[1] =
word_sub(h_0[1], zero, &borrow);
198 h_1[2] =
word_sub(h_0[2], zero, &borrow);
199 h_1[3] =
word_sub(h_0[3], delta_p, &borrow);
200 h_1[4] =
word_sub(h_0[4], zero, &borrow);
201 h_1[5] =
word_sub(h_0[5], zero, &borrow);
202 h_1[6] =
word_sub(h_0[6], zero, &borrow);
205 delta_p = delta << 32;
208 out[0] =
word_sub(h_1[0], delta, &borrow);
209 out[1] =
word_sub(h_1[1], zero, &borrow);
210 out[2] =
word_sub(h_1[2], zero, &borrow);
211 out[3] =
word_sub(h_1[3], delta_p, &borrow);
218void gf_sqr_n(std::span<uint64_t, WORDS_448> out, std::span<const uint64_t, WORDS_448> a,
size_t n) {
220 for(
size_t i = 1; i < n; ++i) {
243void gf_pow_2_222m1(std::span<uint64_t, WORDS_448> x222,
244 std::span<uint64_t, WORDS_448> x223,
245 std::span<const uint64_t, WORDS_448> a) {
246 std::array<uint64_t, WORDS_448> t;
249 std::array<uint64_t, WORDS_448> a2;
253 std::array<uint64_t, WORDS_448> a3;
257 std::array<uint64_t, WORDS_448> a7;
262 std::array<uint64_t, WORDS_448> a63;
267 std::array<uint64_t, WORDS_448> x12;
272 std::array<uint64_t, WORDS_448> x24;
273 gf_sqr_n(t, x12, 12);
277 std::array<uint64_t, WORDS_448> i34;
278 gf_sqr_n(i34, x24, 6);
281 std::array<uint64_t, WORDS_448> x30;
282 gf_mul(x30, a63, i34);
285 std::array<uint64_t, WORDS_448> x48;
286 gf_sqr_n(t, i34, 18);
290 std::array<uint64_t, WORDS_448> x96;
291 gf_sqr_n(t, x48, 48);
295 std::array<uint64_t, WORDS_448> x192;
296 gf_sqr_n(t, x96, 96);
297 gf_mul(x192, x96, t);
300 gf_sqr_n(t, x192, 30);
301 gf_mul(x222, x30, t);
316void gf_inv(std::span<uint64_t, WORDS_448> out, std::span<const uint64_t, WORDS_448> a) {
317 std::array<uint64_t, WORDS_448> x222;
318 std::array<uint64_t, WORDS_448> x223;
319 gf_pow_2_222m1(x222, x223, a);
322 std::array<uint64_t, WORDS_448> t;
323 gf_sqr_n(t, x223, 223);
335std::array<uint64_t, WORDS_448> to_canonical(std::span<const uint64_t, WORDS_448> in) {
336 const std::array<uint64_t, WORDS_448> p = {0xffffffffffffffff,
344 std::array<uint64_t, WORDS_448> in_minus_p;
347 in_minus_p[i] =
word_sub(in[i], p[i], &borrow);
349 std::array<uint64_t, WORDS_448> out;
362 m_x[0] = least_sig_word;
370 std::array<uint8_t, BYTES_448> bytes{};
387 gf_add(res.m_x, m_x, other.m_x);
393 gf_sub(res.m_x, m_x, other.m_x);
399 gf_sub(res.m_x, res.m_x, m_x);
405 gf_mul(res.m_x, m_x, other.m_x);
411 gf_inv(res.m_x, other.m_x);
412 gf_mul(res.m_x, m_x, res.m_x);
417 const auto canonical_form_this = to_canonical(m_x);
418 const auto canonical_form_other = to_canonical(other.m_x);
423 const auto canonical_form = to_canonical(m_x);
429 const auto canonical_form = to_canonical(m_x);
430 return (canonical_form[0] & 1) == 1;
435 const auto x_words_canonical = to_canonical(x_words);
455 std::array<uint64_t, WORDS_448> x222;
456 std::array<uint64_t, WORDS_448> x223;
457 gf_pow_2_222m1(x222, x223, elem.
words());
460 gf_sqr_n(res.
words(), x223, 223);
void conditional_swap(U &x, U &y) const
constexpr void select_n(T output[], const T x[], const T y[], size_t len) const
static constexpr Mask< T > expand(T v)
void ct_cond_swap(CT::Mask< uint64_t > mask, Gf448Elem &other)
Swap this and other if mask is set. Constant time.
Gf448Elem operator*(const Gf448Elem &other) const
Gf448Elem operator-() const
static bool bytes_are_canonical_representation(std::span< const uint8_t, BYTES_448 > x)
Given 56 bytes, checks that the (little endian) number from this bytes is a valid GF element,...
std::array< uint8_t, BYTES_448 > to_bytes() const
Return the canonical representation of the GF element as 56 bytes in little-endian order.
Gf448Elem operator/(const Gf448Elem &other) const
bool is_odd() const
Return true iff this element is odd. Constant time.
Gf448Elem operator+(const Gf448Elem &other) const
bool operator==(const Gf448Elem &other) const
std::span< uint64_t, WORDS_448 > words()
Accessor to the internal words of the GF element.
Gf448Elem(std::span< const uint8_t, BYTES_448 > x)
Construct a GF element from a 448-bit integer gives as 56 bytes x in little-endian order.
void ct_cond_assign(CT::Mask< uint64_t > mask, const Gf448Elem &other)
Set this to other if mask is true. Constant time.
bool is_zero() const
Return true iff this element is zero. Constant time.
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
Gf448Elem mul_a24(const Gf448Elem &a)
Multiply a field element by the Curve448 constant a24 = 39081.
Gf448Elem root(const Gf448Elem &elem)
Compute the root of elem in the field.
constexpr auto word_sub(W x, W y, W *carry) -> W
constexpr auto word_add(W x, W y, W *carry) -> W
constexpr void comba_sqr(W z[2 *N], const W x[N])
constexpr void comba_mul(W z[2 *N], const W x[N], const W y[N])
BigInt square(const BigInt &x)
constexpr auto word_madd2(W a, W b, W *c) -> W
constexpr auto store_le(ParamTs &&... params)
void carry(int64_t &h0, int64_t &h1)
constexpr auto load_le(ParamTs &&... params)
constexpr void clear_mem(T *ptr, size_t n)
constexpr size_t WORDS_448