Skip to content

Commit 92c7179

Browse files
committed
multiprecision: make goldilocks operations constexpr
1 parent b1f0ccf commit 92c7179

File tree

7 files changed

+132
-202
lines changed

7 files changed

+132
-202
lines changed

crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_mod.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ namespace nil::crypto3::multiprecision {
170170

171171
private:
172172
template<typename S, std::enable_if_t<is_integral_v<S>, int> = 0>
173-
static base_type convert_to_raw_base(const S& s, const modular_ops_t& ops) {
173+
static constexpr base_type convert_to_raw_base(const S& s, const modular_ops_t& ops) {
174174
if (nil::crypto3::multiprecision::is_zero(s)) {
175175
return base_type{};
176176
}

crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/big_uint.hpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,16 +1425,10 @@ namespace nil::crypto3::multiprecision {
14251425
template<std::size_t Bits1>
14261426
friend class big_uint;
14271427

1428-
template<std::size_t Bits1, std::size_t Bits2, std::size_t Bits3>
1429-
friend constexpr bool detail::add_unsigned_constexpr(
1430-
big_uint<Bits1>& result, const big_uint<Bits2>& a,
1431-
const big_uint<Bits3>& b) noexcept;
1432-
#ifdef NIL_CO3_MP_HAS_INTRINSICS
14331428
template<std::size_t Bits1, std::size_t Bits2, std::size_t Bits3>
14341429
friend constexpr bool detail::add_unsigned_intrinsic(
14351430
big_uint<Bits1>& result, const big_uint<Bits2>& a,
14361431
const big_uint<Bits3>& b) noexcept;
1437-
#endif
14381432
template<detail::overflow_policy OverflowPolicy, std::size_t Bits1,
14391433
std::size_t Bits2, std::size_t Bits3>
14401434
friend constexpr bool detail::add_unsigned(big_uint<Bits1>& result,
@@ -1445,16 +1439,10 @@ namespace nil::crypto3::multiprecision {
14451439
friend constexpr bool detail::add_unsigned(big_uint<Bits1>& result,
14461440
const big_uint<Bits2>& a,
14471441
const limb_type& o);
1448-
template<detail::overflow_policy OverflowPolicy, std::size_t Bits1,
1449-
std::size_t Bits2, std::size_t Bits3>
1450-
friend constexpr void detail::subtract_unsigned_constexpr(
1451-
big_uint<Bits1>& result, const big_uint<Bits2>& a, const big_uint<Bits3>& b);
1452-
#ifdef NIL_CO3_MP_HAS_INTRINSICS
14531442
template<detail::overflow_policy OverflowPolicy, std::size_t Bits1,
14541443
std::size_t Bits2, std::size_t Bits3>
14551444
friend constexpr void detail::subtract_unsigned_intrinsic(
14561445
big_uint<Bits1>& result, const big_uint<Bits2>& a, const big_uint<Bits3>& b);
1457-
#endif
14581446
template<detail::overflow_policy OverflowPolicy, bool GuaranteedGreater,
14591447
std::size_t Bits1, std::size_t Bits2, std::size_t Bits3>
14601448
friend constexpr void detail::subtract_unsigned(big_uint<Bits1>& result,
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//---------------------------------------------------------------------------//
2+
// Copyright (c) 2020 Madhur Chauhan
3+
// Copyright (c) 2020 John Maddock
4+
// Copyright (c) 2024 Andrey Nefedov <[email protected]>
5+
//
6+
// Distributed under the Boost Software License, Version 1.0
7+
// See accompanying file LICENSE_1_0.txt or copy at
8+
// http://www.boost.org/LICENSE_1_0.txt
9+
//---------------------------------------------------------------------------//
10+
11+
#pragma once
12+
13+
#include <climits>
14+
#include <cstdint>
15+
#include <type_traits>
16+
#include "nil/crypto3/multiprecision/detail/force_inline.hpp"
17+
#include "nil/crypto3/multiprecision/detail/intel_intrinsics.hpp"
18+
19+
namespace nil::crypto3::multiprecision::detail {
20+
template<typename T, std::enable_if_t<std::is_unsigned_v<T>, int> = 0>
21+
constexpr std::uint8_t addcarry_constexpr(std::uint8_t carry, T a, T b, T* p_result) {
22+
T r = a + b + carry;
23+
*p_result = r;
24+
return r < a || (r == a && carry);
25+
}
26+
27+
template<typename T, std::enable_if_t<std::is_unsigned_v<T>, int> = 0>
28+
constexpr std::uint8_t subborrow_constexpr(std::uint8_t borrow, T a, T b,
29+
T* p_result) {
30+
T r = a - b - borrow;
31+
*p_result = r;
32+
return r > a || (r == a && borrow);
33+
}
34+
} // namespace nil::crypto3::multiprecision::detail
35+
36+
#ifdef NIL_CO3_MP_HAS_INTRINSICS
37+
38+
namespace nil::crypto3::multiprecision::detail {
39+
static_assert(std::is_same_v<std::uint8_t, unsigned char>);
40+
41+
template<typename T, std::enable_if_t<std::is_unsigned_v<T>, int> = 0>
42+
NIL_CO3_MP_FORCEINLINE constexpr std::uint8_t addcarry(std::uint8_t carry, T a, T b,
43+
T* p_result) {
44+
if (!std::is_constant_evaluated()) {
45+
if constexpr (sizeof(T) * CHAR_BIT == 64) {
46+
return _addcarry_u64(carry, a, b,
47+
reinterpret_cast<unsigned long long*>(p_result));
48+
} else if constexpr (sizeof(T) * CHAR_BIT == 32) {
49+
return _addcarry_u32(carry, a, b,
50+
reinterpret_cast<unsigned int*>(p_result));
51+
} else {
52+
return addcarry_constexpr(carry, a, b, p_result);
53+
}
54+
}
55+
return addcarry_constexpr(carry, a, b, p_result);
56+
}
57+
58+
template<typename T, std::enable_if_t<std::is_unsigned_v<T>, int> = 0>
59+
NIL_CO3_MP_FORCEINLINE constexpr std::uint8_t subborrow(std::uint8_t borrow, T a, T b,
60+
T* p_result) {
61+
if (!std::is_constant_evaluated()) {
62+
if constexpr (sizeof(T) * CHAR_BIT == 64) {
63+
return _subborrow_u64(borrow, a, b,
64+
reinterpret_cast<unsigned long long*>(p_result));
65+
} else if constexpr (sizeof(T) * CHAR_BIT == 32) {
66+
return _subborrow_u32(borrow, a, b,
67+
reinterpret_cast<unsigned int*>(p_result));
68+
} else {
69+
return subborrow_constexpr(borrow, a, b, p_result);
70+
}
71+
}
72+
return subborrow_constexpr(borrow, a, b, p_result);
73+
}
74+
} // namespace nil::crypto3::multiprecision::detail
75+
76+
#else
77+
78+
#ifndef NIL_CO3_MP_DISABLE_INTRINSICS
79+
#warning "x86 intrinsics are not available, addcarry and subborrow optimizations disabled"
80+
#endif
81+
82+
namespace nil::crypto3::multiprecision::detail {
83+
template<typename T, std::enable_if_t<std::is_unsigned_v<T>, int> = 0>
84+
NIL_CO3_MP_FORCEINLINE constexpr std::uint8_t addcarry(std::uint8_t carry, T a, T b,
85+
T* p_result) {
86+
return addcarry_constexpr(carry, a, b, p_result);
87+
}
88+
89+
template<typename T, std::enable_if_t<std::is_unsigned_v<T>, int> = 0>
90+
NIL_CO3_MP_FORCEINLINE constexpr std::uint8_t subborrow(std::uint8_t borrow, T a, T b,
91+
T* p_result) {
92+
return subborrow_constexpr(borrow, a, b, p_result);
93+
}
94+
} // namespace nil::crypto3::multiprecision::detail
95+
96+
#endif

crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/big_mod/modular_ops/goldilocks.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@
1515

1616
#include <boost/assert.hpp>
1717

18+
#include "nil/crypto3/multiprecision/detail/addcarry_subborrow.hpp"
1819
#include "nil/crypto3/multiprecision/detail/big_mod/modular_ops/common.hpp"
1920
#include "nil/crypto3/multiprecision/detail/int128.hpp"
20-
#include "nil/crypto3/multiprecision/detail/intel_intrinsics.hpp"
2121

22-
#if !(defined(NIL_CO3_MP_HAS_INTRINSICS) && defined(NIL_CO3_MP_HAS_INT128))
22+
#if !defined(NIL_CO3_MP_HAS_INT128)
2323
#include "nil/crypto3/multiprecision/detail/big_mod/modular_ops/montgomery.hpp"
2424
#endif
2525

2626
namespace nil::crypto3::multiprecision {
2727
inline constexpr std::uint64_t goldilocks_modulus = 0xffffffff00000001ULL;
2828

2929
namespace detail {
30-
#if defined(NIL_CO3_MP_HAS_INTRINSICS) && defined(NIL_CO3_MP_HAS_INT128)
30+
#if defined(NIL_CO3_MP_HAS_INT128)
3131
class goldilocks_modular_ops : public common_modular_ops<std::uint64_t> {
3232
public:
3333
using base_type = std::uint64_t;
@@ -50,6 +50,7 @@ namespace nil::crypto3::multiprecision {
5050
BOOST_ASSERT(result < goldilocks_modulus);
5151
}
5252

53+
private:
5354
static constexpr base_type reduce128(const detail::uint128_t &input) {
5455
/*
5556
@@ -74,13 +75,13 @@ Goldilocks::new(t2)
7475
std::uint64_t x_hi_lo = x_hi & NEG_ORDER;
7576

7677
std::uint64_t t0 = 0u;
77-
std::uint8_t borrow = subborrow_limb(0, x_lo, x_hi_hi, &t0);
78+
std::uint8_t borrow = subborrow(0, x_lo, x_hi_hi, &t0);
7879
if (borrow) {
7980
t0 -= NEG_ORDER;
8081
}
8182
std::uint64_t t1 = x_hi_lo * NEG_ORDER;
8283
std::uint64_t t2 = 0;
83-
std::uint8_t carry = addcarry_limb(0, t0, t1, &t2);
84+
std::uint8_t carry = addcarry(0, t0, t1, &t2);
8485
std::uint64_t result = t2 + NEG_ORDER * carry;
8586
// TODO(ioxid): store noncanonical and remove this canonicalization
8687
if (result >= goldilocks_modulus) {
@@ -89,6 +90,7 @@ Goldilocks::new(t2)
8990
return result;
9091
}
9192

93+
public:
9294
static constexpr void mul(base_type &result, const base_type &y) {
9395
BOOST_ASSERT(result < goldilocks_modulus && y < goldilocks_modulus);
9496
detail::uint128_t prod = static_cast<detail::uint128_t>(result) *

0 commit comments

Comments
 (0)