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: 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
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
37// TODO(https://github.com/AztecProtocol/barretenberg/issues/1066): This function adds valid (but arbitrary) gates to
38// ensure that the circuit which includes them will not result in any zero-polynomials. This method is designed to be
39// used in conjunction with the corresponding method on the Ultra builder. It handles databus and ecc-op related
40// polynomials.
42{
43 // Add a single default value to all databus columns. Note: This value must be equal across all columns in order for
44 // inter-circuit databus commitment checks to pass in IVC settings.
45
46 // Create an arbitrary calldata read gate
47 add_public_calldata(this->add_variable(BusVector::DEFAULT_VALUE)); // add one entry in calldata
48 auto raw_read_idx = static_cast<uint32_t>(get_calldata().size()) - 1; // read data that was just added
49 auto read_idx = this->add_variable(raw_read_idx);
50 read_calldata(read_idx);
51
52 // Create an arbitrary secondary_calldata read gate
53 add_public_secondary_calldata(this->add_variable(BusVector::DEFAULT_VALUE)); // add one entry in secondary_calldata
54 raw_read_idx = static_cast<uint32_t>(get_secondary_calldata().size()) - 1; // read data that was just added
55 read_idx = this->add_variable(raw_read_idx);
56 read_secondary_calldata(read_idx);
57
58 // Create an arbitrary return data read gate
59 add_public_return_data(this->add_variable(BusVector::DEFAULT_VALUE)); // add one entry in return data
60 raw_read_idx = static_cast<uint32_t>(get_return_data().size()) - 1; // read data that was just added
61 read_idx = this->add_variable(raw_read_idx);
62 read_return_data(read_idx);
63
64 // add dummy mul accum op and an equality op
65 this->queue_ecc_mul_accum(bb::g1::affine_element::one(), 2);
66 this->queue_ecc_eq();
67}
68
76// TODO(https://github.com/AztecProtocol/barretenberg/issues/1066): This function adds valid (but arbitrary) gates to
77// ensure that the circuit which includes them will not result in any zero-polynomials. It also ensures that the first
78// coefficient of the wire polynomials is zero, which is required for them to be shiftable.
80{
81 // Most polynomials are handled via the conventional Ultra method
83 add_mega_gates_to_ensure_all_polys_are_non_zero();
84}
85
92{
93 // Add the operation to the op queue
94 auto ultra_op = op_queue->add_accumulate(point);
95
96 // Add corresponding gates for the operation
97 ecc_op_tuple op_tuple = populate_ecc_op_wires(ultra_op);
98 return op_tuple;
99}
100
109template <typename FF>
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);
117 return op_tuple;
118}
119
127{
128 // Add the operation to the op queue
129 auto ultra_op = op_queue->eq_and_reset();
130
131 // Add corresponding gates for the operation
132 ecc_op_tuple op_tuple = populate_ecc_op_wires(ultra_op);
133 op_tuple.return_is_infinity = ultra_op.return_is_infinity;
134 return op_tuple;
135}
136
143{
144 // Add the operation to the op queue
145 auto ultra_op = op_queue->no_op_ultra_only();
146
147 // Add corresponding gates for the operation
148 ecc_op_tuple op_tuple = populate_ecc_op_wires(ultra_op);
149 return op_tuple;
150}
151
159{
160 ecc_op_tuple op_tuple;
161 op_tuple.op = get_ecc_op_idx(ultra_op.op_code);
162 op_tuple.x_lo = this->add_variable(ultra_op.x_lo);
163 op_tuple.x_hi = this->add_variable(ultra_op.x_hi);
164 op_tuple.y_lo = this->add_variable(ultra_op.y_lo);
165 op_tuple.y_hi = this->add_variable(ultra_op.y_hi);
166 op_tuple.z_1 = this->add_variable(ultra_op.z_1);
167 op_tuple.z_2 = this->add_variable(ultra_op.z_2);
168
169 // Set the indices for the op values for each of the two rows
170 uint32_t op_val_idx_1 = op_tuple.op; // genuine op code value
171 uint32_t op_val_idx_2 = this->zero_idx; // second row value always set to 0
172 // If this is a random operation, the op values are randomized
173 if (ultra_op.op_code.is_random_op) {
174 op_val_idx_1 = this->add_variable(ultra_op.op_code.random_value_1);
175 op_val_idx_2 = this->add_variable(ultra_op.op_code.random_value_2);
176 }
177
178 this->blocks.ecc_op.populate_wires(op_val_idx_1, op_tuple.x_lo, op_tuple.x_hi, op_tuple.y_lo);
179 for (auto& selector : this->blocks.ecc_op.get_selectors()) {
180 selector.emplace_back(0);
181 }
182
183 this->blocks.ecc_op.populate_wires(op_val_idx_2, op_tuple.y_hi, op_tuple.z_1, op_tuple.z_2);
184 for (auto& selector : this->blocks.ecc_op.get_selectors()) {
185 selector.emplace_back(0);
186 }
187
188 return op_tuple;
189};
190
199{
200 // Add the operation to the op queue
201 auto ultra_op = op_queue->random_op_ultra_only();
202
203 // Add corresponding gates for the operation
204 (void)populate_ecc_op_wires(ultra_op);
205}
206
208{
209 null_op_idx = this->zero_idx; // constant 0 is is associated with the zero index
210 add_accum_op_idx = this->put_constant_variable(FF(EccOpCode{ .add = true }.value()));
211 mul_accum_op_idx = this->put_constant_variable(FF(EccOpCode{ .mul = true }.value()));
212 equality_op_idx = this->put_constant_variable(FF(EccOpCode{ .eq = true, .reset = true }.value()));
213}
214
223template <typename FF>
224uint32_t MegaCircuitBuilder_<FF>::read_bus_vector(BusId bus_idx, const uint32_t& read_idx_witness_idx)
225{
226 auto& bus_vector = databus[static_cast<size_t>(bus_idx)];
227 // Get the raw index into the databus column
228 const uint32_t read_idx = static_cast<uint32_t>(uint256_t(this->get_variable(read_idx_witness_idx)));
229
230 BB_ASSERT_LT(read_idx, bus_vector.size()); // Ensure that the read index is valid
231
232 // Create a variable corresponding to the result of the read. Note that we do not in general connect reads from
233 // databus via copy constraints (i.e. we create a unique variable for the result of each read)
234 FF value = this->get_variable(bus_vector[read_idx]);
235 uint32_t value_witness_idx = this->add_variable(value);
236
237 create_databus_read_gate({ read_idx_witness_idx, value_witness_idx }, bus_idx);
238 bus_vector.increment_read_count(read_idx);
239
240 return value_witness_idx;
241}
242
249template <typename FF>
251{
252 auto& block = this->blocks.busread;
253 block.populate_wires(in.value, in.index, this->zero_idx, this->zero_idx);
254 apply_databus_selectors(bus_idx);
255
256 this->check_selector_length_consistency();
257 ++this->num_gates;
258}
259
260template <typename FF> void MegaCircuitBuilder_<FF>::apply_databus_selectors(const BusId bus_idx)
261{
262 auto& block = this->blocks.busread;
263 switch (bus_idx) {
264 case BusId::CALLDATA: {
265 block.q_1().emplace_back(1);
266 block.q_2().emplace_back(0);
267 block.q_3().emplace_back(0);
268 break;
269 }
271 block.q_1().emplace_back(0);
272 block.q_2().emplace_back(1);
273 block.q_3().emplace_back(0);
274 break;
275 }
276 case BusId::RETURNDATA: {
277 block.q_1().emplace_back(0);
278 block.q_2().emplace_back(0);
279 block.q_3().emplace_back(1);
280 break;
281 }
282 }
283 block.q_busread().emplace_back(1);
284 block.q_m().emplace_back(0);
285 block.q_c().emplace_back(0);
286 block.q_delta_range().emplace_back(0);
287 block.q_arith().emplace_back(0);
288 block.q_4().emplace_back(0);
289 block.q_lookup_type().emplace_back(0);
290 block.q_elliptic().emplace_back(0);
291 block.q_memory().emplace_back(0);
292 block.q_nnf().emplace_back(0);
293 block.q_poseidon2_external().emplace_back(0);
294 block.q_poseidon2_internal().emplace_back(0);
295}
296
297template class MegaCircuitBuilder_<bb::fr>;
298} // namespace bb
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:115
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.
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...
ecc_op_tuple queue_ecc_eq()
Add point equality operation to the op queue based on the value of the internal accumulator and add c...
ecc_op_tuple populate_ecc_op_wires(const UltraOp &ultra_op)
Add goblin ecc op gates for a single operation.
ecc_op_tuple queue_ecc_mul_accum(const g1::affine_element &point, const FF &scalar)
Add point mul-then-accumulate operation to the op queue and add corresponding gates.
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...
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 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.
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.
typename Flavor::FF FF
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