16 const std::string& tag,
20 circuit_info.variables,
21 circuit_info.public_inps,
22 circuit_info.real_variable_index,
23 circuit_info.real_variable_tags,
28 , selectors(circuit_info.selectors)
29 , wires_idxs(circuit_info.wires)
30 , lookup_tables(circuit_info.lookup_tables)
31 , range_tags(circuit_info.range_tags)
32 , rom_records(circuit_info.rom_records)
33 , rom_states(circuit_info.rom_states)
34 , ram_records(circuit_info.ram_records)
35 , ram_states(circuit_info.ram_states)
36 , rom_ram_relaxed(rom_ram_relaxed)
41 size_t arith_cursor = 0;
46 size_t elliptic_cursor = 0;
51 size_t lookup_cursor = 0;
56 size_t nnf_cursor = 0;
69 info(
"Finished solver prep");
107 bool boolean_gate_flag = (boolean_gate == this_gate) && (w_l_idx == w_r_idx) && (w_o_idx == 0) && (w_4_idx == 0);
108 if (boolean_gate_flag) {
115 bool put_constant_variable_flag =
116 (fix_witness_gate == this_gate) && (w_r_idx == 0) && (w_o_idx == 0) && (w_4_idx == 0);
117 if (put_constant_variable_flag) {
127 res += ((q_arith - 3) * q_m * neg_half) * w_r * w_l;
145 res += (q_arith - 1) * w_4_shift;
157 if (q_arith * (q_arith - 1) * (q_arith - 2) != 0) {
158 res = w_l + w_4 - w_l_shift + q_m;
178 new_table.push_back(tmp_entry);
180 is_xor &= (
static_cast<uint256_t>(table_entry[0]) ^
static_cast<uint256_t>(table_entry[1])) ==
182 is_and &= (
static_cast<uint256_t>(table_entry[0]) &
static_cast<uint256_t>(table_entry[1])) ==
186 std::string table_name;
197 this->
tables_sizes.insert({ table_idx, new_table.size() });
238 auto table_idx =
static_cast<uint32_t
>(q_o);
244 STerm second_entry = this->symbolic_vars[w_r_idx] + q_m * this->symbolic_vars[w_r_shift_idx];
245 STerm third_entry = this->symbolic_vars[w_o_idx] + q_c * this->symbolic_vars[w_o_shift_idx];
250 if (q_r == -64 && q_m == -64 && q_c == -64) {
251 this->symbolic_vars[w_l_shift_idx] = this->symbolic_vars[w_l_idx] >> 6;
252 this->symbolic_vars[w_r_shift_idx] = this->symbolic_vars[w_r_idx] >> 6;
253 this->symbolic_vars[w_o_shift_idx] = this->symbolic_vars[w_o_idx] >> 6;
256 auto sqrt = [](
size_t table_size) ->
size_t {
257 auto [is_sqr, res] =
bb::fr(table_size).
sqrt();
258 info(
"Is square: ", is_sqr);
264 return static_cast<size_t>(ures);
269 info(
"XOR optimization");
272 first_entry < max_val;
273 second_entry < max_val;
274 third_entry < max_val;
276 (first_entry ^ second_entry) == third_entry;
280 info(
"AND optimization");
283 first_entry < max_val;
284 second_entry < max_val;
285 third_entry < max_val;
287 (first_entry & second_entry) == third_entry;
294 info(
"Unknown Table");
295 STuple entries({ first_entry, second_entry, third_entry });
335 auto x_diff = (x_2 - x_1);
336 auto y2_sqr = (y_2 * y_2);
337 auto y1_sqr = (y_1 * y_1);
338 auto y1y2 = y_1 * y_2 * q_sign;
339 auto x_add_identity = (x_3 + x_2 + x_1) * x_diff * x_diff - y2_sqr - y1_sqr + y1y2 + y1y2;
341 auto y1_plus_y3 = y_1 + y_3;
342 auto y_diff = y_2 * q_sign - y_1;
343 auto y_add_identity = y1_plus_y3 * x_diff + (x_3 - x_1) * y_diff;
351 auto x_pow_4 = (y1_sqr - curve_b) * x_1;
352 auto y1_sqr_mul_4 = y1_sqr + y1_sqr;
353 y1_sqr_mul_4 += y1_sqr_mul_4;
354 auto x1_pow_4_mul_9 = x_pow_4 * 9;
355 auto x_double_identity = (x_3 + x_1 + x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9;
357 auto x1_sqr_mul_3 = (x_1 + x_1 + x_1) * x_1;
358 auto y_double_identity = x1_sqr_mul_3 * (x_1 - x_3) - (y_1 + y_1) * (y_1 + y_3);
361 x_double_identity == 0;
362 y_double_identity == 0;
378 if (q_delta_range == 0) {
394 STerm delta_1 = w_2 - w_1;
395 STerm delta_2 = w_3 - w_2;
396 STerm delta_3 = w_4 - w_3;
397 STerm delta_4 = w_1_shift - w_4;
399 STerm tmp = (delta_1 - 1) * (delta_1 - 1) - 1;
400 tmp *= (delta_1 - 2) * (delta_1 - 2) - 1;
403 tmp = (delta_2 - 1) * (delta_2 - 1) - 1;
404 tmp *= (delta_2 - 2) * (delta_2 - 2) - 1;
407 tmp = (delta_3 - 1) * (delta_3 - 1) - 1;
408 tmp *= (delta_3 - 2) * (delta_3 - 2) - 1;
411 tmp = (delta_4 - 1) * (delta_4 - 1) - 1;
412 tmp *= (delta_4 - 2) * (delta_4 - 2) - 1;
434 for (
size_t entry = 0; entry <= range; entry++) {
439 info(
RED,
"Initialized new range: ", table_name,
RESET);
492 size_t entry_flag = 0;
494 if (q_3 != 0 && q_4 != 0) {
498 STerm limb_accumulator_1 = w_2_shift * SUBLIMB_SHIFT;
499 limb_accumulator_1 += w_1_shift;
500 limb_accumulator_1 *= SUBLIMB_SHIFT;
501 limb_accumulator_1 += w_3;
502 limb_accumulator_1 *= SUBLIMB_SHIFT;
503 limb_accumulator_1 += w_2;
504 limb_accumulator_1 *= SUBLIMB_SHIFT;
505 limb_accumulator_1 += w_1;
506 limb_accumulator_1 -= w_4;
507 limb_accumulator_1 == 0;
510 if (q_3 != 0 && q_m != 0) {
514 STerm limb_accumulator_2 = w_3_shift * SUBLIMB_SHIFT;
515 limb_accumulator_2 += w_2_shift;
516 limb_accumulator_2 *= SUBLIMB_SHIFT;
517 limb_accumulator_2 += w_1_shift;
518 limb_accumulator_2 *= SUBLIMB_SHIFT;
519 limb_accumulator_2 += w_4;
520 limb_accumulator_2 *= SUBLIMB_SHIFT;
521 limb_accumulator_2 += w_3;
522 limb_accumulator_2 -= w_4_shift;
523 limb_accumulator_2 == 0;
526 STerm limb_subproduct = w_1 * w_2_shift + w_1_shift * w_2;
527 if (q_2 != 0 && q_4 != 0) {
531 STerm non_native_field_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift);
532 non_native_field_gate_2 *= LIMB_SIZE;
533 non_native_field_gate_2 -= w_4_shift;
534 non_native_field_gate_2 += limb_subproduct;
535 non_native_field_gate_2 == 0;
538 limb_subproduct *= LIMB_SIZE;
539 limb_subproduct += (w_1_shift * w_2_shift);
540 if (q_2 != 0 && q_3 != 0) {
544 STerm non_native_field_gate_1 = limb_subproduct;
545 non_native_field_gate_1 -= (w_3 + w_4);
546 non_native_field_gate_1 == 0;
549 if (q_2 != 0 && q_m != 0) {
553 STerm non_native_field_gate_3 = limb_subproduct;
554 non_native_field_gate_3 += w_4;
555 non_native_field_gate_3 -= (w_3_shift + w_4_shift);
556 non_native_field_gate_3 == 0;
559 if (entry_flag > 1) {
560 throw std::runtime_error(
"Double entry in NNF");
574 uint32_t rom_index_idx,
575 uint32_t read_to_value1_idx,
576 uint32_t read_to_value2_idx)
578 if (this->
public_inps.contains(rom_index_idx) || this->rom_ram_relaxed) {
585 STuple table_entry = rom_table[index];
589 STuple value_entry({ value1, value2 });
591 table_entry == value_entry;
603 if (this->
public_inps.contains(ram_index_idx) || this->rom_ram_relaxed) {
610 STerm table_entry = ram_table[index];
614 table_entry == value_entry;
626 if (this->
public_inps.contains(ram_index_idx) || this->rom_ram_relaxed) {
635 ram_table.
put(index, value_entry);
644 static constexpr uint32_t UNINITIALIZED_MEMORY_RECORD = UINT32_MAX;
647 STuple entry_ex({ idx_ex, idx_ex });
649 cvc5::Sort ind_sort = idx_ex.
term.getSort();
651 cvc5::Sort entry_sort = entry_ex.term.getSort();
652 TermType entry_type = entry_ex.type;
654 for (uint32_t i = 0; i < this->
rom_records.size(); i++) {
658 for (
size_t j = 0; j < this->
rom_states[i].size(); j++) {
660 if (this->
rom_states[i][j][0] == UNINITIALIZED_MEMORY_RECORD) {
666 rom_table.
put(idx,
STuple({ value1, value2 }));
672 uint32_t index_witness = rom_record[0];
673 uint32_t value1_witness = rom_record[1];
674 uint32_t value2_witness = rom_record[2];
675 this->
rom_table_read(i, index_witness, value1_witness, value2_witness);
687 STuple entry_ex({ idx_ex, idx_ex });
689 cvc5::Sort sort = idx_ex.
term.getSort();
692 for (uint32_t i = 0; i < this->
ram_records.size(); i++) {
698 uint32_t index_witness = ram_record[0];
699 uint32_t value_witness = ram_record[1];
701 uint32_t access_type = ram_record[3];
702 switch (access_type) {
710 info(
"Reached an invalid access type");
729 if (witness.size() != this->get_num_vars()) {
756 const std::vector<std::string>& equal,
757 const std::vector<std::string>& not_equal,
758 const std::vector<std::string>& equal_at_the_same_time,
759 const std::vector<std::string>& not_equal_at_the_same_time,
760 bool enable_optimizations)
765 for (
const auto& term : equal) {
766 c1[term] == c2[term];
768 for (
const auto& term : not_equal) {
769 c1[term] != c2[term];
773 for (
const auto& term : equal_at_the_same_time) {
778 if (eqs.size() > 1) {
779 batch_or(eqs).assert_term();
780 }
else if (eqs.size() == 1) {
781 eqs[0].assert_term();
785 for (
const auto& term : not_equal_at_the_same_time) {
790 if (neqs.size() > 1) {
791 batch_or(neqs).assert_term();
792 }
else if (neqs.size() == 1) {
793 neqs[0].assert_term();
814 const std::vector<std::string>& equal,
815 bool enable_optimizations)
820 for (
const auto& term : equal) {
821 c1[term] == c2[term];
826 uint32_t i = node.first;
837 if (neqs.size() > 1) {
838 batch_or(neqs).assert_term();
839 }
else if (neqs.size() == 1) {
840 neqs[0].assert_term();
Base class for symbolic circuits.
std::vector< uint32_t > real_variable_index
std::unordered_set< uint32_t > public_inps
std::vector< uint32_t > real_variable_tags
bool enable_optimizations
std::unordered_map< uint32_t, bool > optimized
std::vector< bb::fr > variables
size_t get_num_vars() const
std::unordered_map< uint32_t, std::string > variable_names
std::unordered_map< std::string, uint32_t > variable_names_inverse
std::unordered_map< uint32_t, STerm > symbolic_vars
Symbolic Circuit class for Standard Circuit Builder.
std::unordered_map< uint32_t, SymSet< STuple > > cached_symbolic_tables
std::unordered_map< uint32_t, size_t > tables_sizes
UltraCircuit(CircuitSchema &circuit_info, Solver *solver, TermType type=TermType::FFTerm, const std::string &tag="", bool enable_optimizations=true, bool rom_ram_relaxed=false)
Construct a new UltraCircuit object.
void rom_table_read(uint32_t rom_array_idx, uint32_t index_idx, uint32_t value1_idx, uint32_t value2_idx)
Perform read from ROM table.
std::vector< std::vector< std::vector< uint32_t > > > ram_records
std::vector< std::vector< std::vector< bb::fr > > > lookup_tables
std::unordered_map< uint32_t, TableType > tables_types
std::vector< std::vector< std::array< uint32_t, 2 > > > rom_states
std::unordered_map< uint32_t, SymArray< STerm, STerm > > cached_ram_tables
static std::pair< UltraCircuit, UltraCircuit > unique_witness(CircuitSchema &circuit_info, Solver *s, TermType type, const std::vector< std::string > &equal={}, bool enable_optimizations=false)
Check your circuit for witness uniqueness.
size_t handle_lookup_relation(size_t cursor)
Adds all the lookup gate constraints to the solver. Relaxes constraint system for non-ff solver engin...
bool simulate_circuit_eval(std::vector< bb::fr > &witness) const override
Similar functionality to old .check_circuit() method in standard circuit builder.
size_t handle_elliptic_relation(size_t cursor)
Adds all the elliptic gate constraints to the solver.
size_t handle_nnf_relation(size_t cursor)
Adds all the nnf constraints to the solver.
void handle_ram_tables()
Adds all the RAM related constraints into the solver.
static std::pair< UltraCircuit, UltraCircuit > unique_witness_ext(CircuitSchema &circuit_info, Solver *s, TermType type, const std::vector< std::string > &equal={}, const std::vector< std::string > ¬_equal={}, const std::vector< std::string > &equal_at_the_same_time={}, const std::vector< std::string > ¬_equal_at_the_same_time={}, bool enable_optimizations=false)
Check your circuit for witness uniqueness.
std::vector< std::vector< std::vector< uint32_t > > > rom_records
std::unordered_map< uint32_t, uint64_t > range_tags
void process_new_table(uint32_t table_idx)
void handle_rom_tables()
Adds all the ROM related constraints into the solver.
void ram_table_read(uint32_t ram_array_idx, uint32_t index_idx, uint32_t value_idx)
Perform read from RAM table.
void ram_table_write(uint32_t ram_array_idx, uint32_t ram_index_idx, uint32_t read_from_value_idx)
Perform write to RAM table.
void handle_range_constraints()
Adds all the range constraints to the solver.
size_t handle_arithmetic_relation(size_t cursor)
Adds all the arithmetic gate constraints to the solver. Relaxes constraint system for non-ff solver e...
std::unordered_map< uint32_t, SymArray< STerm, STuple > > cached_rom_tables
size_t handle_delta_range_relation(size_t cursor)
Adds all the delta_range gate constraints to the solver.
std::vector< std::vector< std::vector< bb::fr > > > selectors
std::unordered_map< uint64_t, SymSet< STerm > > cached_range_tables
std::vector< std::vector< std::vector< uint32_t > > > wires_idxs
Symbolic term element class.
void put(const sym_index &ind, const sym_entry &entry)
field< Bn254FrParams > fr
TermType
Allows to define three types of symbolic terms STerm - Symbolic Variables acting like a Finte Field e...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::string to_string(bb::avm2::ValueTag tag)
constexpr field invert() const noexcept
constexpr std::pair< bool, field > sqrt() const noexcept
Compute square root of the field element.
BB_INLINE constexpr bool is_zero() const noexcept
static constexpr field zero()
static const size_t ARITHMETIC
static const size_t DELTA_RANGE
static const size_t LOOKUP
static const size_t ELLIPTIC
static const size_t q_elliptic
static const size_t q_lookup
static const size_t q_nnf
static const size_t curve_b
static const size_t q_arith
static const size_t q_delta_range
static const size_t w_4_shift
static const size_t w_l_shift
static const size_t w_o_shift
static const size_t w_r_shift
Serialized state of a circuit.