Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
mega_circuit_builder.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Luke, Raju], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
11#include <unordered_map>
12#include <unordered_set>
13
14using namespace bb;
15using namespace bb::crypto;
16
17namespace bb {
18
19template <typename FF> void MegaCircuitBuilder_<FF>::finalize_circuit(const bool ensure_nonzero)
20{
21 if (ensure_nonzero && !this->circuit_finalized) {
22 // do the mega part of ensuring all polynomials are nonzero; ultra part will be done inside of
23 // Ultra::finalize_circuit
24 add_mega_gates_to_ensure_all_polys_are_non_zero();
25 }
26 // All of the gates involved in finalization are part of the Ultra arithmetization
28}
29
38{
39 // Add a single default value to all databus columns. Note: This value must be equal across all columns in order for
40 // inter-circuit databus commitment checks to pass in IVC settings.
41
42 // Create an arbitrary calldata read gate
43 add_public_calldata(this->add_variable(BusVector::DEFAULT_VALUE)); // add one entry in calldata
44 auto raw_read_idx = static_cast<uint32_t>(get_calldata().size()) - 1; // read data that was just added
45 auto read_idx = this->add_variable(FF(raw_read_idx));
46 update_finalize_witnesses({ read_idx, read_calldata(read_idx) });
47
48 // Create an arbitrary secondary_calldata read gate
49 add_public_secondary_calldata(this->add_variable(BusVector::DEFAULT_VALUE)); // add one entry in secondary_calldata
50 raw_read_idx = static_cast<uint32_t>(get_secondary_calldata().size()) - 1; // read data that was just added
51 read_idx = this->add_variable(FF(raw_read_idx));
52 update_finalize_witnesses({ read_idx, read_secondary_calldata(read_idx) });
53
54 // Create an arbitrary return data read gate
55 add_public_return_data(this->add_variable(BusVector::DEFAULT_VALUE)); // add one entry in return data
56 raw_read_idx = static_cast<uint32_t>(get_return_data().size()) - 1; // read data that was just added
57 read_idx = this->add_variable(FF(raw_read_idx));
58 update_finalize_witnesses({ read_idx, read_return_data(read_idx) });
59
60 if (op_queue->get_current_subtable_size() == 0) {
61 // Add a mul dummy op in the subtable to avoid column polynomial being zero (it has to be a mul rather than an
62 // add to ensure all 4 column polynomials contain some data)
63 this->queue_ecc_mul_accum(bb::g1::affine_element::one(), 2, /*in_finalize=*/true);
64 this->queue_ecc_eq(/*in_finalize=*/true);
65 }
66}
67
76{
77 // Most polynomials are handled via the conventional Ultra method
79 add_mega_gates_to_ensure_all_polys_are_non_zero();
80}
81
88{
89 // Add the operation to the op queue
90 auto ultra_op = op_queue->add_accumulate(point);
91
92 // Add corresponding gates for the operation
93 ecc_op_tuple op_tuple = populate_ecc_op_wires(ultra_op);
94 return op_tuple;
95}
96
107template <typename FF>
109 const FF& scalar,
110 bool in_finalize)
111{
112 // Add the operation to the op queue
113 auto ultra_op = op_queue->mul_accumulate(point, scalar);
114
115 // Add corresponding gates for the operation
116 ecc_op_tuple op_tuple = populate_ecc_op_wires(ultra_op, in_finalize);
117 return op_tuple;
118}
119
127template <typename FF> ecc_op_tuple MegaCircuitBuilder_<FF>::queue_ecc_eq(bool in_finalize)
128{
129 // Add the operation to the op queue
130 auto ultra_op = op_queue->eq_and_reset();
131
132 // Add corresponding gates for the operation
133 ecc_op_tuple op_tuple = populate_ecc_op_wires(ultra_op, in_finalize);
134 op_tuple.return_is_infinity = ultra_op.return_is_infinity;
135 return op_tuple;
136}
137
144{
145 // Add the operation to the op queue
146 auto ultra_op = op_queue->no_op_ultra_only();
147
148 // Add corresponding gates for the operation
149 ecc_op_tuple op_tuple = populate_ecc_op_wires(ultra_op);
150 return op_tuple;
151}
152
165template <typename FF>
167{
168 ecc_op_tuple op_tuple;
169 op_tuple.op = get_ecc_op_idx(ultra_op.op_code);
170 op_tuple.x_lo = this->add_variable(ultra_op.x_lo);
171 op_tuple.x_hi = this->add_variable(ultra_op.x_hi);
172 op_tuple.y_lo = this->add_variable(ultra_op.y_lo);
173 op_tuple.y_hi = this->add_variable(ultra_op.y_hi);
174 op_tuple.z_1 = this->add_variable(ultra_op.z_1);
175 op_tuple.z_2 = this->add_variable(ultra_op.z_2);
176
177 // Set the indices for the op values for each of the two rows
178 uint32_t op_val_idx_1 = op_tuple.op; // genuine op code value
179 uint32_t op_val_idx_2 = this->zero_idx(); // second row value always set to 0
180 // If this is a random operation, the op values are randomized
181 if (ultra_op.op_code.is_random_op) {
182 op_val_idx_1 = this->add_variable(ultra_op.op_code.random_value_1);
183 op_val_idx_2 = this->add_variable(ultra_op.op_code.random_value_2);
184 }
185 // Populate the ecc_op block with TWO rows (matching Ultra format)
186 // Row 1: OP | x_lo | x_hi | y_lo
187 // Row 2: 0 | y_hi | z_1 | z_2
188 this->blocks.ecc_op.populate_wires(op_val_idx_1, op_tuple.x_lo, op_tuple.x_hi, op_tuple.y_lo);
189 for (auto& selector : this->blocks.ecc_op.get_selectors()) {
190 selector.emplace_back(0);
191 }
192 this->blocks.ecc_op.populate_wires(op_val_idx_2, op_tuple.y_hi, op_tuple.z_1, op_tuple.z_2);
193 for (auto& selector : this->blocks.ecc_op.get_selectors()) {
194 selector.emplace_back(0);
195 }
196
197 if (in_finalize) {
198 update_used_witnesses(
199 { op_tuple.op, op_tuple.x_lo, op_tuple.x_hi, op_tuple.y_lo, op_tuple.y_hi, op_tuple.z_1, op_tuple.z_2 });
200 update_finalize_witnesses(
201 { op_tuple.op, op_tuple.x_lo, op_tuple.x_hi, op_tuple.y_lo, op_tuple.y_hi, op_tuple.z_1, op_tuple.z_2 });
202 }
203
204 return op_tuple;
205};
206
215{
216 // Add the operation to the op queue
217 auto ultra_op = op_queue->random_op_ultra_only();
218
219 // Add corresponding gates for the operation
220 (void)populate_ecc_op_wires(ultra_op);
221}
222
234template <typename FF>
236{
237 // Add the operation to the op queue (returns the UltraOp for gate creation)
238 auto ultra_op = op_queue->append_hiding_op(Px, Py);
239
240 // Add corresponding gates for the operation
241 populate_ecc_op_wires(ultra_op);
242}
243
245{
246 null_op_idx = this->zero_idx(); // constant 0 is is associated with the zero index
247 add_accum_op_idx = this->put_constant_variable(FF(EccOpCode{ .add = true }.value()));
248 mul_accum_op_idx = this->put_constant_variable(FF(EccOpCode{ .mul = true }.value()));
249 equality_op_idx = this->put_constant_variable(FF(EccOpCode{ .eq = true, .reset = true }.value()));
250}
251
260template <typename FF>
261uint32_t MegaCircuitBuilder_<FF>::read_bus_vector(BusId bus_idx, const uint32_t& read_idx_witness_idx)
262{
263 auto& bus_vector = databus[static_cast<size_t>(bus_idx)];
264 // Get the raw index into the databus column
265 const uint32_t read_idx = static_cast<uint32_t>(uint256_t(this->get_variable(read_idx_witness_idx)));
266
267 BB_ASSERT_LT(read_idx, bus_vector.size()); // Ensure that the read index is valid
268
269 // Create a variable corresponding to the result of the read. Note that we do not in general connect reads from
270 // databus via copy constraints (i.e. we create a unique variable for the result of each read)
271 FF value = this->get_variable(bus_vector[read_idx]);
272 uint32_t value_witness_idx = this->add_variable(value);
273
274 create_databus_read_gate({ read_idx_witness_idx, value_witness_idx }, bus_idx);
275 bus_vector.increment_read_count(read_idx);
276
277 return value_witness_idx;
278}
279
286template <typename FF>
288{
289 auto& block = this->blocks.busread;
290 block.populate_wires(in.value, in.index, this->zero_idx(), this->zero_idx());
291 apply_databus_selectors(bus_idx);
292
293 this->check_selector_length_consistency();
294 this->increment_num_gates();
295}
296
297template <typename FF> void MegaCircuitBuilder_<FF>::apply_databus_selectors(const BusId bus_idx)
298{
299 auto& block = this->blocks.busread;
300 switch (bus_idx) {
301 case BusId::CALLDATA: {
302 block.q_1().emplace_back(1);
303 block.q_2().emplace_back(0);
304 block.q_3().emplace_back(0);
305 break;
306 }
308 block.q_1().emplace_back(0);
309 block.q_2().emplace_back(1);
310 block.q_3().emplace_back(0);
311 break;
312 }
313 case BusId::RETURNDATA: {
314 block.q_1().emplace_back(0);
315 block.q_2().emplace_back(0);
316 block.q_3().emplace_back(1);
317 break;
318 }
319 }
320 block.q_4().emplace_back(0);
321 block.q_m().emplace_back(0);
322 block.q_c().emplace_back(0);
323 block.set_gate_selector(1);
324}
325
326template class MegaCircuitBuilder_<bb::fr>;
327} // namespace bb
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:153
void queue_ecc_random_op()
Mechanism for populating two rows with randomness. This "operation" doesn't return a tuple representi...
ecc_op_tuple queue_ecc_add_accum(const g1::affine_element &point)
Add simple point addition operation to the op queue and add corresponding gates.
ecc_op_tuple queue_ecc_mul_accum(const g1::affine_element &point, const FF &scalar, bool in_finalize=false)
Add point mul-then-accumulate operation to the op queue and add corresponding gates.
void apply_databus_selectors(BusId bus_idx)
void add_mega_gates_to_ensure_all_polys_are_non_zero()
Ensure all polynomials have at least one non-zero coefficient to avoid commiting to the zero-polynomi...
void add_ultra_and_mega_gates_to_ensure_all_polys_are_non_zero()
Ensure all polynomials have at least one non-zero coefficient to avoid commiting to the zero-polynomi...
ecc_op_tuple queue_ecc_eq(bool in_finalize=true)
Add point equality operation to the op queue based on the value of the internal accumulator and add c...
void create_databus_read_gate(const databus_lookup_gate_< FF > &in, BusId bus_idx)
Create a databus lookup/read gate.
ecc_op_tuple queue_ecc_no_op()
Logic for a no-op operation.
void queue_ecc_hiding_op(const curve::BN254::BaseField &Px, const curve::BN254::BaseField &Py)
Add a hiding op with random (possibly non-curve) Px, Py values to the op queue and circuit.
void finalize_circuit(const bool ensure_nonzero)
uint32_t read_bus_vector(BusId bus_idx, const uint32_t &read_idx_witness_idx)
Read from a databus column.
ecc_op_tuple populate_ecc_op_wires(const UltraOp &ultra_op, bool in_finalize=false)
Add goblin ecc op gates for a single operation.
void add_gates_to_ensure_all_polys_are_non_zero()
Ensure all polynomials have at least one non-zero coefficient to avoid commiting to the zero-polynomi...
void finalize_circuit(const bool ensure_nonzero)
static constexpr element one
Definition group.hpp:46
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
BusId
Definition databus.hpp:77
@ SECONDARY_CALLDATA
static constexpr bb::fr DEFAULT_VALUE
Definition databus.hpp:29
Defines the opcodes for ECC operations used in both the Ultra and ECCVM formats. There are three opco...
EccOpCode op_code