8#include <botan/internal/curve448_scalar.h>
10#include <botan/internal/ct_utils.h>
11#include <botan/internal/mp_core.h>
21auto div_mod_2_446(std::span<const word, S> x) {
23 std::array<word, Scalar448::WORDS> r = {0};
24 copy_mem(std::span(r).
template first<S>(), x);
25 return std::make_pair(std::array<word, 1>({0}), r);
27 std::array<word, Scalar448::WORDS> r;
28 copy_mem(r, std::span(x).
template first<Scalar448::WORDS>());
35 return std::make_pair(q, r);
40consteval std::array<word, WORDS_C> c_words() {
41 const std::array<uint8_t, WORDS_C *
sizeof(word)> c_bytes{0x0d, 0xbb, 0xa7, 0x54, 0x6d, 0x3d, 0x87, 0xdc, 0xaa, 0x70,
42 0x3a, 0x72, 0x8d, 0x3d, 0x93, 0xde, 0x6f, 0xc9, 0x29, 0x51,
43 0xb6, 0x24, 0xb1, 0x3b, 0x16, 0xdc, 0x35, 0x83};
48consteval std::array<word, Scalar448::WORDS> big_l_words() {
50 0xf3, 0x44, 0x58, 0xab, 0x92, 0xc2, 0x78, 0x23, 0x55, 0x8f, 0xc5, 0x8d, 0x72, 0xc2, 0x6c, 0x21, 0x90, 0x36, 0xd6,
51 0xae, 0x49, 0xdb, 0x4e, 0xc4, 0xe9, 0x23, 0xca, 0x7c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f};
58std::array<word, S + WORDS_C> mul_c(std::span<const word, S> x) {
59 std::array<word, S + WORDS_C> res;
60 std::array<word, S + WORDS_C> ws;
61 constexpr std::array<word, WORDS_C> c = c_words();
62 bigint_mul(res.data(), res.size(), x.data(), x.size(), x.size(), c.data(), c.size(), c.size(), ws.data(), ws.size());
70std::array<word, Scalar448::WORDS> add(std::span<const word, Scalar448::WORDS> x,
71 std::span<const word, Scalar448::WORDS> y) {
72 std::array<word, Scalar448::WORDS> res;
85bool ct_subtract_L_if_bigger(std::span<word, Scalar448::WORDS> x) {
86 std::array<word, Scalar448::WORDS> tmp;
88 constexpr auto big_l = big_l_words();
90 const word borrow =
bigint_sub2(tmp.data(), tmp.size(), big_l.data(), big_l.size());
94 return !smaller_than_L.as_bool();
98std::array<word,
words_for_bits(S * 8)> bytes_to_words(std::span<const uint8_t, S> x) {
100 std::array<uint8_t, words *
sizeof(word)> x_word_bytes = {0};
101 copy_mem(std::span(x_word_bytes).
template first<S>(), x);
113std::array<word, Scalar448::WORDS> ct_reduce_mod_L(
const std::array<word, WORDS_REDUCE_SZ> x) {
114 const auto [q_0, r_0] = div_mod_2_446(std::span(x));
119 const auto q_0_c = mul_c(std::span(q_0));
120 const auto [q_1, r_1] = div_mod_2_446(std::span(q_0_c));
124 const auto q_1_c = mul_c(std::span(q_1));
125 const auto [q_2, r_2] = div_mod_2_446(std::span(q_1_c));
129 const auto q_2_c = mul_c(std::span(q_2));
130 const auto [q_3, r_3] = div_mod_2_446(std::span(q_2_c));
138 for(
size_t i = 0; i < 4; ++i) {
139 ct_subtract_L_if_bigger(r);
148 BOTAN_ARG_CHECK(in_bytes.size() <= 114,
"Input must be at most 114 bytes long");
149 std::array<uint8_t, 114> max_bytes = {0};
150 copy_mem(std::span(max_bytes).first(in_bytes.size()), in_bytes);
152 const auto x_words = bytes_to_words(std::span<const uint8_t, 114>(max_bytes));
153 m_scalar_words = ct_reduce_mod_L(x_words);
158 constexpr size_t word_sz =
sizeof(word) * 8;
159 return (m_scalar_words[bit_pos / word_sz] >> (bit_pos % word_sz)) & 1;
163 auto sum = add(m_scalar_words, other.m_scalar_words);
164 ct_subtract_L_if_bigger(sum);
169 std::array<word, WORDS_REDUCE_SZ> product = {0};
170 std::array<word, WORDS_REDUCE_SZ> ws = {0};
173 m_scalar_words.data(),
174 m_scalar_words.size(),
175 m_scalar_words.size(),
176 other.m_scalar_words.data(),
177 other.m_scalar_words.size(),
178 other.m_scalar_words.size(),
182 return Scalar448(ct_reduce_mod_L(product));
188 const auto leading_zeros = x.subspan(
BYTES);
189 const auto leading_zeros_are_zero =
CT::all_zeros(leading_zeros.data(), leading_zeros.size());
190 auto x_sig_words = bytes_to_words(x.first<56>());
192 return (leading_zeros_are_zero & least_56_bytes_smaller_L).as_bool();
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
static constexpr Mask< T > expand(T v)
Representation of a scalar for X448.
Scalar448 operator+(const Scalar448 &other) const
scalar = (scalar + other) mod L
Scalar448(std::span< const uint8_t > x)
Construct a new scalar from (max. 114) bytes. Little endian.
static constexpr size_t WORDS
static bool bytes_are_reduced(std::span< const uint8_t > x)
static constexpr size_t BYTES
bool get_bit(size_t i) const
Access the i-th bit of the scalar. From 0 (lsb) to 445 (msb).
Scalar448 operator*(const Scalar448 &other) const
scalar = (scalar * other) mod L
constexpr void unpoison(const T *p, size_t n)
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
constexpr void bigint_shr2(W y[], const W x[], size_t x_size, size_t shift)
constexpr size_t words_for_bits(size_t x)
void bigint_mul(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, const word y[], size_t y_size, size_t y_sw, word workspace[], size_t ws_size)
void carry(int64_t &h0, int64_t &h1)
constexpr auto load_le(ParamTs &&... params)
constexpr auto bigint_sub2(W x[], size_t x_size, const W y[], size_t y_size) -> W
constexpr auto bigint_add2_nc(W x[], size_t x_size, const W y[], size_t y_size) -> W
constexpr void copy_mem(T *out, const T *in, size_t n)