Skip to content

Commit b0a937b

Browse files
author
dbanks12
committed
Merge branch 'master' into db/enforce-class-registered
2 parents 629796e + 61c3e95 commit b0a937b

File tree

305 files changed

+6896
-4505
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

305 files changed

+6896
-4505
lines changed

barretenberg/.gitrepo

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[subrepo]
77
remote = https://github.com/AztecProtocol/barretenberg
88
branch = master
9-
commit = e66e46848abe6b5b192eed7b23a7d2522b5bb096
10-
parent = cd5a615f154446878cb8681d70b9e55c14511690
9+
commit = 560058aa5ec26a23436f09d89a8b80633fbee785
10+
parent = 36b640aed54fd4da0f9899300bf7b0d05faf5b8d
1111
method = merge
1212
cmdver = 0.4.6

barretenberg/cpp/src/barretenberg/common/thread.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,22 @@ void parallel_for_heuristic(size_t num_points,
170170
});
171171
};
172172

173+
MultithreadData calculate_thread_data(size_t num_iterations, size_t min_iterations_per_thread)
174+
{
175+
size_t num_threads = calculate_num_threads(num_iterations, min_iterations_per_thread);
176+
const size_t thread_size = num_iterations / num_threads;
177+
178+
// Cumpute the index bounds for each thread
179+
std::vector<size_t> start(num_threads);
180+
std::vector<size_t> end(num_threads);
181+
for (size_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
182+
start[thread_idx] = thread_idx * thread_size;
183+
end[thread_idx] = (thread_idx == num_threads - 1) ? num_iterations : (thread_idx + 1) * thread_size;
184+
}
185+
186+
return MultithreadData{ num_threads, start, end };
187+
}
188+
173189
/**
174190
* @brief calculates number of threads to create based on minimum iterations per thread
175191
* @details Finds the number of cpus with get_num_cpus(), and calculates `desired_num_threads`

barretenberg/cpp/src/barretenberg/common/thread.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,24 @@ std::vector<Accum> parallel_for_heuristic(size_t num_points,
8888

8989
const size_t DEFAULT_MIN_ITERS_PER_THREAD = 1 << 4;
9090

91+
struct MultithreadData {
92+
size_t num_threads;
93+
// index bounds for each thread
94+
std::vector<size_t> start;
95+
std::vector<size_t> end;
96+
};
97+
98+
/**
99+
* @brief Calculates number of threads and index bounds for each thread
100+
* @details Finds the number of cpus with calculate_num_threads() then divides domain evenly amongst threads
101+
*
102+
* @param num_iterations
103+
* @param min_iterations_per_thread
104+
* @return size_t
105+
*/
106+
MultithreadData calculate_thread_data(size_t num_iterations,
107+
size_t min_iterations_per_thread = DEFAULT_MIN_ITERS_PER_THREAD);
108+
91109
/**
92110
* @brief calculates number of threads to create based on minimum iterations per thread
93111
* @details Finds the number of cpus with get_num_cpus(), and calculates `desired_num_threads`

barretenberg/cpp/src/barretenberg/flavor/flavor.hpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,29 @@ class PrecomputedEntitiesBase {
9898
uint64_t log_circuit_size;
9999
uint64_t num_public_inputs;
100100
};
101+
// Specifies the regions of the execution trace containing non-trivial wire values
102+
struct ActiveRegionData {
103+
void add_range(const size_t start, const size_t end)
104+
{
105+
ASSERT(start >= current_end); // ranges should be non-overlapping and increasing
106+
ranges.emplace_back(start, end);
107+
for (size_t i = start; i < end; ++i) {
108+
idxs.push_back(i);
109+
}
110+
current_end = end;
111+
}
112+
113+
std::vector<std::pair<size_t, size_t>> get_ranges() const { return ranges; }
114+
size_t get_idx(const size_t idx) const { return idxs[idx]; }
115+
std::pair<size_t, size_t> get_range(const size_t idx) const { return ranges.at(idx); }
116+
size_t size() const { return idxs.size(); }
117+
size_t num_ranges() const { return ranges.size(); }
118+
119+
private:
120+
std::vector<std::pair<size_t, size_t>> ranges; // active ranges [start_i, end_i) of the execution trace
121+
std::vector<size_t> idxs; // full set of poly indices corresposponding to active ranges
122+
size_t current_end{ 0 }; // end of last range; for ensuring monotonicity of ranges
123+
};
101124

102125
/**
103126
* @brief Base proving key class.
@@ -123,8 +146,7 @@ template <typename FF, typename CommitmentKey_> class ProvingKey_ {
123146
// folded element by element.
124147
std::vector<FF> public_inputs;
125148

126-
// Ranges of the form [start, end) where witnesses have non-zero values (hence the execution trace is "active")
127-
std::vector<std::pair<size_t, size_t>> active_block_ranges;
149+
ActiveRegionData active_region_data; // specifies active regions of execution trace
128150

129151
ProvingKey_() = default;
130152
ProvingKey_(const size_t dyadic_circuit_size,

barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ class GoblinMockCircuits {
191191
static void construct_simple_circuit(MegaBuilder& builder)
192192
{
193193
PROFILE_THIS();
194-
195194
add_some_ecc_op_gates(builder);
196195
MockCircuits::construct_arithmetic_circuit(builder);
197196
}

barretenberg/cpp/src/barretenberg/plonk_honk_shared/composer/permutation_lib.hpp

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -224,33 +224,43 @@ void compute_honk_style_permutation_lagrange_polynomials_from_mapping(
224224
using FF = typename Flavor::FF;
225225
const size_t num_gates = proving_key->circuit_size;
226226

227+
size_t domain_size = proving_key->active_region_data.size();
228+
229+
const MultithreadData thread_data = calculate_thread_data(domain_size);
230+
227231
size_t wire_idx = 0;
228232
for (auto& current_permutation_poly : permutation_polynomials) {
229-
ITERATE_OVER_DOMAIN_START(proving_key->evaluation_domain);
230-
auto idx = static_cast<ptrdiff_t>(i);
231-
const auto& current_row_idx = permutation_mappings[wire_idx].row_idx[idx];
232-
const auto& current_col_idx = permutation_mappings[wire_idx].col_idx[idx];
233-
const auto& current_is_tag = permutation_mappings[wire_idx].is_tag[idx];
234-
const auto& current_is_public_input = permutation_mappings[wire_idx].is_public_input[idx];
235-
if (current_is_public_input) {
236-
// We intentionally want to break the cycles of the public input variables.
237-
// During the witness generation, the left and right wire polynomials at idx i contain the i-th public
238-
// input. The CyclicPermutation created for these variables always start with (i) -> (n+i), followed by
239-
// the indices of the variables in the "real" gates. We make i point to -(i+1), so that the only way of
240-
// repairing the cycle is add the mapping
241-
// -(i+1) -> (n+i)
242-
// These indices are chosen so they can easily be computed by the verifier. They can expect the running
243-
// product to be equal to the "public input delta" that is computed in <honk/utils/grand_product_delta.hpp>
244-
current_permutation_poly.at(i) = -FF(current_row_idx + 1 + num_gates * current_col_idx);
245-
} else if (current_is_tag) {
246-
// Set evaluations to (arbitrary) values disjoint from non-tag values
247-
current_permutation_poly.at(i) = num_gates * Flavor::NUM_WIRES + current_row_idx;
248-
} else {
249-
// For the regular permutation we simply point to the next location by setting the evaluation to its
250-
// idx
251-
current_permutation_poly.at(i) = FF(current_row_idx + num_gates * current_col_idx);
252-
}
253-
ITERATE_OVER_DOMAIN_END;
233+
parallel_for(thread_data.num_threads, [&](size_t j) {
234+
const size_t start = thread_data.start[j];
235+
const size_t end = thread_data.end[j];
236+
for (size_t i = start; i < end; ++i) {
237+
const size_t poly_idx = proving_key->active_region_data.get_idx(i);
238+
const auto idx = static_cast<ptrdiff_t>(poly_idx);
239+
const auto& current_row_idx = permutation_mappings[wire_idx].row_idx[idx];
240+
const auto& current_col_idx = permutation_mappings[wire_idx].col_idx[idx];
241+
const auto& current_is_tag = permutation_mappings[wire_idx].is_tag[idx];
242+
const auto& current_is_public_input = permutation_mappings[wire_idx].is_public_input[idx];
243+
if (current_is_public_input) {
244+
// We intentionally want to break the cycles of the public input variables.
245+
// During the witness generation, the left and right wire polynomials at idx i contain the i-th
246+
// public input. The CyclicPermutation created for these variables always start with (i) -> (n+i),
247+
// followed by the indices of the variables in the "real" gates. We make i point to
248+
// -(i+1), so that the only way of repairing the cycle is add the mapping
249+
// -(i+1) -> (n+i)
250+
// These indices are chosen so they can easily be computed by the verifier. They can expect
251+
// the running product to be equal to the "public input delta" that is computed
252+
// in <honk/utils/grand_product_delta.hpp>
253+
current_permutation_poly.at(poly_idx) = -FF(current_row_idx + 1 + num_gates * current_col_idx);
254+
} else if (current_is_tag) {
255+
// Set evaluations to (arbitrary) values disjoint from non-tag values
256+
current_permutation_poly.at(poly_idx) = num_gates * Flavor::NUM_WIRES + current_row_idx;
257+
} else {
258+
// For the regular permutation we simply point to the next location by setting the
259+
// evaluation to its idx
260+
current_permutation_poly.at(poly_idx) = FF(current_row_idx + num_gates * current_col_idx);
261+
}
262+
}
263+
});
254264
wire_idx++;
255265
}
256266
}

barretenberg/cpp/src/barretenberg/plonk_honk_shared/library/grand_product_library.hpp

Lines changed: 75 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
#include "barretenberg/common/debug_log.hpp"
44
#include "barretenberg/common/thread.hpp"
55
#include "barretenberg/common/zip_view.hpp"
6+
#include "barretenberg/flavor/flavor.hpp"
67
#include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp"
78
#include "barretenberg/relations/relation_parameters.hpp"
9+
#include "barretenberg/trace_to_polynomials/trace_to_polynomials.hpp"
810
#include <typeinfo>
911

1012
namespace bb {
@@ -47,74 +49,68 @@ namespace bb {
4749
*
4850
* Note: Step (3) utilizes Montgomery batch inversion to replace n-many inversions with
4951
*
52+
* @note This method makes use of the fact that there are at most as many unique entries in the grand product as active
53+
* rows in the execution trace to efficiently compute the grand product when a structured trace is in use. I.e. the
54+
* computation peformed herein is proportional to the number of active rows in the trace and the constant values in the
55+
* inactive regions are simply populated from known values on the last step.
56+
*
5057
* @tparam Flavor
5158
* @tparam GrandProdRelation
5259
* @param full_polynomials
5360
* @param relation_parameters
5461
* @param size_override optional size of the domain; otherwise based on dyadic polynomial domain
62+
* @param active_region_data optional specification of active region of execution trace
5563
*/
5664
template <typename Flavor, typename GrandProdRelation>
5765
void compute_grand_product(typename Flavor::ProverPolynomials& full_polynomials,
5866
bb::RelationParameters<typename Flavor::FF>& relation_parameters,
5967
size_t size_override = 0,
60-
std::vector<std::pair<size_t, size_t>> active_block_ranges = {})
68+
const ActiveRegionData& active_region_data = ActiveRegionData{})
6169
{
6270
PROFILE_THIS_NAME("compute_grand_product");
6371

6472
using FF = typename Flavor::FF;
6573
using Polynomial = typename Flavor::Polynomial;
6674
using Accumulator = std::tuple_element_t<0, typename GrandProdRelation::SumcheckArrayOfValuesOverSubrelations>;
6775

76+
const bool has_active_ranges = active_region_data.size() > 0;
77+
6878
// Set the domain over which the grand product must be computed. This may be less than the dyadic circuit size, e.g
6979
// the permutation grand product does not need to be computed beyond the index of the last active wire
7080
size_t domain_size = size_override == 0 ? full_polynomials.get_polynomial_size() : size_override;
7181

72-
const size_t num_threads = domain_size >= get_num_cpus_pow2() ? get_num_cpus_pow2() : 1;
73-
const size_t block_size = domain_size / num_threads;
74-
const size_t final_idx = domain_size - 1;
75-
76-
// Cumpute the index bounds for each thread for reuse in the computations below
77-
std::vector<std::pair<size_t, size_t>> idx_bounds;
78-
idx_bounds.reserve(num_threads);
79-
for (size_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
80-
const size_t start = thread_idx * block_size;
81-
const size_t end = (thread_idx == num_threads - 1) ? final_idx : (thread_idx + 1) * block_size;
82-
idx_bounds.push_back(std::make_pair(start, end));
83-
}
82+
// Returns the ith active index if specified, otherwise acts as the identity map on the input
83+
auto get_active_range_poly_idx = [&](size_t i) { return has_active_ranges ? active_region_data.get_idx(i) : i; };
84+
85+
size_t active_domain_size = has_active_ranges ? active_region_data.size() : domain_size;
86+
87+
// The size of the iteration domain is one less than the number of active rows since the final value of the
88+
// grand product is constructed only in the relation and not explicitly in the polynomial
89+
const MultithreadData active_range_thread_data = calculate_thread_data(active_domain_size - 1);
8490

8591
// Allocate numerator/denominator polynomials that will serve as scratch space
8692
// TODO(zac) we can re-use the permutation polynomial as the numerator polynomial. Reduces readability
87-
Polynomial numerator{ domain_size, domain_size };
88-
Polynomial denominator{ domain_size, domain_size };
89-
90-
auto check_is_active = [&](size_t idx) {
91-
if (active_block_ranges.empty()) {
92-
return true;
93-
}
94-
return std::any_of(active_block_ranges.begin(), active_block_ranges.end(), [idx](const auto& range) {
95-
return idx >= range.first && idx < range.second;
96-
});
97-
};
93+
Polynomial numerator{ active_domain_size };
94+
Polynomial denominator{ active_domain_size };
9895

9996
// Step (1)
10097
// Populate `numerator` and `denominator` with the algebra described by Relation
101-
FF gamma_fourth = relation_parameters.gamma.pow(4);
102-
parallel_for(num_threads, [&](size_t thread_idx) {
98+
parallel_for(active_range_thread_data.num_threads, [&](size_t thread_idx) {
99+
const size_t start = active_range_thread_data.start[thread_idx];
100+
const size_t end = active_range_thread_data.end[thread_idx];
103101
typename Flavor::AllValues row;
104-
const size_t start = idx_bounds[thread_idx].first;
105-
const size_t end = idx_bounds[thread_idx].second;
106102
for (size_t i = start; i < end; ++i) {
107-
if (check_is_active(i)) {
108-
// TODO(https://github.com/AztecProtocol/barretenberg/issues/940):consider avoiding get_row if possible.
109-
row = full_polynomials.get_row(i);
110-
numerator.at(i) =
111-
GrandProdRelation::template compute_grand_product_numerator<Accumulator>(row, relation_parameters);
112-
denominator.at(i) = GrandProdRelation::template compute_grand_product_denominator<Accumulator>(
113-
row, relation_parameters);
103+
// TODO(https://github.com/AztecProtocol/barretenberg/issues/940):consider avoiding get_row if possible.
104+
auto row_idx = get_active_range_poly_idx(i);
105+
if constexpr (IsUltraFlavor<Flavor>) {
106+
row = full_polynomials.get_row_for_permutation_arg(row_idx);
114107
} else {
115-
numerator.at(i) = gamma_fourth;
116-
denominator.at(i) = gamma_fourth;
108+
row = full_polynomials.get_row(row_idx);
117109
}
110+
numerator.at(i) =
111+
GrandProdRelation::template compute_grand_product_numerator<Accumulator>(row, relation_parameters);
112+
denominator.at(i) =
113+
GrandProdRelation::template compute_grand_product_denominator<Accumulator>(row, relation_parameters);
118114
}
119115
});
120116

@@ -133,12 +129,12 @@ void compute_grand_product(typename Flavor::ProverPolynomials& full_polynomials,
133129
// (ii) Take partial products P = { 1, a0a1, a2a3, a4a5 }
134130
// (iii) Each thread j computes N[i][j]*P[j]=
135131
// {{a0,a0a1},{a0a1a2,a0a1a2a3},{a0a1a2a3a4,a0a1a2a3a4a5},{a0a1a2a3a4a5a6,a0a1a2a3a4a5a6a7}}
136-
std::vector<FF> partial_numerators(num_threads);
137-
std::vector<FF> partial_denominators(num_threads);
132+
std::vector<FF> partial_numerators(active_range_thread_data.num_threads);
133+
std::vector<FF> partial_denominators(active_range_thread_data.num_threads);
138134

139-
parallel_for(num_threads, [&](size_t thread_idx) {
140-
const size_t start = idx_bounds[thread_idx].first;
141-
const size_t end = idx_bounds[thread_idx].second;
135+
parallel_for(active_range_thread_data.num_threads, [&](size_t thread_idx) {
136+
const size_t start = active_range_thread_data.start[thread_idx];
137+
const size_t end = active_range_thread_data.end[thread_idx];
142138
for (size_t i = start; i < end - 1; ++i) {
143139
numerator.at(i + 1) *= numerator[i];
144140
denominator.at(i + 1) *= denominator[i];
@@ -150,9 +146,9 @@ void compute_grand_product(typename Flavor::ProverPolynomials& full_polynomials,
150146
DEBUG_LOG_ALL(partial_numerators);
151147
DEBUG_LOG_ALL(partial_denominators);
152148

153-
parallel_for(num_threads, [&](size_t thread_idx) {
154-
const size_t start = idx_bounds[thread_idx].first;
155-
const size_t end = idx_bounds[thread_idx].second;
149+
parallel_for(active_range_thread_data.num_threads, [&](size_t thread_idx) {
150+
const size_t start = active_range_thread_data.start[thread_idx];
151+
const size_t end = active_range_thread_data.end[thread_idx];
156152
if (thread_idx > 0) {
157153
FF numerator_scaling = 1;
158154
FF denominator_scaling = 1;
@@ -179,14 +175,44 @@ void compute_grand_product(typename Flavor::ProverPolynomials& full_polynomials,
179175
// We have a 'virtual' 0 at the start (as this is a to-be-shifted polynomial)
180176
ASSERT(grand_product_polynomial.start_index() == 1);
181177

182-
parallel_for(num_threads, [&](size_t thread_idx) {
183-
const size_t start = idx_bounds[thread_idx].first;
184-
const size_t end = idx_bounds[thread_idx].second;
178+
// For Ultra/Mega, the first row is an inactive zero row thus the grand prod takes value 1 at both i = 0 and i = 1
179+
if constexpr (IsUltraFlavor<Flavor>) {
180+
grand_product_polynomial.at(1) = 1;
181+
}
182+
183+
// Compute grand product values corresponding only to the active regions of the trace
184+
parallel_for(active_range_thread_data.num_threads, [&](size_t thread_idx) {
185+
const size_t start = active_range_thread_data.start[thread_idx];
186+
const size_t end = active_range_thread_data.end[thread_idx];
185187
for (size_t i = start; i < end; ++i) {
186-
grand_product_polynomial.at(i + 1) = numerator[i] * denominator[i];
188+
const auto poly_idx = get_active_range_poly_idx(i + 1);
189+
grand_product_polynomial.at(poly_idx) = numerator[i] * denominator[i];
187190
}
188191
});
189192

193+
// Final step: If active/inactive regions have been specified, the value of the grand product in the inactive
194+
// regions have not yet been set. The polynomial takes an already computed constant value across each inactive
195+
// region (since no copy constraints are present there) equal to the value of the grand product at the first index
196+
// of the subsequent active region.
197+
if (has_active_ranges) {
198+
MultithreadData full_domain_thread_data = calculate_thread_data(domain_size);
199+
parallel_for(full_domain_thread_data.num_threads, [&](size_t thread_idx) {
200+
const size_t start = full_domain_thread_data.start[thread_idx];
201+
const size_t end = full_domain_thread_data.end[thread_idx];
202+
for (size_t i = start; i < end; ++i) {
203+
for (size_t j = 0; j < active_region_data.num_ranges() - 1; ++j) {
204+
const size_t previous_range_end = active_region_data.get_range(j).second;
205+
const size_t next_range_start = active_region_data.get_range(j + 1).first;
206+
// Set the value of the polynomial if the index falls in an inactive region
207+
if (i >= previous_range_end && i < next_range_start) {
208+
grand_product_polynomial.at(i) = grand_product_polynomial[next_range_start];
209+
break;
210+
}
211+
}
212+
}
213+
});
214+
}
215+
190216
DEBUG_LOG_ALL(grand_product_polynomial.coeffs());
191217
}
192218

0 commit comments

Comments
 (0)