From 27fe06eced3277f03d3596e11802c3d0a3613521 Mon Sep 17 00:00:00 2001 From: Andrey Nefedov Date: Wed, 18 Dec 2024 00:08:46 +0100 Subject: [PATCH] multiprecision: refactor big_int and inverse_extended_euclidean_algorithm --- crypto3/benchmarks/multiprecision/big_int.cpp | 4 +- .../algebra/fields/detail/element/fp.hpp | 2 +- .../crypto3/multiprecision/detail/big_int.hpp | 314 ++++++-------- .../detail/big_mod/ops/inverse.hpp | 4 +- .../multiprecision/detail/big_mod/ops/pow.hpp | 2 +- .../detail/big_uint/arithmetic.hpp | 1 + .../detail/big_uint/ops/gcd_inverse.hpp | 35 +- .../multiprecision/test/big_int_inverse.cpp | 398 ++++-------------- 8 files changed, 243 insertions(+), 517 deletions(-) diff --git a/crypto3/benchmarks/multiprecision/big_int.cpp b/crypto3/benchmarks/multiprecision/big_int.cpp index ae39f8c621..4eafb97bae 100644 --- a/crypto3/benchmarks/multiprecision/big_int.cpp +++ b/crypto3/benchmarks/multiprecision/big_int.cpp @@ -297,8 +297,8 @@ BOOST_AUTO_TEST_CASE(inverse_extended_euclidean_algorithm_test) { auto x_modular = x_mod_ct_odd; nil::crypto3::bench::run_benchmark<>( - "[odd modulus][compile time] inverse_extended_euclidean_algorithm_test", [&]() { - x_modular = inverse_extended_euclidean_algorithm(x_modular); + "[odd modulus][compile time] inverse with extended euclidean algorithm", [&]() { + x_modular = inverse(x_modular); ++x_modular; return x_modular; }); diff --git a/crypto3/libs/algebra/include/nil/crypto3/algebra/fields/detail/element/fp.hpp b/crypto3/libs/algebra/include/nil/crypto3/algebra/fields/detail/element/fp.hpp index 6268f24000..e2dfb8b05e 100644 --- a/crypto3/libs/algebra/include/nil/crypto3/algebra/fields/detail/element/fp.hpp +++ b/crypto3/libs/algebra/include/nil/crypto3/algebra/fields/detail/element/fp.hpp @@ -208,7 +208,7 @@ namespace nil { } constexpr element_fp inversed() const { - return element_fp(inverse_extended_euclidean_algorithm(data)); + return element_fp(inverse(data)); } constexpr element_fp squared() const { diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_int.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_int.hpp index 048ab8001a..4393bc6cc5 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_int.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_int.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -7,8 +8,6 @@ #include #include -#include - #include "nil/crypto3/multiprecision/detail/assert.hpp" #include "nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp" #include "nil/crypto3/multiprecision/detail/config.hpp" @@ -41,9 +40,7 @@ namespace nil::crypto3::multiprecision { constexpr big_int(const big_uint& b) : m_abs(b) {} template && std::is_signed_v, int> = 0> - constexpr big_int(T val) : m_abs(abs(val)) { - // for ADL - using std::abs; + constexpr big_int(T val) : m_abs(unsigned_abs(val)) { if (val < 0) { negate(); } @@ -53,7 +50,7 @@ namespace nil::crypto3::multiprecision { constexpr big_int(T val) : m_abs(val) {} template - constexpr big_int(const big_int& other) noexcept + constexpr big_int(const big_int& other) : m_negative(other.negative()), m_abs(other.abs()) {} // Assignment @@ -74,8 +71,8 @@ namespace nil::crypto3::multiprecision { template && std::is_signed_v, int> = 0> constexpr big_int& operator=(T val) { - using std::abs; - m_abs = abs(val); + m_negative = false; + m_abs = unsigned_abs(val); if (val < 0) { negate(); } @@ -90,8 +87,8 @@ namespace nil::crypto3::multiprecision { return *this; } - constexpr std::string str() const { - return (negative() ? std::string("-") : std::string("")) + m_abs.str(); + constexpr std::string str(std::ios_base::fmtflags flags = std::ios_base::dec) const { + return (negative() ? std::string("-") : std::string("")) + m_abs.str(flags); } template = 0> @@ -143,80 +140,139 @@ namespace nil::crypto3::multiprecision { return this->m_abs.compare(other.m_abs); } +#define NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(op) \ + friend constexpr bool operator op(const big_int& a, const big_int& b) noexcept { \ + return a.compare(b) op 0; \ + } + + NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(<) + NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(<=) + NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(>) + NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(>=) + NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(==) + NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(!=) + +#undef NIL_CO3_MP_BIG_INT_IMPL_OPERATOR + // Arithmetic operations - // Addition/subtraction + friend constexpr big_int operator+(big_int a, const big_int& b) noexcept { + a += b; + return a; + } - static constexpr big_int add(const big_int& a, const big_int& b) { - if (!a.negative() && !b.negative()) { - return big_uint(a.m_abs) + b.m_abs; + friend constexpr auto& operator+=(big_int& a, const big_int& b) noexcept { + if (a.negative() == b.negative()) { + a.m_abs += b.m_abs; + return a; } - if (!a.negative() && b.negative()) { - if (a.m_abs >= b.m_abs) { - return a.m_abs - b.m_abs; - } - return -big_int(b.m_abs - a.m_abs); + if (a.m_abs >= b.m_abs) { + a.m_abs -= b.m_abs; + } else { + auto a_m_abs = a.m_abs; + a.m_abs = b.m_abs; + a.m_abs -= a_m_abs; + a.negate(); } - if (a.negative() && !b.negative()) { - return add(b, a); - } - return -big_int(big_uint(a.m_abs) + b.m_abs); - } - - static constexpr big_int subtract(const big_int& a, const big_int& b) { - return add(a, -b); + return a; } - NIL_CO3_MP_FORCEINLINE constexpr void increment() { + constexpr auto& operator++() { if (negative()) { --m_abs; normalize(); - return; + return *this; } ++m_abs; + return *this; } - NIL_CO3_MP_FORCEINLINE constexpr void decrement() { + friend constexpr auto operator++(big_int& a, int) { + auto copy = a; + ++a; + return copy; + } + + friend constexpr auto operator+(const big_int& a) noexcept { return a; } + + friend constexpr auto operator-(const big_int& a, const big_int& b) { return a + (-b); } + + friend constexpr auto& operator-=(big_int& a, const big_int& b) { + a = a - b; + return a; + } + + constexpr auto& operator--() { if (negative()) { ++m_abs; - return; + return *this; } if (is_zero(m_abs)) { m_negative = true; ++m_abs; - return; + return *this; } --m_abs; + return *this; } - // Modulus + friend constexpr auto operator--(big_int& a, int) { + auto copy = a; + --a; + return copy; + } - static constexpr big_int modulus(const big_int& x, const big_int& y) { - return static_cast(x - static_cast((x / y) * y)); + friend constexpr auto operator-(big_int a) noexcept { + a.negate(); + return a; } - // Division + friend constexpr auto operator*(const big_int& a, const big_int& b) { + big_int result = a.m_abs * b.m_abs; + if (a.sign() * b.sign() < 0) { + result = -result; + } + return result; + } - static constexpr big_int divide(const big_int& x, const big_int& y) { - big_int result = x.m_abs / y.m_abs; - if (x.negative() != y.negative()) { + friend constexpr auto& operator*=(big_int& a, const big_int& b) { + a = a * b; + return a; + } + + friend constexpr auto operator/(const big_int& a, const big_int& b) { + big_int result = a.m_abs / b.m_abs; + if (a.negative() != b.negative()) { result.negate(); } return result; } - // Multiplication + friend constexpr auto& operator/=(big_int& a, const big_int& b) { + a = a / b; + return a; + } - template - static constexpr big_int multiply(const big_int& a, - const big_int& b) noexcept { - big_int result = a.m_abs * b.m_abs; - if (a.sign() * b.sign() < 0) { - result = -result; + friend constexpr auto operator%(const big_int& a, const big_int& b) { + big_int result = a.m_abs % b.m_abs; + if (a.negative() != b.negative()) { + result.negate(); } return result; } + friend constexpr auto& operator%=(big_int& a, const big_int& b) { + a = a % b; + return a; + } + + // IO + + friend std::ostream& operator<<(std::ostream& os, const big_int& value) { + os << value.str(os.flags()); + return os; + } + // Misc ops NIL_CO3_MP_FORCEINLINE constexpr bool is_zero() const noexcept { return abs().is_zero(); } @@ -244,141 +300,16 @@ namespace nil::crypto3::multiprecision { bool m_negative = false; big_uint m_abs; - }; - - namespace detail { - template - constexpr bool is_big_int_v = false; - - template - constexpr bool is_big_int_v> = true; - - template - constexpr bool is_signed_integral_v = is_integral_v || is_big_int_v; - - template, int> = 0> - constexpr std::size_t get_bits() { - return T::Bits; - } - } // namespace detail - -#define NIL_CO3_MP_BIG_INT_INTEGRAL_TEMPLATE \ - template< \ - typename T1, typename T2, \ - std::enable_if_t && detail::is_signed_integral_v && \ - (detail::is_big_int_v || detail::is_big_int_v), \ - int> = 0, \ - typename largest_t = big_int(), detail::get_bits())>> - -#define NIL_CO3_MP_BIG_INT_INTEGRAL_ASSIGNMENT_TEMPLATE \ - template && detail::is_signed_integral_v, \ - int> = 0> - -#define NIL_CO3_MP_BIG_INT_UNARY_TEMPLATE \ - template, int> = 0> - - // Comparison - -#define NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(op) \ - NIL_CO3_MP_BIG_INT_INTEGRAL_TEMPLATE \ - constexpr bool operator op(const T1& a, const T2& b) noexcept { \ - largest_t ap = a; \ - largest_t bp = b; \ - return ap.compare(bp) op 0; \ - } - NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(<) - NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(<=) - NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(>) - NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(>=) - NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(==) - NIL_CO3_MP_BIG_INT_IMPL_OPERATOR(!=) + // Friends -#undef NIL_CO3_MP_BIG_INT_IMPL_OPERATOR + template + friend constexpr void divide_qr(const big_int& a, const big_int& b, + big_int& q, big_int& r); + }; // Arithmetic operations - NIL_CO3_MP_BIG_INT_INTEGRAL_TEMPLATE - constexpr auto operator+(const T1& a, const T2& b) noexcept { - big_int result; - result = decltype(result)::add(a, b); - return result; - } - NIL_CO3_MP_BIG_INT_INTEGRAL_ASSIGNMENT_TEMPLATE - constexpr auto& operator+=(big_int_t& a, const T& b) noexcept { - a = a + b; - return a; - } - NIL_CO3_MP_BIG_INT_UNARY_TEMPLATE - constexpr auto& operator++(big_int_t& a) { - a.increment(); - return a; - } - NIL_CO3_MP_BIG_INT_UNARY_TEMPLATE - constexpr auto operator++(big_int_t& a, int) { - auto copy = a; - ++a; - return copy; - } - NIL_CO3_MP_BIG_INT_UNARY_TEMPLATE - constexpr auto operator+(const big_int_t& a) noexcept { return a; } - - NIL_CO3_MP_BIG_INT_INTEGRAL_TEMPLATE - constexpr auto operator-(const T1& a, const T2& b) { return T1::subtract(a, b); } - NIL_CO3_MP_BIG_INT_INTEGRAL_ASSIGNMENT_TEMPLATE - constexpr auto& operator-=(big_int_t& a, const T& b) { - a = a - b; - return a; - } - NIL_CO3_MP_BIG_INT_UNARY_TEMPLATE - constexpr auto& operator--(big_int_t& a) { - a.decrement(); - return a; - } - NIL_CO3_MP_BIG_INT_UNARY_TEMPLATE - constexpr auto operator--(big_int_t& a, int) { - auto copy = a; - --a; - return copy; - } - - NIL_CO3_MP_BIG_INT_UNARY_TEMPLATE - constexpr big_int_t operator-(big_int_t a) noexcept { - a.negate(); - return a; - } - - NIL_CO3_MP_BIG_INT_INTEGRAL_TEMPLATE - constexpr auto operator*(const T1& a, const T2& b) noexcept { - return std::decay_t::multiply(a, b); - } - NIL_CO3_MP_BIG_INT_INTEGRAL_ASSIGNMENT_TEMPLATE - constexpr auto& operator*=(big_int_t& a, const T& b) noexcept { - a = a * b; - return a; - } - - NIL_CO3_MP_BIG_INT_INTEGRAL_TEMPLATE - constexpr auto operator/(const T1& a, const T2& b) noexcept { - return largest_t::divide(static_cast(a), static_cast(b)); - } - NIL_CO3_MP_BIG_INT_INTEGRAL_ASSIGNMENT_TEMPLATE - constexpr auto& operator/=(big_int_t& a, const T& b) noexcept { - a = a / b; - return a; - } - - NIL_CO3_MP_BIG_INT_INTEGRAL_TEMPLATE - constexpr auto operator%(const T1& a, const T2& b) noexcept { - return largest_t::modulus(static_cast(a), static_cast(b)); - } - NIL_CO3_MP_BIG_INT_INTEGRAL_ASSIGNMENT_TEMPLATE - constexpr auto& operator%=(big_int_t& a, const T& b) { - a = a % b; - return a; - } - template constexpr std::size_t hash_value(const big_int& val) noexcept { std::size_t result = 0; @@ -387,16 +318,29 @@ namespace nil::crypto3::multiprecision { return result; } - // IO + // Misc ops - NIL_CO3_MP_BIG_INT_UNARY_TEMPLATE - std::ostream& operator<<(std::ostream& os, const big_int_t& value) { - os << value.str(); - return os; + template + constexpr bool is_zero(const big_int& a) { + return a.is_zero(); } -#undef NIL_CO3_MP_BIG_INT_UNARY_TEMPLATE -#undef NIL_CO3_MP_BIG_INT_INTEGRAL_ASSIGNMENT_TEMPLATE -#undef NIL_CO3_MP_BIG_INT_INTEGRAL_TEMPLATE - + template + constexpr void divide_qr(const big_int& a, const big_int& b, big_int& q, + big_int& r) { + detail::divide(&q.m_abs, a.m_abs, b.m_abs, r.m_abs); + q.m_negative = false; + r.m_negative = false; + if (a.negative() != b.negative()) { + q.negate(); + r.negate(); + } + } } // namespace nil::crypto3::multiprecision + +template +struct std::hash> { + std::size_t operator()(const nil::crypto3::multiprecision::big_int& a) const noexcept { + return boost::hash>{}(a); + } +}; diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/ops/inverse.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/ops/inverse.hpp index 4ac66b42c6..645b6e771f 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/ops/inverse.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/ops/inverse.hpp @@ -20,7 +20,7 @@ namespace nil::crypto3::multiprecision { template, int> = 0> - constexpr big_mod_t inverse_extended_euclidean_algorithm(const big_mod_t &modular) { - return big_mod_t(inverse_extended_euclidean_algorithm(modular.base(), modular.mod()), modular.ops_storage()); + constexpr big_mod_t inverse(const big_mod_t &modular) { + return big_mod_t(inverse_mod(modular.base(), modular.mod()), modular.ops_storage()); } } // namespace nil::crypto3::multiprecision 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 31a9aaeb62..f682613877 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 @@ -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), detail::unsigned_abs(e)); + return pow(inverse(b), detail::unsigned_abs(e)); } return pow(b, static_cast>(e)); } diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/arithmetic.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/arithmetic.hpp index ac0a4b5e9d..29dfcd1f36 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/arithmetic.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/arithmetic.hpp @@ -37,6 +37,7 @@ namespace nil::crypto3::multiprecision { 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 v = static_cast(*a.limbs()) + static_cast(*b.limbs()); diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/ops/gcd_inverse.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/ops/gcd_inverse.hpp index 92b3a57de6..8c8d2d903a 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/ops/gcd_inverse.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_uint/ops/gcd_inverse.hpp @@ -14,20 +14,19 @@ #include #include +#include "nil/crypto3/multiprecision/detail/assert.hpp" #include "nil/crypto3/multiprecision/detail/big_int.hpp" #include "nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp" -#include "nil/crypto3/multiprecision/detail/assert.hpp" namespace nil::crypto3::multiprecision { namespace detail { // a^(-1) mod p // http://www-math.ucdenver.edu/~wcherowi/courses/m5410/exeucalg.html template - constexpr big_int extended_euclidean_algorithm(const big_int& num1, - const big_int& num2, + constexpr big_int extended_euclidean_algorithm(big_int num1, big_int num2, big_int& bezout_x, big_int& bezout_y) { - big_int x, y, tmp_num1 = num1, tmp_num2 = num2; + big_int x, y; y = 1u; x = 0u; @@ -35,29 +34,24 @@ namespace nil::crypto3::multiprecision { bezout_y = 0u; // Extended Euclidean Algorithm - while (!tmp_num2.is_zero()) { - big_int quotient = tmp_num1; - big_int remainder = tmp_num1; - big_int placeholder; + while (!num2.is_zero()) { + big_int quotient; + big_int remainder; - quotient /= tmp_num2; - remainder %= tmp_num2; + divide_qr(num1, num2, quotient, remainder); - tmp_num1 = tmp_num2; - tmp_num2 = remainder; + num1 = num2; + num2 = remainder; big_int temp_x = x, temp_y = y; - placeholder = quotient * x; - placeholder = bezout_x - placeholder; - x = placeholder; + x = bezout_x - quotient * x; bezout_x = temp_x; - placeholder = quotient * y; - placeholder = bezout_y - placeholder; - y = placeholder; + y = bezout_y - quotient * y; bezout_y = temp_y; } - return tmp_num1; + + return num1; } } // namespace detail @@ -70,8 +64,7 @@ namespace nil::crypto3::multiprecision { } template - constexpr big_uint inverse_extended_euclidean_algorithm(const big_uint& a, - const big_uint& m) { + constexpr big_uint inverse_mod(const big_uint& a, const big_uint& m) { big_int aa = a, mm = m, x, y, g; g = detail::extended_euclidean_algorithm(aa, mm, x, y); if (g != 1u) { diff --git a/crypto3/libs/multiprecision/test/big_int_inverse.cpp b/crypto3/libs/multiprecision/test/big_int_inverse.cpp index f73a359a69..6f19878818 100644 --- a/crypto3/libs/multiprecision/test/big_int_inverse.cpp +++ b/crypto3/libs/multiprecision/test/big_int_inverse.cpp @@ -24,119 +24,6 @@ using namespace nil::crypto3::multiprecision; NIL_CO3_MP_DEFINE_BIG_UINT_LITERAL(6) -template -void test_inverse_extended_euclidean_algorithm() { - BOOST_CHECK_EQUAL( - inverse_extended_euclidean_algorithm(T(5), T("0x7fffffffffffffffffffffffffffffff")), - T("0x33333333333333333333333333333333")); - BOOST_CHECK_EQUAL( - inverse_extended_euclidean_algorithm(T(333), T("0x7fffffffffffffffffffffffffffffff")), - T("0x17d4f2ee517d4f2ee517d4f2ee517d4f")); - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm(T("0x435b21e35ccd62dbdbafa1368cf742f0"), - T("0x7fffffffffffffffffffffffffffffff")), - T("0x604ddb74e5a55e559a7320e45b06eaf6")); - BOOST_CHECK_EQUAL( - inverse_extended_euclidean_algorithm( - T(2), T("0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), - T("0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "00000000000000000000" - "0000000000000000000000000")); - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm(T(3), T(8)), T(3)); - BOOST_CHECK_THROW(inverse_extended_euclidean_algorithm(T(46), T(207)), std::invalid_argument); - BOOST_CHECK_THROW(inverse_extended_euclidean_algorithm(T(2), T(2)), std::invalid_argument); - BOOST_CHECK_THROW(inverse_extended_euclidean_algorithm(T(0), T(2)), std::invalid_argument); - BOOST_CHECK_THROW(inverse_extended_euclidean_algorithm(T(46), T(46)), std::invalid_argument); - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm(T(1), T(7)), T(1)); - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm(T(35), T(118)), T(27)); - BOOST_CHECK_THROW(inverse_extended_euclidean_algorithm(T(37), T(37)), std::invalid_argument); - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm(T(32), T(247)), T(193)); - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm(T(3), T(232)), T(155)); - - BOOST_CHECK_EQUAL( - inverse_extended_euclidean_algorithm( - T("256992387993922882115519242002267204163958280694902854777438773165028812741820300742" - "384101" - "620467227297951260702776745365693102268609333941403372929142489383748076291"), - T("310556067329850632847208938574658589632291100674077275160516075249922714838542485036" - "214015" - "8165019680645739648726058090243814223511639161631852729287604717869259565828")), - T("2322484593360248972803085811686365806060063797313230509497970163285203519904646342173323" - "688226" - "147654544918783691327115436052292182385106099615339567513136063879840431")); - - BOOST_CHECK_EQUAL( - inverse_extended_euclidean_algorithm( - T("657900513264442578215729259525804042708991731028255426638688946278845827095715186772" - "097484" - "16019817305674876843604308670298295897660589296995641401495105646770364032950"), - T("146059874272782860583686068115674600616627249438711269370889274434354805551497286303" - "947620" - "1659720247220048664250204314648520085411164461712526657028588699682983099362771")), - T("3701344688092353558099310214964185602579277616517826314317231208222417072861266226192312" - "282752" - "10678415132318220494260963802381448709723310690465171935975287188943190781")); - - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm(T(3), T(0x10)), T(11)); - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm(T(43000466091), T(0x10000000000)), - T(140404367363)); - - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm( - T("3329223706171052463206866408355190852145308853551222855374206553291583" - "6412003628111698671675220667324272" - "5944106904545859091557017307727326666832362641891029072983311591760876" - "2612451607036836604560196526748133" - "2952294823154321608619569856617204150085028173765891223691691685030517" - "0057553436136073435791550700526779" - "1266056164843197115173542457409178397682412186017844044878477733706673" - "6659493124795020814172868481356070" - "6694079674126165187970576121654781364910559498699000784756722078722425" - "3724912309650653332895570458720843" - "3224850656811897686972917521497485758932335208567118381404016914945323" - "3350227887942508765678216349436356" - "7584633848194784070822245649557468578497368723157561724530746784741768" - "6461029368632606300888825458750471" - "73194357829837349405264332156553159"), - T("5159669275902268897019683770634129859849131442089512209466255369748647" - "8852950434581004530951396375324897" - "3237934933418399835900527154085143847573539006016005510145975736902509" - "4548935216928274885474920588457238" - "9321992128261328481129830302072287292303501430702452146150323300983736" - "0681685755548737891159735617529596" - "3296209024100980888874174104384926439773409352855895683162800486061893" - "6254613392484195923653331976713963" - "9022384965245831654887217363203207214249335996119270164515039005157887" - "5246900773560274606831152842526302" - "3211977032707524224960793107608042288596827341046613333670880853546357" - "0182780841768637479016464266039055" - "7925243983808216928421220094838103017958334974205040660858707963225716" - "1952224606791379941232782765846637" - "12976241848458904056941218720227786752")), - T("16169765086855986127154046155397117295914963038387272783617457684599127447" - "6610311080533553178926047190203266" - "85568238777817971191773697446756550362276938623879013359293805261585253356" - "1719117119940626105914149272955096" - "43833787555922713773309241786955753178554821984186872072841194724366388916" - "5526728787046894739482800359519447" - "64596203739541946184136389849598657786471023022865585926888106336640072640" - "1157990917652680450814220027329982" - "28525926769366297380133831033446426381884582602684819819652397562413743816" - "5546650367370131035732951388159175" - "97189009924722836031296505773554187289297878370713302855264475968171422470" - "4381891573964406129272600659255700" - "50082441202586929437053251315496103922094819482313181774501817762229043061" - "5352105032422136121552433314291445" - "5291939319")); - BOOST_CHECK_EQUAL( - inverse_extended_euclidean_algorithm( - T(65279), T("0x100000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000" - "00000000000000000000000000000000000000000000000000000000000")), - T("2136191453734241471355287191702994357470910407859959447816962783332820558450714636705703" - "817069" - "8710253677755075362127788711957331760388539866898398399344480664991941861081743615")); -} - template void test_inverse_mod() { BOOST_CHECK_EQUAL(inverse_mod(T(5), T("0x7fffffffffffffffffffffffffffffff")), @@ -154,13 +41,13 @@ void test_inverse_mod() { "00000000000000000000" "0000000000000000000000000")); BOOST_CHECK_EQUAL(inverse_mod(T(3), T(8)), T(3)); - BOOST_CHECK_EQUAL(inverse_mod(T(46), T(207)), T(0)); - BOOST_CHECK_EQUAL(inverse_mod(T(2), T(2)), T(0)); - BOOST_CHECK_EQUAL(inverse_mod(T(0), T(2)), T(0)); - BOOST_CHECK_EQUAL(inverse_mod(T(46), T(46)), T(0)); + BOOST_CHECK_THROW(inverse_mod(T(46), T(207)), std::invalid_argument); + BOOST_CHECK_THROW(inverse_mod(T(2), T(2)), std::invalid_argument); + BOOST_CHECK_THROW(inverse_mod(T(0), T(2)), std::invalid_argument); + BOOST_CHECK_THROW(inverse_mod(T(46), T(46)), std::invalid_argument); BOOST_CHECK_EQUAL(inverse_mod(T(1), T(7)), T(1)); BOOST_CHECK_EQUAL(inverse_mod(T(35), T(118)), T(27)); - BOOST_CHECK_EQUAL(inverse_mod(T(37), T(37)), T(0)); + BOOST_CHECK_THROW(inverse_mod(T(37), T(37)), std::invalid_argument); BOOST_CHECK_EQUAL(inverse_mod(T(32), T(247)), T(193)); BOOST_CHECK_EQUAL(inverse_mod(T(3), T(232)), T(155)); @@ -191,205 +78,106 @@ void test_inverse_mod() { BOOST_CHECK_EQUAL(inverse_mod(T(3), T(0x10)), T(11)); BOOST_CHECK_EQUAL(inverse_mod(T(43000466091), T(0x10000000000)), T(140404367363)); - BOOST_CHECK_EQUAL(inverse_mod(T("33292237061710524632068664083551908521453088535512228553742065" - "532915836412003628111698671675220667324272" - "59441069045458590915570173077273266668323626418910290729833115" - "917608762612451607036836604560196526748133" - "29522948231543216086195698566172041500850281737658912236916916" - "850305170057553436136073435791550700526779" - "12660561648431971151735424574091783976824121860178440448784777" - "337066736659493124795020814172868481356070" - "66940796741261651879705761216547813649105594986990007847567220" - "787224253724912309650653332895570458720843" - "32248506568118976869729175214974857589323352085671183814040169" - "149453233350227887942508765678216349436356" - "75846338481947840708222456495574685784973687231575617245307467" - "847417686461029368632606300888825458750471" - "73194357829837349405264332156553159"), - T("51596692759022688970196837706341298598491314420895122094662553" - "697486478852950434581004530951396375324897" - "32379349334183998359005271540851438475735390060160055101459757" - "369025094548935216928274885474920588457238" - "93219921282613284811298303020722872923035014307024521461503233" - "009837360681685755548737891159735617529596" - "32962090241009808888741741043849264397734093528558956831628004" - "860618936254613392484195923653331976713963" - "90223849652458316548872173632032072142493359961192701645150390" - "051578875246900773560274606831152842526302" - "32119770327075242249607931076080422885968273410466133336708808" - "535463570182780841768637479016464266039055" - "79252439838082169284212200948381030179583349742050406608587079" - "632257161952224606791379941232782765846637" - "12976241848458904056941218720227786752")), - T("16169765086855986127154046155397117295914963038387272783617457684599127447" - "6610311080533553178926047190203266" - "85568238777817971191773697446756550362276938623879013359293805261585253356" - "1719117119940626105914149272955096" - "43833787555922713773309241786955753178554821984186872072841194724366388916" - "5526728787046894739482800359519447" - "64596203739541946184136389849598657786471023022865585926888106336640072640" - "1157990917652680450814220027329982" - "28525926769366297380133831033446426381884582602684819819652397562413743816" - "5546650367370131035732951388159175" - "97189009924722836031296505773554187289297878370713302855264475968171422470" - "4381891573964406129272600659255700" - "50082441202586929437053251315496103922094819482313181774501817762229043061" - "5352105032422136121552433314291445" - "5291939319")); BOOST_CHECK_EQUAL( - inverse_mod(T(65279), T("0x1000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000" - "00000000000000000000000000000000000000000000000000000000000")), + inverse_mod(T("3329223706171052463206866408355190852145308853551222855374206553291583" + "6412003628111698671675220667324272" + "5944106904545859091557017307727326666832362641891029072983311591760876" + "2612451607036836604560196526748133" + "2952294823154321608619569856617204150085028173765891223691691685030517" + "0057553436136073435791550700526779" + "1266056164843197115173542457409178397682412186017844044878477733706673" + "6659493124795020814172868481356070" + "6694079674126165187970576121654781364910559498699000784756722078722425" + "3724912309650653332895570458720843" + "3224850656811897686972917521497485758932335208567118381404016914945323" + "3350227887942508765678216349436356" + "7584633848194784070822245649557468578497368723157561724530746784741768" + "6461029368632606300888825458750471" + "73194357829837349405264332156553159"), + T("5159669275902268897019683770634129859849131442089512209466255369748647" + "8852950434581004530951396375324897" + "3237934933418399835900527154085143847573539006016005510145975736902509" + "4548935216928274885474920588457238" + "9321992128261328481129830302072287292303501430702452146150323300983736" + "0681685755548737891159735617529596" + "3296209024100980888874174104384926439773409352855895683162800486061893" + "6254613392484195923653331976713963" + "9022384965245831654887217363203207214249335996119270164515039005157887" + "5246900773560274606831152842526302" + "3211977032707524224960793107608042288596827341046613333670880853546357" + "0182780841768637479016464266039055" + "7925243983808216928421220094838103017958334974205040660858707963225716" + "1952224606791379941232782765846637" + "12976241848458904056941218720227786752")), + T("16169765086855986127154046155397117295914963038387272783617457684599127447" + "6610311080533553178926047190203266" + "85568238777817971191773697446756550362276938623879013359293805261585253356" + "1719117119940626105914149272955096" + "43833787555922713773309241786955753178554821984186872072841194724366388916" + "5526728787046894739482800359519447" + "64596203739541946184136389849598657786471023022865585926888106336640072640" + "1157990917652680450814220027329982" + "28525926769366297380133831033446426381884582602684819819652397562413743816" + "5546650367370131035732951388159175" + "97189009924722836031296505773554187289297878370713302855264475968171422470" + "4381891573964406129272600659255700" + "50082441202586929437053251315496103922094819482313181774501817762229043061" + "5352105032422136121552433314291445" + "5291939319")); + BOOST_CHECK_EQUAL( + inverse_mod(T(65279), + T("0x100000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000" + "00000000000000000000000000000000000000000000000000000000000")), T("2136191453734241471355287191702994357470910407859959447816962783332820558450714636705703" "817069" "8710253677755075362127788711957331760388539866898398399344480664991941861081743615")); } -template -void test_monty_inverse() { - // test for monty_inverse - BOOST_CHECK_EQUAL(monty_inverse(T(12), T(5), T(5)), T(1823)); - BOOST_CHECK_EQUAL(monty_inverse(T(10), T(37), T(1)), T(26)); - BOOST_CHECK_EQUAL(monty_inverse(T(3), T(2), T(3)), T(3)); - BOOST_CHECK_EQUAL(monty_inverse(T(3), T(4), T(2)), T(11)); - BOOST_CHECK_EQUAL(monty_inverse(T(4), T(7), T(2)), T(37)); - BOOST_CHECK_EQUAL(monty_inverse(T(32), T(247), T(1)), T(193)); - BOOST_CHECK_EQUAL(monty_inverse(T(3), T(7), T(7)), T(549029)); - BOOST_CHECK_EQUAL(monty_inverse(T(5317589), T(23), T(8)), T(32104978469)); -} - BOOST_AUTO_TEST_SUITE(runtime_tests) -BOOST_AUTO_TEST_CASE(inverse_tests) { - // test_monty_inverse>(); - // test_inverse_mod>(); - test_inverse_extended_euclidean_algorithm>(); -} +BOOST_AUTO_TEST_CASE(inverse_tests) { test_inverse_mod>(); } BOOST_AUTO_TEST_CASE(test_big_mod_6_bits) { auto modular = big_mod_rt<6>(10_big_uint6, 37_big_uint6); - BOOST_CHECK_EQUAL(inverse_extended_euclidean_algorithm(modular).base(), 26u); -} + BOOST_CHECK_EQUAL(inverse(modular).base(), 26u); -// BOOST_AUTO_TEST_CASE(test_cpp_int_modular_backend_6_bits) { -// using namespace boost::multiprecision; -// using T = boost::multiprecision::cpp_int_modular_modular_backend<6>; -// -// modular = number>>(3, 8); -// modular.backend().mod_data().adjust_regular(res.backend(), -// inverse_extended_euclidean_algorithm(modular).backend().base_data()); -// BOOST_CHECK_EQUAL(number(res.backend()), number(3)); -// -// modular = number>>(3, 16); -// modular.backend().mod_data().adjust_regular(res.backend(), -// inverse_extended_euclidean_algorithm(modular).backend().base_data()); -// BOOST_CHECK_EQUAL(number(res.backend()), number(11)); -// -// modular = number>>( -// 65279, -// "0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" -// "000000000000000000000000000000000000000"); -// modular.backend().mod_data().adjust_regular(res.backend(), -// inverse_extended_euclidean_algorithm(modular).backend().base_data()); -// BOOST_CHECK_EQUAL( -// number(res.backend()), -// number("213619145373424147135528719170299435747091040785995944781696278333282055845071463670570381706987102536" -// "77755075362127788711957331760388539866898398399344480664991941861081743615")); -// -// modular = number>>( -// "33292237061710524632068664083551908521453088535512228553742065532915836412003628111698671675220667324272594410" -// "69045458590915570173077273266668323626418910290729833115917608762612451607036836604560196526748133295229482315" -// "43216086195698566172041500850281737658912236916916850305170057553436136073435791550700526779126605616484319711" -// "51735424574091783976824121860178440448784777337066736659493124795020814172868481356070669407967412616518797057" -// "61216547813649105594986990007847567220787224253724912309650653332895570458720843322485065681189768697291752149" -// "74857589323352085671183814040169149453233350227887942508765678216349436356758463384819478407082224564955746857" -// "8497368723157561724530746784741768646102936863260630088882545875047173194357829837349405264332156553159", -// "51596692759022688970196837706341298598491314420895122094662553697486478852950434581004530951396375324897323793" -// "49334183998359005271540851438475735390060160055101459757369025094548935216928274885474920588457238932199212826" -// "13284811298303020722872923035014307024521461503233009837360681685755548737891159735617529596329620902410098088" -// "88741741043849264397734093528558956831628004860618936254613392484195923653331976713963902238496524583165488721" -// "73632032072142493359961192701645150390051578875246900773560274606831152842526302321197703270752422496079310760" -// "80422885968273410466133336708808535463570182780841768637479016464266039055792524398380821692842122009483810301" -// "7958334974205040660858707963225716195222460679137994123278276584663712976241848458904056941218720227786752"); -// modular.backend().mod_data().adjust_regular(res.backend(), -// inverse_extended_euclidean_algorithm(modular).backend().base_data()); -// BOOST_CHECK_EQUAL( -// number(res.backend()), -// number("161697650868559861271540461553971172959149630383872727836174576845991274476610311080533553178926047190" -// "203266855682387778179711917736974467565503622769386238790133592938052615852533561719117119940626105914" -// "149272955096438337875559227137733092417869557531785548219841868720728411947243663889165526728787046894" -// "739482800359519447645962037395419461841363898495986577864710230228655859268881063366400726401157990917" -// "652680450814220027329982285259267693662973801338310334464263818845826026848198196523975624137438165546" -// "650367370131035732951388159175971890099247228360312965057735541872892978783707133028552644759681714224" -// "704381891573964406129272600659255700500824412025869294370532513154961039220948194823131817745018177622" -// "2904306153521050324221361215524333142914455291939319")); -// number> -// t1("46183318524466423714385242700212935662232011232920767824642233133732825160423"); -// number> -// t2("52435875175126190479447740508185965837690552500527637822603658699938581184513"); -// std::cout << "res1=" << inverse_mod(t1, t2) << std::endl; -// std::cout << std::endl; -// std::cout << "res1=" << inverse_mod(number>>(t1, t2)) << std::endl; -////5340958855958624790350191648327454295961274282628640357656781123563169745534 -// modular = number>>(43000466091, -// 0x10000000000); modular.backend().mod_data().adjust_regular(res.backend(), -// inverse_extended_euclidean_algorithm(modular).backend().base_data()); -// BOOST_CHECK_EQUAL(number(res.backend()), number(140404367363)); -//} + modular = big_mod_rt<6>(3_big_uint6, 8_big_uint6); + BOOST_CHECK_EQUAL(inverse(modular).base(), 3u); + + modular = big_mod_rt<6>(3_big_uint6, 16_big_uint6); + BOOST_CHECK_EQUAL(inverse(modular).base(), 11u); +} BOOST_AUTO_TEST_SUITE_END() -// BOOST_AUTO_TEST_SUITE(static_tests) -// -// BOOST_AUTO_TEST_CASE(cpp_int_fixed_test) { -// using Backend = cpp_int_modular_backend<585>; -// using Backend_modular = modular_adaptor>; -// using modular_number = number; -// -// constexpr auto mod = -// 0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_cppui_modular585; -// constexpr auto a = 0xfeff_cppui_modular585; -// constexpr auto a_inv = -// 0x565eb513c8dca58227a9d17b4cc814dcf1cec08f4fdf2f0e3d4b88d45d318ec04f0f5e6dcc3a06404686cd542175970ca3b05404585cb511c6d89f78178fa736de14f307fb02fe00ff_cppui_modular585; -// static_assert(a_inv == inverse_extended_euclidean_algorithm(a, mod), "inverse error"); -// -// constexpr modular_number a_m(a, mod); -// constexpr modular_number a_inv_m(a_inv, mod); -// static_assert(a_inv_m == inverse_extended_euclidean_algorithm(a_m), "inverse error"); -// -// using T = number; -// -// static_assert(inverse_extended_euclidean_algorithm(T(3), T(8)) == T(3)); -// static_assert(inverse_extended_euclidean_algorithm(T(46), T(207)) == T(0)); -// static_assert(inverse_extended_euclidean_algorithm(T(2), T(2)) == T(0)); -// static_assert(inverse_extended_euclidean_algorithm(T(0), T(2)) == T(0)); -// static_assert(inverse_extended_euclidean_algorithm(T(46), T(46)) == T(0)); -// static_assert(inverse_extended_euclidean_algorithm(T(1), T(7)) == T(1)); -// static_assert(inverse_extended_euclidean_algorithm(T(35), T(118)) == T(27)); -// static_assert(inverse_extended_euclidean_algorithm(T(37), T(37)) == T(0)); -// static_assert(inverse_extended_euclidean_algorithm(T(32), T(247)) == T(193)); -// static_assert(inverse_extended_euclidean_algorithm(T(3), T(232)) == T(155)); -// -// static_assert(inverse_mod(T(3), T(8)) == T(3)); -// static_assert(inverse_mod(T(46), T(207)) == T(0)); -// static_assert(inverse_mod(T(2), T(2)) == T(0)); -// static_assert(inverse_mod(T(0), T(2)) == T(0)); -// static_assert(inverse_mod(T(46), T(46)) == T(0)); -// static_assert(inverse_mod(T(1), T(7)) == T(1)); -// static_assert(inverse_mod(T(35), T(118)) == T(27)); -// static_assert(inverse_mod(T(37), T(37)) == T(0)); -// static_assert(inverse_mod(T(32), T(247)) == T(193)); -// static_assert(inverse_mod(T(3), T(232)) == T(155)); -// -// static_assert(monty_inverse(T(12), T(5), T(5)) == T(1823)); -// static_assert(monty_inverse(T(10), T(37), T(1)) == T(26)); -// static_assert(monty_inverse(T(3), T(2), T(3)) == T(3)); -// static_assert(monty_inverse(T(3), T(4), T(2)) == T(11)); -// static_assert(monty_inverse(T(4), T(7), T(2)) == T(37)); -// static_assert(monty_inverse(T(32), T(247), T(1)) == T(193)); -// static_assert(monty_inverse(T(3), T(7), T(7)) == T(549029)); -// static_assert(monty_inverse(T(5317589), T(23), T(8)) == T(32104978469)); -// } -// -// BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(static_tests) + +BOOST_AUTO_TEST_CASE(fixed_test) { + using modular_number = nil::crypto3::multiprecision::big_mod_rt<585>; + using T = nil::crypto3::multiprecision::big_uint<585>; + + constexpr auto mod = + 0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_big_uint585; + constexpr auto a = 0xfeff_big_uint585; + constexpr auto a_inv = + 0x565eb513c8dca58227a9d17b4cc814dcf1cec08f4fdf2f0e3d4b88d45d318ec04f0f5e6dcc3a06404686cd542175970ca3b05404585cb511c6d89f78178fa736de14f307fb02fe00ff_big_uint585; + static_assert(a_inv == inverse_mod(a, mod), "inverse error"); + + constexpr modular_number a_m(a, mod); + constexpr modular_number a_inv_m(a_inv, mod); + static_assert(a_inv_m == inverse(a_m), "inverse error"); + + static_assert(inverse_mod(T(3), T(8)) == T(3)); + // static_assert(inverse_mod(T(46), T(207)) == T(0)); + // static_assert(inverse_mod(T(2), T(2)) == T(0)); + // static_assert(inverse_mod(T(0), T(2)) == T(0)); + // static_assert(inverse_mod(T(46), T(46)) == T(0)); + static_assert(inverse_mod(T(1), T(7)) == T(1)); + static_assert(inverse_mod(T(35), T(118)) == T(27)); + // static_assert(inverse_mod(T(37), T(37)) == T(0)); + static_assert(inverse_mod(T(32), T(247)) == T(193)); + static_assert(inverse_mod(T(3), T(232)) == T(155)); +} + +BOOST_AUTO_TEST_SUITE_END()