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
15
16// TODO(md): note that this has now been added
18#include "rom_ram_logic.hpp"
19#include <optional>
20#include <unordered_set>
21
23
24namespace bb {
25
26template <typename FF> struct non_native_multiplication_witnesses {
27 // first 4 array elements = limbs
28 std::array<uint32_t, 4> a;
29 std::array<uint32_t, 4> b;
30 std::array<uint32_t, 4> q;
31 std::array<uint32_t, 4> r;
32 std::array<FF, 4> neg_modulus;
33};
34
35template <typename FF> struct non_native_partial_multiplication_witnesses {
36 // first 4 array elements = limbs
37 std::array<uint32_t, 4> a;
38 std::array<uint32_t, 4> b;
39};
40
41template <typename ExecutionTrace_>
42class UltraCircuitBuilder_ : public CircuitBuilderBase<typename ExecutionTrace_::FF> {
43 public:
44 using ExecutionTrace = ExecutionTrace_;
45 using FF = typename ExecutionTrace::FF;
47
48 static constexpr size_t NUM_WIRES = ExecutionTrace::NUM_WIRES;
49 // Keeping NUM_WIRES, at least temporarily, for backward compatibility
50 static constexpr size_t program_width = ExecutionTrace::NUM_WIRES;
51
52 static constexpr std::string_view NAME_STRING = "UltraCircuitBuilder";
55 static constexpr size_t UINT_LOG2_BASE = 6; // DOCTODO: explain what this is, or rename.
56 // The plookup range proof requires work linear in range size, thus cannot be used directly for
57 // large ranges such as 2^64. For such ranges the element will be decomposed into smaller
58 // chuncks according to the parameter below
59 static constexpr size_t DEFAULT_PLOOKUP_RANGE_BITNUM = 14;
60 static constexpr size_t DEFAULT_PLOOKUP_RANGE_STEP_SIZE = 3;
61 static constexpr size_t DEFAULT_PLOOKUP_RANGE_SIZE = (1 << DEFAULT_PLOOKUP_RANGE_BITNUM) - 1;
62 static constexpr size_t DEFAULT_NON_NATIVE_FIELD_LIMB_BITS = 68;
63 static constexpr uint32_t UNINITIALIZED_MEMORY_RECORD = UINT32_MAX;
64 static constexpr size_t NUMBER_OF_GATES_PER_RAM_ACCESS = 2;
65 static constexpr size_t NUMBER_OF_ARITHMETIC_GATES_PER_RAM_ARRAY = 1;
66 // number of gates created per non-native field operation in process_non_native_field_multiplications
68
78
87
88 struct RangeList {
89 uint64_t target_range;
90 uint32_t range_tag;
91 uint32_t tau_tag;
92 std::vector<uint32_t> variable_indices;
93 bool operator==(const RangeList& other) const noexcept
94 {
95 return target_range == other.target_range && range_tag == other.range_tag && tau_tag == other.tau_tag &&
96 variable_indices == other.variable_indices;
97 }
98 };
99
106 std::array<uint32_t, 4> a;
107 std::array<uint32_t, 4> b;
108 uint32_t lo_0;
109 uint32_t hi_0;
110 uint32_t hi_1;
111
113 {
114 bool valid = true;
115 for (size_t i = 0; i < 4; ++i) {
116 valid = valid && (a[i] == other.a[i]);
117 valid = valid && (b[i] == other.b[i]);
118 }
119 return valid;
120 }
121
133 {
135
137
138 for (const auto& item : vec) {
139 auto [existing_element, not_in_set] = seen.insert(item);
140 // Memorize if not in set yet
141 if (not_in_set) {
142 uniqueVec.push_back(item);
143 } else {
144 // If we already have a representative, we need to connect the outputs together
145 circuit_builder->assert_equal(item.lo_0, (*existing_element).lo_0);
146 circuit_builder->assert_equal(item.hi_0, (*existing_element).hi_0);
147 circuit_builder->assert_equal(item.hi_1, (*existing_element).hi_1);
148 }
149 }
150
151 vec.swap(uniqueVec);
152 }
153
155 {
156 if (a < other.a) {
157 return true;
158 }
159 if (other.a < a) {
160 return false;
161 }
162 if (b < other.b) {
163 return true;
164 }
165 return other.b < b;
166 }
167
168 struct Hash {
170 {
171 size_t combined_hash = 0;
172
173 // C++ does not have a standard way to hash values, so we use the
174 // common algorithm that boot uses.
175 // You can search for 'cpp hash_combine' to find more information.
176 // Here is one reference:
177 // https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x
178 auto hash_combiner = [](size_t lhs, size_t rhs) {
179 return lhs ^ (rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2));
180 };
181
182 for (const auto& elem : obj.a) {
183 combined_hash = hash_combiner(combined_hash, std::hash<uint32_t>()(elem));
184 }
185 for (const auto& elem : obj.b) {
186 combined_hash = hash_combiner(combined_hash, std::hash<uint32_t>()(elem));
187 }
188
189 return combined_hash;
190 }
191 };
192 };
193
195 uint32_t lo_0_idx;
196 uint32_t lo_1_idx;
197 uint32_t hi_0_idx;
198 uint32_t hi_1_idx;
199 uint32_t hi_2_idx;
200 uint32_t hi_3_idx;
201 };
202
203 // Storage for wires and selectors for all gate types
205
206 // These are variables that we have used a gate on, to enforce that they are
207 // equal to a defined value.
208 std::map<FF, uint32_t> constant_variable_indices;
209
210 // The set of lookup tables used by the circuit, plus the gate data for the lookups from each table
212
213 // Rom/Ram logic
215
216 // Stores gate index of ROM/RAM reads (required by proving key)
217 std::vector<uint32_t> memory_read_records;
218 // Stores gate index of RAM writes (required by proving key)
219 std::vector<uint32_t> memory_write_records;
221
222 // Witnesses that can be in one gate, but that's intentional (used in boomerang catcher)
223 std::vector<uint32_t> used_witnesses;
225
226 bool circuit_finalized = false;
227
228 std::vector<fr> ipa_proof;
229
231
233 UltraCircuitBuilder_(const size_t size_hint = 0)
234 : CircuitBuilderBase<FF>(size_hint)
235 {
237 this->tau.insert({ DUMMY_TAG, DUMMY_TAG }); // TODO(luke): explain this
238 };
253 UltraCircuitBuilder_(const size_t size_hint,
254 auto& witness_values,
255 const std::vector<uint32_t>& public_inputs,
256 size_t varnum,
257 bool recursive = false)
258 : CircuitBuilderBase<FF>(size_hint, witness_values.empty())
259 {
260 for (size_t idx = 0; idx < varnum; ++idx) {
261 // Zeros are added for variables whose existence is known but whose values are not yet known. The values may
262 // be "set" later on via the assert_equal mechanism.
263 auto value = idx < witness_values.size() ? witness_values[idx] : 0;
264 this->add_variable(value);
265 }
266
267 // Initialize the builder public_inputs directly from the acir public inputs.
268 this->initialize_public_inputs(public_inputs);
269
270 // Add the const zero variable after the acir witness has been
271 // incorporated into variables.
273 this->tau.insert({ DUMMY_TAG, DUMMY_TAG }); // TODO(luke): explain this
274
275 this->is_recursive_circuit = recursive;
276 };
280 , blocks(other.blocks)
281 , constant_variable_indices(other.constant_variable_indices)
282 , lookup_tables(other.lookup_tables)
283 , rom_ram_logic(other.rom_ram_logic)
284 , memory_read_records(other.memory_read_records)
285 , memory_write_records(other.memory_write_records)
286 , range_lists(other.range_lists)
287 , cached_partial_non_native_field_multiplications(other.cached_partial_non_native_field_multiplications)
288 , circuit_finalized(other.circuit_finalized)
289 , ipa_proof(other.ipa_proof) {};
292 {
294 blocks = other.blocks;
295 constant_variable_indices = other.constant_variable_indices;
296
297 lookup_tables = other.lookup_tables;
298 range_lists = other.range_lists;
299 rom_ram_logic = other.rom_ram_logic;
300 memory_read_records = other.memory_read_records;
301 memory_write_records = other.memory_write_records;
302 cached_partial_non_native_field_multiplications = other.cached_partial_non_native_field_multiplications;
303 circuit_finalized = other.circuit_finalized;
304 ipa_proof = other.ipa_proof;
305 return *this;
306 };
307 ~UltraCircuitBuilder_() override = default;
308
329 {
330#if NDEBUG
331 // do nothing
332#else
333 for (auto& block : blocks.get()) {
334 const auto& block_selectors = block.get_selectors();
335 size_t nominal_size = block_selectors[0].size();
336 for (size_t idx = 1; idx < block_selectors.size(); ++idx) {
337 ASSERT_DEBUG(block_selectors[idx].size() == nominal_size);
338 }
339 }
340
341#endif // NDEBUG
342 }
343
344 void finalize_circuit(const bool ensure_nonzero);
345
347
348 void create_add_gate(const add_triple_<FF>& in) override;
349 void create_big_mul_add_gate(const mul_quad_<FF>& in, const bool use_next_gate_w_4 = false);
350 void create_big_add_gate(const add_quad_<FF>& in, const bool use_next_gate_w_4 = false);
352 void create_big_mul_gate(const mul_quad_<FF>& in);
354
355 void create_mul_gate(const mul_triple_<FF>& in) override;
356 void create_bool_gate(const uint32_t a) override;
357 void create_poly_gate(const poly_triple_<FF>& in) override;
360
361 void fix_witness(const uint32_t witness_index, const FF& witness_value);
362
363 void create_new_range_constraint(const uint32_t variable_index,
364 const uint64_t target_range,
365 std::string const msg = "create_new_range_constraint");
366 void create_range_constraint(const uint32_t variable_index, const size_t num_bits, std::string const& msg)
367 {
368 if (num_bits == 1) {
369 create_bool_gate(variable_index);
370 } else if (num_bits <= DEFAULT_PLOOKUP_RANGE_BITNUM) {
386 .a = variable_index,
387 .b = variable_index,
388 .c = variable_index,
389 .q_m = 0,
390 .q_l = 1,
391 .q_r = -1,
392 .q_o = 0,
393 .q_c = 0,
394 });
395 create_new_range_constraint(variable_index, (1ULL << num_bits) - 1, msg);
396 } else {
397 decompose_into_default_range(variable_index, num_bits, DEFAULT_PLOOKUP_RANGE_BITNUM, msg);
398 }
399 }
400
401 uint32_t put_constant_variable(const FF& variable);
402
403 size_t get_num_constant_gates() const override { return 0; }
420 size_t& count, size_t& rangecount, size_t& romcount, size_t& ramcount, size_t& nnfcount) const
421 {
422 count = this->num_gates;
423
424 // each ROM gate adds +1 extra gate due to the rom reads being copied to a sorted list set
425 for (size_t i = 0; i < rom_ram_logic.rom_arrays.size(); ++i) {
426 for (size_t j = 0; j < rom_ram_logic.rom_arrays[i].state.size(); ++j) {
428 romcount += 2;
429 }
430 }
431 romcount += (rom_ram_logic.rom_arrays[i].records.size());
432 romcount += 1; // we add an addition gate after procesing a rom array
433 }
434
435 // each RAM gate adds +2 extra gates due to the ram reads being copied to a sorted list set,
436 // as well as an extra gate to validate timestamps
437 std::vector<size_t> ram_timestamps;
438 std::vector<size_t> ram_range_sizes;
439 std::vector<size_t> ram_range_exists;
440 for (size_t i = 0; i < rom_ram_logic.ram_arrays.size(); ++i) {
441 for (size_t j = 0; j < rom_ram_logic.ram_arrays[i].state.size(); ++j) {
444 }
445 }
446 ramcount += (rom_ram_logic.ram_arrays[i].records.size() * NUMBER_OF_GATES_PER_RAM_ACCESS);
447 ramcount += NUMBER_OF_ARITHMETIC_GATES_PER_RAM_ARRAY; // we add an addition gate after procesing a ram array
448
449 // there will be 'max_timestamp' number of range checks, need to calculate.
450 const auto max_timestamp = rom_ram_logic.ram_arrays[i].access_count - 1;
451
452 // if a range check of length `max_timestamp` already exists, we are double counting.
453 // We record `ram_timestamps` to detect and correct for this error when we process range lists.
454
455 ram_timestamps.push_back(max_timestamp);
456 size_t padding = (NUM_WIRES - (max_timestamp % NUM_WIRES)) % NUM_WIRES;
457 if (max_timestamp == NUM_WIRES) {
458 padding += NUM_WIRES;
459 }
460 const size_t ram_range_check_list_size = max_timestamp + padding;
461
462 size_t ram_range_check_gate_count = (ram_range_check_list_size / NUM_WIRES);
463 ram_range_check_gate_count += 1; // we need to add 1 extra addition gates for every distinct range list
464
465 ram_range_sizes.push_back(ram_range_check_gate_count);
466 ram_range_exists.push_back(false);
467 }
468 for (const auto& list : range_lists) {
469 auto list_size = list.second.variable_indices.size();
470 size_t padding = (NUM_WIRES - (list.second.variable_indices.size() % NUM_WIRES)) % NUM_WIRES;
471 if (list.second.variable_indices.size() == NUM_WIRES) {
472 padding += NUM_WIRES;
473 }
474 list_size += padding;
475
476 for (size_t i = 0; i < ram_timestamps.size(); ++i) {
477 if (list.second.target_range == ram_timestamps[i]) {
478 ram_range_exists[i] = true;
479 }
480 }
481 rangecount += (list_size / NUM_WIRES);
482 rangecount += 1; // we need to add 1 extra addition gates for every distinct range list
483 }
484 // update rangecount to include the ram range checks the composer will eventually be creating
485 for (size_t i = 0; i < ram_range_sizes.size(); ++i) {
486 if (!ram_range_exists[i]) {
487 rangecount += ram_range_sizes[i];
488 }
489 }
492 // update nnfcount
493 std::sort(nnf_copy.begin(), nnf_copy.end());
494
495 auto last = std::unique(nnf_copy.begin(), nnf_copy.end());
496 const size_t num_nnf_ops = static_cast<size_t>(std::distance(nnf_copy.begin(), last));
498 }
499
504 size_t get_num_finalized_gates() const override
505 {
507 return this->num_gates;
508 }
509
525 size_t get_estimated_num_finalized_gates() const override
526 {
527 // if circuit finalized already added extra gates
528 if (circuit_finalized) {
529 return this->num_gates;
530 }
531 size_t count = 0;
532 size_t rangecount = 0;
533 size_t romcount = 0;
534 size_t ramcount = 0;
535 size_t nnfcount = 0;
536 get_num_estimated_gates_split_into_components(count, rangecount, romcount, ramcount, nnfcount);
537 return count + romcount + ramcount + rangecount + nnfcount;
538 }
539
546 {
547 UltraCircuitBuilder_<ExecutionTrace> builder; // instantiate new builder
548
549 size_t num_gates_prior = builder.get_estimated_num_finalized_gates();
550 builder.add_gates_to_ensure_all_polys_are_non_zero();
551 size_t num_gates_post = builder.get_estimated_num_finalized_gates(); // accounts for finalization gates
552
553 return num_gates_post - num_gates_prior;
554 }
555
560 size_t get_tables_size() const
561 {
562 size_t tables_size = 0;
563 for (const auto& table : lookup_tables) {
564 tables_size += table.size();
565 }
566 return tables_size;
567 }
568
573 size_t get_lookups_size() const
574 {
575 size_t lookups_size = 0;
576 for (const auto& table : lookup_tables) {
577 lookups_size += table.lookup_gates.size();
578 }
579 return lookups_size;
580 }
581
592 {
594 auto num_filled_gates = get_num_finalized_gates() + this->num_public_inputs();
595 return std::max(get_tables_size(), num_filled_gates);
596 }
597
608 {
609 auto num_filled_gates = get_estimated_num_finalized_gates() + this->num_public_inputs();
610 return std::max(get_tables_size(), num_filled_gates);
611 }
612
613 std::vector<uint32_t> get_used_witnesses() const { return used_witnesses; }
614
615 void update_used_witnesses(uint32_t var_idx) { used_witnesses.emplace_back(var_idx); }
616
622 {
623 size_t count = 0;
624 size_t rangecount = 0;
625 size_t romcount = 0;
626 size_t ramcount = 0;
627 size_t nnfcount = 0;
628 get_num_estimated_gates_split_into_components(count, rangecount, romcount, ramcount, nnfcount);
629
630 size_t total = count + romcount + ramcount + rangecount;
631 std::cout << "gates = " << total << " (arith " << count << ", rom " << romcount << ", ram " << ramcount
632 << ", range " << rangecount << ", non native field gates " << nnfcount
633 << "), pubinp = " << this->num_public_inputs() << std::endl;
634 }
635
636 void assert_equal_constant(const uint32_t a_idx, const FF& b, std::string const& msg = "assert equal constant")
637 {
638 if (this->get_variable(a_idx) != b && !this->failed()) {
639 this->failure(msg);
640 }
641 auto b_idx = put_constant_variable(b);
642 this->assert_equal(a_idx, b_idx, msg);
643 }
644
649 bool (*generator)(std::vector<FF>&, std::vector<FF>&, std::vector<FF>&),
650 std::array<FF, 2> (*get_values_from_key)(const std::array<uint64_t, 2>));
651
654
656 const plookup::MultiTableId& id,
657 const plookup::ReadData<FF>& read_values,
658 const uint32_t key_a_index,
660
664 std::vector<uint32_t> decompose_into_default_range(
665 const uint32_t variable_index,
666 const uint64_t num_bits,
667 const uint64_t target_range_bitnum = DEFAULT_PLOOKUP_RANGE_BITNUM,
668 std::string const& msg = "decompose_into_default_range");
670 const uint32_t variable_index,
671 const size_t num_bits,
672 std::string const& msg = "decompose_into_default_range_better_for_oddlimbnum");
673
683 auto& block, const uint32_t& idx_1, const uint32_t& idx_2, const uint32_t& idx_3, const uint32_t& idx_4)
684 {
685 block.populate_wires(idx_1, idx_2, idx_3, idx_4);
686 block.q_m().emplace_back(0);
687 block.q_1().emplace_back(0);
688 block.q_2().emplace_back(0);
689 block.q_3().emplace_back(0);
690 block.q_c().emplace_back(0);
691 block.q_arith().emplace_back(0);
692 block.q_4().emplace_back(0);
693 block.q_delta_range().emplace_back(0);
694 block.q_elliptic().emplace_back(0);
695 block.q_lookup_type().emplace_back(0);
696 block.q_memory().emplace_back(0);
697 block.q_nnf().emplace_back(0);
698 block.q_poseidon2_external().emplace_back(0);
699 block.q_poseidon2_internal().emplace_back(0);
700
702 block.pad_additional();
703 }
705 ++this->num_gates;
706 }
707 void create_dummy_constraints(const std::vector<uint32_t>& variable_index);
708 void create_sort_constraint(const std::vector<uint32_t>& variable_index);
709 void create_sort_constraint_with_edges(const std::vector<uint32_t>& variable_index, const FF&, const FF&);
710 void assign_tag(const uint32_t variable_index, const uint32_t tag)
711 {
712 BB_ASSERT_LTE(tag, this->current_tag);
713 // If we've already assigned this tag to this variable, return (can happen due to copy constraints)
714 if (this->real_variable_tags[this->real_variable_index[variable_index]] == tag) {
715 return;
716 }
717
718 BB_ASSERT_EQ(this->real_variable_tags[this->real_variable_index[variable_index]], DUMMY_TAG);
719 this->real_variable_tags[this->real_variable_index[variable_index]] = tag;
720 }
721
722 uint32_t create_tag(const uint32_t tag_index, const uint32_t tau_index)
723 {
724 this->tau.insert({ tag_index, tau_index });
725 this->current_tag++; // Why exactly?
726 return this->current_tag;
727 }
728
729 uint32_t get_new_tag()
730 {
731 this->current_tag++;
732 return this->current_tag;
733 }
734
735 RangeList create_range_list(const uint64_t target_range);
736 void process_range_list(RangeList& list);
737 void process_range_lists();
738
743 void apply_nnf_selectors(const NNF_SELECTORS type);
744
748 void range_constrain_two_limbs(const uint32_t lo_idx,
749 const uint32_t hi_idx,
750 const size_t lo_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS,
751 const size_t hi_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS);
752 std::array<uint32_t, 2> decompose_non_native_field_double_width_limb(
753 const uint32_t limb_idx, const size_t num_limb_bits = (2 * DEFAULT_NON_NATIVE_FIELD_LIMB_BITS));
754 std::array<uint32_t, 2> evaluate_non_native_field_multiplication(
756 std::array<uint32_t, 2> queue_partial_non_native_field_multiplication(
761 add_simple limb1,
762 add_simple limb2,
763 add_simple limb3,
766 add_simple limb1,
767 add_simple limb2,
768 add_simple limb3,
770
775 size_t create_ROM_array(const size_t array_size);
776 void set_ROM_element(const size_t rom_id, const size_t index_value, const uint32_t value_witness);
777 void set_ROM_element_pair(const size_t rom_id,
778 const size_t index_value,
779 const std::array<uint32_t, 2>& value_witnesses);
780
781 uint32_t read_ROM_array(const size_t rom_id, const uint32_t index_witness);
782 std::array<uint32_t, 2> read_ROM_array_pair(const size_t rom_id, const uint32_t index_witness);
783
784 size_t create_RAM_array(const size_t array_size);
785 void init_RAM_element(const size_t ram_id, const size_t index_value, const uint32_t value_witness);
786
787 uint32_t read_RAM_array(const size_t ram_id, const uint32_t index_witness);
788 void write_RAM_array(const size_t ram_id, const uint32_t index_witness, const uint32_t value_witness);
789 // note that the `process_ROM_array` and `process_RAM_array` methods are controlled by `RomRamLogic` and hence are
790 // not present here.
791
794
795 msgpack::sbuffer export_circuit() override;
796};
798} // namespace bb
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:59
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:129
#define ASSERT(expression,...)
Definition assert.hpp:49
#define ASSERT_DEBUG(expression,...)
Definition assert.hpp:26
void initialize_public_inputs(const std::vector< uint32_t > &public_inputs)
Directly initialize the public inputs vector.
CircuitBuilderBase & operator=(const CircuitBuilderBase &other)=default
bool operator==(const CircuitBuilderBase &other) const =default
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
void create_ecc_dbl_gate(const ecc_dbl_gate_< FF > &in)
Create an elliptic curve doubling gate.
std::map< uint64_t, RangeList > range_lists
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.
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
bool operator==(const UltraCircuitBuilder_ &other) const
static constexpr uint32_t UNINITIALIZED_MEMORY_RECORD
RomRamLogic_< ExecutionTrace > RomRamLogic
static constexpr size_t GATES_PER_NON_NATIVE_FIELD_MULTIPLICATION_ARITHMETIC
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....
static constexpr size_t NUMBER_OF_ARITHMETIC_GATES_PER_RAM_ARRAY
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)
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_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_num_gates_added_to_ensure_nonzero_polynomials()
Dynamically compute the number of gates added by the "add_gates_to_ensure_all_polys_are_non_zero" met...
size_t get_estimated_total_circuit_size() const
Get the estimated size of the circuit if it was finalized now.
typename ExecutionTrace::FF FF
UltraCircuitBuilder_ & operator=(UltraCircuitBuilder_ &&other) noexcept
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.
void create_balanced_add_gate(const add_quad_< FF > &in)
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.
UltraCircuitBuilder_(const size_t size_hint, auto &witness_values, const std::vector< uint32_t > &public_inputs, size_t varnum, bool recursive=false)
Constructor from data generated from ACIR.
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...
static constexpr size_t UINT_LOG2_BASE
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
UltraCircuitBuilder_(const UltraCircuitBuilder_ &other)=default
std::vector< uint32_t > decompose_into_default_range_better_for_oddlimbnum(const uint32_t variable_index, const size_t num_bits, std::string const &msg="decompose_into_default_range_better_for_oddlimbnum")
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)
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 create_dummy_constraints(const std::vector< uint32_t > &variable_index)
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.
static constexpr merkle::HashType merkle_hash_type
static constexpr CircuitType CIRCUIT_TYPE
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 create_dummy_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.
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)
static constexpr size_t program_width
uint32_t create_tag(const uint32_t tag_index, const uint32_t tau_index)
UltraCircuitBuilder_(UltraCircuitBuilder_ &&other) noexcept
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 create_big_add_gate_with_bit_extraction(const add_quad_< FF > &in)
A legacy method that was used to extract a bit from c-4d by using gate selectors in the Turboplonk,...
void process_non_native_field_multiplications()
Called in compute_proving_key when finalizing circuit. Iterates over the cached_non_native_field_mult...
static constexpr size_t DEFAULT_PLOOKUP_RANGE_BITNUM
static constexpr size_t NUMBER_OF_GATES_PER_RAM_ACCESS
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:418
AluTraceBuilder builder
Definition alu.test.cpp:123
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:348
Container for managing multiple BasicTables plus the data needed to combine basic table outputs (e....
Definition types.hpp:154