1414namespace bb {
1515
1616/* *
17- * @brief Helper method to compute quantities like total number of gates and dyadic circuit size
17+ * @brief Compute the minimum dyadic (power-of-2) circuit size
18+ * @details The dyadic circuit size is the smallest power of two which can accommodate all polynomials required for the
19+ * proving system. This size must account for the execution trace itself, i.e. the wires/selectors, but also any
20+ * auxiliary polynomials like those that store the table data for lookup arguments.
1821 *
1922 * @tparam Flavor
2023 * @param circuit
2124 */
2225template <IsUltraOrMegaHonk Flavor> size_t ProverInstance_<Flavor>::compute_dyadic_size(Circuit& circuit)
2326{
24- // for the lookup argument the circuit size must be at least as large as the sum of all tables used
25- const size_t min_size_due_to_lookups = circuit.get_tables_size ();
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 ();
2629
2730 // minimum size of execution trace due to everything else
2831 size_t min_size_of_execution_trace = circuit.blocks .get_total_content_size ();
2932
3033 // The number of gates is the maximum required by the lookup argument or everything else, plus an optional zero row
3134 // to allow for shifts.
3235 size_t total_num_gates =
33- NUM_DISABLED_ROWS_IN_SUMCHECK + num_zero_rows + std::max (min_size_due_to_lookups , min_size_of_execution_trace);
36+ NUM_DISABLED_ROWS_IN_SUMCHECK + num_zero_rows + std::max (tables_size , min_size_of_execution_trace);
3437
3538 // Next power of 2 (dyadic circuit size)
3639 return circuit.get_circuit_subgroup_size (total_num_gates);
@@ -40,24 +43,29 @@ template <IsUltraOrMegaHonk Flavor> void ProverInstance_<Flavor>::allocate_wires
4043{
4144 BB_BENCH_NAME (" allocate_wires" );
4245
43- // Allocate only enough memory for the active range; wires are zero outside this range
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+
4449 for (auto & wire : polynomials.get_wires ()) {
45- wire = Polynomial::shiftable (final_active_wire_idx + 1 , dyadic_size ());
50+ wire = Polynomial::shiftable (wire_size , dyadic_size ());
4651 }
4752}
4853
4954template <IsUltraOrMegaHonk Flavor> void ProverInstance_<Flavor>::allocate_permutation_argument_polynomials()
5055{
5156 BB_BENCH_NAME (" allocate_permutation_argument_polynomials" );
5257
53- // Allocate only enough memory for the active range; permutation polynomials are zero outside this range
58+ // Sigma and ID polynomials are zero outside the active trace range
5459 for (auto & sigma : polynomials.get_sigmas ()) {
55- sigma = Polynomial::shiftable (final_active_wire_idx + 1 , dyadic_size ());
60+ sigma = Polynomial::shiftable (trace_active_range_size () , dyadic_size ());
5661 }
5762 for (auto & id : polynomials.get_ids ()) {
58- id = Polynomial::shiftable (final_active_wire_idx + 1 , dyadic_size ());
63+ id = Polynomial::shiftable (trace_active_range_size () , dyadic_size ());
5964 }
60- polynomials.z_perm = Polynomial::shiftable (final_active_wire_idx + 1 , dyadic_size ());
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 ());
6169}
6270
6371template <IsUltraOrMegaHonk Flavor> void ProverInstance_<Flavor>::allocate_lagrange_polynomials()
@@ -91,31 +99,27 @@ void ProverInstance_<Flavor>::allocate_table_lookup_polynomials(const Circuit& c
9199{
92100 BB_BENCH_NAME (" allocate_table_lookup_and_lookup_read_polynomials" );
93101
94- size_t table_offset = circuit.blocks .lookup .trace_offset ();
95- const size_t tables_size = circuit.get_tables_size (); // cumulative size of all lookup tables used in the circuit
96- BB_ASSERT_GT (dyadic_size (), tables_size);
102+ const size_t tables_size = circuit.get_tables_size (); // cumulative size of all lookup tables
97103
98- // Allocate the polynomials containing the actual table data
99- for (auto & poly : polynomials.get_tables ()) {
100- poly = Polynomial (tables_size, dyadic_size (), table_offset);
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 ());
101108 }
102109
103- // Allocate the read counts and tags polynomials
104- polynomials.lookup_read_counts = Polynomial (tables_size, dyadic_size (), table_offset);
105- polynomials.lookup_read_tags = Polynomial (tables_size, dyadic_size (), table_offset);
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 ());
106115
107- // Determine end index for the lookup block and the tables themselves
108- // Note that the start of the tables is aligned with the start of the lookup block in the trace
109- const size_t lookup_block_end =
110- static_cast <size_t >(circuit.blocks .lookup .trace_offset ()) + circuit.blocks .lookup .size ();
111- const auto tables_end = circuit.blocks .lookup .trace_offset () + tables_size;
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);
112120
113- // Allocate the lookup_inverses polynomial
114- const size_t lookup_inverses_start = table_offset;
115- const size_t lookup_inverses_end = std::max (lookup_block_end, tables_end);
116-
117- polynomials.lookup_inverses =
118- Polynomial (lookup_inverses_end - lookup_inverses_start, dyadic_size (), lookup_inverses_start);
121+ const size_t lookup_inverses_size = (Flavor::HasZK ? dyadic_size () : lookup_inverses_end);
122+ polynomials.lookup_inverses = Polynomial (lookup_inverses_size, dyadic_size ());
119123}
120124
121125template <IsUltraOrMegaHonk Flavor>
@@ -125,6 +129,7 @@ void ProverInstance_<Flavor>::allocate_ecc_op_polynomials(const Circuit& circuit
125129 BB_BENCH_NAME (" allocate_ecc_op_polynomials" );
126130
127131 // 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
128133 const size_t ecc_op_block_size = circuit.blocks .ecc_op .size ();
129134 for (auto & wire : polynomials.get_ecc_op_wires ()) {
130135 wire = Polynomial (ecc_op_block_size, dyadic_size ());
@@ -139,36 +144,41 @@ void ProverInstance_<Flavor>::allocate_databus_polynomials(const Circuit& circui
139144 BB_BENCH_NAME (" allocate_databus_and_lookup_inverse_polynomials" );
140145
141146 const size_t calldata_size = circuit.get_calldata ().size ();
142- const size_t secondary_calldata_size = circuit.get_secondary_calldata ().size ();
147+ const size_t sec_calldata_size = circuit.get_secondary_calldata ().size ();
143148 const size_t return_data_size = circuit.get_return_data ().size ();
144149
145- polynomials.calldata = Polynomial (calldata_size, dyadic_size ());
146- polynomials.calldata_read_counts = Polynomial (calldata_size, dyadic_size ());
147- polynomials.calldata_read_tags = Polynomial (calldata_size, dyadic_size ());
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;
148154
149- polynomials.secondary_calldata = Polynomial (secondary_calldata_size , dyadic_size ());
150- polynomials.secondary_calldata_read_counts = Polynomial (secondary_calldata_size , dyadic_size ());
151- polynomials.secondary_calldata_read_tags = Polynomial (secondary_calldata_size , dyadic_size ());
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 ());
152158
153- polynomials.return_data = Polynomial (return_data_size , dyadic_size ());
154- polynomials.return_data_read_counts = Polynomial (return_data_size , dyadic_size ());
155- polynomials.return_data_read_tags = Polynomial (return_data_size , dyadic_size ());
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 ());
156162
157- // Allocate log derivative lookup argument inverse polynomials
158- const size_t q_busread_end = circuit.blocks .busread .trace_offset () + circuit.blocks .busread .size ();
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 ());
159166
160- // TODO(https://github.com/AztecProtocol/barretenberg/issues/1555): Size of databus_id can always be set to max size
161- // between the three databus columns. It currently uses dyadic_size because its values are later set based on its
162- // size(). This means when we naively construct all ProverPolynomials with dyadic size (e.g. for ZK), we get a
163- // different databus_id polynomial and therefore a different VK.
164- polynomials.databus_id = Polynomial (dyadic_size (), dyadic_size ());
165- // polynomials.databus_id = Polynomial(std::max({ calldata_size, secondary_calldata_size, return_data_size,
166- // q_busread_end }), dyadic_size());
167-
168- polynomials.calldata_inverses = Polynomial (std::max (calldata_size, q_busread_end), dyadic_size ());
169- polynomials.secondary_calldata_inverses =
170- Polynomial (std::max (secondary_calldata_size, q_busread_end), dyadic_size ());
171- polynomials.return_data_inverses = Polynomial (std::max (return_data_size, q_busread_end), dyadic_size ());
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 ());
172182}
173183
174184/* *
0 commit comments