Skip to content

Commit

Permalink
multiprecision: big_uint: fix add
Browse files Browse the repository at this point in the history
  • Loading branch information
ioxid committed Dec 16, 2024
1 parent c37ea13 commit e95de6b
Showing 1 changed file with 29 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ namespace nil::crypto3::multiprecision {
template<std::size_t Bits1, std::size_t Bits2, std::size_t Bits3>
constexpr void add_constexpr(big_uint<Bits1>& result, const big_uint<Bits2>& a,
const big_uint<Bits3>& b) noexcept {
// TODO(ioxid): fix this
//
// This is the generic, C++ only version of addition.
// It's also used for all constexpr branches, hence the name.
// Nothing fancy, just let uintmax_t take the strain:
//
double_limb_type carry = 0;
std::size_t s = a.limbs_count();
if (s == 1) {
std::size_t as = a.used_limbs();
std::size_t bs = b.used_limbs();
auto [m, x] = std::minmax(as, bs);
if (x == 1) {
double_limb_type r = static_cast<double_limb_type>(*a.limbs()) +
static_cast<double_limb_type>(*b.limbs());
double_limb_type mask = big_uint<Bits1>::upper_limb_mask;
Expand All @@ -45,25 +45,47 @@ namespace nil::crypto3::multiprecision {
}
return;
}
result.zero_after(x);

const_limb_pointer pa = a.limbs();
const_limb_pointer pb = b.limbs();
limb_pointer pr = result.limbs();
limb_pointer pr_end = pr + m;

if (as < bs) {
std::swap(pa, pb);
}

// First where a and b overlap:
for (std::size_t i = 0; i < s; ++i) {
while (pr != pr_end) {
carry += static_cast<double_limb_type>(*pa) + static_cast<double_limb_type>(*pb);
*pr = static_cast<limb_type>(carry);
carry >>= limb_bits;
++pr, ++pa, ++pb;
}
pr_end += x - m;

// Now where only a has digits:
while (pr != pr_end) {
if (!carry) {
if (pa != pr) {
std::copy(pa, pa + (pr_end - pr), pr);
}
break;
}
carry += static_cast<double_limb_type>(*pa);
*pr = static_cast<limb_type>(carry);
carry >>= limb_bits;
++pr, ++pa;
}

if constexpr (Bits1 % limb_bits == 0) {
result.set_carry(carry);
} else {
limb_type mask = big_uint<Bits1>::upper_limb_mask;
// If we have set any bit above "Bits", then we have a carry.
if (result.limbs()[s - 1] & ~mask) {
result.limbs()[s - 1] &= mask;
if (result.limbs()[result.limbs_count() - 1] & ~mask) {
result.limbs()[result.limbs_count() - 1] &= mask;
result.set_carry(true);
}
}
Expand Down Expand Up @@ -168,8 +190,6 @@ namespace nil::crypto3::multiprecision {
if (std::is_constant_evaluated()) {
add_constexpr(result, a, b);
} else {
// TODO(ioxid): fix this
// Nothing fancy, just let uintmax_t take the strain:
std::size_t as = a.used_limbs();
std::size_t bs = b.used_limbs();
auto [m, x] = std::minmax(as, bs);
Expand Down

0 comments on commit e95de6b

Please sign in to comment.