Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ultra_circuit_builder.hpp
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#pragma once
14
16#include "rom_ram_logic.hpp"
17#include <optional>
18#include <unordered_set>
19
21
22namespace bb {
23
24template <typename FF> struct non_native_multiplication_witnesses {
25 // first 4 array elements = limbs
26 std::array<uint32_t, 4> a;
27 std::array<uint32_t, 4> b;
28 std::array<uint32_t, 4> q;
29 std::array<uint32_t, 4> r;
30 std::array<FF, 4> neg_modulus;
31};
32
33template <typename FF> struct non_native_partial_multiplication_witnesses {
34 // first 4 array elements = limbs
35 std::array<uint32_t, 4> a;
36 std::array<uint32_t, 4> b;
37};
38
39template <typename ExecutionTrace_>
40class UltraCircuitBuilder_ : public CircuitBuilderBase<typename ExecutionTrace_::FF> {
41 public:
42 using ExecutionTrace = ExecutionTrace_;
43 using FF = typename ExecutionTrace::FF;
45
46 static constexpr size_t NUM_WIRES = ExecutionTrace::NUM_WIRES;
47
48 static constexpr std::string_view NAME_STRING = "UltraCircuitBuilder";
49 // The plookup range proof requires work linear in range size, thus cannot be used directly for
50 // large ranges such as 2^64. For such ranges the element will be decomposed into smaller
51 // chuncks according to the parameter below
52 static constexpr size_t DEFAULT_PLOOKUP_RANGE_BITNUM = 14;
53 static constexpr size_t DEFAULT_PLOOKUP_RANGE_STEP_SIZE = 3;
54 static constexpr size_t DEFAULT_PLOOKUP_RANGE_SIZE = (1 << DEFAULT_PLOOKUP_RANGE_BITNUM) - 1;
55 static constexpr size_t DEFAULT_NON_NATIVE_FIELD_LIMB_BITS = 68;
56
66
75
76 struct RangeList {
77 uint64_t target_range;
78 uint32_t range_tag;
79 uint32_t tau_tag;
80 std::vector<uint32_t> variable_indices;
81 bool operator==(const RangeList& other) const noexcept
82 {
83 return target_range == other.target_range && range_tag == other.range_tag && tau_tag == other.tau_tag &&
84 variable_indices == other.variable_indices;
85 }
86 };
87
88 // AUDITTODO: this is not a large optimization (~0.5% reduction for ultra rec verifier); consider removing
95 std::array<uint32_t, 4> a;
96 std::array<uint32_t, 4> b;
97 uint32_t lo_0;
98 uint32_t hi_0;
99 uint32_t hi_1;
100
102 {
103 bool valid = true;
104 for (size_t i = 0; i < 4; ++i) {
105 valid = valid && (a[i] == other.a[i]);
106 valid = valid && (b[i] == other.b[i]);
107 }
108 return valid;
109 }
110
122 {
124
126
127 for (const auto& item : vec) {
128 auto [existing_element, not_in_set] = seen.insert(item);
129 // Memorize if not in set yet
130 if (not_in_set) {
131 uniqueVec.push_back(item);
132 } else {
133 // If we already have a representative, we need to connect the outputs together
134 circuit_builder->assert_equal(item.lo_0, (*existing_element).lo_0);
135 circuit_builder->assert_equal(item.hi_0, (*existing_element).hi_0);
136 circuit_builder->assert_equal(item.hi_1, (*existing_element).hi_1);
137 }
138 }
139
140 vec.swap(uniqueVec);
141 }
142
144 {
145 if (a < other.a) {
146 return true;
147 }
148 if (other.a < a) {
149 return false;
150 }
151 if (b < other.b) {
152 return true;
153 }
154 return other.b < b;
155 }
156
157 struct Hash {
159 {
160 size_t combined_hash = 0;
161
162 // C++ does not have a standard way to hash values, so we use the
163 // common algorithm that boot uses.
164 // You can search for 'cpp hash_combine' to find more information.
165 // Here is one reference:
166 // https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x
167 auto hash_combiner = [](size_t lhs, size_t rhs) {
168 return lhs ^ (rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2));
169 };
170
171 for (const auto& elem : obj.a) {
172 combined_hash = hash_combiner(combined_hash, std::hash<uint32_t>()(elem));
173 }
174 for (const auto& elem : obj.b) {
175 combined_hash = hash_combiner(combined_hash, std::hash<uint32_t>()(elem));
176 }
177
178 return combined_hash;
179 }
180 };
181 };
182
183 // Storage for wires and selectors for all gate types
185
186 // These are variables that we have used a gate on, to enforce that they are
187 // equal to a defined value.
188 std::map<FF, uint32_t> constant_variable_indices;
189
190 // The set of lookup tables used by the circuit, plus the gate data for the lookups from each table
192
193 // Rom/Ram logic
195
196 // Stores gate index of ROM/RAM reads (required by proving key)
197 std::vector<uint32_t> memory_read_records;
198 // Stores gate index of RAM writes (required by proving key)
199 std::vector<uint32_t> memory_write_records;
201
202 // Witnesses that can be in one gate, but that's intentional (used in boomerang catcher)
203 std::vector<uint32_t> used_witnesses; // AUDITTODO: isolate these boomerang details?
204 // Witnesses that appear in finalize method (used in boomerang catcher). Need to check
205 // that all variables from some connected component were created after finalize method was called
206 std::unordered_set<uint32_t> finalize_witnesses;
208
209 bool circuit_finalized = false;
210
211 std::vector<fr> ipa_proof;
212
214
216
217 UltraCircuitBuilder_(const size_t size_hint = 0)
218 : CircuitBuilderBase<FF>(size_hint)
219 {
221 this->tau.insert({ DUMMY_TAG, DUMMY_TAG }); // TODO(luke): explain this
222 };
223
238 UltraCircuitBuilder_(const size_t size_hint,
239 auto& witness_values,
240 const std::vector<uint32_t>& public_inputs,
241 size_t varnum)
242 : CircuitBuilderBase<FF>(size_hint, witness_values.empty())
243 {
244 for (size_t idx = 0; idx < varnum; ++idx) {
245 // Zeros are added for variables whose existence is known but whose values are not yet known. The values may
246 // be "set" later on via the assert_equal mechanism.
247 auto value = idx < witness_values.size() ? witness_values[idx] : 0;
248 this->add_variable(value);
249 }
250
251 // Initialize the builder public_inputs directly from the acir public inputs.
252 this->initialize_public_inputs(public_inputs);
253
254 // Add the const zero variable after the acir witness has been
255 // incorporated into variables.
257 this->tau.insert({ DUMMY_TAG, DUMMY_TAG }); // TODO(luke): explain this
258 };
263 ~UltraCircuitBuilder_() override = default;
264
273 {
274#if NDEBUG
275 // do nothing
276#else
277 for (auto& block : blocks.get()) {
278 const auto& block_selectors = block.get_selectors();
279 size_t nominal_size = block_selectors[0].size();
280 for (size_t idx = 1; idx < block_selectors.size(); ++idx) {
281 BB_ASSERT_EQ(block_selectors[idx].size(), nominal_size);
282 }
283 }
284
285#endif // NDEBUG
286 }
287
288 void finalize_circuit(const bool ensure_nonzero);
289
291
292 void create_add_gate(const add_triple_<FF>& in) override;
293 void create_big_mul_add_gate(const mul_quad_<FF>& in, const bool use_next_gate_w_4 = false);
294 void create_big_add_gate(const add_quad_<FF>& in, const bool use_next_gate_w_4 = false);
295 void create_big_mul_gate(const mul_quad_<FF>& in);
296
297 void create_mul_gate(const mul_triple_<FF>& in) override;
298 void create_bool_gate(const uint32_t a) override;
299 void create_poly_gate(const poly_triple_<FF>& in) override;
302
303 void fix_witness(const uint32_t witness_index, const FF& witness_value);
304
305 void create_new_range_constraint(const uint32_t variable_index,
306 const uint64_t target_range,
307 std::string const msg = "create_new_range_constraint");
308 void create_range_constraint(const uint32_t variable_index, const size_t num_bits, std::string const& msg)
309 {
310 if (num_bits == 1) {
311 create_bool_gate(variable_index);
312 } else if (num_bits <= DEFAULT_PLOOKUP_RANGE_BITNUM) {
328 .a = variable_index,
329 .b = variable_index,
330 .c = variable_index,
331 .q_m = 0,
332 .q_l = 1,
333 .q_r = -1,
334 .q_o = 0,
335 .q_c = 0,
336 });
337 create_new_range_constraint(variable_index, (1ULL << num_bits) - 1, msg);
338 } else {
339 decompose_into_default_range(variable_index, num_bits, DEFAULT_PLOOKUP_RANGE_BITNUM, msg);
340 }
341 }
342
343 uint32_t put_constant_variable(const FF& variable);
344
345 size_t get_num_constant_gates() const override { return 0; }
362 size_t& count, size_t& rangecount, size_t& romcount, size_t& ramcount, size_t& nnfcount) const
363 {
364 static constexpr uint32_t UNINITIALIZED_MEMORY_RECORD = UINT32_MAX;
365 static constexpr size_t NUMBER_OF_GATES_PER_RAM_ACCESS = 2;
366 static constexpr size_t NUMBER_OF_ARITHMETIC_GATES_PER_RAM_ARRAY = 1;
367 // number of gates created per non-native field operation in process_non_native_field_multiplications
368 static constexpr size_t GATES_PER_NON_NATIVE_FIELD_MULTIPLICATION_ARITHMETIC = 7;
369 count = this->num_gates;
370
371 // each ROM gate adds +1 extra gate due to the rom reads being copied to a sorted list set
372 for (size_t i = 0; i < rom_ram_logic.rom_arrays.size(); ++i) {
373 for (size_t j = 0; j < rom_ram_logic.rom_arrays[i].state.size(); ++j) {
374 if (rom_ram_logic.rom_arrays[i].state[j][0] == UNINITIALIZED_MEMORY_RECORD) {
375 romcount += 2;
376 }
377 }
378 romcount += (rom_ram_logic.rom_arrays[i].records.size());
379 romcount += 1; // we add an addition gate after procesing a rom array
380 }
381
382 // each RAM gate adds +2 extra gates due to the ram reads being copied to a sorted list set,
383 // as well as an extra gate to validate timestamps
384 std::vector<size_t> ram_timestamps;
385 std::vector<size_t> ram_range_sizes;
386 std::vector<size_t> ram_range_exists;
387 for (size_t i = 0; i < rom_ram_logic.ram_arrays.size(); ++i) {
388 for (size_t j = 0; j < rom_ram_logic.ram_arrays[i].state.size(); ++j) {
389 if (rom_ram_logic.ram_arrays[i].state[j] == UNINITIALIZED_MEMORY_RECORD) {
390 ramcount += NUMBER_OF_GATES_PER_RAM_ACCESS;
391 }
392 }
393 ramcount += (rom_ram_logic.ram_arrays[i].records.size() * NUMBER_OF_GATES_PER_RAM_ACCESS);
394 ramcount += NUMBER_OF_ARITHMETIC_GATES_PER_RAM_ARRAY; // we add an addition gate after procesing a ram array
395
396 // there will be 'max_timestamp' number of range checks, need to calculate.
397 const auto max_timestamp = rom_ram_logic.ram_arrays[i].access_count - 1;
398
399 // if a range check of length `max_timestamp` already exists, we are double counting.
400 // We record `ram_timestamps` to detect and correct for this error when we process range lists.
401
402 ram_timestamps.push_back(max_timestamp);
403 size_t padding = (NUM_WIRES - (max_timestamp % NUM_WIRES)) % NUM_WIRES;
404 if (max_timestamp == NUM_WIRES) {
405 padding += NUM_WIRES;
406 }
407 const size_t ram_range_check_list_size = max_timestamp + padding;
408
409 size_t ram_range_check_gate_count = (ram_range_check_list_size / NUM_WIRES);
410 ram_range_check_gate_count += 1; // we need to add 1 extra addition gates for every distinct range list
411
412 ram_range_sizes.push_back(ram_range_check_gate_count);
413 ram_range_exists.push_back(false);
414 }
415 for (const auto& list : range_lists) {
416 auto list_size = list.second.variable_indices.size();
417 size_t padding = (NUM_WIRES - (list.second.variable_indices.size() % NUM_WIRES)) % NUM_WIRES;
418 if (list.second.variable_indices.size() == NUM_WIRES) {
419 padding += NUM_WIRES;
420 }
421 list_size += padding;
422
423 for (size_t i = 0; i < ram_timestamps.size(); ++i) {
424 if (list.second.target_range == ram_timestamps[i]) {
425 ram_range_exists[i] = true;
426 }
427 }
428 rangecount += (list_size / NUM_WIRES);
429 rangecount += 1; // we need to add 1 extra addition gates for every distinct range list
430 }
431 // update rangecount to include the ram range checks the composer will eventually be creating
432 for (size_t i = 0; i < ram_range_sizes.size(); ++i) {
433 if (!ram_range_exists[i]) {
434 rangecount += ram_range_sizes[i];
435 }
436 }
439 // update nnfcount
440 std::sort(nnf_copy.begin(), nnf_copy.end());
441
442 auto last = std::unique(nnf_copy.begin(), nnf_copy.end());
443 const size_t num_nnf_ops = static_cast<size_t>(std::distance(nnf_copy.begin(), last));
444 nnfcount = num_nnf_ops * GATES_PER_NON_NATIVE_FIELD_MULTIPLICATION_ARITHMETIC;
445 }
446
451 size_t get_num_finalized_gates() const override
452 {
454 return this->num_gates;
455 }
456
472 size_t get_estimated_num_finalized_gates() const override
473 {
474 // if circuit finalized already added extra gates
475 if (circuit_finalized) {
476 return this->num_gates;
477 }
478 size_t count = 0;
479 size_t rangecount = 0;
480 size_t romcount = 0;
481 size_t ramcount = 0;
482 size_t nnfcount = 0;
483 get_num_estimated_gates_split_into_components(count, rangecount, romcount, ramcount, nnfcount);
484 return count + romcount + ramcount + rangecount + nnfcount;
485 }
486
491 size_t get_tables_size() const
492 {
493 size_t tables_size = 0;
494 for (const auto& table : lookup_tables) {
495 tables_size += table.size();
496 }
497 return tables_size;
498 }
499
504 size_t get_lookups_size() const
505 {
506 size_t lookups_size = 0;
507 for (const auto& table : lookup_tables) {
508 lookups_size += table.lookup_gates.size();
509 }
510 return lookups_size;
511 }
512
523 {
525 auto num_filled_gates = get_num_finalized_gates() + this->num_public_inputs();
526 return std::max(get_tables_size(), num_filled_gates);
527 }
528
539 {
540 auto num_filled_gates = get_estimated_num_finalized_gates() + this->num_public_inputs();
541 return std::max(get_tables_size(), num_filled_gates);
542 }
543
544 std::vector<uint32_t> get_used_witnesses() const { return used_witnesses; }
545
553 void update_used_witnesses(uint32_t var_idx) { used_witnesses.emplace_back(var_idx); }
554
562 void update_used_witnesses(const std::vector<uint32_t>& used_indices)
563 {
564 used_witnesses.reserve(used_witnesses.size() + used_indices.size());
565 for (const auto& it : used_indices) {
566 used_witnesses.emplace_back(it);
567 }
568 }
576 void update_finalize_witnesses(uint32_t var_idx) { finalize_witnesses.insert(var_idx); }
584 void update_finalize_witnesses(const std::vector<uint32_t>& finalize_indices)
585 {
586 for (const auto& it : finalize_indices) {
587 finalize_witnesses.insert(it);
588 }
589 }
590
596 {
597 size_t count = 0;
598 size_t rangecount = 0;
599 size_t romcount = 0;
600 size_t ramcount = 0;
601 size_t nnfcount = 0;
602 get_num_estimated_gates_split_into_components(count, rangecount, romcount, ramcount, nnfcount);
603
604 size_t total = count + romcount + ramcount + rangecount;
605 std::cout << "gates = " << total << " (arith " << count << ", rom " << romcount << ", ram " << ramcount
606 << ", range " << rangecount << ", non native field gates " << nnfcount
607 << "), pubinp = " << this->num_public_inputs() << std::endl;
608 }
609
610 void assert_equal_constant(const uint32_t a_idx, const FF& b, std::string const& msg = "assert equal constant")
611 {
612 if (this->get_variable(a_idx) != b && !this->failed()) {
613 this->failure(msg);
614 }
615 auto b_idx = put_constant_variable(b);
616 this->assert_equal(a_idx, b_idx, msg);
617 }
618
623 bool (*generator)(std::vector<FF>&, std::vector<FF>&, std::vector<FF>&),
624 std::array<FF, 2> (*get_values_from_key)(const std::array<uint64_t, 2>));
625
628
630 const plookup::MultiTableId& id,
631 const plookup::ReadData<FF>& read_values,
632 const uint32_t key_a_index,
634
638 std::vector<uint32_t> decompose_into_default_range(
639 const uint32_t variable_index,
640 const uint64_t num_bits,
641 const uint64_t target_range_bitnum = DEFAULT_PLOOKUP_RANGE_BITNUM,
642 std::string const& msg = "decompose_into_default_range");
643
653 auto& block, const uint32_t& idx_1, const uint32_t& idx_2, const uint32_t& idx_3, const uint32_t& idx_4)
654 {
655 block.populate_wires(idx_1, idx_2, idx_3, idx_4);
656 block.q_m().emplace_back(0);
657 block.q_1().emplace_back(0);
658 block.q_2().emplace_back(0);
659 block.q_3().emplace_back(0);
660 block.q_c().emplace_back(0);
661 block.q_4().emplace_back(0);
662 block.set_gate_selector(0); // all selectors zero
663
665 ++this->num_gates;
666 }
667 void create_unconstrained_gates(const std::vector<uint32_t>& variable_index);
668 void create_sort_constraint(const std::vector<uint32_t>& variable_index);
669 void create_sort_constraint_with_edges(const std::vector<uint32_t>& variable_index, const FF&, const FF&);
670 void assign_tag(const uint32_t variable_index, const uint32_t tag)
671 {
672 BB_ASSERT_LTE(tag, this->current_tag);
673 // If we've already assigned this tag to this variable, return (can happen due to copy constraints)
674 if (this->real_variable_tags[this->real_variable_index[variable_index]] == tag) {
675 return;
676 }
677
678 BB_ASSERT_EQ(this->real_variable_tags[this->real_variable_index[variable_index]], DUMMY_TAG);
679 this->real_variable_tags[this->real_variable_index[variable_index]] = tag;
680 }
681
682 uint32_t create_tag(const uint32_t tag_index, const uint32_t tau_index)
683 {
684 this->tau.insert({ tag_index, tau_index });
685 this->current_tag++; // Why exactly?
686 return this->current_tag;
687 }
688
689 uint32_t get_new_tag()
690 {
691 this->current_tag++;
692 return this->current_tag;
693 }
694
695 RangeList create_range_list(const uint64_t target_range);
696 void process_range_list(RangeList& list);
697 void process_range_lists();
698
703 void apply_nnf_selectors(const NNF_SELECTORS type);
704
708 void range_constrain_two_limbs(const uint32_t lo_idx,
709 const uint32_t hi_idx,
710 const size_t lo_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS,
711 const size_t hi_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS,
712 std::string const& msg = "range_constrain_two_limbs");
713 std::array<uint32_t, 2> decompose_non_native_field_double_width_limb(
714 const uint32_t limb_idx, const size_t num_limb_bits = (2 * DEFAULT_NON_NATIVE_FIELD_LIMB_BITS));
715 std::array<uint32_t, 2> evaluate_non_native_field_multiplication(
717 std::array<uint32_t, 2> queue_partial_non_native_field_multiplication(
722 add_simple limb1,
723 add_simple limb2,
724 add_simple limb3,
727 add_simple limb1,
728 add_simple limb2,
729 add_simple limb3,
731
735 size_t create_ROM_array(const size_t array_size);
736 void set_ROM_element(const size_t rom_id, const size_t index_value, const uint32_t value_witness);
737 void set_ROM_element_pair(const size_t rom_id,
738 const size_t index_value,
739 const std::array<uint32_t, 2>& value_witnesses);
740
741 uint32_t read_ROM_array(const size_t rom_id, const uint32_t index_witness);
742 std::array<uint32_t, 2> read_ROM_array_pair(const size_t rom_id, const uint32_t index_witness);
743
744 size_t create_RAM_array(const size_t array_size);
745 void init_RAM_element(const size_t ram_id, const size_t index_value, const uint32_t value_witness);
746
747 uint32_t read_RAM_array(const size_t ram_id, const uint32_t index_witness);
748 void write_RAM_array(const size_t ram_id, const uint32_t index_witness, const uint32_t value_witness);
749
752
753 msgpack::sbuffer export_circuit() override;
754};
756} // namespace bb
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:88
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:163
#define ASSERT(expression,...)
Definition assert.hpp:77
void initialize_public_inputs(const std::vector< uint32_t > &public_inputs)
Directly initialize the public inputs vector.
const std::vector< uint32_t > & public_inputs() const
virtual void assert_equal(uint32_t a_idx, uint32_t b_idx, std::string const &msg="assert_equal")
FF get_variable(const uint32_t index) const
Get the value of the variable v_{index}.
ROM/RAM logic handler for UltraCircuitBuilder.
std::vector< RomTranscript > rom_arrays
Each entry in ram_arrays represents an independent ROM table. RomTranscript tracks the current table ...
std::vector< RamTranscript > ram_arrays
Each entry in ram_arrays represents an independent RAM table. RamTranscript tracks the current table ...
void create_add_gate(const add_triple_< FF > &in) override
Create an addition gate, where in.a * in.a_scaling + in.b * in.b_scaling + in.c * in....
void fix_witness(const uint32_t witness_index, const FF &witness_value)
Add a gate equating a particular witness to a constant, fixing its value.
void init_RAM_element(const size_t ram_id, const size_t index_value, const uint32_t value_witness)
Initialize a RAM cell to equal value_witness
size_t get_num_finalized_gates() const override
Get the number of gates in a finalized circuit.
std::map< FF, uint32_t > constant_variable_indices
UltraCircuitBuilder_(const size_t size_hint, auto &witness_values, const std::vector< uint32_t > &public_inputs, size_t varnum)
Constructor from data generated from ACIR.
void create_ecc_dbl_gate(const ecc_dbl_gate_< FF > &in)
Create an elliptic curve doubling gate.
std::map< uint64_t, RangeList > range_lists
UltraCircuitBuilder_ & operator=(UltraCircuitBuilder_ &&other)=default
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 print_num_estimated_finalized_gates() const override
Print the number and composition of gates in the circuit.
UltraCircuitBuilder_(UltraCircuitBuilder_ &&other)=default
void update_used_witnesses(const std::vector< uint32_t > &used_indices)
Add a list of witness indices to the boomerang exclusion list.
plookup::MultiTable & get_multitable(const plookup::MultiTableId id)
void process_range_list(RangeList &list)
size_t get_lookups_size() const
Get total number of lookups used in circuit.
void create_poseidon2_internal_gate(const poseidon2_internal_gate_< FF > &in)
Poseidon2 internal round gate, activates the q_poseidon2_internal selector and relation.
size_t create_RAM_array(const size_t array_size)
Create a new updatable memory region.
static constexpr size_t DEFAULT_NON_NATIVE_FIELD_LIMB_BITS
void create_unconstrained_gate(auto &block, const uint32_t &idx_1, const uint32_t &idx_2, const uint32_t &idx_3, const uint32_t &idx_4)
Create a gate with no constraints but with possibly non-trivial wire values.
RomRamLogic_< ExecutionTrace > RomRamLogic
void update_finalize_witnesses(const std::vector< uint32_t > &finalize_indices)
Add a list of witness indices to the finalize exclusion list.
void create_big_mul_gate(const mul_quad_< FF > &in)
Create a basic multiplication gate q_m * a * b + q_1 * a + q_2 * b + q_3 * c + q_4 * d + q_c = 0 (q_a...
UltraCircuitBuilder_ & operator=(const UltraCircuitBuilder_ &other)=default
void create_big_mul_add_gate(const mul_quad_< FF > &in, const bool use_next_gate_w_4=false)
Create a big multiplication-addition gate, where in.a * in.b * in.mul_scaling + in....
std::unordered_set< uint32_t > finalize_witnesses
static constexpr size_t NUM_WIRES
std::vector< uint32_t > decompose_into_default_range(const uint32_t variable_index, const uint64_t num_bits, const uint64_t target_range_bitnum=DEFAULT_PLOOKUP_RANGE_BITNUM, std::string const &msg="decompose_into_default_range")
std::vector< cached_partial_non_native_field_multiplication > cached_partial_non_native_field_multiplications
msgpack::sbuffer export_circuit() override
void create_sort_constraint_with_edges(const std::vector< uint32_t > &variable_index, const FF &, const FF &)
std::vector< plookup::BasicTable > lookup_tables
std::tuple< scaled_witness, scaled_witness, FF > add_simple
uint32_t read_RAM_array(const size_t ram_id, const uint32_t index_witness)
void create_unconstrained_gates(const std::vector< uint32_t > &variable_index)
void create_big_add_gate(const add_quad_< FF > &in, const bool use_next_gate_w_4=false)
Create a big addition gate, where in.a * in.a_scaling + in.b * in.b_scaling + in.c * in....
void initialize_precomputed_table(const plookup::BasicTableId id, bool(*generator)(std::vector< FF > &, std::vector< FF > &, std::vector< FF > &), std::array< FF, 2 >(*get_values_from_key)(const std::array< uint64_t, 2 >))
size_t get_estimated_total_circuit_size() const
Get the estimated size of the circuit if it was finalized now.
typename ExecutionTrace::FF FF
std::vector< uint32_t > used_witnesses
std::array< uint32_t, 5 > evaluate_non_native_field_addition(add_simple limb0, add_simple limb1, add_simple limb2, add_simple limb3, std::tuple< uint32_t, uint32_t, FF > limbp)
size_t get_num_constant_gates() const override
size_t create_ROM_array(const size_t array_size)
Create a new read-only memory region.
plookup::ReadData< uint32_t > create_gates_from_plookup_accumulators(const plookup::MultiTableId &id, const plookup::ReadData< FF > &read_values, const uint32_t key_a_index, std::optional< uint32_t > key_b_index=std::nullopt)
Perform a series of lookups, one for each 'row' in read_values.
std::array< uint32_t, 2 > decompose_non_native_field_double_width_limb(const uint32_t limb_idx, const size_t num_limb_bits=(2 *DEFAULT_NON_NATIVE_FIELD_LIMB_BITS))
Decompose a single witness into two, where the lowest is DEFAULT_NON_NATIVE_FIELD_LIMB_BITS (68) rang...
plookup::BasicTable & get_table(const plookup::BasicTableId id)
Get the basic table with provided ID from the set of tables for the present circuit; create it if it ...
static constexpr std::string_view NAME_STRING
void apply_nnf_selectors(const NNF_SELECTORS type)
Enable the nnf gate of particular type.
void create_bool_gate(const uint32_t a) override
Generate an arithmetic gate equivalent to x^2 - x = 0, which forces x to be 0 or 1.
void get_num_estimated_gates_split_into_components(size_t &count, size_t &rangecount, size_t &romcount, size_t &ramcount, size_t &nnfcount) const
Get the final number of gates in a circuit, which consists of the sum of: 1) Current number number of...
void create_ecc_add_gate(const ecc_add_gate_< FF > &in)
Create an elliptic curve addition gate.
void finalize_circuit(const bool ensure_nonzero)
void create_sort_constraint(const std::vector< uint32_t > &variable_index)
void create_poly_gate(const poly_triple_< FF > &in) override
A plonk gate with disabled (set to zero) fourth wire. q_m * a * b + q_1 * a + q_2 * b + q_3.
void create_poseidon2_external_gate(const poseidon2_external_gate_< FF > &in)
Poseidon2 external round gate, activates the q_poseidon2_external selector and relation.
std::array< uint32_t, 2 > evaluate_non_native_field_multiplication(const non_native_multiplication_witnesses< FF > &input)
Queue up non-native field multiplication data.
size_t get_estimated_num_finalized_gates() const override
Get the final number of gates in a circuit, which consists of the sum of: 1) Current number number of...
std::vector< uint32_t > get_used_witnesses() const
void populate_public_inputs_block()
Copy the public input idx data into the public inputs trace block.
void create_range_constraint(const uint32_t variable_index, const size_t num_bits, std::string const &msg)
uint32_t read_ROM_array(const size_t rom_id, const uint32_t index_witness)
Read a single element from ROM.
RangeList create_range_list(const uint64_t target_range)
void assign_tag(const uint32_t variable_index, const uint32_t tag)
uint32_t put_constant_variable(const FF &variable)
void set_ROM_element(const size_t rom_id, const size_t index_value, const uint32_t value_witness)
Initialize a rom cell to equal value_witness
~UltraCircuitBuilder_() override=default
void update_finalize_witnesses(uint32_t var_idx)
Add a witness index to the finalize exclusion list.
UltraCircuitBuilder_(const UltraCircuitBuilder_ &other)=default
std::vector< uint32_t > memory_read_records
void create_mul_gate(const mul_triple_< FF > &in) override
Create a multiplication gate with q_m * a * b + q_3 * c + q_const = 0.
void update_used_witnesses(uint32_t var_idx)
Add a witness index to the boomerang exclusion list.
void check_selector_length_consistency()
Debug helper method for ensuring all selectors have the same size.
std::vector< uint32_t > memory_write_records
void write_RAM_array(const size_t ram_id, const uint32_t index_witness, const uint32_t value_witness)
void set_ROM_element_pair(const size_t rom_id, const size_t index_value, const std::array< uint32_t, 2 > &value_witnesses)
Initialize a ROM array element with a pair of witness values.
std::array< uint32_t, 2 > read_ROM_array_pair(const size_t rom_id, const uint32_t index_witness)
Read a pair of elements from ROM.
UltraCircuitBuilder_(const size_t size_hint=0)
void assert_equal_constant(const uint32_t a_idx, const FF &b, std::string const &msg="assert equal constant")
void range_constrain_two_limbs(const uint32_t lo_idx, const uint32_t hi_idx, const size_t lo_limb_bits=DEFAULT_NON_NATIVE_FIELD_LIMB_BITS, const size_t hi_limb_bits=DEFAULT_NON_NATIVE_FIELD_LIMB_BITS, std::string const &msg="range_constrain_two_limbs")
std::pair< uint32_t, FF > scaled_witness
std::array< uint32_t, 2 > queue_partial_non_native_field_multiplication(const non_native_partial_multiplication_witnesses< FF > &input)
uint32_t create_tag(const uint32_t tag_index, const uint32_t tau_index)
std::array< uint32_t, 5 > evaluate_non_native_field_subtraction(add_simple limb0, add_simple limb1, add_simple limb2, add_simple limb3, std::tuple< uint32_t, uint32_t, FF > limbp)
void apply_memory_selectors(const MEMORY_SELECTORS type)
Enable the memory gate of particular type.
size_t get_finalized_total_circuit_size() const
Get the actual finalized size of a circuit. Assumes the circuit is finalized already.
static constexpr size_t DEFAULT_PLOOKUP_RANGE_SIZE
void process_non_native_field_multiplications()
Called in compute_prover_instance when finalizing circuit. Iterates over the cached_non_native_field_...
static constexpr size_t DEFAULT_PLOOKUP_RANGE_BITNUM
void create_new_range_constraint(const uint32_t variable_index, const uint64_t target_range, std::string const msg="create_new_range_constraint")
Constrain a variable to a range.
size_t get_tables_size() const
Get combined size of all tables used in circuit.
static constexpr size_t DEFAULT_PLOOKUP_RANGE_STEP_SIZE
Container type for lookup table reads.
Definition types.hpp:357
FF a
FF b
Entry point for Barretenberg command-line interface.
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
bool operator==(const RangeList &other) const noexcept
size_t operator()(const cached_partial_non_native_field_multiplication &obj) const
Used to store instructions to create partial_non_native_field_multiplication gates.
static void deduplicate(std::vector< cached_partial_non_native_field_multiplication > &vec, UltraCircuitBuilder_< ExecutionTrace > *circuit_builder)
Dedupilcate cache entries which represent multiplication of the same witnesses.
bool operator<(const cached_partial_non_native_field_multiplication &other) const
bool operator==(const cached_partial_non_native_field_multiplication &other) const
static constexpr field zero()
A basic table from which we can perform lookups (for example, an xor table)
Definition types.hpp:287
Container for managing multiple BasicTables plus the data needed to combine basic table outputs (e....
Definition types.hpp:154