From 4ec6f44a0f19ffaad46bb05ecdb53e4e0ae2a56b Mon Sep 17 00:00:00 2001 From: Andrey Nefedov Date: Fri, 13 Dec 2024 13:07:26 +0000 Subject: [PATCH] multiprecision: big_uint: refactor operators WIP 8 --- .../detail/big_mod/modular_ops.hpp | 3 +- .../multiprecision/detail/big_mod/ops/pow.hpp | 4 +- .../detail/big_uint/big_uint_impl.hpp | 134 +++++++++++++----- .../detail/big_uint/type_traits.hpp | 19 ++- .../detail/integer_ops_base.hpp | 6 - .../multiprecision/detail/integer_utils.hpp | 12 ++ 6 files changed, 122 insertions(+), 56 deletions(-) create mode 100644 crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_utils.hpp diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/modular_ops.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/modular_ops.hpp index 3924f61b3..d62b934ab 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/modular_ops.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/modular_ops.hpp @@ -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 { @@ -636,7 +637,7 @@ namespace nil::crypto3::multiprecision::detail { template && std::is_signed_v, int> = 0> constexpr void init_raw_base(big_uint &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); } diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/ops/pow.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/ops/pow.hpp index f4203e362..31a9aaeb6 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/ops/pow.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/ops/pow.hpp @@ -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 { @@ -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>(e)); } diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp index d2033f57c..cb8879b67 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp @@ -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 { @@ -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 result; \ - if constexpr (detail::is_big_uint_v) { \ - 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) { + detail::largest_big_uint_t result; + if constexpr (std::is_signed_v) { + 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) { + 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) { + detail::largest_big_uint_t result; + if constexpr (std::is_signed_v) { + 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) { + 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) { + decltype(auto) b_unsigned = detail::unsigned_or_throw(b); + detail::largest_big_uint_t 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 { @@ -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; \ - if constexpr (detail::is_big_uint_v) { \ - 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) { \ + detail::largest_big_uint_t 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) diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/type_traits.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/type_traits.hpp index 2730481e3..412b00533 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/type_traits.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/type_traits.hpp @@ -6,7 +6,6 @@ #include #include "nil/crypto3/multiprecision/detail/big_uint/storage.hpp" -#include "nil/crypto3/multiprecision/detail/type_traits.hpp" namespace nil::crypto3::multiprecision { template @@ -49,19 +48,19 @@ namespace nil::crypto3::multiprecision { return std::forward(a); } - template< - typename T, - std::enable_if_t && sizeof(T) * CHAR_BIT <= limb_bits, int> = 0> + template && std::is_unsigned_v && + sizeof(T) * CHAR_BIT <= limb_bits, + int> = 0> constexpr limb_type as_limb_type_or_big_uint(const T& a) { - return static_cast(unsigned_or_throw(a)); + return static_cast(a); } - template && sizeof(T) * CHAR_BIT <= limb_bits) && - !is_big_uint_v, - int> = 0> + template && std::is_unsigned_v && + sizeof(T) * CHAR_BIT <= limb_bits) && + !is_big_uint_v, + 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>, int> = 0> diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_ops_base.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_ops_base.hpp index b207ea7c6..e23ee48b1 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_ops_base.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_ops_base.hpp @@ -29,10 +29,4 @@ namespace nil::crypto3::multiprecision { constexpr bool is_zero(T a) { return a == 0; } - - template && std::is_signed_v, int> = 0> - constexpr std::make_unsigned_t unsigned_abs(T x) { - std::make_unsigned_t ux = x; - return (x < 0) ? -ux : ux; // compare signed x, negate unsigned x - } } // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_utils.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_utils.hpp new file mode 100644 index 000000000..261cbcf56 --- /dev/null +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_utils.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace nil::crypto3::multiprecision::detail { + template && std::is_signed_v, int> = 0> + constexpr std::make_unsigned_t unsigned_abs(T x) { + std::make_unsigned_t ux = x; + return (x < 0) ? -ux : ux; // compare signed x, negate unsigned x + } + +} // namespace nil::crypto3::multiprecision::detail