17 const std::string&
tag,
21 circuit_info.variables,
22 circuit_info.public_inps,
23 circuit_info.real_variable_index,
24 circuit_info.real_variable_tags,
29 , selectors(circuit_info.selectors)
30 , wires_idxs(circuit_info.wires)
31 , lookup_tables(circuit_info.lookup_tables)
32 , range_tags(circuit_info.range_tags)
33 , rom_records(circuit_info.rom_records)
34 , rom_states(circuit_info.rom_states)
35 , ram_records(circuit_info.ram_records)
36 , ram_states(circuit_info.ram_states)
37 , rom_ram_relaxed(rom_ram_relaxed)
42 size_t arith_cursor = 0;
47 size_t elliptic_cursor = 0;
52 size_t lookup_cursor = 0;
57 size_t nnf_cursor = 0;
70 info(
"Finished solver prep");
105 std::vector<bb::fr> this_gate = { q_m, q_l, q_r, q_o, q_c, q_arith, q_4 };
107 std::vector<bb::fr> boolean_gate = { 1, -1, 0, 0, 0, 1, 0 };
108 bool boolean_gate_flag = (boolean_gate == this_gate) && (w_l_idx == w_r_idx) && (w_o_idx == 0) && (w_4_idx == 0);
109 if (boolean_gate_flag) {
115 std::vector<bb::fr> fix_witness_gate = { 0, 1, 0, 0, q_c, 1, 0 };
116 bool put_constant_variable_flag =
117 (fix_witness_gate == this_gate) && (w_r_idx == 0) && (w_o_idx == 0) && (w_4_idx == 0);
118 if (put_constant_variable_flag) {
128 res += ((q_arith - 3) * q_m * neg_half) * w_r * w_l;
146 res += (q_arith - 1) * w_4_shift;
158 if (q_arith * (q_arith - 1) * (q_arith - 2) != 0) {
159 res = w_l + w_4 - w_l_shift + q_m;
173 const size_t table_offset =
static_cast<size_t>(table_idx) - 1;
182 new_table.push_back(tmp_entry);
184 is_xor &= (
static_cast<uint256_t>(table_entry[0]) ^
static_cast<uint256_t>(table_entry[1])) ==
186 is_and &= (
static_cast<uint256_t>(table_entry[0]) &
static_cast<uint256_t>(table_entry[1])) ==
190 std::string table_name;
201 this->
tables_sizes.insert({ table_idx, new_table.size() });
242 auto table_idx =
static_cast<uint32_t
>(q_o);
248 STerm second_entry = this->symbolic_vars[w_r_idx] + q_m * this->symbolic_vars[w_r_shift_idx];
249 STerm third_entry = this->symbolic_vars[w_o_idx] + q_c * this->symbolic_vars[w_o_shift_idx];
254 if (q_r == -64 && q_m == -64 && q_c == -64) {
255 this->symbolic_vars[w_l_shift_idx] = this->symbolic_vars[w_l_idx] >> 6;
256 this->symbolic_vars[w_r_shift_idx] = this->symbolic_vars[w_r_idx] >> 6;
257 this->symbolic_vars[w_o_shift_idx] = this->symbolic_vars[w_o_idx] >> 6;
260 auto sqrt = [](
size_t table_size) ->
size_t {
261 auto [is_sqr, res] =
bb::fr(table_size).
sqrt();
262 info(
"Is square: ", is_sqr);
268 return static_cast<size_t>(ures);
273 info(
"XOR optimization");
276 first_entry < max_val;
277 second_entry < max_val;
278 third_entry < max_val;
280 (first_entry ^ second_entry) == third_entry;
284 info(
"AND optimization");
287 first_entry < max_val;
288 second_entry < max_val;
289 third_entry < max_val;
291 (first_entry & second_entry) == third_entry;
298 info(
"Unknown Table");
299 STuple entries({ first_entry, second_entry, third_entry });
339 auto x_diff = (x_2 - x_1);
340 auto y2_sqr = (y_2 * y_2);
341 auto y1_sqr = (y_1 * y_1);
342 auto y1y2 = y_1 * y_2 * q_sign;
343 auto x_add_identity = (x_3 + x_2 + x_1) * x_diff * x_diff - y2_sqr - y1_sqr + y1y2 + y1y2;
345 auto y1_plus_y3 = y_1 + y_3;
346 auto y_diff = y_2 * q_sign - y_1;
347 auto y_add_identity = y1_plus_y3 * x_diff + (x_3 - x_1) * y_diff;
355 auto x_pow_4 = (y1_sqr - curve_b) * x_1;
356 auto y1_sqr_mul_4 = y1_sqr + y1_sqr;
357 y1_sqr_mul_4 += y1_sqr_mul_4;
358 auto x1_pow_4_mul_9 = x_pow_4 * 9;
359 auto x_double_identity = (x_3 + x_1 + x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9;
361 auto x1_sqr_mul_3 = (x_1 + x_1 + x_1) * x_1;
362 auto y_double_identity = x1_sqr_mul_3 * (x_1 - x_3) - (y_1 + y_1) * (y_1 + y_3);
365 x_double_identity == 0;
366 y_double_identity == 0;
382 if (q_delta_range == 0) {
398 STerm delta_1 = w_2 - w_1;
399 STerm delta_2 = w_3 - w_2;
400 STerm delta_3 = w_4 - w_3;
401 STerm delta_4 = w_1_shift - w_4;
403 STerm tmp = (delta_1 - 1) * (delta_1 - 1) - 1;
404 tmp *= (delta_1 - 2) * (delta_1 - 2) - 1;
407 tmp = (delta_2 - 1) * (delta_2 - 1) - 1;
408 tmp *= (delta_2 - 2) * (delta_2 - 2) - 1;
411 tmp = (delta_3 - 1) * (delta_3 - 1) - 1;
412 tmp *= (delta_3 - 2) * (delta_3 - 2) - 1;
415 tmp = (delta_4 - 1) * (delta_4 - 1) - 1;
416 tmp *= (delta_4 - 2) * (delta_4 - 2) - 1;
438 for (
size_t entry = 0; entry <= range; entry++) {
443 info(
RED,
"Initialized new range: ", table_name,
RESET);
496 size_t entry_flag = 0;
498 if (q_3 != 0 && q_4 != 0) {
502 STerm limb_accumulator_1 = w_2_shift * SUBLIMB_SHIFT;
503 limb_accumulator_1 += w_1_shift;
504 limb_accumulator_1 *= SUBLIMB_SHIFT;
505 limb_accumulator_1 += w_3;
506 limb_accumulator_1 *= SUBLIMB_SHIFT;
507 limb_accumulator_1 += w_2;
508 limb_accumulator_1 *= SUBLIMB_SHIFT;
509 limb_accumulator_1 += w_1;
510 limb_accumulator_1 -= w_4;
511 limb_accumulator_1 == 0;
514 if (q_3 != 0 && q_m != 0) {
518 STerm limb_accumulator_2 = w_3_shift * SUBLIMB_SHIFT;
519 limb_accumulator_2 += w_2_shift;
520 limb_accumulator_2 *= SUBLIMB_SHIFT;
521 limb_accumulator_2 += w_1_shift;
522 limb_accumulator_2 *= SUBLIMB_SHIFT;
523 limb_accumulator_2 += w_4;
524 limb_accumulator_2 *= SUBLIMB_SHIFT;
525 limb_accumulator_2 += w_3;
526 limb_accumulator_2 -= w_4_shift;
527 limb_accumulator_2 == 0;
530 STerm limb_subproduct = w_1 * w_2_shift + w_1_shift * w_2;
531 if (q_2 != 0 && q_4 != 0) {
535 STerm non_native_field_gate_2 = (w_1 * w_4 + w_2 * w_3 - w_3_shift);
536 non_native_field_gate_2 *= LIMB_SIZE;
537 non_native_field_gate_2 -= w_4_shift;
538 non_native_field_gate_2 += limb_subproduct;
539 non_native_field_gate_2 == 0;
542 limb_subproduct *= LIMB_SIZE;
543 limb_subproduct += (w_1_shift * w_2_shift);
544 if (q_2 != 0 && q_3 != 0) {
548 STerm non_native_field_gate_1 = limb_subproduct;
549 non_native_field_gate_1 -= (w_3 + w_4);
550 non_native_field_gate_1 == 0;
553 if (q_2 != 0 && q_m != 0) {
557 STerm non_native_field_gate_3 = limb_subproduct;
558 non_native_field_gate_3 += w_4;
559 non_native_field_gate_3 -= (w_3_shift + w_4_shift);
560 non_native_field_gate_3 == 0;
563 if (entry_flag > 1) {
564 throw std::runtime_error(
"Double entry in NNF");
578 uint32_t rom_index_idx,
579 uint32_t read_to_value1_idx,
580 uint32_t read_to_value2_idx)
582 if (this->
public_inps.contains(rom_index_idx) ||
this->rom_ram_relaxed) {
593 STuple value_entry({ value1, value2 });
595 table_entry == value_entry;
607 if (this->
public_inps.contains(ram_index_idx) ||
this->rom_ram_relaxed) {
618 table_entry == value_entry;
630 if (this->
public_inps.contains(ram_index_idx) ||
this->rom_ram_relaxed) {
648 static constexpr uint32_t UNINITIALIZED_MEMORY_RECORD = UINT32_MAX;
651 STuple entry_ex({ idx_ex, idx_ex });
653 cvc5::Sort ind_sort = idx_ex.
term.getSort();
655 cvc5::Sort entry_sort = entry_ex.term.getSort();
656 TermType entry_type = entry_ex.type;
658 for (uint32_t i = 0; i < this->
rom_records.size(); i++) {
662 for (
size_t j = 0; j < this->
rom_states[i].size(); j++) {
664 if (this->
rom_states[i][j][0] == UNINITIALIZED_MEMORY_RECORD) {
670 rom_table.
put(idx,
STuple({ value1, value2 }));
676 uint32_t index_witness = rom_record[0];
677 uint32_t value1_witness = rom_record[1];
678 uint32_t value2_witness = rom_record[2];
679 this->
rom_table_read(i, index_witness, value1_witness, value2_witness);
691 STuple entry_ex({ idx_ex, idx_ex });
693 cvc5::Sort sort = idx_ex.
term.getSort();
696 for (uint32_t i = 0; i < this->
ram_records.size(); i++) {
702 uint32_t index_witness = ram_record[0];
703 uint32_t value_witness = ram_record[1];
705 uint32_t access_type = ram_record[3];
706 switch (access_type) {
714 info(
"Reached an invalid access type");
733 if (witness.size() !=
this->get_num_vars()) {
760 const std::vector<std::string>& equal,
761 const std::vector<std::string>& not_equal,
762 const std::vector<std::string>& equal_at_the_same_time,
763 const std::vector<std::string>& not_equal_at_the_same_time,
764 bool enable_optimizations)
769 for (
const auto& term : equal) {
770 c1[term] == c2[term];
772 for (
const auto& term : not_equal) {
773 c1[term] != c2[term];
777 for (
const auto& term : equal_at_the_same_time) {
782 if (eqs.size() > 1) {
783 batch_or(eqs).assert_term();
784 }
else if (eqs.size() == 1) {
785 eqs[0].assert_term();
789 for (
const auto& term : not_equal_at_the_same_time) {
794 if (neqs.size() > 1) {
795 batch_or(neqs).assert_term();
796 }
else if (neqs.size() == 1) {
797 neqs[0].assert_term();
818 const std::vector<std::string>& equal,
819 bool enable_optimizations)
824 for (
const auto& term : equal) {
825 c1[term] == c2[term];
830 uint32_t i = node.first;
841 if (neqs.size() > 1) {
842 batch_or(neqs).assert_term();
843 }
else if (neqs.size() == 1) {
844 neqs[0].assert_term();
#define BB_ASSERT_GT(left, right,...)
#define BB_ASSERT_LT(left, right,...)
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.