Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
evaluation_domain.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Nishat], commit: 94f596f8b3bbbc216f9ad7dc33253256141156b2 }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
14#include <memory.h>
15#include <memory>
16
17namespace bb {
18
19namespace {
20constexpr size_t MIN_GROUP_PER_THREAD = 4;
21
22size_t compute_num_threads(const size_t size)
23{
24 size_t num_threads = get_num_cpus_pow2();
25 if (size <= (num_threads * MIN_GROUP_PER_THREAD)) {
26 num_threads = 1;
27 }
28
29 return num_threads;
30}
31
32template <typename Fr>
33void compute_lookup_table_single(const Fr& input_root,
34 const size_t size,
35 Fr* const roots,
36 std::vector<Fr*>& round_roots)
37{
38 // num_rounds = 0 results in underflow in the loop below, so we require num_rounds >= 1, which is equivalent to size
39 // >= 2.
40 BB_ASSERT(size >= 2);
41 const size_t num_rounds = static_cast<size_t>(numeric::get_msb(size));
42
43 round_roots.reserve(num_rounds - 1);
44 round_roots.emplace_back(&roots[0]);
45 for (size_t i = 1; i < num_rounds - 1; ++i) {
46 round_roots.emplace_back(round_roots.back() + (1UL << i));
47 }
48
49 for (size_t i = 0; i < num_rounds - 1; ++i) {
50 const size_t m = 1UL << (i + 1);
51 const Fr round_root = input_root.pow(static_cast<uint64_t>(size / (2 * m)));
52 Fr* const current_round_roots = round_roots[i];
53 current_round_roots[0] = Fr::one();
54 for (size_t j = 1; j < m; ++j) {
55 current_round_roots[j] = current_round_roots[j - 1] * round_root;
56 }
57 }
58}
59} // namespace
60
61template <typename Fr>
62EvaluationDomain<Fr>::EvaluationDomain(const size_t domain_size, const size_t target_generator_size)
63 : size(domain_size)
64 , num_threads(compute_num_threads(domain_size))
65 , thread_size(domain_size / num_threads)
66 , log2_size(static_cast<size_t>(numeric::get_msb(size)))
67 , log2_thread_size(static_cast<size_t>(numeric::get_msb(thread_size)))
68 , log2_num_threads(static_cast<size_t>(numeric::get_msb(num_threads)))
69 , generator_size(target_generator_size ? target_generator_size : domain_size)
70 , domain(Fr{ size, 0, 0, 0 }.to_montgomery_form())
71 , domain_inverse(domain.invert())
72 , generator(Fr::coset_generator())
73 , generator_inverse(Fr::coset_generator().invert())
74 , roots(nullptr)
75{
76 // Grumpkin does not have many roots of unity and, given these are not used for Honk, we set it to one.
78 root = Fr::one();
79 } else {
81 }
82
84
85 BB_ASSERT((1UL << log2_size) == size || (size == 0));
86 BB_ASSERT((1UL << log2_thread_size) == thread_size || (size == 0));
87 BB_ASSERT((1UL << log2_num_threads) == num_threads || (size == 0));
88}
89
91{
92 // Prevent self-corruption of data
93 if (this == &other) {
94 return *this;
95 }
96 // Steal-and-zero the source's invariant-gating scalar fields. All validity checks on an
97 // EvaluationDomain gate on `size > 0`, so zeroing it on move makes the source visibly empty
98 // (matching the default-constructed state) rather than partially valid (size > 0 but
99 // roots == nullptr).
100 size = std::exchange(other.size, 0);
101 generator_size = std::exchange(other.generator_size, 0);
102 num_threads = std::exchange(other.num_threads, 0);
103 thread_size = std::exchange(other.thread_size, 0);
104 log2_size = std::exchange(other.log2_size, 0);
105 log2_thread_size = std::exchange(other.log2_thread_size, 0);
106 log2_num_threads = std::exchange(other.log2_num_threads, 0);
107 Fr::__copy(other.root, root);
108 Fr::__copy(other.root_inverse, root_inverse);
109 Fr::__copy(other.domain, domain);
110 Fr::__copy(other.domain_inverse, domain_inverse);
111 Fr::__copy(other.generator, generator);
112 Fr::__copy(other.generator_inverse, generator_inverse);
113 roots = std::move(other.roots);
114 round_roots = std::move(other.round_roots);
115 inverse_round_roots = std::move(other.inverse_round_roots);
116 other.roots = nullptr;
117 return *this;
118}
119
121
123{
124 BB_ASSERT_EQ(roots, nullptr);
125 roots = std::make_shared<Fr[]>(size * 2);
126 compute_lookup_table_single(root, size, roots.get(), round_roots);
127 compute_lookup_table_single(root_inverse, size, &roots.get()[size], inverse_round_roots);
128}
129
130// explicitly instantiate both EvaluationDomain
131template class EvaluationDomain<bb::fr>;
132template class EvaluationDomain<grumpkin::fr>;
133
134} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
EvaluationDomain & operator=(const EvaluationDomain &)=delete
constexpr T get_msb(const T in)
Definition get_msb.hpp:50
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
size_t get_num_cpus_pow2()
Definition thread.hpp:25
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr field get_root_of_unity(size_t subgroup_size) noexcept
static constexpr field one()
BB_INLINE constexpr field pow(const uint256_t &exponent) const noexcept
constexpr field invert() const noexcept
static BB_INLINE void __copy(const field &a, field &r) noexcept