Skip to content

Commit

Permalink
multiprecision: big_uint: refactor operators WIP 8
Browse files Browse the repository at this point in the history
  • Loading branch information
ioxid committed Dec 13, 2024
1 parent 5b09cdf commit 4ec6f44
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp"
#include "nil/crypto3/multiprecision/detail/big_uint/storage.hpp"
#include "nil/crypto3/multiprecision/detail/integer_ops_base.hpp"
#include "nil/crypto3/multiprecision/detail/integer_utils.hpp"
#include "nil/crypto3/multiprecision/detail/type_traits.hpp"

namespace nil::crypto3::multiprecision::detail {
Expand Down Expand Up @@ -636,7 +637,7 @@ namespace nil::crypto3::multiprecision::detail {
template<std::size_t Bits, typename SI, typename modular_ops_t,
typename std::enable_if_t<std::is_integral_v<SI> && std::is_signed_v<SI>, int> = 0>
constexpr void init_raw_base(big_uint<Bits> &raw_base, SI b, const modular_ops_t &ops) {
ops.adjust_modular(raw_base, detail::as_big_uint(unsigned_abs(b)));
ops.adjust_modular(raw_base, detail::as_big_uint(detail::unsigned_abs(b)));
if (b < 0) {
ops.negate(raw_base);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#include "nil/crypto3/multiprecision/detail/big_mod/big_mod_impl.hpp"
#include "nil/crypto3/multiprecision/detail/big_mod/ops/inverse.hpp"
#include "nil/crypto3/multiprecision/detail/integer_ops_base.hpp"
#include "nil/crypto3/multiprecision/detail/integer_utils.hpp"
#include "nil/crypto3/multiprecision/detail/type_traits.hpp"

namespace nil::crypto3::multiprecision {
Expand All @@ -37,7 +37,7 @@ namespace nil::crypto3::multiprecision {
int> = 0>
constexpr big_mod_t pow(const big_mod_t &b, const T &e) {
if (e < 0) {
return pow(inverse_extended_euclidean_algorithm(b), unsigned_abs(e));
return pow(inverse_extended_euclidean_algorithm(b), detail::unsigned_abs(e));
}
return pow(b, static_cast<std::make_unsigned_t<T>>(e));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "nil/crypto3/multiprecision/detail/big_uint/type_traits.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/config.hpp"
#include "nil/crypto3/multiprecision/detail/endian.hpp"
#include "nil/crypto3/multiprecision/detail/integer_utils.hpp"
#include "nil/crypto3/multiprecision/detail/type_traits.hpp"

namespace nil::crypto3::multiprecision {
Expand Down Expand Up @@ -913,28 +914,90 @@ namespace nil::crypto3::multiprecision {

// Arithmetic operations

#define NIL_CO3_MP_BIG_UINT_SYMMETRIC_OPERATOR_IMPL(OP_, OP_ASSIGN_, FUNC_) \
NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE \
constexpr auto operator OP_(const T1& a, const T2& b) noexcept { \
detail::largest_big_uint_t<T1, T2> result; \
if constexpr (detail::is_big_uint_v<T1>) { \
detail::FUNC_(result, a, detail::as_limb_type_or_big_uint(b)); \
} else { \
detail::FUNC_(result, b, detail::as_limb_type_or_big_uint(a)); \
} \
return result; \
} \
NIL_CO3_MP_BIG_UINT_INTEGRAL_ASSIGNMENT_TEMPLATE \
constexpr auto& operator OP_ASSIGN_(big_uint_t & a, const T & b) noexcept { \
detail::FUNC_(a, a, detail::as_limb_type_or_big_uint(b)); \
return a; \
NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE
constexpr auto operator+(const T1& a, const T2& b) noexcept {
if constexpr (detail::is_big_uint_v<T1>) {
detail::largest_big_uint_t<T1, T2> result;
if constexpr (std::is_signed_v<T2>) {
auto b_abs = detail::unsigned_abs(b);
if (b < 0) {
detail::subtract(result, a, detail::as_limb_type_or_big_uint(b_abs));
}
detail::add(result, a, detail::as_limb_type_or_big_uint(b_abs));
} else {
detail::add(result, a, detail::as_limb_type_or_big_uint(b));
}
return result;
} else {
return b + a;
}
}
NIL_CO3_MP_BIG_UINT_INTEGRAL_ASSIGNMENT_TEMPLATE
constexpr auto& operator+=(big_uint_t& a, const T& b) noexcept {
if constexpr (std::is_signed_v<T>) {
auto b_abs = detail::unsigned_abs(b);
if (b < 0) {
detail::subtract(a, a, detail::as_limb_type_or_big_uint(b_abs));
}
detail::add(a, a, detail::as_limb_type_or_big_uint(b_abs));
} else {
detail::add(a, a, detail::as_limb_type_or_big_uint(b));
}
return a;
}

NIL_CO3_MP_BIG_UINT_SYMMETRIC_OPERATOR_IMPL(+, +=, add)
NIL_CO3_MP_BIG_UINT_SYMMETRIC_OPERATOR_IMPL(-, -=, subtract)
NIL_CO3_MP_BIG_UINT_SYMMETRIC_OPERATOR_IMPL(*, *=, multiply)
NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE
constexpr auto operator-(const T1& a, const T2& b) noexcept {
if constexpr (detail::is_big_uint_v<T1>) {
detail::largest_big_uint_t<T1, T2> result;
if constexpr (std::is_signed_v<T2>) {
auto b_abs = detail::unsigned_abs(b);
if (b < 0) {
detail::add(result, a, detail::as_limb_type_or_big_uint(b_abs));
}
detail::subtract(result, a, detail::as_limb_type_or_big_uint(b_abs));
} else {
detail::subtract(result, a, detail::as_limb_type_or_big_uint(b));
}
return result;
} else {
return (-b) + a;
}
}
NIL_CO3_MP_BIG_UINT_INTEGRAL_ASSIGNMENT_TEMPLATE
constexpr auto& operator-=(big_uint_t& a, const T& b) noexcept {
if constexpr (std::is_signed_v<T>) {
auto b_abs = detail::unsigned_abs(b);
if (b < 0) {
detail::add(a, a, detail::as_limb_type_or_big_uint(b_abs));
} else {
detail::subtract(a, a, detail::as_limb_type_or_big_uint(b_abs));
}
} else {
detail::subtract(a, a, detail::as_limb_type_or_big_uint(b));
}
return a;
}

#undef NIL_CO3_MP_BIG_UINT_SYMMETRIC_OPERATOR_IMPL
NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE
constexpr auto operator*(const T1& a, const T2& b) noexcept {
if constexpr (detail::is_big_uint_v<T1>) {
decltype(auto) b_unsigned = detail::unsigned_or_throw(b);
detail::largest_big_uint_t<T1, T2> result;
detail::multiply(result, a, detail::as_big_uint(b_unsigned));
return result;
} else {
return b * a;
}
}
NIL_CO3_MP_BIG_UINT_INTEGRAL_ASSIGNMENT_TEMPLATE
constexpr auto& operator*=(big_uint_t& a, const T& b) noexcept {
decltype(auto) b_unsigned = detail::unsigned_or_throw(b);
big_uint_t result;
detail::multiply(result, a, detail::as_big_uint(b_unsigned));
a = result;
return a;
}

NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE
constexpr auto operator/(const T1& a, const T2& b) noexcept {
Expand Down Expand Up @@ -977,24 +1040,21 @@ namespace nil::crypto3::multiprecision {
return a;
}

#define NIL_CO3_MP_BIG_UINT_BITWISE_OPERATOR_IMPL(OP_, OP_ASSIGN_, METHOD_) \
NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE \
constexpr auto operator OP_(const T1& a, const T2& b) noexcept { \
using largest_t = detail::largest_big_uint_t<T1, T2>; \
if constexpr (detail::is_big_uint_v<T1>) { \
largest_t result = a; \
result.METHOD_(detail::as_limb_type_or_big_uint(b)); \
return result; \
} else { \
largest_t result = b; \
result.METHOD_(detail::as_limb_type_or_big_uint(a)); \
return result; \
} \
} \
NIL_CO3_MP_BIG_UINT_INTEGRAL_ASSIGNMENT_TEMPLATE \
constexpr auto& operator OP_ASSIGN_(big_uint_t & a, const T & b) noexcept { \
a.METHOD_(detail::as_limb_type_or_big_uint(b)); \
return a; \
#define NIL_CO3_MP_BIG_UINT_BITWISE_OPERATOR_IMPL(OP_, OP_ASSIGN_, METHOD_) \
NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE \
constexpr auto operator OP_(const T1& a, const T2& b) noexcept { \
if constexpr (detail::is_big_uint_v<T1>) { \
detail::largest_big_uint_t<T1, T2> result = a; \
result.METHOD_(detail::as_limb_type_or_big_uint(detail::unsigned_or_throw(b))); \
return result; \
} else { \
return b OP_ a; \
} \
} \
NIL_CO3_MP_BIG_UINT_INTEGRAL_ASSIGNMENT_TEMPLATE \
constexpr auto& operator OP_ASSIGN_(big_uint_t & a, const T & b) noexcept { \
a.METHOD_(detail::as_limb_type_or_big_uint(detail::unsigned_or_throw(b))); \
return a; \
}

NIL_CO3_MP_BIG_UINT_BITWISE_OPERATOR_IMPL(&, &=, bitwise_and)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <type_traits>

#include "nil/crypto3/multiprecision/detail/big_uint/storage.hpp"
#include "nil/crypto3/multiprecision/detail/type_traits.hpp"

namespace nil::crypto3::multiprecision {
template<std::size_t Bits>
Expand Down Expand Up @@ -49,19 +48,19 @@ namespace nil::crypto3::multiprecision {
return std::forward<T>(a);
}

template<
typename T,
std::enable_if_t<std::is_integral_v<T> && sizeof(T) * CHAR_BIT <= limb_bits, int> = 0>
template<typename T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T> &&
sizeof(T) * CHAR_BIT <= limb_bits,
int> = 0>
constexpr limb_type as_limb_type_or_big_uint(const T& a) {
return static_cast<limb_type>(unsigned_or_throw(a));
return static_cast<limb_type>(a);
}

template<typename T,
std::enable_if_t<!(std::is_integral_v<T> && sizeof(T) * CHAR_BIT <= limb_bits) &&
!is_big_uint_v<T>,
int> = 0>
template<typename T, std::enable_if_t<!(std::is_integral_v<T> && std::is_unsigned_v<T> &&
sizeof(T) * CHAR_BIT <= limb_bits) &&
!is_big_uint_v<T>,
int> = 0>
constexpr auto as_limb_type_or_big_uint(const T& a) {
return as_big_uint(unsigned_or_throw(a));
return as_big_uint(a);
}

template<typename T, std::enable_if_t<is_big_uint_v<std::decay_t<T>>, int> = 0>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,4 @@ namespace nil::crypto3::multiprecision {
constexpr bool is_zero(T a) {
return a == 0;
}

template<typename T, std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>, int> = 0>
constexpr std::make_unsigned_t<T> unsigned_abs(T x) {
std::make_unsigned_t<T> ux = x;
return (x < 0) ? -ux : ux; // compare signed x, negate unsigned x
}
} // namespace nil::crypto3::multiprecision
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include <type_traits>

namespace nil::crypto3::multiprecision::detail {
template<typename T, std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>, int> = 0>
constexpr std::make_unsigned_t<T> unsigned_abs(T x) {
std::make_unsigned_t<T> ux = x;
return (x < 0) ? -ux : ux; // compare signed x, negate unsigned x
}

} // namespace nil::crypto3::multiprecision::detail

0 comments on commit 4ec6f44

Please sign in to comment.