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: Complete, auditors: [Luke, Raju], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
13
15#include "rom_ram_logic.hpp"
16#include <deque>
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-style 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 // We offer two types of range constraints: small (which can be non-dyadic) and general. The below constants
57 // determine their max values.
58 static constexpr size_t MAX_SMALL_RANGE_CONSTRAINT_VAL = (1 << 16) - 1;
59 static constexpr size_t MAX_NUM_BITS_RANGE_CONSTRAINT =
60 253; // the Grumpkin scalar field modulus is between 2^253 and 2^254 and has 254 bits. Therefore the largest
61 // non-vacuous dyadic range-constraint we can enforce is 2^253 - 1, i.e., `num_bits == 253`.
70 ROM_LOGUP_TABLE, // single-value ROM table entry (LogUp scheme)
71 ROM_LOGUP_READ, // single-value ROM read access (LogUp scheme)
72 };
73
82
83 struct RangeList {
84 uint64_t target_range; // range constraint will be for the range [0, target_range], i.e., is inclusive of
85 // `target_range`.
86 uint32_t range_tag; // Every variable that is range-constrained to a given `target_range` has the same tag,
87 // namely, `range_tag`. Never `DEFAULT_TAG`.
88 uint32_t tau_tag; // Tag assigned to the sorted reference set. Never `DEFAULT_TAG`.
89 std::vector<uint32_t>
90 variable_indices; // All variable-indices constrained to this range. During processing, this will be
91 // mutated: replaced by real-variable-indices, then deduplicated.
92 bool operator==(const RangeList& other) const noexcept
93 {
94 return target_range == other.target_range && range_tag == other.range_tag && tau_tag == other.tau_tag &&
95 variable_indices == other.variable_indices;
96 }
97 };
98
99 // AUDITTODO: this is not a large optimization (~0.5% reduction for ultra rec verifier); consider removing
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
194 private:
195 // The set of lookup tables used by the circuit, plus the gate data for the lookups from each table
197
198 public:
199 // Storage for wires and selectors for all gate types
201
202 // The set of variables which have been constrained to a particular value via an arithmetic gate
203 std::unordered_map<FF, uint32_t> constant_variable_indices;
204
205 // Rom/Ram logic
207
208 // Stores gate index of ROM/RAM reads (required by proving key)
209 std::vector<uint32_t> memory_read_records;
210 // Stores gate index of RAM writes (required by proving key)
211 std::vector<uint32_t> memory_write_records;
212 // Stores gate index of ROM-LogUp rows (both table-entry and read-access)
213 std::vector<uint32_t> rom_logup_records;
214 // Range constraints to be batched, keyed by target_range. See create_small_range_constraint() for details.
216
218
219 std::vector<fr> ipa_proof;
220
222
224
227 {
229 // The identity permutation on the set `{DEFAULT_TAG}`. We therefore assume that the
230 // `DEFAULT_TAG` is not involved in any non-trivial multiset-equality checks.
231 this->set_tau_at_index(DEFAULT_TAG, DEFAULT_TAG);
232 };
233
249 UltraCircuitBuilder_(const std::vector<FF>& witness_values,
250 const std::vector<uint32_t>& public_inputs,
251 const bool is_write_vk_mode)
253 {
254 // Real (ACIR) circuits create far more variables than the witness count (limb
255 // decompositions, gadget internals — typically 4-40x); reserve generously so the
256 // per-variable bookkeeping vectors do not repeatedly reallocate during construction.
257 // 4x keeps the transient over-allocation for large-witness circuits within a few MB.
258 constexpr size_t VARIABLES_PER_ACIR_WITNESS_HINT = 4;
259 constexpr size_t MIN_VARIABLES_RESERVE = 1 << 16;
260 this->reserve_variables(
261 std::max(witness_values.size() * VARIABLES_PER_ACIR_WITNESS_HINT, MIN_VARIABLES_RESERVE));
262 for (const auto value : witness_values) {
263 this->add_variable(value);
264 }
265
266 // Initialize the builder public_inputs directly from the acir public inputs.
267 this->initialize_public_inputs(public_inputs);
268
269 // Add the const zero variable after the acir witness has been
270 // incorporated into variables.
272 this->set_tau_at_index(DEFAULT_TAG,
273 DEFAULT_TAG); // tau fixes the `DEFAULT_TAG`, as we assume that `DEFAULT_TAG` is not
274 // involved in any non-trivial multiset-equality checks.
275 };
280 ~UltraCircuitBuilder_() override = default;
281
282 void finalize_circuit();
283
284 void create_add_gate(const add_triple_<FF>& in);
285 void create_big_mul_add_gate(const mul_quad_<FF>& in, const bool use_next_gate_w_4 = false);
286 void create_big_add_gate(const add_quad_<FF>& in, const bool use_next_gate_w_4 = false);
288
289 void create_bool_gate(const uint32_t a);
291 void create_ecc_add_gate(const ecc_add_gate_& in);
293
294 void fix_witness(const uint32_t witness_index, const FF& witness_value);
295
316 void create_small_range_constraint(const uint32_t variable_index,
317 const uint64_t target_range,
318 std::string_view msg = "create_small_range_constraint");
319
330 void create_dyadic_range_constraint(const uint32_t variable_index, const size_t num_bits, std::string_view msg)
331 {
332 if (num_bits == 1) {
333 create_bool_gate(variable_index);
334 } else if (num_bits <= DEFAULT_PLOOKUP_RANGE_BITNUM) {
335 // Add an unconstrained gate to ensure variable_index appears in a wire. (See warning in
336 // `create_small_range_constraint` for more details.)
338 blocks.arithmetic, variable_index, this->zero_idx(), this->zero_idx(), this->zero_idx());
339 create_small_range_constraint(variable_index, (1ULL << num_bits) - 1, msg);
340 } else {
341 create_limbed_range_constraint(variable_index, num_bits, DEFAULT_PLOOKUP_RANGE_BITNUM, msg);
342 }
343 }
344
345 uint32_t put_constant_variable(const FF& variable);
346
347 size_t get_num_constant_gates() const override { return 0; }
348
353 size_t get_num_finalized_gates() const override
354 {
356 return this->num_gates();
357 }
358
368 {
369 UltraCircuitBuilder_ builder_copy = *this;
370 builder_copy.finalize_circuit();
371 return builder_copy.get_num_finalized_gates();
372 }
373
378 size_t get_tables_size() const
379 {
380 size_t tables_size = 0;
381 for (const auto& table : lookup_tables) {
382 tables_size += table.size();
383 }
384 return tables_size;
385 }
386
397 {
399 auto num_filled_gates = get_num_finalized_gates() + this->num_public_inputs();
400 return std::max(get_tables_size(), num_filled_gates);
401 }
402
403 void assert_equal_constant(const uint32_t a_idx, const FF& b, std::string const& msg = "assert equal constant")
404 {
405 if (this->get_variable(a_idx) != b && !this->failed()) {
406 this->failure(msg);
407 }
408 auto b_idx = put_constant_variable(b);
409 this->assert_equal(a_idx, b_idx, msg);
410 }
411
417
418 // Accessors for lookup tables
421 size_t get_num_lookup_tables() const { return lookup_tables.size(); }
422
428
434 void create_lookup_gate(uint32_t key_idx,
435 uint32_t val1_idx,
436 uint32_t val2_idx,
437 plookup::BasicTable& table,
439 FF column_1_step_size = 0,
440 FF column_2_step_size = 0,
441 FF column_3_step_size = 0);
442
444 const plookup::MultiTableId& id,
445 const plookup::ReadData<FF>& read_values,
446 const uint32_t key_a_index,
448
457 std::vector<uint32_t> create_limbed_range_constraint(
458 const uint32_t variable_index,
459 const uint64_t num_bits,
460 const uint64_t target_range_bitnum = DEFAULT_PLOOKUP_RANGE_BITNUM,
461 std::string_view msg = "create_limbed_range_constraint");
462
472 auto& block, const uint32_t& idx_1, const uint32_t& idx_2, const uint32_t& idx_3, const uint32_t& idx_4)
473 {
474 block.append_gate({ .wires = { idx_1, idx_2, idx_3, idx_4 } });
475 this->increment_num_gates();
476 }
477 void create_unconstrained_gates(const std::vector<uint32_t>& variable_index);
478
485 void enforce_small_deltas(const std::vector<uint32_t>& variable_indices);
502 void create_sort_constraint_with_edges(const std::vector<uint32_t>& variable_indices,
503 const FF& start,
504 const FF& end);
505
509 void assign_tag(const uint32_t variable_index, const uint32_t tag)
510 {
512 // If we've already assigned this tag to this variable, return (can happen due to copy constraints)
513 if (this->real_variable_tags[this->real_variable_index[variable_index]] == tag) {
514 return;
515 }
516
517 BB_ASSERT_EQ(this->real_variable_tags[this->real_variable_index[variable_index]], DEFAULT_TAG);
518 this->real_variable_tags[this->real_variable_index[variable_index]] = tag;
519 }
527 void set_tau_at_index(const uint32_t tag_index, const uint32_t tau_index)
528 {
529 auto [it, inserted] = this->_tau.insert({ tag_index, tau_index });
530 BB_ASSERT_DEBUG(inserted, "tag reuse detected");
531 }
544 void set_tau_transposition(const uint32_t tag_index_1, const uint32_t tag_index_2)
545 {
546 set_tau_at_index(tag_index_1, tag_index_2);
547 set_tau_at_index(tag_index_2, tag_index_1);
548 }
549
550 uint32_t get_new_tag()
551 {
552 this->_current_tag++;
553 return this->_current_tag;
554 }
555
556 RangeList create_range_list(const uint64_t target_range);
557 void process_range_list(RangeList& list);
558 void process_range_lists();
559
564 // Build the selector/gate-kind part of a memory or nnf gate row; the caller fills in the wires
565 // and appends the completed row.
568
572 void range_constrain_two_limbs(const uint32_t lo_idx,
573 const uint32_t hi_idx,
574 const size_t lo_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS,
575 const size_t hi_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS,
576 std::string_view msg = "range_constrain_two_limbs");
577 std::array<uint32_t, 2> evaluate_non_native_field_multiplication(
579 std::array<uint32_t, 2> queue_partial_non_native_field_multiplication(
584 add_simple limb1,
585 add_simple limb2,
586 add_simple limb3,
589 add_simple limb1,
590 add_simple limb2,
591 add_simple limb3,
593
597 size_t create_ROM_array(const size_t array_size);
598 void set_ROM_element(const size_t rom_id, const size_t index_value, const uint32_t value_witness);
599 void set_ROM_element_pair(const size_t rom_id,
600 const size_t index_value,
601 const std::array<uint32_t, 2>& value_witnesses);
602
603 uint32_t read_ROM_array(const size_t rom_id, const uint32_t index_witness);
604 std::array<uint32_t, 2> read_ROM_array_pair(const size_t rom_id, const uint32_t index_witness);
605
606 size_t create_RAM_array(const size_t array_size);
607 void init_RAM_element(const size_t ram_id, const size_t index_value, const uint32_t value_witness);
608
609 uint32_t read_RAM_array(const size_t ram_id, const uint32_t index_witness);
610 void write_RAM_array(const size_t ram_id, const uint32_t index_witness, const uint32_t value_witness);
611
614
615 // ========================================================================================
616 // TOOLING: Boomerang Detection
617 // ========================================================================================
618 // The boomerang mechanism enables detection of variables used in only one gate, which may
619 // indicate bugs.
620 // Note: some patterns (like x*(x^-1)=1 for non-zero checks) intentionally employ single-use witnesses. These
621 // members and methods allow excluding such witnesses from boomerang detection.
622
623 private:
624 // Witnesses that can be in one gate, but that's intentional (used in boomerang catcher)
625 std::vector<uint32_t> used_witnesses;
626 // Witnesses that appear in finalize method (used in boomerang catcher). Need to check
627 // that all variables from some connected component were created after finalize method was called
628 std::unordered_set<uint32_t> finalize_witnesses;
629
630 public:
631 const std::vector<uint32_t>& get_used_witnesses() const { return used_witnesses; }
632 const std::unordered_set<uint32_t>& get_finalize_witnesses() const { return finalize_witnesses; }
633
641 void update_used_witnesses(uint32_t var_idx) { used_witnesses.emplace_back(var_idx); }
642
650 void update_used_witnesses(const std::vector<uint32_t>& used_indices)
651 {
652 used_witnesses.reserve(used_witnesses.size() + used_indices.size());
653 for (const auto& it : used_indices) {
654 used_witnesses.emplace_back(it);
655 }
656 }
657
665 void update_finalize_witnesses(uint32_t var_idx) { finalize_witnesses.insert(var_idx); }
666
674 void update_finalize_witnesses(const std::vector<uint32_t>& finalize_indices)
675 {
676 for (const auto& it : finalize_indices) {
677 finalize_witnesses.insert(it);
678 }
679 }
680
681 // ========================================================================================
682
683 msgpack::sbuffer export_circuit();
684};
685using UltraCircuitBuilder = UltraCircuitBuilder_<UltraExecutionTraceBlocks>;
686} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_DEBUG(expression,...)
Definition assert.hpp:55
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:158
virtual uint32_t add_variable(const FF &in)
Add a variable to variables.
std::unordered_map< uint32_t, uint32_t > _tau
The permutation on variable tags, as a constituent of the generalized permutation argument.
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
void reserve_variables(size_t capacity)
Reserve capacity for capacity variables across the per-variable bookkeeping vectors.
std::vector< uint32_t > real_variable_tags
real_variable_tags is the tagging mechanism for the the multiset-equality check.
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}.
std::vector< uint32_t > real_variable_index
Map from witness index to real variable index.
ROM/RAM logic handler for UltraCircuitBuilder.
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.
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
const std::unordered_set< uint32_t > & get_finalize_witnesses() const
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 create_sort_constraint_with_edges(const std::vector< uint32_t > &variable_indices, const FF &start, const FF &end)
Constrain consecutive variable differences to be in {0, 1, 2, 3}, with boundary checks.
void process_range_list(RangeList &list)
void create_poseidon2_internal_gate(const poseidon2_internal_gate_< FF > &in)
Poseidon2 internal round gate, activates the q_poseidon2_internal selector and relation....
std::vector< uint32_t > create_limbed_range_constraint(const uint32_t variable_index, const uint64_t num_bits, const uint64_t target_range_bitnum=DEFAULT_PLOOKUP_RANGE_BITNUM, std::string_view msg="create_limbed_range_constraint")
Range-constrain a variable to [0, 2^num_bits - 1] by decomposing into smaller limbs.
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.
void set_tau_at_index(const uint32_t tag_index, const uint32_t tau_index)
Set the tau(tag_index) = tau_index.
void update_finalize_witnesses(const std::vector< uint32_t > &finalize_indices)
Add a list of witness indices to the finalize exclusion list.
void create_small_range_constraint(const uint32_t variable_index, const uint64_t target_range, std::string_view msg="create_small_range_constraint")
Range-constraints for small ranges, where the upper bound (target_range) need not be dyadic....
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....
size_t get_num_finalized_gates_inefficient() const
Get the number of gates in the finalized version of the circuit.
std::unordered_set< uint32_t > finalize_witnesses
std::vector< uint32_t > rom_logup_records
static constexpr size_t NUM_WIRES
static constexpr size_t MAX_NUM_BITS_RANGE_CONSTRAINT
std::vector< cached_partial_non_native_field_multiplication > cached_partial_non_native_field_multiplications
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_add_gate(const add_triple_< FF > &in)
Create an addition gate, where in.a * in.a_scaling + in.b * in.b_scaling + in.c * in....
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 create_ecc_add_gate(const ecc_add_gate_ &in)
Create an elliptic curve addition gate.
GateRowT memory_selectors_row(const MEMORY_SELECTORS type) const
Enable the memory gate of particular type.
plookup::BasicTable * register_basic_lookup_table(plookup::BasicTable &&table)
Register a BasicTable with the builder, assigning it a unique table_index.
GateRowT nnf_selectors_row(const NNF_SELECTORS type) const
Enable the nnf gate of particular type.
typename ExecutionTrace::FF FF
const std::vector< uint32_t > & get_used_witnesses() const
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)
Construct gates for non-native field addition.
const std::deque< plookup::BasicTable > & get_lookup_tables() const
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 (a.k.a. ROM table)
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)
Create gates from pre-computed accumulator values which simultaneously establish individual basic-tab...
UltraCircuitBuilder_(bool is_write_vk_mode=false)
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 create_dyadic_range_constraint(const uint32_t variable_index, const size_t num_bits, std::string_view msg)
Entry point for range constraints where the upper bound is a power of 2 (i.e., dyadic)....
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)
Create gates for a full non-native field multiplication identity a * b = q * p + r.
void populate_public_inputs_block()
Copy the public input idx data into the public inputs trace block.
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)
UltraCircuitBuilder_(const std::vector< FF > &witness_values, const std::vector< uint32_t > &public_inputs, const bool is_write_vk_mode)
Constructor from data generated from ACIR.
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
void enforce_small_deltas(const std::vector< uint32_t > &variable_indices)
Check for a sequence of variables that the neighboring differences are in {0, 1, 2,...
std::unordered_map< FF, uint32_t > constant_variable_indices
~UltraCircuitBuilder_() override=default
void create_bool_gate(const uint32_t a)
Generate an arithmetic gate equivalent to x^2 - x = 0, which forces x to be 0 or 1.
static constexpr size_t MAX_SMALL_RANGE_CONSTRAINT_VAL
void update_finalize_witnesses(uint32_t var_idx)
Add a witness index to the finalize exclusion list.
void set_tau_transposition(const uint32_t tag_index_1, const uint32_t tag_index_2)
Add a transposition to tau.
UltraCircuitBuilder_(const UltraCircuitBuilder_ &other)=default
std::vector< uint32_t > memory_read_records
void update_used_witnesses(uint32_t var_idx)
Add a witness index to the boomerang exclusion list.
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_view msg="range_constrain_two_limbs")
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.
void assert_equal_constant(const uint32_t a_idx, const FF &b, std::string const &msg="assert equal constant")
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)
Queue the addition of gates constraining the limb-multiplication part of a non native field mul.
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)
Construct gates for non-native field subtraction.
std::deque< plookup::BasicTable > lookup_tables
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()
Iterates over the cached_non_native_field_multiplication objects, removes duplicates,...
static constexpr size_t DEFAULT_PLOOKUP_RANGE_BITNUM
void create_bilinear_batched_eq_gate(const bilinear_batched_eq_gate_< FF > &in)
Create a bilinear / batched-eq gate.
void create_arithmetic_gate(const arithmetic_triple_< FF > &in)
A plonk gate with disabled (set to zero) fourth wire. q_m * a * b + q_1 * a + q_2 * b + q_3.
std::deque< plookup::BasicTable > & get_lookup_tables()
size_t get_tables_size() const
Get combined size of all tables used in circuit.
static constexpr size_t DEFAULT_PLOOKUP_RANGE_STEP_SIZE
void create_lookup_gate(uint32_t key_idx, uint32_t val1_idx, uint32_t val2_idx, plookup::BasicTable &table, const plookup::BasicTable::LookupEntry &entry, FF column_1_step_size=0, FF column_2_step_size=0, FF column_3_step_size=0)
Create a single plookup lookup gate.
Container for lookup accumulator values and table reads.
Definition types.hpp:377
FF a
FF b
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
UltraCircuitBuilder_< UltraExecutionTraceBlocks > UltraCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
bb::VectorAffineElementPushSpan< BaseParams > lhs
bb::VectorAffineElementPushSpan< BaseParams > rhs
One gate: its wire indices, the non-gate selectors present on every block (see NON_GATE_SELECTORS),...
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
Definition types.hpp:306
A basic table from which we can perform lookups (for example, an xor table)
Definition types.hpp:305
Container for managing multiple BasicTables plus the data needed to combine basic table outputs (e....
Definition types.hpp:167
BB_VF_LOAD_LIMBS * this