Skip to content

Commit

Permalink
multiprecision: add custom and boost tests and fix bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
ioxid committed Dec 19, 2024
1 parent 81f11dd commit b8adb34
Show file tree
Hide file tree
Showing 11 changed files with 2,287 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "nil/crypto3/multiprecision/detail/big_uint/limits.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/big_uint/ops/gcd_inverse.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/big_uint/ops/jacobi.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/big_uint/ops/pow.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/big_uint/ops/powm.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/big_uint/ops/ressol.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/big_uint/ops/wnaf.hpp" // IWYU pragma: export
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2019-2021 Aleksei Moskvin <[email protected]>
// Copyright (c) 2020 Mikhail Komarov <[email protected]>
// Copyright (c) 2020 Ilias Khairullin <[email protected]>
// Copyright (c) 2024 Andrey Nefedov <[email protected]>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//---------------------------------------------------------------------------//

#pragma once

// IWYU pragma: private; include "nil/crypto3/multiprecision/big_uint.hpp"

#include <type_traits>

#include "nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp"
#include "nil/crypto3/multiprecision/detail/integer_ops_base.hpp"

namespace nil::crypto3::multiprecision {
template<typename T1, typename T2,
std::enable_if_t<detail::is_integral_v<std::decay_t<T1>> &&
detail::is_integral_v<std::decay_t<T2>>,
int> = 0>
constexpr std::decay_t<T1> pow(T1 b, T2 e) {
if (is_zero(e)) {
return 1u;
}

T1 res = 1u;

while (true) {
bool lsb = bit_test(e, 0u);
e >>= 1u;
if (lsb) {
res *= b;
if (is_zero(e)) {
break;
}
}
b *= b;
}

return res;
}
} // namespace nil::crypto3::multiprecision
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,22 @@

// IWYU pragma: private; include "nil/crypto3/multiprecision/big_uint.hpp"

#include <cstddef>
#include <type_traits>

#include "nil/crypto3/multiprecision/detail/big_mod/big_mod_impl.hpp"
#include "nil/crypto3/multiprecision/detail/big_mod/ops/pow.hpp"
#include "nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp"

