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