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 995ee27b7..d2033f57c 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 @@ -24,9 +24,10 @@ #include "nil/crypto3/multiprecision/detail/big_uint/arithmetic.hpp" #include "nil/crypto3/multiprecision/detail/big_uint/parsing.hpp" #include "nil/crypto3/multiprecision/detail/big_uint/storage.hpp" -#include "nil/crypto3/multiprecision/detail/big_uint/type_traits.hpp" +#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/type_traits.hpp" namespace nil::crypto3::multiprecision { /** @@ -937,33 +938,41 @@ namespace nil::crypto3::multiprecision { NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE constexpr auto operator/(const T1& a, const T2& b) noexcept { - using big_uint_a = std::decay_t; + decltype(auto) a_unsigned = detail::unsigned_or_throw(a); + decltype(auto) b_unsigned = detail::unsigned_or_throw(b); + using big_uint_a = std::decay_t; big_uint_a result; big_uint_a modulus; - detail::divide(&result, detail::as_big_uint(a), detail::as_big_uint(b), modulus); + detail::divide(&result, detail::as_big_uint(a_unsigned), detail::as_big_uint(b_unsigned), + modulus); return static_cast>(result); } 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; big_uint_t modulus; - detail::divide(&result, a, detail::as_big_uint(b), modulus); + detail::divide(&result, a, detail::as_big_uint(b_unsigned), modulus); a = result; return a; } NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE constexpr auto operator%(const T1& a, const T2& b) { - using big_uint_a = std::decay_t; + decltype(auto) a_unsigned = detail::unsigned_or_throw(a); + decltype(auto) b_unsigned = detail::unsigned_or_throw(b); + using big_uint_a = std::decay_t; big_uint_a modulus; - detail::divide(static_cast(nullptr), detail::as_big_uint(a), - detail::as_big_uint(b), modulus); + detail::divide(static_cast(nullptr), detail::as_big_uint(a_unsigned), + detail::as_big_uint(b_unsigned), modulus); return static_cast>(modulus); } NIL_CO3_MP_BIG_UINT_INTEGRAL_ASSIGNMENT_TEMPLATE constexpr auto& operator%=(big_uint_t& a, const T& b) { + decltype(auto) b_unsigned = detail::unsigned_or_throw(b); big_uint_t modulus; - detail::divide(static_cast(nullptr), a, detail::as_big_uint(b), modulus); + detail::divide(static_cast(nullptr), a, detail::as_big_uint(b_unsigned), + modulus); a = modulus; return a; } 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 310df4c05..2730481e3 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 @@ -3,10 +3,10 @@ #include #include #include -#include #include #include "nil/crypto3/multiprecision/detail/big_uint/storage.hpp" +#include "nil/crypto3/multiprecision/detail/type_traits.hpp" namespace nil::crypto3::multiprecision { template @@ -38,31 +38,22 @@ namespace nil::crypto3::multiprecision { big_uint(), get_bits())>, std::conditional_t, T1, T2>>; - template, int> = 0> + template && std::is_unsigned_v, int> = 0> constexpr big_uint as_big_uint(const T& a) { - if constexpr (std::is_signed_v) { - if (a < 0) { - throw std::invalid_argument("as_big_uint: negative value"); - } - } return static_cast>(a); } - template - constexpr const auto& as_big_uint(const big_uint& a) { - return a; + template>, int> = 0> + constexpr decltype(auto) as_big_uint(T&& a) { + return std::forward(a); } template< typename T, std::enable_if_t && sizeof(T) * CHAR_BIT <= limb_bits, int> = 0> constexpr limb_type as_limb_type_or_big_uint(const T& a) { - if constexpr (std::is_signed_v) { - if (a < 0) { - throw std::invalid_argument("as_limb_type_or_big_uint: negative value"); - } - } - return static_cast(a); + return static_cast(unsigned_or_throw(a)); } template, int> = 0> constexpr auto as_limb_type_or_big_uint(const T& a) { - return as_big_uint(a); + return as_big_uint(unsigned_or_throw(a)); } - template - constexpr const auto& as_limb_type_or_big_uint(const big_uint& a) { - return a; + template>, int> = 0> + constexpr decltype(auto) as_limb_type_or_big_uint(T&& a) { + return std::forward(a); } } // namespace detail } // namespace nil::crypto3::multiprecision 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 61d45fa31..b207ea7c6 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 @@ -4,24 +4,25 @@ #include #include "nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp" +#include "nil/crypto3/multiprecision/detail/type_traits.hpp" namespace nil::crypto3::multiprecision { template, int> = 0> constexpr std::size_t msb(T a) { // TODO(ioxid): optimize - return detail::as_big_uint(a).msb(); + return detail::as_big_uint(detail::unsigned_or_throw(a)).msb(); } template, int> = 0> constexpr std::size_t lsb(T a) { // TODO(ioxid): optimize - return detail::as_big_uint(a).lsb(); + return detail::as_big_uint(detail::unsigned_or_throw(a)).lsb(); } template, int> = 0> constexpr bool bit_test(T a, std::size_t index) { // TODO(ioxid): optimize - return detail::as_big_uint(a).bit_test(index); + return detail::as_big_uint(detail::unsigned_or_throw(a)).bit_test(index); } template, int> = 0> diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_ops_powm.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_ops_powm.hpp index 25b8dd0ae..42fbefbed 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_ops_powm.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/integer_ops_powm.hpp @@ -3,7 +3,6 @@ #include #include -#include "nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp" #include "nil/crypto3/multiprecision/detail/big_uint/ops/powm.hpp" namespace nil::crypto3::multiprecision { @@ -14,7 +13,8 @@ namespace nil::crypto3::multiprecision { int> = 0> constexpr T3 powm(T1 &&b, T2 &&e, T3 m) { // TODO(ioxid): optimize - return static_cast(nil::crypto3::multiprecision::powm( - std::forward(b), std::forward(e), detail::as_big_uint(m))); + return static_cast( + nil::crypto3::multiprecision::powm(std::forward(b), std::forward(e), + detail::as_big_uint(detail::unsigned_or_throw(m)))); } } // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/type_traits.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/type_traits.hpp index a406592c3..8841175bc 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/type_traits.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/type_traits.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace nil::crypto3::multiprecision::detail { @@ -10,4 +11,17 @@ namespace nil::crypto3::multiprecision::detail { template constexpr bool is_unsigned_integer_v = is_integer_v && !std::numeric_limits::is_signed; + + template>, int> = 0> + constexpr decltype(auto) unsigned_or_throw(T&& a) { + return std::forward(a); + } + + template, int> = 0> + constexpr std::make_unsigned_t unsigned_or_throw(const T& a) { + if (a < 0) { + throw std::invalid_argument("nonnegative value expected"); + } + return static_cast>(a); + } } // namespace nil::crypto3::multiprecision::detail