Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiprecision refactoring #98

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

namespace nil::crypto3::multiprecision {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/big_integer/big_integer_ops.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/big_integer/limits.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/big_integer/storage.hpp" // IWYU pragma: export

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
#pragma once

#include <algorithm>
#include <climits>
#include <cstring>
#include <ostream>
#include <type_traits>

#include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp"

#include "nil/crypto3/multiprecision/big_integer/ops/import_export.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/big_integer/ops/misc.hpp" // IWYU pragma: export

namespace nil::crypto3::multiprecision {
namespace detail {
template<typename T>
static constexpr bool always_false = false;

template<typename T>
constexpr bool is_big_integer_v = false;

template<unsigned Bits>
constexpr bool is_big_integer_v<big_integer<Bits>> = true;

template<typename T>
constexpr bool is_integral_v = std::is_integral_v<T> || is_big_integer_v<T>;

template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
constexpr std::size_t get_bits() {
return sizeof(T) * CHAR_BIT;
}

template<typename T, std::enable_if_t<is_big_integer_v<T>, int> = 0>
constexpr std::size_t get_bits() {
return T::Bits;
}
} // namespace detail

#define CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE \
template<typename T1, typename T2, \
std::enable_if_t<detail::is_integral_v<T1> && detail::is_integral_v<T2> && \
(detail::is_big_integer_v<T1> || detail::is_big_integer_v<T2>), \
int> = 0, \
typename largest_t = \
big_integer<std::max(detail::get_bits<T1>(), detail::get_bits<T2>())>>

// TODO(ioxid): somehow error on overflow
#define CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE \
template<typename big_integer_t, typename T, \
std::enable_if_t<detail::is_big_integer_v<big_integer_t> && detail::is_integral_v<T>, \
int> = 0>

#define CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE \
template<typename big_integer_t, \
std::enable_if_t<detail::is_big_integer_v<big_integer_t>, int> = 0>

// Comparison

#define CRYPTO3_MP_BIG_INTEGER_IMPL_OPERATOR(op) \
CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE \
inline constexpr bool operator op(const T1& a, const T2& b) noexcept { \
largest_t ap = a; \
largest_t bp = b; \
return ap.compare(bp) op 0; \
}

CRYPTO3_MP_BIG_INTEGER_IMPL_OPERATOR(<)
CRYPTO3_MP_BIG_INTEGER_IMPL_OPERATOR(<=)
CRYPTO3_MP_BIG_INTEGER_IMPL_OPERATOR(>)
CRYPTO3_MP_BIG_INTEGER_IMPL_OPERATOR(>=)
CRYPTO3_MP_BIG_INTEGER_IMPL_OPERATOR(==)
CRYPTO3_MP_BIG_INTEGER_IMPL_OPERATOR(!=)

// TODO(ioxid): implement comparison with signed types, needed for boost::random
#undef CRYPTO3_MP_BIG_INTEGER_IMPL_OPERATOR

// Arithmetic operations

CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE
inline constexpr auto operator+(const T1& a, const T2& b) noexcept {
big_integer<largest_t::Bits + 1> result = a;
decltype(result)::add(result, result, b);
return result;
}
CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE
inline constexpr auto& operator+=(big_integer_t& a, const T& b) noexcept {
big_integer_t::add(a, a, b);
return a;
}
CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto& operator++(big_integer_t& a) noexcept {
a.increment();
return a;
}
CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto operator++(big_integer_t& a, int) noexcept {
auto copy = a;
++a;
return copy;
}
CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto operator+(const big_integer_t& a) noexcept { return a; }

CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE
inline constexpr auto operator-(const T1& a, const T2& b) noexcept {
T1 result;
T1::subtract(result, a, b);
return result;
}
CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE
inline constexpr auto& operator-=(big_integer_t& a, const T& b) {
big_integer_t::subtract(a, a, b);
return a;
}
CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto& operator--(big_integer_t& a) noexcept {
a.decrement();
return a;
}
CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto operator--(big_integer_t& a, int) noexcept {
auto copy = a;
--a;
return copy;
}

CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr big_integer_t operator-(const big_integer_t& /* unused */) noexcept {
// TODO(ioxid): implement?
static_assert(detail::always_false<big_integer_t>, "can't negate unsigned type");
}

CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE
inline constexpr auto operator*(const T1& a, const T2& b) noexcept {
big_integer<detail::get_bits<T1>() + detail::get_bits<T2>()> result;
decltype(result)::multiply(result, a, b);
return result;
}
CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE
inline constexpr auto& operator*=(big_integer_t& a, const T& b) noexcept {
big_integer<detail::get_bits<big_integer_t>() + detail::get_bits<T>()> result;
decltype(result)::multiply(result, a, static_cast<big_integer_t>(b));
a = result;
return a;
}

CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE
inline constexpr auto operator/(const T1& a, const T2& b) noexcept {
largest_t result;
largest_t modulus;
largest_t::divide(&result, a, b, modulus);
return result;
}
CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE
inline constexpr auto& operator/=(big_integer_t& a, const T& b) noexcept {
big_integer_t result;
big_integer_t modulus;
big_integer_t::divide(&result, a, b, modulus);
a = result;
return a;
}

CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE
inline constexpr auto operator%(const T1& a, const T2& b) noexcept {
largest_t modulus;
largest_t::divide(nullptr, a, b, modulus);
return modulus;
}
CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE
inline constexpr auto& operator%=(big_integer_t& a, const T& b) {
big_integer_t modulus;
big_integer_t::divide(nullptr, a, b, modulus);
a = modulus;
return a;
}

CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE
inline constexpr auto operator&(const T1& a, const T2& b) noexcept {
largest_t result = a;
T1::bitwise_and(result, b);
return result;
}
CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE
inline constexpr auto& operator&=(big_integer_t& a, const T& b) {
big_integer_t::bitwise_and(a, b);
return a;
}

CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE
inline constexpr auto operator|(const T1& a, const T2& b) noexcept {
largest_t result = a;
T1::bitwise_or(result, b);
return result;
}
CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE
inline constexpr auto& operator|=(big_integer_t& a, const T& b) {
big_integer_t::bitwise_or(a, b);
return a;
}

CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE
inline constexpr auto operator^(const T1& a, const T2& b) noexcept {
largest_t result = a;
T1::bitwise_xor(result, b);
return result;
}
CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE
inline constexpr auto& operator^=(big_integer_t& a, const T& b) {
big_integer_t::bitwise_or(a, b);
return a;
}

CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto operator~(const big_integer_t& a) noexcept {
big_integer_t result;
big_integer_t::complement(result, a);
return result;
}

CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto operator<<(const big_integer_t& a, unsigned shift) noexcept {
big_integer_t result = a;
big_integer_t::left_shift(result, shift);
return result;
}
CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto& operator<<=(big_integer_t& a, unsigned shift) noexcept {
// TODO(ioxid): check
big_integer_t::left_shift(a, shift);
return a;
}

CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto operator>>(const big_integer_t& a, unsigned shift) noexcept {
big_integer_t result = a;
big_integer_t::right_shift(result, shift);
return result;
}
CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
inline constexpr auto& operator>>=(big_integer_t& a, unsigned shift) noexcept {
// TODO(ioxid): check
big_integer_t::right_shift(a, shift);
return a;
}

// IO

CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
std::ostream& operator<<(std::ostream& os, const big_integer_t& value) {
os << value.str() << std::endl;
return os;
}

#undef CRYPTO3_MP_BIG_INTEGER_UNARY_TEMPLATE
#undef CRYPTO3_MP_BIG_INTEGER_INTEGRAL_ASSIGNMENT_TEMPLATE
#undef CRYPTO3_MP_BIG_INTEGER_INTEGRAL_TEMPLATE
} // namespace nil::crypto3::multiprecision
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#if !defined(NIL_CO3_MP_FORCEINLINE)

#if defined(NDEBUG) && !defined(_DEBUG)

#if defined(_MSC_VER)
#define NIL_CO3_MP_FORCEINLINE __forceinline
#elif defined(__GNUC__) && __GNUC__ > 3
// Clang also defines __GNUC__ (as 4)
#define NIL_CO3_MP_FORCEINLINE inline __attribute__((__always_inline__))
#else
#define NIL_CO3_MP_FORCEINLINE inline
#endif

#else

#define NIL_CO3_MP_FORCEINLINE inline

#endif

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
///////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt

#pragma once

#include <climits>
#include <limits>

#include "nil/crypto3/multiprecision/big_integer/big_integer_impl.hpp"

namespace nil::crypto3::multiprecision::detail {
template<unsigned Bits>
inline constexpr big_integer<Bits> get_min() {
constexpr big_integer<Bits> val = 0u;
return val;
}

template<unsigned Bits>
inline constexpr nil::crypto3::multiprecision::big_integer<Bits> get_max() {
constexpr auto val = ~big_integer<Bits>(0u);
return val;
}

inline constexpr unsigned calc_digits10(unsigned d) {
//
// We need floor(log10(2) * (d-1)), see:
// https://www.exploringbinary.com/number-of-digits-required-for-round-trip-conversions/
// and references therein.
//
return static_cast<unsigned>(0.301029995663981195213738894724493026768189881462108541310 *
static_cast<double>(d - 1u));
}
} // namespace nil::crypto3::multiprecision::detail

namespace std {
template<unsigned Bits>
class numeric_limits<nil::crypto3::multiprecision::big_integer<Bits>> {
using number_type = nil::crypto3::multiprecision::big_integer<Bits>;

public:
static constexpr bool is_specialized = true;
//
// Largest and smallest numbers are bounded only by available memory, set
// to zero:
//
static constexpr number_type(min)() {
return nil::crypto3::multiprecision::detail::get_min<Bits>();
}
static constexpr number_type(max)() {
return nil::crypto3::multiprecision::detail::get_max<Bits>();
}
static constexpr number_type lowest() { return (min)(); }
static constexpr int digits = number_type::Bits;
static constexpr int digits10 = nil::crypto3::multiprecision::detail::calc_digits10(digits);
static constexpr int max_digits10 =
nil::crypto3::multiprecision::detail::calc_digits10(digits);
static constexpr bool is_signed = false;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr int radix = 2;
static constexpr number_type epsilon() { return 0; }
static constexpr number_type round_error() { return 0; }
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_NaN = false;
static constexpr bool has_signaling_NaN = false;
static constexpr float_denorm_style has_denorm = denorm_absent;
static constexpr bool has_denorm_loss = false;
static constexpr number_type infinity() { return 0; }
static constexpr number_type quiet_NaN() { return 0; }
static constexpr number_type signaling_NaN() { return 0; }
static constexpr number_type denorm_min() { return 0; }
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool traps = false;
static constexpr bool tinyness_before = false;
};

} // namespace std
Loading
Loading