namespace nil::crypto3::multiprecision {
template<typename T1, std::size_t Bits, typename T2,
template<typename T1, typename T2, typename T3,
std::enable_if_t<detail::is_integral_v<std::decay_t<T1>> &&
detail::is_integral_v<std::decay_t<T2>>,
detail::is_integral_v<std::decay_t<T2>> &&
detail::is_integral_v<std::decay_t<T3>>,
int> = 0>
constexpr big_uint<Bits> powm(T1 &&b, T2 &&e, const big_uint<Bits> &m) {
return pow(big_mod_rt<Bits>(std::forward<T1>(b), m), std::forward<T2>(e)).base();
constexpr std::decay_t<T3> powm(T1 &&b, T2 &&e, T3 &&m) {
using big_mod_t = big_mod_rt<
std::decay_t<decltype(detail::as_big_uint(detail::unsigned_or_throw(m)))>::Bits>;
return static_cast<std::decay_t<T3>>(
pow(big_mod_t(std::forward<T1>(b), std::forward<T3>(m)), std::forward<T2>(e)).base());
}
} // namespace nil::crypto3::multiprecision
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,27 @@ namespace nil::crypto3::multiprecision {
return detail::as_big_uint(detail::unsigned_or_throw(a)).bit_test(index);
}

template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
constexpr T &bit_set(T &a, std::size_t index) {
// TODO(ioxid): optimize
a = detail::as_big_uint(detail::unsigned_or_throw(a)).bit_set(index);
return a;
}

template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
constexpr T &bit_unset(T &a, std::size_t index) {
// TODO(ioxid): optimize
a = detail::as_big_uint(detail::unsigned_or_throw(a)).bit_unset(index);
return a;
}

template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
constexpr T &bit_flip(T &a, std::size_t index) {
// TODO(ioxid): optimize
a = detail::as_big_uint(detail::unsigned_or_throw(a)).bit_flip(index);
return a;
}

template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
constexpr bool is_zero(T a) {
return a == 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2024 Andrey Nefedov <[email protected]>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//---------------------------------------------------------------------------//

#pragma once

#include "nil/crypto3/multiprecision/detail/big_uint/ops/pow.hpp" // IWYU pragma: export
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,5 @@

#pragma once

#include <limits>
#include <type_traits>

#include "nil/crypto3/multiprecision/detail/big_uint/ops/powm.hpp"

namespace nil::crypto3::multiprecision {
template<typename T1, typename T2, typename T3,
std::enable_if_t<std::numeric_limits<std::decay_t<T1>>::is_integer &&
std::numeric_limits<std::decay_t<T2>>::is_integer &&
std::is_integral_v<T3>,
int> = 0>
constexpr T3 powm(T1 &&b, T2 &&e, T3 m) {
// TODO(ioxid): optimize
return static_cast<T3>(
nil::crypto3::multiprecision::powm(std::forward<T1>(b), std::forward<T2>(e),
detail::as_big_uint(detail::unsigned_or_throw(m))));
}
} // namespace nil::crypto3::multiprecision
// Reusing big_uint's implementation. TODO(ioxid): optimize for builtin types
#include "nil/crypto3/multiprecision/detail/big_uint/ops/powm.hpp" // IWYU pragma: export
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
#pragma once

#include "nil/crypto3/multiprecision/detail/integer_ops_base.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/integer_ops_pow.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/integer_ops_powm.hpp" // IWYU pragma: export
1 change: 1 addition & 0 deletions crypto3/libs/multiprecision/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ set(MULTIPRECISION_TESTS_NAMES
"big_mod_randomized"
"big_uint_comparison_randomized"
"big_uint"
"boost_arithmetic_test"
"inverse"
"jacobi"
"miller_rabin"
Expand Down
44 changes: 42 additions & 2 deletions crypto3/libs/multiprecision/test/big_uint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,35 @@ using int_types = std::tuple<std::int8_t, std::int16_t, std::int32_t, std::int64
std::uint8_t, std::uint16_t, std::uint32_t, uint64_t, //
big_uint<7>>;

using unsigned_builtin_types =
std::tuple<std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t>;

using signed_types = std::tuple<std::int8_t, std::int16_t, std::int32_t, std::int64_t>;

BOOST_AUTO_TEST_SUITE(assignment)

BOOST_AUTO_TEST_CASE_TEMPLATE(assignment_signed, T, signed_types) {
BOOST_CHECK_EQUAL(big_uint<7>(static_cast<T>(2)), 2_big_uint7);
BOOST_CHECK_THROW(big_uint<7>(static_cast<T>(-1)), std::range_error);
BOOST_CHECK_THROW(big_uint<7>(static_cast<T>(128)), std::range_error);
BOOST_CHECK_THROW(big_uint<7>(static_cast<T>(129)), std::range_error);
big_uint<7> n;
BOOST_CHECK_EQUAL(n = static_cast<T>(2), 2_big_uint7);
BOOST_CHECK_THROW(n = static_cast<T>(-1), std::range_error);
BOOST_CHECK_THROW(n = static_cast<T>(128), std::range_error);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(assignment_unsigned, T, unsigned_builtin_types) {
BOOST_CHECK_EQUAL(big_uint<7>(static_cast<T>(2)), 2_big_uint7);
BOOST_CHECK_THROW(big_uint<7>(static_cast<T>(128)), std::range_error);
BOOST_CHECK_THROW(big_uint<7>(static_cast<T>(129)), std::range_error);
big_uint<7> n;
BOOST_CHECK_EQUAL(n = static_cast<T>(2), 2_big_uint7);
BOOST_CHECK_THROW(n = static_cast<T>(128), std::range_error);
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE(checked_operations)

BOOST_AUTO_TEST_CASE_TEMPLATE(addition_positive, T, int_types) {
Expand Down Expand Up @@ -387,6 +414,12 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(multiplication_negative, T, signed_types) {

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_CASE(add_assign_with_carry_test) {
auto n = 122_big_uint7;
BOOST_CHECK_EQUAL(add_assign_with_carry(n, 4_big_uint7), false);
BOOST_CHECK_EQUAL(add_assign_with_carry(n, 4_big_uint7), true);
}

BOOST_AUTO_TEST_SUITE(bit_operations)

BOOST_AUTO_TEST_CASE_TEMPLATE(and_positive, T, int_types) {
Expand Down Expand Up @@ -430,7 +463,7 @@ BOOST_AUTO_TEST_CASE(shift_left) {
BOOST_CHECK_EQUAL(21_big_uint7 << 5, 32_big_uint7);
BOOST_CHECK_EQUAL(21_big_uint7 << 7, 0_big_uint7);
BOOST_CHECK_EQUAL(21_big_uint7 << 0, 21_big_uint7);
BOOST_CHECK_EQUAL(21_big_uint7 << -1, 0_big_uint7);
BOOST_CHECK_THROW(21_big_uint7 << -1, std::range_error);
}

BOOST_AUTO_TEST_CASE(shift_right) {
Expand All @@ -439,7 +472,7 @@ BOOST_AUTO_TEST_CASE(shift_right) {
BOOST_CHECK_EQUAL(21_big_uint7 >> 5, 0_big_uint7);
BOOST_CHECK_EQUAL(21_big_uint7 >> 7, 0_big_uint7);
BOOST_CHECK_EQUAL(21_big_uint7 >> 0, 21_big_uint7);
BOOST_CHECK_EQUAL(21_big_uint7 >> -1, 0_big_uint7);
BOOST_CHECK_THROW(21_big_uint7 >> -1, std::range_error);
}

BOOST_AUTO_TEST_CASE(bit_set) {
Expand Down Expand Up @@ -492,3 +525,10 @@ BOOST_AUTO_TEST_CASE(lsb) {
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_CASE(powm_test) {
BOOST_CHECK_EQUAL(powm(2_big_uint7, 4_big_uint7, 5_big_uint7), 1_big_uint7);
BOOST_CHECK_EQUAL(powm(2_big_uint7, 4_big_uint7, 5), 1);
BOOST_CHECK_EQUAL(powm(2_big_uint7, 4, 5_big_uint7), 1_big_uint7);
BOOST_CHECK_EQUAL(powm(2, 4, 5), 1);
}
Loading

0 comments on commit b8adb34

Please sign in to comment.