Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
trace_to_polynomials.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Completed, auditors: [Sergei], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
13
19namespace bb {
20
21template <class Flavor>
23{
24
25 BB_BENCH_NAME("trace populate");
26
27 auto copy_cycles = populate_wires_and_selectors_and_compute_copy_cycles(builder, polynomials);
28
29 if constexpr (IsMegaFlavor<Flavor>) {
30 BB_BENCH_NAME("add_ecc_op_wires_to_prover_instance");
31
32 add_ecc_op_wires_to_prover_instance(builder, polynomials);
33 }
34
35 // Compute the permutation argument polynomials (sigma/id) and add them to proving key
36 {
37 BB_BENCH_NAME("compute_permutation_argument_polynomials");
38
39 compute_permutation_argument_polynomials<Flavor>(builder, polynomials, copy_cycles);
40 }
41}
42
43template <class Flavor>
45 Builder& builder, ProverPolynomials& polynomials)
46{
47
48 BB_BENCH_NAME("construct_trace_data");
49
51 copy_cycles.resize(builder.get_num_variables()); // at most one copy cycle per variable
52
53 RefArray<Polynomial, NUM_WIRES> wires = polynomials.get_wires();
54 auto selectors = polynomials.get_selectors();
55
56 // Two-phase parallelisation. Phase 1 fans out over blocks to populate wires and emit copy-cycle
57 // nodes; phase 2 fans out over a flattened (block, selector) task list to fill selectors.
58 auto blocks_array = builder.blocks.get();
59 const size_t num_blocks = blocks_array.size();
60
61 // Pre-pass: count copy-cycle sizes per real-variable index so each copy_cycles[i] can be
62 // reserve()d once before the serial concat in phase 1.5, avoiding repeated reallocations.
63 {
64 BB_BENCH_NAME("counting copy_cycles");
65 std::vector<uint32_t> cycle_counts(builder.real_variable_index.size(), 0);
66 for (auto& block : blocks_array) {
67 const uint32_t block_size = static_cast<uint32_t>(block.size());
68 for (uint32_t block_row_idx = 0; block_row_idx < block_size; ++block_row_idx) {
69 for (uint32_t wire_idx = 0; wire_idx < NUM_WIRES; ++wire_idx) {
70 uint32_t var_idx = block.wires[wire_idx][block_row_idx];
71 // var_idx may be untrusted (e.g. from ACIR) so use .at() to catch OOB. This validates real_var_idx
72 // as an in-range index for both cycle_counts and copy_cycles (same size), which is why phase 1.5
73 // below can index copy_cycles[real_var_idx] without .at().
74 ++cycle_counts.at(builder.real_variable_index.at(var_idx));
75 }
76 }
77 }
78 for (size_t i = 0; i < copy_cycles.size(); ++i) {
79 copy_cycles[i].reserve(cycle_counts[i]);
80 }
81 }
82
83 // Phase 1: per-block parallel pass over wires and emit copy-cycle nodes.
85 {
86 BB_BENCH_NAME("populate_wires_and_emit_cycles");
87 parallel_for(num_blocks, [&](size_t block_idx) {
88 auto& block = blocks_array[block_idx];
89 const uint32_t offset = block.trace_offset();
90 const uint32_t block_size = static_cast<uint32_t>(block.size());
91 auto& local_nodes = per_block_nodes[block_idx];
92 local_nodes.reserve(static_cast<size_t>(block_size) * NUM_WIRES);
93
94 // NB: The order of row/column loops is arbitrary but needs to be row/column to match old copy_cycle code.
95 for (uint32_t block_row_idx = 0; block_row_idx < block_size; ++block_row_idx) {
96 for (uint32_t wire_idx = 0; wire_idx < NUM_WIRES; ++wire_idx) {
97 uint32_t var_idx = block.wires[wire_idx][block_row_idx]; // an index into the variables array
98 // Use .at() so out-of-range var_idx is caught instead of producing a silent OOB read.
99 uint32_t real_var_idx = builder.real_variable_index.at(var_idx);
100 uint32_t trace_row_idx = block_row_idx + offset;
101 // Insert the real witness values from this block into the wire polys at the correct offset
102 wires[wire_idx].at(trace_row_idx) = builder.get_variable(var_idx);
103 local_nodes.emplace_back(real_var_idx, cycle_node{ wire_idx, trace_row_idx });
104 }
105 }
106 });
107 }
108
109 // Phase 1.5: Serial concat in block order to preserve cycle-node ordering within each variable's cycle list.
110 {
111 BB_BENCH_NAME("fill_copy_cycles");
112 for (const auto& block_nodes : per_block_nodes) {
113 for (const auto& [real_var_idx, node] : block_nodes) {
114 copy_cycles[real_var_idx].emplace_back(node);
115 }
116 }
117 }
118
119 // Phase 2: parallel selector filling. Each task copies one selector column into one polynomial
120 // slot. Walking blocks in declaration order then each block's `gate_selectors` in order yields
121 // polynomial gate slots in canonical order — same invariant `get_gate_blocks()` relies on.
122 {
123 BB_BENCH_NAME("populate_selectors");
124 struct SelectorTask {
125 Selector<FF>* source;
126 size_t target_poly_idx;
127 uint32_t trace_offset;
128 uint32_t block_size;
129 };
130 std::vector<SelectorTask> selector_tasks;
131 const size_t num_non_gate_poly = polynomials.get_non_gate_selectors().size();
132 size_t gate_poly_idx = num_non_gate_poly;
133 for (auto& block : blocks_array) {
134 const uint32_t off = block.trace_offset();
135 const uint32_t bsz = static_cast<uint32_t>(block.size());
136 for (size_t i = 0; i < num_non_gate_poly; ++i) {
137 selector_tasks.emplace_back(SelectorTask{ &block.non_gate_selectors[i], i, off, bsz });
138 }
139 for (auto& [kind, sel] : block.gate_selectors) {
140 selector_tasks.emplace_back(SelectorTask{ &sel, gate_poly_idx, off, bsz });
141 ++gate_poly_idx;
142 }
143 }
144 parallel_for(selector_tasks.size(), [&](size_t task_idx) {
145 const auto& task = selector_tasks[task_idx];
146 const auto& source = *task.source;
147 for (uint32_t row_idx = 0; row_idx < task.block_size; ++row_idx) {
148 selectors[task.target_poly_idx].set_if_valid_index(row_idx + task.trace_offset, source[row_idx]);
149 }
150 });
151 }
152
153 return copy_cycles;
154}
155
156template <class Flavor>
158 requires IsMegaFlavor<Flavor>
159{
160 auto& ecc_op_selector = polynomials.lagrange_ecc_op;
161
162 // The EccOpQueueRelation constrains ecc_op_wire[row] == w_shift[row] where lagrange_ecc_op == 1;
163 // equivalently, ecc_op_wire[row] == w[row + NUM_ZERO_ROWS], so we write ecc_op_wire starting at
164 // (ecc_op_block.trace_offset() - NUM_ZERO_ROWS).
165 const auto& ecc_op_block = builder.blocks.ecc_op;
166 const size_t wire_start = ecc_op_block.trace_offset();
167 BB_ASSERT_GTE(wire_start, NUM_ZERO_ROWS, "ecc_op block must start beyond the zero row");
168 const size_t op_wire_start = wire_start - NUM_ZERO_ROWS;
169 for (auto [ecc_op_wire, wire] : zip_view(polynomials.get_ecc_op_wires(), polynomials.get_wires())) {
170 for (size_t i = 0; i < ecc_op_block.size(); ++i) {
171 ecc_op_wire.at(op_wire_start + i) = wire[wire_start + i];
172 ecc_op_selector.at(op_wire_start + i) = 1;
173 }
174 }
175}
176
180#ifdef STARKNET_GARAGA_FLAVORS
183#endif
185template class TraceToPolynomials<MegaFlavor>;
188
189} // namespace bb
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
A container for the prover polynomials.
A template class for a reference array. Behaves as if std::array<T&, N> was possible.
Definition ref_array.hpp:22
constexpr std::size_t size() const
Abstract interface for a generic selector.
virtual size_t size() const =0
Get the number of elements.
typename Flavor::CircuitBuilder Builder
static std::vector< CyclicPermutation > populate_wires_and_selectors_and_compute_copy_cycles(Builder &builder, ProverPolynomials &)
Populate wire polynomials, selector polynomials and copy cycles from raw circuit data.
static void populate(Builder &builder, ProverPolynomials &)
Given a circuit, populate a proving key with wire polys, selector polys, and sigma/id polys.
typename Flavor::ProverPolynomials ProverPolynomials
AluTraceBuilder builder
Definition alu.test.cpp:124
ssize_t offset
Definition engine.cpp:62
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
cycle_node represents the idx of a value of the circuit. It will belong to a CyclicPermutation,...