10#ifndef BOTAN_MP_CORE_OPS_H_
11#define BOTAN_MP_CORE_OPS_H_
13#include <botan/assert.h>
14#include <botan/types.h>
15#include <botan/internal/ct_utils.h>
16#include <botan/internal/mem_utils.h>
17#include <botan/internal/mp_asmi.h>
32 for(
size_t i = 0; i != size; ++i) {
35 x[i] = mask.select(b, a);
36 y[i] = mask.select(a, b);
50 for(
size_t i = 0; i != size; ++i) {
54 return (mask &
carry);
62inline constexpr auto bigint_cnd_sub(W cnd, W x[],
const W y[],
size_t size) -> W {
67 for(
size_t i = 0; i != size; ++i) {
71 return (mask &
carry);
83 W
carry = mask.if_set_return(1);
84 for(
size_t i = 0; i != size; ++i) {
86 x[i] = mask.select(z, x[i]);
94inline constexpr auto bigint_add2(W x[],
size_t x_size,
const W y[],
size_t y_size) -> W {
99 const size_t blocks = y_size - (y_size % 8);
101 for(
size_t i = 0; i != blocks; i += 8) {
105 for(
size_t i = blocks; i != y_size; ++i) {
109 for(
size_t i = y_size; i != x_size; ++i) {
120inline constexpr auto bigint_add3(W z[],
const W x[],
size_t x_size,
const W y[],
size_t y_size) -> W {
121 if(x_size < y_size) {
127 const size_t blocks = y_size - (y_size % 8);
129 for(
size_t i = 0; i != blocks; i += 8) {
133 for(
size_t i = blocks; i != y_size; ++i) {
137 for(
size_t i = y_size; i != x_size; ++i) {
148inline constexpr auto bigint_sub2(W x[],
size_t x_size,
const W y[],
size_t y_size) -> W {
153 const size_t blocks = y_size - (y_size % 8);
155 for(
size_t i = 0; i != blocks; i += 8) {
159 for(
size_t i = blocks; i != y_size; ++i) {
160 x[i] =
word_sub(x[i], y[i], &borrow);
163 for(
size_t i = y_size; i != x_size; ++i) {
164 x[i] =
word_sub(x[i],
static_cast<W
>(0), &borrow);
177 for(
size_t i = 0; i != y_size; ++i) {
178 x[i] =
word_sub(y[i], x[i], &borrow);
192inline constexpr auto bigint_sub3(W z[],
const W x[],
size_t x_size,
const W y[],
size_t y_size) -> W {
197 const size_t blocks = y_size - (y_size % 8);
199 for(
size_t i = 0; i != blocks; i += 8) {
200 borrow =
word8_sub3(z + i, x + i, y + i, borrow);
203 for(
size_t i = blocks; i != y_size; ++i) {
204 z[i] =
word_sub(x[i], y[i], &borrow);
207 for(
size_t i = y_size; i != x_size; ++i) {
208 z[i] =
word_sub(x[i],
static_cast<W
>(0), &borrow);
228 const size_t blocks = N - (N % 8);
230 for(
size_t i = 0; i != blocks; i += 8) {
231 borrow =
word8_sub3(z + i, x + i, p + i, borrow);
234 for(
size_t i = blocks; i != N; ++i) {
235 z[i] =
word_sub(x[i], p[i], &borrow);
238 borrow = (x0 - borrow) > x0;
253template <
size_t N, WordType W>
257 for(
size_t i = 0; i != N; ++i) {
258 z[i] =
word_sub(x[i], y[i], &borrow);
261 borrow = (x0 - borrow) > x0;
288 const size_t blocks = N - (N % 8);
290 for(
size_t i = 0; i != blocks; i += 8) {
291 borrow0 =
word8_sub3(ws0 + i, x + i, y + i, borrow0);
292 borrow1 =
word8_sub3(ws1 + i, y + i, x + i, borrow1);
295 for(
size_t i = blocks; i != N; ++i) {
296 ws0[i] =
word_sub(x[i], y[i], &borrow0);
297 ws1[i] =
word_sub(y[i], x[i], &borrow1);
309inline constexpr void bigint_shl1(W x[],
size_t x_size,
size_t x_words,
size_t shift) {
323 for(
size_t i = word_shift; i != x_size; ++i) {
325 x[i] = (w << bit_shift) |
carry;
331inline constexpr void bigint_shr1(W x[],
size_t x_size,
size_t shift) {
335 const size_t top = x_size >= word_shift ? (x_size - word_shift) : 0;
347 for(
size_t i = 0; i != top; ++i) {
348 const W w = x[top - i - 1];
349 x[top - i - 1] = (w >> bit_shift) |
carry;
355inline constexpr void bigint_shl2(W y[],
size_t y_size,
const W x[],
size_t x_size,
size_t shift) {
364 zeroize_buffer(y + word_shift + x_size, y_size - word_shift - x_size);
370 for(
size_t i = word_shift; i != x_size + word_shift + 1; ++i) {
372 y[i] = (w << bit_shift) |
carry;
378inline constexpr void bigint_shr2(W y[],
size_t y_size,
const W x[],
size_t x_size,
size_t shift) {
381 const size_t new_size = x_size < word_shift ? 0 : (x_size - word_shift);
394 for(
size_t i = new_size; i > 0; --i) {
396 y[i - 1] = (w >> bit_shift) |
carry;
405[[nodiscard]]
inline constexpr auto bigint_linmul2(W x[],
size_t x_size, W y) -> W {
408 for(
size_t i = 0; i != x_size; ++i) {
417 const size_t blocks = x_size - (x_size % 8);
421 for(
size_t i = 0; i != blocks; i += 8) {
425 for(
size_t i = blocks; i != x_size; ++i) {
439inline constexpr int32_t
bigint_cmp(
const W x[],
size_t x_size,
const W y[],
size_t y_size) {
440 static_assert(
sizeof(W) >=
sizeof(uint32_t),
"Size assumption");
442 const W LT =
static_cast<W
>(-1);
446 const size_t common_elems = std::min(x_size, y_size);
450 for(
size_t i = 0; i != common_elems; i++) {
454 result = is_eq.select(result, is_lt.select(LT, GT));
457 if(x_size < y_size) {
459 for(
size_t i = x_size; i != y_size; i++) {
465 }
else if(y_size < x_size) {
467 for(
size_t i = y_size; i != x_size; i++) {
477 return static_cast<int32_t
>(result);
486inline constexpr auto bigint_ct_is_lt(
const W x[],
size_t x_size,
const W y[],
size_t y_size,
bool lt_or_equal =
false)
488 const size_t common_elems = std::min(x_size, y_size);
492 for(
size_t i = 0; i != common_elems; i++) {
495 is_lt = eq.select_mask(is_lt, lt);
498 if(x_size < y_size) {
500 for(
size_t i = x_size; i != y_size; i++) {
505 }
else if(y_size < x_size) {
507 for(
size_t i = y_size; i != x_size; i++) {
520 const size_t common_elems = std::min(x_size, y_size);
524 for(
size_t i = 0; i != common_elems; i++) {
525 diff |= (x[i] ^ y[i]);
529 if(x_size < y_size) {
530 for(
size_t i = x_size; i != y_size; i++) {
533 }
else if(y_size < x_size) {
534 for(
size_t i = y_size; i != x_size; i++) {
542template <WordType W, W div>
546 if constexpr(div == 10 && std::same_as<W, uint32_t>) {
547 constexpr W magic = 0xCCCCCCCD;
548 constexpr size_t shift = 35;
549 return std::make_pair(magic, shift);
550 }
else if constexpr(div == 10 && std::same_as<W, uint64_t>) {
551 constexpr W magic = 0xCCCCCCCCCCCCCCCD;
552 constexpr size_t shift = 67;
553 return std::make_pair(magic, shift);
561 return static_cast<W
>(p >> shift);
585 return vartime_div_2to1_max_d(n1, n0);
593 if(!std::is_constant_evaluated()) {
594#if defined(BOTAN_MP_USE_X86_64_ASM)
595 if constexpr(std::same_as<W, uint64_t>) {
599 asm(
"divq %[v]" :
"=a"(quotient),
"=d"(remainder) : [v]
"r"(m_divisor),
"a"(n0),
"d"(n1) :
"cc");
604#if !defined(BOTAN_BUILD_COMPILER_IS_CLANGCL)
615 n <<= WordInfo<W>::bits;
617 return static_cast<W
>(n / m_divisor);
632 if(high_top_bit || high >= m_divisor) {
657 static inline constexpr W vartime_div_2to1_max_d(W n1, W n0) {
704 BOTAN_ARG_CHECK(a % 2 == 1,
"Cannot compute Montgomery inverse of an even integer");
714 for(
size_t i = 0; i != iter; ++i) {
724template <
size_t S, WordType W,
size_t N>
726 static_assert(N >= 1,
"Invalid input size");
727 static_assert(S > 0,
"Zero shift not supported");
728 static_assert(S < WordInfo<W>::bits,
"Shift too large");
732 for(
size_t i = N - 1; i != 0; --i) {
740template <
size_t S, WordType W,
size_t N>
742 static_assert(N >= 1,
"Invalid input size");
743 static_assert(S > 0,
"Zero shift not supported");
744 static_assert(S < WordInfo<W>::bits,
"Shift too large");
748 for(
size_t i = 0; i != N - 1; ++i) {
757template <WordType W,
size_t N>
760 const constexpr size_t C = N - 1;
766 const constexpr size_t S = (C + NPW - 1) / NPW;
768 static_assert(S > 0,
"Input too small");
770 auto hex2int = [](
char c) -> int8_t {
771 if(c >=
'0' && c <=
'9') {
772 return static_cast<int8_t
>(c -
'0');
773 }
else if(c >=
'a' && c <=
'f') {
774 return static_cast<int8_t
>(c -
'a' + 10);
775 }
else if(c >=
'A' && c <=
'F') {
776 return static_cast<int8_t
>(c -
'A' + 10);
782 std::array<W, S> r = {0};
784 for(
size_t i = 0; i != C; ++i) {
785 const int8_t c = hex2int(s[i]);
817template <
size_t N, WordType W>
818constexpr inline void comba_mul(W z[2 * N],
const W x[N],
const W y[N]) {
819 if(!std::is_constant_evaluated()) {
820 if constexpr(std::same_as<W, word> && N == 4) {
823 if constexpr(std::same_as<W, word> && N == 6) {
826 if constexpr(std::same_as<W, word> && N == 7) {
829 if constexpr(std::same_as<W, word> && N == 8) {
832 if constexpr(std::same_as<W, word> && N == 9) {
835 if constexpr(std::same_as<W, word> && N == 16) {
842 for(
size_t i = 0; i != 2 * N; ++i) {
843 const size_t start = i + 1 < N ? 0 : i + 1 - N;
844 const size_t end = std::min(N, i + 1);
846 for(
size_t j = start; j != end; ++j) {
847 accum.
mul(x[j], y[i - j]);
853template <
size_t N, WordType W>
854constexpr inline void comba_sqr(W z[2 * N],
const W x[N]) {
855 if(!std::is_constant_evaluated()) {
856 if constexpr(std::same_as<W, word> && N == 4) {
859 if constexpr(std::same_as<W, word> && N == 6) {
862 if constexpr(std::same_as<W, word> && N == 7) {
865 if constexpr(std::same_as<W, word> && N == 8) {
868 if constexpr(std::same_as<W, word> && N == 9) {
871 if constexpr(std::same_as<W, word> && N == 16) {
878 for(
size_t i = 0; i != 2 * N; ++i) {
879 const size_t start = i + 1 < N ? 0 : i + 1 - N;
880 const size_t end = std::min(N, i + 1);
882 for(
size_t j = start; j != end; ++j) {
883 accum.
mul(x[j], x[i - j]);
906 word r[],
const word z[],
size_t z_size,
const word p[],
size_t p_size,
word p_dash,
word ws[]);
924 word r[],
const word z[],
const word p[],
size_t p_size,
word p_dash,
word ws[],
size_t ws_size) {
925 const size_t z_size = 2 * p_size;
927 BOTAN_ARG_CHECK(ws_size >= p_size,
"Montgomery reduction workspace too small");
931 }
else if(p_size == 6) {
933 }
else if(p_size == 8) {
935 }
else if(p_size == 12) {
937 }
else if(p_size == 16) {
939 }
else if(p_size == 24) {
941 }
else if(p_size == 32) {
979void bigint_sqr(
word z[],
size_t z_size,
const word x[],
size_t x_size,
size_t x_sw,
word workspace[],
size_t ws_size);
991template <WordType W,
size_t N, W C>
993 static_assert(N >= 2);
995 std::array<W, N> hi = {};
1000 for(
size_t i = 0; i != N; ++i) {
1005 word carry_c[2] = {0};
1012 std::array<W, N> r = {};
1027#if defined(BOTAN_MP_USE_X86_64_ASM) && defined(__GNUC__) && !defined(__clang__)
1028 if constexpr(N == 4 && std::same_as<W, uint64_t>) {
1029 if(!std::is_constant_evaluated()) {
1031 movq 0(%[x]), %[borrow]
1032 subq %[p0], %[borrow]
1033 movq %[borrow], 0(%[r])
1034 movq 8(%[x]), %[borrow]
1036 movq %[borrow], 8(%[r])
1037 movq 16(%[x]), %[borrow]
1039 movq %[borrow], 16(%[r])
1040 movq 24(%[x]), %[borrow]
1042 movq %[borrow], 24(%[r])
1043 sbbq %[borrow],%[borrow]
1046 : [borrow] "=r"(borrow)
1047 : [x]
"r"(hi.data()), [p0]
"r"(
P0), [r]
"r"(r.data()),
"0"(borrow)
1058 for(
size_t i = 1; i != N; ++i) {
1070template <
size_t WindowBits,
typename W,
size_t N>
1072 static_assert(WindowBits >= 1 && WindowBits <= 7);
1074 constexpr uint8_t WindowMask =
static_cast<uint8_t
>(1 << WindowBits) - 1;
1076 constexpr size_t W_bits =
sizeof(W) * 8;
1077 const auto bit_shift = offset % W_bits;
1078 const auto word_offset = words.size() - 1 - (offset / W_bits);
1080 const bool single_byte_window = bit_shift <= (W_bits - WindowBits) || word_offset == 0;
1082 const auto w0 = words[word_offset];
1084 if(single_byte_window) {
1085 return (w0 >> bit_shift) & WindowMask;
1088 const auto w1 = words[word_offset - 1];
1089 const auto combined = ((w0 >> bit_shift) | (w1 << (W_bits - bit_shift)));
1090 return combined & WindowMask;
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_DEBUG_ASSERT(expr)
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
static constexpr Mask< T > expand(T v)
static constexpr Mask< T > is_equal(T x, T y)
static constexpr Mask< T > is_lt(T x, T y)
static constexpr Mask< T > is_zero(T x)
constexpr W vartime_mod_2to1(W n1, W n0) const
constexpr W vartime_div_2to1(W n1, W n0) const
constexpr divide_precomp(W divisor)
constexpr void mul(W x, W y)
constexpr Mask< T > conditional_copy_mem(Mask< T > mask, T *dest, const T *if_set, const T *if_unset, size_t elems)
constexpr void unpoison(const T *p, size_t n)
constexpr Mask< T > conditional_assign_mem(T cnd, T *dest, const T *src, size_t elems)
constexpr void bigint_cnd_abs(W cnd, W x[], size_t size)
constexpr auto bigint_add2(W x[], size_t x_size, const W y[], size_t y_size) -> W
constexpr void bigint_linmul3(W z[], const W x[], size_t x_size, W y)
constexpr auto bigint_cnd_sub(W cnd, W x[], const W y[], size_t size) -> W
constexpr auto bigint_add3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
constexpr void bigint_cnd_swap(W cnd, W x[], W y[], size_t size)
constexpr auto word8_sub3(W z[8], const W x[8], const W y[8], W carry) -> W
constexpr W shift_left(std::array< W, N > &x)
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 uint64_t carry_shift(const donna128 &a, size_t shift)
BOTAN_FUZZER_API void basecase_sqr(word z[], size_t z_size, const word x[], size_t x_size)
constexpr size_t read_window_bits(std::span< const W, N > words, size_t offset)
void bigint_comba_sqr4(word z[8], const word x[4])
void bigint_comba_sqr6(word z[12], const word x[6])
constexpr void bigint_shr1(W x[], size_t x_size, size_t shift)
constexpr auto word8_add3(W z[8], const W x[8], const W y[8], W carry) -> W
BOTAN_FUZZER_API void bigint_monty_redc_6(word r[6], const word z[12], const word p[6], word p_dash, word ws[6])
constexpr void comba_mul(W z[2 *N], const W x[N], const W y[N])
constexpr auto word8_sub2(W x[8], const W y[8], W carry) -> W
void bigint_comba_sqr7(word z[14], const word x[7])
void bigint_comba_mul4(word z[8], const word x[4], const word y[4])
constexpr auto word_madd2(W a, W b, W *c) -> W
void bigint_sqr(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, word workspace[], size_t ws_size)
void bigint_comba_mul16(word z[32], const word x[16], const word y[16])
BOTAN_FUZZER_API void bigint_monty_redc_24(word r[24], const word z[48], const word p[24], word p_dash, word ws[24])
constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
constexpr auto monty_inverse(W a) -> W
BOTAN_FUZZER_API void bigint_monty_redc_generic(word r[], const word z[], size_t z_size, const word p[], size_t p_size, word p_dash, word ws[])
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 zeroize_buffer(T buf[], size_t n)
void bigint_comba_mul6(word z[12], const word x[6], const word y[6])
constexpr void bigint_shl1(W x[], size_t x_size, size_t x_words, size_t shift)
constexpr auto bigint_ct_is_eq(const W x[], size_t x_size, const W y[], size_t y_size) -> CT::Mask< W >
constexpr int32_t bigint_cmp(const W x[], size_t x_size, const W y[], size_t y_size)
consteval std::pair< W, size_t > div_magic()
BOTAN_FUZZER_API void bigint_monty_redc_4(word r[4], const word z[8], const word p[4], word p_dash, word ws[4])
void bigint_monty_redc_inplace(word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size)
void bigint_monty_redc(word r[], const word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size)
void bigint_comba_mul7(word z[14], const word x[7], const word y[7])
constexpr W divide_10(W x)
constexpr W bigint_cnd_add(W cnd, W x[], const W y[], size_t size)
void unchecked_copy_memory(T *out, const T *in, size_t n)
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
void bigint_comba_mul9(word z[18], const word x[9], const word y[9])
BOTAN_FUZZER_API void bigint_monty_redc_12(word r[12], const word z[24], const word p[12], word p_dash, word ws[12])
void carry(int64_t &h0, int64_t &h1)
BOTAN_FUZZER_API void bigint_monty_redc_16(word r[16], const word z[32], const word p[16], word p_dash, word ws[16])
constexpr void bigint_shr2(W y[], size_t y_size, const W x[], size_t x_size, size_t shift)
void bigint_comba_mul24(word z[48], const word x[24], const word y[24])
constexpr auto bigint_sub_abs(W z[], const W x[], const W y[], size_t N, W ws[]) -> CT::Mask< W >
constexpr auto bigint_ct_is_lt(const W x[], size_t x_size, const W y[], size_t y_size, bool lt_or_equal=false) -> CT::Mask< W >
constexpr std::array< W, N > redc_crandall(std::span< const W, 2 *N > z)
constexpr auto word8_add2(W x[8], const W y[8], W carry) -> W
constexpr auto bigint_sub2(W x[], size_t x_size, const W y[], size_t y_size) -> W
void bigint_comba_sqr8(word z[16], const word x[8])
constexpr auto hex_to_words(const char(&s)[N])
void bigint_comba_sqr16(word z[32], const word x[16])
constexpr void bigint_shl2(W y[], size_t y_size, const W x[], size_t x_size, size_t shift)
constexpr void bigint_sub2_rev(W x[], const W y[], size_t y_size)
void bigint_comba_sqr9(word z[18], const word x[9])
constexpr auto word8_linmul3(W z[8], const W x[8], W y, W carry) -> W
BOTAN_FUZZER_API void basecase_mul(word z[], size_t z_size, const word x[], size_t x_size, const word y[], size_t y_size)
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
The native machine word, used as the limb type for multiprecision integers.
void bigint_comba_sqr24(word z[48], const word x[24])
void bigint_comba_mul8(word z[16], const word x[8], const word y[8])
BOTAN_FUZZER_API void bigint_monty_redc_8(word r[8], const word z[16], const word p[8], word p_dash, word ws[8])
constexpr W shift_right(std::array< W, N > &x)
BOTAN_FUZZER_API void bigint_monty_redc_32(word r[32], const word z[64], const word p[32], word p_dash, word ws[32])
constexpr auto word_madd3(W a, W b, W c, W *d) -> W
constexpr auto bigint_linmul2(W x[], size_t x_size, W y) -> W