Skip to content

Commit

Permalink
multiprecision: goldilocks: fix compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
ioxid committed Dec 25, 2024
1 parent e98e87f commit bdd6b08
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,19 @@ namespace nil::crypto3::multiprecision {

// Components

constexpr base_type base() const {
private:
constexpr base_type internal_base() const {
base_type result;
ops().adjust_regular(result, raw_base());
return result;
}

constexpr const base_type& mod() const { return ops().mod(); }
public:
constexpr auto base() const { return detail::as_big_uint(internal_base()); }

constexpr decltype(auto) mod() const { return detail::as_big_uint(ops().mod()); }

explicit constexpr operator base_type() const { return base(); }
explicit constexpr operator auto() const { return base(); }

explicit constexpr operator bool() const { return !is_zero(); }

Expand All @@ -101,12 +105,12 @@ namespace nil::crypto3::multiprecision {
\
template<typename T, std::enable_if_t<is_integral_v<T>, int> = 0> \
friend constexpr bool operator OP_(const big_mod_impl& a, const T& b) noexcept { \
return a.base() OP_ b; \
return a.internal_base() OP_ b; \
} \
\
template<typename T, std::enable_if_t<is_integral_v<T>, int> = 0> \
friend constexpr bool operator OP_(const T& a, const big_mod_impl& b) noexcept { \
return a OP_ b.base(); \
return a OP_ b.internal_base(); \
}

NIL_CO3_MP_BIG_MOD_COMPARISON_IMPL(==)
Expand All @@ -118,20 +122,16 @@ namespace nil::crypto3::multiprecision {
// In barrett form raw_base is the same as base
// In montgomery form raw_base is base multiplied by r, so it is zero iff base
// is
return raw_base().is_zero();
return nil::crypto3::multiprecision::is_zero(raw_base());
}

// String conversion

constexpr std::string str(
std::ios_base::fmtflags flags = std::ios_base::hex | std::ios_base::showbase |
std::ios_base::uppercase) const {
if constexpr (std::is_integral_v<base_type>) {
// TODO(ioxid): support formating flags
return std::to_string(base());
} else {
return base().str(flags);
}
// TODO(ioxid): optimize when base_type is not big_uint
return base().str(flags);
}

// Arithmetic operations
Expand Down Expand Up @@ -227,14 +227,14 @@ namespace nil::crypto3::multiprecision {
std::enable_if_t<is_integral_v<T> && !std::numeric_limits<T>::is_signed,
int> = 0>
friend constexpr big_mod_impl pow_unsigned(big_mod_impl b, const T& e) {
b.ops().pow(b.m_raw_base, b.raw_base(), e);
b.ops().pow_unsigned(b.m_raw_base, b.raw_base(), e);
return b;
}

// Hash

friend constexpr std::size_t hash_value(const big_mod_impl& value) noexcept {
return hash_value(value.raw_base());
return boost::hash<base_type>{}(value.raw_base());
// mod() is ignored because we don't allow comparing numbers with different
// moduli anyway
}
Expand Down Expand Up @@ -294,8 +294,8 @@ namespace nil::crypto3::multiprecision {

// Simple modular big integer type with compile-time modulus. Modulus should be a
// static big_uint constant. Uses barret optimizations.
template<const auto& modulus>
using big_mod = big_mod_ct_impl<modulus, detail::barrett_modular_ops>;
template<const auto& Modulus>
using big_mod = big_mod_ct_impl<Modulus, detail::barrett_modular_ops>;

// Simple modular big integer type with runtime modulus. Uses barret optimizations.
template<std::size_t Bits>
Expand All @@ -307,11 +307,11 @@ namespace nil::crypto3::multiprecision {
// Modular big integer type with compile-time modulus, which automatically uses
// montomery form whenever possible (i.e. for odd moduli). Modulus should be a static
// big_uint constant.
template<const auto& modulus>
template<const auto& Modulus>
using auto_big_mod = std::conditional_t<
modulus == goldilocks_modulus, goldilocks_mod,
std::conditional_t<detail::check_montgomery_constraints(modulus),
montgomery_big_mod<modulus>, big_mod<modulus>>>;
Modulus == goldilocks_modulus, goldilocks_mod,
std::conditional_t<detail::modulus_supports_montgomery(Modulus),
montgomery_big_mod<Modulus>, big_mod<Modulus>>>;
} // namespace nil::crypto3::multiprecision

// std::hash specializations
Expand All @@ -337,3 +337,11 @@ struct std::hash<
a);
}
};

template<>
struct std::hash<nil::crypto3::multiprecision::goldilocks_mod> {
std::size_t operator()(
const nil::crypto3::multiprecision::goldilocks_mod& a) const noexcept {
return boost::hash<nil::crypto3::multiprecision::goldilocks_mod>{}(a);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,10 @@ namespace nil::crypto3::multiprecision::detail {
barrett_reduce(result, tmp);
}

template<
std::size_t Bits2, std::size_t Bits3, typename T,
// result should fit in the output parameter
std::enable_if_t<big_uint<Bits2>::Bits >= big_uint_t::Bits &&
is_integral_v<T> && !std::numeric_limits<T>::is_signed,
int> = 0>
constexpr void pow(big_uint<Bits2> &result, const big_uint<Bits3> &a,
T exp) const {
template<typename T,
std::enable_if_t<is_integral_v<T> && !std::numeric_limits<T>::is_signed,
int> = 0>
constexpr void pow_unsigned(base_type &result, const base_type &a, T exp) const {
// input parameter should be less than modulus
BOOST_ASSERT(a < this->mod());

Expand All @@ -102,7 +98,7 @@ namespace nil::crypto3::multiprecision::detail {
return;
}

big_uint<2 * Bits> base(a), res(1u);
big_uint<2 * Bits> base = a, res = 1u;

while (true) {
bool lsb = bit_test(exp, 0u);
Expand All @@ -117,7 +113,7 @@ namespace nil::crypto3::multiprecision::detail {
base *= base;
barrett_reduce(base);
}
result = static_cast<big_uint<Bits2>>(res);
result = static_cast<base_type>(res);
}

// Adjust to/from modular form
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ namespace nil::crypto3::multiprecision::detail {
public:
using base_type = base_type_;

static_assert(is_integral_v<base_type>);

constexpr common_modular_ops(const base_type &m) : m_mod(m) {}

constexpr bool compare_eq(const common_modular_ops &other) const {
return mod() == other.mod();
}

constexpr void negate_inplace(base_type &raw_base) const {
if (!raw_base.is_zero()) {
if (!is_zero(raw_base)) {
auto initial_raw_base = raw_base;
raw_base = mod();
raw_base -= initial_raw_base;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,39 @@ Goldilocks::new(t2)
result = reduce128(prod);
}

template<typename T,
std::enable_if_t<
is_integral_v<T> && !std::numeric_limits<T>::is_signed, int> = 0>
constexpr void pow_unsigned(base_type &result, const base_type &a,
T exp) const {
// input parameter should be less than modulus
BOOST_ASSERT(a < this->mod());

if (is_zero(exp)) {
result = 1u;
return;
}
if (this->mod() == 1u) {
result = 0u;
return;
}

base_type base = a, res = 1u;

while (true) {
bool lsb = bit_test(exp, 0u);
exp >>= 1u;
if (lsb) {
mul(res, base);
if (is_zero(exp)) {
break;
}
}
mul(base, base);
}
result = res;
}

template<typename T,
std::enable_if_t<
is_integral_v<T> && !std::numeric_limits<T>::is_signed, int> = 0>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@
#include "nil/crypto3/multiprecision/detail/integer_ops_base.hpp"

namespace nil::crypto3::multiprecision::detail {
template<std::size_t Bits>
constexpr bool check_montgomery_constraints(const big_uint<Bits> &m) {
template<typename T>
constexpr bool modulus_supports_montgomery(const T &m) {
static_assert(is_integral_v<T> && !std::numeric_limits<T>::is_signed);
// Check m % 2 == 0
return m.bit_test(0u);
return bit_test(m, 0u);
}

// Montgomery modular operations. Uses Barrett reduction internally and inherits
Expand All @@ -43,7 +44,7 @@ namespace nil::crypto3::multiprecision::detail {
static constexpr std::size_t limb_count = big_uint_t::static_limb_count;

constexpr montgomery_modular_ops(const big_uint_t &m) : barrett_modular_ops<Bits_>(m) {
if (!check_montgomery_constraints(m)) {
if (!modulus_supports_montgomery(m)) {
throw std::invalid_argument("module not usable with montgomery");
}

Expand Down Expand Up @@ -329,14 +330,10 @@ namespace nil::crypto3::multiprecision::detail {
}
}

template<
std::size_t Bits2, std::size_t Bits3, typename T,
// result should fit in the output parameter
std::enable_if_t<big_uint<Bits2>::Bits >= big_uint_t::Bits &&
is_integral_v<T> && !std::numeric_limits<T>::is_signed,
int> = 0>
constexpr void pow(big_uint<Bits2> &result, const big_uint<Bits3> &a,
T exp) const {
template<typename T,
std::enable_if_t<is_integral_v<T> && !std::numeric_limits<T>::is_signed,
int> = 0>
constexpr void pow_unsigned(base_type &result, const base_type &a, T exp) const {
// input parameter should be less than modulus
BOOST_ASSERT(a < this->mod());

Expand All @@ -349,7 +346,7 @@ namespace nil::crypto3::multiprecision::detail {
return;
}

big_uint_t base(a), res = m_one;
big_uint_t base = a, res = m_one;

while (true) {
bool lsb = bit_test(exp, 0u);
Expand Down
41 changes: 26 additions & 15 deletions crypto3/libs/multiprecision/test/big_mod_basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,35 @@

#define BOOST_TEST_MODULE big_mod_basic_test

#include <boost/test/unit_test.hpp>

#include <cstdint>
#include <type_traits>
#include <utility>

#include <boost/test/unit_test.hpp>

#include "nil/crypto3/multiprecision/big_mod.hpp"
#include "nil/crypto3/multiprecision/big_uint.hpp"
#include "nil/crypto3/multiprecision/literals.hpp"

using namespace nil::crypto3::multiprecision;
using namespace nil::crypto3::multiprecision::literals;

NIL_CO3_MP_DEFINE_BIG_UINT_LITERAL(2)
NIL_CO3_MP_DEFINE_BIG_UINT_LITERAL(32)
NIL_CO3_MP_DEFINE_BIG_UINT_LITERAL(36)
NIL_CO3_MP_DEFINE_BIG_UINT_LITERAL(57)
NIL_CO3_MP_DEFINE_BIG_UINT_LITERAL(60)

using namespace nil::crypto3::multiprecision::literals;
constexpr big_uint<64> goldilocks_modulus_big_uint = 0xFFFFFFFF00000001ULL;
static_assert(std::is_same_v<auto_big_mod<goldilocks_modulus_big_uint>, goldilocks_mod>);

constexpr auto odd_mod = 0x123456789ABCDEF_big_uint57;
constexpr auto even_mod = 0x123456789ABCDEE_big_uint57;

static_assert(std::is_same_v<auto_big_mod<odd_mod>, montgomery_big_mod<odd_mod>>);
static_assert(std::is_same_v<auto_big_mod<even_mod>, big_mod<even_mod>>);

constexpr auto mod = 0x123456789ABCDEF_big_uint57;
using montgomery_big_mod_t = montgomery_big_mod<mod>;
using big_mod_t = big_mod<mod>;
using montgomery_big_mod_t = montgomery_big_mod<odd_mod>;
using big_mod_t = big_mod<odd_mod>;

BOOST_AUTO_TEST_SUITE(smoke)

Expand Down Expand Up @@ -196,25 +202,30 @@ BOOST_AUTO_TEST_CASE(multilimb) {
BOOST_AUTO_TEST_CASE(big) {
static constexpr auto mod =
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001_big_uint224;
big_mod<mod> a = 0xC5067EE5D80302E0561545A8467C6D5C98BC4D37672EB301C38CE9A9_big_uint224;
big_mod<mod> a =
0xC5067EE5D80302E0561545A8467C6D5C98BC4D37672EB301C38CE9A9_big_uint224;

big_mod<mod> b = 0xE632329C42040E595D127EB6889D22215DBE56F540425C705D6BF83_big_uint224;
big_mod<mod> b =
0xE632329C42040E595D127EB6889D22215DBE56F540425C705D6BF83_big_uint224;

BOOST_CHECK_EQUAL((a * b).base(),
0x107BC09A9F3443A6F6458495ADD98CBA1FCD15F17D0EAB66302FEFA6_big_uint224);
BOOST_CHECK_EQUAL(
(a * b).base(),
0x107BC09A9F3443A6F6458495ADD98CBA1FCD15F17D0EAB66302FEFA6_big_uint224);
}

BOOST_AUTO_TEST_CASE(big_assign) {
static constexpr auto mod =
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001_big_uint224;
big_mod<mod> a = 0xC5067EE5D80302E0561545A8467C6D5C98BC4D37672EB301C38CE9A9_big_uint224;
big_mod<mod> a =
0xC5067EE5D80302E0561545A8467C6D5C98BC4D37672EB301C38CE9A9_big_uint224;

big_mod<mod> b = 0xE632329C42040E595D127EB6889D22215DBE56F540425C705D6BF83_big_uint224;
big_mod<mod> b =
0xE632329C42040E595D127EB6889D22215DBE56F540425C705D6BF83_big_uint224;

a *= b;

BOOST_CHECK_EQUAL(a.base(),
0x107BC09A9F3443A6F6458495ADD98CBA1FCD15F17D0EAB66302FEFA6_big_uint224);
BOOST_CHECK_EQUAL(
a.base(), 0x107BC09A9F3443A6F6458495ADD98CBA1FCD15F17D0EAB66302FEFA6_big_uint224);
}

BOOST_AUTO_TEST_SUITE_END()
Expand Down

0 comments on commit bdd6b08

Please sign in to comment.