Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
gate_separator.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Khashayar], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
13
14#include <cstddef>
15#include <vector>
16namespace bb {
17
18template <typename FF> struct GateSeparatorPolynomial {
23 std::vector<FF> betas;
24
41 size_t periodicity = 2;
50
57 GateSeparatorPolynomial(const std::vector<FF>& betas, const size_t log_num_monomials)
58 : betas(betas)
59 , beta_products(compute_beta_products(betas, log_num_monomials))
60 {}
61
68 GateSeparatorPolynomial(const std::vector<FF>& betas)
69 : betas(betas)
70 {}
71
77 GateSeparatorPolynomial(const std::vector<FF>& betas, const std::vector<FF>& challenge)
78 : betas(betas)
79 {
80 if (!betas.empty()) {
81 for (const auto& u_k : challenge) {
83 }
84 }
85 }
86
93 FF const& operator[](size_t idx) const
94 {
95 // At round i, we only iterate over beta_products of indices that are multiples of 2^i,
96 // Hence for the idx-th element we need to get the (idx * 2^i)-th element in #beta_products.
97 return beta_products.at((idx >> 1) * periodicity);
98 }
105 {
106 if (betas.empty()) {
107 return FF(1);
108 };
110 }
111
115 FF univariate_eval(FF challenge) const { return (FF(1) + (challenge * (betas[current_element_idx] - FF(1)))); };
116
123 void partially_evaluate(FF challenge)
124 {
125 if (!betas.empty()) {
126 FF current_univariate_eval = univariate_eval(challenge);
127 partial_evaluation_result *= current_univariate_eval;
129 periodicity *= 2;
130 }
131 }
132
142 const size_t log_num_monomials,
143 const FF& scaling_factor = FF(1))
144 {
145 if (betas.empty()) {
146 Polynomial<FF> out(1);
147 return out;
148 }
149
150 BB_BENCH_NAME("GateSeparatorPolynomial::compute_beta_products");
151 size_t pow_size = static_cast<size_t>(1) << log_num_monomials;
153
154 // Explanations of the algorithm:
155 // The product of the betas at index i (beta_products[i]) contains the multiplicative factor betas[j] if and
156 // only if the jth bit of i is 1 (j starting with 0 for the least significant bit). For instance, i = 13 = 1101
157 // in binary, so the product is betas[0] * betas[2] * betas[3].
158 //
159 // Key insight: beta_products[i] = beta_products[predecessor] * betas[lsb_position], where predecessor is i
160 // with the least significant bit cleared. For example:
161 // - i = 6 (binary 110): LSB is at position 1, predecessor = 4 (binary 100)
162 // beta_products[6] = beta_products[4] * betas[1]
163 // - i = 12 (binary 1100): LSB is at position 2, predecessor = 8 (binary 1000)
164 // beta_products[12] = beta_products[8] * betas[2]
165 //
166 // For each index i, if the predecessor falls within our thread's range [start, start + chunk_size), we use
167 // this O(1) recurrence. Otherwise, we compute directly by iterating over all set bits in i, which requires
168 // O(popcount(i)) multiplications. This direct computation handles boundary cases between thread chunks.
169 //
170 // This algorithm works with any number of threads (not just powers of 2), unlike the previous prefix/suffix
171 // approach which required power-of-2 thread counts to ensure even work distribution.
172
173 // Cost per iteration: typically 1 multiplication (when predecessor is in range),
174 // occasionally O(popcount) multiplications at chunk boundaries
175 constexpr size_t iteration_cost = thread_heuristics::FF_MULTIPLICATION_COST;
177 pow_size,
178 [&](size_t start, size_t end, BB_UNUSED size_t chunk_index) {
179 BB_BENCH_TRACY_NAME("GateSeparator::beta_products/chunk");
180 for (size_t i = start; i < end; i++) {
181 if (i == 0) {
182 beta_products.at(0) = scaling_factor;
183 continue;
184 }
185
186 // Find the lowest set bit position and the predecessor index
187 size_t lsb_pos = numeric::get_lsb(i);
188 size_t predecessor = i ^ (static_cast<size_t>(1) << lsb_pos); // clear the lowest set bit
189
190 if (predecessor >= start) {
191 // Predecessor is in our range, O(1) computation
192 beta_products.at(i) = beta_products.at(predecessor) * betas[lsb_pos];
193 } else {
194 // Predecessor is not in our range, compute directly from set bits only
195 FF result = scaling_factor;
196 size_t remaining = i;
197 while (remaining != 0) {
198 size_t bit = numeric::get_lsb(remaining);
199 result *= betas[bit];
200 remaining ^= static_cast<size_t>(1) << bit; // clear this bit
201 }
202 beta_products.at(i) = result;
203 }
204 }
205 },
206 iteration_cost);
207
208 return beta_products;
209 }
210};
285} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
#define BB_BENCH_TRACY_NAME(name)
Definition bb_bench.hpp:256
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
#define BB_PROFILE
#define BB_UNUSED
constexpr T get_lsb(const T in)
Definition get_msb.hpp:71
constexpr size_t FF_MULTIPLICATION_COST
Definition thread.hpp:134
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void parallel_for_heuristic(size_t num_points, const std::function< void(size_t, size_t, size_t)> &func, size_t heuristic_cost)
Split a loop into several loops running in parallel based on operations in 1 iteration.
Definition thread.cpp:171
Implementation of the methods for the -polynomials used in in Sumcheck.
GateSeparatorPolynomial(const std::vector< FF > &betas)
Construct a new GateSeparatorPolynomial object without expanding to a vector of monomials.
size_t periodicity
In Round of Sumcheck, the periodicity equals to and represents the fixed interval at which elements...
GateSeparatorPolynomial(const std::vector< FF > &betas, const size_t log_num_monomials)
Construct a new GateSeparatorPolynomial.
std::vector< FF > betas
The challenges .
FF current_element() const
Computes the component at index current_element_idx in betas.
FF const & operator[](size_t idx) const
Retruns the element in beta_products at place #idx.
void partially_evaluate(FF challenge)
Partially evaluate the -polynomial at the new challenge and update .
FF univariate_eval(FF challenge) const
Evaluate at the challenge point .
GateSeparatorPolynomial(const std::vector< FF > &betas, const std::vector< FF > &challenge)
Constructs a virtual GateSeparator used by the prover in rounds k > d - 1, and computes its partial e...
FF partial_evaluation_result
The value obtained by partially evaluating one variable in the power polynomial at each round....
size_t current_element_idx
In Round of Sumcheck, it points to the -th element in .
Polynomial< FF > beta_products
The consecutive evaluations for identified with the integers .
static BB_PROFILE Polynomial< FF > compute_beta_products(const std::vector< FF > &betas, const size_t log_num_monomials, const FF &scaling_factor=FF(1))
Given compute for .