diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/add.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/add.hpp similarity index 73% rename from crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/add.hpp rename to crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/add.hpp index 1249b9e3c8..d90e6f8cd3 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/add.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/add.hpp @@ -10,12 +10,12 @@ // #include #include +#include "nil/crypto3/multiprecision/big_integer/basic_ops/add_unsigned.hpp" #include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" #include "nil/crypto3/multiprecision/big_integer/detail/config.hpp" -#include "nil/crypto3/multiprecision/big_integer/ops/add_unsigned.hpp" #include "nil/crypto3/multiprecision/big_integer/storage.hpp" -namespace nil::crypto3::multiprecision { +namespace nil::crypto3::multiprecision::detail { template inline constexpr void add_unsigned(big_integer& result, const big_integer& a, @@ -91,84 +91,80 @@ namespace nil::crypto3::multiprecision { // above: // template - NIL_CO3_MP_FORCEINLINE constexpr void eval_add(big_integer& result, - const big_integer& o) noexcept { - eval_add(result, result, o); + NIL_CO3_MP_FORCEINLINE constexpr void add(big_integer& result, const big_integer& a, + const big_integer& b) noexcept { + add_unsigned(result, a, b); } template - inline constexpr void eval_add(big_integer& result, const big_integer& a, - const big_integer& b) noexcept { - add_unsigned(result, a, b); + NIL_CO3_MP_FORCEINLINE constexpr void add(big_integer& result, + const big_integer& o) noexcept { + add(result, result, o); } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_add(big_integer& result, - const limb_type& o) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void add(big_integer& result, + const limb_type& o) noexcept { add_unsigned(result, result, o); } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_add(big_integer& result, - const big_integer& a, - const limb_type& o) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void add(big_integer& result, const big_integer& a, + const limb_type& o) noexcept { add_unsigned(result, a, o); } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_subtract(big_integer& result, - const limb_type& o) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void subtract(big_integer& result, + const limb_type& o) noexcept { subtract_unsigned(result, result, o); } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_subtract(big_integer& result, - const big_integer& a, - const limb_type& o) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void subtract(big_integer& result, + const big_integer& a, + const limb_type& o) noexcept { subtract_unsigned(result, a, o); } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_increment(big_integer& result) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void increment(big_integer& result) noexcept { if ((result.limbs()[0] < big_integer::max_limb_value)) { ++result.limbs()[0]; } else { - eval_add(result, (limb_type)1); + add(result, static_cast(1u)); } } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_decrement(big_integer& result) noexcept { - constexpr const limb_type one = 1; - + NIL_CO3_MP_FORCEINLINE constexpr void decrement(big_integer& result) noexcept { if (result.limbs()[0]) { --result.limbs()[0]; } else { - eval_subtract(result, one); + subtract(result, static_cast(1u)); } } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_subtract(big_integer& result, - const big_integer& o) noexcept { - eval_subtract(result, result, o); + NIL_CO3_MP_FORCEINLINE constexpr void subtract(big_integer& result, + const big_integer& a, + const big_integer& b) noexcept { + subtract_unsigned(result, a, b); } - template - NIL_CO3_MP_FORCEINLINE constexpr void eval_subtract(big_integer& result, - const big_integer& a, - const big_integer& b) noexcept { - subtract_unsigned(result, a, b); + NIL_CO3_MP_FORCEINLINE constexpr void subtract(big_integer& result, + const big_integer& o) noexcept { + subtract(result, result, o); } template - NIL_CO3_MP_FORCEINLINE constexpr typename std::enable_if<(Bits1 >= Bits2)>::type eval_subtract( + NIL_CO3_MP_FORCEINLINE constexpr typename std::enable_if<(Bits1 >= Bits2)>::type subtract( big_integer& result, const big_integer& o) noexcept { big_integer o_larger = o; - eval_subtract(result, result, o_larger); + subtract(result, result, o_larger); } template - NIL_CO3_MP_FORCEINLINE constexpr typename std::enable_if<(Bits1 >= Bits2)>::type eval_subtract( + NIL_CO3_MP_FORCEINLINE constexpr typename std::enable_if<(Bits1 >= Bits2)>::type subtract( big_integer& result, const big_integer& a, const big_integer& b) noexcept { big_integer b_larger = b; subtract_unsigned(result, a, b_larger); } -} // namespace nil::crypto3::multiprecision +} // namespace nil::crypto3::multiprecision::detail diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/add_unsigned.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/add_unsigned.hpp similarity index 99% rename from crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/add_unsigned.hpp rename to crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/add_unsigned.hpp index aef579034c..3abef6016d 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/add_unsigned.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/add_unsigned.hpp @@ -13,7 +13,7 @@ #include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" #include "nil/crypto3/multiprecision/big_integer/storage.hpp" -namespace nil::crypto3::multiprecision { +namespace nil::crypto3::multiprecision::detail { template inline constexpr void add_unsigned_constexpr(big_integer& result, const big_integer& a, @@ -288,4 +288,4 @@ namespace nil::crypto3::multiprecision { } #endif -} // namespace nil::crypto3::multiprecision +} // namespace nil::crypto3::multiprecision::detail diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/bitwise.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/bitwise.hpp similarity index 75% rename from crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/bitwise.hpp rename to crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/bitwise.hpp index 1a9150ad66..a7b10639cd 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/bitwise.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/bitwise.hpp @@ -15,12 +15,7 @@ #include "nil/crypto3/multiprecision/big_integer/detail/config.hpp" #include "nil/crypto3/multiprecision/big_integer/storage.hpp" -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4319) -#endif - -namespace nil::crypto3::multiprecision { +namespace nil::crypto3::multiprecision::detail { template constexpr void bitwise_op(big_integer& result, const big_integer& o, Op op) noexcept { @@ -49,47 +44,47 @@ namespace nil::crypto3::multiprecision { } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_bitwise_and(big_integer& result, - const big_integer& o) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void bitwise_and(big_integer& result, + const big_integer& o) noexcept { bitwise_op(result, o, std::bit_and()); } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_bitwise_or(big_integer& result, - const big_integer& o) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void bitwise_or(big_integer& result, + const big_integer& o) noexcept { bitwise_op(result, o, std::bit_or()); } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_bitwise_xor(big_integer& result, - const big_integer& o) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void bitwise_xor(big_integer& result, + const big_integer& o) noexcept { bitwise_op(result, o, std::bit_xor()); } // // Again for operands which are single limbs: // template - NIL_CO3_MP_FORCEINLINE constexpr void eval_bitwise_and(big_integer& result, - limb_type l) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void bitwise_and(big_integer& result, + limb_type l) noexcept { result.limbs()[0] &= l; result.zero_after(1); } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_bitwise_or(big_integer& result, - limb_type l) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void bitwise_or(big_integer& result, + limb_type l) noexcept { result.limbs()[0] |= l; } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_bitwise_xor(big_integer& result, - limb_type l) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void bitwise_xor(big_integer& result, + limb_type l) noexcept { result.limbs()[0] ^= l; } template - NIL_CO3_MP_FORCEINLINE constexpr void eval_complement(big_integer& result, - const big_integer& o) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr void complement(big_integer& result, + const big_integer& o) noexcept { unsigned os = o.size(); for (unsigned i = 0; i < os; ++i) { result.limbs()[i] = ~o.limbs()[i]; @@ -101,9 +96,9 @@ namespace nil::crypto3::multiprecision { // This function must be called only when s % 8 == 0, i.e. we shift bytes. template inline void left_shift_byte(big_integer& result, double_limb_type s) { - typedef big_integer Int; + typedef big_integer big_integer_t; - typename Int::limb_pointer pr = result.limbs(); + typename big_integer_t::limb_pointer pr = result.limbs(); std::size_t bytes = static_cast(s / CHAR_BIT); if (s >= Bits) { @@ -121,12 +116,12 @@ namespace nil::crypto3::multiprecision { // are normally 64 bit. template inline constexpr void left_shift_limb(big_integer& result, double_limb_type s) { - typedef big_integer Int; + using big_integer_t = big_integer; - limb_type offset = static_cast(s / Int::limb_bits); - BOOST_ASSERT(static_cast(s % Int::limb_bits) == 0); + limb_type offset = static_cast(s / big_integer_t::limb_bits); + BOOST_ASSERT(static_cast(s % big_integer_t::limb_bits) == 0); - typename Int::limb_pointer pr = result.limbs(); + typename big_integer_t::limb_pointer pr = result.limbs(); if (s >= Bits) { // Set result to 0. @@ -146,16 +141,16 @@ namespace nil::crypto3::multiprecision { // Left shift will throw away upper Bits. template inline constexpr void left_shift_generic(big_integer& result, double_limb_type s) { - typedef big_integer Int; + using big_integer_t = big_integer; if (s >= Bits) { // Set result to 0. result.zero_after(0); } else { - limb_type offset = static_cast(s / Int::limb_bits); - limb_type shift = static_cast(s % Int::limb_bits); + limb_type offset = static_cast(s / big_integer_t::limb_bits); + limb_type shift = static_cast(s % big_integer_t::limb_bits); - typename Int::limb_pointer pr = result.limbs(); + typename big_integer_t::limb_pointer pr = result.limbs(); std::size_t i = 0; std::size_t rs = result.size(); // This code only works when shift is non-zero, otherwise we invoke undefined @@ -163,7 +158,7 @@ namespace nil::crypto3::multiprecision { BOOST_ASSERT(shift); for (; rs - i >= 2 + offset; ++i) { pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift; - pr[rs - 1 - i] |= pr[rs - 2 - i - offset] >> (Int::limb_bits - shift); + pr[rs - 1 - i] |= pr[rs - 2 - i - offset] >> (big_integer_t::limb_bits - shift); } if (rs - i >= 1 + offset) { pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift; @@ -177,7 +172,7 @@ namespace nil::crypto3::multiprecision { // Shifting left throws away upper Bits. template - inline constexpr void eval_left_shift(big_integer& result, double_limb_type s) noexcept { + inline constexpr void left_shift(big_integer& result, double_limb_type s) noexcept { if (!s) { return; } @@ -226,9 +221,9 @@ namespace nil::crypto3::multiprecision { template inline void right_shift_byte(big_integer& result, double_limb_type s) { - typedef big_integer Int; + typedef big_integer big_integer_t; - limb_type offset = static_cast(s / Int::limb_bits); + limb_type offset = static_cast(s / big_integer_t::limb_bits); BOOST_ASSERT((s % CHAR_BIT) == 0); unsigned ors = result.size(); unsigned rs = ors; @@ -237,12 +232,12 @@ namespace nil::crypto3::multiprecision { return; } rs -= offset; - typename Int::limb_pointer pr = result.limbs(); + typename big_integer_t::limb_pointer pr = result.limbs(); unsigned char* pc = reinterpret_cast(pr); limb_type shift = static_cast(s / CHAR_BIT); std::memmove(pc, pc + shift, ors * sizeof(pr[0]) - shift); shift = (sizeof(limb_type) - shift % sizeof(limb_type)) * CHAR_BIT; - if (shift < Int::limb_bits) { + if (shift < big_integer_t::limb_bits) { pr[ors - offset - 1] &= (static_cast(1u) << shift) - 1; if (!pr[ors - offset - 1] && (rs > 1)) { --rs; @@ -254,10 +249,10 @@ namespace nil::crypto3::multiprecision { template inline constexpr void right_shift_limb(big_integer& result, double_limb_type s) { - typedef big_integer Int; + typedef big_integer big_integer_t; - limb_type offset = static_cast(s / Int::limb_bits); - BOOST_ASSERT((s % Int::limb_bits) == 0); + limb_type offset = static_cast(s / big_integer_t::limb_bits); + BOOST_ASSERT((s % big_integer_t::limb_bits) == 0); unsigned ors = result.size(); unsigned rs = ors; if (offset >= rs) { @@ -265,7 +260,7 @@ namespace nil::crypto3::multiprecision { return; } rs -= offset; - typename Int::limb_pointer pr = result.limbs(); + typename big_integer_t::limb_pointer pr = result.limbs(); unsigned i = 0; for (; i < rs; ++i) { pr[i] = pr[i + offset]; @@ -276,9 +271,9 @@ namespace nil::crypto3::multiprecision { template inline constexpr void right_shift_generic(big_integer& result, double_limb_type s) { - typedef big_integer Int; - limb_type offset = static_cast(s / Int::limb_bits); - limb_type shift = static_cast(s % Int::limb_bits); + typedef big_integer big_integer_t; + limb_type offset = static_cast(s / big_integer_t::limb_bits); + limb_type shift = static_cast(s % big_integer_t::limb_bits); unsigned ors = result.size(); unsigned rs = ors; @@ -287,7 +282,7 @@ namespace nil::crypto3::multiprecision { return; } rs -= offset; - typename Int::limb_pointer pr = result.limbs(); + typename big_integer_t::limb_pointer pr = result.limbs(); if ((pr[ors - 1] >> shift) == 0) { if (--rs == 0) { result = limb_type(0); @@ -300,7 +295,7 @@ namespace nil::crypto3::multiprecision { BOOST_ASSERT(shift); for (; i + offset + 1 < ors; ++i) { pr[i] = pr[i + offset] >> shift; - pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift); + pr[i] |= pr[i + offset + 1] << (big_integer_t::limb_bits - shift); } pr[i] = pr[i + offset] >> shift; @@ -309,7 +304,7 @@ namespace nil::crypto3::multiprecision { } template - inline constexpr void eval_right_shift(big_integer& result, double_limb_type s) noexcept { + inline constexpr void right_shift(big_integer& result, double_limb_type s) noexcept { if (!s) { return; } @@ -352,8 +347,4 @@ namespace nil::crypto3::multiprecision { right_shift_generic(result, s); } } -} // namespace nil::crypto3::multiprecision - -#ifdef _MSC_VER -#pragma warning(pop) -#endif +} // namespace nil::crypto3::multiprecision::detail diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/divide.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/divide.hpp new file mode 100644 index 0000000000..1fd314d72a --- /dev/null +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/divide.hpp @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////// +// Copyright (c) 2023 Martun Karapetyan +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt +// +// Contains modulus for big_integer, which uses conversion to cpp_int_backend to +// actually apply the operation. +// + +#pragma once + +#include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" + +// Functions in this file should be called only for creation of montgomery and Barett +// params, no during "normal" execution, so we do NOT care about the execution speed, +// and will just redirect calls to normal boost::cpp_int. + +namespace nil::crypto3::multiprecision::detail { + // Just a call to the upper function, similar to operator*=. + // Caller is responsible for the result to fit in Bits1 Bits, we will NOT throw! + template + inline constexpr void modulus(big_integer &result, + const big_integer &a) noexcept { + auto result_cpp_int = result.to_cpp_int(); + result_cpp_int %= a.to_cpp_int(); + result.from_cpp_int(result_cpp_int); + } + + template + inline constexpr void divide(big_integer &result, const big_integer &a) noexcept { + auto result_cpp_int = result.to_cpp_int(); + result_cpp_int /= a.to_cpp_int(); + result.from_cpp_int(result_cpp_int); + } +} // namespace nil::crypto3::multiprecision::detail diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/multiply.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/multiply.hpp new file mode 100644 index 0000000000..c71520e98c --- /dev/null +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/basic_ops/multiply.hpp @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////// +// Copyright (c) 2023 Martun Karapetyan +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt +// +// Contains multiply for big_integer, which does nothing but converts it to +// cpp_int_backend and does the multiplication. +// + +#pragma once + +#include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" +#include "nil/crypto3/multiprecision/big_integer/storage.hpp" + +// Functions in this file should be called only for creation of montgomery and Barett +// params, calculation of inverse element and montgomery_reduce. Since these functions +// are relatively slow and are not called very often, we will not optimize them. We do +// NOT care about the execution speed, and will just redirect calls to normal +// boost::cpp_int. + +// Caller is responsible for the result to fit in Bits1 Bits, we will NOT throw!!! + +namespace nil::crypto3::multiprecision::detail { + template + inline constexpr void multiply(big_integer &result, const limb_type &b) noexcept { + auto result_cpp_int = result.to_cpp_int(); + result_cpp_int *= b; + result.from_cpp_int(result_cpp_int); + } + + template + inline constexpr void multiply(big_integer &result, + const big_integer &a) noexcept { + auto result_cpp_int = result.to_cpp_int(); + result_cpp_int *= a.to_cpp_int(); + result.from_cpp_int(result_cpp_int); + } +} // namespace nil::crypto3::multiprecision::detail diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp index 3a0ca0a4b9..8578b9673a 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp @@ -9,10 +9,10 @@ #include #include #include +#include #include #include #include -#include // TODO(ioxid): replace with custom code #include @@ -30,22 +30,25 @@ namespace nil::crypto3::multiprecision { Bits, Bits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked>>; + using limb_type = detail::limb_type; + using double_limb_type = detail::double_limb_type; + using signed_limb_type = detail::signed_limb_type; + using signed_double_limb_type = detail::signed_double_limb_type; + using unsigned_types = std::tuple; using signed_types = std::tuple; // Storage - using limb_type = limb_type; - using double_limb_type = double_limb_type; - using limb_pointer = limb_type*; - using const_limb_pointer = const limb_type*; + using limb_pointer = detail::limb_pointer; + using const_limb_pointer = detail::const_limb_pointer; + static constexpr unsigned limb_bits = detail::limb_bits; + static constexpr unsigned max_limb_value = detail::max_limb_value; - static constexpr unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; - static constexpr limb_type max_limb_value = ~static_cast(0u); static constexpr unsigned internal_limb_count = - (Bits / limb_bits) + (((Bits % limb_bits) != 0u) ? 1 : 0); + (Bits / limb_bits) + (((Bits % limb_bits) != 0u) ? 1u : 0u); static constexpr limb_type upper_limb_mask = - (Bits % limb_bits) ? (limb_type(1) << (Bits % limb_bits)) - 1 : (~limb_type(0)); + (Bits % limb_bits) ? (limb_type(1) << (Bits % limb_bits)) - 1 : (~limb_type(0u)); // // Helper functions for getting at our internal data, and manipulating storage: @@ -88,24 +91,14 @@ namespace nil::crypto3::multiprecision { } // TODO(ioxid): forbid signed, implement comparison with signed instead - template /*&& std::is_unsigned_v*/, - bool> = true> - inline constexpr big_integer(UI val) noexcept { + template /*&& std::is_unsigned_v*/, int> = 0> + inline constexpr big_integer(T val) noexcept { if (val < 0) { std::cerr << "big_integer: assignment from negative integer" << std::endl; std::terminate(); } - // TODO(ioxid): support assignment from uint64_t and uint128_t - do_assign_integral(static_cast(val)); - } - - // Move constructors - - inline constexpr big_integer(big_integer&& other) noexcept { do_assign(other); } - - template - inline constexpr big_integer(big_integer&& other) noexcept { - do_assign(other); + do_assign_integral(static_cast>(val)); } // Copy construction @@ -128,35 +121,24 @@ namespace nil::crypto3::multiprecision { return *this; } - // Move assignment - - inline constexpr auto& operator=(big_integer&& other) noexcept { - do_assign(other); - return *this; - } - template - inline constexpr big_integer& operator=(big_integer&& other) noexcept { - do_assign(other); - return *this; - } - // Assignment from other types // TODO(ioxid): forbid signed, implement comparison with signed instead - template + template inline constexpr - typename std::enable_if_t /*&& std::is_unsigned_v*/, + typename std::enable_if_t /*&& std::is_unsigned_v*/, big_integer&> - operator=(UI val) noexcept { + operator=(T val) noexcept { if (val < 0) { std::cerr << "big_integer: assignment from negative integer" << std::endl; std::terminate(); } - do_assign_integral(val); + do_assign_integral(static_cast>(val)); return *this; } inline constexpr auto& operator=(const char* s) { + // TODO(ioxid): rewrite without cpp_int cpp_int_type value; value = s; this->from_cpp_int(value); @@ -175,55 +157,58 @@ namespace nil::crypto3::multiprecision { // cpp_int conversion - inline constexpr void from_cpp_int(const cpp_int_type& other) { - // Here we need other.size(), not this->size(), because cpp_int may not use all the - // limbs it has, but we will. - for (unsigned i = 0; i < other.backend().size(); ++i) { - this->limbs()[i] = other.backend().limbs()[i]; - } - // Zero out the rest. - for (unsigned i = other.backend().size(); i < this->size(); ++i) { - this->limbs()[i] = 0; + inline constexpr void from_cpp_int(cpp_int_type cppint) { + for (limb_type& limb : m_data) { + limb = static_cast(cppint & static_cast(-1)); + cppint >>= limb_bits; } } // Converting to cpp_int. We need this for multiplication, division and string - // conversions. Since these operations are rare, there's no reason to implement then for + // conversions. Since these operations are rare, there's no reason to implement them for // big_integer, converting to cpp_int does not result to performance penalty. inline constexpr cpp_int_type to_cpp_int() const { cpp_int_type result; - // TODO(ioxid): not constexpr? - // result.backend().resize(this->size(), this->size()); - // for (unsigned i = 0; i < this->size(); ++i) { - // result.backend().limbs()[i] = this->limbs()[i]; - // } - // result.backend().normalize(); - return std::move(result); + for (const limb_type limb : m_data | std::views::reverse) { + result <<= limb_bits; + result |= limb; + } + return result; } // cast to integral types - template, bool> = true> + template && std::is_unsigned_v, int> = 0> explicit inline constexpr operator T() const { - return static_cast(this->limbs()[0]); + if constexpr (sizeof(T) <= sizeof(limb_type)) { + return static_cast(this->limbs()[0]); + } else { + constexpr std::size_t n = sizeof(T) / sizeof(limb_type); + T result = 0; + for (std::size_t i = 0; i < n; ++i) { + result <<= limb_bits; + result |= limbs()[n - i - 1]; + } + return result; + } } private: - inline constexpr void do_assign_integral(limb_type i) noexcept { - // TODO(ioxid): support assignment from uint64_t and uint128_t - *this->limbs() = i; - this->zero_after(1); - this->normalize(); - } - - inline constexpr void do_assign_integral(double_limb_type i) noexcept { - // TODO(ioxid): support assignment from uint128_t - static_assert(sizeof(i) == 2 * sizeof(limb_type), "Failed integer size check"); - auto p = this->limbs(); - *p = static_cast(i); - if (this->size() > 1) { - p[1] = static_cast(i >> limb_bits); - this->zero_after(2); + template && std::is_unsigned_v, int> = 0> + inline constexpr void do_assign_integral(T a) noexcept { + if constexpr (sizeof(T) <= sizeof(limb_type)) { + this->limbs()[0] = a; + this->zero_after(1); + } else { + static_assert(sizeof(T) % sizeof(limb_type) == 0); + constexpr std::size_t n = sizeof(T) / sizeof(limb_type); + for (std::size_t i = 0; i < n; ++i) { + limbs()[i] = a & static_cast(static_cast(-1)); + a >>= limb_bits; + } + zero_after(n); } this->normalize(); } diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/big_integer_ops.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/big_integer_ops.hpp index 6cdf17b8d9..15cf6d4659 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/big_integer_ops.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/big_integer_ops.hpp @@ -8,12 +8,13 @@ #include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" -#include "nil/crypto3/multiprecision/big_integer/ops/add.hpp" -#include "nil/crypto3/multiprecision/big_integer/ops/bitwise.hpp" -#include "nil/crypto3/multiprecision/big_integer/ops/divide.hpp" +#include "nil/crypto3/multiprecision/big_integer/basic_ops/add.hpp" +#include "nil/crypto3/multiprecision/big_integer/basic_ops/bitwise.hpp" +#include "nil/crypto3/multiprecision/big_integer/basic_ops/divide.hpp" +#include "nil/crypto3/multiprecision/big_integer/basic_ops/multiply.hpp" + #include "nil/crypto3/multiprecision/big_integer/ops/import_export.hpp" // IWYU pragma: export #include "nil/crypto3/multiprecision/big_integer/ops/misc.hpp" // IWYU pragma: export -#include "nil/crypto3/multiprecision/big_integer/ops/multiply.hpp" namespace nil::crypto3::multiprecision { namespace detail { @@ -29,12 +30,12 @@ namespace nil::crypto3::multiprecision { template constexpr bool is_integral_v = std::is_integral_v || is_big_integer_v; - template, bool> = true> + template, int> = 0> constexpr std::size_t get_bits() { return sizeof(T) * CHAR_BIT; } - template, bool> = true> + template, int> = 0> constexpr std::size_t get_bits() { return T::Bits; } @@ -44,7 +45,7 @@ namespace nil::crypto3::multiprecision { template && detail::is_integral_v && \ (detail::is_big_integer_v || detail::is_big_integer_v), \ - bool> = true, \ + int> = 0, \ typename result_t = \ big_integer(), detail::get_bits())>> @@ -53,11 +54,11 @@ namespace nil::crypto3::multiprecision { typename big_integer_t, typename T, \ std::enable_if_t && detail::is_integral_v && \ detail::get_bits() <= big_integer_t::Bits, \ - bool> = true> + int> = 0> #define CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE \ template, bool> = true> + std::enable_if_t, int> = 0> // Comparison @@ -82,17 +83,17 @@ namespace nil::crypto3::multiprecision { CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator+(const T1& a, const T2& b) noexcept { result_t tmp{a}; - eval_add(tmp, b); + detail::add(tmp, b); return tmp; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator+=(big_integer_t& a, const T& b) noexcept { - eval_add(a, b); + detail::add(a, b); return a; } CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto& operator++(big_integer_t& a) noexcept { - eval_increment(a); + detail::increment(a); return a; } CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE @@ -107,17 +108,17 @@ namespace nil::crypto3::multiprecision { CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator-(const T1& a, const T2& b) noexcept { result_t tmp; - eval_subtract(tmp, a, b); + detail::subtract(tmp, a, b); return tmp; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator-=(big_integer_t& a, const T& b) { - eval_subtract(a, b); + detail::subtract(a, b); return a; } CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto& operator--(big_integer_t& a) noexcept { - eval_decrement(a); + detail::decrement(a); return a; } CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE @@ -136,105 +137,105 @@ namespace nil::crypto3::multiprecision { CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator*(const T1& a, const T2& b) noexcept { result_t result{a}; - eval_multiply(result, b); + detail::multiply(result, b); return result; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator*=(big_integer_t& a, const T& b) noexcept { - eval_multiply(a, b); + detail::multiply(a, b); return a; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator/(const T1& a, const T2& b) noexcept { - result_t result; - eval_divide(result, a, b); + result_t result = a; + detail::divide(result, b); return result; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator/=(big_integer_t& a, const T& b) noexcept { - eval_divide(a, b); + detail::divide(a, b); return a; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator%(const T1& a, const T2& b) noexcept { - result_t result; - eval_modulus(result, a, b); + result_t result = a; + detail::modulus(result, b); return result; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator%=(big_integer_t& a, const T& b) { - eval_modulus(a, b); + detail::modulus(a, b); return a; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator&(const T1& a, const T2& b) noexcept { result_t result{a}; - eval_bitwise_and(result, b); + detail::bitwise_and(result, b); return result; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator&=(big_integer_t& a, const T& b) { - eval_bitwise_and(a, b); + detail::bitwise_and(a, b); return a; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator|(const T1& a, const T2& b) noexcept { result_t result{a}; - eval_bitwise_or(result, b); + detail::bitwise_or(result, b); return result; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator|=(big_integer_t& a, const T& b) { - eval_bitwise_or(a, b); + detail::bitwise_or(a, b); return a; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator^(const T1& a, const T2& b) noexcept { result_t result{a}; - eval_bitwise_xor(result, b); + detail::bitwise_xor(result, b); return result; } CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator^=(big_integer_t& a, const T& b) { - eval_bitwise_or(a, b); + detail::bitwise_or(a, b); return a; } CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto operator~(const big_integer_t& a) noexcept { big_integer_t result; - eval_complement(result, a); + detail::complement(result, a); return result; } CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto operator<<(const big_integer_t& a, unsigned shift) noexcept { big_integer_t result{a}; - eval_left_shift(result, shift); + detail::left_shift(result, shift); return result; } CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto& operator<<=(big_integer_t& a, unsigned shift) noexcept { // TODO(ioxid): check - eval_left_shift(a, shift); + detail::left_shift(a, shift); return a; } CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto operator>>(const big_integer_t& a, unsigned shift) noexcept { big_integer_t result{a}; - eval_right_shift(result, shift); + detail::right_shift(result, shift); return result; } CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto& operator>>=(big_integer_t& a, unsigned shift) noexcept { // TODO(ioxid): check - eval_right_shift(a, shift); + detail::right_shift(a, shift); return a; } @@ -242,8 +243,7 @@ namespace nil::crypto3::multiprecision { CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE std::ostream& operator<<(std::ostream& os, const big_integer_t& value) { - // TODO(ioxid): rewrite without cpp_int - os << value.to_cpp_int() << std::endl; + os << value.str() << std::endl; return os; } diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/limits.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/limits.hpp index 083d089a75..cc54a079b1 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/limits.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/limits.hpp @@ -8,47 +8,33 @@ #include #include -#include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" +#include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" -namespace nil::crypto3::multiprecision { - template - class big_integer; -} - -namespace std { - namespace detail { - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4307) -#endif - - template - inline constexpr nil::crypto3::multiprecision::big_integer get_min() { - constexpr const nil::crypto3::multiprecision::big_integer val(0u); - return val; - } +namespace nil::crypto3::multiprecision::detail { + template + inline constexpr big_integer get_min() { + constexpr big_integer val = 0u; + return val; + } - template - inline constexpr nil::crypto3::multiprecision::big_integer get_max() { - using result_type = nil::crypto3::multiprecision::big_integer; - using ui_type = nil::crypto3::multiprecision::big_integer; - constexpr const result_type val = ~ui_type(0); - return val; - } + template + inline constexpr nil::crypto3::multiprecision::big_integer get_max() { + constexpr auto val = ~big_integer(0u); + return val; + } - inline constexpr unsigned calc_digits10(unsigned d) { - // - // We need floor(log10(2) * (d-1)), see: - // https://www.exploringbinary.com/number-of-digits-required-for-round-trip-conversions/ - // and references therein. - // - return static_cast( - 0.301029995663981195213738894724493026768189881462108541310 * - static_cast(d - 1u)); - } - } // namespace detail + inline constexpr unsigned calc_digits10(unsigned d) { + // + // We need floor(log10(2) * (d-1)), see: + // https://www.exploringbinary.com/number-of-digits-required-for-round-trip-conversions/ + // and references therein. + // + return static_cast(0.301029995663981195213738894724493026768189881462108541310 * + static_cast(d - 1u)); + } +} // namespace nil::crypto3::multiprecision::detail +namespace std { template class numeric_limits> { using number_type = nil::crypto3::multiprecision::big_integer; @@ -59,12 +45,17 @@ namespace std { // Largest and smallest numbers are bounded only by available memory, set // to zero: // - static constexpr number_type(min)() { return detail::get_min(); } - static constexpr number_type(max)() { return detail::get_max(); } + static constexpr number_type(min)() { + return nil::crypto3::multiprecision::detail::get_min(); + } + static constexpr number_type(max)() { + return nil::crypto3::multiprecision::detail::get_max(); + } static constexpr number_type lowest() { return (min)(); } static constexpr int digits = number_type::Bits; - static constexpr int digits10 = detail::calc_digits10(digits); - static constexpr int max_digits10 = detail::calc_digits10(digits); + static constexpr int digits10 = nil::crypto3::multiprecision::detail::calc_digits10(digits); + static constexpr int max_digits10 = + nil::crypto3::multiprecision::detail::calc_digits10(digits); static constexpr bool is_signed = false; static constexpr bool is_integer = true; static constexpr bool is_exact = true; @@ -91,8 +82,4 @@ namespace std { static constexpr bool tinyness_before = false; }; -#ifdef _MSC_VER -#pragma warning(pop) -#endif - } // namespace std diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/literals.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/literals.hpp index d48e5748aa..aeb8079f0d 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/literals.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/literals.hpp @@ -6,25 +6,58 @@ #pragma once #include +#include #include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" namespace nil::crypto3::multiprecision::literals { namespace detail { + constexpr bool is_valid_hex_digit(char c) { + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); + } + + constexpr int parse_hex_digit(char c) { + if ('0' <= c && c <= '9') { + return c - '0'; + } + if ('a' <= c && c <= 'f') { + return (c - 'a') + 10; + } + return (c - 'A') + 10; + } + template constexpr big_integer parse_int_hex() { static_assert(c1 == '0', "hex literal should start with 0x"); static_assert(c2 == 'x', "hex literal should start with 0x"); - constexpr std::size_t hex_digits = sizeof...(STR); - static_assert(Bits >= hex_digits * 4, "not enough bits to store literal"); - static_assert(hex_digits >= 1, "at least one digit expected"); - big_integer result{0}; + std::size_t bits = 0; for (const char c : {STR...}) { + if (!is_valid_hex_digit(c)) { + throw std::invalid_argument("non hex character in literal"); + } + int digit = parse_hex_digit(c); result <<= 4; - result += c - '0'; + if (bits != 0) { + bits += 4; + } + result += parse_hex_digit(c); + if (digit != 0) { + if (digit >= 8) { + bits = 4; + } else if (digit >= 4) { + bits = 3; + } else if (digit >= 2) { + bits = 2; + } else { + bits = 1; + } + } + } + if (bits > Bits) { + throw "not enough bits to store literal"; } return result; } @@ -32,124 +65,126 @@ namespace nil::crypto3::multiprecision::literals { template constexpr auto operator"" _big_integer() { - return detail::parse_int_hex(); + return detail::parse_int_hex<(sizeof...(STR) - 2) * 4, STR...>(); } +} // namespace nil::crypto3::multiprecision::literals -#define CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(Bits) \ - template \ - constexpr auto operator"" _big_integer##Bits() { \ - return detail::parse_int_hex(); \ +#define CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(Bits) \ + namespace nil::crypto3::multiprecision::literals { \ + template \ + constexpr auto operator"" _big_integer##Bits() { \ + return nil::crypto3::multiprecision::literals::detail::parse_int_hex(); \ + } \ } - // This is a comprehensive list of all bitlengths we use - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(4) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(7) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(8) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(13) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(15) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(16) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(17) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(18) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(64) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(92) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(94) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(128) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(130) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(149) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(150) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(151) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(152) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(160) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(161) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(163) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(164) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(177) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(178) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(179) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(180) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(181) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(182) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(183) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(191) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(192) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(205) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(206) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(222) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(223) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(224) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(225) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(226) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(239) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(248) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(249) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(250) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(251) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(252) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(253) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(254) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(255) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(256) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(257) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(263) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(264) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(280) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(281) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(292) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(293) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(294) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(295) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(296) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(297) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(298) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(315) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(316) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(319) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(320) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(330) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(331) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(374) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(375) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(376) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(377) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(378) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(379) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(380) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(381) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(384) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(503) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(504) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(507) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(512) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(515) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(516) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(521) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(546) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(577) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(578) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(585) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(595) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(636) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(706) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(707) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(758) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(753) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(759) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(761) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(859) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(860) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(893) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(894) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(913) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(1024) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(1490) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(1536) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(2048) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(2790) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(3072) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(4096) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(4269) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(4314) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(6144) - CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(8192) -#undef CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL -} // namespace nil::crypto3::multiprecision::literals +// This is a comprehensive list of all bitlengths we use in algebra. +// Custom ones can be defined using this macro in every place where they are used. +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(4) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(7) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(8) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(13) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(15) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(16) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(17) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(18) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(64) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(92) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(94) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(128) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(130) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(149) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(150) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(151) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(152) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(160) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(161) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(163) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(164) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(177) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(178) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(179) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(180) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(181) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(182) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(183) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(191) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(192) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(205) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(206) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(222) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(223) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(224) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(225) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(226) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(239) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(248) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(249) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(250) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(251) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(252) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(253) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(254) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(255) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(256) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(257) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(263) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(264) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(280) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(281) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(292) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(293) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(294) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(295) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(296) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(297) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(298) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(315) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(316) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(319) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(320) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(330) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(331) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(374) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(375) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(376) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(377) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(378) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(379) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(380) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(381) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(384) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(503) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(504) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(507) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(512) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(515) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(516) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(521) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(546) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(577) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(578) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(585) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(595) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(636) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(706) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(707) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(758) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(753) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(759) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(761) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(859) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(860) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(893) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(894) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(913) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(1024) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(1490) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(1536) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(2048) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(2790) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(3072) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(4096) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(4269) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(4314) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(6144) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(8192) diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer.hpp index da6b087bea..05dd23a18e 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer.hpp @@ -1,20 +1,4 @@ #pragma once -#include - -#include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" #include "nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_impl.hpp" // IWYU pragma: export #include "nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_ops.hpp" // IWYU pragma: export -#include "nil/crypto3/multiprecision/big_integer/modular/modular_params.hpp" - -namespace nil::crypto3::multiprecision { - template - using modular_big_integer_ct = - modular_big_integer, - modular_params_storage_ct, modulus>>; - - // TODO(ioxid): modulus in constructor - template - using modular_big_integer_rt = - modular_big_integer, modular_params_storage_rt>>; -} // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_impl.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_impl.hpp index a88290cfa3..b7ba3b2547 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_impl.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_impl.hpp @@ -19,237 +19,225 @@ #include #include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" -#include "nil/crypto3/multiprecision/big_integer/modular/modular_params.hpp" +#include "nil/crypto3/multiprecision/big_integer/modular/modular_ops.hpp" namespace nil::crypto3::multiprecision { - // fixed precision modular big integer which supports compile-time execution - template - class modular_big_integer { - public: - constexpr static auto Bits = big_integer_t::Bits; - using limb_type = typename big_integer_t::limb_type; - using double_limb_type = typename big_integer_t::double_limb_type; - using modular_params_t = modular_params; - using Backend_type = big_integer_t; - - using unsigned_types = typename big_integer_t::unsigned_types; - using signed_types = typename big_integer_t::signed_types; - - protected: - using policy_type = typename modular_params_t::policy_type; - using Backend_padded_limbs = typename policy_type::Backend_padded_limbs; - using Backend_doubled_limbs = typename policy_type::Backend_doubled_limbs; - modular_params_storage_t modular_params_storage; - - public: - // This version of conversion - constexpr typename big_integer_t::cpp_int_type to_cpp_int() const { - big_integer_t tmp; - modular_params_storage.modular_params().adjust_regular(tmp, this->base_data()); - return tmp.to_cpp_int(); - } + namespace detail { + // fixed precision modular big integer which supports compile-time execution + template + class modular_big_integer_impl { + public: + using big_integer_t = big_integer_t_; + constexpr static auto Bits = big_integer_t::Bits; + using limb_type = typename big_integer_t::limb_type; + using double_limb_type = typename big_integer_t::double_limb_type; + using modular_ops_t = modular_ops; + + using unsigned_types = typename big_integer_t::unsigned_types; + using signed_types = typename big_integer_t::signed_types; + + private: + using policy_type = typename modular_ops_t::policy_type; + using big_integer_padded_limbs = typename policy_type::big_integer_padded_limbs; + using big_integer_doubled_limbs = typename policy_type::big_integer_doubled_limbs; + + // Constructors + + protected: + inline constexpr modular_big_integer_impl(modular_ops_storage_t&& modular_ops_storage) + : m_modular_ops_storage(std::move(modular_ops_storage)) {} + + public: + // Comparison + + constexpr bool compare_eq(const modular_big_integer_impl& o) const { + // TODO(ioxid): ensure modulus comparison is done in compile time when possible + return modular_ops().compare_eq(o.modular_ops()) && m_base == o.m_base; + } - constexpr auto mod_data() { return modular_params_storage.modular_params(); } - constexpr auto mod_data() const { return modular_params_storage.modular_params(); } + template + constexpr int compare_eq(const T& val) const { + // TODO(ioxid): should compare adjusted? + return m_base == val; + } - constexpr big_integer_t& base_data() { return m_base; } - constexpr const big_integer_t& base_data() const { return m_base; } + // cpp_int conversion - constexpr modular_big_integer() {} + constexpr typename big_integer_t::cpp_int_type to_cpp_int() const { + return modular_ops().adjusted_regular(m_base).to_cpp_int(); + } - constexpr modular_big_integer(const modular_big_integer& o) : m_base(o.base_data()) { - modular_params_storage.set_modular_params(o.modular_params_storage.modular_params()); - } + // String conversion - constexpr modular_big_integer(modular_big_integer&& o) noexcept - : m_base(std::move(o.base_data())) { - modular_params_storage.set_modular_params( - std::move(o.modular_params_storage.modular_params())); - } + inline std::string str(std::streamsize digits = 0, + std::ios_base::fmtflags f = std::ios_base::fmtflags(0)) const { + // TODO(ioxid): add module to output + return modular_ops().adjusted_regular(m_base).str(digits, f); + } - template && - std::is_unsigned_v> const* = nullptr> - constexpr modular_big_integer(UI b, const big_integer_t& m) : m_base(limb_type(b)) { - modular_params_storage.set_modular_params(m); - modular_params_storage.modular_params().adjust_modular(m_base); - } + // TODO(ioxid): why is it here + // Mathemetical operations - // A method for converting a signed integer to a modular adaptor. We are not supposed to - // have this, but in the code we already have conversion for an 'int' into modular type. In - // the future we must remove. - template && - std::is_signed_v> const* = nullptr> - constexpr modular_big_integer(SI b) : m_base(limb_type(0u)) { - if (b >= 0) { - m_base = static_cast(b); - } else { - m_base = modular_params_storage.modular_params().get_mod(); - eval_subtract(m_base, static_cast(-b)); + inline constexpr void negate() { + if (m_base != m_zero) { + auto initial_m_base = m_base; + m_base = modular_ops().get_mod(); + m_base -= initial_m_base; + } } - // This method must be called only for compile time modular params. - // modular_params_storage.set_modular_params(m); - modular_params_storage.modular_params().adjust_modular(m_base); - } + // TODO(ioxid): who needs this and why is it an assignment operator + // This function sets default modulus value to zero to make sure it fails if not used + // with compile-time fixed modulus. + modular_big_integer_impl& operator=(const char* s) { + using ui_type = typename std::tuple_element<0, unsigned_types>::type; + ui_type zero = 0u; + + if (s && (*s == '(')) { + std::string part; + const char* p = ++s; + while (*p && (*p != ',') && (*p != ')')) { + ++p; + } + part.assign(s, p); + if (!part.empty()) { + m_base = part.c_str(); + } else { + m_base = zero; + } + s = p; + if (*p && (*p != ')')) { + ++p; + while (*p && (*p != ')')) { + ++p; + } + part.assign(s + 1, p); + } else { + part.erase(); + } + if (!part.empty()) { + m_modular_ops_storage.set_modular_ops(part.c_str()); + } else { + m_modular_ops_storage.set_modular_ops(zero); + } + } else { + m_base = s; + m_modular_ops_storage.set_modular_ops(zero); + } + return *this; + } - template && - std::is_unsigned_v> const* = nullptr> - constexpr modular_big_integer(UI b) : m_base(static_cast(b)) { - // This method must be called only for compile time modular params. - // modular_params_storage.set_modular_params(m); - modular_params_storage.modular_params().adjust_modular(m_base); - } + constexpr auto& base_data() { return m_base; } + constexpr const auto& base_data() const { return m_base; } - template && - std::is_signed_v> const* = nullptr> - constexpr modular_big_integer(SI b, const modular_params_t& m) : m_base(limb_type(0u)) { - if (b >= 0) { - m_base = static_cast(b); - } else { - m_base = modular_params_storage.modular_params().get_mod(); - eval_subtract(m_base, static_cast(-b)); + constexpr auto& modular_ops() { return m_modular_ops_storage.modular_ops(); } + constexpr const auto& modular_ops() const { + return m_modular_ops_storage.modular_ops(); } - modular_params_storage.set_modular_params(m); - modular_params_storage.modular_params().adjust_modular(m_base); - } + protected: + modular_ops_storage_t m_modular_ops_storage; - template && - std::is_unsigned_v> const* = nullptr> - constexpr modular_big_integer(UI b, const modular_params_t& m) - : m_base(static_cast(b)) { - modular_params_storage.set_modular_params(m); - modular_params_storage.modular_params().adjust_modular(m_base); - } + big_integer_t m_base; + static constexpr big_integer_t m_zero = + static_cast::type>(0u); + ; + }; - // TODO - // // We may consider to remove this constructor later, and set Bits2 to Bits only, - // // but we need it for use cases from h2f/h2c, - // // where a larger number of 512 or 256 bits is passed to a field of 255 or 254 bits. - // template - // constexpr modular_big_integer(const number> &b, - // const number &m) { - // modular_params_storage.set_modular_params(m.big_integer_t()); - // modular_params_storage.modular_params().adjust_modular(m_base, b.big_integer_t()); - // } - - // We may consider to remove this constructor later, and set Bits2 to Bits only, - // but we need it for use cases from h2f/h2c, - // where a larger number of 512 or 256 bits is passed to a field of 255 or 254 bits. - template - constexpr modular_big_integer(const big_integer& b, const modular_params_t& m) { - modular_params_storage.set_modular_params(m); - modular_params_storage.modular_params().adjust_modular(m_base, b); + template + constexpr void assign_components( + modular_big_integer_impl, modular_ops_storage_t>& result, + const big_integer_t1& a, const big_integer_t2& b) { + BOOST_ASSERT_MSG(Bits == msb(b) + 1, + "modulus precision should match used big_integer_t"); + + result.set_modular_ops(b); + result.modular_ops().adjust_modular(result.base_data(), a); } + } // namespace detail + + template + struct modular_big_integer_ct + : public detail::modular_big_integer_impl< + std::decay_t, + detail::modular_ops_storage_ct, modulus>> { + using base_type = detail::modular_big_integer_impl< + std::decay_t, + detail::modular_ops_storage_ct, modulus>>; + + using typename base_type::big_integer_t; + + constexpr modular_big_integer_ct() : base_type({}) {} - // We may consider to remove this constructor later, and set Bits2 to Bits only, - // but we need it for use cases from h2f/h2c, - // where a larger number of 512 or 256 bits is passed to a field of 255 or 254 bits. template - constexpr explicit modular_big_integer(const big_integer& b) { - // This method must be called only for compile time modular params. - // modular_params_storage.set_modular_params(m); - modular_params_storage.modular_params().adjust_modular(m_base, b); + constexpr explicit modular_big_integer_ct(const big_integer& b) : base_type({}) { + this->modular_ops().adjust_modular(this->m_base, b); } - // This function sets default modulus value to zero to make sure it fails if not used with - // compile-time fixed modulus. - modular_big_integer& operator=(const char* s) { - using ui_type = typename std::tuple_element<0, unsigned_types>::type; - ui_type zero = 0u; - - if (s && (*s == '(')) { - std::string part; - const char* p = ++s; - while (*p && (*p != ',') && (*p != ')')) { - ++p; - } - part.assign(s, p); - if (!part.empty()) { - m_base = part.c_str(); - } else { - m_base = zero; - } - s = p; - if (*p && (*p != ')')) { - ++p; - while (*p && (*p != ')')) { - ++p; - } - part.assign(s + 1, p); - } else { - part.erase(); - } - if (!part.empty()) { - modular_params_storage.set_modular_params(part.c_str()); - } else { - modular_params_storage.set_modular_params(zero); - } + // A method for converting a signed integer to a modular adaptor. We are not supposed to + // have this, but in the code we already have conversion for an 'int' into modular type. In + // the future we must remove. + template && std::is_signed_v, int> = 0> + constexpr modular_big_integer_ct(SI b) : base_type({}) { + if (b >= 0) { + this->m_base = static_cast>(b); } else { - m_base = s; - modular_params_storage.set_modular_params(zero); + this->m_base = this->modular_ops().get_mod(); + // TODO(ioxid): should work not just with limb_type + this->m_base -= static_cast(-b); } - return *this; - } - constexpr bool compare_eq(const modular_big_integer& o) const { - return !(modular_params_storage.modular_params()) - .compare(o.modular_params_storage.modular_params()) && - !base_data().compare(o.base_data()); + // This method must be called only for compile time modular params. + // modular_ops_storage.set_modular_ops(m); + this->modular_ops().adjust_modular(this->m_base); } - template - constexpr int compare_eq(const T& val) const { - return !base_data().compare(val); + template && std::is_unsigned_v, int> = 0> + constexpr modular_big_integer_ct(UI b) : base_type({}) { + this->m_base = b; + this->modular_ops().adjust_modular(this->m_base); } + }; - constexpr modular_big_integer& operator=(const modular_big_integer& o) { - m_base = o.base_data(); - modular_params_storage.set_modular_params(o.modular_params_storage.modular_params()); + template + struct modular_big_integer_rt + : public detail::modular_big_integer_impl< + big_integer, detail::modular_ops_storage_rt>> { + using base_type = + detail::modular_big_integer_impl, + detail::modular_ops_storage_rt>>; - return *this; - } + using typename base_type::big_integer_t; - constexpr modular_big_integer& operator=(modular_big_integer&& o) noexcept { - m_base = o.base_data(); - modular_params_storage.set_modular_params(o.modular_params_storage.modular_params()); + template && std::is_signed_v, int> = 0> + constexpr modular_big_integer_rt(SI b, const big_integer_t& m): base_type(m) { + if (b >= 0) { + this->m_base = b; + } else { + this->m_base = this->modular_ops().get_mod(); + // TODO(ioxid): should work not just with limb_type + this->m_base -= static_cast(-b); + } - return *this; + this->modular_ops().adjust_modular(this->m_base); } - ~modular_big_integer() = default; - - // If we want to print a value, we must first convert it back to normal form. - inline std::string str(std::streamsize dig, std::ios_base::fmtflags f) const { - big_integer_t tmp; - modular_params_storage.modular_params().adjust_regular(tmp, m_base); - return tmp.str(dig, f); + template && std::is_unsigned_v, int> = 0> + constexpr modular_big_integer_rt(UI b, const big_integer_t& m) : base_type(m) { + this->m_base = b; + this->modular_ops().adjust_modular(this->m_base); } - inline constexpr void negate() { - if (m_base == m_zero) { - auto initial_m_base = m_base; - m_base = modular_params_storage.modular_params().get_mod(); - eval_subtract(m_base, initial_m_base); - } + // TODO(ioxid): move adjust modular to impl constructor + template + constexpr modular_big_integer_rt(const big_integer& b, const big_integer_t& m) + : base_type(m) { + this->modular_ops().adjust_modular(this->m_base, b); } - - protected: - big_integer_t m_base; - static constexpr big_integer_t m_zero = - static_cast::type>(0u); - ; }; - - template - constexpr void assign_components( - modular_big_integer, modular_params_storage_t>& result, - const big_integer_t1& a, const big_integer_t2& b) { - BOOST_ASSERT_MSG(Bits == eval_msb(b) + 1, - "modulus precision should match used big_integer_t"); - - result.set_modular_params(b); - result.modular_params().adjust_modular(result.base_data(), a); - } } // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_ops.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_ops.hpp index 4dbeb46187..04c373db1e 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_ops.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_ops.hpp @@ -14,19 +14,19 @@ #include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" #include "nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_impl.hpp" -#include "nil/crypto3/multiprecision/big_integer/modular/modular_ops.hpp" +#include "nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_ops_impl.hpp" namespace nil::crypto3::multiprecision { // Comparison // TODO(ioxid): comparison with big_integer and basic types (including signed) -#define CRYPTO3_MP_MODULAR_BIG_INTEGER_COMPARISON_IMPL(op) \ - template \ - inline constexpr bool operator op( \ - const modular_big_integer& a, \ - const modular_big_integer& b) noexcept { \ - return a.compare_eq(b) op true; \ +#define CRYPTO3_MP_MODULAR_BIG_INTEGER_COMPARISON_IMPL(op) \ + template \ + inline constexpr bool operator op( \ + const detail::modular_big_integer_impl& a, \ + const detail::modular_big_integer_impl& b) noexcept { \ + return a.compare_eq(b) op true; \ } CRYPTO3_MP_MODULAR_BIG_INTEGER_COMPARISON_IMPL(==) @@ -40,9 +40,11 @@ namespace nil::crypto3::multiprecision { template constexpr bool is_modular_big_integer_v = false; - template - constexpr bool - is_modular_big_integer_v> = true; + template + constexpr bool is_modular_big_integer_v> = true; + + template + constexpr bool is_modular_big_integer_v> = true; template constexpr bool is_integral_v = @@ -50,8 +52,7 @@ namespace nil::crypto3::multiprecision { } // namespace modular_detail namespace detail { - template, bool> = true> + template, int> = 0> constexpr std::size_t get_bits() { return T::Bits; } @@ -64,7 +65,7 @@ namespace nil::crypto3::multiprecision { std::enable_if_t && modular_detail::is_integral_v && \ (modular_detail::is_modular_big_integer_v || \ modular_detail::is_modular_big_integer_v), \ - bool> = true, \ + int> = 0, \ typename result_t = T1> #define CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE \ @@ -72,35 +73,39 @@ namespace nil::crypto3::multiprecision { std::enable_if_t && \ modular_detail::is_integral_v && \ detail::get_bits() <= modular_big_integer_t::Bits, \ - bool> = true> + int> = 0> #define CRYPTO3_MP_MODULAR_BIG_INTEGER_UNARY_TEMPLATE \ template, \ - bool> = true> + int> = 0> // Arithmetic operations CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator+(const T1& a, const T2& b) noexcept { - result_t tmp{a}; - // eval_add(tmp, b); - return tmp; + BOOST_ASSERT(a.modular_ops().compare_eq(b.modular_ops())); + result_t result{a}; + a.modular_ops().add(result.base_data(), b.base_data()); + return result; } CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator+=(modular_big_integer_t& a, const T& b) noexcept { - // eval_add(a, b); + BOOST_ASSERT(a.modular_ops().compare_eq(b.modular_ops())); + a.modular_ops().add(a.base_data(), b.base_data()); return a; } CRYPTO3_MP_MODULAR_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto& operator++(modular_big_integer_t& a) noexcept { - // eval_increment(a); + // TODO(ioxid): implement faster + a += static_cast(1u); return a; } CRYPTO3_MP_MODULAR_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto operator++(modular_big_integer_t& a, int) noexcept { auto copy = a; - // eval_increment(a); + // TODO(ioxid): implement faster + a += static_cast(1u); return copy; } CRYPTO3_MP_MODULAR_BIG_INTEGER_UNARY_TEMPLATE @@ -108,24 +113,26 @@ namespace nil::crypto3::multiprecision { CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator-(const T1& a, const T2& b) noexcept { - result_t tmp; - // eval_subtract(tmp, a, b); + result_t tmp{a}; + detail::subtract(tmp, b); return tmp; } CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator-=(modular_big_integer_t& a, const T& b) { - // eval_subtract(a, b); + detail::subtract(a, b); return a; } CRYPTO3_MP_MODULAR_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto& operator--(modular_big_integer_t& a) noexcept { - // eval_decrement(a); + // TODO(ioxid): implement faster + a -= static_cast(1u); return a; } CRYPTO3_MP_MODULAR_BIG_INTEGER_UNARY_TEMPLATE inline constexpr auto operator--(modular_big_integer_t& a, int) noexcept { auto copy = a; - // eval_decrement(a); + // TODO(ioxid): implement faster + a -= static_cast(1u); return copy; } @@ -138,64 +145,55 @@ namespace nil::crypto3::multiprecision { CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator*(const T1& a, const T2& b) noexcept { + BOOST_ASSERT(a.modular_ops().compare_eq(b.modular_ops())); result_t result{a}; - eval_multiply(result, b); + a.modular_ops().mul(result.base_data(), b.base_data()); return result; } CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator*=(modular_big_integer_t& a, const T& b) noexcept { - // eval_multiply(a, b); + BOOST_ASSERT(a.modular_ops().compare_eq(b.modular_ops())); + a.modular_ops().add(a.base_data(), b.base_data()); return a; } CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_TEMPLATE inline constexpr auto operator/(const T1& a, const T2& b) noexcept { result_t result; - // eval_divide(result, a, b); + eval_divide(result, a, b); return result; } CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE inline constexpr auto& operator/=(modular_big_integer_t& a, const T& b) noexcept { - // eval_divide(a, b); + eval_divide(a, b); return a; } + template + constexpr bool is_zero( + const detail::modular_big_integer_impl& val) noexcept { + return is_zero(val.base_data()); + } + + // Hash + + template + inline constexpr std::size_t hash_value( + const detail::modular_big_integer_impl& val) noexcept { + return hash_value(val.base_data()); + } + // IO - template + template std::ostream& operator<<( - std::ostream& os, const modular_big_integer, modular_params_t>& value) { - os << value.base_data(); + std::ostream& os, + const detail::modular_big_integer_impl, modular_ops_t>& value) { + os << value.str(); return os; } #undef CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_TEMPLATE #undef CRYPTO3_MP_MODULAR_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE #undef CRYPTO3_MP_MODULAR_BIG_INTEGER_UNARY_TEMPLATE -} // namespace nil::crypto3::multiprecision - -// TODO(ioxid): should use this optimization? -// // We need to specialize this function, because default boost implementation is "return -// a.compare(b) -// // == 0;", which is waay slower. -// template inline constexpr bool operator==( -// const number, modular_params_t>, -// ExpressionTemplates> &a, -// const number, modular_params_t>, -// ExpressionTemplates> &b) { -// return a.big_integer_t().compare_eq(b.big_integer_t()); -// } -// -// // We need to specialize this function, because default boost implementation is "return -// a.compare(b) -// // == 0;", which is waay slower. -// template inline constexpr bool operator!=( -// const number, modular_params_t>, -// ExpressionTemplates> &a, -// const number, modular_params_t>, -// ExpressionTemplates> &b) { -// return !a.big_integer_t().compare_eq(b.big_integer_t()); -// } -// } +} // namespace nil::crypto3::multiprecision \ No newline at end of file diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_ops_impl.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_ops_impl.hpp new file mode 100644 index 0000000000..1ecb45f6cb --- /dev/null +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_ops_impl.hpp @@ -0,0 +1,203 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2020 Mikhail Komarov +// Copyright (c) 2019-2021 Aleksei Moskvin +// Copyright (c) 2020 Ilias Khairullin +// Copyright (c) 2024 Andrey Nefedov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" +#include "nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_impl.hpp" +#include "nil/crypto3/multiprecision/big_integer/modular/modular_ops.hpp" + +namespace nil::crypto3::multiprecision::detail { + template + constexpr void subtract(modular_big_integer_impl, modular_ops_t> &result, + const modular_big_integer_impl, modular_ops_t> &o) { + if (result.base_data() < o.base_data()) { + auto v = result.modular_ops().get_mod(); + v -= o.base_data(); + result.base_data() += v; + } else { + result.base_data() -= o.base_data(); + } + } + + // template + // constexpr void eval_powm(modular_big_integer_impl, modular_ops_t> &result, + // const modular_big_integer_impl &b, + // const T &e) { + // result.set_modular_ops(b.modular_ops()); + // result.modular_ops().exp(result.base_data(), b.base_data(), e); + // } + + // template + // constexpr void eval_powm(modular_big_integer_impl, modular_ops_t> &result, + // const modular_big_integer_impl &b, + // const modular_big_integer_impl &e) { + // using big_integer_t = big_integer; + + // big_integer_t exp; + // e.modular_ops().adjust_regular(exp, e.base_data()); + // eval_powm(result, b, exp); + // } + + // template + // constexpr void eval_inverse_mod( + // modular_big_integer_impl, modular_ops_t> &result, + // const modular_big_integer_impl, modular_ops_t> &input) { + // using big_integer_t = big_integer; + // using big_integer_t_padded_limbs = + // typename modular_ops::policy_type::big_integer_padded_limbs; + + // big_integer_t_padded_limbs new_base, res, tmp = input.modular_ops().get_mod(); + + // input.modular_ops().adjust_regular(new_base, input.base_data()); + // eval_inverse_mod(res, new_base, tmp); + // assign_components(result, res, input.modular_ops().get_mod()); + // } + + // template + // constexpr void eval_redc(big_integer_t1 &result, const modular_ops &mod) { + // mod.reduce(result); + // eval_modulus(result, mod.get_mod()); + // } + + // template + // constexpr void eval_multiply(modular_big_integer_impl &result, + // const modular_big_integer_impl &o) + // { + // eval_multiply(result.base_data(), o.base_data()); + // eval_redc(result.base_data(), result.modular_ops()); + // } + + // template + // constexpr void eval_divide(modular_big_integer_impl &result, + // const modular_big_integer_impl &o) { + // big_integer_t tmp1, tmp2; + // result.modular_ops().adjust_regular(tmp1, result.base_data()); + // result.modular_ops().adjust_regular(tmp2, o.base_data()); + // eval_divide(tmp1, tmp2); + // result.base_data() = tmp1; + // result.modular_ops().adjust_modular(result.base_data()); + // result.modular_ops().adjust_regular(tmp2, result.base_data()); + // } + + // template + // constexpr void eval_sqrt(modular_big_integer_impl &result, + // const modular_big_integer_impl &val) { + // eval_sqrt(result.base_data(), val.base_data()); + // } + + // inline size_t window_bits(size_t exp_bits) { + // constexpr static size_t wsize_count = 6; + // constexpr static size_t wsize[wsize_count][2] = {{1434, 7}, {539, 6}, {197, 4}, + // {70, 3}, {17, 2}, {0, 0}}; + + // size_t window_bits = 1; + + // size_t j = wsize_count - 1; + // while (wsize[j][0] > exp_bits) { + // --j; + // } + // window_bits += wsize[j][1]; + + // return window_bits; + // } + + // template + // inline void find_modular_pow(modular_big_integer_impl &result, + // const modular_big_integer_impl &b, + // const big_integer_t &exp) { + // modular_ops mod = b.modular_ops(); + // size_t m_window_bits; + // unsigned long cur_exp_index; + // size_t exp_bits = eval_msb(exp); + // m_window_bits = window_bits(exp_bits + 1); + + // std::vector m_g(1U << m_window_bits); + // big_integer_t *p_g = m_g.data(); + // big_integer_t x(1, mod); + // big_integer_t nibble = exp; + // big_integer_t mask; + // eval_bit_set(mask, m_window_bits); + // eval_decrement(mask); + // *p_g = x; + // ++p_g; + // *p_g = b; + // ++p_g; + // for (size_t i = 2; i < (1U << m_window_bits); i++) { + // eval_multiply(*p_g, m_g[i - 1], b); + // ++p_g; + // } + // size_t exp_nibbles = (exp_bits + 1 + m_window_bits - 1) / m_window_bits; + // std::vector exp_index; + + // for (size_t i = 0; i < exp_nibbles; ++i) { + // big_integer_t tmp = nibble; + // eval_bitwise_and(tmp, mask); + // eval_convert_to(&cur_exp_index, tmp); + // eval_right_shift(nibble, m_window_bits); + // exp_index.push_back(cur_exp_index); + // } + + // eval_multiply(x, m_g[exp_index[exp_nibbles - 1]]); + // for (size_t i = exp_nibbles - 1; i > 0; --i) { + // for (size_t j = 0; j != m_window_bits; ++j) { + // eval_multiply(x, x); + // } + + // eval_multiply(x, m_g[exp_index[i - 1]]); + // } + // result = x; + // } + + // template + // constexpr void eval_pow(modular_big_integer_impl &result, + // const modular_big_integer_impl &b, + // const T &e) { + // find_modular_pow(result, b, e); + // } + + // template + // constexpr void eval_pow(modular_big_integer_impl &result, + // const modular_big_integer_impl &b, + // const modular_big_integer_impl &e) { + // big_integer_t exp; + // e.modular_ops().adjust_regular(exp, e.base_data()); + // find_modular_pow(result, b, exp); + // } + + // template constexpr void eval_powm(modular_big_integer_impl &result, + // const modular_big_integer_impl &b, + // const T &e) { + // eval_pow(result, b, e); + // } + + // template + // constexpr void eval_powm(modular_big_integer_impl &result, + // const modular_big_integer_impl &b, + // const modular_big_integer_impl &e) { + // eval_pow(result, b, e); + // } +} // namespace nil::crypto3::multiprecision::detail diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_functions.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_functions.hpp index 33c8aa9376..55fd216f5c 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_functions.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_functions.hpp @@ -16,42 +16,39 @@ #include #include -#include #include #include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" -#include "nil/crypto3/multiprecision/big_integer/modular/modular_policy.hpp" #include "nil/crypto3/multiprecision/big_integer/storage.hpp" -namespace nil::crypto3::multiprecision { +namespace nil::crypto3::multiprecision::detail { template constexpr bool check_montgomery_constraints(const big_integer_t &m) { // Check m % 2 == 0 - // It's important to have std::size_t on the next line, - // otherwise a function from boost is called, which is not constexpr - // on gcc. - return eval_bit_test(m, std::size_t(0)); + return bit_test(m, 0u); } - // TODO(ioxid): rewrite it - // - // a little trick to prevent error in constexpr execution of - // eval_right_shift due to non-constexpr nature of right_shift_byte - // - template - constexpr void custom_right_shift(big_integer_t &b, unsigned s) { - if (!s) { - return; - } - - limb_type byte_shift_mask = CHAR_BIT - 1; - if ((s & byte_shift_mask) == 0) { - eval_right_shift(b, s - 1u); - eval_right_shift(b, 1u); - } else { - eval_right_shift(b, s); - } - } + template + struct modular_policy { + using big_integer_t = big_integer; + + constexpr static auto limbs_count = big_integer_t::internal_limb_count; + constexpr static auto limb_bits = big_integer_t::limb_bits; + + constexpr static auto BitsCount_doubled = 2u * Bits; + constexpr static auto BitsCount_doubled_1 = BitsCount_doubled + 1; + constexpr static auto BitsCount_quadruple_1 = 2u * BitsCount_doubled + 1; + constexpr static auto BitsCount_padded_limbs = limbs_count * limb_bits + limb_bits; + constexpr static auto BitsCount_doubled_limbs = 2u * limbs_count * limb_bits; + constexpr static auto BitsCount_doubled_padded_limbs = BitsCount_doubled_limbs + limb_bits; + + using big_integer_doubled = big_integer; + using big_integer_doubled_1 = big_integer; + using big_integer_quadruple_1 = big_integer; + using big_integer_padded_limbs = big_integer; + using big_integer_doubled_limbs = big_integer; + using big_integer_doubled_padded_limbs = big_integer; + }; template class modular_functions { @@ -60,14 +57,11 @@ namespace nil::crypto3::multiprecision { using policy_type = modular_policy; protected: - using limb_type = typename policy_type::limb_type; - using double_limb_type = typename policy_type::double_limb_type; - - using Backend_doubled_1 = typename policy_type::Backend_doubled_1; - using Backend_quadruple_1 = typename policy_type::Backend_quadruple_1; - using Backend_padded_limbs = typename policy_type::Backend_padded_limbs; - using Backend_doubled_limbs = typename policy_type::Backend_doubled_limbs; - using Backend_doubled_padded_limbs = typename policy_type::Backend_doubled_padded_limbs; + using big_integer_doubled_1 = typename policy_type::big_integer_doubled_1; + using big_integer_quadruple_1 = typename policy_type::big_integer_quadruple_1; + using big_integer_padded_limbs = typename policy_type::big_integer_padded_limbs; + using big_integer_doubled_limbs = typename policy_type::big_integer_doubled_limbs; + using big_integer_doubled_padded_limbs = typename policy_type::big_integer_doubled_padded_limbs; constexpr static auto limbs_count = policy_type::limbs_count; constexpr static auto limb_bits = policy_type::limb_bits; @@ -75,17 +69,17 @@ namespace nil::crypto3::multiprecision { constexpr void initialize_modulus(const big_integer_t &m) { m_mod = m; } constexpr void initialize_barrett_params() { - m_barrett_mu = static_cast(0u); + m_barrett_mu = 0u; - size_t bit = 2u * (1u + eval_msb(m_mod)); - eval_bit_set(m_barrett_mu, bit); + std::size_t bit = 2u * (1u + msb(m_mod)); + bit_set(m_barrett_mu, bit); - // TODO(ioxid): not constexpr - // m_barrett_mu /= m_mod; + m_barrett_mu /= m_mod; } constexpr void initialize_montgomery_params() { find_const_variables(); } + // TODO(ioxid): no exception actually /* * Compute -input^-1 mod 2^limb_bits. Throws an exception if input * is even. If input is odd, then input and 2^n are relatively prime @@ -105,7 +99,7 @@ namespace nil::crypto3::multiprecision { } // Now invert in addition space - r = (~static_cast(0) - r) + 1; + r = (~0u - r) + 1; return r; } @@ -114,8 +108,8 @@ namespace nil::crypto3::multiprecision { if (check_montgomery_constraints(m_mod)) { m_montgomery_p_dash = monty_inverse(m_mod.limbs()[0]); - Backend_doubled_padded_limbs r; - eval_bit_set(r, 2 * m_mod.size() * limb_bits); + big_integer_doubled_padded_limbs r; + bit_set(r, 2 * m_mod.size() * limb_bits); barrett_reduce(r); // Here we are intentionally throwing away half of the bits of r, it's @@ -124,9 +118,9 @@ namespace nil::crypto3::multiprecision { } // Compute 2^Bits - Modulus, no matter if modulus is even or odd. - Backend_padded_limbs compliment = static_cast(1u), modulus = m_mod; - eval_left_shift(compliment, Bits); - eval_subtract(compliment, modulus); + big_integer_padded_limbs compliment = 1u, modulus = m_mod; + compliment <<= Bits; + compliment -= modulus; m_mod_compliment = compliment; } @@ -150,90 +144,80 @@ namespace nil::crypto3::multiprecision { constexpr const auto &get_r2() const { return m_montgomery_r2; } constexpr auto get_p_dash() const { return m_montgomery_p_dash; } - constexpr modular_functions() {} - constexpr modular_functions(const big_integer_t &m) { initialize(m); } - constexpr modular_functions(const modular_functions &o) - : m_mod(o.get_mod()), - m_mod_compliment(o.get_mod_compliment()), - m_barrett_mu(o.get_mu()), - m_montgomery_r2(o.get_r2()), - m_montgomery_p_dash(o.get_p_dash()), - m_no_carry_montgomery_mul_allowed(is_applicable_for_no_carry_montgomery_mul()) {} - - template - constexpr void barrett_reduce(Backend1 &result) const { + template + constexpr void barrett_reduce(big_integer_t1 &result) const { barrett_reduce(result, result); } + // TODO(ioxid): something wrong with parameters here // // this overloaded barrett_reduce is intended to work with built-in integral types // - template - constexpr typename std::enable_if::value && - std::is_unsigned::value>::type - barrett_reduce(Backend1 &result, Backend2 input) const { - using input_backend_type = - typename std::conditional_t Bits), Backend2, big_integer_t>; - - input_backend_type input_adjusted(input); + template + constexpr typename std::enable_if::value && + std::is_unsigned::value>::type + barrett_reduce(big_integer_t1 &result, big_integer_t2 input) const { + using input_big_integer_type = + typename std::conditional_t Bits), big_integer_t2, big_integer_t>; + + input_big_integer_type input_adjusted(input); barrett_reduce(result, input_adjusted); } // - // this overloaded barrett_reduce is intended to work with input Backend2 type of + // this overloaded barrett_reduce is intended to work with input big_integer_t2 type of // less precision than modular big_integer_t to satisfy constraints of core barrett_reduce // overloading // - template = true> - constexpr void barrett_reduce(Backend1 &result, const Backend2 &input) const { + template = 0> + constexpr void barrett_reduce(big_integer_t1 &result, const big_integer_t2 &input) const { big_integer_t input_adjusted(input); barrett_reduce(result, input_adjusted); } - template= big_integer_t::Bits && + big_integer_t1::Bits >= big_integer_t::Bits && /// to prevent problems with trivial cpp_int - Backend2::Bits >= big_integer_t::Bits, - bool> = true> - constexpr void barrett_reduce(Backend1 &result, Backend2 input) const { + big_integer_t2::Bits >= big_integer_t::Bits, + int> = 0> + constexpr void barrett_reduce(big_integer_t1 &result, big_integer_t2 input) const { // // to prevent problems with trivial cpp_int // - Backend2 modulus(m_mod); + big_integer_t2 modulus(m_mod); - if (eval_msb(input) < 2u * eval_msb(modulus) + 1u) { - Backend_quadruple_1 t1(input); + if (msb(input) < 2u * msb(modulus) + 1u) { + big_integer_quadruple_1 t1(input); - eval_multiply(t1, m_barrett_mu); - std::size_t shift_size = 2u * (1u + eval_msb(modulus)); - custom_right_shift(t1, shift_size); - eval_multiply(t1, modulus); + t1 *= m_barrett_mu; + std::size_t shift_size = 2u * (1u + msb(modulus)); + t1 >>= shift_size; + t1 *= modulus; // We do NOT allow subtracting a larger size number from a smaller one, - // we need to cast to Backend2 here. - eval_subtract(input, static_cast(t1)); + // we need to cast to big_integer_t2 here. + input -= static_cast(t1); if (input >= modulus) { - eval_subtract(input, modulus); + input -= modulus; } } else { - // TODO(ioxid): not constexpr - // eval_modulus(input, modulus); + input %= modulus; } result = input; } template= Bits>::type> + std::enable_if_t= Bits, int> = 0> constexpr void montgomery_reduce(big_integer &result) const { - Backend_doubled_padded_limbs accum(result); - Backend_doubled_padded_limbs prod; + big_integer_doubled_padded_limbs accum(result); + big_integer_doubled_padded_limbs prod; for (size_t i = 0; i < m_mod.size(); ++i) { limb_type limb_accum = accum.limbs()[i]; @@ -242,16 +226,18 @@ namespace nil::crypto3::multiprecision { static_cast(m_montgomery_p_dash); limb_type mult_res_limb = static_cast(mult_res); - eval_multiply(prod, m_mod, mult_res_limb); - eval_left_shift(prod, i * limb_bits); - eval_add(accum, prod); + prod = m_mod; + prod *= mult_res_limb; + prod <<= i * limb_bits; + accum += prod; } - custom_right_shift(accum, m_mod.size() * limb_bits); - // We cannot use eval_subtract for numbers of difference sizes, so resizing + accum >>= m_mod.size() * limb_bits; + // TODO(ioxid): true? + // We cannot use -= for numbers of difference sizes, so resizing // m_mod. - Backend_doubled_padded_limbs large_mod = m_mod; + big_integer_doubled_padded_limbs large_mod = m_mod; if (accum >= large_mod) { - eval_subtract(accum, large_mod); + accum -= large_mod; } // Here only the bytes that fit in sizeof result will be copied, and that's // intentional. @@ -260,30 +246,29 @@ namespace nil::crypto3::multiprecision { template= Bits2>::type> + std::enable_if_t= Bits2, int> = 0> constexpr void regular_add(big_integer &result, const big_integer &y) const { - BOOST_ASSERT(eval_lt(result, m_mod) && eval_lt(y, m_mod)); + BOOST_ASSERT(result < m_mod && y < m_mod); - eval_add(result, y); + result += y; // If we overflow and set the carry, we need to subtract the modulus, which is // the same as adding 2 ^ Bits - Modulus to the remaining part of the number. // After this we know for sure that the result < Modulus, do not waste time on // checking again. if (result.has_carry()) { - eval_add(result, m_mod_compliment); + result += m_mod_compliment; result.set_carry(false); - } else if (!eval_lt(result, m_mod)) { - eval_subtract(result, m_mod); + } else if (result >= m_mod) { + result -= m_mod; } } - template< - typename Backend1, typename Backend2, - /// result should fit in the output parameter - typename = typename boost::enable_if_c= big_integer_t::Bits>::type> - constexpr void regular_mul(Backend1 &result, const Backend2 &y) const { - Backend_doubled_limbs tmp(result); - eval_multiply(tmp, y); + template= big_integer_t::Bits, int> = 0> + constexpr void regular_mul(big_integer_t1 &result, const big_integer_t2 &y) const { + big_integer_doubled_limbs tmp = result; + tmp *= y; barrett_reduce(result, tmp); } @@ -296,19 +281,7 @@ namespace nil::crypto3::multiprecision { } } - // Given a value represented in 'double_limb_type', decomposes it into - // two 'limb_type' variables, based on high order bits and low order bits. - // There 'a' receives high order bits of 'X', and 'b' receives the low order bits. - static constexpr void dbl_limb_to_limbs(const double_limb_type &X, limb_type &a, - limb_type &b) { - b = X; - a = X >> limb_bits; - } - // Tests if the faster implementation of Montgomery multiplication is possible. - // We don't need the template argument Backend1, it's just here to enable - // specialization. - template constexpr bool is_applicable_for_no_carry_montgomery_mul() const { // Check that // 1. The most significant bit of modulus is non-zero, meaning we have at least @@ -323,20 +296,20 @@ namespace nil::crypto3::multiprecision { // Non-carry implementation of Montgomery multiplication. // Implemented from pseudo-code at // "https://hackmd.io/@gnark/modular_multiplication". - template - constexpr void montgomery_mul_no_carry_impl(Backend1 &c, const Backend1 &b) const { + template + constexpr void montgomery_mul_no_carry_impl(big_integer_t1 &c, const big_integer_t1 &b) const { BOOST_ASSERT(c < m_mod && b < m_mod); BOOST_ASSERT(is_applicable_for_no_carry_montgomery_mul()); // Obtain number of limbs - constexpr int N = Backend1::internal_limb_count; + constexpr int N = big_integer_t1::internal_limb_count; - const Backend1 a(c); // Copy the first argument, as the implemented + const big_integer_t1 a(c); // Copy the first argument, as the implemented // algorithm doesn't work in-place. // We cannot write directly to 'c', because b may be equal to c, and by changing // the value of 'c' we will change 'b' as well. - Backend1 result = limb_type(0u); + big_integer_t1 result = limb_type(0u); // Prepare temporary variables limb_type A(0u), C(0u); @@ -353,7 +326,7 @@ namespace nil::crypto3::multiprecision { tmp = a_limbs[0]; tmp *= b_limbs[i]; tmp += result_limbs[0]; - modular_functions::dbl_limb_to_limbs(tmp, A, result_limbs[0]); + dbl_limb_to_limbs(tmp, A, result_limbs[0]); // "m := t[0]*q'[0] mod W" tmp = result_limbs[0]; @@ -367,7 +340,7 @@ namespace nil::crypto3::multiprecision { tmp = m; tmp *= m_mod_limbs[0]; tmp += result_limbs[0]; - modular_functions::dbl_limb_to_limbs(tmp, C, dummy); + dbl_limb_to_limbs(tmp, C, dummy); // The lower loop is unrolled. We want to do this for every 3, because // normally mod_size == 4. @@ -379,14 +352,14 @@ namespace nil::crypto3::multiprecision { tmp *= b_limbs[i]; \ tmp += result_limbs[X]; \ tmp += A; \ - modular_functions::dbl_limb_to_limbs(tmp, A, result_limbs[X]); \ + dbl_limb_to_limbs(tmp, A, result_limbs[X]); \ \ /* "(C,t[X-1]) := t[X] + m*q[X] + C" */ \ tmp = m; \ tmp *= m_mod_limbs[X]; \ tmp += result_limbs[X]; \ tmp += C; \ - modular_functions::dbl_limb_to_limbs(tmp, C, result_limbs[X - 1]); + dbl_limb_to_limbs(tmp, C, result_limbs[(X) - 1]); for (; j + 5 <= N; j += 5) { MONTGOMERY_MUL_NO_CARRY_LOOP_BODY(j); @@ -411,14 +384,14 @@ namespace nil::crypto3::multiprecision { } if (result >= m_mod) { - eval_subtract(result, m_mod); + result -= m_mod; } c = result; } // A specialization for non-trivial cpp_int_modular types only. - template - constexpr void montgomery_mul_CIOS_impl(Backend1 &result, const Backend1 &y) const { + template + constexpr void montgomery_mul_CIOS_impl(big_integer_t1 &result, const big_integer_t1 &y) const { BOOST_ASSERT(result < m_mod && y < m_mod); big_integer_t A(limb_type(0u)); @@ -470,7 +443,7 @@ namespace nil::crypto3::multiprecision { A_limbs[X] + k; \ t2 = static_cast(mod_limbs[X]) * static_cast(u_i) + \ static_cast(t) + k2; \ - A_limbs[X - 1] = static_cast(t2); \ + A_limbs[(X) - 1] = static_cast(t2); \ k = static_cast(t >> std::numeric_limits::digits); \ k2 = static_cast(t2 >> std::numeric_limits::digits); @@ -499,84 +472,82 @@ namespace nil::crypto3::multiprecision { if (carry) { // The value of A is actually A + 2 ^ Bits, so remove that 2 ^ Bits. - eval_add(A, m_mod_compliment); + A += m_mod_compliment; } else if (A >= m_mod) { - eval_subtract(A, m_mod); + A -= m_mod; } result = A; } - template< - typename Backend1, typename Backend2, typename Backend3, - /// result should fit in the output parameter - typename = typename boost::enable_if_c= big_integer_t::Bits>::type> - constexpr void regular_exp(Backend1 &result, Backend2 &a, Backend3 exp) const { - BOOST_ASSERT(eval_lt(a, m_mod)); + template= big_integer_t::Bits, int> = 0> + constexpr void regular_exp(big_integer_t1 &result, big_integer_t2 &a, big_integer_t3 exp) const { + BOOST_ASSERT(a < m_mod); - if (eval_eq(exp, static_cast(0u))) { - result = static_cast(1u); + if (exp == 0u) { + result = 1u; return; } - if (eval_eq(m_mod, static_cast(1u))) { - result = static_cast(0u); + if (m_mod == 1u) { + result = 0u; return; } - Backend_doubled_limbs base(a), res(static_cast(1u)); + big_integer_doubled_limbs base(a), res(1u); while (true) { limb_type lsb = exp.limbs()[0] & 1u; - custom_right_shift(exp, static_cast(1u)); + exp >>= 1u; if (lsb) { - eval_multiply(res, base); + res *= base; barrett_reduce(res); - if (eval_is_zero(exp)) { + if (is_zero(exp)) { break; } } - eval_multiply(base, base); + base *= base; barrett_reduce(base); } result = res; } - template< - typename Backend1, typename Backend2, typename Backend3, - /// result should fit in the output parameter - typename = typename boost::enable_if_c= big_integer_t::Bits>::type> - constexpr void montgomery_exp(Backend1 &result, const Backend2 &a, Backend3 exp) const { + template= big_integer_t::Bits, int> = 0> + constexpr void montgomery_exp(big_integer_t1 &result, const big_integer_t2 &a, big_integer_t3 exp) const { /// input parameter should be lesser than modulus - BOOST_ASSERT(eval_lt(a, m_mod)); + BOOST_ASSERT(a < m_mod); - Backend_doubled_limbs tmp(static_cast(1u)); - eval_multiply(tmp, m_montgomery_r2); + big_integer_doubled_limbs tmp(1u); + tmp *= m_montgomery_r2; montgomery_reduce(tmp); big_integer_t R_mod_m(tmp); big_integer_t base(a); - if (eval_eq(exp, static_cast(0u))) { - result = static_cast(1u); + if (exp == 0u) { + result = 1u; // // TODO: restructure code // adjust_modular // - eval_multiply(result, m_montgomery_r2); + result *= m_montgomery_r2; montgomery_reduce(result); return; } - if (eval_eq(m_mod, static_cast(1u))) { - result = static_cast(0u); + if (m_mod == 1u) { + result = 0u; return; } while (true) { limb_type lsb = exp.limbs()[0] & 1u; - custom_right_shift(exp, static_cast(1u)); + exp >>= 1u; if (lsb) { montgomery_mul(R_mod_m, base); - if (eval_eq(exp, static_cast(0u))) { + if (exp == 0u) { break; } } @@ -585,17 +556,6 @@ namespace nil::crypto3::multiprecision { result = R_mod_m; } - constexpr modular_functions &operator=(const modular_functions &o) { - m_mod = o.get_mod(); - m_barrett_mu = o.get_mu(); - m_montgomery_r2 = o.get_r2(); - m_montgomery_p_dash = o.get_p_dash(); - m_mod_compliment = o.get_mod_compliment(); - m_no_carry_montgomery_mul_allowed = is_applicable_for_no_carry_montgomery_mul(); - - return *this; - } - constexpr modular_functions &operator=(const big_integer_t &m) { initialize(m); @@ -606,7 +566,7 @@ namespace nil::crypto3::multiprecision { big_integer_t m_mod; // This is 2^Bits - m_mod, precomputed. big_integer_t m_mod_compliment; - Backend_doubled_1 m_barrett_mu; + big_integer_doubled_1 m_barrett_mu; big_integer_t m_montgomery_r2; limb_type m_montgomery_p_dash = 0; diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_ops.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_ops.hpp index 6bca814546..107914b32d 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_ops.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_ops.hpp @@ -1,7 +1,7 @@ //---------------------------------------------------------------------------// // Copyright (c) 2020 Mikhail Komarov -// Copyright (c) 2019-2021 Aleksei Moskvin // Copyright (c) 2020 Ilias Khairullin +// Copyright (c) 2021 Aleksei Moskvin // Copyright (c) 2024 Andrey Nefedov // // Distributed under the Boost Software License, Version 1.0 @@ -11,472 +11,163 @@ #pragma once -#include -#include -#include -#include -#include +#include -#include -#include -#include -#include +#include #include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" -#include "nil/crypto3/multiprecision/big_integer/modular/modular_big_integer_impl.hpp" -#include "nil/crypto3/multiprecision/big_integer/modular/modular_params.hpp" - -namespace nil::crypto3::multiprecision { - - template - constexpr void eval_add(modular_big_integer, modular_params_t> &result, - const modular_big_integer, modular_params_t> &o) { - BOOST_ASSERT(eval_eq(result.mod_data().get_mod(), o.mod_data().get_mod())); - result.mod_data().mod_add(result.base_data(), o.base_data()); - } - - template - constexpr void eval_add(modular_big_integer, modular_params_t> &result, - const modular_big_integer &o) { - result.mod_data().mod_add(result.base_data(), o.base_data()); - } - - template - constexpr void eval_add(modular_big_integer &result, - const modular_big_integer, modular_params_t> &o) { - o.mod_data().mod_add(result.base_data(), o.base_data()); - } - - template - constexpr void eval_multiply( - modular_big_integer, modular_params_t> &result, - const modular_big_integer, modular_params_t> &o) { - result.mod_data().mod_mul(result.base_data(), o.base_data()); - } - - template - constexpr void eval_multiply(modular_big_integer, modular_params_t> &result, - const modular_big_integer &o) { - result.mod_data().mod_mul(result.base_data(), o.base_data()); - } - - template - constexpr void eval_multiply( - modular_big_integer &result, - const modular_big_integer, modular_params_t> &o) { - o.mod_data().mod_mul(result.base_data(), o.base_data()); - } - - template - constexpr void eval_powm(modular_big_integer, modular_params_t> &result, - const modular_big_integer &b, - const T &e) { - result.set_modular_params(b.mod_data()); - result.mod_data().mod_exp(result.base_data(), b.base_data(), e); - } - - template - constexpr void eval_powm(modular_big_integer, modular_params_t> &result, - const modular_big_integer &b, - const modular_big_integer &e) { - using big_integer_t = big_integer; - - big_integer_t exp; - e.mod_data().adjust_regular(exp, e.base_data()); - eval_powm(result, b, exp); - } - - template - constexpr void eval_inverse_mod( - modular_big_integer, modular_params_t> &result, - const modular_big_integer, modular_params_t> &input) { - using big_integer_t = big_integer; - using big_integer_t_padded_limbs = - typename modular_params::policy_type::Backend_padded_limbs; - - big_integer_t_padded_limbs new_base, res, tmp = input.mod_data().get_mod(); - - input.mod_data().adjust_regular(new_base, input.base_data()); - eval_inverse_mod(res, new_base, tmp); - assign_components(result, res, input.mod_data().get_mod()); - } - - // Used for converting number> to number. - // We cannot change the first argument to a reference... - template - constexpr void eval_convert_to( - big_integer_t *result, const modular_big_integer &val) { - val.mod_data().adjust_regular(*result, val.base_data()); - } - - template - constexpr typename boost::enable_if, bool>::type eval_eq( - const modular_big_integer &a, const T &b) { - return a.compare(b) == 0; - } - - template - constexpr void eval_redc(big_integer_t1 &result, const modular_params &mod) { - mod.reduce(result); - eval_modulus(result, mod.get_mod()); - } - - template - constexpr void eval_add(modular_big_integer &result, - const modular_big_integer &o) { - eval_add(result.base_data(), o.base_data()); - if (!eval_lt(result.base_data(), result.mod_data().get_mod())) { - eval_subtract(result.base_data(), result.mod_data().get_mod()); +#include "nil/crypto3/multiprecision/big_integer/modular/modular_functions.hpp" + +namespace nil::crypto3::multiprecision::detail { + // TODO(ioxid): merge with modular_functions + // fixed precision modular params type which supports compile-time execution + template + class modular_ops { + private: + using modular_functions_t = modular_functions; + + public: + using policy_type = typename modular_functions_t::policy_type; + + using big_integer_doubled_limbs = typename policy_type::big_integer_doubled_limbs; + // using big_integer_t = typename policy_type::big_integer_t; + + constexpr modular_ops(const big_integer_t &m) + : m_modular_functions(m), m_use_montgomery_form(check_montgomery_constraints(m)) {} + + private: + constexpr auto &get_modular_functions() { return m_modular_functions; } + constexpr const auto &get_modular_functions() const { return m_modular_functions; } + + constexpr bool is_montgomery_form() const { return m_use_montgomery_form; } + + public: + constexpr const auto &get_mod() const { return m_modular_functions.get_mod(); } + + template + constexpr void reduce(big_integer &result) const { + if (m_use_montgomery_form) { + m_modular_functions.montgomery_reduce(result); + } else { + m_modular_functions.barrett_reduce(result); + } } - } - - template - constexpr void eval_subtract(modular_big_integer &result, - const modular_big_integer &o) { - using ui_type = - typename std::tuple_element<0, typename big_integer_t::unsigned_types>::type; - eval_subtract(result.base_data(), o.base_data()); - if (eval_lt(result.base_data(), ui_type(0u))) { - eval_add(result.base_data(), result.mod_data().get_mod()); + + constexpr void adjust_modular(big_integer_t &result) const { + adjust_modular(result, result); } - } - - template - constexpr void eval_subtract( - modular_big_integer, modular_params_t> &result, - const modular_big_integer, modular_params_t> &o) { - if (eval_lt(result.base_data(), o.base_data())) { - auto v = result.mod_data().get_mod(); - eval_subtract(v, o.base_data()); - eval_add(result.base_data(), v); - } else { - eval_subtract(result.base_data(), o.base_data()); + + template + constexpr void adjust_modular(big_integer_t &result, + const big_integer &input) const { + big_integer_doubled_limbs tmp; + m_modular_functions.barrett_reduce(tmp, input); + if (m_use_montgomery_form) { + // + // to prevent problems with trivial cpp_int + // + big_integer_doubled_limbs r2(m_modular_functions.get_r2()); + + tmp *= r2; + m_modular_functions.montgomery_reduce(tmp); + } + result = tmp; } - } - - template - constexpr void eval_multiply(modular_big_integer &result, - const modular_big_integer &o) { - eval_multiply(result.base_data(), o.base_data()); - eval_redc(result.base_data(), result.mod_data()); - } - - template - constexpr void eval_divide(modular_big_integer &result, - const modular_big_integer &o) { - big_integer_t tmp1, tmp2; - result.mod_data().adjust_regular(tmp1, result.base_data()); - result.mod_data().adjust_regular(tmp2, o.base_data()); - eval_divide(tmp1, tmp2); - result.base_data() = tmp1; - result.mod_data().adjust_modular(result.base_data()); - result.mod_data().adjust_regular(tmp2, result.base_data()); - } - - template - constexpr void eval_modulus(modular_big_integer &result, - const modular_big_integer &o) { - big_integer_t tmp1, tmp2; - result.mod_data().adjust_regular(tmp1, result.base_data()); - result.mod_data().adjust_regular(tmp2, o.base_data()); - eval_modulus(tmp1, tmp2); - result.base_data() = tmp1; - result.mod_data().adjust_modular(result.base_data()); - // result.mod_data().adjust_regular(tmp2, result.base_data()); - } - - // If called with 3 arguments, delegate the call to the upper function. - template - constexpr void eval_modulus(modular_big_integer &result, - const modular_big_integer &u, - const modular_big_integer &v) { - result = std::move(u); - eval_modulus(result, v); - } - - template - constexpr bool eval_is_zero( - const modular_big_integer &val) noexcept { - return eval_is_zero(val.base_data()); - } - - template - constexpr int eval_get_sign( - const modular_big_integer & /*unused*/) { - return 1; - } - - template - constexpr void assign_components(modular_big_integer &result, - const T &a, const V &b) { - result.base_data() = a; - result.mod_data() = b; - result.mod_data().adjust_modular(result.base_data()); - } - - template - constexpr void eval_sqrt(modular_big_integer &result, - const modular_big_integer &val) { - eval_sqrt(result.base_data(), val.base_data()); - } - - template - constexpr void eval_abs(modular_big_integer &result, - const modular_big_integer &val) { - result = val; - } - - inline size_t window_bits(size_t exp_bits) { - constexpr static size_t wsize_count = 6; - constexpr static size_t wsize[wsize_count][2] = {{1434, 7}, {539, 6}, {197, 4}, - {70, 3}, {17, 2}, {0, 0}}; - - size_t window_bits = 1; - - size_t j = wsize_count - 1; - while (wsize[j][0] > exp_bits) { - --j; + + [[nodiscard]] constexpr big_integer_t adjusted_regular(const big_integer_t &a) const { + big_integer_t result; + adjust_regular(result, a); + return result; } - window_bits += wsize[j][1]; - - return window_bits; - } - - template - inline void find_modular_pow(modular_big_integer &result, - const modular_big_integer &b, - const big_integer_t &exp) { - modular_params mod = b.mod_data(); - size_t m_window_bits; - unsigned long cur_exp_index; - size_t exp_bits = eval_msb(exp); - m_window_bits = window_bits(exp_bits + 1); - - std::vector m_g(1U << m_window_bits); - big_integer_t *p_g = m_g.data(); - big_integer_t x(1, mod); - big_integer_t nibble = exp; - big_integer_t mask; - eval_bit_set(mask, m_window_bits); - eval_decrement(mask); - *p_g = x; - ++p_g; - *p_g = b; - ++p_g; - for (size_t i = 2; i < (1U << m_window_bits); i++) { - eval_multiply(*p_g, m_g[i - 1], b); - ++p_g; + + template= Bits2, int> = 0> + constexpr void adjust_regular(big_integer &result, + const big_integer &input) const { + result = input; + if (m_use_montgomery_form) { + m_modular_functions.montgomery_reduce(result); + } } - size_t exp_nibbles = (exp_bits + 1 + m_window_bits - 1) / m_window_bits; - std::vector exp_index; - - for (size_t i = 0; i < exp_nibbles; ++i) { - big_integer_t tmp = nibble; - eval_bitwise_and(tmp, mask); - eval_convert_to(&cur_exp_index, tmp); - eval_right_shift(nibble, m_window_bits); - exp_index.push_back(cur_exp_index); + + template + constexpr void exp(big_integer_t1 &result, const T &exp) const { + exp(result, result, exp); } - eval_multiply(x, m_g[exp_index[exp_nibbles - 1]]); - for (size_t i = exp_nibbles - 1; i > 0; --i) { - for (size_t j = 0; j != m_window_bits; ++j) { - eval_multiply(x, x); + template + constexpr void exp(big_integer_t1 &result, const big_integer_t2 &a, const T &exp) const { + if (m_use_montgomery_form) { + m_modular_functions.montgomery_exp(result, a, exp); + } else { + m_modular_functions.regular_exp(result, a, exp); } + } - eval_multiply(x, m_g[exp_index[i - 1]]); + template + constexpr void mul(big_integer_t1 &result, const big_integer_t1 &y) const { + if (m_use_montgomery_form) { + m_modular_functions.montgomery_mul(result, y); + } else { + m_modular_functions.regular_mul(result, y); + } } - result = x; - } - - template - constexpr void eval_pow(modular_big_integer &result, - const modular_big_integer &b, - const T &e) { - find_modular_pow(result, b, e); - } - - template - constexpr void eval_pow(modular_big_integer &result, - const modular_big_integer &b, - const modular_big_integer &e) { - big_integer_t exp; - e.mod_data().adjust_regular(exp, e.base_data()); - find_modular_pow(result, b, exp); - } - - template - constexpr void eval_powm(modular_big_integer &result, - const modular_big_integer &b, - const T &e) { - eval_pow(result, b, e); - } - - template - constexpr void eval_powm(modular_big_integer &result, - const modular_big_integer &b, - const modular_big_integer &e) { - eval_pow(result, b, e); - } - - template - inline constexpr void eval_left_shift(modular_big_integer &t, - UI i) noexcept { - big_integer_t tmp; - t.mod_data().adjust_regular(tmp, t.base_data()); - eval_left_shift(tmp, i); - t.base_data() = tmp; - t.mod_data().adjust_modular(t.base_data()); - } - - template - constexpr void eval_right_shift(modular_big_integer &t, UI i) { - big_integer_t tmp; - t.mod_data().adjust_regular(tmp, t.base_data()); - eval_right_shift(tmp, i); - t.base_data() = tmp; - t.mod_data().adjust_modular(t.base_data()); - } - - template - constexpr void eval_left_shift(modular_big_integer &t, - const modular_big_integer &v, - UI i) { - big_integer_t tmp1, tmp2; - t.mod_data().adjust_regular(tmp1, t.base_data()); - t.mod_data().adjust_regular(tmp2, v.base_data()); - eval_left_shift(tmp1, tmp2, static_cast(i)); - t.base_data() = tmp1; - t.mod_data().adjust_modular(t.base_data()); - } - - template - constexpr void eval_right_shift(modular_big_integer &t, - const modular_big_integer &v, - UI i) { - big_integer_t tmp1, tmp2; - t.mod_data().adjust_regular(tmp1, t.base_data()); - t.mod_data().adjust_regular(tmp2, v.base_data()); - eval_right_shift(tmp1, tmp2, static_cast(i)); - t.base_data() = tmp1; - t.mod_data().adjust_modular(t.base_data()); - } - - template - constexpr void eval_bitwise_and(modular_big_integer &result, - const modular_big_integer &v) { - big_integer_t tmp1, tmp2; - result.mod_data().adjust_regular(tmp1, result.base_data()); - v.mod_data().adjust_regular(tmp2, v.base_data()); - eval_bitwise_and(tmp1, tmp2); - result.base_data() = tmp1; - result.mod_data().adjust_modular(result.base_data()); - } - - template - constexpr void eval_bitwise_or(modular_big_integer &result, - const modular_big_integer &v) { - big_integer_t tmp1, tmp2; - result.mod_data().adjust_regular(tmp1, result.base_data()); - v.mod_data().adjust_regular(tmp2, v.base_data()); - eval_bitwise_or(tmp1, tmp2); - result.base_data() = tmp1; - result.mod_data().adjust_modular(result.base_data()); - } - - template - constexpr void eval_bitwise_xor(modular_big_integer &result, - const modular_big_integer &v) { - big_integer_t tmp1, tmp2; - result.mod_data().adjust_regular(tmp1, result.base_data()); - v.mod_data().adjust_regular(tmp2, v.base_data()); - eval_bitwise_xor(tmp1, tmp2); - result.base_data() = tmp1; - result.mod_data().adjust_modular(result.base_data()); - } - - template - constexpr int eval_msb(const modular_big_integer &m) { - big_integer_t tmp; - m.mod_data().adjust_regular(tmp, m.base_data()); - return eval_msb(tmp); - } - - template - constexpr unsigned eval_lsb(const modular_big_integer &m) { - big_integer_t tmp; - m.mod_data().adjust_regular(tmp, m.base_data()); - return eval_lsb(tmp); - } - - template - constexpr bool eval_bit_test(const modular_big_integer &m, - std::size_t index) { - big_integer_t tmp; - m.mod_data().adjust_regular(tmp, m.base_data()); - return eval_bit_test(tmp, index); - } - - template - constexpr void eval_bit_set(modular_big_integer &result, - std::size_t index) { - big_integer_t tmp; - result.mod_data().adjust_regular(tmp, result.base_data()); - eval_bit_set(tmp, index); - result.mod_data().adjust_modular(result.base_data(), tmp); - } - - // We must make sure any call with any integral type ends up here, if we use std::size_t - // here, something this function is not preferred by the compiler and boost's version is - // used, which is worse. - template - constexpr void eval_bit_unset(modular_big_integer &result, - std::size_t index) { - big_integer_t tmp; - result.mod_data().adjust_regular(tmp, result.base_data()); - eval_bit_unset(tmp, index); - result.mod_data().adjust_modular(result.base_data(), tmp); - } - - template - constexpr void eval_bit_flip(modular_big_integer &result, - std::size_t index) { - big_integer_t tmp; - result.mod_data().adjust_regular(tmp, result.base_data()); - eval_bit_flip(tmp, index); - result.mod_data().adjust_modular(result.base_data(), tmp); - } - - template - constexpr modular_big_integer eval_ressol( - const modular_big_integer &input) { - big_integer_t new_base, res; - modular_big_integer res_mod; - - input.mod_data().adjust_regular(new_base, input.base_data()); - res = eval_ressol(new_base, input.mod_data().get_mod()); - assign_components(res_mod, res, input.mod_data().get_mod()); - - return res_mod; - } - - template - constexpr void eval_inverse_mod( - modular_big_integer &result, - const modular_big_integer &input) { - big_integer_t new_base, res; - - input.mod_data().adjust_regular(new_base, input.base_data()); - eval_inverse_mod(res, new_base, input.mod_data().get_mod()); - assign_components(result, res, input.mod_data().get_mod()); - } - - template - inline constexpr std::size_t hash_value( - const modular_big_integer &val) noexcept { - return hash_value(val.base_data()); - } + + template + constexpr void add(big_integer_t1 &result, const big_integer_t2 &y) const { + m_modular_functions.regular_add(result, y); + } + + template + constexpr operator big_integer_t1() { + return get_mod(); + }; + + constexpr bool compare_eq(const modular_ops &o) const { return get_mod() == o.get_mod(); } + + constexpr void swap(modular_ops &o) noexcept { + m_modular_functions.swap(o.get_modular_functions()); + bool t = m_use_montgomery_form; + m_use_montgomery_form = o.m_use_montgomery_form; + o.m_use_montgomery_form = t; + } + + // TODO: check function correctness + constexpr friend std::ostream &operator<<(std::ostream &o, const modular_ops &a) { + o << a.get_mod(); + return o; + } + + private: + modular_functions_t m_modular_functions; + bool m_use_montgomery_form = false; + }; + + template + class modular_ops_storage_ct { + public: + using modular_ops_t = modular_ops; + + constexpr modular_ops_storage_ct() {} + + static constexpr const modular_ops_t &modular_ops() { return m_modular_ops; } + + private: + static constexpr modular_ops_t m_modular_ops{Modulus}; + }; + + // Must be used only in the tests, we must normally use only modular_ops_storage_ct. + template + class modular_ops_storage_rt { + public: + using modular_ops_t = modular_ops; + + constexpr modular_ops_storage_rt(const big_integer_t &input) : m_modular_ops(input) {} + + constexpr const modular_ops_t &modular_ops() const { return m_modular_ops; } + + private: + modular_ops_t m_modular_ops; + }; } // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_params.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_params.hpp deleted file mode 100644 index 7a82248c15..0000000000 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_params.hpp +++ /dev/null @@ -1,203 +0,0 @@ -//---------------------------------------------------------------------------// -// Copyright (c) 2020 Mikhail Komarov -// Copyright (c) 2020 Ilias Khairullin -// Copyright (c) 2021 Aleksei Moskvin -// Copyright (c) 2024 Andrey Nefedov -// -// Distributed under the Boost Software License, Version 1.0 -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt -//---------------------------------------------------------------------------// - -#pragma once - -#include - -#include - -#include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" -#include "nil/crypto3/multiprecision/big_integer/modular/modular_functions.hpp" - -namespace nil::crypto3::multiprecision { - // TODO(ioxid): merge with modular_functions - // fixed precision modular params type which supports compile-time execution - template - class modular_params { - protected: - using modular_functions_t = modular_functions; - - public: - using policy_type = typename modular_functions_t::policy_type; - - using Backend_doubled_limbs = typename policy_type::Backend_doubled_limbs; - // using big_integer_t = typename policy_type::big_integer_t; - - constexpr auto &get_modular_functions() { return m_modular_functions; } - constexpr const auto &get_modular_functions() const { return m_modular_functions; } - - constexpr auto &get_is_odd_mod() { return is_odd_mod; } - constexpr const auto &get_is_odd_mod() const { return is_odd_mod; } - - constexpr auto get_mod() const { return m_modular_functions.get_mod(); } - - constexpr modular_params() {} - - constexpr modular_params(const big_integer_t &m) : m_modular_functions(m) { - using boost::multiprecision::default_ops::eval_bit_test; - is_odd_mod = eval_bit_test(m, 0); - } - - constexpr modular_params(const modular_params &o) - : m_modular_functions(o.get_modular_functions()) { - is_odd_mod = o.get_is_odd_mod(); - } - - template - constexpr void reduce(big_integer &result) const { - if (is_odd_mod) { - m_modular_functions.montgomery_reduce(result); - } else { - m_modular_functions.barrett_reduce(result); - } - } - - constexpr void adjust_modular(big_integer_t &result) const { - adjust_modular(result, result); - } - - template - constexpr void adjust_modular(big_integer_t &result, - const big_integer &input) const { - Backend_doubled_limbs tmp; - m_modular_functions.barrett_reduce(tmp, input); - if (is_odd_mod) { - // - // to prevent problems with trivial cpp_int - // - Backend_doubled_limbs r2(m_modular_functions.get_r2()); - - eval_multiply(tmp, r2); - m_modular_functions.montgomery_reduce(tmp); - } - result = tmp; - } - - template= Bits2>::type> - constexpr void adjust_regular(big_integer &result, - const big_integer &input) const { - result = input; - if (is_odd_mod) { - m_modular_functions.montgomery_reduce(result); - } - } - - template - constexpr void mod_exp(Backend1 &result, const T &exp) const { - mod_exp(result, result, exp); - } - - template - constexpr void mod_exp(Backend1 &result, const Backend2 &a, const T &exp) const { - if (is_odd_mod) { - m_modular_functions.montgomery_exp(result, a, exp); - } else { - m_modular_functions.regular_exp(result, a, exp); - } - } - - template - constexpr void mod_mul(Backend1 &result, const Backend1 &y) const { - if (is_odd_mod) { - m_modular_functions.montgomery_mul(result, y); - } else { - m_modular_functions.regular_mul(result, y); - } - } - - template - constexpr void mod_add(Backend1 &result, const Backend2 &y) const { - m_modular_functions.regular_add(result, y); - } - - template - constexpr operator Backend1() { - return get_mod(); - }; - - constexpr bool compare_eq(const modular_params &o) const { - // They are either equal or not: - return get_mod().compare(o.get_mod()) == 0; - } - - constexpr void swap(modular_params &o) noexcept { - m_modular_functions.swap(o.get_modular_functions()); - bool t = is_odd_mod; - is_odd_mod = o.get_is_odd_mod(); - o.get_is_odd_mod() = t; - } - - constexpr modular_params &operator=(const modular_params &o) { - m_modular_functions = o.get_modular_functions(); - is_odd_mod = o.get_is_odd_mod(); - return *this; - } - - constexpr modular_params &operator=(const big_integer_t &m) { - m_modular_functions = m; - is_odd_mod = boost::multiprecision::default_ops::eval_bit_test(m, 0); - return *this; - } - - // TODO: check function correctness - constexpr friend std::ostream &operator<<(std::ostream &o, const modular_params &a) { - o << a.get_mod(); - return o; - } - - protected: - modular_functions_t m_modular_functions; - bool is_odd_mod = false; - }; - - template - class modular_params_storage_ct { - public: - using modular_params_t = modular_params; - - constexpr modular_params_storage_ct() {} - - constexpr modular_params_storage_ct(modular_params_t &input) {} - - constexpr void set_modular_params(const modular_params_t &input) {} - - template - constexpr void set_modular_params(const T &input) {} - - constexpr const modular_params_t &modular_params() const { return m_mod; } - - protected: - constexpr static const modular_params_t m_mod{Modulus}; - }; - - // Must be used only in the tests, we must normally use only modular_params_storage_ct. - template - class modular_params_storage_rt { - public: - using modular_params_t = modular_params; - - constexpr modular_params_storage_rt() {} - - constexpr modular_params_storage_rt(modular_params_t input) : m_mod(input) {} - - constexpr void set_modular_params(const modular_params_t &input) { m_mod = input; } - - constexpr void set_modular_params(const big_integer_t &input) { m_mod = input; } - - constexpr modular_params_t &modular_params() { return m_mod; } - constexpr const modular_params_t &modular_params() const { return m_mod; } - - modular_params_t m_mod; - }; -} // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_policy.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_policy.hpp deleted file mode 100644 index 0a0f3e7c10..0000000000 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/modular/modular_policy.hpp +++ /dev/null @@ -1,43 +0,0 @@ -//---------------------------------------------------------------------------// -// Copyright (c) 2020 Mikhail Komarov -// Copyright (c) 2020 Ilias Khairullin -// Copyright (c) 2024 Andrey Nefedov -// -// Distributed under the Boost Software License, Version 1.0 -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt -//---------------------------------------------------------------------------// - -#pragma once - -#include - -#include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" - -namespace nil::crypto3::multiprecision { - // TODO(ioxid): maybe remove - template - struct modular_policy { - using Backend = big_integer; - - using limb_type = limb_type; - using double_limb_type = double_limb_type; - - constexpr static auto limbs_count = Backend::internal_limb_count; - constexpr static auto limb_bits = Backend::limb_bits; - - constexpr static auto BitsCount_doubled = 2u * Bits; - constexpr static auto BitsCount_doubled_1 = BitsCount_doubled + 1; - constexpr static auto BitsCount_quadruple_1 = 2u * BitsCount_doubled + 1; - constexpr static auto BitsCount_padded_limbs = limbs_count * limb_bits + limb_bits; - constexpr static auto BitsCount_doubled_limbs = 2u * limbs_count * limb_bits; - constexpr static auto BitsCount_doubled_padded_limbs = BitsCount_doubled_limbs + limb_bits; - - using Backend_doubled = big_integer; - using Backend_doubled_1 = big_integer; - using Backend_quadruple_1 = big_integer; - using Backend_padded_limbs = big_integer; - using Backend_doubled_limbs = big_integer; - using Backend_doubled_padded_limbs = big_integer; - }; -} // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/divide.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/divide.hpp deleted file mode 100644 index 6b00ea9ced..0000000000 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/divide.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/////////////////////////////////////////////////////////////// -// Copyright (c) 2023 Martun Karapetyan -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt -// -// Contains eval_modulus for big_integer, which uses conversion to cpp_int_backend to -// actually apply the operation. -// - -#pragma once - -#include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" - -namespace nil::crypto3::multiprecision { - - // Functions in this file should be called only for creation of montgomery and Barett - // params, no during "normal" execution, so we do NOT care about the execution speed, - // and will just redirect calls to normal boost::cpp_int. - - template - inline constexpr void eval_modulus(big_integer &result, const big_integer &a, - const big_integer &b) noexcept { - result = a; - // Call the function below. - eval_modulus(result, b); - } - - // Just a call to the upper function, similar to operator*=. - // Caller is responsible for the result to fit in Bits1 Bits, we will NOT throw! - template - inline constexpr void eval_modulus(big_integer &result, - const big_integer &a) noexcept { - auto result_cpp_int = result.to_cpp_int(); - result_cpp_int %= a.to_cpp_int(); - result.from_cpp_int(result_cpp_int); - } - - // This function should be called only for creation of montgomery and Barett params and - // calculation of inverse, element, not during "normal" execution. We will use - // conversion to normal boost::cpp_int here and then convert back. - template - inline constexpr void eval_divide(big_integer &result, const big_integer &a, - const big_integer &b) noexcept { - result = a; - // Just make a call to the lower function. - eval_divide(result, b); - } - - // Caller is responsible for the result to fit in Bits1 Bits, we will NOT throw! - // Covers the case where the second operand is not trivial. - template - inline constexpr void eval_divide(big_integer &result, - const big_integer &a) noexcept { - auto result_cpp_int = result.to_cpp_int(); - result_cpp_int /= a.to_cpp_int(); - result.from_cpp_int(result_cpp_int); - } -} // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/eval_jacobi.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/eval_jacobi.hpp deleted file mode 100644 index a30bbde7e7..0000000000 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/eval_jacobi.hpp +++ /dev/null @@ -1,78 +0,0 @@ -//---------------------------------------------------------------------------// -// Copyright (c) 2018-2020 Mikhail Komarov -// Copyright (c) 2021 Aleksei Moskvin -// -// Distributed under the Boost Software License, Version 1.0 -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt -//---------------------------------------------------------------------------// - -#pragma once - -#include -#include - -#include "nil/crypto3/multiprecision/big_integer/modular/modular_functions.hpp" - -namespace nil::crypto3::multiprecision { - template - class big_integer; - - template - constexpr int eval_jacobi(const Backend &a, const Backend &n) { - using boost::multiprecision::default_ops::eval_divide; - using boost::multiprecision::default_ops::eval_get_sign; - using boost::multiprecision::default_ops::eval_gt; - using boost::multiprecision::default_ops::eval_integer_modulus; - using boost::multiprecision::default_ops::eval_is_zero; - using boost::multiprecision::default_ops::eval_lsb; - using boost::multiprecision::default_ops::eval_lt; - using boost::multiprecision::default_ops::eval_modulus; - using boost::multiprecision::default_ops::eval_right_shift; - - // BOOST_THROW_EXCEPTION(std::invalid_argument("jacobi: second argument must be odd - // and > 1")); - BOOST_ASSERT(eval_integer_modulus(n, 2) && eval_gt(n, 1)); - - Backend x = a, y = n; - int J = 1; - - while (eval_gt(y, 1)) { - eval_modulus(x, y); - - Backend yd2 = y; - eval_right_shift(yd2, 1); - - if (eval_gt(x, yd2)) { - Backend tmp(y); - eval_subtract(tmp, x); - x = tmp; - if (eval_integer_modulus(y, 4) == 3) { - J = -J; - } - } - if (eval_is_zero(x)) { - return 0; - } - - size_t shifts = eval_lsb(x); - custom_right_shift(x, shifts); - if (shifts & 1) { - std::size_t y_mod_8 = eval_integer_modulus(y, 8); - if (y_mod_8 == 3 || y_mod_8 == 5) { - J = -J; - } - } - - if (eval_integer_modulus(x, 4) == 3 && eval_integer_modulus(y, 4) == 3) { - J = -J; - } - - // std::swap(x, y); - auto tmp = x; - x = y; - y = tmp; - } - return J; - } -} // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/import_export.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/import_export.hpp index b3cfc85475..8ce53c2a67 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/import_export.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/import_export.hpp @@ -7,30 +7,24 @@ #include #include +#include #include #include #include #include -// #include // For 'extract_bits'. -#include -#include - #include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" #include "nil/crypto3/multiprecision/big_integer/storage.hpp" namespace nil::crypto3::multiprecision { - namespace detail { - using limb_type = nil::crypto3::multiprecision::limb_type; - /* This specialization is used when assigning `chunk_bits` * of `bits` into `val` at `bit_location` in case where `val` * is larger than one limb (machine word). */ template void assign_bits(big_integer& val, Unsigned bits, std::size_t bit_location, - std::size_t chunk_bits, const std::integral_constant& tag) { + std::size_t chunk_bits) { unsigned limb = bit_location / (sizeof(limb_type) * CHAR_BIT); unsigned shift = bit_location % (sizeof(limb_type) * CHAR_BIT); @@ -54,7 +48,7 @@ namespace nil::crypto3::multiprecision { bit_location += shift; auto extra_bits = bits >> shift; if (extra_bits) { - assign_bits(val, extra_bits, bit_location, chunk_bits, tag); + assign_bits(val, extra_bits, bit_location, chunk_bits); } } } @@ -67,40 +61,58 @@ namespace nil::crypto3::multiprecision { void assign_bits(big_integer& val, Unsigned bits, std::size_t bit_location, std::size_t chunk_bits, const std::integral_constant& /*unused*/) { - using local_limb_type = typename big_integer::local_limb_type; + using limb_type = typename big_integer::limb_type; // // Check for possible overflow, this may trigger an exception, or have no effect // depending on whether this is a checked integer or not: // // We are not throwing, we will use as many bits from the input as we need to. - // BOOST_ASSERT(!((bit_location >= sizeof(local_limb_type) * CHAR_BIT) && bits)); + // BOOST_ASSERT(!((bit_location >= sizeof(limb_type) * CHAR_BIT) && bits)); - local_limb_type mask = chunk_bits >= sizeof(local_limb_type) * CHAR_BIT - ? ~static_cast(0u) - : (static_cast(1u) << chunk_bits) - 1; - local_limb_type value = (static_cast(bits) & mask) << bit_location; + limb_type mask = chunk_bits >= sizeof(limb_type) * CHAR_BIT + ? ~static_cast(0u) + : (static_cast(1u) << chunk_bits) - 1; + limb_type value = (static_cast(bits) & mask) << bit_location; *val.limbs() |= value; // // Check for overflow bits: // - bit_location = sizeof(local_limb_type) * CHAR_BIT - bit_location; + bit_location = sizeof(limb_type) * CHAR_BIT - bit_location; // We are not throwing, we will use as many bits from the input as we need to. // BOOST_ASSERT(!((bit_location < sizeof(bits) * CHAR_BIT) && (bits >>= // bit_location))); } + template + std::uintmax_t extract_bits(const big_integer& val, std::size_t location, + std::size_t count) { + std::size_t limb = location / (sizeof(limb_type) * CHAR_BIT); + std::size_t shift = location % (sizeof(limb_type) * CHAR_BIT); + std::uintmax_t result = 0; + std::uintmax_t mask = count == std::numeric_limits::digits + ? ~static_cast(0) + : (static_cast(1u) << count) - 1; + if (count > (sizeof(limb_type) * CHAR_BIT - shift)) { + result = extract_bits(val, location + sizeof(limb_type) * CHAR_BIT - shift, + count - sizeof(limb_type) * CHAR_BIT + shift); + result <<= sizeof(limb_type) * CHAR_BIT - shift; + } + if (limb < val.size()) { + result |= (val.limbs()[limb] >> shift) & mask; + } + return result; + } + template - big_integer& import_bits_generic(big_integer& val, Iterator i, Iterator j, + big_integer& import_bits_generic(big_integer& result, Iterator i, Iterator j, std::size_t chunk_size = 0, bool msv_first = true) { big_integer newval; using value_type = typename std::iterator_traits::value_type; using difference_type = typename std::iterator_traits::difference_type; - using size_type = - typename ::boost::multiprecision::detail::make_unsigned::type; - using tag_type = typename big_integer::trivial_tag; + using size_type = typename std::make_unsigned::type; if (!chunk_size) { chunk_size = std::numeric_limits::digits; @@ -117,8 +129,7 @@ namespace nil::crypto3::multiprecision { msv_first ? -static_cast(chunk_size) : chunk_size; while (i != j) { - assign_bits(newval, *i, static_cast(bit_location), chunk_size, - tag_type()); + assign_bits(newval, *i, static_cast(bit_location), chunk_size); ++i; bit_location += bit_location_change; } @@ -126,12 +137,12 @@ namespace nil::crypto3::multiprecision { // This will remove the upper bits using upper_limb_mask. newval.normalize(); - val.backend() = std::move(newval); - return val; + result = std::move(newval); + return result; } template - inline big_integer import_bits_fast(big_integer& val, T* i, T* j, + inline big_integer import_bits_fast(big_integer& result, T* i, T* j, std::size_t chunk_size = 0) { std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i)); std::size_t limb_len = byte_len / sizeof(limb_type); @@ -139,7 +150,6 @@ namespace nil::crypto3::multiprecision { ++limb_len; } - big_integer& result = val.backend(); BOOST_VERIFY(result.size() > limb_len); result.limbs()[result.size() - 1] = 0u; @@ -147,7 +157,7 @@ namespace nil::crypto3::multiprecision { // This is probably unneeded, but let it stay for now. result.normalize(); - return val; + return result; } } // namespace detail @@ -170,36 +180,26 @@ namespace nil::crypto3::multiprecision { template OutputIterator export_bits(const big_integer& val, OutputIterator out, std::size_t chunk_size, bool msv_first = true) { -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable : 4244) -#endif - using tag_type = typename big_integer::trivial_tag; if (!val) { *out = 0; ++out; return out; } - std::size_t bitcount = eval_msb_imp(val.backend()) + 1; + std::size_t bitcount = msb(val) + 1; std::ptrdiff_t bit_location = msv_first ? static_cast(bitcount - chunk_size) : 0; - const std::ptrdiff_t bit_step = - msv_first ? static_cast(-static_cast(chunk_size)) - : static_cast(chunk_size); + const std::ptrdiff_t bit_step = msv_first ? (-static_cast(chunk_size)) + : static_cast(chunk_size); while (bit_location % bit_step) { ++bit_location; } do { - *out = boost::multiprecision::detail::extract_bits(val.backend(), bit_location, - chunk_size, tag_type()); + *out = detail::extract_bits(val, bit_location, chunk_size); ++out; bit_location += bit_step; } while ((bit_location >= 0) && (bit_location < static_cast(bitcount))); return out; -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif } } // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/integer_ops.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/integer_ops.hpp deleted file mode 100644 index b285b95fc7..0000000000 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/integer_ops.hpp +++ /dev/null @@ -1,55 +0,0 @@ -//---------------------------------------------------------------------------// -// Copyright 2024 Martun Karapetyan -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt -// -// We need to include this file after modular adaptor, in order for these functions to 'see' -//---------------------------------------------------------------------------// - -#pragma once - -#include - -namespace nil::crypto3::multiprecision { - // TODO - - // // Only for our modular numbers function powm takes 2 arguments, - // // so we need to add this specialization. - // template - // inline constexpr - // typename std::enable_if::value && is_integral::value, - // number>>::type - // powm(const number< - // boost::multiprecision::backends::modular_adaptor>& - // b, - // const U& p) { - // // We will directly call eval_powm here, that's what a call through a - // // default_ops::powm_func would do if expression tempaltes are off. We don't want to - // // change that structure. - // boost::multiprecision::backends::modular_adaptor result; - // result.set_modular_params(b.backend().mod_data()); - // boost::multiprecision::backends::eval_powm(result, b.backend(), p); - // return result; - // } - - // template - // inline constexpr - // typename std::enable_if<(detail::is_backend::value && - // (is_number::value || is_number_expression::value)), - // number>>::type - // powm(const number< - // boost::multiprecision::backends::modular_adaptor>& - // b, - // const U& p) { - // // We will directly call eval_powm here, that's what a call through a - // // default_ops::powm_func would do if expression tempaltes are off. We don't want to - // // change that structure. - // boost::multiprecision::backends::modular_adaptor result; - // result.set_modular_params(b.backend().mod_data()); - // boost::multiprecision::backends::eval_powm(result, b.backend(), p.backend()); - // return result; - // } -} // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/jacobi.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/jacobi.hpp new file mode 100644 index 0000000000..9d6ec0c21f --- /dev/null +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/jacobi.hpp @@ -0,0 +1,66 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2018-2020 Mikhail Komarov +// Copyright (c) 2021 Aleksei Moskvin +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#pragma once + +#include +#include + +#include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" + +namespace nil::crypto3::multiprecision { + template + constexpr int eval_jacobi(const big_integer &a, const big_integer &n) { + using big_integer_t = big_integer; + // BOOST_THROW_EXCEPTION(std::invalid_argument("jacobi: second argument must be odd + // and > 1")); + BOOST_ASSERT(n % 2 && n > 1); + + big_integer_t x = a, y = n; + int J = 1; + + while (y > 1) { + x %= y; + + big_integer_t yd2 = y; + yd2 >>= 1; + + if (eval_gt(x, yd2)) { + big_integer_t tmp(y); + tmp -= x; + x = tmp; + if (y % 4 == 3) { + J = -J; + } + } + if (is_zero(x)) { + return 0; + } + + size_t shifts = lsb(x); + x >>= shifts; + if (shifts & 1) { + std::size_t y_mod_8 = y % 8; + if (y_mod_8 == 3 || y_mod_8 == 5) { + J = -J; + } + } + + if (x % 4 == 3 && y % 4 == 3) { + J = -J; + } + + // std::swap(x, y); + auto tmp = x; + x = y; + y = tmp; + } + return J; + } +} // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/misc.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/misc.hpp index 816bb2e489..4ec3da669f 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/misc.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/misc.hpp @@ -21,20 +21,13 @@ #include "nil/crypto3/multiprecision/big_integer/detail/config.hpp" #include "nil/crypto3/multiprecision/big_integer/storage.hpp" -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable : 4702) -#pragma warning(disable : 4127) // conditional expression is constant -#pragma warning( \ - disable : 4146) // unary minus operator applied to unsigned type, result still unsigned -#endif - namespace nil::crypto3::multiprecision { // TODO refactor template inline constexpr typename std::enable_if::value, void>::type - eval_convert_to(R *result, const big_integer &backend) { + convert_to(R *result, const big_integer &backend) { + using detail::limb_type; if constexpr (boost::multiprecision::backends::numeric_limits_workaround::digits < big_integer::limb_bits) { if (boost::multiprecision::detail::is_signed::value && @@ -44,8 +37,9 @@ namespace nil::crypto3::multiprecision { return; } *result = static_cast(backend.limbs()[0]); - } else + } else { *result = static_cast(backend.limbs()[0]); + } unsigned shift = big_integer::limb_bits; unsigned i = 1; @@ -94,7 +88,7 @@ namespace nil::crypto3::multiprecision { } template - NIL_CO3_MP_FORCEINLINE constexpr bool eval_is_zero(const big_integer &val) noexcept { + NIL_CO3_MP_FORCEINLINE constexpr bool is_zero(const big_integer &val) noexcept { // std::all_of is not constexpr, so writing manually. for (std::size_t i = 0; i < val.size(); ++i) { if (val.limbs()[i] != 0) { @@ -108,7 +102,7 @@ namespace nil::crypto3::multiprecision { // Get the location of the least-significant-bit: // template - inline constexpr unsigned eval_lsb(const big_integer &a) { + inline constexpr unsigned lsb(const big_integer &a) { // // Find the index of the least significant limb that is non-zero: // @@ -125,7 +119,7 @@ namespace nil::crypto3::multiprecision { } template - inline constexpr unsigned eval_msb(const big_integer &a) { + inline constexpr unsigned msb(const big_integer &a) { // // Find the index of the most significant bit that is non-zero: // @@ -141,17 +135,10 @@ namespace nil::crypto3::multiprecision { return boost::multiprecision::detail::find_msb(a.limbs()[0]); } -#ifdef BOOST_GCC -// -// We really shouldn't need to be disabling this warning, but it really does appear to be -// spurious. The warning appears only when in release mode, and asserts are on. -// -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" -#endif - template - inline constexpr bool eval_bit_test(const big_integer &val, std::size_t index) noexcept { + inline constexpr bool bit_test(const big_integer &val, std::size_t index) noexcept { + using detail::limb_type; + unsigned offset = index / big_integer::limb_bits; unsigned shift = index % big_integer::limb_bits; limb_type mask = limb_type(1u) << shift; @@ -161,12 +148,10 @@ namespace nil::crypto3::multiprecision { return static_cast(val.limbs()[offset] & mask); } -#ifdef BOOST_GCC -#pragma GCC diagnostic pop -#endif - template - inline constexpr void eval_bit_set(big_integer &val, std::size_t index) { + inline constexpr void bit_set(big_integer &val, std::size_t index) { + using detail::limb_type; + unsigned offset = index / big_integer::limb_bits; unsigned shift = index % big_integer::limb_bits; limb_type mask = limb_type(1u) << shift; @@ -177,7 +162,9 @@ namespace nil::crypto3::multiprecision { } template - inline constexpr void eval_bit_unset(big_integer &val, std::size_t index) noexcept { + inline constexpr void bit_unset(big_integer &val, std::size_t index) noexcept { + using detail::limb_type; + unsigned offset = index / big_integer::limb_bits; unsigned shift = index % big_integer::limb_bits; limb_type mask = limb_type(1u) << shift; @@ -189,7 +176,9 @@ namespace nil::crypto3::multiprecision { } template - inline constexpr void eval_bit_flip(big_integer &val, std::size_t index) { + inline constexpr void bit_flip(big_integer &val, std::size_t index) { + using detail::limb_type; + unsigned offset = index / big_integer::limb_bits; unsigned shift = index % big_integer::limb_bits; limb_type mask = limb_type(1u) << shift; @@ -206,7 +195,10 @@ namespace nil::crypto3::multiprecision { inline constexpr typename std::enable_if::value, Integer>::type - eval_integer_modulus(const big_integer &a, Integer mod) { + integer_modulus(const big_integer &a, Integer mod) { + using detail::limb_type; + using detail::double_limb_type; + if constexpr (sizeof(Integer) <= sizeof(limb_type)) { if (mod <= (std::numeric_limits::max)()) { const int n = a.size(); @@ -230,8 +222,8 @@ namespace nil::crypto3::multiprecision { typename std::enable_if::value && boost::multiprecision::detail::is_integral::value, Integer>::type - eval_integer_modulus(const big_integer &x, Integer val) { - return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val)); + integer_modulus(const big_integer &x, Integer val) { + return integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val)); } template @@ -242,27 +234,4 @@ namespace nil::crypto3::multiprecision { } return result; } - -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - } // namespace nil::crypto3::multiprecision - -// TODO -// namespace detail { - -// // We need to specialize this class, because big_integer does not have -// // signed_types. All we have changed here is Backend::signed_types -> -// // Backend::unsigned_types, this will work for our use cases. -// template -// struct canonical_imp, std::integral_constant> { -// static constexpr int index = -// find_index_of_large_enough_type::unsigned_types, 0, -// bits_of::value>::value; -// using type = typename dereference_tuple::unsigned_types, -// Val>::type; -// }; - -// } // namespace detail diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/multiply.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/multiply.hpp deleted file mode 100644 index e173b8f464..0000000000 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/ops/multiply.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/////////////////////////////////////////////////////////////// -// Copyright (c) 2023 Martun Karapetyan -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt -// -// Contains eval_multiply for big_integer, which does nothing but converts it to -// cpp_int_backend and does the multiplication. -// - -#pragma once - -#include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" - -namespace nil::crypto3::multiprecision { - - // Functions in this file should be called only for creation of montgomery and Barett - // params, calculation of inverse element and montgomery_reduce. Since these functions - // are relatively slow and are not called very often, we will not optimize them. We do - // NOT care about the execution speed, and will just redirect calls to normal - // boost::cpp_int. - template - inline constexpr void eval_multiply(big_integer &result, - const big_integer &a, - const big_integer &b) noexcept { - result = a; - // Call the lower function, we don't care about speed here. - eval_multiply(result, b); - } - - // If the second argument is trivial or not, we still assign it to the first the exact - // same way. - template - inline constexpr void eval_multiply(big_integer &result, const big_integer &a, - const limb_type &b) noexcept { - result = a; - // Call the lower function, we don't care about speed here. - eval_multiply(result, b); - } - - template - inline constexpr void eval_multiply(big_integer &result, const limb_type &b) noexcept { - auto result_cpp_int = result.to_cpp_int(); - result_cpp_int *= b; - result.from_cpp_int(result_cpp_int); - } - - // Caller is responsible for the result to fit in Bits1 Bits, we will NOT throw!!! - // Covers the case where the second operand is not trivial. - // Redirects the call to normal boost::cpp_int. We do not care about speed here. - template - inline constexpr void eval_multiply(big_integer &result, - const big_integer &a) noexcept { - auto result_cpp_int = result.to_cpp_int(); - result_cpp_int *= a.to_cpp_int(); - result.from_cpp_int(result_cpp_int); - } -} // namespace nil::crypto3::multiprecision diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/storage.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/storage.hpp index b0c50be6bd..bb079903e2 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/storage.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_integer/storage.hpp @@ -1,10 +1,28 @@ #pragma once +#include #include -namespace nil::crypto3::multiprecision { +namespace nil::crypto3::multiprecision::detail { using limb_type = std::uint32_t; using double_limb_type = std::uint64_t; using signed_limb_type = std::int32_t; using signed_double_limb_type = std::int64_t; -} // namespace nil::crypto3::multiprecision + + using limb_type = limb_type; + using double_limb_type = double_limb_type; + using limb_pointer = limb_type *; + using const_limb_pointer = const limb_type *; + + static constexpr unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; + static constexpr limb_type max_limb_value = ~static_cast(0u); + + // Given a value represented in 'double_limb_type', decomposes it into + // two 'limb_type' variables, based on high order bits and low order bits. + // There 'a' receives high order bits of 'X', and 'b' receives the low order bits. + static constexpr void dbl_limb_to_limbs(const double_limb_type &X, limb_type &a, limb_type &b) { + b = X; + a = X >> limb_bits; + } + +} // namespace nil::crypto3::multiprecision::detail diff --git a/crypto3/libs/multiprecision/test/CMakeLists.txt b/crypto3/libs/multiprecision/test/CMakeLists.txt index 847f39bba1..0070cc9640 100644 --- a/crypto3/libs/multiprecision/test/CMakeLists.txt +++ b/crypto3/libs/multiprecision/test/CMakeLists.txt @@ -27,7 +27,7 @@ macro(define_runtime_multiprecision_test name) ${Boost_INCLUDE_DIRS} ) - set_target_properties(${test_name} PROPERTIES CXX_STANDARD 17 + set_target_properties(${test_name} PROPERTIES CXX_STANDARD 23 CXX_STANDARD_REQUIRED TRUE) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") @@ -74,6 +74,7 @@ set(BIG_INTEGER_TESTS_NAMES "big_integer" "big_integer_comparision" "big_integer_modular" + "big_integer_modular_comprehensive" ) foreach(TEST_NAME ${RUNTIME_TESTS_NAMES}) diff --git a/crypto3/libs/multiprecision/test/big_integer.cpp b/crypto3/libs/multiprecision/test/big_integer.cpp index 4f13652ac5..7f890968ca 100644 --- a/crypto3/libs/multiprecision/test/big_integer.cpp +++ b/crypto3/libs/multiprecision/test/big_integer.cpp @@ -1,62 +1,148 @@ +#include #define BOOST_TEST_MODULE big_integer_test #include #include +#include #include #include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" #include "nil/crypto3/multiprecision/big_integer/literals.hpp" +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(60) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(32) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(36) +BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(60) + using namespace nil::crypto3::multiprecision::literals; +using namespace boost::multiprecision::literals; -BOOST_AUTO_TEST_SUITE(big_integer_smoke_tests) +BOOST_AUTO_TEST_SUITE(smoke) -BOOST_AUTO_TEST_CASE(construct) { - nil::crypto3::multiprecision::big_integer<315> a = 0x123_big_integer315; +BOOST_AUTO_TEST_CASE(construct_constexpr) { + constexpr nil::crypto3::multiprecision::big_integer<60> a = 0x123_big_integer60; } -BOOST_AUTO_TEST_CASE(to_string_trivial) { BOOST_CHECK((0x1_big_integer315).str() == "1"); } - -BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_CASE(to_string_trivial) { BOOST_CHECK_EQUAL((0x1_big_integer60).str(), "1"); } -BOOST_AUTO_TEST_SUITE(big_integer_operations_tests) +BOOST_AUTO_TEST_CASE(to_string_small) { BOOST_CHECK_EQUAL((0x20_big_integer60).str(), "32"); } BOOST_AUTO_TEST_CASE(ops) { - nil::crypto3::multiprecision::big_integer<315> a = 2u; + nil::crypto3::multiprecision::big_integer<60> a = 2u, b; - auto b = a + a; - b += a; + auto c1{a}; + auto c2{std::move(a)}; + auto c3{2}; + auto c4{2u}; + b = a; + b = std::move(a); + b = 2; + b = 2u; + +#define TEST_BINARY_OP(op) \ + do { \ + b = 32u; \ + a = 4; \ + b = a op a; \ + /* b = 2 op a; */ \ + /* b = a op 2; */ \ + /* b = 2u op a; */ \ + /* b = a op 2u; */ \ + b = 32u; \ + b op## = a; \ + /* b op## = 2; */ \ + /*b op## = 2u; */ \ + } while (false) + + TEST_BINARY_OP(+); ++b; b++; + b = +b; + TEST_BINARY_OP(-); --b; b--; - b -= a; - b = b - a; - - b = std::move(a); + // b = -b; - b = a * b; - b *= a; - b = a / b; - b /= a; - b = a % b; - b %= a; + TEST_BINARY_OP(%); + TEST_BINARY_OP(/); + TEST_BINARY_OP(*); - b = a & b; - b &= a; - b = a | b; - b |= a; - b = a ^ b; - b ^= a; + TEST_BINARY_OP(&); + TEST_BINARY_OP(|); + TEST_BINARY_OP(^); b = ~a; +} - // b = -b; - b = +b; +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(cpp_int_conversion) + +BOOST_AUTO_TEST_CASE(to_cpp_int) { + BOOST_CHECK_EQUAL((0xFFFFFFFFFFF_big_integer60).to_cpp_int().str(), "17592186044415"); +} + +BOOST_AUTO_TEST_CASE(from_cpp_int) { + nil::crypto3::multiprecision::big_integer<60> result; + result.from_cpp_int(0xFFFFFFFFFFF_cppui60); + BOOST_CHECK_EQUAL(result, 0xFFFFFFFFFFF_big_integer60); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(addition) + +BOOST_AUTO_TEST_CASE(simple) { + BOOST_CHECK_EQUAL(0x2_big_integer60 + 0x3_big_integer60, 0x5_big_integer60); +} + +BOOST_AUTO_TEST_CASE(wraps) { + BOOST_CHECK_EQUAL(0xFFFFFFFF_big_integer32 + 0x2_big_integer32, 0x1_big_integer32); +} + +BOOST_AUTO_TEST_CASE(multilimb) { + BOOST_CHECK_EQUAL(0xAFFFFFFFF_big_integer36 + 0x2_big_integer36, 0xB00000001_big_integer36); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(multiplication) + +BOOST_AUTO_TEST_CASE(simple) { + BOOST_CHECK_EQUAL(0x2_big_integer60 * 0x3_big_integer60, 0x6_big_integer60); +} + +BOOST_AUTO_TEST_CASE(wraps) { + BOOST_CHECK_EQUAL(0xFFFFFFFF_big_integer32 * 0x2_big_integer32, 0xFFFFFFFE_big_integer32); +} + +BOOST_AUTO_TEST_CASE(multilimb) { + BOOST_CHECK_EQUAL(0xAFFFFFFFF_big_integer36 * 0x2_big_integer36, 0x5FFFFFFFE_big_integer36); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(convert) + +BOOST_AUTO_TEST_CASE(to_uint64_t) { + std::uint64_t a = static_cast(0x123456789ABCDEF_big_integer64); + BOOST_CHECK_EQUAL(a, 0x123456789ABCDEF); +} + +BOOST_AUTO_TEST_CASE(from_uint64_t) { + nil::crypto3::multiprecision::big_integer<64> a = + static_cast(0x123456789ABCDEFull); + BOOST_CHECK_EQUAL(a, 0x123456789ABCDEF_big_integer64); +} + +BOOST_AUTO_TEST_CASE(from_int64_t) { + nil::crypto3::multiprecision::big_integer<64> a = + static_cast(0x123456789ABCDEFull); + BOOST_CHECK_EQUAL(a, 0x123456789ABCDEF_big_integer64); } BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/multiprecision/test/big_integer_modular.cpp b/crypto3/libs/multiprecision/test/big_integer_modular.cpp index 09e373c573..1d6e593a89 100644 --- a/crypto3/libs/multiprecision/test/big_integer_modular.cpp +++ b/crypto3/libs/multiprecision/test/big_integer_modular.cpp @@ -12,32 +12,149 @@ using namespace nil::crypto3::multiprecision; using namespace nil::crypto3::multiprecision::literals; -BOOST_AUTO_TEST_SUITE(big_integer_smoke_tests) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(60) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(32) +CRYPTO3_MP_DEFINE_BIG_INTEGER_LITERAL(36) +BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(60) -constexpr auto mod = 0x123_big_integer315; +using namespace nil::crypto3::multiprecision::literals; +using namespace boost::multiprecision::literals; + +constexpr auto mod = 0x123456789ABCDEF_big_integer64; +using modular_big_int = modular_big_integer_ct; + +BOOST_AUTO_TEST_SUITE(smoke) + +BOOST_AUTO_TEST_CASE(construct_constexpr) { + constexpr modular_big_int a = static_cast(0x123_big_integer64); +} + +BOOST_AUTO_TEST_CASE(construct_modular_ct_trivial_montgomery) { + static constexpr auto mod = 0x3_big_integer64; + modular_big_integer_ct a = modular_big_integer_ct(0x5_big_integer64); + BOOST_CHECK_EQUAL(a.str(), "2"); +} + +BOOST_AUTO_TEST_CASE(construct_modular_rt_trivial_montgomery) { + modular_big_integer_rt<64> a{0x5_big_integer64, 0x3_big_integer64}; + BOOST_CHECK_EQUAL(a.str(), "2"); +} + +BOOST_AUTO_TEST_CASE(construct_modular_ct_small_montgomery) { + static constexpr auto mod = 0x79_big_integer64; + modular_big_integer_ct a = modular_big_integer_ct(0x1234_big_integer64); + BOOST_CHECK_EQUAL(a.str(), "62"); +} + +BOOST_AUTO_TEST_CASE(construct_modular_rt_small_montgomery) { + modular_big_integer_rt<64> a{0x1234_big_integer64, 0x79_big_integer64}; + BOOST_CHECK_EQUAL(a.str(), "62"); +} + +BOOST_AUTO_TEST_CASE(construct_modular_ct_small) { + static constexpr auto mod = 0x78_big_integer64; + modular_big_integer_ct a = modular_big_integer_ct(0x1234_big_integer64); + BOOST_CHECK_EQUAL(a.str(), "100"); +} + +BOOST_AUTO_TEST_CASE(construct_modular_rt_small) { + modular_big_integer_rt<64> a{0x1234_big_integer64, 0x78_big_integer64}; + BOOST_CHECK_EQUAL(a.str(), "100"); +} + +BOOST_AUTO_TEST_CASE(to_string_trivial) { + BOOST_CHECK_EQUAL((static_cast(0x1_big_integer64)).str(), "1"); +} + +BOOST_AUTO_TEST_CASE(to_string_small) { + BOOST_CHECK_EQUAL((static_cast(0x20_big_integer64)).str(), "32"); +} + +BOOST_AUTO_TEST_CASE(ops) { + modular_big_int a = 2u, b; + + auto c1{a}; + auto c2{std::move(a)}; + auto c3{2}; + auto c4{2u}; + b = a; + b = std::move(a); + b = 2; + b = 2u; -BOOST_AUTO_TEST_CASE(operations) { - modular_big_integer_ct a = 2; +#define TEST_BINARY_OP(op) \ + do { \ + b = a op a; \ + /* b = 2 op a; */ \ + /* b = a op 2; */ \ + /* b = 2u op a; */ \ + /* b = a op 2u; */ \ + b op## = a; \ + /* b op## = 2; */ \ + /*b op## = 2u; */ \ + } while (false) - auto b = a + a; - b += a; + TEST_BINARY_OP(+); ++b; b++; + b = +b; + TEST_BINARY_OP(-); --b; b--; - b -= a; - b = b - a; + b = -b; +} - b = std::move(a); +BOOST_AUTO_TEST_SUITE_END() - b = a * b; - b *= a; - b = a / b; - b /= a; +BOOST_AUTO_TEST_SUITE(addition) - b = -b; - b = +b; +BOOST_AUTO_TEST_CASE(simple) { + BOOST_CHECK_EQUAL(static_cast(0x2_big_integer64) + + static_cast(0x3_big_integer64), + static_cast(0x5_big_integer64)); +} + +BOOST_AUTO_TEST_CASE(multilimb) { + BOOST_CHECK_EQUAL(static_cast(0xAFFFFFFFF_big_integer64) + + static_cast(0x2_big_integer36), + static_cast(0xB00000001_big_integer64)); } BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(multiplication) + +BOOST_AUTO_TEST_CASE(simple) { + BOOST_CHECK_EQUAL(static_cast(0x2_big_integer64) * + static_cast(0x3_big_integer64), + static_cast(0x6_big_integer64)); +} + +BOOST_AUTO_TEST_CASE(multilimb) { + BOOST_CHECK_EQUAL(static_cast(0xAFFFFFFFF_big_integer64) * + static_cast(0x2_big_integer36), + static_cast(0x15FFFFFFFE_big_integer64)); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(convert) + +// BOOST_AUTO_TEST_CASE(to_uint64_t) { +// std::uint64_t a = +// static_cast(static_cast(0x123456789ABCDEF_big_integer64)); +// BOOST_CHECK_EQUAL(a, 0x123456789ABCDEF); +// } + +// BOOST_AUTO_TEST_CASE(from_uint64_t) { +// modular_big_integer_impl a = static_cast(0x123456789ABCDEFull); +// BOOST_CHECK_EQUAL(a, static_cast(0x123456789ABCDEF_big_integer64)); +// } + +// BOOST_AUTO_TEST_CASE(from_int64_t) { +// modular_big_integer_impl a = static_cast(0x123456789ABCDEFull); +// BOOST_CHECK_EQUAL(a, static_cast(0x123456789ABCDEF_big_integer64)); +// } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/multiprecision/test/big_integer_modular_comprehensive.cpp b/crypto3/libs/multiprecision/test/big_integer_modular_comprehensive.cpp new file mode 100644 index 0000000000..51caad8499 --- /dev/null +++ b/crypto3/libs/multiprecision/test/big_integer_modular_comprehensive.cpp @@ -0,0 +1,612 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2020 Mikhail Komarov +// Copyright (c) 2020 Ilias Khairullin +// Copyright (c) 2024 Martun Karapetyan +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE big_integer_modular_comprehensive_test + +#include + +#include +#include + +// We need cpp_int to compare to it. +#include + +#include +#include +#include "nil/crypto3/multiprecision/big_integer/big_integer.hpp" + +using namespace nil::crypto3::multiprecision::literals; + +enum test_set_enum : std::size_t { + mod_e, + a_e, + b_e, + // a_add_b_e, a_sub_b_e, a_mul_b_e, a_div_b_e, a_mod_b_e, a_pow_b_e, + test_set_len +}; + +template +constexpr void pow_test(const big_integer_t& a, const big_integer_t& b, const big_integer_t& m) { + typedef nil::crypto3::multiprecision::modular_big_integer_rt + modular_number; + typedef typename big_integer_t::cpp_int_type standard_number; + + modular_number a_m(a, m); + modular_number b_m(b, m); + + standard_number a_cppint = a.to_cpp_int(); + standard_number b_cppint = b.to_cpp_int(); + standard_number m_cppint = m.to_cpp_int(); + + standard_number a_powm_b = powm(a_cppint, b_cppint, m_cppint); + // pow could be used only with modular_numbers + // modular_number a_m_pow_b_m = pow(a_m, b_m); + // powm could be used with mixed types + // TODO(ioxid): enable these + // modular_number a_m_powm_b_m = powm(a_m, b_m); + // modular_number a_m_powm_b = powm(a_m, b); + // BOOST_ASSERT_MSG(standard_number(a_m_powm_b_m.to_cpp_int()) == a_powm_b, "powm error"); + // BOOST_ASSERT_MSG(standard_number(a_m_powm_b.to_cpp_int()) == a_powm_b, "powm error"); +} + +template +bool base_operations_test(std::array test_set) { + typedef typename big_integer_t::cpp_int_type::backend_type CppIntBackend; + + typedef nil::crypto3::multiprecision::big_integer Backend_doubled; + typedef typename boost::multiprecision::default_ops::double_precision_type::type + CppIntBackend_doubled; + typedef nil::crypto3::multiprecision::modular_big_integer_rt + modular_number; + typedef boost::multiprecision::number standard_number; + typedef boost::multiprecision::number dbl_standard_number; + + // Convert from cpp_int_modular_backend to cpp_int_backend numbers. + standard_number a_cppint = test_set[a_e].to_cpp_int(); + standard_number b_cppint = test_set[b_e].to_cpp_int(); + standard_number e_cppint = test_set[mod_e].to_cpp_int(); + + dbl_standard_number a_add_b_s = + (static_cast(a_cppint) + static_cast(b_cppint)) % + e_cppint; + dbl_standard_number a_sub_b_s = (static_cast(a_cppint) - + static_cast(b_cppint) + e_cppint) % + e_cppint; + dbl_standard_number a_mul_b_s = + (static_cast(a_cppint) * static_cast(b_cppint)) % + e_cppint; + dbl_standard_number a_mod_b_s = + (static_cast(a_cppint) % static_cast(b_cppint)) % + e_cppint; + standard_number a_and_b_s = (a_cppint & b_cppint) % e_cppint; + standard_number a_or_b_s = (a_cppint | b_cppint) % e_cppint; + standard_number a_xor_b_s = (a_cppint ^ b_cppint) % e_cppint; + standard_number a_powm_b_s = powm(a_cppint, b_cppint, e_cppint); + standard_number a_bit_set_s = a_cppint; + bit_set(a_bit_set_s, 1); + a_bit_set_s %= e_cppint; + standard_number a_bit_unset_s = a_cppint; + a_bit_unset_s %= e_cppint; + bit_unset(a_bit_unset_s, 2); + standard_number a_bit_flip_s = a_cppint; + bit_flip(a_bit_flip_s, 3); + a_bit_flip_s %= e_cppint; + + int b_msb_s = msb(b_cppint); + int b_lsb_s = lsb(b_cppint); + + modular_number a(test_set[a_e], test_set[mod_e]); + modular_number b(test_set[b_e], test_set[mod_e]); + + modular_number a_add_b = a + b; + modular_number a_sub_b = a - b; + modular_number a_mul_b = a * b; + // modular_number a_and_b = a & b; + // modular_number a_or_b = a | b; + // modular_number a_xor_b = a ^ b; + // TODO(ioxid): need this one + // modular_number a_powm_b = powm(a, b); + // modular_number a_bit_set = a; + // bit_set(a_bit_set, 1); + // modular_number a_bit_unset = a; + // bit_unset(a_bit_unset, 2); + // modular_number a_bit_flip = a; + // bit_flip(a_bit_flip, 3); + + int b_msb = msb(b_cppint); + int b_lsb = lsb(b_cppint); + + // We cannot use convert_to here, because there's a bug inside boost, convert_to is constexpr, + // but it calls function generic_interconvert which is not. + BOOST_ASSERT_MSG(standard_number(a_add_b.to_cpp_int()) == a_add_b_s, "addition error"); + BOOST_ASSERT_MSG(standard_number(a_sub_b.to_cpp_int()) == a_sub_b_s, "subtraction error"); + BOOST_ASSERT_MSG(standard_number(a_mul_b.to_cpp_int()) == a_mul_b_s, "multiplication error"); + + // BOOST_ASSERT_MSG((a > b) == (a_cppint > b_cppint), "g error"); + // BOOST_ASSERT_MSG((a >= b) == (a_cppint >= b_cppint), "ge error"); + BOOST_ASSERT_MSG((a == b) == (a_cppint == b_cppint), "e error"); + // BOOST_ASSERT_MSG((a < b) == (a_cppint < b_cppint), "l error"); + // BOOST_ASSERT_MSG((a <= b) == (a_cppint <= b_cppint), "le error"); + BOOST_ASSERT_MSG((a != b) == (a_cppint != b_cppint), "ne error"); + + // BOOST_ASSERT_MSG(standard_number(a_and_b.to_cpp_int()) == a_and_b_s, "and error"); + // BOOST_ASSERT_MSG(standard_number(a_or_b.to_cpp_int()) == a_or_b_s, "or error"); + // BOOST_ASSERT_MSG(standard_number(a_xor_b.to_cpp_int()) == a_xor_b_s, "xor error"); + + // BOOST_ASSERT_MSG(standard_number(a_powm_b.to_cpp_int()) == a_powm_b_s, "powm error"); + pow_test(test_set[a_e], test_set[b_e], test_set[mod_e]); + + // BOOST_ASSERT_MSG(standard_number(a_bit_set.to_cpp_int()) == a_bit_set_s, "bit set error"); + // BOOST_ASSERT_MSG(standard_number(a_bit_unset.to_cpp_int()) == a_bit_unset_s, "bit unset + // error"); BOOST_ASSERT_MSG(standard_number(a_bit_flip.to_cpp_int()) == a_bit_flip_s, "bit flip + // error"); + + BOOST_ASSERT_MSG(b_msb_s == b_msb, "msb error"); + BOOST_ASSERT_MSG(b_lsb_s == b_lsb, "lsb error"); + + return true; +} + +template +bool base_operations_test(const std::array, N>& test_data) { + for (const auto& test_set : test_data) { + base_operations_test(test_set); + } + return true; +} + +BOOST_AUTO_TEST_SUITE(static_tests) + +BOOST_AUTO_TEST_CASE(base_ops_prime_mod_backend_130) { + using standard_number = nil::crypto3::multiprecision::big_integer<130>; + using test_set = std::array; + using test_data_t = std::array; + constexpr test_data_t test_data = {{ + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x1902d38b6904893e90b9c5b8732d1f37d_big_integer130, + 0x2b9060b88dea177d5213deb6f3794434_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x20de70b3f1426ef30b2b2c85d75e2ff2a_big_integer130, + 0x1a50227dc3bd742a232db8798e16d1fbb_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x2395c23e8da249dec864da20301b1b64a_big_integer130, + 0xdf185b46a84f318f34160415cc2cc010_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x43c06149ee7c03529dc8a03d091b4e94_big_integer130, + 0x310216180d322187af2c938af5a1ce59_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x26352a54193fd97c1b30ba3e4f624abf3_big_integer130, + 0x271cc74f6ca6cb859a1c1420922eb29ae_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x55cc328d5cc8b9d3362664a61c49d05_big_integer130, + 0x203c88f7c00196a19ca13f3956d823cf9_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x2b7b43b1d5e1d838e06ac851dd57c2921_big_integer130, + 0x1c3e4586b67511bdc48a424ab7934f3e2_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x71bff3e8b1dca8851adc38f3f7949f15_big_integer130, + 0x1aa747f949397fd5dd7c8651e8150552_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x1a2ce759cfc6960d663313054f1bb102f_big_integer130, + 0xc7a66c97d85f5662ffeebbb953476196_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x29e2517b6b554a879c74e8c4e0516f177_big_integer130, + 0x1f1218f45001011d29934c8cf15c52970_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x24633cbd7c7bfc5f2bd53ee68d61c35d2_big_integer130, + 0x144cedf22adfea125bb43d0be11ca1d0c_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0xfa48dc5dd7b4b1489220e933791b4338_big_integer130, + 0x2b234e335952ad1681afa214a74622526_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x15b8a80d1056036fb5b43afa7acf2fba1_big_integer130, + 0x20100f6e5147f7eae0dd456dcb21a8b57_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x11ad3e87c291c9ee81d50b80086315fff_big_integer130, + 0x21f4e281ab8da64819ab4c2311bb5b18e_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x1cac9e60c8ba9fe1dd02a72bd7f302986_big_integer130, + 0x1ca1068fbfa3b573d8f1f189dd5747a16_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x1ed35770d0d86801f43eeb651aff88be9_big_integer130, + 0x1906ec17bd1c75f7427c8c94bd7d1baa8_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x159635b82f84b811c9dd90d5cb6b178b_big_integer130, + 0x140f2dea986ddcb181072cb9211f57a8d_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x27d6f0f737bacbce899e43dc682b5624d_big_integer130, + 0x1011587e1de922107a18d7b925c77dd54_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x280f4c62adaa0ffd674affb50fe2e1695_big_integer130, + 0x1d094e72b514dcbf1c711fdcf3e53cb8_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x6e5882e4497adbf5bb25efec29dfc7d8_big_integer130, + 0x1a842e4abcdeedbc8abc583f41e46b125_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0xdf8e9c5a1aef9fb8a84c47e4c13a8e32_big_integer130, + 0x1a60dcd50617841662e100abea05666b4_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x1f80459133a5f8b5049a346d931edca2e_big_integer130, + 0x130fe586a5ec4e0045a6e16c4ebac2486_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x1f284be48f9037159abfc1c11bd1e06e6_big_integer130, + 0x31251cfead95629cb37cf61595785efa6_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x63766cb772cbaf3e4dfedffb2af6f181_big_integer130, + 0x311d5240457feecb26f8c0e214a1bca75_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x2ce5755bfe84b7cb37503711fe5585523_big_integer130, + 0x1f028047ad558bd3208927b6644ae2ab9_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x2bee37fdda5691f95381d391f9194f3f_big_integer130, + 0xcbba87247175168e5d40dfb270b3427a_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x9bff8375de0961c15151ff7bc1c97589_big_integer130, + 0x4ccf8b525bf3db5773680b031b007029_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x2b861409455060d7b6a5e1d5f6c652548_big_integer130, + 0x220fdc8a8d41a6ef2b2c0a1ec4569300b_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x239d57e467841c5247327e4eaa8d001f8_big_integer130, + 0x10dfd3fb5b333abdaf5529542ce52b843_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x8c555f62b02b7f2c94987bd4e0c400a4_big_integer130, + 0x326eaaaa17ba3ffef1b2622038e4277a_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x2b7199f47c784514517cb65fbc3681820_big_integer130, + 0x53368a9f4b547e43867c3b0fbbb55ba0_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x1c867f8a6c7f7ba691baba7c34c8972c0_big_integer130, + 0x18a36d27f551b90f3b70990c02be4040f_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0xe08f32c086174483eb5c0fd194284789_big_integer130, + 0x232cee45b9fafa3dd99b916f0da6b5b9f_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x2fa93bf0d7dcdd1d2490b228602c11bc4_big_integer130, + 0x313e75ddb32849fc2f920b7dac0784b8e_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0xfa23f38fe8ee768390a947885b402fbb_big_integer130, + 0x1ed41f3daece99382858b91eb9341352_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x19046693c278bc3362c21e3369d28337b_big_integer130, + 0x213100709424048752d19aaba00d597d2_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x1c50381e9fe77faacbb4625d8a73454a9_big_integer130, + 0x4c27748ded9d69446a518953eda5ea0c_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x19038fc207ecfca9a1a474489cd184a6d_big_integer130, + 0xcf46092c1d5ccf5e41dff63f92c079b9_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x248e3a01cf8cd1147bfa3e5ed0b6e4a41_big_integer130, + 0x7388310b8e62700604f76f2d45f98e52_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x282252b232f1c43f5f014529ee6e3134e_big_integer130, + 0xc324f7242a9d93665f3f3d72bf731500_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x136d5cc4b596ecbacbcbea6385708cea8_big_integer130, + 0x2eceb23b47b8beeb5cd704605f0102a27_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0xa41d7a6deba861eb210e76fedf048120_big_integer130, + 0x2b80b6fe5fce48e77bc6529a43670fa89_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0xbe044d7bc860898b4b67f2b0e47b2957_big_integer130, + 0x1385abf4521b731a0ef6585e6fcbe1087_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x15431c536a4b40b7a2def9881b3ed3f65_big_integer130, + 0x2c7a86a326513aec20b909a5b06e1d724_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x22dae6c3c21886db3a222b319df2fcc18_big_integer130, + 0x29874fcdec2d26c29d56990f86e49921e_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x1966a81455bb9ae791b06c79361cb04a9_big_integer130, + 0x1ffebba8847893384f651589275aaceb1_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x2744dda0f21e9343d45d80cf7717947c4_big_integer130, + 0x5559c5bfee5bdd51d7695f8be84aa7e0_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x217faf49e078d4f40e8bed99a20a4e3f4_big_integer130, + 0x21e2c14e9f39cfdfc87a7eddbfa8de653_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x571a667c902421037c8d855907b904fd_big_integer130, + 0x873f600a7769bf94aab70506e04d3dee_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48bb_big_integer130, + 0x662ba0a5876b6f5f448563d9194ff704_big_integer130, + 0xc88c6b7366ae5740e6860d5f1c906c00_big_integer130}, + }}; + + bool res = base_operations_test(test_data); +} + +BOOST_AUTO_TEST_CASE(base_ops_even_mod_backend_130) { + using standard_number = nil::crypto3::multiprecision::big_integer<130>; + using test_set = std::array; + using test_data_t = std::array; + constexpr test_data_t test_data = {{ + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xf6ce85e6f42595ffc6fcb50fdc3c9160_big_integer130, + 0x2f04006a57e467c0d45f180da37f9a602_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x6d9d6fed00c44c3eaa674b2b86004106_big_integer130, + 0x1f811a14b9a0ea15d873e532bb3364548_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x1f72515d6e96f189c58447d4424da9cf5_big_integer130, + 0x1cb8d94653cfbe79c97028957fd6b37d3_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x4c2fe1ff52320c73ec081a03082dfaf7_big_integer130, + 0xb156219a04e9ac54ba60ce2d79d706eb_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xb6222e4281e459f84c0bd5d77ce3493_big_integer130, + 0x32efd252fec869d766989d986cf31fc2_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x1043b1bfcefc15dbe214d68e1061d8645_big_integer130, + 0x43dede03370eb136ecbfa7ec396f0d6d_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x514c264f84ecf1c6e27d7c7c78e6b4a2_big_integer130, + 0x2e9bae255ae7a67003d91da36a76615b8_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x2ff3bee3f9723332a002b583133320c93_big_integer130, + 0x25283c79b9b1e505f159c2fe560caffc9_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x1446284dc17091cd19bf687b8bcfa8829_big_integer130, + 0xc9e35084ad8092316a3ce0b77b61b998_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xc447bb62c4287d9f409ab060dae3ae92_big_integer130, + 0x22efe8c2ac2188ad9e638d88bb4c754b5_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x313265520502bb48dceca31b17afa02f0_big_integer130, + 0x109c4589d316e8ec374c1671ed51ee911_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x2d639758db1ae7106138010f0e573079e_big_integer130, + 0x268a07bc08a254c23c9d71e3303352c1b_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x20898a292ba2360df9b8f42651f342554_big_integer130, + 0x13ea3770bbfab80ba966ddc255a419664_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x879758e1d55d9db504d0122b735255ac_big_integer130, + 0x2287b16011ef333a67b1984c1f8d2aa55_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xeff14b264f211d251f3852bd87ebeae2_big_integer130, + 0x1b5ebb5ef4a47e00cc6a801e5b383b69e_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xc2723880d0678f28cd177e8792d5ed2d_big_integer130, + 0x2a790884868d6fc5ef87d73d5b80ff46e_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x28a83dffca1513a29489e8835d244d6c5_big_integer130, + 0x15d4f2d8e0949e0aa82f178300c2da5d3_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x25ded52e8495fe687f442ab3579d22963_big_integer130, + 0x2754bb6b9fb861566833f59229e28e0b1_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x1ec91d30d83ac012534a9b7561f390be4_big_integer130, + 0x308d7237b1cfb01b5ca9fa894ae3c6c48_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xa8b175970e5266b7575376c254c5ad4_big_integer130, + 0x7bd2cb80c703ab2fe711022067a805f1_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x3068f458ab46abf38f3ab53368fefe1b3_big_integer130, + 0x44da306ee50c5462b9910fcba033ec28_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x7347fcf946c50eb24121d2695a74138_big_integer130, + 0x2cc6b5e5400509f854189e73f9e252331_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x13e5c415b09516c96134af94a77018a61_big_integer130, + 0x4b1f1e72fb30cffbef1bbe88d8d6c25_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x157cedbd74cdd229f3b43e8ab59199092_big_integer130, + 0x144db4073011653f19851e3b7231b8eb0_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xadbf28669d70f71efea08f2b7dcd3929_big_integer130, + 0x2352ba5d47b493e545238dc33f8018555_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x3118fbf21bf8820849498b777ae4369c2_big_integer130, + 0x8e3b38851b87235ab9e415c4f9973cb5_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x2d87b88301585c45369f392edad58ebbb_big_integer130, + 0x17b9f6b9257dc97b99d2b43da9a557a76_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x2836115435665dffa299a2e1dba2bc02_big_integer130, + 0x181aa88e10efd256cebb4563cbfb06436_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x4010011e94719b273a8f657daecb8154_big_integer130, + 0x16aa3735374efa31f48b9f0b63eca9f1e_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xfd82a47f158cf4773e6177c3b9087ce1_big_integer130, + 0x14686b4ba0accbb93c1fb046e69015338_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x662de620b44deb4469155819375bd2ae_big_integer130, + 0xa1a7f7e023df7165ca899d4366bbc7f5_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xd12ea24d1261fc11787313ef5906f58d_big_integer130, + 0x1c2a2731db836bc6156689cd762da9364_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x26d99465f1a39a64ef21a46d454161f24_big_integer130, + 0x27c3ed62253a11d4dc15d370704817498_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x2570d84dca037136829b41df4809e3810_big_integer130, + 0x904beba3c2f174a54466d0bed0fb581b_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x1183aa1a729def2d3c7138aae27332134_big_integer130, + 0x208bc970b97cf55008c06fc620d025053_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xd8c70b07b915682a3d9f01ea5c51d34b_big_integer130, + 0x6584051efd453ff081e2189928a9a9c4_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xa14b405e334ae992f920fb9373508696_big_integer130, + 0x104aa2d49412388ae364af54a916fb501_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xe5f1875befdf2bc34c0ef450753afb87_big_integer130, + 0x20f84732af830324ed3949c93704a0ce2_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x22dea1e18f9ec2bdb731db37bcab995ad_big_integer130, + 0x1eb896b7179ab4a60a5cfb051c4f6805b_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x322c6c9cd1a662e0a20738db589ae298_big_integer130, + 0x2872647f25d62d395a64406fdcf9ea04b_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xbfde51cd756d321a25d54a3909890edb_big_integer130, + 0xbd2e612e27d726d58a8be3a643373147_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xb63cc77f71d194b5824946e44fe21831_big_integer130, + 0x556942440de628a1b78d70b8ce61cad5_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x28b231976fbb6484e07f1c36b709811c6_big_integer130, + 0x22da443e75ea4b64e4dd5b0e701948b9a_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x2b564befbf84fb99e6d3e96a00e28a111_big_integer130, + 0x2680850f06cffc374d3c98dac2a3522ca_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x19738eb221a6b1cc01159dac5232f5f94_big_integer130, + 0x1888b0fd2c91a44559730f4772021e7ae_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x128cbc897d8a21f0924f0824cc0a2a2af_big_integer130, + 0x1667817727b346d00cfe296b83099260a_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x1176a4938cafb93365f979e0648a9b36d_big_integer130, + 0x1d424e90ed8b1d58a4e5f63a983f66b23_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0xe1d5e0b579b9ffabd79f55a3ad58095a_big_integer130, + 0x28facaa806c45f06b33f90a25a256cb57_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x29492c8c9736c8b22abbe8cc151c0bbe5_big_integer130, + 0x1e2e6cf551c64286202dbc4202eb950b4_big_integer130}, + {0x314107b9ef725f87fa08f9fdadd4f48ba_big_integer130, + 0x2d38c6d88e4be77725f5a337fadacb890_big_integer130, + 0x2b711aed3a4d108fd95d3a8c3338bf713_big_integer130}, + }}; + + bool res = base_operations_test(test_data); +} + +// This one tests 64-bit numbers used in Goldilock fields. +BOOST_AUTO_TEST_CASE(base_ops_even_mod_backend_64) { + using standard_number = nil::crypto3::multiprecision::big_integer<64>; + using test_set = std::array; + using test_data_t = std::array; + constexpr test_data_t test_data = {{ + {0xffffffff00000001_big_integer64, 0x1_big_integer64, 0x2_big_integer64}, + {0xffffffff00000001_big_integer64, 0x7fffffff91725e00_big_integer64, + 0x3fffffffe6869400_big_integer64}, + {0xffffffff00000001_big_integer64, 0x7ffaffff91745e00_big_integer64, + 0x1fafff0fe6869400_big_integer64}, + {0xffffffff00000001_big_integer64, 0x7ffaffff91745e00_big_integer64, + 0x1fafff0fe6869400_big_integer64}, + {0xffffffff00000001_big_integer64, 0x1ffaffff91745e00_big_integer64, + 0xffffffff00000000_big_integer64}, + {0xffffffff00000001_big_integer64, 0x00_big_integer64, 0x1_big_integer64}, + }}; + + bool res = base_operations_test(test_data); +} + +// BOOST_AUTO_TEST_CASE(base_ops_even_mod_backend_17) { +// using standard_number = nil::crypto3::multiprecision::big_integer<17>; +// using test_set = std::array; +// using test_data_t = std::array; +// constexpr test_data_t test_data = {{ +// {0x1e240_big_integer17, 0x3a97_big_integer17, 0xc070_big_integer17}, +// {0x1e240_big_integer17, 0x1dea7_big_integer17, 0x1aaab_big_integer17}, +// {0x1e240_big_integer17, 0x1936f_big_integer17, 0xfb0b_big_integer17}, +// {0x1e240_big_integer17, 0x13067_big_integer17, 0x1566c_big_integer17}, +// {0x1e240_big_integer17, 0x1b960_big_integer17, 0x1773f_big_integer17}, +// {0x1e240_big_integer17, 0x101e4_big_integer17, 0x156ca_big_integer17}, +// {0x1e240_big_integer17, 0x167f3_big_integer17, 0x13c52_big_integer17}, +// {0x1e240_big_integer17, 0xc536_big_integer17, 0x14c8e_big_integer17}, +// {0x1e240_big_integer17, 0xed02_big_integer17, 0x1dafc_big_integer17}, +// {0x1e240_big_integer17, 0x126a6_big_integer17, 0x18a8b_big_integer17}, +// {0x1e240_big_integer17, 0x111ac_big_integer17, 0x94c2_big_integer17}, +// {0x1e240_big_integer17, 0x3a03_big_integer17, 0x89d8_big_integer17}, +// {0x1e240_big_integer17, 0x3add_big_integer17, 0x101ae_big_integer17}, +// {0x1e240_big_integer17, 0x8db4_big_integer17, 0x50e2_big_integer17}, +// {0x1e240_big_integer17, 0x1bab_big_integer17, 0x1d5f6_big_integer17}, +// {0x1e240_big_integer17, 0x144dc_big_integer17, 0x172f8_big_integer17}, +// {0x1e240_big_integer17, 0x1cd30_big_integer17, 0x1a5c_big_integer17}, +// {0x1e240_big_integer17, 0x13c3d_big_integer17, 0x4358_big_integer17}, +// {0x1e240_big_integer17, 0x18d68_big_integer17, 0x1299d_big_integer17}, +// {0x1e240_big_integer17, 0x10153_big_integer17, 0x2c8a_big_integer17}, +// }}; + +// bool res = base_operations_test(test_data); +// } + +// BOOST_AUTO_TEST_CASE(base_ops_odd_mod_backend_17) { +// using Backend = cpp_int_modular_backend<17>; +// using standard_number = boost::multiprecision::number; +// using test_set = std::array; +// using test_data_t = std::array; +// constexpr test_data_t test_data = {{ +// {0x1e241_big_integer17, 0x3a97_big_integer17, 0xc070_big_integer17}, +// {0x1e241_big_integer17, 0x1dea7_big_integer17, 0x1aaab_big_integer17}, +// {0x1e241_big_integer17, 0x1936f_big_integer17, 0xfb0b_big_integer17}, +// {0x1e241_big_integer17, 0x13067_big_integer17, 0x1566c_big_integer17}, +// {0x1e241_big_integer17, 0x1b960_big_integer17, 0x1773f_big_integer17}, +// {0x1e241_big_integer17, 0x101e4_big_integer17, 0x156ca_big_integer17}, +// {0x1e241_big_integer17, 0x167f3_big_integer17, 0x13c52_big_integer17}, +// {0x1e241_big_integer17, 0xc536_big_integer17, 0x14c8e_big_integer17}, +// {0x1e241_big_integer17, 0xed02_big_integer17, 0x1dafc_big_integer17}, +// {0x1e241_big_integer17, 0x126a6_big_integer17, 0x18a8b_big_integer17}, +// {0x1e241_big_integer17, 0x111ac_big_integer17, 0x94c2_big_integer17}, +// {0x1e241_big_integer17, 0x3a03_big_integer17, 0x89d8_big_integer17}, +// {0x1e241_big_integer17, 0x3add_big_integer17, 0x101ae_big_integer17}, +// {0x1e241_big_integer17, 0x8db4_big_integer17, 0x50e2_big_integer17}, +// {0x1e241_big_integer17, 0x1bab_big_integer17, 0x1d5f6_big_integer17}, +// {0x1e241_big_integer17, 0x144dc_big_integer17, 0x172f8_big_integer17}, +// {0x1e241_big_integer17, 0x1cd30_big_integer17, 0x1a5c_big_integer17}, +// {0x1e241_big_integer17, 0x13c3d_big_integer17, 0x4358_big_integer17}, +// {0x1e241_big_integer17, 0x18d68_big_integer17, 0x1299d_big_integer17}, +// {0x1e241_big_integer17, 0x10153_big_integer17, 0x2c8a_big_integer17}, +// }}; + +// bool res = base_operations_test(test_data); +// } + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(runtime_tests) + +BOOST_AUTO_TEST_CASE(secp256k1_incorrect_multiplication) { + using standart_number = nil::crypto3::multiprecision::big_integer<256>; + using modular_number = nil::crypto3::multiprecision::modular_big_integer_rt<256>; + + constexpr standart_number modulus = + 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f_big_integer256; + constexpr standart_number x_standard = + 0xb5d724ce6f44c3c587867bbcb417e9eb6fa05e7e2ef029166568f14eb3161387_big_integer256; + constexpr standart_number res_standard = + 0xad6e1fcc680392abfb075838eafa513811112f14c593e0efacb6e9d0d7770b4_big_integer256; + constexpr modular_number x(x_standard, modulus); + constexpr modular_number res(res_standard, modulus); + BOOST_CHECK_EQUAL(x * x, res); +} + +BOOST_AUTO_TEST_CASE(bad_negation) { + using standart_number = nil::crypto3::multiprecision::big_integer<256>; + using modular_number = nil::crypto3::multiprecision::modular_big_integer_rt<256>; + + constexpr standart_number modulus = + 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f_big_integer256; + constexpr modular_number x(0u, modulus); + constexpr modular_number res = -x; + // TODO + // BOOST_CHECK(res == 0u); + BOOST_CHECK(res == x); + BOOST_CHECK(-res == x); +} + +BOOST_AUTO_TEST_CASE(conversion_to_shorter_number) { + using standart_number = nil::crypto3::multiprecision::big_integer<256>; + using short_number = nil::crypto3::multiprecision::big_integer<128>; + constexpr standart_number x = + 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f_big_integer256; + short_number s = x; + // 2nd half of the number must stay. + BOOST_CHECK_EQUAL(s, 0xfffffffffffffffffffffffefffffc2f_big_integer128); +} + +BOOST_AUTO_TEST_SUITE_END()