Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
prover_instance.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#include "prover_instance.hpp"
14
15namespace bb {
16
26template <IsUltraOrMegaHonk Flavor> size_t ProverInstance_<Flavor>::compute_dyadic_size(Circuit& circuit)
27{
28 // For the lookup argument the circuit size must be at least as large as the sum of all tables used
29 const size_t tables_size = circuit.get_tables_size();
30
31 // minimum size of execution trace due to everything else
32 size_t min_size_of_execution_trace = circuit.blocks.get_total_content_size();
33
34 // The number of gates is the maximum required by the lookup argument or everything else, plus an optional zero row
35 // to allow for shifts.
36 size_t total_num_gates =
37 NUM_DISABLED_ROWS_IN_SUMCHECK + num_zero_rows + std::max(tables_size, min_size_of_execution_trace);
38
39 // Next power of 2 (dyadic circuit size)
40 return circuit.get_circuit_subgroup_size(total_num_gates);
41}
42
43template <IsUltraOrMegaHonk Flavor> void ProverInstance_<Flavor>::allocate_wires()
44{
45 BB_BENCH_NAME("allocate_wires");
46
47 // If no ZK, allocate only the active range of the trace; else allocate full dyadic size to allow for blinding
48 const size_t wire_size = Flavor::HasZK ? dyadic_size() : trace_active_range_size();
49
50 for (auto& wire : polynomials.get_wires()) {
51 wire = Polynomial::shiftable(wire_size, dyadic_size());
52 }
53}
54
56{
57 BB_BENCH_NAME("allocate_permutation_argument_polynomials");
58
59 // Sigma and ID polynomials are zero outside the active trace range
60 for (auto& sigma : polynomials.get_sigmas()) {
61 sigma = Polynomial::shiftable(trace_active_range_size(), dyadic_size());
62 }
63 for (auto& id : polynomials.get_ids()) {
64 id = Polynomial::shiftable(trace_active_range_size(), dyadic_size());
65 }
66
67 // If no ZK, allocate only the active range of the trace; else allocate full dyadic size to allow for blinding
68 const size_t z_perm_size = Flavor::HasZK ? dyadic_size() : trace_active_range_size();
69 polynomials.z_perm = Polynomial::shiftable(z_perm_size, dyadic_size());
70}
71
72template <IsUltraOrMegaHonk Flavor> void ProverInstance_<Flavor>::allocate_lagrange_polynomials()
73{
74 BB_BENCH_NAME("allocate_lagrange_polynomials");
75
76 polynomials.lagrange_first = Polynomial(
77 /* size=*/1, /*virtual size=*/dyadic_size(), /*start_index=*/0);
78
79 polynomials.lagrange_last = Polynomial(
80 /* size=*/1, /*virtual size=*/dyadic_size(), /*start_index=*/final_active_wire_idx);
81}
82
83template <IsUltraOrMegaHonk Flavor> void ProverInstance_<Flavor>::allocate_selectors(const Circuit& circuit)
84{
85 BB_BENCH_NAME("allocate_selectors");
86
87 // Define gate selectors over the block they are isolated to
88 for (auto [selector, block] : zip_view(polynomials.get_gate_selectors(), circuit.blocks.get_gate_blocks())) {
89 selector = Polynomial(block.size(), dyadic_size(), block.trace_offset());
90 }
91
92 // Set the other non-gate selector polynomials (e.g. q_l, q_r, q_m etc.) to full size
93 for (auto& selector : polynomials.get_non_gate_selectors()) {
94 selector = Polynomial(dyadic_size());
95 }
96}
97
98template <IsUltraOrMegaHonk Flavor>
100{
101 BB_BENCH_NAME("allocate_table_lookup_and_lookup_read_polynomials");
102
103 const size_t tables_size = circuit.get_tables_size(); // cumulative size of all lookup tables
104
105 // Allocate polynomials containing the actual table data; offset to align with the lookup gate block
106 BB_ASSERT_GT(dyadic_size(), tables_size);
107 for (auto& table_poly : polynomials.get_tables()) {
108 table_poly = Polynomial(tables_size, dyadic_size());
109 }
110
111 // Read counts and tags: track which table entries have been read
112 // For non-ZK, allocate just the table size; for ZK: allocate fulll dyadic_size
113 const size_t counts_and_tags_size = Flavor::HasZK ? dyadic_size() : tables_size;
114 polynomials.lookup_read_counts = Polynomial(counts_and_tags_size, dyadic_size());
115 polynomials.lookup_read_tags = Polynomial(counts_and_tags_size, dyadic_size());
116
117 // Lookup inverses: used in the log-derivative lookup argument
118 // Must cover both the lookup gate block (where reads occur) and the table data itself
119 const size_t lookup_block_end = circuit.blocks.lookup.trace_offset() + circuit.blocks.lookup.size();
120 const size_t lookup_inverses_end = std::max(lookup_block_end, tables_size);
121
122 const size_t lookup_inverses_size = (Flavor::HasZK ? dyadic_size() : lookup_inverses_end);
123 polynomials.lookup_inverses = Polynomial(lookup_inverses_size, dyadic_size());
124}
125
126template <IsUltraOrMegaHonk Flavor>
128 requires IsMegaFlavor<Flavor>
129{
130 BB_BENCH_NAME("allocate_ecc_op_polynomials");
131
132 // Allocate the ecc op wires and selector
133 // Note: ECC op wires are not blinded directly so we do not need to allocate full dyadic size for ZK
134 const size_t ecc_op_block_size = circuit.blocks.ecc_op.size();
135 for (auto& wire : polynomials.get_ecc_op_wires()) {
136 wire = Polynomial(ecc_op_block_size, dyadic_size());
137 }
138 polynomials.lagrange_ecc_op = Polynomial(ecc_op_block_size, dyadic_size());
139}
140
141template <IsUltraOrMegaHonk Flavor>
143 requires HasDataBus<Flavor>
144{
145 BB_BENCH_NAME("allocate_databus_and_lookup_inverse_polynomials");
146
147 const size_t calldata_size = circuit.get_calldata().size();
148 const size_t sec_calldata_size = circuit.get_secondary_calldata().size();
149 const size_t return_data_size = circuit.get_return_data().size();
150
151 // Allocate only enough space for the databus data; for ZK, allocate full dyadic size
152 const size_t calldata_poly_size = Flavor::HasZK ? dyadic_size() : calldata_size;
153 const size_t sec_calldata_poly_size = Flavor::HasZK ? dyadic_size() : sec_calldata_size;
154 const size_t return_data_poly_size = Flavor::HasZK ? dyadic_size() : return_data_size;
155
156 polynomials.calldata = Polynomial(calldata_poly_size, dyadic_size());
157 polynomials.calldata_read_counts = Polynomial(calldata_poly_size, dyadic_size());
158 polynomials.calldata_read_tags = Polynomial(calldata_poly_size, dyadic_size());
159
160 polynomials.secondary_calldata = Polynomial(sec_calldata_poly_size, dyadic_size());
161 polynomials.secondary_calldata_read_counts = Polynomial(sec_calldata_poly_size, dyadic_size());
162 polynomials.secondary_calldata_read_tags = Polynomial(sec_calldata_poly_size, dyadic_size());
163
164 polynomials.return_data = Polynomial(return_data_poly_size, dyadic_size());
165 polynomials.return_data_read_counts = Polynomial(return_data_poly_size, dyadic_size());
166 polynomials.return_data_read_tags = Polynomial(return_data_poly_size, dyadic_size());
167
168 // Databus lookup inverses: used in the log-derivative lookup argument
169 // Must cover both the databus gate block (where reads occur) and the databus data itself
170 const size_t q_busread_end = circuit.blocks.busread.trace_offset() + circuit.blocks.busread.size();
171 size_t calldata_inverses_size = Flavor::HasZK ? dyadic_size() : std::max(calldata_size, q_busread_end);
172 size_t sec_calldata_inverses_size = Flavor::HasZK ? dyadic_size() : std::max(sec_calldata_size, q_busread_end);
173 size_t return_data_inverses_size = Flavor::HasZK ? dyadic_size() : std::max(return_data_size, q_busread_end);
174
175 polynomials.calldata_inverses = Polynomial(calldata_inverses_size, dyadic_size());
176 polynomials.secondary_calldata_inverses = Polynomial(sec_calldata_inverses_size, dyadic_size());
177 polynomials.return_data_inverses = Polynomial(return_data_inverses_size, dyadic_size());
178
179 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1555): Allocate minimum size >1 to avoid point at
180 // infinity commitment.
181 const size_t max_databus_column_size = std::max({ calldata_size, sec_calldata_size, return_data_size, 2UL });
182 polynomials.databus_id = Polynomial(max_databus_column_size, dyadic_size());
183}
184
192template <IsUltraOrMegaHonk Flavor>
194 requires HasDataBus<Flavor>
195{
196 auto& calldata_poly = polynomials.calldata;
197 auto& calldata_read_counts = polynomials.calldata_read_counts;
198 auto& calldata_read_tags = polynomials.calldata_read_tags;
199 auto& secondary_calldata_poly = polynomials.secondary_calldata;
200 auto& secondary_calldata_read_counts = polynomials.secondary_calldata_read_counts;
201 auto& secondary_calldata_read_tags = polynomials.secondary_calldata_read_tags;
202 auto& return_data_poly = polynomials.return_data;
203 auto& return_data_read_counts = polynomials.return_data_read_counts;
204 auto& return_data_read_tags = polynomials.return_data_read_tags;
205
206 const auto& calldata = circuit.get_calldata();
207 const auto& secondary_calldata = circuit.get_secondary_calldata();
208 const auto& return_data = circuit.get_return_data();
209
210 // Note: Databus columns start from index 0. If this ever changes, make sure to also update the active range
211 // construction in ExecutionTraceUsageTracker::update(). We do not utilize a zero row for databus columns.
212 for (size_t idx = 0; idx < calldata.size(); ++idx) {
213 calldata_poly.at(idx) = circuit.get_variable(calldata[idx]); // calldata values
214 calldata_read_counts.at(idx) = calldata.get_read_count(idx); // read counts
215 calldata_read_tags.at(idx) = calldata_read_counts[idx] > 0 ? 1 : 0; // has row been read or not
216 }
217 for (size_t idx = 0; idx < secondary_calldata.size(); ++idx) {
218 secondary_calldata_poly.at(idx) = circuit.get_variable(secondary_calldata[idx]); // secondary_calldata values
219 secondary_calldata_read_counts.at(idx) = secondary_calldata.get_read_count(idx); // read counts
220 secondary_calldata_read_tags.at(idx) =
221 secondary_calldata_read_counts[idx] > 0 ? 1 : 0; // has row been read or not
222 }
223 for (size_t idx = 0; idx < return_data.size(); ++idx) {
224 return_data_poly.at(idx) = circuit.get_variable(return_data[idx]); // return data values
225 return_data_read_counts.at(idx) = return_data.get_read_count(idx); // read counts
226 return_data_read_tags.at(idx) = return_data_read_counts[idx] > 0 ? 1 : 0; // has row been read or not
227 }
228
229 auto& databus_id = polynomials.databus_id;
230 // Compute a simple identity polynomial for use in the databus lookup argument
231 for (size_t i = 0; i < databus_id.size(); ++i) {
232 databus_id.at(i) = i;
233 }
234}
235
241template <IsUltraOrMegaHonk Flavor> void ProverInstance_<Flavor>::populate_memory_records(const Circuit& circuit)
242{
243 // Store the read/write records as indices into the full trace by accounting for the offset of the memory block.
244 uint32_t ram_rom_offset = circuit.blocks.memory.trace_offset();
245 memory_read_records.reserve(circuit.memory_read_records.size());
246 for (auto& index : circuit.memory_read_records) {
247 memory_read_records.emplace_back(index + ram_rom_offset);
248 }
249 memory_write_records.reserve(circuit.memory_write_records.size());
250 for (auto& index : circuit.memory_write_records) {
251 memory_write_records.emplace_back(index + ram_rom_offset);
252 }
253}
254
255template class ProverInstance_<UltraFlavor>;
256template class ProverInstance_<UltraZKFlavor>;
258#ifdef STARKNET_GARAGA_FLAVORS
261#endif
264template class ProverInstance_<MegaFlavor>;
265template class ProverInstance_<MegaZKFlavor>;
266template class ProverInstance_<MegaAvmFlavor>;
267
268} // namespace bb
#define BB_ASSERT_GT(left, right,...)
Definition assert.hpp:123
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:219
static constexpr bool HasZK
static Polynomial shiftable(size_t virtual_size)
Utility to create a shiftable polynomial of given virtual size.
A ProverInstance is normally constructed from a finalized circuit and it contains all the information...
void allocate_selectors(const Circuit &)
size_t compute_dyadic_size(Circuit &)
Compute the minimum dyadic (power-of-2) circuit size.
void allocate_ecc_op_polynomials(const Circuit &)
void allocate_permutation_argument_polynomials()
void allocate_table_lookup_polynomials(const Circuit &)
typename Flavor::CircuitBuilder Circuit
void populate_memory_records(const Circuit &circuit)
Copy RAM/ROM record of reads and writes from the circuit to the instance.
void construct_databus_polynomials(Circuit &)
void allocate_databus_polynomials(const Circuit &)
typename Flavor::Polynomial Polynomial
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Contains various functions that help construct Honk Sigma and Id polynomials.
std::vector< MemoryValue > calldata