18#ifndef JAU_BIG_INT_OPS_HPP_
19#define JAU_BIG_INT_OPS_HPP_
39 #undef JAU_FORCE_MP_WORD_32_BITS
40 #if !defined( JAU_FORCE_MP_WORD_32_BITS )
53 #if defined(__SIZEOF_INT128__)
71 carry = c1 | (z < carry);
104 carry = c1 | (z > t0);
145 inline void mul64x64_128(
const uint64_t a,
const uint64_t b, uint64_t& lo, uint64_t& hi)
noexcept {
147 const uint128_t r =
static_cast<uint128_t
>(a) * b;
148 hi = (r >> 64) & 0xFFFFFFFFFFFFFFFFUL;
149 lo = (r ) & 0xFFFFFFFFFFFFFFFFUL;
156 constexpr const size_t HWORD_BITS = 32;
157 constexpr const uint32_t HWORD_MASK = 0xFFFFFFFFU;
159 const uint32_t a_hi = (a >> HWORD_BITS);
160 const uint32_t a_lo = (a & HWORD_MASK);
161 const uint32_t b_hi = (b >> HWORD_BITS);
162 const uint32_t b_lo = (b & HWORD_MASK);
164 uint64_t x0 =
static_cast<uint64_t
>(a_hi) * b_hi;
165 uint64_t x1 =
static_cast<uint64_t
>(a_lo) * b_hi;
166 uint64_t x2 =
static_cast<uint64_t
>(a_hi) * b_lo;
167 uint64_t x3 =
static_cast<uint64_t
>(a_lo) * b_lo;
170 x2 += x3 >> HWORD_BITS;
176 x0 +=
static_cast<uint64_t
>(
static_cast<bool>(x2 < x1)) << HWORD_BITS;
178 hi = x0 + (x2 >> HWORD_BITS);
179 lo = ((x2 & HWORD_MASK) << HWORD_BITS) + (x3 & HWORD_MASK);
279 assert(x_size >= y_size);
281 const size_t blocks = y_size - (y_size % 8);
283 for(
size_t i = 0; i != blocks; i += 8) {
286 for(
size_t i = blocks; i != y_size; ++i) {
289 for(
size_t i = y_size; i != x_size; ++i) {
302 const size_t blocks = y_size - (y_size % 8);
304 for(
size_t i = 0; i != blocks; i += 8) {
305 carry =
word8_add3(z + i, x + i, y + i, carry);
307 for(
size_t i = blocks; i != y_size; ++i) {
310 for(
size_t i = y_size; i != x_size; ++i) {
317 z[x_size > y_size ? x_size : y_size] +=
325 assert(x_size >= y_size);
327 const size_t blocks = y_size - (y_size % 8);
329 for(
size_t i = 0; i != blocks; i += 8) {
332 for(
size_t i = blocks; i != y_size; ++i) {
333 x[i] =
word_sub(x[i], y[i], borrow);
335 for(
size_t i = y_size; i != x_size; ++i) {
345 const size_t blocks = y_size - (y_size % 8);
347 for(
size_t i = 0; i != blocks; i += 8) {
350 for(
size_t i = blocks; i != y_size; ++i) {
351 x[i] =
word_sub(y[i], x[i], borrow);
360 assert(x_size >= y_size);
362 const size_t blocks = y_size - (y_size % 8);
364 for(
size_t i = 0; i != blocks; i += 8) {
365 borrow =
word8_sub3(z + i, x + i, y + i, borrow);
367 for(
size_t i = blocks; i != y_size; ++i) {
368 z[i] =
word_sub(x[i], y[i], borrow);
370 for(
size_t i = y_size; i != x_size; ++i) {
391 const int32_t relative_size =
bigint_cmp(x, x_size, y, y_size);
394 const bool need_swap = relative_size < 0;
407 return relative_size;
414 const size_t blocks = x_size - (x_size % 8);
418 for(
size_t i = 0; i != blocks; i += 8) {
421 for(
size_t i = blocks; i != x_size; ++i) {
428 const size_t blocks = x_size - (x_size % 8);
432 for(
size_t i = 0; i != blocks; i += 8) {
435 for(
size_t i = blocks; i != x_size; ++i) {
441 inline void bigint_shl1(
mp_word_t x[],
size_t x_size,
size_t x_words,
size_t word_shift,
size_t bit_shift)
noexcept {
442 std::memmove(x + word_shift, x,
sizeof(
mp_word_t)*x_words);
443 std::memset(x, 0,
sizeof(
mp_word_t)*word_shift);
446 const size_t carry_shift = carry_mask.if_set_return(
mp_word_bits - bit_shift);
449 for(
size_t i = word_shift; i != x_size; ++i) {
451 x[i] = (w << bit_shift) | carry;
452 carry = carry_mask.if_set_return(w >> carry_shift);
457 const size_t top = x_size >= word_shift ? (x_size - word_shift) : 0;
460 std::memmove(x, x + word_shift,
sizeof(
mp_word_t)*top);
465 const size_t carry_shift = carry_mask.if_set_return(
mp_word_bits - bit_shift);
468 for(
size_t i = 0; i != top; ++i) {
470 x[top-i-1] = (w >> bit_shift) | carry;
471 carry = carry_mask.if_set_return(w << carry_shift);
476 std::memmove(y + word_shift, x,
sizeof(
mp_word_t)*x_size);
479 const size_t carry_shift = carry_mask.if_set_return(
mp_word_bits - bit_shift);
482 for(
size_t i = word_shift; i != x_size + word_shift + 1; ++i) {
484 y[i] = (w << bit_shift) | carry;
485 carry = carry_mask.if_set_return(w >> carry_shift);
489 const size_t new_size = x_size < word_shift ? 0 : (x_size - word_shift);
492 std::memmove(y, x + word_shift,
sizeof(
mp_word_t)*new_size);
495 const size_t carry_shift = carry_mask.if_set_return(
mp_word_bits - bit_shift);
498 for(
size_t i = new_size; i > 0; --i) {
500 y[i-1] = (w >> bit_shift) | carry;
501 carry = carry_mask.if_set_return(w << carry_shift);
510 const mp_word_t y[],
size_t y_size)
noexcept
512 assert(z_size >= x_size + y_size);
514 const size_t x_size_8 = x_size - (x_size % 8);
516 for(
size_t i=0; i<z_size; ++i) { z[i]=0; }
518 for(
size_t i = 0; i != y_size; ++i) {
523 for(
size_t j = 0; j != x_size_8; j += 8) {
526 for(
size_t j = x_size_8; j != x_size; ++j) {
527 z[i+j] =
word_madd3(x[j], y_i, z[i+j], carry);
551 if(high_top_bit || high >= d) {
577 const size_t common_elems =
std::min(x_size, y_size);
580 for(
size_t i = 0; i != common_elems; i++) {
581 diff |= (x[i] ^ y[i]);
587 for(
size_t i = x_size; i != y_size; i++) {
590 }
else if(y_size < x_size) {
591 for(
size_t i = y_size; i != x_size; i++) {
606 const size_t common_elems =
jau::min(x_size, y_size);
610 for(
size_t i = 0; i != common_elems; i++)
614 is_lt = eq.select_mask(is_lt, lt);
617 if(x_size < y_size) {
619 for(
size_t i = x_size; i != y_size; i++) {
624 }
else if(y_size < x_size) {
626 for(
size_t i = y_size; i != x_size; i++) {
650 const size_t common_elems =
jau::min(x_size, y_size);
654 for(
size_t i = 0; i != common_elems; i++) {
657 result = is_eq.select(result, is_lt.select(LT, GT));
659 if(x_size < y_size) {
661 for(
size_t i = x_size; i != y_size; i++) {
666 }
else if(y_size < x_size) {
668 for(
size_t i = y_size; i != x_size; i++) {
675 return static_cast<int>(result);
A Mask type used for constant-time operations.
static Mask< T > is_equal(T x, T y) noexcept
Return a Mask<T> which is set if x == y.
static Mask< T > expand(T v) noexcept
Return a Mask<T> which is set if v is != 0.
static Mask< T > is_zero(T x) noexcept
Return a Mask<T> which is set if v is == 0 or cleared otherwise.
static Mask< T > is_lt(T x, T y) noexcept
Return a Mask<T> which is set if x < y.
math_error_t::div_by_zero, i.e.
consteval_cxx20 bool is_builtin_int128_available() noexcept
constexpr T min(const T x, const T y) noexcept
Returns the minimum of two integrals (w/ branching) in O(1)
constexpr size_t pointer_bit_size() noexcept
Returns the compile time pointer architecture size in bits.
void unpoison(const T *p, size_t n)
void conditional_swap(bool cnd, T &x, T &y) noexcept
void conditional_swap_ptr(bool cnd, T &x, T &y) noexcept
constexpr size_t best_word_byte_size()
mp_word_t word8_madd3(mp_word_t z[8], const mp_word_t x[8], mp_word_t y, mp_word_t carry) noexcept
mp_word_t word8_sub2(mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
CT::Mask< mp_word_t > bigint_ct_is_lt(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size, bool lt_or_equal=false) noexcept
Compare x and y Return ~0 if x[0:x_size] < y[0:y_size] or 0 otherwise If lt_or_equal is true,...
CT::Mask< mp_word_t > bigint_ct_is_eq(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
mp_word_t word8_sub2_rev(mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
int bigint_cmp(const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Compare unsigned x and y mp_word_t.
mp_word_t bigint_divop(mp_word_t n1, mp_word_t n0, mp_word_t d)
Computes ((n1<<bits) + n0) / d.
int32_t bigint_sub_abs(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Set z to abs(x-y), ie if x >= y, then compute z = x - y Otherwise compute z = y - x No borrow is poss...
mp_word_t bigint_add2(mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Two operand addition with carry out.
mp_word_t word8_linmul3(mp_word_t z[8], const mp_word_t x[8], mp_word_t y, mp_word_t carry) noexcept
mp_word_t word_sub(mp_word_t x, mp_word_t y, mp_word_t &carry) noexcept
mp_word_t word8_sub3(mp_word_t z[8], const mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
void bigint_shr1(mp_word_t x[], size_t x_size, size_t word_shift, size_t bit_shift) noexcept
mp_word_t bigint_linmul2(mp_word_t x[], size_t x_size, mp_word_t y) noexcept
void bigint_linmul3(mp_word_t z[], const mp_word_t x[], size_t x_size, mp_word_t y) noexcept
mp_word_t bigint_sub3(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Three operand subtraction.
mp_word_t bigint_add3_nc(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Three operand addition with carry out.
void bigint_shl2(mp_word_t y[], const mp_word_t x[], size_t x_size, size_t word_shift, size_t bit_shift) noexcept
void bigint_add3(mp_word_t z[], const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Three operand addition.
mp_word_t bigint_sub2(mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
Two operand subtraction.
void mul64x64_128(const uint64_t a, const uint64_t b, uint64_t &lo, uint64_t &hi) noexcept
64x64->128 bit multiplication
mp_word_t word8_linmul2(mp_word_t x[8], mp_word_t y, mp_word_t carry) noexcept
mp_word_t word8_add3(mp_word_t z[8], const mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
mp_word_t bigint_modop(mp_word_t n1, mp_word_t n0, mp_word_t d)
Compute ((n1<<bits) + n0) % d.
mp_word_t word_madd3(mp_word_t a, mp_word_t b, mp_word_t c, mp_word_t &d) noexcept
Word Multiply/Add.
mp_word_t word_madd2(mp_word_t a, mp_word_t b, mp_word_t &c) noexcept
Word Multiply/Add.
void bigint_shl1(mp_word_t x[], size_t x_size, size_t x_words, size_t word_shift, size_t bit_shift) noexcept
void basecase_mul(mp_word_t z[], size_t z_size, const mp_word_t x[], size_t x_size, const mp_word_t y[], size_t y_size) noexcept
mp_word_t word8_add2(mp_word_t x[8], const mp_word_t y[8], mp_word_t carry) noexcept
void bigint_shr2(mp_word_t y[], const mp_word_t x[], size_t x_size, size_t word_shift, size_t bit_shift) noexcept
mp_word_t word_add(const mp_word_t x, const mp_word_t y, mp_word_t &carry) noexcept
void bigint_sub2_rev(mp_word_t x[], const mp_word_t y[], size_t y_size) noexcept
Two operand subtraction, x = y - x; assumes y >= x.
big_int_t (this file) (c) 2024 Gothel Software e.K.
constexpr const bool has_mp_dword
jau::uint_bytes< impl::best_word_byte_size()>::type mp_word_t
constexpr const size_t mp_word_bits
jau::uint_bytes< impl::best_word_byte_size() *2 >::type mp_dword_t
constexpr const mp_word_t mp_word_max