18#include <unordered_set>
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;
35 std::array<uint32_t, 4>
a;
36 std::array<uint32_t, 4>
b;
39template <
typename ExecutionTrace_>
43 using FF =
typename ExecutionTrace::FF;
46 static constexpr size_t NUM_WIRES = ExecutionTrace::NUM_WIRES;
48 static constexpr std::string_view
NAME_STRING =
"UltraCircuitBuilder";
95 std::array<uint32_t, 4>
a;
96 std::array<uint32_t, 4>
b;
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]);
127 for (
const auto& item : vec) {
128 auto [existing_element, not_in_set] = seen.insert(item);
131 uniqueVec.push_back(item);
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);
160 size_t combined_hash = 0;
167 auto hash_combiner = [](
size_t lhs,
size_t rhs) {
168 return lhs ^ (rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2));
171 for (
const auto& elem : obj.
a) {
174 for (
const auto& elem : obj.
b) {
178 return combined_hash;
221 this->
tau.insert({ DUMMY_TAG, DUMMY_TAG });
239 auto& witness_values,
244 for (
size_t idx = 0; idx < varnum; ++idx) {
247 auto value = idx < witness_values.size() ? witness_values[idx] : 0;
257 this->
tau.insert({ DUMMY_TAG, DUMMY_TAG });
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);
303 void fix_witness(
const uint32_t witness_index,
const FF& witness_value);
306 const uint64_t target_range,
307 std::string
const msg =
"create_new_range_constraint");
362 size_t& count,
size_t& rangecount,
size_t& romcount,
size_t& ramcount,
size_t& nnfcount)
const
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;
368 static constexpr size_t GATES_PER_NON_NATIVE_FIELD_MULTIPLICATION_ARITHMETIC = 7;
384 std::vector<size_t> ram_timestamps;
385 std::vector<size_t> ram_range_sizes;
386 std::vector<size_t> ram_range_exists;
390 ramcount += NUMBER_OF_GATES_PER_RAM_ACCESS;
394 ramcount += NUMBER_OF_ARITHMETIC_GATES_PER_RAM_ARRAY;
402 ram_timestamps.push_back(max_timestamp);
407 const size_t ram_range_check_list_size = max_timestamp + padding;
409 size_t ram_range_check_gate_count = (ram_range_check_list_size /
NUM_WIRES);
410 ram_range_check_gate_count += 1;
412 ram_range_sizes.push_back(ram_range_check_gate_count);
413 ram_range_exists.push_back(
false);
416 auto list_size = list.second.variable_indices.size();
418 if (list.second.variable_indices.size() ==
NUM_WIRES) {
421 list_size += padding;
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;
432 for (
size_t i = 0; i < ram_range_sizes.size(); ++i) {
433 if (!ram_range_exists[i]) {
434 rangecount += ram_range_sizes[i];
440 std::sort(nnf_copy.begin(), nnf_copy.end());
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;
475 if (circuit_finalized) {
479 size_t rangecount = 0;
484 return count + romcount + ramcount + rangecount + nnfcount;
493 size_t tables_size = 0;
495 tables_size += table.size();
506 size_t lookups_size = 0;
508 lookups_size += table.lookup_gates.size();
565 for (
const auto& it : used_indices) {
586 for (
const auto& it : finalize_indices) {
598 size_t rangecount = 0;
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
623 bool (*generator)(std::vector<FF>&, std::vector<FF>&, std::vector<FF>&),
632 const uint32_t key_a_index,
639 const uint32_t variable_index,
640 const uint64_t num_bits,
642 std::string
const& msg =
"decompose_into_default_range");
653 auto& block,
const uint32_t& idx_1,
const uint32_t& idx_2,
const uint32_t& idx_3,
const uint32_t& idx_4)
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);
670 void assign_tag(
const uint32_t variable_index,
const uint32_t tag)
682 uint32_t
create_tag(
const uint32_t tag_index,
const uint32_t tau_index)
684 this->
tau.insert({ tag_index, tau_index });
709 const uint32_t hi_idx,
712 std::string
const& msg =
"range_constrain_two_limbs");
736 void set_ROM_element(
const size_t rom_id,
const size_t index_value,
const uint32_t value_witness);
738 const size_t index_value,
739 const std::array<uint32_t, 2>& value_witnesses);
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);
745 void init_RAM_element(
const size_t ram_id,
const size_t index_value,
const uint32_t value_witness);
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);
#define BB_ASSERT_EQ(actual, expected,...)
#define BB_ASSERT_LTE(left, right,...)
#define ASSERT(expression,...)
virtual uint32_t add_variable(const FF &in)
void failure(std::string msg)
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
size_t num_public_inputs() const
std::vector< uint32_t > real_variable_tags
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::map< uint32_t, uint32_t > tau
std::vector< uint32_t > real_variable_index
void set_zero_idx(uint32_t value)
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....
void process_range_lists()
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 >))
RomRamLogic rom_ram_logic
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")
ExecutionTrace_ ExecutionTrace
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
std::vector< fr > ipa_proof
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.
Entry point for Barretenberg command-line interface.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
bool operator==(const RangeList &other) const noexcept
std::vector< uint32_t > variable_indices
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
std::array< uint32_t, 4 > b
std::array< uint32_t, 4 > a
bool operator==(const cached_partial_non_native_field_multiplication &other) const
static constexpr field zero()
std::array< uint32_t, 4 > a
std::array< uint32_t, 4 > q
std::array< uint32_t, 4 > b
std::array< uint32_t, 4 > r
std::array< FF, 4 > neg_modulus
std::array< uint32_t, 4 > b
std::array< uint32_t, 4 > a
A basic table from which we can perform lookups (for example, an xor table)
Container for managing multiple BasicTables plus the data needed to combine basic table outputs (e....