diff --git a/doc/multiprecision.qbk b/doc/multiprecision.qbk index aff15bf39..6eb758f7b 100644 --- a/doc/multiprecision.qbk +++ b/doc/multiprecision.qbk @@ -5998,7 +5998,19 @@ Open question - what should be the default - int32_t or int64_t? (done 2012/09/ [[Why not abstract out addition/multiplication algorithms?] [This was deemed not to be practical: these algorithms are intimately tied to the actual data representation used.]] -] + [[How do I choose between Boost.Multiprecision cpp_bin_50 and cpp_dec_50?] + [Unless you have a specific reason to choose `cpp_dec_`, then the default choice should be `cpp_bin_`, + for example using the convenience `typedefs` like `boost::multiprecision::cpp_bin_50` or `boost::multiprecision::cpp_bin_100`. + + In general, both work well and give the same results and at roughly the same speed with `cpp_dec_50` sometimes faster. + + `cpp_dec_` was developed first paving the way for `cpp_bin_`. + `cpp_dec_` has several guard digits and is not rounded at all, using 'brute force' to get the promised number of decimal digits correct, + but making it difficult to reason about precision and computational uncertainty, for example see [*https://svn.boost.org/trac10/ticket/12133]. + It also has a fast but imprecise division operator giving surprising results sometimes, see [*https://svn.boost.org/trac10/ticket/11178]. + + `cpp_bin_` is correctly/exactly rounded making it possible to reason about both the precision and rounding of the results.]] +] [/variablelist] [endsect] diff --git a/include/boost/multiprecision/detail/default_ops.hpp b/include/boost/multiprecision/detail/default_ops.hpp index 145ecc672..459092c7e 100644 --- a/include/boost/multiprecision/detail/default_ops.hpp +++ b/include/boost/multiprecision/detail/default_ops.hpp @@ -824,6 +824,15 @@ inline int eval_get_sign(const T& val) return val.compare(static_cast(0)); } +template +inline void assign_components_imp(T& result, const long long& v1, const U& v2, const mpl::int_&) +{ + result.m_params = v2; + result = v1; + eval_multiply(result, v2.R2().backend()); + //eval_multiply(result, v1); +} + template inline void assign_components_imp(T& result, const V& v1, const U& v2, const mpl::int_&) { @@ -837,7 +846,6 @@ template inline void assign_components_imp(T& result, const V& v1, const U& v2, const mpl::int_&) { typedef typename component_type >::type component_number_type; - component_number_type x(v1), y(v2); assign_components(result, x.backend(), y.backend()); } diff --git a/include/boost/multiprecision/detail/number_base.hpp b/include/boost/multiprecision/detail/number_base.hpp index cb2951570..685e0fe9c 100644 --- a/include/boost/multiprecision/detail/number_base.hpp +++ b/include/boost/multiprecision/detail/number_base.hpp @@ -1546,7 +1546,8 @@ enum number_category_type number_kind_floating_point = 1, number_kind_rational = 2, number_kind_fixed_point = 3, - number_kind_complex = 4 + number_kind_complex = 4, + number_kind_modulus = 5 }; template diff --git a/include/boost/multiprecision/inverse_euclid.hpp b/include/boost/multiprecision/inverse_euclid.hpp new file mode 100644 index 000000000..0ab37aff6 --- /dev/null +++ b/include/boost/multiprecision/inverse_euclid.hpp @@ -0,0 +1,103 @@ +#ifndef CRYPTO3_INVERSE_EUCLID_HPP +#define CRYPTO3_INVERSE_EUCLID_HPP + +#include + +namespace nil { + namespace crypto3 { + using namespace boost::multiprecision; + + template + inline Backend eval_inverse_euclid(const Backend &n, const Backend &mod) { + + typedef typename default_ops::double_precision_type::type double_type; + typedef typename boost::multiprecision::detail::canonical::type ui_type; + + using default_ops::eval_is_zero; + using default_ops::eval_lt; + using default_ops::eval_eq; + using default_ops::eval_add; + using default_ops::eval_subtract; + using default_ops::eval_get_sign; + using default_ops::eval_right_shift; + using default_ops::eval_integer_modulus; + + if (eval_is_zero(mod)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("inverse_mod: arguments must be non-zero")); + } + if (eval_get_sign(mod) || eval_get_sign(n)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("inverse_mod: arguments must be non-negative")); + } + + if (eval_is_zero(n) || (!eval_integer_modulus(n, 2) && !eval_integer_modulus(mod, 2))) { + return 0; + } // fast fail checks + + number u = mod, v = n; + number a = 1, b = 0, c = 0, d = 1; + + while (!eval_is_zero(u)) { + const ui_type u_zero_bits = lsb(u); + eval_right_shift(u, u_zero_bits); + + for (std::size_t i = 0; i != u_zero_bits; ++i) { + if (eval_integer_modulus(a, 2) || eval_integer_modulus(b, 2)) { + eval_add(a, n); + eval_subtract(b, mod); + } + eval_right_shift(a, 1); + eval_right_shift(b, 1); + } + + const ui_type v_zero_bits = lsb(v); + eval_right_shift(v, v_zero_bits); + for (size_t i = 0; i != v_zero_bits; ++i) { + if (eval_integer_modulus(c, 2) || eval_integer_modulus(d, 2)) { + eval_add(c, n); + eval_subtract(d, mod); + } + eval_right_shift(c, 1); + eval_right_shift(d, 1); + } + + if (!eval_lt(u, v)) { + eval_subtract(u, v); + eval_subtract(a, c); + eval_subtract(b, d); + } else { + eval_subtract(v, u); + eval_subtract(c, a); + eval_subtract(d, b); + } + } + + if (!eval_eq(v, 1)) { + return 0; + } // no modular inverse + + while (eval_lt(d, 0)) { + eval_add(d, mod); + } + while (d >= mod) { + eval_subtract(d, mod); + } + + return d; + } + + /** + * Modular inversion using extended binary Euclidian algorithm + * @param x a positive integer + * @param modulus a positive integer + * @return y st (x*y) % modulus == 1 or 0 if no such value + * @note Non-const time + */ + template + inline number inverse_euclid(const number &n, + const number &mod) { + return number(eval_inverse_euclid(n.backend(), mod.backend())); + } + } +} + +#endif //CRYPTO3_INVERSE_EUCLID_HPP diff --git a/include/boost/multiprecision/jacobi.hpp b/include/boost/multiprecision/jacobi.hpp new file mode 100644 index 000000000..f11c90727 --- /dev/null +++ b/include/boost/multiprecision/jacobi.hpp @@ -0,0 +1,82 @@ +#ifndef CRYPTO3_JACOBI_HPP +#define CRYPTO3_JACOBI_HPP + +#include + +namespace nil { + namespace crypto3 { + using namespace boost::multiprecision; + + template + inline limb_type eval_jacobi(const Backend &a, const Backend &n) { + using default_ops::eval_is_zero; + using default_ops::eval_lt; + using default_ops::eval_lsb; + using default_ops::eval_gt; + using default_ops::eval_integer_modulus; + using default_ops::eval_modulus; + using default_ops::eval_right_shift; + using default_ops::eval_get_sign; + + if (eval_get_sign(a) < 0) { + BOOST_THROW_EXCEPTION(std::invalid_argument("jacobi: first argument must be non-negative")); + } + if (!eval_integer_modulus(n, 2) || eval_lt(n, 2)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("jacobi: second argument must be odd and > 1")); + } + + Backend x = a, y = n; + limb_type J = 1; + + while (eval_gt(y, 1)) { + eval_modulus(x, y); + + Backend yd2 = y; + eval_divide(yd2, 2); + + if (eval_gt(x, yd2)) { + eval_subtract(x, y, x); + if (eval_integer_modulus(y, 4) == 3) { + J = -J; + } + } + if (eval_is_zero(x)) { + return 0; + } + + size_t shifts = eval_lsb(x); + eval_right_shift(x, shifts); + if (eval_integer_modulus(shifts, 2)) { + limb_type 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); + } + return J; + } + + /** + * Compute the Jacobi symbol. If n is prime, this is equivalent + * to the Legendre symbol. + * @see http://mathworld.wolfram.com/JacobiSymbol.html + * + * @param a is a non-negative integer + * @param n is an odd integer > 1 + * @return (n / m) + */ + template + inline typename std::enable_if::value == number_kind_integer, limb_type>::type jacobi( + const number &a, const number &n) { + return number(eval_jacobi(a.backend(), n.backend())); + } + } +} + +#endif //CRYPTO3_JACOBI_HPP \ No newline at end of file diff --git a/include/boost/multiprecision/mask_bits.hpp b/include/boost/multiprecision/mask_bits.hpp new file mode 100644 index 000000000..e83140763 --- /dev/null +++ b/include/boost/multiprecision/mask_bits.hpp @@ -0,0 +1,37 @@ +#ifndef CRYPTO3_MASK_BITS_HPP +#define CRYPTO3_MASK_BITS_HPP + +#include +#include +#include + +namespace nil { + namespace crypto3 { + + template + void eval_mask_bits(Backend &val, Integer n) { + typedef typename boost::multiprecision::limb_type limb_type; + + typedef typename boost::multiprecision::detail::canonical::type ui_type; + static const ui_type zero = 0u; + + if (n == 0) { + val = zero; + return; + } + + const size_t top_word = n / Backend::limb_bits; + const limb_type mask = (limb_type(1) << (n % Backend::limb_bits)) - 1; + + if (top_word < val.size()) { + const size_t len = val.size() - (top_word + 1); + if (len > 0) { + //clear_mem(&val.limbs()[top_word + 1], len); #TODO return this + } + val.limbs()[top_word] &= mask; + } + } + } +} + +#endif //CRYPTO3_MASK_BITS_HPP diff --git a/include/boost/multiprecision/modular_inverse.hpp b/include/boost/multiprecision/modular_inverse.hpp new file mode 100644 index 000000000..11c8edb76 --- /dev/null +++ b/include/boost/multiprecision/modular_inverse.hpp @@ -0,0 +1,179 @@ +#ifndef CRYPTO3_MOD_INVERSE_HPP +#define CRYPTO3_MOD_INVERSE_HPP + +#include + +#include + +#include + +namespace nil { + namespace crypto3 { + using namespace boost::multiprecision; + + template + inline Backend eval_ct_inverse_mod_odd_modulus(const Backend &n, const Backend &mod) { + + typedef typename default_ops::double_precision_type::type double_type; + typedef typename boost::multiprecision::detail::canonical::type ui_type; + + using default_ops::eval_is_zero; + using default_ops::eval_lt; + using default_ops::eval_eq; + using default_ops::eval_get_sign; + using default_ops::eval_integer_modulus; + using default_ops::eval_msb; + using default_ops::eval_add; + using default_ops::eval_multiply; + using default_ops::eval_multiply_add; + using default_ops::eval_multiply_subtract; + using default_ops::eval_right_shift; + + typedef cpp_int_backend<0, 0, Backend::integer_type, Backend::checked_type, + secure_allocator> secure_cpp_int_backend; + + if (eval_get_sign(n) < 0 || eval_get_sign(mod) < 0) { + BOOST_THROW_EXCEPTION(std::invalid_argument("ct_inverse_mod_odd_modulus: arguments must be " + "non-negative")); + } + + if (eval_lt(mod, 3) || !eval_integer_modulus(mod, 2)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("Bad modulus to ct_inverse_mod_odd_modulus")); + } + if (!eval_lt(n, mod)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("ct_inverse_mod_odd_modulus n >= mod not supported")); + } + + /* + This uses a modular inversion algorithm designed by Niels Möller + and implemented in Nettle. The same algorithm was later also + adapted to GMP in mpn_sec_invert. + + It can be easily implemented in a way that does not depend on + secret branches or memory lookups, providing resistance against + some forms of side channel attack. + + There is also a description of the algorithm in Appendix 5 of "Fast + Software Polynomial Multiplication on ARM Processors using the NEON Engine" + by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo + Dahab in LNCS 8182 + https://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf + + Thanks to Niels for creating the algorithm, explaining some things + about it, and the reference to the paper. + */ + + secure_cpp_int_backend mp1, mp1o2; + eval_add(mod, 1); + eval_right_shift(mp1o2, mp1, 1); + + // todo allow this to be pre-calculated and passed in as arg + + const size_t mod_words = mod.size(); + CRYPTO3_ASSERT(mod_words > 0, "Not empty"); + + secure_cpp_int_backend a = n; + secure_cpp_int_backend b = mod; + secure_cpp_int_backend u = 1, v = 0; + + ct::poison(a.limbs(), a.size()); + ct::poison(b.limbs(), b.size()); + ct::poison(u.limbs(), u.size()); + ct::poison(v.limbs(), v.size()); + + // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n + ui_type bits = 2ul * eval_msb(mod); + + while (bits--) { + const bool odd = eval_integer_modulus(a, 2); + eval_multiply_subtract(a, odd, b); + + const bool underflow = eval_get_sign(a) < 0; + eval_multiply_add(b, a, underflow); + + if (eval_get_sign(a) < 0) { + eval_multiply(a, -1); + } + + eval_right_shift(a, 1); + + if (underflow) { + std::swap(u, v); + } + + eval_multiply_subtract(u, odd, v); + eval_multiply_add(u, eval_get_sign(u) < 0, mod); + + eval_right_shift(u, 1); + eval_multiply_add(u, mp1o2, eval_integer_modulus(u, 2)); + } + + ct::unpoison(a.limbs(), a.size()); + ct::unpoison(b.limbs(), b.size()); + ct::unpoison(u.limbs(), u.size()); + ct::unpoison(v.limbs(), v.size()); + + CRYPTO3_ASSERT(eval_is_zero(a), "A is zero"); + + if (!eval_eq(b, 1)) { + return 0; + } + + return v; + } + + template + inline Backend eval_inverse_mod(const Backend &x, const Backend &mod) { + using default_ops::eval_is_zero; + using default_ops::eval_lt; + using default_ops::eval_get_sign; + + if (eval_is_zero(mod)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("eval_inverse_mod: zero division")); + } + if (eval_get_sign(mod) < 0 || eval_get_sign(x) < 0) { + BOOST_THROW_EXCEPTION(std::invalid_argument("eval_inverse_mod: arguments must be non-negative")); + } + + if (eval_is_zero(x) || + (!eval_is_zero(eval_integer_modulus(x, 2)) && !eval_is_zero(eval_integer_modulus(mod, 2)))) { + return 0; + } // fast fail checks + + if (!eval_is_zero(eval_integer_modulus(mod, 2)) && eval_lt(x, mod)) { + return ct_inverse_mod_odd_modulus(x, mod); + } + + return eval_inverse_euclid(x, mod); + } + + /** + * @brief Modular inversion + * @param x a positive integer + * @param mod a positive integer + * @return y st (x*y) % modulus == 1 or 0 if no such value + * @note Non-const time + */ + template + inline number inverse_mod(const number &x, + const number &mod) { + return eval_inverse_mod(x.backend(), mod.backend()); + } + + /** + * @brief Const time modular inversion + * + * @param n + * @param mod + * + * @note Requires the modulus be odd + */ + template + inline number ct_inverse_mod_odd_modulus( + const number &n, const number &mod) { + return number(eval_ct_inverse_mod_odd_modulus(n.backend(), mod.backend())); + } + } +} + +#endif //CRYPTO3_MOD_INVERSE_HPP diff --git a/include/boost/multiprecision/montgomery_int/add.hpp b/include/boost/multiprecision/montgomery_int/add.hpp new file mode 100644 index 000000000..ec274df11 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/add.hpp @@ -0,0 +1,573 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_ADD_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_ADD_HPP + +namespace boost { + namespace multiprecision { + namespace backends { + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif + + +// +// Now the actual functions called by the front end, all of which forward to one of the above: +// + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_add(montgomery_int_backend &result, + const Backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + eval_add(result, result, o); + } + + template class Backend1, + template< unsigned, unsigned, cpp_integer_type, cpp_int_check_type, typename, typename> class Backend2, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, + class Allocator3, typename ParamsBackend3> + inline typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend1 >::value && !is_trivial_montgomery_int< + Backend2 >::value && + is_equal_montgomery_int_backend>::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_add(montgomery_int_backend &result, + const Backend1 &a, + const Backend2 &b) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (a.sign() != b.sign()) { + subtract_unsigned(result, a, b); + return; + } + add_unsigned(result, a, b); + eval_divide(result, result.m_params.p().backend()); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_add(montgomery_int_backend &result, + const limb_type &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (result.sign()) { + subtract_unsigned(result, result, o); + } else { + add_unsigned(result, result, o); + } + eval_divide(result, result.m_params.p().backend()); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_add(montgomery_int_backend &result, + const Backend &a, + const limb_type &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (a.sign()) { + subtract_unsigned(result, a, o); + } else { + add_unsigned(result, a, o); + } + eval_divide(result, result.m_params.p().backend()); + } + + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_add(montgomery_int_backend &result, + const signed_limb_type &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (o < 0) { + eval_subtract(result, static_cast(boost::multiprecision::detail::unsigned_abs(o))); + } else if (o > 0) { + eval_add(result, static_cast(o)); + } + eval_divide(result, result.m_params.p().backend()); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_add(montgomery_int_backend &result, + const Backend &a, + const signed_limb_type &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (o < 0) { + eval_subtract(result, a, static_cast + (boost::multiprecision::detail::unsigned_abs(o))); + } else if (o > 0) { + eval_add(result, a, static_cast + (o)); + } else if (&result != &a) { + result = a; + eval_divide(result, result.m_params.p().backend()); + } + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_subtract(montgomery_int_backend &result, + const limb_type &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (result.sign()) { + add_unsigned(result, result, o); + } else { + subtract_unsigned(result, result, o); + } + eval_divide(result, result.m_params.p().backend()); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_subtract(montgomery_int_backend &result, + const Backend &a, + const limb_type &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (a.sign()) { + add_unsigned(result, a, o); + } else { + subtract_unsigned(result, a, o); + } + eval_divide(result, result.m_params.p().backend()); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_subtract(montgomery_int_backend &result, + const signed_limb_type &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (o) { + if (o < 0) { + eval_add(result, static_cast(boost::multiprecision::detail::unsigned_abs(o))); + } else { + eval_subtract(result, static_cast(o)); + } + } + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_subtract(montgomery_int_backend &result, + const Backend &a, + const signed_limb_type &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (o) { + if (o < 0) { + eval_add(result, a, static_cast(boost::multiprecision::detail::unsigned_abs(o))); + } else { + eval_subtract(result, a, static_cast(o)); + } + } else if (&result != &a) { + result = a; + eval_divide(result, result.m_params.p().backend()); + } + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_increment(montgomery_int_backend &result) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + static const limb_type one = 1; + if (!result.sign() && (result.limbs()[0] < + montgomery_int_backend::max_limb_value)) { + ++result.limbs()[0]; + eval_divide(result, result.m_params.p().backend()); + } else if (result.sign() && result.limbs()[0]) { + --result.limbs()[0]; + eval_divide(result, result.m_params.p().backend()); + } else { + eval_add(result, one); + } + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_decrement(montgomery_int_backend &result) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + static const limb_type one = 1; + if (!result.sign() && result.limbs()[0]) { + --result.limbs()[0]; + eval_divide(result, result.m_params.p().backend()); + } else if (result.sign() && (result.limbs()[0] < + montgomery_int_backend::max_limb_value)) { + ++result.limbs()[0]; + eval_divide(result, result.m_params.p().backend()); + } else { + eval_subtract(result, one); + } + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_subtract(montgomery_int_backend &result, + const Backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + eval_subtract(result, result, o); + } + + template class Backend1, + template< unsigned, unsigned, cpp_integer_type, cpp_int_check_type, typename, typename> class Backend2, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, + class Allocator3, typename ParamsBackend3> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend1 >::value && + !is_trivial_montgomery_int< + Backend2 >::value && + is_equal_montgomery_int_backend>::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_subtract(montgomery_int_backend &result, + const Backend1 &a, + const Backend2 &b) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (a.sign() != b.sign()) { + add_unsigned(result, a, b); + eval_divide(result, result.m_params.p().backend()); + return; + } + subtract_unsigned(result, a, b); + eval_divide(result, result.m_params.p().backend()); + } + +// +// Simple addition and subtraction routine for trivial cpp_int's come last: +// +// One of the arguments is signed: +// + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + inline typename enable_if_c >::value && + is_trivial_montgomery_int< + montgomery_int_backend >::value && (is_signed_number< + montgomery_int_backend >::value || + is_signed_number< + montgomery_int_backend< + MinBits1, MaxBits1, + SignType1, Checked1, + Allocator1, ParamsBackend1> >::value) && + is_trivial_montgomery_int< + Backend >::value && + is_trivial_montgomery_int< + Backend >::value && (is_signed_number< + Backend >::value || + is_signed_number< + Backend< + MinBits1, MaxBits1, + SignType1, Checked1, + Allocator1, ParamsBackend1> >::value) && + is_equal_montgomery_int_backend>::value> + + ::type eval_add(montgomery_int_backend &result, + const Backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (result.sign() != o.sign()) { + if (*o.limbs() > *result.limbs()) { + *result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), + typename montgomery_int_backend::checked_type()); + + result.negate(); + } else { + *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), + typename montgomery_int_backend::checked_type()); + } + } else { + *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), + typename montgomery_int_backend::checked_type()); + } + + result.normalize(); + eval_divide(result, result.m_params.p().backend()); + } + +// Simple version for two unsigned arguments: + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + is_trivial_montgomery_int< + montgomery_int_backend >::value && + is_unsigned_number< + montgomery_int_backend >::value && + is_unsigned_number< + montgomery_int_backend >::value && + is_trivial_montgomery_int< + Backend >::value && + is_trivial_montgomery_int< + Backend >::value && + is_unsigned_number< + Backend >::value && + is_unsigned_number< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_add(montgomery_int_backend &result, + const Backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), + typename montgomery_int_backend::checked_type()); + + result.normalize(); + eval_divide(result, result.m_params.p().backend()); + } + +// signed subtraction: + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + inline typename enable_if_c >::value && + is_trivial_montgomery_int< + montgomery_int_backend >::value && (is_signed_number< + montgomery_int_backend >::value || + is_signed_number< + montgomery_int_backend< + MinBits1, MaxBits1, + SignType1, Checked1, + Allocator1, ParamsBackend1> >::value) && + is_trivial_montgomery_int< + Backend >::value && + is_trivial_montgomery_int< + Backend >::value && (is_signed_number< + Backend >::value || + is_signed_number< + Backend< + MinBits1, MaxBits1, + SignType1, Checked1, + Allocator1, ParamsBackend1> >::value) && + is_equal_montgomery_int_backend>::value> + + ::type eval_subtract(montgomery_int_backend &result, + const Backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + if (result.sign() != o.sign()) { + *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), + typename montgomery_int_backend::checked_type()); + } else if (*result.limbs() < *o.limbs()) { + *result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), + typename montgomery_int_backend::checked_type()); + + result.negate(); + } else { + *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), + typename montgomery_int_backend::checked_type()); + } + + result.normalize(); + eval_divide(result, result.m_params.p().backend()); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + is_trivial_montgomery_int< + montgomery_int_backend >::value && + is_unsigned_number< + montgomery_int_backend >::value && + is_unsigned_number< + montgomery_int_backend >::value && + is_trivial_montgomery_int< + Backend >::value && + is_trivial_montgomery_int< + Backend >::value && + is_unsigned_number< + Backend >::value && + is_unsigned_number< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_subtract(montgomery_int_backend &result, + const Backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), + typename montgomery_int_backend::checked_type()); + + result.normalize(); + eval_divide(result, result.m_params.p().backend()); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend>::value> + + ::type eval_subtract(montgomery_int_backend &result, + const Backend &o) + { + int x = 0; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend1>::value> + ::type eval_subtract(montgomery_int_backend &result, + const Backend1 &a, const Backend2 &b) + { + int x = 0; + } + + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + } + } +} // namespaces + +#endif \ No newline at end of file diff --git a/include/boost/multiprecision/montgomery_int/bitwise.hpp b/include/boost/multiprecision/montgomery_int/bitwise.hpp new file mode 100644 index 000000000..52e52704a --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/bitwise.hpp @@ -0,0 +1,605 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_BIT_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_BIT_HPP + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4319) +#endif + +namespace boost { + namespace multiprecision { + namespace backends { + + template + void is_valid_bitwise_op(montgomery_int_backend &result, + const montgomery_int_backend &o, + const mpl::int_ &) { + if (result.sign() || o.sign()) { + BOOST_THROW_EXCEPTION( + std::range_error("Bitwise operations on negative values results in undefined behavior.")); + } + } + + template + void is_valid_bitwise_op(montgomery_int_backend &, + const montgomery_int_backend &, + const mpl::int_ &) { + } + + template + void is_valid_bitwise_op( + const montgomery_int_backend &result, + const mpl::int_ &) { + if (result.sign()) { + BOOST_THROW_EXCEPTION( + std::range_error("Bitwise operations on negative values results in undefined behavior.")); + } + } + + template + void is_valid_bitwise_op( + const montgomery_int_backend &, + const mpl::int_ &) { + } + + template + void is_valid_bitwise_op(montgomery_int_backend &, + const mpl::int_ &) { + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_bitwise_and(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + bitwise_op(result, o, bit_and(), mpl::bool_ > >::is_signed || + std::numeric_limits< + number>>::is_signed>()); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_bitwise_or(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + bitwise_op(result, o, bit_or(), mpl::bool_ > >::is_signed || + std::numeric_limits< + number>>::is_signed>()); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_bitwise_xor(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + bitwise_op(result, o, bit_xor(), mpl::bool_ > >::is_signed || + std::numeric_limits< + number>>::is_signed>()); + } + +// +// Again for operands which are single limbs: +// + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + ::type eval_bitwise_and( + montgomery_int_backend &result, limb_type + l) BOOST_NOEXCEPT { + result.limbs()[0] &= l; + result.resize(1, 1); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_bitwise_or( + montgomery_int_backend &result, limb_type l) + + BOOST_NOEXCEPT { + result.limbs()[0] |= l; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_bitwise_xor( + montgomery_int_backend &result, limb_type l) + + BOOST_NOEXCEPT { + result.limbs()[0] ^= l; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_signed_number >::value && + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_complement(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), + "Attempt to take the complement of a signed type results in undefined behavior."); +// Increment and negate: + result = o; + eval_increment(result); + result.negate(); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_unsigned_number >::value && + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_complement(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + unsigned os = o.size(); + result.resize(UINT_MAX, os); + for (unsigned i = 0; i < os; ++i) { + result.limbs()[i] = ~o.limbs()[i]; + } + + for (unsigned i = os; i < result.size(); ++i) { + result.limbs()[i] = ~static_cast(0); + } + + result.normalize(); + } + + template + inline typename enable_if_c< + !is_trivial_montgomery_int >::value> + + ::type eval_left_shift(montgomery_int_backend &result, + double_limb_type s) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + is_valid_bitwise_op(result, + + typename montgomery_int_backend::checked_type() + + ); + if (!s) { + return; + } + +#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT) + static const limb_type limb_shift_mask = montgomery_int_backend::limb_bits - 1; + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if((s & limb_shift_mask) == 0) + { + left_shift_limb(result, s); + } + else if((s & byte_shift_mask) == 0) + { + left_shift_byte(result, s); + } +#elif defined(BOOST_LITTLE_ENDIAN) + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if ((s & byte_shift_mask) == 0) { + left_shift_byte(result, s); + } +#else + static const limb_type limb_shift_mask = + montgomery_int_backend::limb_bits - 1; + if (( + s &limb_shift_mask + ) == 0) + { + left_shift_limb(result, s + ); + } +#endif + else { + left_shift_generic(result, s); + } +// +// We may have shifted off the end and have leading zeros: +// + result.normalize(); + } + template + inline typename enable_if_c >::value> + + ::type eval_right_shift( + montgomery_int_backend &result, + double_limb_type s) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + is_valid_bitwise_op(result, + + typename montgomery_int_backend::checked_type() + + ); + if (!s) { + return; + } + +#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT) + static const limb_type limb_shift_mask = montgomery_int_backend::limb_bits - 1; + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if((s & limb_shift_mask) == 0) + right_shift_limb(result, s); + else if((s & byte_shift_mask) == 0) + right_shift_byte(result, s); +#elif defined(BOOST_LITTLE_ENDIAN) + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if ((s & byte_shift_mask) == 0) { + right_shift_byte(result, s); + } +#else + static const limb_type limb_shift_mask = + montgomery_int_backend::limb_bits - 1; + if ((s &limb_shift_mask) == 0) { + right_shift_limb(result, s); + } +#endif + else { + right_shift_generic(result, s); + } + } + + template + inline typename enable_if_c >::value> + + ::type eval_right_shift(montgomery_int_backend &result, + double_limb_type s) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + is_valid_bitwise_op(result, typename montgomery_int_backend::checked_type()); + if (!s) { + return; + } + + bool is_neg = result.sign(); + if (is_neg) { + eval_increment(result); + } + +#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT) + static const limb_type limb_shift_mask = montgomery_int_backend::limb_bits - 1; + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if((s & limb_shift_mask) == 0) + right_shift_limb(result, s); + else if((s & byte_shift_mask) == 0) + right_shift_byte(result, s); +#elif defined(BOOST_LITTLE_ENDIAN) + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if ((s & byte_shift_mask) == 0) { + right_shift_byte(result, s); + } +#else + static const limb_type limb_shift_mask = + montgomery_int_backend::limb_bits - 1; + if ((s &limb_shift_mask) == 0) { + right_shift_limb(result, s); + } +#endif + else { + right_shift_generic(result, s); + } + if (is_neg) { + eval_decrement(result); + } + } + +// +// Over again for trivial cpp_int's: +// + template BOOST_MP_FORCEINLINE typename enable_if< + is_trivial_montgomery_int < montgomery_int_backend > > + + ::type eval_left_shift(montgomery_int_backend &result, T s) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + is_valid_bitwise_op(result,typename montgomery_int_backend::checked_type()); + *result.limbs() = detail::checked_left_shift(*result.limbs(), s, + typename montgomery_int_backend::checked_type()); + + result.normalize(); + } + + template BOOST_MP_FORCEINLINE typename enable_if< + is_trivial_montgomery_int < montgomery_int_backend > > + + ::type eval_right_shift(montgomery_int_backend &result, T s) + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { +// Nothing to check here... just make sure we don't invoke undefined behavior: + is_valid_bitwise_op(result, typename montgomery_int_backend::checked_type()); + *result.limbs() = (static_cast(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : (result.sign + () ? ((--*result.limbs()) >> s) + 1 : *result.limbs()>> s); + + if (result.sign() && (*result.limbs() == 0)) { + result = static_cast(-1); + } + } + + template + inline typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + (is_signed_number >::value || + is_signed_number >::value)> + + ::type eval_complement(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), + "Attempt to take the complement of a signed type results in undefined behavior."); +// +// If we're not checked then emulate 2's complement behavior: +// + if (o.sign()) { + *result.limbs() = *o.limbs() - 1; + + result.sign(false); + } else { + *result.limbs() = 1 + *o.limbs(); + + result.sign(true); + } + result.normalize(); + } + + template + inline typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + is_unsigned_number >::value && + is_unsigned_number >::value> + + ::type eval_complement(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + *result.limbs() = ~*o.limbs(); + + result.normalize(); + } + + template + inline typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + is_unsigned_number >::value && + is_unsigned_number >::value> + + ::type eval_bitwise_and(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + *result.limbs() &= *o.limbs(); + } + + template + inline typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + (is_signed_number >::value || + is_signed_number >::value)> + + ::type eval_bitwise_and(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + is_valid_bitwise_op(result, o, + + typename montgomery_int_backend::checked_type() + + ); + + using default_ops::eval_bit_test; + using default_ops::eval_increment; + + if (result.sign() || o.sign()) { + static const unsigned m = static_unsigned_max::value, + static_unsigned_max::value>::value; + montgomery_int_backend t1(result); + montgomery_int_backend t2(o); + eval_bitwise_and(t1, t2); + bool s = eval_bit_test(t1, m + 1); + if (s) { + eval_complement(t1, t1); + eval_increment(t1); + } + result = t1; + result.sign(s); + } else { + *result.limbs() &= *o.limbs(); + } + } + + template + inline typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + is_unsigned_number >::value && + is_unsigned_number >::value> + + ::type eval_bitwise_or(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + *result.limbs() |= *o.limbs(); + } + + template + inline typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + (is_signed_number >::value || + is_signed_number >::value)> + + ::type eval_bitwise_or(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + is_valid_bitwise_op(result, o, + + typename montgomery_int_backend::checked_type() + + ); + + using default_ops::eval_bit_test; + using default_ops::eval_increment; + + if (result.sign() || o.sign()) { + static const unsigned m = static_unsigned_max::value, + static_unsigned_max::value>::value; + montgomery_int_backend t1(result); + montgomery_int_backend t2(o); + eval_bitwise_or(t1, t2); + bool s = eval_bit_test(t1, m + 1); + if (s) { + eval_complement(t1, t1); + eval_increment(t1); + } + result = t1; + result.sign(s); + } else { + *result.limbs() |= *o.limbs(); + result.normalize(); + } + } + + template + inline typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + is_unsigned_number >::value && + is_unsigned_number >::value> + + ::type eval_bitwise_xor(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + *result.limbs() ^= *o.limbs(); + } + + template + inline typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + (is_signed_number >::value || + is_signed_number >::value)> + + ::type eval_bitwise_xor(montgomery_int_backend &result, + const montgomery_int_backend &o) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + is_valid_bitwise_op(result, o, typename montgomery_int_backend::checked_type()); + + using default_ops::eval_bit_test; + using default_ops::eval_increment; + + if (result.sign() || o.sign()) { + static const unsigned m = static_unsigned_max::value, + static_unsigned_max::value>::value; + montgomery_int_backend t1(result); + montgomery_int_backend t2(o); + eval_bitwise_xor(t1, t2); + bool s = eval_bit_test(t1, m + 1); + if (s) { + eval_complement(t1, t1); + eval_increment(t1); + } + result = t1; + result.sign(s); + } else { + *result.limbs() ^= *o.limbs(); + } + } + } + } +} // namespaces + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/include/boost/multiprecision/montgomery_int/comparison.hpp b/include/boost/multiprecision/montgomery_int/comparison.hpp new file mode 100644 index 000000000..b02c1cf80 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/comparison.hpp @@ -0,0 +1,479 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_COMPARISON_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_COMPARISON_HPP + +#include + +namespace boost { + namespace multiprecision { + + namespace backends { + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4018 4389 4996) +#endif + +// +// Start with non-trivial cpp_int's: +// + template class Backend, + unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, typename ParamsBackend> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_eq(const montgomery_int_backend &a, + const Backend &b) BOOST_NOEXCEPT { +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600) + return (a.sign() == b.sign()) + && (a.size() == b.size()) + && std::equal(a.limbs(), a.limbs() + a.size(), + stdext::checked_array_iterator::const_limb_pointer>(b.limbs(), b.size())); +#else + return (a.sign() == b.sign()) && (a.size() == b.size()) && + std::equal(a.limbs(), a.limbs() + a.size(), b.limbs()); +#endif + } + + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_eq(const montgomery_int_backend &a, + const Backend &b) BOOST_NOEXCEPT { +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600) + return (a.sign() == b.sign()) + && (a.size() == b.size()) + && std::equal(a.limbs(), a.limbs() + a.size(), stdext::checked_array_iterator::const_limb_pointer>(b.limbs(), b.size())); +#else + return (a.sign() == b.sign()) && (a.size() == b.size()) && + std::equal(a.limbs(), a.limbs() + a.size(), b.limbs()); +#endif + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_eq(const montgomery_int_backend &a, + limb_type b) BOOST_NOEXCEPT { + return (a.sign() == false) && (a.size() == 1) && (*a.limbs() == b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_eq(const montgomery_int_backend &a, + signed_limb_type b) BOOST_NOEXCEPT { + return (a.sign() == (b < 0)) && (a.size() == 1) && + (*a.limbs() == boost::multiprecision::detail::unsigned_abs(b)); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_eq(const montgomery_int_backend &a, + limb_type b) BOOST_NOEXCEPT { + return (a.size() == 1) && (*a.limbs() == b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_eq(const montgomery_int_backend &a, + signed_limb_type b) BOOST_NOEXCEPT { + return (b < 0) ? eval_eq(a, + montgomery_int_backend(b)) : eval_eq( + a, static_cast(b)); // Use bit pattern of b for comparison + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_lt(const montgomery_int_backend &a, + limb_type b) BOOST_NOEXCEPT { + if (a.sign()) { + return true; + } + if (a.size() > 1) { + return false; + } + return *a.limbs() < b; + } + + template + inline typename enable_if_c >::value, bool> + + ::type eval_lt(const montgomery_int_backend &a, + signed_limb_type b) BOOST_NOEXCEPT { + if ((b == 0) || (a.sign() != (b < 0))) { + return a.sign(); + } + if (a.sign()) { + if (a.size() > 1) { + return true; + } + return *a.limbs() > boost::multiprecision::detail::unsigned_abs(b); + } else { + if (a.size() > 1) { + return false; + } + return *a.limbs() < boost::multiprecision::detail::unsigned_abs(b); + } + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_lt(const montgomery_int_backend &a, + limb_type b) BOOST_NOEXCEPT { + if (a.size() > 1) { + return false; + } + return *a.limbs() < b; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_lt(const montgomery_int_backend &a, + signed_limb_type b) BOOST_NOEXCEPT { + return (b < 0) ? a.compare(b) < 0 : eval_lt(a, + static_cast(b)); // Use bit pattern of b for comparison + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_gt(const montgomery_int_backend &a, + limb_type b) BOOST_NOEXCEPT { + if (a.sign()) { + return false; + } + if (a.size() > 1) { + return true; + } + return *a.limbs() > b; + } + + template + inline typename enable_if_c >::value, bool> + + ::type eval_gt(const montgomery_int_backend &a, + signed_limb_type b) BOOST_NOEXCEPT { + if (b == 0) { + return !a.sign() && ((a.size() > 1) || *a.limbs()); + } + if (a.sign() != (b < 0)) { + return !a.sign(); + } + if (a.sign()) { + if (a.size() > 1) { + return false; + } + return *a.limbs() < boost::multiprecision::detail::unsigned_abs(b); + } else { + if (a.size() > 1) { + return true; + } + return *a.limbs() > boost::multiprecision::detail::unsigned_abs(b); + } + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_gt(const montgomery_int_backend &a, + limb_type b) BOOST_NOEXCEPT { + if (a.size() > 1) { + return true; + } + return *a.limbs() > b; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_gt(const montgomery_int_backend &a, + signed_limb_type b) BOOST_NOEXCEPT { + return (b < 0) ? a.compare(b) > 0 : eval_gt(a, + static_cast(b)); // Use bit pattern of b for comparison. + } + + /*!template class Backend, + unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator, typename ParamsBackend> + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::value eval_eq(const montgomery_int_backend &a, + const montgomery_int_backend &b) BOOST_NOEXCEPT { + return (a.sign() == b.sign()) && (*a.limbs() == *b.limbs()); + }*/ + + +// +// And again for trivial cpp_ints: +// + template class Backend, + unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, typename ParamsBackend> + + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::value eval_eq(const montgomery_int_backend &a, + const Backend &b) BOOST_NOEXCEPT { + return (a.sign() == b.sign()) && (*a.limbs() == *b.limbs()); + } + + template class Backend, + unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, typename ParamsBackend> + + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + is_equal_montgomery_int_backend>::value> + + ::value eval_eq(const montgomery_int_backend &a, + const Backend &b) BOOST_NOEXCEPT { + return *a.limbs() == *b.limbs(); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_eq(const montgomery_int_backend &a, + U b) BOOST_NOEXCEPT { + return !a.sign() && (*a.limbs() == b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_eq(const montgomery_int_backend &a, + S b) BOOST_NOEXCEPT { + return (a.sign() == (b < 0)) && (*a.limbs() == boost::multiprecision::detail::unsigned_abs(b)); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_eq(const montgomery_int_backend &a, + U b) BOOST_NOEXCEPT { + return *a.limbs() == b; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_eq(const montgomery_int_backend &a, + S b) BOOST_NOEXCEPT { + typedef typename make_unsigned::type ui_type; + if (b < 0) { + montgomery_int_backend t(b); + return *a.limbs() == *t.limbs(); + } else { + return *a.limbs() == static_cast(b); + } + } + + template class Backend, + unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, typename ParamsBackend> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_lt(const montgomery_int_backend &a, + const Backend &b) BOOST_NOEXCEPT { + if (a.sign() != b.sign()) { + return a.sign(); + } + return a.sign() ? *a.limbs() > *b.limbs() : *a.limbs() < *b.limbs(); + } + + template class Backend, + unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, typename ParamsBackend> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_lt(const montgomery_int_backend &a, + const montgomery_int_backend &b) BOOST_NOEXCEPT { + return *a.limbs() < *b.limbs(); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_lt(const montgomery_int_backend &a, + U b) BOOST_NOEXCEPT { + if (a.sign()) { + return true; + } + return *a.limbs() < b; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_lt(const montgomery_int_backend &a, + S b) BOOST_NOEXCEPT { + if (a.sign() != (b < 0)) { + return a.sign(); + } + return a.sign() ? (*a.limbs() > boost::multiprecision::detail::unsigned_abs(b)) : (*a.limbs() < + boost::multiprecision::detail::unsigned_abs( + b)); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_lt(const montgomery_int_backend &a, + U b) BOOST_NOEXCEPT { + return *a.limbs() < b; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_lt(const montgomery_int_backend &a, + S b) BOOST_NOEXCEPT { + typedef typename make_unsigned::type ui_type; + if (b < 0) { + montgomery_int_backend t(b); + return *a.limbs() < *t.limbs(); + } else { + return *a.limbs() < static_cast(b); + } + } + + template class Backend, + unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, typename ParamsBackend> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_gt(const montgomery_int_backend &a, + const Backend &b) BOOST_NOEXCEPT { + if (a.sign() != b.sign()) { + return !a.sign(); + } + return a.sign() ? *a.limbs() < *b.limbs() : *a.limbs() > *b.limbs(); + } + + template class Backend, + unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, typename ParamsBackend> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + is_trivial_montgomery_int< + Backend >::value && + is_equal_montgomery_int_backend>::value> + + ::type eval_gt(const montgomery_int_backend &a, + const Backend &b) BOOST_NOEXCEPT { + return *a.limbs() > *b.limbs(); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_gt(const montgomery_int_backend &a, + U b) BOOST_NOEXCEPT { + if (a.sign()) { + return false; + } + return *a.limbs() > b; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_gt(const montgomery_int_backend &a, + S b) BOOST_NOEXCEPT { + if (a.sign() != (b < 0)) { + return !a.sign(); + } + return a.sign() ? (*a.limbs() < boost::multiprecision::detail::unsigned_abs(b)) : (*a.limbs() > + boost::multiprecision::detail::unsigned_abs( + b)); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_gt(const montgomery_int_backend &a, + U b) BOOST_NOEXCEPT { + return *a.limbs() > b; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && is_trivial_montgomery_int< + montgomery_int_backend >::value, bool> + + ::type eval_gt(const montgomery_int_backend &a, + S b) BOOST_NOEXCEPT { + typedef typename make_unsigned::type ui_type; + if (b < 0) { + montgomery_int_backend t(b); + return *a.limbs() > *t.limbs(); + } else { + return *a.limbs() > static_cast(b); + } + } + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + + } + } +} // namespaces + +#endif \ No newline at end of file diff --git a/include/boost/multiprecision/montgomery_int/divide.hpp b/include/boost/multiprecision/montgomery_int/divide.hpp new file mode 100644 index 000000000..e4a92048a --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/divide.hpp @@ -0,0 +1,477 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_DIV_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_DIV_HPP + +namespace boost { + namespace multiprecision { + namespace backends { + + template + + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int::value && + !is_trivial_montgomery_int::value> + + ::type eval_divide(montgomery_int_backend &result, + const Backend2 &a, + const Backend3 &b) { + montgomery_int_backend r; + bool s = a.sign() != b.sign(); + divide_unsigned_helper(&result, a, b, r); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int::value> + + ::type eval_divide(montgomery_int_backend &result, + const Backend2 &a, + limb_type &b) { + montgomery_int_backend r; + bool s = a.sign(); + divide_unsigned_helper(&result, a, b, r); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int::value> + + ::type eval_divide(montgomery_int_backend &result, + const Backend2 &a, + signed_limb_type &b) { + montgomery_int_backend r; + bool s = a.sign() != (b < 0); + divide_unsigned_helper(&result, a, + static_cast(boost::multiprecision::detail::unsigned_abs(b)), r); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int::value> + + ::type eval_divide(montgomery_int_backend &result, + const Backend2 &b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_divide(result, a, b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value> + + ::type eval_divide(montgomery_int_backend &result, + limb_type b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_divide(result, a, b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value> + + ::type eval_divide(montgomery_int_backend &result, + signed_limb_type b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_divide(result, a, b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int::value && + !is_trivial_montgomery_int::value> + + ::type eval_modulus(montgomery_int_backend &result, + const Backend2 &a, + const Backend3 &b) { + bool s = a.sign(); + divide_unsigned_helper( + static_cast * >(0), a, b, + result); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int::value> + + ::type eval_modulus(montgomery_int_backend &result, + const Backend2 &a, + limb_type b) { + bool s = a.sign(); + divide_unsigned_helper( + static_cast * >(0), a, b, + result); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int::value> + + ::type eval_modulus(montgomery_int_backend &result, + const Backend2 &a, + signed_limb_type b) { + bool s = a.sign(); + divide_unsigned_helper( + static_cast * >(0), a, + static_cast(boost::multiprecision::detail::unsigned_abs(b)), result); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int::value> + + ::type eval_modulus(montgomery_int_backend &result, + const Backend2 &b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_modulus(result, a, b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value> + + ::type eval_modulus(montgomery_int_backend &result, + limb_type b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_modulus(result, a, b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value> + + ::type eval_modulus(montgomery_int_backend &result, + signed_limb_type b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_modulus(result, a, b); + } + +// +// Over again for trivial cpp_int's: +// + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int::value && + (is_signed_number >::value || + is_signed_number::value)> + + ::type eval_divide(montgomery_int_backend &result, + const Backend &o) { + if (!*o.limbs()) { + BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); + } + *result.limbs() /= *o.limbs(); + result.sign(result.sign() != o.sign()); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int::value && + is_unsigned_number >::value && + is_unsigned_number::value> + + ::type eval_divide(montgomery_int_backend &result, + const Backend &o) { + if (!*o.limbs()) { + BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); + } + *result.limbs() /= *o.limbs(); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int::value> + + ::type eval_modulus(montgomery_int_backend &result, + const Backend &o) { + if (!*o.limbs()) { + BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); + } + *result.limbs() %= *o.limbs(); + result.sign(result.sign()); + } + /* + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_divide(montgomery_int_backend &result, + const montgomery_int_backend &a, + const montgomery_int_backend &b) { + montgomery_int_backend r; + bool s = a.sign() != b.sign(); + divide_unsigned_helper(&result, a, b, r); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_divide(montgomery_int_backend &result, + const montgomery_int_backend &a, + limb_type &b) { + montgomery_int_backend r; + bool s = a.sign(); + divide_unsigned_helper(&result, a, b, r); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_divide(montgomery_int_backend &result, + const montgomery_int_backend &a, + signed_limb_type &b) { + montgomery_int_backend r; + bool s = a.sign() != (b < 0); + divide_unsigned_helper(&result, a, + static_cast(boost::multiprecision::detail::unsigned_abs(b)), r); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_divide(montgomery_int_backend &result, + const montgomery_int_backend &b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_divide(result, a, b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value> + + ::type eval_divide(montgomery_int_backend &result, + limb_type b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_divide(result, a, b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value> + + ::type eval_divide(montgomery_int_backend &result, + signed_limb_type b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_divide(result, a, b); + } + --- + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_modulus(montgomery_int_backend &result, + const montgomery_int_backend &a, + const montgomery_int_backend &b) { + bool s = a.sign(); + divide_unsigned_helper( + static_cast * >(0), a, b, + result); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_modulus(montgomery_int_backend &result, + const montgomery_int_backend &a, + limb_type b) { + bool s = a.sign(); + divide_unsigned_helper( + static_cast * >(0), a, b, + result); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_modulus(montgomery_int_backend &result, + const montgomery_int_backend &a, + signed_limb_type b) { + bool s = a.sign(); + divide_unsigned_helper( + static_cast * >(0), a, + static_cast(boost::multiprecision::detail::unsigned_abs(b)), result); + result.sign(s); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int >::value> + + ::type eval_modulus(montgomery_int_backend &result, + const montgomery_int_backend &b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_modulus(result, a, b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value> + + ::type eval_modulus(montgomery_int_backend &result, + limb_type b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_modulus(result, a, b); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value> + + ::type eval_modulus(montgomery_int_backend &result, + signed_limb_type b) { + // There is no in place divide: + montgomery_int_backend a(result); + eval_modulus(result, a, b); + } + +// +// Over again for trivial cpp_int's: +// + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + (is_signed_number >::value || + is_signed_number >::value)> + + ::type eval_divide(montgomery_int_backend &result, + const montgomery_int_backend &o) { + if (!*o.limbs()) { + BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); + } + *result.limbs() /= *o.limbs(); + result.sign(result.sign() != o.sign()); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value && + is_unsigned_number >::value && + is_unsigned_number >::value> + + ::type eval_divide(montgomery_int_backend &result, + const montgomery_int_backend &o) { + if (!*o.limbs()) { + BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); + } + *result.limbs() /= *o.limbs(); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int >::value && + is_trivial_montgomery_int >::value> + + ::type eval_modulus(montgomery_int_backend &result, + const montgomery_int_backend &o) { + if (!*o.limbs()) { + BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero.")); + } + *result.limbs() %= *o.limbs(); + result.sign(result.sign()); + } + */ + + } + } +} // namespaces + +#endif diff --git a/include/boost/multiprecision/montgomery_int/import_export.hpp b/include/boost/multiprecision/montgomery_int/import_export.hpp new file mode 100644 index 000000000..13d27aaa1 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/import_export.hpp @@ -0,0 +1,298 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_IMPORT_EXPORT_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_IMPORT_EXPORT_HPP + +//#include +//#include + +namespace boost { + namespace multiprecision { + + namespace detail { + template + montgomery_int_backend &eval_import_bits_generic(montgomery_int_backend &val, Iterator i, Iterator j, unsigned chunk_size = 0, + bool msv_first = true) { + montgomery_int_backend newval; + + typedef typename std::iterator_traits::value_type value_type; + typedef typename boost::make_unsigned::type unsigned_value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename boost::make_unsigned::type size_type; + typedef typename montgomery_int_backend::trivial_tag tag_type; + + if (!chunk_size) { + chunk_size = std::numeric_limits::digits; + } + + size_type limbs = std::distance(i, j); + size_type bits = limbs * chunk_size; + + detail::resize_to_bit_size(newval, static_cast(bits), tag_type()); + + difference_type bit_location = msv_first ? bits - chunk_size : 0; + difference_type bit_location_change = msv_first ? -static_cast(chunk_size) + : chunk_size; + + while (i != j) { + detail::assign_bits(newval, static_cast(*i), + static_cast(bit_location), chunk_size, tag_type()); + ++i; + bit_location += bit_location_change; + } + + newval.normalize(); + + val.swap(newval); + return val; + } + + template + inline typename boost::disable_if_c>::value, + montgomery_int_backend &>::type eval_import_bits_fast(montgomery_int_backend &val, T *i, T *j, unsigned 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); + if (byte_len % sizeof(limb_type)) { + ++limb_len; + } + val.resize(static_cast(limb_len), + static_cast(limb_len)); // checked types may throw here if they're not large enough to hold the data! + val.limbs()[val.size() - 1] = 0u; + std::memcpy(val.limbs(), i, (std::min)(byte_len, val.size() * sizeof(limb_type))); + val.normalize(); // In case data has leading zeros. + return val; + } + + template + inline typename boost::enable_if_c>::value, + montgomery_int_backend &>::type eval_import_bits_fast(montgomery_int_backend &val, T *i, T *j, unsigned 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(val.limbs()[0]); + if (byte_len % sizeof(val.limbs()[0])) { + ++limb_len; + } + val.limbs()[0] = 0u; + val.resize(static_cast(limb_len), + static_cast(limb_len)); // checked types may throw here if they're not large enough to hold the data! + std::memcpy(val.limbs(), i, (std::min)(byte_len, val.size() * sizeof(val.limbs()[0]))); + val.normalize(); // In case data has leading zeros. + return val; + } + + template + number, + ExpressionTemplates> &import_bits_generic( + number, + ExpressionTemplates> &val, Iterator i, Iterator j, unsigned chunk_size = 0, + bool msv_first = true) { + typename number, + ExpressionTemplates>::backend_type newval; + + typedef typename std::iterator_traits::value_type value_type; + typedef typename boost::make_unsigned::type unsigned_value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename boost::make_unsigned::type size_type; + typedef typename montgomery_int_backend::trivial_tag tag_type; + + if (!chunk_size) { + chunk_size = std::numeric_limits::digits; + } + + size_type limbs = std::distance(i, j); + size_type bits = limbs * chunk_size; + + detail::resize_to_bit_size(newval, static_cast(bits), tag_type()); + + difference_type bit_location = msv_first ? bits - chunk_size : 0; + difference_type bit_location_change = msv_first ? -static_cast(chunk_size) + : chunk_size; + + while (i != j) { + detail::assign_bits(newval, static_cast(*i), + static_cast(bit_location), chunk_size, tag_type()); + ++i; + bit_location += bit_location_change; + } + + newval.normalize(); + + val.backend().swap(newval); + return val; + } + + template + inline typename boost::disable_if_c >::value, + number, + ExpressionTemplates> &> + + ::type import_bits_fast(number, + ExpressionTemplates> &val, T *i, T *j, unsigned 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); + if (byte_len % sizeof(limb_type)) { + ++limb_len; + } + montgomery_int_backend &result = val.backend(); + result.resize(static_cast(limb_len), + static_cast(limb_len)); // checked types may throw here if they're not large enough to hold the data! + result.limbs()[result.size() - 1] = 0u; + std::memcpy(result.limbs(), i, (std::min)(byte_len, result.size() * sizeof(limb_type))); + result.normalize(); // In case data has leading zeros. + return val; + } + + template + inline typename boost::enable_if_c >::value, + number, + ExpressionTemplates> &> + + ::type import_bits_fast(number, + ExpressionTemplates> &val, T *i, T *j, unsigned chunk_size = 0) { + montgomery_int_backend &result = val.backend(); + std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i)); + std::size_t limb_len = byte_len / sizeof(result.limbs()[0]); + if (byte_len % sizeof(result.limbs()[0])) { + ++limb_len; + } + result.limbs()[0] = 0u; + result.resize(static_cast(limb_len), + static_cast(limb_len)); // checked types may throw here if they're not large enough to hold the data! + std::memcpy(result.limbs(), i, (std::min)(byte_len, result.size() * sizeof(result.limbs()[0]))); + result.normalize(); // In case data has leading zeros. + return val; + } + } + + template + inline montgomery_int_backend &eval_import_bits(montgomery_int_backend &val, Iterator i, Iterator j, unsigned chunk_size = 0, + bool msv_first = true) { + return detail::eval_import_bits_generic(val, i, j, chunk_size, msv_first); + } + + template + inline montgomery_int_backend &eval_import_bits(montgomery_int_backend &val, T *i, T *j, unsigned chunk_size = 0, bool msv_first = true) { +#ifdef BOOST_LITTLE_ENDIAN + if (((chunk_size % CHAR_BIT) == 0) && !msv_first) { + return detail::eval_import_bits_fast(val, i, j, chunk_size); + } +#endif + return detail::eval_import_bits_generic(val, i, j, chunk_size, msv_first); + } + + template + OutputIterator eval_export_bits(const montgomery_int_backend &val, OutputIterator out, unsigned chunk_size, + bool msv_first = true) { +#ifdef _MSC_VER + #pragma warning(push) +#pragma warning(disable:4244) +#endif + + typedef typename montgomery_int_backend::trivial_tag tag_type; + if (eval_is_zero(val)) { + *out = 0; + ++out; + return out; + } + unsigned bitcount = backends::eval_msb_imp(val) + 1; + unsigned chunks = bitcount / chunk_size; + if (bitcount % chunk_size) { + ++chunks; + } + + int bit_location = msv_first ? bitcount - chunk_size : 0; + int bit_step = msv_first ? -static_cast(chunk_size) : chunk_size; + while (bit_location % bit_step) { + ++bit_location; + } + + do { + *out = detail::extract_bits(val, bit_location, chunk_size, tag_type()); + ++out; + bit_location += bit_step; + } while ((bit_location >= 0) && (bit_location < (int) bitcount)); + + return out; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } + + template + inline number, + ExpressionTemplates> &import_bits( + number, + ExpressionTemplates> &val, Iterator i, Iterator j, unsigned chunk_size = 0, + bool msv_first = true) { + return detail::import_bits_generic(val, i, j, chunk_size, msv_first); + } + + template + inline number, + ExpressionTemplates> &import_bits( + number, + ExpressionTemplates> &val, T *i, T *j, unsigned chunk_size = 0, bool msv_first = true) { +#ifdef BOOST_LITTLE_ENDIAN + if (((chunk_size % CHAR_BIT) == 0) && !msv_first) { + return detail::import_bits_fast(val, i, j, chunk_size); + } +#endif + return detail::import_bits_generic(val, i, j, chunk_size, msv_first); + } + + template + OutputIterator export_bits(const number, + ExpressionTemplates> &val, OutputIterator out, unsigned chunk_size, bool msv_first = true) { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4244) +#endif + typedef typename montgomery_int_backend::trivial_tag tag_type; + if (!val) { + *out = 0; + ++out; + return out; + } + unsigned bitcount = boost::multiprecision::backends::eval_msb_imp(val.backend()) + 1; + unsigned chunks = bitcount / chunk_size; + if (bitcount % chunk_size) { + ++chunks; + } + + int bit_location = msv_first ? bitcount - chunk_size : 0; + int bit_step = msv_first ? -static_cast(chunk_size) : chunk_size; + while (bit_location % bit_step) { + ++bit_location; + } + + do { + *out = detail::extract_bits(val.backend(), bit_location, chunk_size, tag_type()); + ++out; + bit_location += bit_step; + } while ((bit_location >= 0) && (bit_location < (int) bitcount)); + + return out; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } + + } +} + + +#endif // CRYPTO3_MP_MONTGOMERY_INT_IMPORT_EXPORT_HPP + diff --git a/include/boost/multiprecision/montgomery_int/inverse.hpp b/include/boost/multiprecision/montgomery_int/inverse.hpp new file mode 100644 index 000000000..e94c2f627 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/inverse.hpp @@ -0,0 +1,42 @@ +// +// Created by Zerg1996 on 2019-05-07. +// + +#ifndef CRYPTO3_INVERSE_H +#define CRYPTO3_INVERSE_H + +namespace nil { + namespace crypto3 { + limb_type monty_inverse(limb_type a) + { + const limb_type MP_WORD_MAX = ~static_cast(0); + + if(a % 2 == 0) + throw std::invalid_argument("monty_inverse only valid for odd integers"); + + /* + * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç + * https://eprint.iacr.org/2017/411.pdf sections 5 and 7. + */ + + limb_type b = 1; + limb_type r = 0; + + for(size_t i = 0; i != CRYPTO3_MP_WORD_BITS; ++i) + { + const limb_type bi = b % 2; + r >>= 1; + r += bi << (CRYPTO3_MP_WORD_BITS - 1); + + b -= a * bi; + b >>= 1; + } + + // Now invert in addition space + r = (MP_WORD_MAX - r) + 1; + + return r; + } + } +} +#endif //CRYPTO3_INVERSE_H diff --git a/include/boost/multiprecision/montgomery_int/limits.hpp b/include/boost/multiprecision/montgomery_int/limits.hpp new file mode 100644 index 000000000..c47c6de11 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/limits.hpp @@ -0,0 +1,375 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_LIM_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_LIM_HPP + +namespace std { + + namespace detail { + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4307) +#endif + + template + inline boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> get_min(const boost::mpl::true_ &, const boost::mpl::true_ &) { + // Bounded and signed. + typedef boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> result_type; + typedef boost::multiprecision::number, + ExpressionTemplates> ui_type; + static const result_type val = -result_type(~ui_type(0)); + return val; + } + + template + inline boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> get_min(const boost::mpl::true_ &, const boost::mpl::false_ &) { + // Bounded and unsigned: + static const boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> val(0u); + return val; + } + + template + inline boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> get_min(const boost::mpl::false_ &, const boost::mpl::true_ &) { + // Unbounded and signed. + // There is no minimum value, just return 0: + static const boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> val(0u); + return val; + } + + template + inline boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> get_min(const boost::mpl::false_ &, const boost::mpl::false_ &) { + // Unbound and unsigned: + static const boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> val(0u); + return val; + } + + template + inline boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> get_max(const boost::mpl::true_ &, const boost::mpl::true_ &) { + // Bounded and signed. + typedef boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> result_type; + typedef boost::multiprecision::number, + ExpressionTemplates> ui_type; + static const result_type val = ~ui_type(0); + return val; + } + + template + inline boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> get_max(const boost::mpl::true_ &, const boost::mpl::false_ &) { + // Bound and unsigned: + typedef boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> result_type; + typedef boost::multiprecision::number, + ExpressionTemplates> ui_type; + static const result_type val = ~ui_type(0); + return val; + } + + template + inline boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> get_max(const boost::mpl::false_ &, const boost::mpl::true_ &) { + // Unbounded and signed. + // There is no maximum value, just return 0: + static const boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> val(0u); + return val; + } + + template + inline boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> get_max(const boost::mpl::false_ &, const boost::mpl::false_ &) { + // Unbound and unsigned: + static const boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> val(0u); + return val; + } + + } + + template + class numeric_limits, + ExpressionTemplates> > { + typedef boost::multiprecision::montgomery_int_backend backend_type; + typedef boost::multiprecision::number number_type; + + struct inititializer { + inititializer() { + (std::numeric_limits::max)(); + (std::numeric_limits::min)(); + } + + void do_nothing() const { + } + }; + + static const inititializer init; + + public: + BOOST_STATIC_CONSTEXPR bool is_specialized = true; + + // + // Largest and smallest numbers are bounded only by available memory, set + // to zero: + // + static number_type (min)() { + init.do_nothing(); + return detail::get_min( + boost::multiprecision::backends::is_fixed_precision(), + boost::multiprecision::is_signed_number()); + } + + static number_type (max)() { + init.do_nothing(); + return detail::get_max( + boost::multiprecision::backends::is_fixed_precision(), + boost::multiprecision::is_signed_number()); + } + + static number_type lowest() { + return (min)(); + } + + BOOST_STATIC_CONSTEXPR int digits = + boost::multiprecision::backends::max_precision::value == UINT_MAX ? INT_MAX + : boost::multiprecision::backends::max_precision< + backend_type>::value; + BOOST_STATIC_CONSTEXPR int digits10 = (digits > INT_MAX / 301) ? (digits / 1000) * 301L : (digits * 301) / 1000; + BOOST_STATIC_CONSTEXPR int max_digits10 = digits10 + 3; + BOOST_STATIC_CONSTEXPR bool is_signed = boost::multiprecision::is_signed_number::value; + BOOST_STATIC_CONSTEXPR bool is_integer = true; + BOOST_STATIC_CONSTEXPR bool is_exact = true; + BOOST_STATIC_CONSTEXPR int radix = 2; + + static number_type epsilon() { + return 0; + } + + static number_type round_error() { + return 0; + } + + BOOST_STATIC_CONSTEXPR int min_exponent = 0; + BOOST_STATIC_CONSTEXPR int min_exponent10 = 0; + BOOST_STATIC_CONSTEXPR int max_exponent = 0; + BOOST_STATIC_CONSTEXPR int max_exponent10 = 0; + BOOST_STATIC_CONSTEXPR bool has_infinity = false; + BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = false; + BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false; + BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent; + BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false; + + static number_type infinity() { + return 0; + } + + static number_type quiet_NaN() { + return 0; + } + + static number_type signaling_NaN() { + return 0; + } + + static number_type denorm_min() { + return 0; + } + + BOOST_STATIC_CONSTEXPR bool is_iec559 = false; + BOOST_STATIC_CONSTEXPR bool is_bounded = boost::multiprecision::backends::is_fixed_precision< + backend_type>::value; + BOOST_STATIC_CONSTEXPR bool is_modulo = ( + boost::multiprecision::backends::is_fixed_precision::value && + (Checked == boost::multiprecision::unchecked)); + BOOST_STATIC_CONSTEXPR bool traps = false; + BOOST_STATIC_CONSTEXPR bool tinyness_before = false; + BOOST_STATIC_CONSTEXPR float_round_style round_style = round_toward_zero; + }; + + template const typename numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::inititializer numeric_limits, + ExpressionTemplates> >::init; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION + + template BOOST_CONSTEXPR_OR_CONST int numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::digits; + + template BOOST_CONSTEXPR_OR_CONST int numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::digits10; + + template BOOST_CONSTEXPR_OR_CONST int numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::max_digits10; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::is_signed; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::is_integer; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::is_exact; + + template BOOST_CONSTEXPR_OR_CONST int numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::radix; + + template BOOST_CONSTEXPR_OR_CONST int numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::min_exponent; + + template BOOST_CONSTEXPR_OR_CONST int numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::min_exponent10; + template BOOST_CONSTEXPR_OR_CONST int numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::max_exponent; + + template BOOST_CONSTEXPR_OR_CONST int numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::max_exponent10; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::has_infinity; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::has_quiet_NaN; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::has_signaling_NaN; + + template BOOST_CONSTEXPR_OR_CONST float_denorm_style + numeric_limits, + ExpressionTemplates> >::has_denorm; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::has_denorm_loss; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::is_iec559; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::is_bounded; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::is_modulo; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::traps; + + template BOOST_CONSTEXPR_OR_CONST bool numeric_limits< + boost::multiprecision::number< + boost::multiprecision::montgomery_int_backend, + ExpressionTemplates> >::tinyness_before; + + template BOOST_CONSTEXPR_OR_CONST float_round_style + numeric_limits, + ExpressionTemplates> >::round_style; + +#endif +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +} // namespace std + +#endif diff --git a/include/boost/multiprecision/montgomery_int/literals.hpp b/include/boost/multiprecision/montgomery_int/literals.hpp new file mode 100644 index 000000000..479e775ee --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/literals.hpp @@ -0,0 +1,102 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_LITERALS_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_LITERALS_HPP + +#include +#include + +namespace boost { + namespace multiprecision { + + namespace literals { + namespace detail { + + template + struct signed_montgomery_int_literal_result_type { + static constexpr unsigned bits = Digits * 4; + typedef boost::multiprecision::backends::montgomery_int_backend backend_type; + typedef number number_type; + }; + + template + struct unsigned_montgomery_int_literal_result_type { + static constexpr unsigned bits = Digits * 4; + typedef boost::multiprecision::backends::montgomery_int_backend backend_type; + typedef number number_type; + }; + + } + + template + constexpr typename boost::multiprecision::literals::detail::signed_montgomery_int_literal_result_type< + (sizeof...(STR)) - 2>::number_type operator "" _cppi() { + typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str::type pt; + return boost::multiprecision::literals::detail::make_backend_from_pack::backend_type>::value; + } + + template + constexpr typename boost::multiprecision::literals::detail::unsigned_montgomery_int_literal_result_type< + (sizeof...(STR)) - 2>::number_type operator "" _cppui() { + typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str::type pt; + return boost::multiprecision::literals::detail::make_backend_from_pack::backend_type>::value; + } + +#define BOOST_MP_DEFINE_SIZED_MNT_INT_LITERAL(Bits)\ +template \ +constexpr boost::multiprecision::number > operator "" BOOST_JOIN(_cppi, Bits)()\ +{\ + typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str::type pt;\ + return boost::multiprecision::literals::detail::make_backend_from_pack<\ + pt, \ + boost::multiprecision::backends::montgomery_int_backend \ + >::value;\ +}\ +template \ +constexpr boost::multiprecision::number > operator "" BOOST_JOIN(_cppui, Bits)()\ +{\ + typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str::type pt;\ + return boost::multiprecision::literals::detail::make_backend_from_pack<\ + pt, \ + boost::multiprecision::backends::montgomery_int_backend\ + >::value;\ +}\ + + + BOOST_MP_DEFINE_SIZED_MNT_INT_LITERAL(128) + + BOOST_MP_DEFINE_SIZED_MNT_INT_LITERAL(256) + + BOOST_MP_DEFINE_SIZED_MNT_INT_LITERAL(512) + + BOOST_MP_DEFINE_SIZED_MNT_INT_LITERAL(1024) + + } + +// +// Overload unary minus operator for constexpr use: +// + template + constexpr number, et_off> operator-( + const number, et_off> &a) { + return montgomery_int_backend(a.backend(), + boost::multiprecision::literals::detail::make_negate_tag()); + } + + template + constexpr number, et_off> operator-( + number, et_off> &&a) { + return montgomery_int_backend( + static_cast, + et_off> &>(a).backend(), boost::multiprecision::literals::detail::make_negate_tag()); + } + + } +} // namespaces + +#endif // CRYPTO3_MP_MONTGOMERY_INT_CORE_HPP + diff --git a/include/boost/multiprecision/montgomery_int/misc.hpp b/include/boost/multiprecision/montgomery_int/misc.hpp new file mode 100644 index 000000000..825202a37 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/misc.hpp @@ -0,0 +1,683 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_MISC_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_MISC_HPP + +#include // lsb etc +#include // gcd/lcm +#include + + +#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 boost { + namespace multiprecision { + namespace backends { + + + template< + class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + inline typename enable_if_c::value && !is_trivial_montgomery_int< + montgomery_int_backend >::value, void> + + ::type eval_convert_to(R *result, const montgomery_int_backend &backend) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + typedef mpl::int_ checked_type; + check_in_range(backend, checked_type()); + + *result = static_cast(backend.limbs()[0]); + unsigned shift = montgomery_int_backend::limb_bits; + for (unsigned i = 1; (i < backend.size()) && (shift < static_cast(std::numeric_limits::digits)); ++i) { + *result += static_cast(backend.limbs()[i]) << shift; + shift += montgomery_int_backend::limb_bits; + } + if (backend.sign()) { + check_is_negative(boost::is_signed()); + + *result = negate_integer(*result, boost::is_signed()); + } + } + + template + inline typename enable_if_c::value && !is_trivial_montgomery_int< + montgomery_int_backend >::value, void> + + ::type eval_convert_to(R *result, const montgomery_int_backend &backend) + + BOOST_MP_NOEXCEPT_IF(is_arithmetic::value) { + typename montgomery_int_backend::const_limb_pointer p = backend.limbs(); + unsigned shift = montgomery_int_backend::limb_bits; + *result = static_cast(*p); + for (unsigned i = 1; i < backend.size(); ++i) { + *result += static_cast(std::ldexp(static_cast(p[i]), shift)); + shift += montgomery_int_backend::limb_bits; + } + if (backend.sign()) { + *result = -*result; + } + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool> + + ::type eval_is_zero(const montgomery_int_backend &val) BOOST_NOEXCEPT { + return (val.size() == 1) && (val.limbs()[0] == 0); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value, int> + + ::type eval_get_sign(const montgomery_int_backend &val) BOOST_NOEXCEPT { + return eval_is_zero(val) ? 0 : val.sign() ? -1 : 1; + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_abs(montgomery_int_backend &result, + const montgomery_int_backend &val) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + result = val; + result.sign(false); + } + +// +// Get the location of the least-significant-bit: +// + template + inline typename enable_if_c >::value, unsigned> + + ::type eval_lsb(const montgomery_int_backend &a) { + using default_ops::eval_get_sign; + if (eval_get_sign(a) == 0) { + BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); + } + if (a.sign()) { + BOOST_THROW_EXCEPTION(std::range_error( + "Testing individual bits in negative values is not supported - results are undefined.")); + } + + // + // Find the index of the least significant limb that is non-zero: + // + unsigned index = 0; + while (!a.limbs()[index] && (index < a.size())) { + ++index; + } + // + // Find the index of the least significant bit within that limb: + // + unsigned result = boost::multiprecision::detail::find_lsb(a.limbs()[index]); + + return result + + index * montgomery_int_backend::limb_bits; + } + +// +// Get the location of the most-significant-bit: +// + template + inline typename enable_if_c >::value, unsigned> + + ::type eval_msb_imp(const montgomery_int_backend &a) { + // + // Find the index of the most significant bit that is non-zero: + // + return (a.size() - 1) * + montgomery_int_backend::limb_bits + + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]); + } + + template + inline typename enable_if_c >::value, unsigned> + + ::type eval_msb(const montgomery_int_backend &a) { + using default_ops::eval_get_sign; + if (eval_get_sign(a) == 0) { + BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); + } + if (a.sign()) { + BOOST_THROW_EXCEPTION(std::range_error( + "Testing individual bits in negative values is not supported - results are undefined.")); + } + return eval_msb_imp(a); + } + + template + inline typename enable_if_c >::value, bool> + + ::type eval_bit_test(const montgomery_int_backend &val, + unsigned index) BOOST_NOEXCEPT { + unsigned offset = + index / montgomery_int_backend::limb_bits; + unsigned shift = + index % montgomery_int_backend::limb_bits; + limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u); + if (offset >= val.size()) { + return false; + } + return val.limbs()[offset] & mask ? true : false; + } + + template + inline typename enable_if_c >::value> + + ::type eval_bit_set(montgomery_int_backend &val, + unsigned index) { + unsigned offset = + index / montgomery_int_backend::limb_bits; + unsigned shift = + index % montgomery_int_backend::limb_bits; + limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u); + if (offset >= val.size()) { + unsigned os = val.size(); + val.resize(offset + 1, offset + 1); + if (offset >= val.size()) { + return; + } // fixed precision overflow + for (unsigned i = os; i <= offset; ++i) { + val.limbs()[i] = 0; + } + } + val.limbs()[offset] |= mask; + } + + template + inline typename enable_if_c >::value> + + ::type eval_bit_unset(montgomery_int_backend &val, + unsigned index) BOOST_NOEXCEPT { + unsigned offset = + index / montgomery_int_backend::limb_bits; + unsigned shift = + index % montgomery_int_backend::limb_bits; + limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u); + if (offset >= val.size()) { + return; + } + val.limbs()[offset] &= ~mask; + val.normalize(); + } + + template + inline typename enable_if_c >::value> + + ::type eval_bit_flip(montgomery_int_backend &val, + unsigned index) { + unsigned offset = + index / montgomery_int_backend::limb_bits; + unsigned shift = + index % montgomery_int_backend::limb_bits; + limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u); + if (offset >= val.size()) { + unsigned os = val.size(); + val.resize(offset + 1, offset + 1); + if (offset >= val.size()) { + return; + } // fixed precision overflow + for (unsigned i = os; i <= offset; ++i) { + val.limbs()[i] = 0; + } + } + val.limbs()[offset] ^= mask; + val.normalize(); + } + + template + inline typename enable_if_c >::value> + + ::type eval_qr(const montgomery_int_backend &x, + const montgomery_int_backend &y, + montgomery_int_backend &q, + montgomery_int_backend &r) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + divide_unsigned_helper(&q, x, y, r); + q.sign(x.sign() != y.sign()); + r.sign(x.sign()); + } + + template + inline typename enable_if_c >::value> + + ::type eval_qr(const montgomery_int_backend &x, + limb_type y, montgomery_int_backend &q, + montgomery_int_backend &r) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + divide_unsigned_helper(&q, x, y, r); + q.sign(x.sign()); + r.sign(x.sign()); + } + + template + inline typename enable_if_c::value>::type eval_qr( + const montgomery_int_backend &x, U y, + montgomery_int_backend &q, + montgomery_int_backend &r) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + using default_ops::eval_qr; + montgomery_int_backend t; + t = y; + eval_qr(x, t, q, r); + } + + template + inline typename enable_if_c::value && !is_trivial_montgomery_int< + montgomery_int_backend >::value, Integer> + + ::type eval_integer_modulus( + const montgomery_int_backend &x, Integer val) { + if ((sizeof(Integer) <= sizeof(limb_type)) || (val <= (std::numeric_limits::max)())) { + montgomery_int_backend d; + divide_unsigned_helper(static_cast *>(0), x, static_cast(val), d); + return d.limbs()[0]; + } else { + return default_ops::eval_integer_modulus(x, val); + } + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c::value && !is_trivial_montgomery_int< + montgomery_int_backend >::value, Integer> + + ::type eval_integer_modulus( + const montgomery_int_backend &x, Integer val) { + return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val)); + } + + template + inline typename enable_if_c >::value> + + ::type eval_gcd(montgomery_int_backend &result, + const montgomery_int_backend &a, + limb_type v) { + using default_ops::eval_lsb; + using default_ops::eval_is_zero; + using default_ops::eval_get_sign; + + int shift; + + montgomery_int_backend u(a); + + int s = eval_get_sign(u); + + /* GCD(0,x) := x */ + if (s < 0) { + u.negate(); + } else if (s == 0) { + result = v; + return; + } + if (v == 0) { + result = u; + return; + } + + /* Let shift := lg K, where K is the greatest power of 2 + dividing both u and v. */ + + unsigned us = eval_lsb(u); + unsigned vs = boost::multiprecision::detail::find_lsb(v); + shift = (std::min)(us, vs); + eval_right_shift(u, us); + if (vs) { + v >>= vs; + } + + do { + /* Now u and v are both odd, so diff(u, v) is even. + Let u = min(u, v), v = diff(u, v)/2. */ + if (u.size() <= 2) { + if (u.size() == 1) { + v = integer_gcd_reduce(*u.limbs(), v); + } else { + double_limb_type i; + i = u.limbs()[0] | + (static_cast(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT); + v = static_cast(integer_gcd_reduce(i, static_cast(v))); + } + break; + } + eval_subtract(u, v); + us = eval_lsb(u); + eval_right_shift(u, us); + } while (true); + + result = v; + eval_left_shift(result, shift); + } + + template + inline typename enable_if_c::value && (sizeof(Integer) <= sizeof(limb_type)) && + !is_trivial_montgomery_int< + montgomery_int_backend >::value> + + ::type eval_gcd(montgomery_int_backend &result, + const montgomery_int_backend &a, + const Integer &v) { + eval_gcd(result, a, static_cast(v)); + } + + template + inline typename enable_if_c::value && (sizeof(Integer) <= sizeof(limb_type)) && + !is_trivial_montgomery_int< + montgomery_int_backend >::value> + + ::type eval_gcd(montgomery_int_backend &result, + const montgomery_int_backend &a, + const Integer &v) { + eval_gcd(result, a, static_cast(v < 0 ? -v : v)); + } + + template + inline typename enable_if_c >::value> + + ::type eval_gcd(montgomery_int_backend &result, + const montgomery_int_backend &a, + const montgomery_int_backend &b) { + using default_ops::eval_lsb; + using default_ops::eval_is_zero; + using default_ops::eval_get_sign; + + if (a.size() == 1) { + eval_gcd(result, b, *a.limbs()); + return; + } + if (b.size() == 1) { + eval_gcd(result, a, *b.limbs()); + return; + } + + int shift; + + montgomery_int_backend u(a), v(b); + + int s = eval_get_sign(u); + + /* GCD(0,x) := x */ + if (s < 0) { + u.negate(); + } else if (s == 0) { + result = v; + return; + } + s = eval_get_sign(v); + if (s < 0) { + v.negate(); + } else if (s == 0) { + result = u; + return; + } + + /* Let shift := lg K, where K is the greatest power of 2 + dividing both u and v. */ + + unsigned us = eval_lsb(u); + unsigned vs = eval_lsb(v); + shift = (std::min)(us, vs); + eval_right_shift(u, us); + eval_right_shift(v, vs); + + do { + /* Now u and v are both odd, so diff(u, v) is even. + Let u = min(u, v), v = diff(u, v)/2. */ + s = u.compare(v); + if (s > 0) { + u.swap(v); + } + if (s == 0) { + break; + } + if (v.size() <= 2) { + if (v.size() == 1) { + u = integer_gcd_reduce(*v.limbs(), *u.limbs()); + } else { + double_limb_type i, j; + i = v.limbs()[0] | + (static_cast(v.limbs()[1]) << sizeof(limb_type) * CHAR_BIT); + j = (u.size() == 1) ? *u.limbs() : u.limbs()[0] | + (static_cast(u.limbs()[1]) + << sizeof(limb_type) * CHAR_BIT); + u = integer_gcd_reduce(i, j); + } + break; + } + eval_subtract(v, u); + vs = eval_lsb(v); + eval_right_shift(v, vs); + } while (true); + + result = u; + eval_left_shift(result, shift); + } + +// +// Now again for trivial backends: +// + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_gcd(montgomery_int_backend &result, + const montgomery_int_backend &a, + const montgomery_int_backend &b) BOOST_NOEXCEPT { + *result.limbs() = boost::integer::gcd(*a.limbs(), *b.limbs()); + } + +// This one is only enabled for unchecked cpp_int's, for checked int's we need the checking in the default version: + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + (Checked1 == unchecked)> + + ::type eval_lcm(montgomery_int_backend &result, + const montgomery_int_backend &a, + const montgomery_int_backend &b) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + *result. + + limbs() = boost::integer::lcm(*a.limbs(), *b.limbs()); + + result. + + normalize(); // result may overflow the specified number of bits + } + + template< + class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + inline typename enable_if_c >::value && + is_signed_number >::value && boost::is_convertible< + typename montgomery_int_backend::local_limb_type, R>::value> + + ::type eval_convert_to(R *result, const montgomery_int_backend &val) { + typedef typename common_type::local_limb_type>::type common_type; + if (std::numeric_limits::is_specialized && (static_cast(*val.limbs()) > + static_cast((std::numeric_limits< + R>::max)()))) { + if (val.isneg()) { + if (static_cast(*val.limbs()) > + -static_cast((std::numeric_limits::min)())) { + conversion_overflow(typename montgomery_int_backend::checked_type()); + } + *result = (std::numeric_limits::min)(); + } else { + conversion_overflow(typename montgomery_int_backend::checked_type()); + *result = (std::numeric_limits::max)(); + } + } else { + *result = static_cast(*val.limbs()); + if (val.isneg()) { + check_is_negative(mpl::bool_::value || + (number_category::value == number_kind_floating_point)>()); + *result = negate_integer(*result, mpl::bool_::value || + (number_category::value == + number_kind_floating_point)>()); + } + } + } + + template< + class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + inline typename enable_if_c >::value && + is_unsigned_number< + montgomery_int_backend >::value && boost::is_convertible< + typename montgomery_int_backend::local_limb_type, R>::value> + + ::type eval_convert_to(R *result, const montgomery_int_backend &val) { + typedef typename common_type::local_limb_type>::type common_type; + if (std::numeric_limits::is_specialized && (static_cast(*val.limbs()) > + static_cast((std::numeric_limits< + R>::max)()))) { + conversion_overflow(typename montgomery_int_backend::checked_type()); + *result = (std::numeric_limits::max)(); + } else { + *result = static_cast(*val.limbs()); + } + } + + template + inline typename enable_if_c >::value, unsigned> + + ::type eval_lsb(const montgomery_int_backend &a) { + using default_ops::eval_get_sign; + if (eval_get_sign(a) == 0) { + BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); + } + if (a.sign()) { + BOOST_THROW_EXCEPTION(std::range_error( + "Testing individual bits in negative values is not supported - results are undefined.")); + } + // + // Find the index of the least significant bit within that limb: + // + return boost::multiprecision::detail::find_lsb(*a.limbs()); + } + + template + inline typename enable_if_c >::value, unsigned> + + ::type eval_msb_imp(const montgomery_int_backend &a) { + // + // Find the index of the least significant bit within that limb: + // + return boost::multiprecision::detail::find_msb(*a.limbs()); + } + + template + inline typename enable_if_c >::value, unsigned> + + ::type eval_msb(const montgomery_int_backend &a) { + using default_ops::eval_get_sign; + if (eval_get_sign(a) == 0) { + BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); + } + if (a.sign()) { + BOOST_THROW_EXCEPTION(std::range_error( + "Testing individual bits in negative values is not supported - results are undefined.")); + } + return eval_msb_imp(a); + } + + template + inline std::size_t hash_value(const montgomery_int_backend &val) BOOST_NOEXCEPT { + std::size_t result = 0; + for (unsigned i = 0; i < val.size(); ++i) { + boost::hash_combine(result, val.limbs()[i]); + } + boost::hash_combine(result, val.sign()); + return result; + } + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + + } + } +} // namespaces + +#endif diff --git a/include/boost/multiprecision/montgomery_int/modular_reduce.hpp b/include/boost/multiprecision/montgomery_int/modular_reduce.hpp new file mode 100644 index 000000000..1e7b2bdac --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/modular_reduce.hpp @@ -0,0 +1,94 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_MOD_REDC_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_MOD_REDC_HPP + +//#include + +#include +#include + +namespace boost { + namespace multiprecision { + namespace backends { + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif + + template + inline void mod_redc(Backend &result, const Backend &mod) BOOST_MP_NOEXCEPT_IF ( + is_non_throwing_cpp_int::value) { + + using default_ops::eval_lt; + using default_ops::eval_gt; + using default_ops::eval_add; + using default_ops::eval_multiply; + using default_ops::eval_bit_set; + using nil::crypto3::eval_mask_bits; + using nil::crypto3::eval_reduce_below; + + const size_t x_sw = result.size(); + + Backend mod2 = mod; + eval_add(mod2, mod); + + if (result.size() < mod.size() || eval_lt(result, mod)) { + if (eval_lt(result, 0)) { + eval_add(result, mod); + return; + } // make positive + return; + } else if (eval_lt(result, mod2)) { + //secure_vector ws; + Backend t1; + + eval_import_bits(t1, result.limbs() + mod.size() - 1, result.limbs() + x_sw); + { + Backend p2; + eval_bit_set(p2, 2 * Backend::limb_bits * mod.size()); + eval_divide(p2, mod); + eval_multiply(t1, p2); + } + eval_right_shift(t1, (Backend::limb_bits * (mod.size() + 1))); + + eval_multiply(t1, mod); + + eval_mask_bits(t1, Backend::limb_bits * (mod.size() + 1)); + + eval_subtract(t1, result, t1); + +// t1.rev_sub(result.data(), std::min(x_sw, mod.size() + 1), ws); + + if (eval_lt(t1, 0)) { + Backend p2; + eval_bit_set(p2, Backend::limb_bits * (mod.size() + 1)); + eval_add(t1, p2); + } + + eval_reduce_below(t1, mod); + + if (eval_lt(result, 0)) { + eval_subtract(t1, mod, t1); + } + + result = t1; + return; + } else { + // too big, fall back to normal division + Backend t2; + divide_unsigned_helper(&result, result, mod, t2); + result = t2; + return; + } + + } + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + } + } +} // namespaces + +#endif diff --git a/include/boost/multiprecision/montgomery_int/montgomery_int.hpp b/include/boost/multiprecision/montgomery_int/montgomery_int.hpp new file mode 100644 index 000000000..04d428495 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/montgomery_int.hpp @@ -0,0 +1,2473 @@ + +#ifndef CRYPTO3_MP_MONTGOMERY_INT_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_HPP + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#ifdef BOOST_MP_USER_DEFINED_LITERALS + +#include + +#endif + +#include +#include + + +namespace boost { + namespace multiprecision { + namespace backends { + + using boost::enable_if; + + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4307) // integral constant overflow (oveflow is in a branch not taken when it would overflow) +#pragma warning(disable:4127) // conditional expression is constant +#pragma warning(disable:4702) // Unreachable code (reachability depends on template params) +#endif + + template>::type, typename ParamsBackend = cpp_int > + struct montgomery_int_backend; + + } // namespace backends + + namespace detail { + + template + struct is_byte_container > + : public boost::false_type { + }; + + } // namespace detail + + namespace backends { + + template + struct montgomery_int_base; +// +// Traits class determines the maximum and minimum precision values: +// + template + struct max_precision; + + template + struct max_precision > { + static const unsigned value = is_void::value ? static_unsigned_max::value + : (((MaxBits >= MinBits) && MaxBits) ? MaxBits + : UINT_MAX); + }; + + template + struct min_precision; + + template + struct min_precision > { + static const unsigned value = (is_void::value ? static_unsigned_max::value + : MinBits); + }; +// +// Traits class determines whether the number of bits precision requested could fit in a native type, +// we call this a "trivial" cpp_int: +// + template + struct is_trivial_montgomery_int { + static const bool value = false; + }; + + template + struct is_trivial_montgomery_int > { + typedef montgomery_int_backend self; + static const bool value = is_void::value && (max_precision::value <= + (sizeof(double_limb_type) * CHAR_BIT) - + (SignType == signed_packed ? 1 : 0)); + }; + + template + struct is_trivial_montgomery_int< + montgomery_int_base > { + static const bool value = true; + }; + + template + struct is_trivial_montgomery_int > { + typedef cpp_int_backend self; + static const bool value = is_void::value && (max_precision::value <= + (sizeof(double_limb_type) * CHAR_BIT) - + (SignType == signed_packed ? 1 : 0)); + }; + + template + struct is_trivial_montgomery_int< + cpp_int_base > { + static const bool value = true; + }; + + + + } // namespace backends +// +// Traits class to determine whether a montgomery_int_backend is signed or not: +// + template + struct is_unsigned_number > + : public mpl::bool_<(SignType == unsigned_magnitude) || (SignType == unsigned_packed)> { + }; + + namespace backends { + template + struct is_non_throwing_montgomery_int : public mpl::false_{}; + template + struct is_non_throwing_montgomery_int > : public mpl::true_ {}; + + // +// Traits class determines whether T should be implicitly convertible to U, or +// whether the constructor should be made explicit. The latter happens if we +// are losing the sign, or have fewer digits precision in the target type: +// + template + struct is_equal_montgomery_int_backend { + constexpr static const bool value = false; + }; + + template + struct is_equal_montgomery_int_backend> { + constexpr static const bool value = true; + }; + + template + struct is_equal_montgomery_int_backend> { + constexpr static const bool value = true; + }; + + template + struct is_equal_montgomery_int_field { + constexpr static const bool value = false; + }; + + template + struct is_equal_montgomery_int_field> { + constexpr static const bool value = true; + }; + + + template + struct is_implicit_cpp_int_conversion { + constexpr static const bool value = (is_signed_number::value || !is_signed_number::value) && + (!std::is_constructible, T>::value && !std::is_constructible, U>::value) && + (!std::is_constructible, T>::value && !std::is_constructible, U>::value); + }; + + template + struct is_implicit_cpp_int_conversion< + montgomery_int_backend, + montgomery_int_backend > { + typedef montgomery_int_backend t1; + typedef montgomery_int_backend t2; + static const bool value = (is_signed_number::value || !is_signed_number::value) && + (max_precision::value <= max_precision::value); + }; + +// +// Traits class to determine whether operations on a cpp_int may throw: +// + /* + template + struct is_non_throwing_cpp_int : public mpl::false_ { + }; + template + struct is_non_throwing_cpp_int > + : public mpl::true_ { + }; + */ +// +// Traits class, determines whether the cpp_int is fixed precision or not: +// + template + struct is_fixed_precision; + template + struct is_fixed_precision > + : public mpl::bool_ >::value != + UINT_MAX> { + }; + + + namespace detail { + + //inline void verify_new_size(unsigned new_size, unsigned min_size, const mpl::int_ &) { + // if (new_size < min_size) + // BOOST_THROW_EXCEPTION(std::overflow_error( + // "Unable to allocate sufficient storage for the value of the result: value overflows the maximum allowable magnitude.")); + //} + + //inline void verify_new_size(unsigned /*new_size*/, unsigned /*min_size*/, + // const mpl::int_ &) { + //} + + //template + //inline void verify_limb_mask(bool b, U limb, U mask, const mpl::int_ &) { + // // When we mask out "limb" with "mask", do we loose bits? If so it's an overflow error: + // if (b && (limb & ~mask)) + // BOOST_THROW_EXCEPTION(std::overflow_error( + // "Overflow in cpp_int arithmetic: there is insufficient precision in the target type to hold all of the bits of the result.")); + //} + + //template + //inline void verify_limb_mask(bool /*b*/, U /*limb*/, U /*mask*/, const mpl::int_ &) { + //} + + } + + +// +// Now define the various data layouts that are possible as partial specializations of the base class, +// starting with the default arbitrary precision signed integer type: +// + template + struct montgomery_int_base + : private Allocator::template rebind::other { + typedef typename Allocator::template rebind::other allocator_type; + typedef typename allocator_type::pointer limb_pointer; + typedef typename allocator_type::const_pointer const_limb_pointer; + typedef mpl::int_ checked_type; + + // + // Interface invariants: + // + BOOST_STATIC_ASSERT(!is_void::value); + + private: + struct limb_data { + unsigned capacity; + limb_pointer data; + }; + + public: + BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(limb_type) * CHAR_BIT); + BOOST_STATIC_CONSTANT(limb_type, max_limb_value = ~static_cast(0u)); + BOOST_STATIC_CONSTANT(limb_type, sign_bit_mask = static_cast(1u) << (limb_bits - 1)); + BOOST_STATIC_CONSTANT(unsigned, + internal_limb_count = MinBits ? (MinBits / limb_bits + ((MinBits % limb_bits) ? 1 : 0)) : ( + sizeof(limb_data) / sizeof(limb_type))); + BOOST_STATIC_CONSTANT(bool, variable = true); + + private: + union data_type { + limb_data ld; + limb_type la[internal_limb_count]; + limb_type first; + double_limb_type double_first; + + BOOST_CONSTEXPR data_type() : first(0) { + } + + BOOST_CONSTEXPR data_type(limb_type i) : first(i) { + } + + BOOST_CONSTEXPR data_type(signed_limb_type i) : first( + i < 0 ? static_cast(boost::multiprecision::detail::unsigned_abs(i)) : i) { + } + +#ifdef BOOST_LITTLE_ENDIAN + + BOOST_CONSTEXPR data_type(double_limb_type i) : double_first(i) { + } + + BOOST_CONSTEXPR data_type(signed_double_limb_type i) : double_first( + i < 0 ? static_cast(boost::multiprecision::detail::unsigned_abs(i)) : i) { + } + +#endif + }; + + data_type m_data; + unsigned m_limbs; + bool m_sign, m_internal; + public: + // + // Direct construction: + // + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(limb_type i) BOOST_NOEXCEPT + : m_data(i), m_limbs(1), m_sign(false), m_internal(true) { + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(signed_limb_type i) BOOST_NOEXCEPT + : m_data(i), m_limbs(1), m_sign(i < 0), m_internal(true) { + } + +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(double_limb_type i) BOOST_NOEXCEPT + : m_data(i), m_limbs(i > max_limb_value ? 2 : 1), m_sign(false), m_internal(true) { + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(signed_double_limb_type i) BOOST_NOEXCEPT + : m_data(i), + m_limbs(i < 0 ? (static_cast(boost::multiprecision::detail::unsigned_abs(i)) > + static_cast(max_limb_value) ? 2 : 1) : (i > max_limb_value + ? 2 : 1)), + m_sign(i < 0), m_internal(true) { + } + +#endif + // + // Helper functions for getting at our internal data, and manipulating storage: + // + BOOST_MP_FORCEINLINE allocator_type &allocator() BOOST_NOEXCEPT { + return *this; + } + + BOOST_MP_FORCEINLINE const allocator_type &allocator() const BOOST_NOEXCEPT { + return *this; + } + + BOOST_MP_FORCEINLINE unsigned size() const BOOST_NOEXCEPT { + return m_limbs; + } + + BOOST_MP_FORCEINLINE limb_pointer limbs() BOOST_NOEXCEPT { + return m_internal ? m_data.la : m_data.ld.data; + } + + BOOST_MP_FORCEINLINE const_limb_pointer limbs() const BOOST_NOEXCEPT { + return m_internal ? m_data.la : m_data.ld.data; + } + + BOOST_MP_FORCEINLINE unsigned capacity() const BOOST_NOEXCEPT { + return m_internal ? internal_limb_count : m_data.ld.capacity; + } + + BOOST_MP_FORCEINLINE bool sign() const BOOST_NOEXCEPT { + return m_sign; + } + + void sign(bool b) BOOST_NOEXCEPT { + m_sign = b; + // Check for zero value: + if (m_sign && (m_limbs == 1)) { + if (limbs()[0] == 0) { + m_sign = false; + } + } + } + + void resize(unsigned new_size, unsigned min_size) { + static const unsigned max_limbs = MaxBits / (CHAR_BIT * sizeof(limb_type)) + + ((MaxBits % (CHAR_BIT * sizeof(limb_type))) ? 1 : 0); + // We never resize beyond MaxSize: + if (new_size > max_limbs) { + new_size = max_limbs; + } + detail::verify_new_size(new_size, min_size, checked_type()); + // See if we have enough capacity already: + unsigned cap = capacity(); + if (new_size > cap) { + // Allocate a new buffer and copy everything over: + cap = (std::min)((std::max)(cap * 4, new_size), max_limbs); + limb_pointer pl = allocator().allocate(cap); + std::memcpy(pl, limbs(), size() * sizeof(limbs()[0])); + if (!m_internal) { + allocator().deallocate(limbs(), capacity()); + } else { + m_internal = false; + } + m_limbs = new_size; + m_data.ld.capacity = cap; + m_data.ld.data = pl; + } else { + m_limbs = new_size; + } + } + + BOOST_MP_FORCEINLINE void normalize() BOOST_NOEXCEPT { + limb_pointer p = limbs(); + while ((m_limbs - 1) && !p[m_limbs - 1]) { + --m_limbs; + } + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base() BOOST_NOEXCEPT + : m_data(), m_limbs(1), m_sign(false), m_internal(true) { + } + + BOOST_MP_FORCEINLINE montgomery_int_base(const montgomery_int_base &o) : allocator_type(o), m_limbs(0), + m_internal(true) { + resize(o.size(), o.size()); + std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0])); + m_sign = o.m_sign; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + montgomery_int_base(montgomery_int_base &&o) : allocator_type(static_cast(o)), + m_limbs(o.m_limbs), m_sign(o.m_sign), m_internal(o.m_internal) { + if (m_internal) { + std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0])); + } else { + m_data.ld = o.m_data.ld; + o.m_limbs = 0; + o.m_internal = true; + } + } + + montgomery_int_base &operator=(montgomery_int_base &&o) BOOST_NOEXCEPT { + if (!m_internal) { + allocator().deallocate(m_data.ld.data, m_data.ld.capacity); + } + *static_cast(this) = static_cast(o); + m_limbs = o.m_limbs; + m_sign = o.m_sign; + m_internal = o.m_internal; + if (m_internal) { + std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0])); + } else { + m_data.ld = o.m_data.ld; + o.m_limbs = 0; + o.m_internal = true; + } + return *this; + } + +#endif + + BOOST_MP_FORCEINLINE ~montgomery_int_base() BOOST_NOEXCEPT { + if (!m_internal) { + allocator().deallocate(limbs(), capacity()); + } + } + + void assign(const montgomery_int_base &o) { + if (this != &o) { + static_cast(*this) = static_cast(o); + m_limbs = 0; + resize(o.size(), o.size()); + std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0])); + m_sign = o.m_sign; + } + } + + BOOST_MP_FORCEINLINE void negate() BOOST_NOEXCEPT { + m_sign = !m_sign; + // Check for zero value: + if (m_sign && (m_limbs == 1)) { + if (limbs()[0] == 0) { + m_sign = false; + } + } + } + + BOOST_MP_FORCEINLINE bool isneg() const BOOST_NOEXCEPT { + return m_sign; + } + + BOOST_MP_FORCEINLINE void do_swap(montgomery_int_base &o) BOOST_NOEXCEPT { + std::swap(m_data, o.m_data); + std::swap(m_sign, o.m_sign); + std::swap(m_internal, o.m_internal); + std::swap(m_limbs, o.m_limbs); + } + + protected: + template + void check_in_range(const A &) BOOST_NOEXCEPT { + } + }; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION + + template const unsigned montgomery_int_base::limb_bits; + template const limb_type montgomery_int_base::max_limb_value; + template const limb_type montgomery_int_base::sign_bit_mask; + template const unsigned montgomery_int_base::internal_limb_count; + template const bool montgomery_int_base::variable; + +#endif + + template + struct montgomery_int_base + : private Allocator::template rebind::other { + // + // There is currently no support for unsigned arbitrary precision arithmetic, largely + // because it's not clear what subtraction should do: + // + BOOST_STATIC_ASSERT_MSG(((sizeof(Allocator) == 0) && !is_void::value), + "There is curently no support for unsigned arbitrary precision integers."); + }; + +// +// Fixed precision (i.e. no allocator), signed-magnitude type with limb-usage count: +// + template + struct montgomery_int_base { + typedef limb_type *limb_pointer; + typedef const limb_type *const_limb_pointer; + typedef mpl::int_ checked_type; + + // + // Interface invariants: + // + BOOST_STATIC_ASSERT_MSG(MinBits > sizeof(double_limb_type) * CHAR_BIT, + "Template parameter MinBits is inconsistent with the parameter trivial - did you mistakingly try to override the trivial parameter?"); + + public: + BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(limb_type) * CHAR_BIT); + BOOST_STATIC_CONSTANT(limb_type, max_limb_value = ~static_cast(0u)); + BOOST_STATIC_CONSTANT(limb_type, sign_bit_mask = static_cast(1u) << (limb_bits - 1)); + BOOST_STATIC_CONSTANT(unsigned, + internal_limb_count = MinBits / limb_bits + ((MinBits % limb_bits) ? 1 : 0)); + BOOST_STATIC_CONSTANT(bool, variable = false); + BOOST_STATIC_CONSTANT(limb_type, + upper_limb_mask = (MinBits % limb_bits) ? (limb_type(1) << (MinBits % limb_bits)) - 1 + : (~limb_type(0))); + BOOST_STATIC_ASSERT_MSG(internal_limb_count >= 2, + "A fixed precision integer type must have at least 2 limbs"); + + private: + union data_type { + limb_type m_data[internal_limb_count]; + limb_type m_first_limb; + double_limb_type m_double_first_limb; + + BOOST_CONSTEXPR data_type() : m_first_limb(0) { + } + + BOOST_CONSTEXPR data_type(limb_type i) : m_first_limb(i) { + } + + BOOST_CONSTEXPR data_type(double_limb_type i) : m_double_first_limb(i) { + } + +#if defined(BOOST_MP_USER_DEFINED_LITERALS) + + template + BOOST_CONSTEXPR data_type(literals::detail::value_pack) : m_data{VALUES...} { + } + +#endif + } m_wrapper; + + boost::uint16_t m_limbs; + bool m_sign; + + public: + // + // Direct construction: + // + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(limb_type i) BOOST_NOEXCEPT + : m_wrapper(i), m_limbs(1), m_sign(false) { + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(signed_limb_type i) BOOST_NOEXCEPT + : m_wrapper( + limb_type(i < 0 ? static_cast(-static_cast(i)) : i)), + m_limbs(1), m_sign(i < 0) { + } + +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(double_limb_type i) BOOST_NOEXCEPT + : m_wrapper(i), m_limbs(i > max_limb_value ? 2 : 1), m_sign(false) { + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(signed_double_limb_type i) BOOST_NOEXCEPT + : m_wrapper(double_limb_type( + i < 0 ? static_cast(boost::multiprecision::detail::unsigned_abs(i)) : i)), + m_limbs(i < 0 ? (static_cast(boost::multiprecision::detail::unsigned_abs(i)) > + max_limb_value ? 2 : 1) : (i > max_limb_value ? 2 : 1)), m_sign(i < 0) { + } + +#endif +#if defined(BOOST_MP_USER_DEFINED_LITERALS) + + template + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack i) + : m_wrapper(i), m_limbs(sizeof...(VALUES)), m_sign(false) { + } + + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack<> i) : m_wrapper(i), m_limbs(1), + m_sign(false) { + } + + BOOST_CONSTEXPR montgomery_int_base(const montgomery_int_base &a, const literals::detail::negate_tag &) + : m_wrapper(a.m_wrapper), m_limbs(a.m_limbs), + m_sign((a.m_limbs == 1) && (*a.limbs() == 0) ? false : !a.m_sign) { + } + +#endif + // + // Helper functions for getting at our internal data, and manipulating storage: + // + BOOST_MP_FORCEINLINE unsigned size() const BOOST_NOEXCEPT { + return m_limbs; + } + + BOOST_MP_FORCEINLINE limb_pointer limbs() BOOST_NOEXCEPT { + return m_wrapper.m_data; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const_limb_pointer limbs() const BOOST_NOEXCEPT { + return m_wrapper.m_data; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool sign() const BOOST_NOEXCEPT { + return m_sign; + } + + BOOST_MP_FORCEINLINE void sign(bool b) BOOST_NOEXCEPT { + m_sign = b; + // Check for zero value: + if (m_sign && (m_limbs == 1)) { + if (limbs()[0] == 0) { + m_sign = false; + } + } + } + + BOOST_MP_FORCEINLINE void resize(unsigned new_size, unsigned min_size) BOOST_MP_NOEXCEPT_IF( + (Checked == unchecked)) { + m_limbs = static_cast((std::min)(new_size, internal_limb_count)); + detail::verify_new_size(m_limbs, min_size, checked_type()); + } + + BOOST_MP_FORCEINLINE void normalize() BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) { + limb_pointer p = limbs(); + detail::verify_limb_mask(m_limbs == internal_limb_count, p[internal_limb_count - 1], + upper_limb_mask, checked_type()); + p[internal_limb_count - 1] &= upper_limb_mask; + while ((m_limbs - 1) && !p[m_limbs - 1]) { + --m_limbs; + } + if ((m_limbs == 1) && (!*p)) { + m_sign = false; + } // zero is always unsigned + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base() BOOST_NOEXCEPT : m_wrapper(limb_type(0u)), + m_limbs(1), m_sign(false) { + } + // Not defaulted, it breaks constexpr support in the Intel compiler for some reason: + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(const montgomery_int_base &o) BOOST_NOEXCEPT + : m_wrapper(o.m_wrapper), m_limbs(o.m_limbs), m_sign(o.m_sign) { + } + // Defaulted functions: + //~montgomery_int_base() BOOST_NOEXCEPT {} + + void assign(const montgomery_int_base &o) BOOST_NOEXCEPT { + if (this != &o) { + m_limbs = o.m_limbs; + std::memcpy(limbs(), o.limbs(), o.size() * sizeof(o.limbs()[0])); + m_sign = o.m_sign; + } + } + + BOOST_MP_FORCEINLINE void negate() BOOST_NOEXCEPT { + m_sign = !m_sign; + // Check for zero value: + if (m_sign && (m_limbs == 1)) { + if (limbs()[0] == 0) { + m_sign = false; + } + } + } + + BOOST_MP_FORCEINLINE bool isneg() const BOOST_NOEXCEPT { + return m_sign; + } + + BOOST_MP_FORCEINLINE void do_swap(montgomery_int_base &o) BOOST_NOEXCEPT { + for (unsigned i = 0; i < (std::max)(size(), o.size()); ++i) { + std::swap(m_wrapper.m_data[i], o.m_wrapper.m_data[i]); + } + std::swap(m_sign, o.m_sign); + std::swap(m_limbs, o.m_limbs); + } + + protected: + template + void check_in_range(const A &) BOOST_NOEXCEPT { + } + }; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION + + template const unsigned montgomery_int_base::limb_bits; + template const limb_type montgomery_int_base::max_limb_value; + template const limb_type montgomery_int_base::sign_bit_mask; + template const unsigned montgomery_int_base::internal_limb_count; + template const bool montgomery_int_base::variable; + +#endif + +// +// Fixed precision (i.e. no allocator), unsigned type with limb-usage count: +// + template + struct montgomery_int_base { + typedef limb_type *limb_pointer; + typedef const limb_type *const_limb_pointer; + typedef mpl::int_ checked_type; + + // + // Interface invariants: + // + BOOST_STATIC_ASSERT_MSG(MinBits > sizeof(double_limb_type) * CHAR_BIT, + "Template parameter MinBits is inconsistent with the parameter trivial - did you mistakingly try to override the trivial parameter?"); + + public: + BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(limb_type) * CHAR_BIT); + BOOST_STATIC_CONSTANT(limb_type, max_limb_value = ~static_cast(0u)); + BOOST_STATIC_CONSTANT(limb_type, sign_bit_mask = static_cast(1u) << (limb_bits - 1)); + BOOST_STATIC_CONSTANT(unsigned, + internal_limb_count = MinBits / limb_bits + ((MinBits % limb_bits) ? 1 : 0)); + BOOST_STATIC_CONSTANT(bool, variable = false); + BOOST_STATIC_CONSTANT(limb_type, + upper_limb_mask = (MinBits % limb_bits) ? (limb_type(1) << (MinBits % limb_bits)) - 1 + : (~limb_type(0))); + BOOST_STATIC_ASSERT_MSG(internal_limb_count >= 2, + "A fixed precision integer type must have at least 2 limbs"); + + private: + union data_type { + limb_type m_data[internal_limb_count]; + limb_type m_first_limb; + double_limb_type m_double_first_limb; + + BOOST_CONSTEXPR data_type() : m_first_limb(0) { + } + + BOOST_CONSTEXPR data_type(limb_type i) : m_first_limb(i) { + } + + BOOST_CONSTEXPR data_type(double_limb_type i) : m_double_first_limb(i) { + } + +#if defined(BOOST_MP_USER_DEFINED_LITERALS) + + template + BOOST_CONSTEXPR data_type(literals::detail::value_pack) : m_data{VALUES...} { + } + +#endif + } m_wrapper; + + limb_type m_limbs; + + public: + // + // Direct construction: + // + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(limb_type i) BOOST_NOEXCEPT + : m_wrapper(i), m_limbs(1) { + } + + BOOST_MP_FORCEINLINE montgomery_int_base(signed_limb_type i) BOOST_MP_NOEXCEPT_IF( + (Checked == unchecked)) + : m_wrapper( + limb_type(i < 0 ? static_cast(-static_cast(i)) : i)), + m_limbs(1) { + if (i < 0) { + negate(); + } + } + +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(double_limb_type i) BOOST_NOEXCEPT + : m_wrapper(i), m_limbs(i > max_limb_value ? 2 : 1) { + } + + BOOST_MP_FORCEINLINE montgomery_int_base(signed_double_limb_type i) BOOST_MP_NOEXCEPT_IF( + (Checked == unchecked)) + : m_wrapper(double_limb_type( + i < 0 ? static_cast(boost::multiprecision::detail::unsigned_abs(i)) : i)), + m_limbs(i < 0 ? (static_cast(boost::multiprecision::detail::unsigned_abs(i)) > + max_limb_value ? 2 : 1) : (i > max_limb_value ? 2 : 1)) { + if (i < 0) { + negate(); + } + } + +#endif +#if defined(BOOST_MP_USER_DEFINED_LITERALS) + + template + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack i) + : m_wrapper(i), m_limbs(sizeof...(VALUES)) { + } + + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack<>) : m_wrapper( + static_cast(0u)), m_limbs(1) { + } + +#endif + // + // Helper functions for getting at our internal data, and manipulating storage: + // + BOOST_MP_FORCEINLINE unsigned size() const BOOST_NOEXCEPT { + return m_limbs; + } + + BOOST_MP_FORCEINLINE limb_pointer limbs() BOOST_NOEXCEPT { + return m_wrapper.m_data; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const_limb_pointer limbs() const BOOST_NOEXCEPT { + return m_wrapper.m_data; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool sign() const BOOST_NOEXCEPT { + return false; + } + + BOOST_MP_FORCEINLINE void sign(bool b) BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) { + if (b) { + negate(); + } + } + + BOOST_MP_FORCEINLINE void resize(unsigned new_size, unsigned min_size) BOOST_MP_NOEXCEPT_IF( + (Checked == unchecked)) { + m_limbs = (std::min)(new_size, internal_limb_count); + detail::verify_new_size(m_limbs, min_size, checked_type()); + } + + BOOST_MP_FORCEINLINE void normalize() BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) { + limb_pointer p = limbs(); + detail::verify_limb_mask(m_limbs == internal_limb_count, p[internal_limb_count - 1], + upper_limb_mask, checked_type()); + p[internal_limb_count - 1] &= upper_limb_mask; + while ((m_limbs - 1) && !p[m_limbs - 1]) { + --m_limbs; + } + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base() BOOST_NOEXCEPT + : m_wrapper(limb_type(0u)), m_limbs(1) { + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(const montgomery_int_base &o) BOOST_NOEXCEPT + : m_wrapper(o.m_wrapper), m_limbs(o.m_limbs) { + } + // Defaulted functions: + //~montgomery_int_base() BOOST_NOEXCEPT {} + + BOOST_MP_FORCEINLINE void assign(const montgomery_int_base &o) BOOST_NOEXCEPT { + if (this != &o) { + m_limbs = o.m_limbs; + std::memcpy(limbs(), o.limbs(), o.size() * sizeof(limbs()[0])); + } + } + + private: + void check_negate(const mpl::int_ &) { + BOOST_THROW_EXCEPTION(std::range_error("Attempt to negate an unsigned number.")); + } + + void check_negate(const mpl::int_ &) { + } + + public: + void negate() BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) { + // Not so much a negate as a complement - this gets called when subtraction + // would result in a "negative" number: + unsigned i; + if ((m_limbs == 1) && (m_wrapper.m_data[0] == 0)) { + return; + } // negating zero is always zero, and always OK. + check_negate(checked_type()); + for (i = m_limbs; i < internal_limb_count; ++i) { + m_wrapper.m_data[i] = 0; + } + m_limbs = internal_limb_count; + for (i = 0; i < internal_limb_count; ++i) { + m_wrapper.m_data[i] = ~m_wrapper.m_data[i]; + } + normalize(); + eval_increment(static_cast & >(*this)); + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool isneg() const BOOST_NOEXCEPT { + return false; + } + + BOOST_MP_FORCEINLINE void do_swap(montgomery_int_base &o) BOOST_NOEXCEPT { + for (unsigned i = 0; i < (std::max)(size(), o.size()); ++i) { + std::swap(m_wrapper.m_data[i], o.m_wrapper.m_data[i]); + } + std::swap(m_limbs, o.m_limbs); + } + + protected: + template + void check_in_range(const A &) BOOST_NOEXCEPT { + } + }; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION + + template const unsigned montgomery_int_base::limb_bits; + template const limb_type montgomery_int_base::max_limb_value; + template const limb_type montgomery_int_base::sign_bit_mask; + template const unsigned montgomery_int_base::internal_limb_count; + template const bool montgomery_int_base::variable; + +#endif +// +// Traits classes to figure out a native type with N bits, these vary from boost::uint_t only +// because some platforms have native integer types longer than boost::long_long_type, "really boost::long_long_type" anyone?? +// + /* + template + struct trivial_limb_type_imp { + typedef double_limb_type type; + }; + + template + struct trivial_limb_type_imp { + typedef typename boost::uint_t::least type; + }; + + template + struct trivial_limb_type : public trivial_limb_type_imp { + }; + */ + +// +// Backend for fixed precision signed-magnitude type which will fit entirely inside a "double_limb_type": +// + template + struct montgomery_int_base { + typedef typename trivial_limb_type::type local_limb_type; + typedef local_limb_type *limb_pointer; + typedef const local_limb_type *const_limb_pointer; + typedef mpl::int_ checked_type; + protected: + BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(local_limb_type) * CHAR_BIT); + BOOST_STATIC_CONSTANT(local_limb_type, limb_mask = (MinBits < limb_bits) ? local_limb_type( + (local_limb_type(~local_limb_type(0))) >> (limb_bits - MinBits)) : local_limb_type( + ~local_limb_type(0))); + private: + local_limb_type m_data; + bool m_sign; + + // + // Interface invariants: + // + BOOST_STATIC_ASSERT_MSG(MinBits <= sizeof(double_limb_type) * CHAR_BIT, + "Template parameter MinBits is inconsistent with the parameter trivial - did you mistakingly try to override the trivial parameter?"); + protected: + template + typename boost::disable_if_c::value || (std::numeric_limits::is_specialized && + (std::numeric_limits::digits <= + (int) MinBits))>::type check_in_range( + T val, const mpl::int_ &) { + typedef typename common_type::type, local_limb_type>::type common_type; + + if (static_cast(boost::multiprecision::detail::unsigned_abs(val)) > + static_cast(limb_mask)) + BOOST_THROW_EXCEPTION(std::range_error( + "The argument to a cpp_int constructor exceeded the largest value it can represent.")); + } + + template + typename boost::disable_if_c::value || (std::numeric_limits::is_specialized && + (std::numeric_limits::digits <= + (int) MinBits))>::type check_in_range( + T val, const mpl::int_ &) { + using std::abs; + typedef typename common_type::type common_type; + + if (static_cast(abs(val)) > static_cast(limb_mask)) + BOOST_THROW_EXCEPTION(std::range_error( + "The argument to a cpp_int constructor exceeded the largest value it can represent.")); + } + + template + void check_in_range(T, const mpl::int_ &) BOOST_NOEXCEPT { + } + + template + void check_in_range(T val) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().check_in_range(std::declval(), + checked_type()))) { + check_in_range(val, checked_type()); + } + + public: + // + // Direct construction: + // + template + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(SI i, typename boost::enable_if_c< + is_signed::value && (Checked == unchecked)>::type const * = 0) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().check_in_range(std::declval()))) + : m_data(i < 0 ? static_cast( + static_cast::type>(boost::multiprecision::detail::unsigned_abs(i)) & + limb_mask) : static_cast(i & limb_mask)), m_sign(i < 0) { + } + + template + BOOST_MP_FORCEINLINE montgomery_int_base(SI i, typename boost::enable_if_c< + is_signed::value && (Checked == checked)>::type const * = 0) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().check_in_range(std::declval()))) + : m_data(i < 0 ? (static_cast( + static_cast::type>(boost::multiprecision::detail::unsigned_abs(i)) & + limb_mask)) : static_cast(i & limb_mask)), m_sign(i < 0) { + check_in_range(i); + } + + template + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(UI i, typename boost::enable_if_c< + is_unsigned::value && (Checked == unchecked)>::type const * = 0) BOOST_NOEXCEPT + : m_data(static_cast(i) & limb_mask), m_sign(false) { + } + + template + BOOST_MP_FORCEINLINE montgomery_int_base(UI i, typename boost::enable_if_c< + is_unsigned::value && (Checked == checked)>::type const * = 0) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().check_in_range(std::declval()))) + : m_data(static_cast(i) & limb_mask), m_sign(false) { + check_in_range(i); + } + + template + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(F i, typename boost::enable_if_c< + is_floating_point::value && (Checked == unchecked)>::type const * = 0) BOOST_NOEXCEPT + : m_data(static_cast(std::fabs(i)) & limb_mask), m_sign(i < 0) { + } + + template + BOOST_MP_FORCEINLINE montgomery_int_base(F i, typename boost::enable_if_c< + is_floating_point::value && (Checked == checked)>::type const * = 0) + : m_data(static_cast(std::fabs(i)) & limb_mask), m_sign(i < 0) { + check_in_range(i); + } + +#if defined(BOOST_MP_USER_DEFINED_LITERALS) + + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack<>) BOOST_NOEXCEPT + : m_data(static_cast(0u)), m_sign(false) { + } + + template + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack) BOOST_NOEXCEPT + : m_data(static_cast(a)), m_sign(false) { + } + + template + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack) BOOST_NOEXCEPT + : m_data(static_cast(a) | (static_cast(b) << bits_per_limb)), + m_sign(false) { + } + + BOOST_CONSTEXPR montgomery_int_base(const montgomery_int_base &a, + const literals::detail::negate_tag &) BOOST_NOEXCEPT + : m_data(a.m_data), m_sign(a.m_data ? !a.m_sign : false) { + } + +#endif + // + // Helper functions for getting at our internal data, and manipulating storage: + // + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR unsigned size() const BOOST_NOEXCEPT { + return 1; + } + + BOOST_MP_FORCEINLINE limb_pointer limbs() BOOST_NOEXCEPT { + return &m_data; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const_limb_pointer limbs() const BOOST_NOEXCEPT { + return &m_data; + } + + BOOST_MP_FORCEINLINE bool sign() const BOOST_NOEXCEPT { + return m_sign; + } + + BOOST_MP_FORCEINLINE void sign(bool b) BOOST_NOEXCEPT { + m_sign = b; + // Check for zero value: + if (m_sign && !m_data) { + m_sign = false; + } + } + + BOOST_MP_FORCEINLINE void resize(unsigned new_size, unsigned min_size) { + detail::verify_new_size(2, min_size, checked_type()); + } + + BOOST_MP_FORCEINLINE void normalize() BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) { + if (!m_data) { + m_sign = false; + } // zero is always unsigned + detail::verify_limb_mask(true, m_data, limb_mask, checked_type()); + m_data &= limb_mask; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base() BOOST_NOEXCEPT : m_data(0), m_sign(false) { + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(const montgomery_int_base &o) BOOST_NOEXCEPT + : m_data(o.m_data), m_sign(o.m_sign) { + } + //~montgomery_int_base() BOOST_NOEXCEPT {} + BOOST_MP_FORCEINLINE void assign(const montgomery_int_base &o) BOOST_NOEXCEPT { + m_data = o.m_data; + m_sign = o.m_sign; + } + + BOOST_MP_FORCEINLINE void negate() BOOST_NOEXCEPT { + m_sign = !m_sign; + // Check for zero value: + if (m_data == 0) { + m_sign = false; + } + } + + BOOST_MP_FORCEINLINE bool isneg() const BOOST_NOEXCEPT { + return m_sign; + } + + BOOST_MP_FORCEINLINE void do_swap(montgomery_int_base &o) BOOST_NOEXCEPT { + std::swap(m_sign, o.m_sign); + std::swap(m_data, o.m_data); + } + }; + +// +// Backend for unsigned fixed precision (i.e. no allocator) type which will fit entirely inside a "double_limb_type": +// + template + struct montgomery_int_base { + typedef typename trivial_limb_type::type local_limb_type; + typedef local_limb_type *limb_pointer; + typedef const local_limb_type *const_limb_pointer; + private: + BOOST_STATIC_CONSTANT(unsigned, limb_bits = sizeof(local_limb_type) * CHAR_BIT); + BOOST_STATIC_CONSTANT(local_limb_type, limb_mask = limb_bits != MinBits ? static_cast( + static_cast(~local_limb_type(0)) >> (limb_bits - MinBits)) + : static_cast(~local_limb_type( + 0))); + + local_limb_type m_data; + + typedef mpl::int_ checked_type; + + // + // Interface invariants: + // + BOOST_STATIC_ASSERT_MSG(MinBits <= sizeof(double_limb_type) * CHAR_BIT, + "Template parameter MinBits is inconsistent with the parameter trivial - did you mistakingly try to override the trivial parameter?"); + protected: + template + typename boost::disable_if_c::is_specialized && + (std::numeric_limits::digits <= (int) MinBits)>::type check_in_range( + T val, const mpl::int_ &, const boost::false_type &) { + typedef typename common_type::type common_type; + + if (static_cast(val) > limb_mask) + BOOST_THROW_EXCEPTION(std::range_error( + "The argument to a cpp_int constructor exceeded the largest value it can represent.")); + } + + template + void check_in_range(T val, const mpl::int_ &, const boost::true_type &) { + typedef typename common_type::type common_type; + + if (static_cast(val) > limb_mask) + BOOST_THROW_EXCEPTION(std::range_error( + "The argument to a cpp_int constructor exceeded the largest value it can represent.")); + if (val < 0) + BOOST_THROW_EXCEPTION( + std::range_error("The argument to an unsigned cpp_int constructor was negative.")); + } + + template + BOOST_MP_FORCEINLINE void check_in_range(T, const mpl::int_ &, + const boost::integral_constant &) BOOST_NOEXCEPT { + } + + template + BOOST_MP_FORCEINLINE void check_in_range(T val) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().check_in_range(std::declval(), checked_type(), + is_signed()))) { + check_in_range(val, checked_type(), is_signed()); + } + + public: + // + // Direct construction: + // +#ifdef __MSVC_RUNTIME_CHECKS + template + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(SI i, typename boost::enable_if_c::value && (Checked == unchecked) >::type const* = 0) BOOST_NOEXCEPT + : m_data(i < 0 ? (1 + ~static_cast(-i & limb_mask)) & limb_mask : static_cast(i & limb_mask)) {} + template + BOOST_MP_FORCEINLINE montgomery_int_base(SI i, typename boost::enable_if_c::value && (Checked == checked) >::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval().check_in_range(std::declval()))) + : m_data(i < 0 ? 1 + ~static_cast(-i & limb_mask) : static_cast(i & limb_mask)) { check_in_range(i); } + template + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(UI i, typename boost::enable_if_c::value && (Checked == unchecked) >::type const* = 0) BOOST_NOEXCEPT + : m_data(static_cast(i & limb_mask)) {} + template + BOOST_MP_FORCEINLINE montgomery_int_base(UI i, typename boost::enable_if_c::value && (Checked == checked) >::type const* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval().check_in_range(std::declval()))) + : m_data(static_cast(i & limb_mask)) { check_in_range(i); } +#else + + template + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(SI i, typename boost::enable_if_c< + is_signed::value && (Checked == unchecked)>::type const * = 0) BOOST_NOEXCEPT + : m_data( + i < 0 ? (1 + ~static_cast(-i)) & limb_mask : static_cast(i) & + limb_mask) { + } + + template + BOOST_MP_FORCEINLINE montgomery_int_base(SI i, typename boost::enable_if_c< + is_signed::value && (Checked == checked)>::type const * = 0) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().check_in_range(std::declval()))) + : m_data(i < 0 ? 1 + ~static_cast(-i) : static_cast(i)) { + check_in_range(i); + } + + template + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(UI i, typename boost::enable_if_c< + is_unsigned::value && (Checked == unchecked)>::type const * = 0) BOOST_NOEXCEPT + : m_data(static_cast(i) & limb_mask) { + } + + template + BOOST_MP_FORCEINLINE montgomery_int_base(UI i, typename boost::enable_if_c< + is_unsigned::value && (Checked == checked)>::type const * = 0) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().check_in_range(std::declval()))) + : m_data(static_cast(i)) { + check_in_range(i); + } + +#endif + + template + BOOST_MP_FORCEINLINE montgomery_int_base(F i, typename boost::enable_if< + is_floating_point >::type const * = 0) BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) + : m_data(static_cast(std::fabs(i)) & limb_mask) { + check_in_range(i); + if (i < 0) { + negate(); + } + } + +#if defined(BOOST_MP_USER_DEFINED_LITERALS) + + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack<>) BOOST_NOEXCEPT + : m_data(static_cast(0u)) { + } + + template + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack) BOOST_NOEXCEPT + : m_data(static_cast(a)) { + } + + template + BOOST_CONSTEXPR montgomery_int_base(literals::detail::value_pack) BOOST_NOEXCEPT + : m_data(static_cast(a) | (static_cast(b) << bits_per_limb)) { + } + +#endif + // + // Helper functions for getting at our internal data, and manipulating storage: + // + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR unsigned size() const BOOST_NOEXCEPT { + return 1; + } + + BOOST_MP_FORCEINLINE limb_pointer limbs() BOOST_NOEXCEPT { + return &m_data; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const_limb_pointer limbs() const BOOST_NOEXCEPT { + return &m_data; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool sign() const BOOST_NOEXCEPT { + return false; + } + + BOOST_MP_FORCEINLINE void sign(bool b) BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) { + if (b) { + negate(); + } + } + + BOOST_MP_FORCEINLINE void resize(unsigned, unsigned min_size) { + detail::verify_new_size(2, min_size, checked_type()); + } + + BOOST_MP_FORCEINLINE void normalize() BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) { + detail::verify_limb_mask(true, m_data, limb_mask, checked_type()); + m_data &= limb_mask; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base() BOOST_NOEXCEPT : m_data(0) { + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_base(const montgomery_int_base &o) BOOST_NOEXCEPT + : m_data(o.m_data) { + } + //~montgomery_int_base() BOOST_NOEXCEPT {} + BOOST_MP_FORCEINLINE void assign(const montgomery_int_base &o) BOOST_NOEXCEPT { + m_data = o.m_data; + } + + BOOST_MP_FORCEINLINE void negate() BOOST_MP_NOEXCEPT_IF((Checked == unchecked)) { + if (Checked == checked) { + BOOST_THROW_EXCEPTION(std::range_error("Attempt to negate an unsigned type.")); + } + m_data = ~m_data; + ++m_data; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool isneg() const BOOST_NOEXCEPT { + return false; + } + + BOOST_MP_FORCEINLINE void do_swap(montgomery_int_base &o) BOOST_NOEXCEPT { + std::swap(m_data, o.m_data); + } + }; + +// +// Traits class, lets us know whether type T can be directly converted to the base type, +// used to enable/disable constructors etc: +// + template + struct is_allowed_montgomery_int_base_conversion : public mpl::if_c< + is_same::value || is_same::value + #if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) + || is_same::value || is_same::value + #endif + #if defined(BOOST_MP_USER_DEFINED_LITERALS) + || literals::detail::is_value_pack::value + #endif + || (is_trivial_montgomery_int < Base > ::value && is_arithmetic::value), mpl::true_, + mpl::false_>::type { + }; + +// +// Now the actual backend, normalising parameters passed to the base class: +// + /*!template + */ + template + struct montgomery_int_backend : public montgomery_int_base< + min_precision >::value, + max_precision >::value, + SignType, Checked, Allocator, ParamsBackend, is_trivial_montgomery_int< + montgomery_int_backend >::value> { + typedef montgomery_int_backend self_type; + typedef montgomery_int_base::value, max_precision::value, SignType, + Checked, Allocator, ParamsBackend, is_trivial_montgomery_int::value> base_type; + typedef mpl::bool_::value> trivial_tag; + public: + typedef typename mpl::if_, + mpl::list >::type signed_types; + typedef typename mpl::if_, mpl::list >::type unsigned_types; + typedef typename mpl::if_, + mpl::list >::type float_types; + typedef mpl::int_ checked_type; + + nil::crypto3::montgomery_params m_params; + + //montgomery_int_backend value() const { + void value() const { + //auto t = this->limbs(); + //auto x = redc(m_params, t); + //auto x = redc(*this); + //return redc(this); + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_backend() BOOST_NOEXCEPT { + + } + + //zerg + template + montgomery_int_backend(const cpp_int_backend &o, + const nil::crypto3::montgomery_params ¶ms) : base_type(o) { + m_params = params; + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_backend( + const montgomery_int_backend &o) BOOST_MP_NOEXCEPT_IF(boost::is_void::value) + : base_type(o) { + m_params = o.m_params; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_backend(montgomery_int_backend &&o) BOOST_NOEXCEPT + : base_type(static_cast(o)) { + } + +#endif + template + montgomery_int_backend(Arg i, const nil::crypto3::montgomery_params &p, typename boost::enable_if_c< + is_allowed_montgomery_int_base_conversion::value>::type const * = 0) BOOST_MP_NOEXCEPT_IF( + noexcept(base_type(std::declval()))) + : base_type(i) { + m_params = p; + } + // + // Direct construction from arithmetic type: + // + template + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_int_backend(Arg i, typename boost::enable_if_c< + is_allowed_montgomery_int_base_conversion::value>::type const * = 0) BOOST_MP_NOEXCEPT_IF( + noexcept(base_type(std::declval()))) + : base_type(i) { + } + + private: + template + void do_assign(const montgomery_int_backend &other, + mpl::true_ const &, mpl::true_ const &) { + // Assigning trivial type to trivial type: + this->check_in_range(*other.limbs()); + *this->limbs() = static_cast(*other.limbs()); + this->sign(other.sign()); + this->normalize(); + } + + template + void do_assign(const montgomery_int_backend &other, + mpl::true_ const &, mpl::false_ const &) { + // non-trivial to trivial narrowing conversion: + double_limb_type v = *other.limbs(); + if (other.size() > 1) { + v |= static_cast(other.limbs()[1]) << bits_per_limb; + if ((Checked == checked) && (other.size() > 2)) { + BOOST_THROW_EXCEPTION(std::range_error( + "Assignment of a cpp_int that is out of range for the target type.")); + } + } + *this = v; + this->sign(other.sign()); + this->normalize(); + } + + template + void do_assign(const montgomery_int_backend &other, + mpl::false_ const &, mpl::true_ const &) { + // trivial to non-trivial, treat the trivial argument as if it were an unsigned arithmetic type, then set the sign afterwards: + *this = static_cast< + typename boost::multiprecision::detail::canonical< + typename montgomery_int_backend::local_limb_type, + montgomery_int_backend >::type + >(*other.limbs()); + this->sign(other.sign()); + } + + template + void do_assign(const montgomery_int_backend &other, + mpl::false_ const &, mpl::false_ const &) { + // regular non-trivial to non-trivial assign: + this->resize(other.size(), other.size()); + std::memcpy(this->limbs(), other.limbs(), + (std::min)(other.size(), this->size()) * sizeof(this->limbs()[0])); + this->sign(other.sign()); + this->normalize(); + } + + public: + template + montgomery_int_backend( + const montgomery_int_backend &other, + typename boost::enable_if_c, + self_type>::value>::type * = 0) + : base_type() { + do_assign(other, mpl::bool_::value>(), mpl::bool_< + is_trivial_montgomery_int >::value>()); + } + + template + explicit montgomery_int_backend( + const montgomery_int_backend &other, + typename boost::disable_if_c, + self_type>::value>::type * = 0) + : base_type() { + do_assign(other, mpl::bool_::value>(), mpl::bool_< + is_trivial_montgomery_int >::value>()); + } + + template + montgomery_int_backend &operator=( + const montgomery_int_backend &other) { + do_assign(other, mpl::bool_::value>(), mpl::bool_< + is_trivial_montgomery_int >::value>()); + return *this; + } + +#ifdef BOOST_MP_USER_DEFINED_LITERALS + + BOOST_CONSTEXPR montgomery_int_backend(const montgomery_int_backend &a, + const literals::detail::negate_tag &tag) : base_type( + static_cast(a), tag) { + } + +#endif + + BOOST_MP_FORCEINLINE montgomery_int_backend &operator=( + const montgomery_int_backend &o) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().assign( + std::declval()))) { + this->assign(o); + m_params = o.m_params; + return *this; + } + /* + BOOST_MP_FORCEINLINE montgomery_int_backend &operator=( + const cpp_int &o) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().assign( + std::declval()))) { + //this->assign(o); + return *this; + } + */ +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + BOOST_MP_FORCEINLINE montgomery_int_backend &operator=(montgomery_int_backend &&o) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval() = std::declval())) { + *static_cast(this) = static_cast(o); + return *this; + } + +#endif + private: + template + typename boost::enable_if >::type do_assign_arithmetic(A val, + const mpl::true_ &) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().check_in_range(std::declval()))) { + this->check_in_range(val); + *this->limbs() = static_cast(val); + this->normalize(); + } + + template + typename boost::disable_if_c< + is_unsigned::value || !is_integral::value>::type do_assign_arithmetic(A val, + const mpl::true_ &) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().check_in_range(std::declval())) && + noexcept(std::declval().sign(true))) { + this->check_in_range(val); + *this->limbs() = (val < 0) + ? static_cast(boost::multiprecision::detail::unsigned_abs( + val)) : static_cast(val); + this->sign(val < 0); + this->normalize(); + } + + template + typename boost::enable_if_c::value>::type do_assign_arithmetic(A val, + const mpl::true_ &) { + this->check_in_range(val); + *this->limbs() = (val < 0) + ? static_cast(boost::multiprecision::detail::abs( + val)) : static_cast(val); + this->sign(val < 0); + this->normalize(); + } + + BOOST_MP_FORCEINLINE void do_assign_arithmetic(limb_type i, const mpl::false_ &) BOOST_NOEXCEPT { + this->resize(1, 1); + *this->limbs() = i; + this->sign(false); + } + + BOOST_MP_FORCEINLINE void do_assign_arithmetic(signed_limb_type i, + const mpl::false_ &) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().sign(true))) { + this->resize(1, 1); + *this->limbs() = static_cast(boost::multiprecision::detail::unsigned_abs(i)); + this->sign(i < 0); + } + + void do_assign_arithmetic(double_limb_type i, const mpl::false_ &) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT(sizeof(i) == 2 * sizeof(limb_type)); + BOOST_STATIC_ASSERT(base_type::internal_limb_count >= 2); + typename base_type::limb_pointer p = this->limbs(); +#ifdef __MSVC_RUNTIME_CHECKS + *p = static_cast(i & ~static_cast(0)); +#else + *p = static_cast(i); +#endif + p[1] = static_cast(i >> base_type::limb_bits); + this->resize(p[1] ? 2 : 1, p[1] ? 2 : 1); + this->sign(false); + } + + void do_assign_arithmetic(signed_double_limb_type i, const mpl::false_ &) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().sign(true))) { + BOOST_STATIC_ASSERT(sizeof(i) == 2 * sizeof(limb_type)); + BOOST_STATIC_ASSERT(base_type::internal_limb_count >= 2); + bool s = false; + double_limb_type ui; + if (i < 0) { + s = true; + } + ui = static_cast(boost::multiprecision::detail::unsigned_abs(i)); + typename base_type::limb_pointer p = this->limbs(); +#ifdef __MSVC_RUNTIME_CHECKS + *p = static_cast(ui & ~static_cast(0)); +#else + *p = static_cast(ui); +#endif + p[1] = static_cast(ui >> base_type::limb_bits); + this->resize(p[1] ? 2 : 1, p[1] ? 2 : 1); + this->sign(s); + } + + void do_assign_arithmetic(long double a, const mpl::false_ &) { + using default_ops::eval_add; + using default_ops::eval_subtract; + using std::frexp; + using std::ldexp; + using std::floor; + + if (a < 0) { + do_assign_arithmetic(-a, mpl::false_()); + this->sign(true); + return; + } + + if (a == 0) { + *this = static_cast(0u); + } + + if (a == 1) { + *this = static_cast(1u); + } + + BOOST_ASSERT(!(boost::math::isinf)(a)); + BOOST_ASSERT(!(boost::math::isnan)(a)); + + int e; + long double f, term; + *this = static_cast(0u); + + f = frexp(a, &e); + + static const limb_type shift = std::numeric_limits::digits; + + while (f) { + // extract int sized bits from f: + f = ldexp(f, shift); + term = floor(f); + e -= shift; + eval_left_shift(*this, shift); + if (term > 0) { + eval_add(*this, static_cast(term)); + } else { + eval_subtract(*this, static_cast(-term)); + } + f -= term; + } + if (e > 0) { + eval_left_shift(*this, e); + } else if (e < 0) { + eval_right_shift(*this, -e); + } + } + + public: + template + BOOST_MP_FORCEINLINE typename boost::enable_if_c< + !boost::multiprecision::detail::is_byte_container::value, + montgomery_int_backend &>::type operator=(Arithmetic val) BOOST_MP_NOEXCEPT_IF( + noexcept(std::declval().do_assign_arithmetic(std::declval(), + trivial_tag()))) { + do_assign_arithmetic(val, trivial_tag()); + return *this; + } + + private: + void do_assign_string(const char *s, const mpl::true_ &) { + std::size_t n = s ? std::strlen(s) : 0; + *this = 0; + unsigned radix = 10; + bool isneg = false; + if (n && (*s == '-')) { + --n; + ++s; + isneg = true; + } + if (n && (*s == '0')) { + if ((n > 1) && ((s[1] == 'x') || (s[1] == 'X'))) { + radix = 16; + s += 2; + n -= 2; + } else { + radix = 8; + n -= 1; + } + } + if (n) { + unsigned val; + while (*s) { + if (*s >= '0' && *s <= '9') { + val = *s - '0'; + } else if (*s >= 'a' && *s <= 'f') { + val = 10 + *s - 'a'; + } else if (*s >= 'A' && *s <= 'F') { + val = 10 + *s - 'A'; + } else { + val = radix + 1; + } + if (val >= radix) { + BOOST_THROW_EXCEPTION( + std::runtime_error("Unexpected content found while parsing character string.")); + } + *this->limbs() = detail::checked_multiply(*this->limbs(), + static_cast(radix), checked_type()); + *this->limbs() = detail::checked_add(*this->limbs(), + static_cast(val), checked_type()); + ++s; + } + } + if (isneg) { + this->negate(); + } + } + + void do_assign_string(const char *s, const mpl::false_ &) { + using default_ops::eval_multiply; + using default_ops::eval_add; + std::size_t n = s ? std::strlen(s) : 0; + *this = static_cast(0u); + unsigned radix = 10; + bool isneg = false; + if (n && (*s == '-')) { + --n; + ++s; + isneg = true; + } + if (n && (*s == '0')) { + if ((n > 1) && ((s[1] == 'x') || (s[1] == 'X'))) { + radix = 16; + s += 2; + n -= 2; + } else { + radix = 8; + n -= 1; + } + } + // + // Exception guarantee: create the result in stack variable "result" + // then do a swap at the end. In the event of a throw, *this will + // be left unchanged. + // + montgomery_int_backend result; + if (n) { + if (radix == 16) { + while (*s == '0') { + ++s; + } + std::size_t bitcount = 4 * std::strlen(s); + limb_type val; + std::size_t limb, shift; + if (bitcount > 4) { + bitcount -= 4; + } else { + bitcount = 0; + } + std::size_t newsize = bitcount / (sizeof(limb_type) * CHAR_BIT) + 1; + result.resize(static_cast(newsize), + static_cast(newsize)); // will throw if this is a checked integer that cannot be resized + std::memset(result.limbs(), 0, result.size() * sizeof(limb_type)); + while (*s) { + if (*s >= '0' && *s <= '9') { + val = *s - '0'; + } else if (*s >= 'a' && *s <= 'f') { + val = 10 + *s - 'a'; + } else if (*s >= 'A' && *s <= 'F') { + val = 10 + *s - 'A'; + } else { + BOOST_THROW_EXCEPTION(std::runtime_error( + "Unexpected content found while parsing character string.")); + } + limb = bitcount / (sizeof(limb_type) * CHAR_BIT); + shift = bitcount % (sizeof(limb_type) * CHAR_BIT); + val <<= shift; + if (result.size() > limb) { + result.limbs()[limb] |= val; + } + ++s; + bitcount -= 4; + } + result.normalize(); + } else if (radix == 8) { + while (*s == '0') { + ++s; + } + std::size_t bitcount = 3 * std::strlen(s); + limb_type val; + std::size_t limb, shift; + if (bitcount > 3) { + bitcount -= 3; + } else { + bitcount = 0; + } + std::size_t newsize = bitcount / (sizeof(limb_type) * CHAR_BIT) + 1; + result.resize(static_cast(newsize), + static_cast(newsize)); // will throw if this is a checked integer that cannot be resized + std::memset(result.limbs(), 0, result.size() * sizeof(limb_type)); + while (*s) { + if (*s >= '0' && *s <= '7') { + val = *s - '0'; + } else { + BOOST_THROW_EXCEPTION(std::runtime_error( + "Unexpected content found while parsing character string.")); + } + limb = bitcount / (sizeof(limb_type) * CHAR_BIT); + shift = bitcount % (sizeof(limb_type) * CHAR_BIT); + if (result.size() > limb) { + result.limbs()[limb] |= (val << shift); + if (shift > sizeof(limb_type) * CHAR_BIT - 3) { + // Deal with the bits in val that overflow into the next limb: + val >>= (sizeof(limb_type) * CHAR_BIT - shift); + if (val) { + // If this is the most-significant-limb, we may need to allocate an extra one for the overflow: + if (limb + 1 == newsize) { + result.resize(static_cast(newsize + 1), + static_cast(newsize + 1)); + } + if (result.size() > limb + 1) { + result.limbs()[limb + 1] |= val; + } + } + } + } + ++s; + bitcount -= 3; + } + result.normalize(); + } else { + // Base 10, we extract blocks of size 10^9 at a time, that way + // the number of multiplications is kept to a minimum: + limb_type block_mult = max_block_10; + while (*s) { + limb_type block = 0; + for (unsigned i = 0; i < digits_per_block_10; ++i) { + limb_type val; + if (*s >= '0' && *s <= '9') { + val = *s - '0'; + } else + BOOST_THROW_EXCEPTION( + std::runtime_error("Unexpected character encountered in input.")); + block *= 10; + block += val; + if (!*++s) { + block_mult = block_multiplier(i); + break; + } + } + eval_multiply(result, block_mult); + eval_add(result, block); + } + } + } + if (isneg) { + result.negate(); + } + result.swap(*this); + } + + public: + montgomery_int_backend &operator=(const char *s) { + do_assign_string(s, trivial_tag()); + return *this; + } + + BOOST_MP_FORCEINLINE void swap(montgomery_int_backend &o) BOOST_NOEXCEPT { + this->do_swap(o); + } + + private: + std::string do_get_trivial_string(std::ios_base::fmtflags f, const mpl::false_ &) const { + typedef typename mpl::if_c::type io_type; + if (this->sign() && (((f & std::ios_base::hex) == std::ios_base::hex) || + ((f & std::ios_base::oct) == std::ios_base::oct))) + BOOST_THROW_EXCEPTION( + std::runtime_error("Base 8 or 16 printing of negative numbers is not supported.")); + std::stringstream ss; + ss.flags(f & ~std::ios_base::showpos); + ss << static_cast(*this->limbs()); + std::string result; + if (this->sign()) { + result += '-'; + } else if (f & std::ios_base::showpos) { + result += '+'; + } + result += ss.str(); + return result; + } + + std::string do_get_trivial_string(std::ios_base::fmtflags f, const mpl::true_ &) const { + // Even though we have only one limb, we can't do IO on it :-( + int base = 10; + if ((f & std::ios_base::oct) == std::ios_base::oct) { + base = 8; + } else if ((f & std::ios_base::hex) == std::ios_base::hex) { + base = 16; + } + std::string result; + + unsigned Bits = sizeof(typename base_type::local_limb_type) * CHAR_BIT; + + if (base == 8 || base == 16) { + if (this->sign()) + BOOST_THROW_EXCEPTION( + std::runtime_error("Base 8 or 16 printing of negative numbers is not supported.")); + limb_type shift = base == 8 ? 3 : 4; + limb_type mask = static_cast((1u << shift) - 1); + typename base_type::local_limb_type v = *this->limbs(); + result.assign(Bits / shift + (Bits % shift ? 1 : 0), '0'); + std::string::difference_type pos = result.size() - 1; + for (unsigned i = 0; i < Bits / shift; ++i) { + char c = '0' + static_cast(v & mask); + if (c > '9') { + c += 'A' - '9' - 1; + } + result[pos--] = c; + v >>= shift; + } + if (Bits % shift) { + mask = static_cast((1u << (Bits % shift)) - 1); + char c = '0' + static_cast(v & mask); + if (c > '9') { + c += 'A' - '9'; + } + result[pos] = c; + } + // + // Get rid of leading zeros: + // + std::string::size_type n = result.find_first_not_of('0'); + if (!result.empty() && (n == std::string::npos)) { + n = result.size() - 1; + } + result.erase(0, n); + if (f & std::ios_base::showbase) { + const char *pp = base == 8 ? "0" : "0x"; + result.insert(static_cast(0), pp); + } + } else { + result.assign(Bits / 3 + 1, '0'); + std::string::difference_type pos = result.size() - 1; + typename base_type::local_limb_type v(*this->limbs()); + bool neg = false; + if (this->sign()) { + neg = true; + } + while (v) { + result[pos] = (v % 10) + '0'; + --pos; + v /= 10; + } + std::string::size_type n = result.find_first_not_of('0'); + result.erase(0, n); + if (result.empty()) { + result = "0"; + } + if (neg) { + result.insert(static_cast(0), 1, '-'); + } else if (f & std::ios_base::showpos) { + result.insert(static_cast(0), 1, '+'); + } + } + return result; + } + + std::string do_get_string(std::ios_base::fmtflags f, const mpl::true_ &) const { +#ifdef BOOST_MP_NO_DOUBLE_LIMB_TYPE_IO + return do_get_trivial_string(f, + mpl::bool_::value>()); +#else + return do_get_trivial_string(f, mpl::bool_()); +#endif + } + + std::string do_get_string(std::ios_base::fmtflags f, const mpl::false_ &) const { + using default_ops::eval_get_sign; + int base = 10; + if ((f & std::ios_base::oct) == std::ios_base::oct) { + base = 8; + } else if ((f & std::ios_base::hex) == std::ios_base::hex) { + base = 16; + } + std::string result; + + unsigned Bits = this->size() * base_type::limb_bits; + + if (base == 8 || base == 16) { + if (this->sign()) + BOOST_THROW_EXCEPTION( + std::runtime_error("Base 8 or 16 printing of negative numbers is not supported.")); + limb_type shift = base == 8 ? 3 : 4; + limb_type mask = static_cast((1u << shift) - 1); + montgomery_int_backend t(*this); + result.assign(Bits / shift + ((Bits % shift) ? 1 : 0), '0'); + std::string::difference_type pos = result.size() - 1; + for (unsigned i = 0; i < Bits / shift; ++i) { + char c = '0' + static_cast(t.limbs()[0] & mask); + if (c > '9') { + c += 'A' - '9' - 1; + } + result[pos--] = c; + eval_right_shift(t, shift); + } + if (Bits % shift) { + mask = static_cast((1u << (Bits % shift)) - 1); + char c = '0' + static_cast(t.limbs()[0] & mask); + if (c > '9') { + c += 'A' - '9'; + } + result[pos] = c; + } + // + // Get rid of leading zeros: + // + std::string::size_type n = result.find_first_not_of('0'); + if (!result.empty() && (n == std::string::npos)) { + n = result.size() - 1; + } + result.erase(0, n); + if (f & std::ios_base::showbase) { + const char *pp = base == 8 ? "0" : "0x"; + result.insert(static_cast(0), pp); + } + } else { + result.assign(Bits / 3 + 1, '0'); + std::string::difference_type pos = result.size() - 1; + montgomery_int_backend t(*this); + redc(t); + montgomery_int_backend r; + bool neg = false; + if (t.sign()) { + t.negate(); + neg = true; + } + if (this->size() == 1) { + result = boost::lexical_cast(t.limbs()[0]); + } else { + montgomery_int_backend block10; + block10 = max_block_10; + while (eval_get_sign(t) != 0) { + montgomery_int_backend t2; + divide_unsigned_helper(&t2, t, block10, r); + t = t2; + limb_type v = r.limbs()[0]; + for (unsigned i = 0; i < digits_per_block_10; ++i) { + char c = '0' + v % 10; + v /= 10; + result[pos] = c; + if (pos-- == 0) { + break; + } + } + } + } + std::string::size_type n = result.find_first_not_of('0'); + result.erase(0, n); + if (result.empty()) { + result = "0"; + } + if (neg) { + result.insert(static_cast(0), 1, '-'); + } else if (f & std::ios_base::showpos) { + result.insert(static_cast(0), 1, '+'); + } + } + return result; + } + + public: + std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags f) const { + return do_get_string(f, trivial_tag()); + } + + private: + template + void construct_from_container(const Container &c, const mpl::false_ &) { + // + // We assume that c is a sequence of (unsigned) bytes with the most significant byte first: + // + unsigned newsize = static_cast(c.size() / sizeof(limb_type)); + if (c.size() % sizeof(limb_type)) { + ++newsize; + } + if (newsize) { + this->resize(newsize, newsize); // May throw + std:x:memset(this->limbs(), 0, this->size()); + typename Container::const_iterator i(c.begin()), j(c.end()); + unsigned byte_location = static_cast(c.size() - 1); + while (i != j) { + unsigned limb = byte_location / sizeof(limb_type); + unsigned shift = (byte_location % sizeof(limb_type)) * CHAR_BIT; + if (this->size() > limb) { + this->limbs()[limb] |= static_cast(static_cast(*i)) << shift; + } + ++i; + --byte_location; + } + } + } + + template + void construct_from_container(const Container &c, const mpl::true_ &) { + // + // We assume that c is a sequence of (unsigned) bytes with the most significant byte first: + // + typedef typename base_type::local_limb_type local_limb_type; + *this->limbs() = 0; + if (c.size()) { + typename Container::const_iterator i(c.begin()), j(c.end()); + unsigned byte_location = static_cast(c.size() - 1); + while (i != j) { + unsigned limb = byte_location / sizeof(local_limb_type); + unsigned shift = (byte_location % sizeof(local_limb_type)) * CHAR_BIT; + if (limb == 0) { + this->limbs()[0] |= static_cast(static_cast(*i)) << shift; + } + ++i; + --byte_location; + } + } + } + + public: + template + montgomery_int_backend(const Container &c, typename boost::enable_if_c< + boost::multiprecision::detail::is_byte_container::value>::type const * = 0) { + // + // We assume that c is a sequence of (unsigned) bytes with the most significant byte first: + // + construct_from_container(c, trivial_tag()); + } + + template class Backend, + unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c>::value, int> + ::type compare_imp(const Backend &o, + const mpl::false_ &, const mpl::false_ &) const BOOST_NOEXCEPT { + if (this->sign() != o.sign()) { + return this->sign() ? -1 : 1; + } + + // Only do the compare if the same sign: + int result = compare_unsigned(o); + + if (this->sign()) { + result = -result; + } + return result; + } + + template class Backend, + unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c>::value, int> + + //template + ::type compare_imp(const Backend &o, + const mpl::true_ &, const mpl::false_ &) const { + Backend t(*this); + return t.compare(o); + } + + template class Backend, + unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c>::value, int> + ::type compare_imp(const Backend &o, + const mpl::false_ &, const mpl::true_ &) const { + Backend t(o); + return compare(t); + } + + template class Backend, + unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c>::value, int> + ::type compare_imp(const Backend &o, + const mpl::true_ &, const mpl::true_ &) const BOOST_NOEXCEPT { + if (this->sign()) { + if (o.sign()) { + return *this->limbs() < *o.limbs() ? 1 : (*this->limbs() > *o.limbs() ? -1 : 0); + } else { + return -1; + } + } else { + if (o.sign()) { + return 1; + } + return *this->limbs() < *o.limbs() ? -1 : (*this->limbs() > *o.limbs() ? 1 : 0); + } + } + + template class Backend, + unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c>::value, int> + ::type compare(const Backend &o) const BOOST_NOEXCEPT { + typedef mpl::bool_ >::value> t1; + typedef mpl::bool_ >::value> t2; + return compare_imp(o, t1(), t2()); + } + + template class Backend, + unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c>::value, int> + ::type compare_unsigned(const Backend &o) const BOOST_NOEXCEPT { + if (this->size() != o.size()) { + return this->size() > o.size() ? 1 : -1; + } + typename base_type::const_limb_pointer pa = this->limbs(); + typename base_type::const_limb_pointer pb = o.limbs(); + for (int i = this->size() - 1; i >= 0; --i) { + if (pa[i] != pb[i]) { + return pa[i] > pb[i] ? 1 : -1; + } + } + return 0; + } + + template class Backend, + unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> + BOOST_MP_FORCEINLINE typename enable_if_c>::value, int> + ::type compare_unsigned(const Backend &o) const BOOST_NOEXCEPT { + if (this->size() != o.size()) { + return this->size() > o.size() ? 1 : -1; + } + typename base_type::const_limb_pointer pa = this->limbs(); + typename base_type::const_limb_pointer pb = o.limbs(); + for (int i = this->size() - 1; i >= 0; --i) { + if (pa[i] != pb[i]) { + return pa[i] > pb[i] ? 1 : -1; + } + } + return 0; + } + + template + BOOST_MP_FORCEINLINE typename boost::enable_if, int>::type compare( + Arithmetic i) const { + // braindead version: + montgomery_int_backend t; + t = i; + return compare(t); + } + }; + + } // namespace backends + + namespace default_ops { + + template + struct double_precision_type; + + template + struct double_precision_type< + backends::montgomery_int_backend > { + typedef typename mpl::if_c >::value, + backends::montgomery_int_backend<(is_void::value ? 2 * backends::max_precision< + backends::montgomery_int_backend >::value : MinBits), 2 * backends::max_precision< + backends::montgomery_int_backend >::value, SignType, Checked,Allocator, ParamsBackend>, + backends::montgomery_int_backend >::type type; + }; + + + } + + template + struct expression_template_default< + backends::montgomery_int_backend > { + static const expression_template_option value = et_off; + }; + + using boost::multiprecision::backends::montgomery_int_backend; + + template + struct number_category > + : public mpl::int_ { + }; + + typedef number > montgomery_int; + typedef rational_adaptor > montgomery_rational_backend; + typedef number montgomery_rational; + +// Fixed precision unsigned types: + typedef number > umontgomery128_t; + typedef number > umontgomery256_t; + typedef number > umontgomery512_t; + typedef number > umontgomery1024_t; + +// Fixed precision signed types: + typedef number > montgomery128_t; + typedef number > montgomery256_t; + typedef number > montgomery512_t; + typedef number > montgomery1024_t; + +// Over again, but with checking enabled this time: + typedef number > checked_montgomery_int; + typedef rational_adaptor > checked_montgomery_rational_backend; + typedef number checked_cpp_rational; +// Fixed precision unsigned types: + typedef number > checked_umontgomery128_t; + typedef number > checked_umontgomery256_t; + typedef number > checked_umontgomery512_t; + typedef number > checked_umontgomery1024_t; + +// Fixed precision signed types: + typedef number > checked_montgomery128_t; + typedef number > checked_montgomery256_t; + typedef number > checked_montgomery512_t; + typedef number > checked_montgomery1024_t; + + +#ifdef BOOST_NO_SFINAE_EXPR + + namespace detail{ + + template + struct is_explicitly_convertible, montgomery_int_backend > : public mpl::true_ {}; + + } +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + } +} // namespaces + + +template +struct component_type, ExpressionTemplates> > +{ + typedef cpp_int type; +}; + +// +// Last of all we include the implementations of all the eval_* non member functions: +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_MP_USER_DEFINED_LITERALS + +//#include + +#endif + +#include +#include +#endif \ No newline at end of file diff --git a/include/boost/multiprecision/montgomery_int/montgomery_params.hpp b/include/boost/multiprecision/montgomery_int/montgomery_params.hpp new file mode 100644 index 000000000..485b75da2 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/montgomery_params.hpp @@ -0,0 +1,159 @@ +#ifndef CRYPTO3_MONTY_INT_H_ +#define CRYPTO3_MONTY_INT_H_ + +#include +#include + +using namespace boost::multiprecision; + +namespace nil { + namespace crypto3 { + + class modular_reducer; + + /** + * Parameters for Montgomery Reduction + */ + template + class montgomery_params { + public: + typedef NumberType number_type; + + /** + * Initialize a set of Montgomery reduction parameters. These values + * can be shared by all values in a specific Montgomery domain. + */ + + //work_only_with_cpp_int + template + explicit montgomery_params(const number &p, + const number &redc_module) { + + if (p < 0 || !(p % 2)) { + throw std::invalid_argument("montgomery_params invalid modulus"); + } + + m_p = p; + + m_mod = redc_module; + + m_p_words = m_p.backend().size(); + + m_p_dash = monty_inverse(m_p.backend().limbs()[0]); + + number_type r; + + boost::multiprecision::backends::eval_bit_set(r.backend(), m_p_words * CRYPTO3_MP_WORD_BITS); + + m_r1 = r; + mod_redc(m_r1.backend(), redc_module.backend()); + m_r2 = m_r1; + eval_multiply(m_r2.backend(), m_r1.backend()); + mod_redc(m_r2.backend(), redc_module.backend()); + m_r3 = m_r2; + eval_multiply(m_r3.backend(), m_r1.backend()); + mod_redc(m_r3.backend(), redc_module.backend()); + } + + BOOST_MP_FORCEINLINE BOOST_CONSTEXPR montgomery_params() BOOST_NOEXCEPT { + + } + + template + explicit montgomery_params() { + + } + + /** + * Initialize a set of Montgomery reduction parameters. These values + * can be shared by all values in a specific Montgomery domain. + */ + template + explicit montgomery_params(const number &p) { + + if (p < 0 || !(p % 2)) { + throw std::invalid_argument("montgomery_params invalid modulus"); + } + + m_p = p; + + m_mod = p; + + m_p_words = m_p.backend().size(); + + m_p_dash = monty_inverse(m_p.backend().limbs()[0]); + + number_type r; + + boost::multiprecision::backends::eval_bit_set(r.backend(), m_p_words * CRYPTO3_MP_WORD_BITS); + + m_r1 = r; + mod_redc(m_r1.backend(), p.backend()); + m_r2 = m_r1; + eval_multiply(m_r2.backend(), m_r1.backend()); + mod_redc(m_r2.backend(), p.backend()); + m_r3 = m_r2; + eval_multiply(m_r3.backend(), m_r1.backend()); + mod_redc(m_r3.backend(), p.backend()); + } + + const number_type &mod() const { + return m_mod; + } + + const number_type &p() const { + return m_p; + } + + const number_type &R1() const { + return m_r1; + } + + const number_type &R2() const { + return m_r2; + } + + const number_type &R3() const { + return m_r3; + } + + + limb_type p_dash() const { + return m_p_dash; + } + + size_t p_words() const { + return m_p_words; + } + + + /* + operator number_type() { + return m_p; + }; + */ + + template + operator number() { + number x = 0; + return x; + }; + + private: + NumberType m_p; + NumberType m_r1; + NumberType m_r2; + NumberType m_r3; + limb_type m_p_dash; + size_t m_p_words; + NumberType m_mod; + }; + +/** +* The Montgomery representation of an integer +*/ + + } +} + +#endif diff --git a/include/boost/multiprecision/montgomery_int/multiply.hpp b/include/boost/multiprecision/montgomery_int/multiply.hpp new file mode 100644 index 000000000..cd8c70c72 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/multiply.hpp @@ -0,0 +1,999 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_MUL_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_MUL_HPP + +namespace boost { + namespace multiprecision { + namespace backends { + +#ifdef _MSC_VER + #pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int::value > + ::type eval_multiply_helper( + montgomery_int_backend& result, + const Backend& a, + const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + if (!val) { + result = static_cast(0); + redc(result); + return; + } + if ((void *) &a != (void *) &result) { + result.resize(a.size(), a.size()); + } + double_limb_type carry = 0; + typename montgomery_int_backend::limb_pointer p = result.limbs(); + typename montgomery_int_backend::limb_pointer pe = + result.limbs() + result.size(); + typename Backend::const_limb_pointer pa = a.limbs(); + while (p != pe) { + carry += static_cast + (*pa) * static_cast + (val); +#ifdef __MSVC_RUNTIME_CHECKS + *p = static_cast(carry & ~static_cast(0)); +#else + *p = static_cast(carry); +#endif + carry >>= montgomery_int_backend::limb_bits; + ++p, ++pa; + } + if (carry) { + unsigned i = result.size(); + result.resize(i + 1, i + 1); + if (result.size() > i) { + result.limbs()[i] = static_cast(carry); + } + } + result.sign(a.sign()); + if (!montgomery_int_backend::variable) { + result.normalize(); + } + redc(result); + } + +// +// resize_for_carry forces a resize of the underlying buffer only if a previous request +// for "required" elements could possibly have failed, *and* we have checking enabled. +// This will cause an overflow error inside resize(): +// + template + inline void resize_for_carry( + montgomery_int_backend & /*result*/, + unsigned /*required*/) { + } + + template + inline void resize_for_carry( + montgomery_int_backend &result, + unsigned required) { + if (result.size() < required) { + result.resize(required, required); + } + } + + //SPLIT FOR 2 + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_montgomery_int::value && + !is_trivial_montgomery_int::value >::type + eval_multiply_helper( + montgomery_int_backend& result, + const Backend1& a, + const Backend2& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { +// Very simple long multiplication, only usable for small numbers of limb_type's +// but that's the typical use case for this type anyway: +// +// Special cases first: +// + unsigned as = a.size(); + unsigned bs = b.size(); + typename Backend1::const_limb_pointer pa = a.limbs(); + typename Backend2::const_limb_pointer pb = b.limbs(); + if (as == 1) { + bool s = b.sign() != a.sign(); + if (bs == 1) { + result = static_cast(*pa) * static_cast(*pb); + redc(result); + } else { + limb_type l = *pa; + eval_multiply_helper(result, b, l); + } + result.sign(s); + return; + } + if (bs == 1) { + bool s = b.sign() != a.sign(); + limb_type l = *pb; + eval_multiply_helper(result, a, l); + result.sign(s); + return; + } + + if ((void *) &result == (void *) &a) { + montgomery_int_backend t(a); + eval_multiply_helper(result, t, b); + return; + } + if ((void *) &result == (void *) &b) { + //montgomery_int_backend t(b); //TODO: fix it!!! Very bad if b - cpp_int + //eval_multiply_helper(result, a, t); + return; + } + + result.resize(as + bs, as + bs - 1); + typename montgomery_int_backend::limb_pointer pr = result.limbs(); + + static const double_limb_type limb_max = ~static_cast(0u); + static const double_limb_type double_limb_max = ~static_cast(0u); + BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max); + + double_limb_type carry = 0; + std::memset(pr, 0, result.size() * sizeof(limb_type)); + for (unsigned i = 0; i < as; ++i) { + unsigned inner_limit = montgomery_int_backend::variable ? bs : (std::min)(result.size() - i, bs); + unsigned j; + for (j = 0; j < inner_limit; ++j) { + BOOST_ASSERT(i + j < result.size()); +#if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100) + BOOST_ASSERT(!std::numeric_limits::is_specialized || + ((std::numeric_limits::max)() - carry > static_cast + (montgomery_int_backend::max_limb_value) * static_cast + (montgomery_int_backend::max_limb_value))); +#endif + carry += static_cast + (pa[i]) * static_cast + (pb[j]); + BOOST_ASSERT(!std::numeric_limits::is_specialized || + ((std::numeric_limits::max)() - carry >= pr[i + j])); + carry += pr[i + j]; +#ifdef __MSVC_RUNTIME_CHECKS + pr[i + j] = static_cast(carry & ~static_cast(0)); +#else + pr[i + j] = static_cast + (carry); +#endif + carry >>= montgomery_int_backend::limb_bits; + BOOST_ASSERT(carry <= (montgomery_int_backend::max_limb_value)); + } + if (carry) { + resize_for_carry(result, i + j + 1); // May throw if checking is enabled + if (i + j < result.size()) +#ifdef __MSVC_RUNTIME_CHECKS + pr[i + j] = static_cast(carry & ~static_cast(0)); +#else + { + pr[i + j] = static_cast(carry); + } +#endif + } + carry = 0; + } + result.normalize(); + +// +// Set the sign of the result: +// + result.sign(a.sign() != b.sign()); + redc(result); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int::value >::type + eval_multiply_helper( + montgomery_int_backend& result, + const Backend& a) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + eval_multiply_helper(result, result, a); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c>::value>::type + eval_multiply(montgomery_int_backend& result, const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + { + eval_multiply_helper(result, result, val); + } + + template + + BOOST_MP_FORCEINLINE typename enable_if_c>::value && + !is_trivial_montgomery_int::value >::type + eval_multiply_helper( + montgomery_int_backend& result, + const Backend& a, + const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + if (val <= (std::numeric_limits::max)()) { + eval_multiply_helper(result, a, static_cast + (val)); + } else { +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) + montgomery_int_backend t(val); +#else + montgomery_int_backend t; + t = val; +#endif + eval_multiply_helper(result, a, t); + } + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_multiply(montgomery_int_backend &result, + const double_limb_type &val) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + eval_multiply_helper(result, result, val); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int::value >::type + eval_multiply_helper( + montgomery_int_backend& result, + const Backend& a, + const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + { + if (val > 0) { + eval_multiply_helper(result, a, static_cast(val)); + } else { + eval_multiply_helper(result, a, static_cast(boost::multiprecision::detail::unsigned_abs(val))); + result.negate(); + } + } + + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_multiply(montgomery_int_backend &result, + const signed_limb_type &val) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + eval_multiply_helper(result, result, val); + } + + template + inline typename enable_if_c >::value && !is_trivial_montgomery_int::value >::type + eval_multiply_helper( + montgomery_int_backend& result, + const Backend& a, + const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + { + if (val > 0) { + if (val <= (std::numeric_limits::max)()) { + eval_multiply_helper(result, a, static_cast(val)); + return; + } + } else if (val >= -static_cast((std::numeric_limits::max)())) { + eval_multiply_helper(result, a, static_cast(boost::multiprecision::detail::unsigned_abs(val))); + result.negate(); + + return; + } +#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE) + montgomery_int_backend t(val); +#else + montgomery_int_backend t; + t = val; +#endif + eval_multiply_helper(result, a, t); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_multiply(montgomery_int_backend &result, + const signed_double_limb_type &val) + + BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int< + montgomery_int_backend >::value)) { + eval_multiply_helper(result, result, val); + } + +// +// Now over again for trivial cpp_int's: +// + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_trivial_montgomery_int::value + && (is_signed_number>::value + || is_signed_number::value) + >::type + eval_multiply_helper( + montgomery_int_backend& result, + const Backend& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), + typename montgomery_int_backend::checked_type()); + + result.sign(result.sign() != o.sign()); + result.normalize(); + redc(result); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int >::value + && is_unsigned_number >::value + && is_trivial_montgomery_int::value + && is_unsigned_number::value + >::type + eval_multiply_helper( + montgomery_int_backend& result, + const Backend& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), + typename montgomery_int_backend::checked_type()); + + result.normalize(); + redc(result); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_trivial_montgomery_int::value + && (is_signed_number >::value + || is_signed_number::value) + >::type + eval_multiply_helper( + montgomery_int_backend& result, + const Backend& a, + const Backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), + typename montgomery_int_backend::checked_type()); + + result.sign(a.sign() != b.sign()); + result.normalize(); + redc(result); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_unsigned_number>::value + && is_trivial_montgomery_int::value + && is_unsigned_number::value + >::type + eval_multiply_helper( + montgomery_int_backend& result, + const Backend& a, + const Backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + { + *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), + typename montgomery_int_backend::checked_type()); + + result.normalize(); + redc(result); + } + +// +// Special routines for multiplying two integers to obtain a multiprecision result: +// + template + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value + >::type + eval_multiply( + montgomery_int_backend& result, + signed_double_limb_type a, signed_double_limb_type b) + { + static const signed_double_limb_type mask = ~static_cast(0); + static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; + bool s = false; + double_limb_type w, x, y, z; + if (a < 0) { + a = -a; + s = true; + } + if (b < 0) { + b = -b; + s = !s; + } + w = a & mask; + x = a >> limb_bits; + y = b & mask; + z = b >> limb_bits; + + result.resize(4, 4); + limb_type *pr = result.limbs(); + + double_limb_type carry = w * y; +#ifdef __MSVC_RUNTIME_CHECKS + pr[0] = static_cast(carry & ~static_cast(0)); + carry >>= limb_bits; + carry += w * z + x * y; + pr[1] = static_cast(carry & ~static_cast(0)); + carry >>= limb_bits; + carry += x * z; + pr[2] = static_cast(carry & ~static_cast(0)); + pr[3] = static_cast(carry >> limb_bits); +#else + pr[0] = static_cast(carry); + carry >>= limb_bits; + carry += w * z + x * y; + pr[1] = static_cast(carry); + carry >>= limb_bits; + carry += x * z; + pr[2] = static_cast(carry); + pr[3] = static_cast(carry >> limb_bits); +#endif + result.sign(s); + result.normalize(); + redc(result); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c >::value> + + ::type eval_multiply(montgomery_int_backend &result, + double_limb_type a, double_limb_type b) { + static const signed_double_limb_type mask = ~static_cast(0); + static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; + + double_limb_type w, x, y, z; + w = a & mask; + x = a >> limb_bits; + y = b & mask; + z = b >> limb_bits; + + result.resize(4, 4); + limb_type *pr = result.limbs(); + + double_limb_type carry = w * y; +#ifdef __MSVC_RUNTIME_CHECKS + pr[0] = static_cast(carry & ~static_cast(0)); + carry >>= limb_bits; + carry += w * z; + pr[1] = static_cast(carry & ~static_cast(0)); + carry >>= limb_bits; + pr[2] = static_cast(carry & ~static_cast(0)); + carry = x * y + pr[1]; + pr[1] = static_cast(carry & ~static_cast(0)); + carry >>= limb_bits; + carry += pr[2] + x * z; + pr[2] = static_cast(carry & ~static_cast(0)); + pr[3] = static_cast(carry >> limb_bits); +#else + pr[0] = static_cast(carry); + carry >>= limb_bits; + carry += w * z; + pr[1] = static_cast(carry); + carry >>= limb_bits; + pr[2] = static_cast(carry); + carry = x * y + pr[1]; + pr[1] = static_cast(carry); + carry >>= limb_bits; + carry += pr[2] + x * z; + pr[2] = static_cast(carry); + pr[3] = static_cast(carry >> limb_bits); +#endif + result.sign(false); + result.normalize(); + redc(result); + } + + template + + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value + && is_trivial_montgomery_int::value + && is_trivial_montgomery_int::value> + ::type eval_multiply_helper(montgomery_int_backend& result, + Backend const& a, + Backend const& b) + { + typedef typename boost::multiprecision::detail::canonical< + typename Backend::local_limb_type, + montgomery_int_backend >::type canonical_type; + eval_multiply_helper(result, static_cast(*a.limbs()), static_cast(*b.limbs())); + result.sign(a.sign() != b.sign()); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_signed::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)> + ::type eval_multiply(montgomery_int_backend &result, SI a, SI b) + { + result = static_cast(a) * static_cast(b); + redc(result); + } + + template + BOOST_MP_FORCEINLINE typename enable_if_c< + is_unsigned::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)> + ::type eval_multiply(montgomery_int_backend &result, UI a, UI b) + { + result = static_cast(a) * static_cast(b); + redc(result); + } + + //====================================================// + //====================================================// + //====================================================// + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + is_equal_montgomery_int_field>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, a, val); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + is_equal_montgomery_int_backend >::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, a, val); + } + + +// +// resize_for_carry forces a resize of the underlying buffer only if a previous request +// for "required" elements could possibly have failed, *and* we have checking enabled. +// This will cause an overflow error inside resize(): +// + + template class Backend1, + template< unsigned, unsigned, cpp_integer_type, cpp_int_check_type, typename, typename> class Backend2, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, + class Allocator3, typename ParamsBackend3> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int>::value && + is_equal_montgomery_int_field>::value && + is_equal_montgomery_int_field>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend1& a, + const Backend2& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + eval_multiply_helper(result, a, b); + } + + template class Backend1, + template< unsigned, unsigned, cpp_integer_type, cpp_int_check_type, typename> class Backend2, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, + class Allocator3> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int>::value && + is_equal_montgomery_int_field>::value&& + is_equal_montgomery_int_backend>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend1& a, + const Backend2& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + eval_multiply_helper(result, a, b); + } + + template class Backend1, + template< unsigned, unsigned, cpp_integer_type, cpp_int_check_type, typename, typename> class Backend2, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, + class Allocator3, typename ParamsBackend3> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int>::value && + is_equal_montgomery_int_field>::value && + is_equal_montgomery_int_backend>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend1& a, + const Backend2& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + eval_multiply_helper(result, a, b); + } + + template class Backend1, + template< unsigned, unsigned, cpp_integer_type, cpp_int_check_type, typename> class Backend2, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, + class Allocator3> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + !is_trivial_montgomery_int>::value && + is_equal_montgomery_int_backend>::value && + is_equal_montgomery_int_backend>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend1& a, + const Backend2& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + eval_multiply_helper(result, a, b); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int>::value && + is_equal_montgomery_int_field>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + eval_multiply(result, result, a); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int>::value && + is_equal_montgomery_int_backend>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + eval_multiply(result, result, a); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + + BOOST_MP_FORCEINLINE typename enable_if_c>::value && + !is_trivial_montgomery_int>::value && + is_equal_montgomery_int_field>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, a, val); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2> + + BOOST_MP_FORCEINLINE typename enable_if_c>::value && + !is_trivial_montgomery_int>::value && + is_equal_montgomery_int_backend>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, a, val); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + is_equal_montgomery_int_field>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + { + eval_multiply_helper(result, a, val); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2> + BOOST_MP_FORCEINLINE typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + is_equal_montgomery_int_backend>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + { + eval_multiply_helper(result, a, val); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + inline typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + is_equal_montgomery_int_field>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + { + eval_multiply_helper(result, a, val); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2> + inline typename enable_if_c >::value && + !is_trivial_montgomery_int >::value && + is_equal_montgomery_int_backend>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + { + eval_multiply_helper(result, a, val); + } + +// +// Now over again for trivial cpp_int's: +// + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_trivial_montgomery_int>::value + && (is_signed_number>::value + || is_signed_number>::value) && + is_equal_montgomery_int_field>::value + >::type + eval_multiply( + montgomery_int_backend& result, + const Backend& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + eval_multiply_helper(result, o); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_trivial_montgomery_int>::value + && (is_signed_number>::value + || is_signed_number>::value) && + is_equal_montgomery_int_backend>::value> + ::type eval_multiply( + montgomery_int_backend& result, + const Backend& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + + { + eval_multiply_helper(result, o); + } + + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int >::value + && is_unsigned_number >::value + && is_trivial_montgomery_int >::value + && is_unsigned_number >::value + && is_equal_montgomery_int_field>::value + >::type + eval_multiply( + montgomery_int_backend& result, + const Backend& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, o); + } + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int >::value + && is_unsigned_number >::value + && is_trivial_montgomery_int >::value + && is_unsigned_number >::value + && is_equal_montgomery_int_backend>::value + >::type + eval_multiply( + montgomery_int_backend& result, + const Backend& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, o); + } + + /*! + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_trivial_montgomery_int >::value + && (is_signed_number >::value + || is_signed_number>::value) + >::type + eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const Backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, a, b); + } + + emplate class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_trivial_montgomery_int >::value + && (is_signed_number >::value + || is_signed_number>::value) + >::type + eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const Backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, a, b); + } + + emplate class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_trivial_montgomery_int >::value + && (is_signed_number >::value + || is_signed_number>::value) + >::type + eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const Backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, a, b); + } + + emplate class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_trivial_montgomery_int >::value + && (is_signed_number >::value + || is_signed_number>::value) + >::type + eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const Backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int >::value)) + { + eval_multiply_helper(result, a, b); + } + ----------- + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1> + BOOST_MP_FORCEINLINE typename enable_if_c< + is_trivial_montgomery_int>::value + && is_unsigned_number>::value + && is_trivial_montgomery_int>::value + && is_unsigned_number>::value + >::type + eval_multiply( + montgomery_int_backend& result, + const Backend& a, + const Backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_montgomery_int>::value)) + { + eval_multiply_helper(result, a, b); + } + + + template class Backend, + unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, + class Allocator1, typename ParamsBackend1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, + class Allocator2, typename ParamsBackend2> + + BOOST_MP_FORCEINLINE typename enable_if_c< + !is_trivial_montgomery_int >::value + && is_trivial_montgomery_int >::value + && is_trivial_montgomery_int>::value + >::type + eval_multiply( + montgomery_int_backend& result, + Backend const& a, + Backend const& b) + { + eval_multiply_helper(result, a, b); + } + + */ +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + } + } +} // namespaces + +#endif \ No newline at end of file diff --git a/include/boost/multiprecision/montgomery_int/reduce.hpp b/include/boost/multiprecision/montgomery_int/reduce.hpp new file mode 100644 index 000000000..58bef4cdd --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/reduce.hpp @@ -0,0 +1,113 @@ +#include + +#include +#include +#include +#include +#include + +//#include +//#include + +#ifndef CRYPTO3_MP_MONTGOMERY_INT_REDC_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_REDC_HPP + +namespace boost { + namespace multiprecision { + namespace backends { + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif + template + inline void redc(MontgomeryBackend &result) BOOST_MP_NOEXCEPT_IF ( + is_non_throwing_montgomery_int::value) { + + using default_ops::eval_multiply_add; + using default_ops::eval_lt; + + typedef cpp_int_backend cpp_three_int_backend; + typename MontgomeryBackend::allocator_type alloc; + + const size_t p_size = result.m_params.p_words(); + const limb_type p_dash = result.m_params.p_dash(); + const size_t z_size = 2 * (result.m_params.p_words() + 1); + + + container::vector z(result.size(), 0); + + eval_export_bits(result, z.rbegin(), MontgomeryBackend::limb_bits); + + z.resize(z_size, 0); + + if (result.size() < z_size) { + result.resize(z_size, z_size); + } + + cpp_three_int_backend w(z[0]); + + result.limbs()[0] = w.limbs()[0] * p_dash; + + eval_multiply_add(w, result.limbs()[0], result.m_params.p().backend().limbs()[0]); + eval_right_shift(w, MontgomeryBackend::limb_bits); + + for (size_t i = 1; i != p_size; ++i) { + for (size_t j = 0; j < i; ++j) { + eval_multiply_add(w, result.limbs()[j], result.m_params.p().backend().limbs()[i - j]); + } + + eval_add(w, z[i]); + + result.limbs()[i] = w.limbs()[0] * p_dash; + + eval_multiply_add(w, result.limbs()[i], result.m_params.p().backend().limbs()[0]); + + eval_right_shift(w, MontgomeryBackend::limb_bits); + } + + for (size_t i = 0; i != p_size; ++i) { + for (size_t j = i + 1; j != p_size; ++j) { + eval_multiply_add(w, result.limbs()[j], result.m_params.p().backend().limbs()[p_size + i - j]); + } + + eval_add(w, z[p_size + i]); + + result.limbs()[i] = w.limbs()[0]; + + eval_right_shift(w, MontgomeryBackend::limb_bits); + } + + eval_add(w, z[z_size - 1]); + + result.limbs()[p_size] = w.limbs()[0]; + result.limbs()[p_size + 1] = w.limbs()[1]; + + + if (result.size() != p_size + 1) { + result.resize(p_size + 1, p_size + 1); + } + result.normalize(); + + //if (!eval_lt(result, result.m_params.p().backend())) { + //eval_subtract(result, result.m_params.p().backend()); + //} + + + //nil::crypto3::ct::conditional_copy_mem(borrow, result.limbs(), ws.begin(), ws.begin() + (result.m_params.p_words() + 1), (result.m_params.p_words() + 1)); + //clear_mem(result.m_params.limbs() + result.m_params.p_words(), z_size - result.m_params.p_words() - 2); + + // This check comes after we've used it but that's ok here + //nil::crypto3::ct::unpoison(&borrow, 1); + + } + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + } + } +} // namespaces + +#endif \ No newline at end of file diff --git a/include/boost/multiprecision/montgomery_int/serialize.hpp b/include/boost/multiprecision/montgomery_int/serialize.hpp new file mode 100644 index 000000000..442ee9bc0 --- /dev/null +++ b/include/boost/multiprecision/montgomery_int/serialize.hpp @@ -0,0 +1,201 @@ +#ifndef CRYPTO3_MP_MONTGOMERY_INT_SERIALIZE_HPP +#define CRYPTO3_MP_MONTGOMERY_INT_SERIALIZE_HPP + +namespace boost { + + namespace archive { + + class binary_oarchive; + + class binary_iarchive; + + } + + namespace serialization { + + namespace mp = boost::multiprecision; + + namespace montgomery_int_detail { + + using namespace boost::multiprecision; + using namespace boost::multiprecision::backends; + + template + struct is_binary_archive : public mpl::false_ { + }; + template<> + struct is_binary_archive : public mpl::true_ { + }; + template<> + struct is_binary_archive : public mpl::true_ { + }; + +// +// We have 8 serialization methods to fill out (and test), they are all permutations of: +// Load vs Store. +// Trivial or non-trivial cpp_int type. +// Binary or not archive. +// + template + void do_serialize(Archive &ar, Int &val, mpl::false_ const &, mpl::false_ const &, mpl::false_ const &) { + // Load. + // Non-trivial. + // Non binary. + + bool s; + ar & s; + std::size_t limb_count; + std::size_t byte_count; + ar & byte_count; + limb_count = byte_count / sizeof(limb_type) + ((byte_count % sizeof(limb_type)) ? 1 : 0); + val.resize(limb_count, limb_count); + limb_type *pl = val.limbs(); + for (std::size_t i = 0; i < limb_count; ++i) { + pl[i] = 0; + for (std::size_t j = 0; (j < sizeof(limb_type)) && byte_count; ++j) { + unsigned char byte; + ar & byte; + pl[i] |= static_cast(byte) << (j * CHAR_BIT); + --byte_count; + } + } + if (s != val.sign()) { + val.negate(); + } + val.normalize(); + } + + template + void do_serialize(Archive &ar, Int &val, mpl::true_ const &, mpl::false_ const &, mpl::false_ const &) { + // Store. + // Non-trivial. + // Non binary. + + bool s = val.sign(); + ar & s; + limb_type *pl = val.limbs(); + std::size_t limb_count = val.size(); + std::size_t byte_count = limb_count * sizeof(limb_type); + ar & byte_count; + + for (std::size_t i = 0; i < limb_count; ++i) { + limb_type l = pl[i]; + for (std::size_t j = 0; j < sizeof(limb_type); ++j) { + unsigned char byte = static_cast((l >> (j * CHAR_BIT)) & ((1u << CHAR_BIT) - 1)); + ar & byte; + } + } + } + + template + void do_serialize(Archive &ar, Int &val, mpl::false_ const &, mpl::true_ const &, mpl::false_ const &) { + // Load. + // Trivial. + // Non binary. + bool s; + typename Int::local_limb_type l = 0; + ar & s; + std::size_t byte_count; + ar & byte_count; + for (std::size_t i = 0; i < byte_count; ++i) { + unsigned char b; + ar & b; + l |= static_cast(b) << (i * CHAR_BIT); + } + *val.limbs() = l; + if (s != val.sign()) { + val.negate(); + } + } + + template + void do_serialize(Archive &ar, Int &val, mpl::true_ const &, mpl::true_ const &, mpl::false_ const &) { + // Store. + // Trivial. + // Non binary. + bool s = val.sign(); + typename Int::local_limb_type l = *val.limbs(); + ar & s; + std::size_t limb_count = sizeof(l); + ar & limb_count; + for (std::size_t i = 0; i < limb_count; ++i) { + unsigned char b = static_cast( + static_cast(l >> (i * CHAR_BIT)) & + static_cast((1u << CHAR_BIT) - 1)); + ar & b; + } + } + + template + void do_serialize(Archive &ar, Int &val, mpl::false_ const &, mpl::false_ const &, mpl::true_ const &) { + // Load. + // Non-trivial. + // Binary. + bool s; + std::size_t c; + ar & s; + ar & c; + val.resize(c, c); + ar.load_binary(val.limbs(), c * sizeof(limb_type)); + if (s != val.sign()) { + val.negate(); + } + val.normalize(); + } + + template + void do_serialize(Archive &ar, Int &val, mpl::true_ const &, mpl::false_ const &, mpl::true_ const &) { + // Store. + // Non-trivial. + // Binary. + bool s = val.sign(); + std::size_t c = val.size(); + ar & s; + ar & c; + ar.save_binary(val.limbs(), c * sizeof(limb_type)); + } + + template + void do_serialize(Archive &ar, Int &val, mpl::false_ const &, mpl::true_ const &, mpl::true_ const &) { + // Load. + // Trivial. + // Binary. + bool s; + ar & s; + ar.load_binary(val.limbs(), sizeof(*val.limbs())); + if (s != val.sign()) { + val.negate(); + } + } + + template + void do_serialize(Archive &ar, Int &val, mpl::true_ const &, mpl::true_ const &, mpl::true_ const &) { + // Store. + // Trivial. + // Binary. + bool s = val.sign(); + ar & s; + ar.save_binary(val.limbs(), sizeof(*val.limbs())); + } + + } + + template< + typename Archive, unsigned MinBits, unsigned MaxBits, mp::cpp_integer_type SignType, mp::cpp_int_check_type Checked, + class Allocator, typename ParamsBackend> + void serialize(Archive &ar, mp::montgomery_int_backend &val, + const unsigned int /*version*/) { + + typedef typename Archive::is_saving save_tag; + typedef mpl::bool_ >::value> trivial_tag; + typedef typename montgomery_int_detail::is_binary_archive::type binary_tag; + + // Just dispatch to the correct method: + montgomery_int_detail::do_serialize(ar, val, save_tag(), trivial_tag(), binary_tag()); + } + + } +} // namespaces + +#endif // CRYPTO3_MP_MONTGOMERY_INT_SERIALIZE_HPP \ No newline at end of file diff --git a/include/boost/multiprecision/montgomery_inverse.hpp b/include/boost/multiprecision/montgomery_inverse.hpp new file mode 100644 index 000000000..4e26c5711 --- /dev/null +++ b/include/boost/multiprecision/montgomery_inverse.hpp @@ -0,0 +1,114 @@ +#ifndef CRYPTO3_MONTGOMERY_INVERSE_HPP +#define CRYPTO3_MONTGOMERY_INVERSE_HPP + +#include + +namespace nil { + namespace crypto3 { + template + inline Backend eval_almost_montgomery_inverse(Backend &result, const Backend &a, const Backend &b) { + typedef typename default_ops::double_precision_type::type double_type; + typedef typename boost::multiprecision::detail::canonical::type ui_type; + + using default_ops::eval_is_zero; + using default_ops::eval_lt; + using default_ops::eval_gt; + using default_ops::eval_eq; + using default_ops::eval_get_sign; + using default_ops::eval_integer_modulus; + using default_ops::eval_right_shift; + using default_ops::eval_left_shift; + + ui_type k = 0; + + Backend u = b, v = a, r = 0, s = 1; + + while (eval_gt(v, 0)) { + if (!(eval_integer_modulus(u, 2))) { + eval_right_shift(u, 1); + eval_left_shift(s, 1); + } else if (!eval_integer_modulus(v, 2)) { + eval_right_shift(v, 1); + eval_left_shift(r, 1); + } else if (eval_gt(u, v)) { + eval_subtract(u, v); + eval_right_shift(u, 1); + eval_add(r, s); + eval_left_shift(s, 1); + } else { + eval_subtract(v, u); + eval_right_shift(v, 1); + eval_add(s, r); + eval_left_shift(r, 1); + } + + ++k; + } + + if (!eval_lt(r, b)) { + eval_subtract(r, b); + } + + eval_subtract(result, b, r); + + return k; + } + + /*! + * @brief Sets result to a^-1 * 2^k mod a with n <= k <= 2n + * + * "The Montgomery Modular Inverse - Revisited" Çetin Koç, E. Savas + * https://citeseerx.ist.psu.edu/viewdoc/citations?doi=10.1.1.75.8377 + * + * A const time implementation of this algorithm is described in + * "Constant Time Modular Inversion" Joppe W. Bos + * http://www.joppebos.com/files/CTInversion.pdf + * + * @note Non-const time + * + * @param result + * @param a + * @param b + * @return a^-1 * 2^k mod b + */ + template + inline number almost_montgomery_inverse( + number &result, const number &a, + const number &b) { + return number( + eval_almost_montgomery_inverse(result.backend(), a.backend(), b.backend())); + } + + /** + * Call almost_montgomery_inverse and correct the result to a^-1 mod b + */ + template + inline Backend eval_normalized_montgomery_inverse(const Backend &a, const Backend &p) { + using default_ops::eval_integer_modulus; + using default_ops::eval_add; + using default_ops::eval_right_shift; + + Backend r, k = eval_almost_montgomery_inverse(r, a, p); + + for (size_t i = 0; i != k; ++i) { + if (eval_integer_modulus(r, 2)) { + eval_add(r, p); + } + eval_right_shift(r, 1); + } + + return r; + } + + /** + * @brief Call almost_montgomery_inverse and correct the result to a^-1 mod b + */ + template + inline number normalized_montgomery_inverse( + const number &a, const number &p) { + return number(eval_normalized_montgomery_inverse(a.backend(), p.backend())); + } + } +} + +#endif //CRYPTO3_MONTGOMERY_INVERSE_HPP \ No newline at end of file diff --git a/include/boost/multiprecision/pow_mod.hpp b/include/boost/multiprecision/pow_mod.hpp new file mode 100644 index 000000000..ad5e3ebdf --- /dev/null +++ b/include/boost/multiprecision/pow_mod.hpp @@ -0,0 +1,188 @@ +#ifndef CRYPTO3_POWER_MOD_H_ +#define CRYPTO3_POWER_MOD_H_ + +#include + +namespace nil { + namespace crypto3 { + + using namespace boost::multiprecision; + +/** +* Modular Exponentiator Interface +*/ + class modular_exponentiator { + public: + + virtual void set_base(const cpp_int &) = 0; + + virtual void set_exponent(const cpp_int &) = 0; + + virtual cpp_int execute() const = 0; + + virtual modular_exponentiator *copy() const = 0; + + modular_exponentiator() = default; + + modular_exponentiator(const modular_exponentiator &) = default; + + modular_exponentiator &operator=(const modular_exponentiator &) = default; + + virtual ~modular_exponentiator() = default; + }; + +/** +* Modular Exponentiator Proxy +*/ + class power_mod { + public: + + enum usage_hints { + NO_HINTS = 0x0000, + + BASE_IS_FIXED = 0x0001, BASE_IS_SMALL = 0x0002, BASE_IS_LARGE = 0x0004, BASE_IS_2 = 0x0008, + + EXP_IS_FIXED = 0x0100, EXP_IS_SMALL = 0x0200, EXP_IS_LARGE = 0x0400 + }; + +/* +* Try to choose a good window size +*/ + static size_t window_bits(size_t exp_bits, size_t base_bits, power_mod::usage_hints hints); + +/** +* @param modulus the modulus +* @param hints Passed to set_modulus if modulus > 0 +* @param disable_montgomery_arith Disables use of Montgomery +* representation. Likely only useful for testing. +*/ + void set_modulus(const cpp_int &modulus, usage_hints hints = NO_HINTS, + bool disable_montgomery_arith = false) const; + +/** +* Set the base +*/ + void set_base(const cpp_int &base) const; + +/** +* Set the exponent +*/ + void set_exponent(const cpp_int &exponent) const; + +/** +* All three of the above functions must have already been called. +* @return result of g^x%p +*/ + cpp_int execute() const; + + power_mod &operator=(const power_mod &); + +/** +* @param modulus Optionally call set_modulus +* @param hints Passed to set_modulus if modulus > 0 +* @param disable_montgomery_arith Disables use of Montgomery +* representation. Likely only useful for testing. +*/ + power_mod(const cpp_int &modulus = 0, usage_hints hints = NO_HINTS, bool disable_montgomery_arith = false); + + power_mod(const power_mod &); + + virtual ~power_mod() = default; + + private: + mutable std::unique_ptr m_core; + }; + +/** +* Fixed Exponent Modular Exponentiator Proxy +*/ + class fixed_exponent_power_mod final : public power_mod { + public: + + cpp_int operator()(const cpp_int &b) const { + set_base(b); + return execute(); + } + + fixed_exponent_power_mod() = default; + + fixed_exponent_power_mod(const cpp_int &exponent, const cpp_int &modulus, usage_hints hints = NO_HINTS); + + }; + +/** +* Fixed Base Modular Exponentiator Proxy +*/ + class fixed_base_power_mod final : public power_mod { + public: + + cpp_int operator()(const cpp_int &e) const { + set_exponent(e); + return execute(); + } + + fixed_base_power_mod() = default; + + fixed_base_power_mod(const cpp_int &base, const cpp_int &modulus, usage_hints hints = NO_HINTS); + + }; + + /** + * Modular exponentation + * @param base an integer base + * @param exp a positive exponent + * @param mod a positive modulus + * @return (b^x) % m + */ + template + inline Backend eval_power_mod(const Backend &base, const Backend &exp, const Backend &mod) { + using default_ops::eval_is_zero; + using default_ops::eval_lt; + using default_ops::eval_eq; + using default_ops::eval_integer_modulus; + using default_ops::eval_get_sign; + + if (eval_get_sign(mod) < 0 || eval_eq(mod, 1)) { + return 0; + } + + if (eval_is_zero(base) || eval_is_zero(mod)) { + if (eval_is_zero(exp)) { + return 1; + } + return 0; + } + + class power_mod pow_mod(mod); + + /* + * Calling set_base before set_exponent means we end up using a + * minimal window. This makes sense given that here we know that any + * precomputation is wasted. + */ + + if (eval_get_sign(base) < 0) { + pow_mod.set_base(-base); + pow_mod.set_exponent(exp); + if (!(eval_integer_modulus(exp, 2))) { + return pow_mod.execute(); + } else { + return (mod - pow_mod.execute()); + } + } else { + pow_mod.set_base(base); + pow_mod.set_exponent(exp); + return pow_mod.execute(); + } + } + + template + inline number power_mod(const number &base, + const number &exp, + const number &mod) { + return number(eval_power_mod(base.backend(), exp.backend(), mod.backend())); + } + } +} + +#endif diff --git a/include/boost/multiprecision/prime.hpp b/include/boost/multiprecision/prime.hpp new file mode 100644 index 000000000..99cfbaa57 --- /dev/null +++ b/include/boost/multiprecision/prime.hpp @@ -0,0 +1,363 @@ +#ifndef CRYPTO3_NUMBER_THEORY_H_ +#define CRYPTO3_NUMBER_THEORY_H_ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +namespace nil { + namespace crypto3 { + + using namespace boost::multiprecision; + + namespace detail { + /* + * Check if this size is allowed by FIPS 186-3 + */ + bool fips186_3_valid_size(size_t pbits, size_t qbits) { + if (qbits == 160) { + return (pbits == 1024); + } + + if (qbits == 224) { + return (pbits == 2048); + } + + if (qbits == 256) { + return (pbits == 2048 || pbits == 3072); + } + + return false; + } + + /** + * The size of the PRIMES[] array + */ + const size_t PRIME_TABLE_SIZE = 6541; + + /** + * A const array of all primes less than 65535 + */ + extern const uint16_t PRIMES[]; + } + + /** + * Compute -input^-1 mod 2^MP_WORD_BITS. Returns zero if input + * is even. If input is odd, input and 2^n are relatively prime + * and an inverse exists. + */ + template + typename std::enable_if::value == number_kind_integer, Word>::type monty_inverse( + Word input) { + if (input == 0) { + BOOST_THROW_EXCEPTION(std::invalid_argument("monty_inverse: divide by zero")); + } + + Word b = input; + Word x2 = 1, x1 = 0, y2 = 0, y1 = 1; + + // First iteration, a = n+1 + Word q = bigint_divop(1, 0, b); + Word r = (MP_WORD_MAX - q * b) + 1; + Word x = x2 - q * x1; + Word y = y2 - q * y1; + + Word a = b; + b = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + + while (b > 0) { + q = a / b; + r = a - q * b; + x = x2 - q * x1; + y = y2 - q * y1; + + a = b; + b = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + + const Word check = y2 * input; + CRYPTO3_ASSERT_EQUAL(check, 1, "monty_inverse result is inverse of input"); + + // Now invert in addition space + y2 = (MP_WORD_MAX - y2) + 1; + + return y2; + } + + /** + * Randomly generate a prime + * @param rng a random number generator + * @param bits how large the resulting prime should be in bits + * @param coprime a positive integer that (prime - 1) should be coprime to + * @param equiv a non-negative number that the result should be + equivalent to modulo equiv_mod + * @param equiv_mod the modulus equiv should be checked against + * @param prob use test so false positive is bounded by 1/2**prob + * @return random prime with the specified criteria + */ + template + number random_prime(UniformRandomNumberGenerator &rng, size_t bits, + const number &coprime = 0, + std::size_t equiv = 1, std::size_t modulo = 2, + std::size_t prob = 128) { + if (coprime < 0) { + BOOST_THROW_EXCEPTION(std::invalid_argument("random_prime: coprime must be >= 0")); + } + if (modulo == 0) { + BOOST_THROW_EXCEPTION(std::invalid_argument("random_prime: Invalid modulo value")); + } + + equiv %= modulo; + + if (equiv == 0) { + BOOST_THROW_EXCEPTION(std::invalid_argument("random_prime Invalid value for equiv/modulo")); + } + + // Handle small values: + if (bits <= 1) { + BOOST_THROW_EXCEPTION( + std::invalid_argument("random_prime: Can't make a prime of " + std::to_string(bits) + " bits")); + } else if (bits == 2) { + return ((rng.next_byte() % 2) ? 2 : 3); + } else if (bits == 3) { + return ((rng.next_byte() % 2) ? 5 : 7); + } else if (bits == 4) { + return ((rng.next_byte() % 2) ? 11 : 13); + } else if (bits <= 16) { + for (;;) { + size_t idx = make_uint16(rng.next_byte(), rng.next_byte()) % detail::PRIME_TABLE_SIZE; + uint16_t small_prime = detail::PRIMES[idx]; + + if (high_bit(small_prime) == bits) { + return small_prime; + } + } + } + + secure_vector sieve(detail::PRIME_TABLE_SIZE); + const size_t MAX_ATTEMPTS = 32 * 1024; + + while (true) { + cpp_int p(rng, bits); + + // Force lowest and two top bits on + bit_set(p, bits - 1); + bit_set(p, bits - 2); + bit_set(p, 0); + + // Force p to be equal to equiv mod modulo + p += (modulo - (p % modulo)) + equiv; + + for (size_t i = 0; i != sieve.size(); ++i) { + sieve[i] = static_cast(p % detail::PRIMES[i]); + } + + size_t counter = 0; + while (true) { + ++counter; + + if (counter > MAX_ATTEMPTS) { + break; // don't try forever, choose a new starting point + } + + p += modulo; + + if (msb(p) > bits) { + break; + } + + // Now that p is updated, update the sieve + for (size_t i = 0; i != sieve.size(); ++i) { + sieve[i] = (sieve[i] + modulo) % detail::PRIMES[i]; + } + + bool passes_sieve = true; + for (size_t i = 0; passes_sieve && (i != sieve.size()); ++i) { + /* + In this case, p is a multiple of PRIMES[i] + */ + if (sieve[i] == 0) { + passes_sieve = false; + } + + /* + In this case, 2*p+1 will be a multiple of PRIMES[i] + + So if generating a safe prime, we want to avoid this value + because 2*p+1 will not be useful. Since the check is cheap to + do and doesn't seem to affect the overall distribution of the + generated primes overmuch it's used in all cases. + + See "Safe Prime Generation with a Combined Sieve" M. Wiener + https://eprint.iacr.org/2003/186.pdf + */ + if (sieve[i] == (detail::PRIMES[i] - 1) / 2) { + passes_sieve = false; + } + } + + if (!passes_sieve) { + continue; + } + + if (coprime > 0 && gcd(p - 1, coprime) != 1) { + continue; + } + + if (miller_rabin_test(p, prob, rng)) { + return p; + } + } + } + } + + /** + * Return a 'safe' prime, of the form p=2*q+1 with q prime + * @param rng a random number generator + * @param bits is how long the resulting prime should be + * @return prime randomly chosen from safe primes of length bits + */ + template + number random_safe_prime(UniformRandomNumberGenerator &rng, std::size_t bits) { + if (bits <= 64) { + BOOST_THROW_EXCEPTION(std::invalid_argument( + "random_safe_prime: Can't make a prime of " + std::to_string(bits) + " bits")); + } + + cpp_int q, p; + for (;;) { + /* + Generate q == 2 (mod 3) + + Otherwise [q == 1 (mod 3) case], 2*q+1 == 3 (mod 3) and not prime. + */ + q = random_prime(rng, bits - 1, 1, 2, 3, 8); + p = (q << 1) + 1; + + if (miller_rabin_test(p, 128, rng)) { + // We did only a weak check before, go back and verify q before returning + if (miller_rabin_test(q, 128, rng)) { + return p; + } + } + + } + } + + /** + * @brief Generate DSA parameters using the FIPS 186 kosherizer + * + * @tparam Hasher + * @tparam UniformRandomNumberGenerator + * + * @param rng a random number generator + * @param p_out where the prime p will be stored + * @param q_out where the prime q will be stored + * @param pbits how long p will be in bits + * @param qbits how long q will be in bits + * @param seed_c the seed used to generate the parameters + * @param offset optional offset from seed to start searching at + * @return true if seed generated a valid DSA parameter set, otherwise + false. p_out and q_out are only valid if true was returned. + */ + template class hash::sha, std::size_t PBits, std::size_t QBits, + typename Backend, expression_template_option ExpressionTemplates, typename UniformRandomNumberGenerator> + bool generate_dsa_primes(number &q_out, const std::vector &seed_c, + size_t offset = 0, UniformRandomNumberGenerator &rng, Hasher &hasher) { + if (!detail::fips186_3_valid_size(PBits, QBits)) { + BOOST_THROW_EXCEPTION(std::invalid_argument( + "FIPS 186-3 does not allow DSA domain parameters of " + std::to_string(PBits) + "/" + + std::to_string(QBits) + " bits long")); + } + + if (seed_c.size() * 8 < QBits) { + BOOST_THROW_EXCEPTION(std::invalid_argument( + "Generating a DSA parameter set with a " + std::to_string(QBits) + + " bit long q requires a seed at least as many bits long")); + } + + const std::string hash_name = "SHA-" + std::to_string(QBits); + std::unique_ptr hash(HashFunction::create_or_throw(hash_name)); + + const size_t HASH_SIZE = hash->output_length(); + + class Seed final { + public: + explicit Seed(const std::vector &s) : m_seed(s) { + } + + const std::vector &value() const { + return m_seed; + } + + Seed &operator++() { + for (size_t j = m_seed.size(); j > 0; --j) { + if (++m_seed[j - 1]) { + break; + } + } + return (*this); + } + + private: + std::vector m_seed; + }; + + Seed seed(seed_c); + + q_out.binary_decode(hash->process(seed.value())); + bit_set(q_out, QBits - 1); + bit_set(q_out, 0); + + if (!miller_rabin_test(q_out, 126, rng)) { + return false; + } + + const size_t n = (PBits - 1) / (HASH_SIZE * 8), b = (PBits - 1) % (HASH_SIZE * 8); + + cpp_int X; + std::vector V(HASH_SIZE * (n + 1)); + + for (size_t j = 0; j != 4 * PBits; ++j) { + for (size_t k = 0; k <= n; ++k) { + ++seed; + hash->update(seed.value()); + hash->final(&V[HASH_SIZE * (n - k)]); + } + + if (j >= offset) { + X.binary_decode(&V[HASH_SIZE - 1 - b / 8], V.size() - (HASH_SIZE - 1 - b / 8)); + bit_set(X, PBits - 1); + + p_out = X - (X % (2 * q_out) - 1); + + if (p_out.bits() == PBits && miller_rabin_test(p_out, 126, rng)) { + return true; + } + } + } + return false; + } + } +} + +#endif \ No newline at end of file diff --git a/include/boost/multiprecision/reduce_below.hpp b/include/boost/multiprecision/reduce_below.hpp new file mode 100644 index 000000000..68cc8d3e2 --- /dev/null +++ b/include/boost/multiprecision/reduce_below.hpp @@ -0,0 +1,29 @@ +#ifndef CRYPTO3_REDUCE_BELOW_HPP +#define CRYPTO3_REDUCE_BELOW_HPP + +namespace nil { + namespace crypto3 { + using namespace boost::multiprecision; + + template + void eval_reduce_below(Backend &val, const Backend &mod) { + using default_ops::eval_lt; + + if (eval_lt(mod, 0)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("reduce_below modulus must be positive")); + } + + while (eval_lt(mod, val)) { + eval_subtract(val, mod); + } + } + + template + number reduce_below(number &val, + const number &mod) { + return number(eval_reduce_below(val.backend(), mod.backend())); + } + } +} + +#endif //CRYPTO3_REDUCE_BELOW_HPP diff --git a/include/boost/multiprecision/ressol.hpp b/include/boost/multiprecision/ressol.hpp new file mode 100644 index 000000000..ff2644118 --- /dev/null +++ b/include/boost/multiprecision/ressol.hpp @@ -0,0 +1,114 @@ +#ifndef CRYPTO3_RESSOL_HPP +#define CRYPTO3_RESSOL_HPP + +#include +#include + +namespace nil { + namespace crypto3 { + /** + * Compute the square root of x modulo a prime using the + * Shanks-Tonnelli algorithm + * + * @param x the input + * @param p the prime + * @return y such that (y*y)%p == x, or -1 if no such integer + */ + template + inline Backend eval_ressol(const Backend &a, const Backend &p) { + using default_ops::eval_is_zero; + using default_ops::eval_lt; + using default_ops::eval_gt; + using default_ops::eval_eq; + using default_ops::eval_integer_modulus; + using default_ops::eval_subtract; + using default_ops::eval_get_sign; + using default_ops::eval_right_shift; + using default_ops::eval_bit_set; + using default_ops::eval_lsb; + + if (eval_is_zero(a)) { + return Backend(0); + } else if (eval_get_sign(a) < 0) { + BOOST_THROW_EXCEPTION(std::invalid_argument("ressol: value to solve for must be positive")); + } else if (!eval_lt(a, p)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("ressol: value to solve for must be less than p")); + } + + if (eval_eq(p, 2)) { + return a; + } else if (!eval_gt(p, 1)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("ressol: prime must be > 1 a")); + } else if (eval_integer_modulus(p, 2)) { + BOOST_THROW_EXCEPTION(std::invalid_argument("ressol: invalid prime")); + } + + if (eval_jacobi(a, p) != 1) { // not a quadratic residue + return Backend(-1); + } + + if (eval_integer_modulus(p, 4) == 3) { + return power_mod(a, ((p + 1) >> 2), p); + } + + size_t s = eval_lsb(p - 1); + + Backend q = p; + + eval_right_shift(p, s); + eval_subtract(q, 1); + eval_right_shift(q, 1); + + modular_reducer mod_p(p); + + Backend r = eval_power_mod(a, q, p); + Backend n = mod_p.multiply(a, mod_p.square(r)); + r = mod_p.multiply(r, a); + + if (eval_eq(n, 1)) { + return r; + } + + // find random non quadratic residue z + Backend z = 2; + while (eval_jacobi(z, p) == 1) { // while z quadratic residue + ++z; + } + + Backend c = eval_power_mod(z, (q << 1) + 1, p); + + while (eval_gt(n, 1)) { + q = n; + + size_t i = 0; + while (q != 1) { + q = mod_p.square(q); + ++i; + + if (i >= s) { + return -Backend(1); + } + } + + Backend p2; + eval_bit_set(p2, s - i - 1); + + c = power_mod(c, p2, p); + r = mod_p.multiply(r, c); + c = mod_p.square(c); + n = mod_p.multiply(n, c); + s = i; + } + + return r; + } + + template + inline number ressol(const number &a, + const number &p) { + return number(eval_ressol(a.backend(), p.backend())); + } + } +} + +#endif //CRYPTO3_RESSOL_HPP \ No newline at end of file diff --git a/test/zerg.cpp b/test/zerg.cpp new file mode 100644 index 000000000..8f846d119 --- /dev/null +++ b/test/zerg.cpp @@ -0,0 +1,32 @@ +// +// Created by Zerg1996 on 2019-04-27. +// + +//#include +#include +#include +#include +#include + + +int main() +{ + + using namespace boost::multiprecision; + using default_ops::eval_msb; + + cpp_int a(7); + nil::crypto3::montgomery_params tt(a); + std::cout << "-----" << std::endl; + //montgomery_int x(9299, tt); + //montgomery_int x2(1315541, tt); + montgomery_int x(3, tt); + std::cout << "X1:" << x << std::endl; + //montgomery_int x2(b, tt); + montgomery_int x2(6, tt); + std::cout << "X2:" << x2 << std::endl; + + x = x * x2; + std::cout << "Mult:" << x << std::endl; + return 0; +}