21#include <unordered_map>
22#include <unordered_set>
26template <
typename ExecutionTrace>
54 if (!circuit_finalized) {
56 add_gates_to_ensure_all_polys_are_non_zero();
58 process_non_native_field_multiplications();
60 this->rom_ram_logic.process_ROM_arrays(
this);
61 this->rom_ram_logic.process_RAM_arrays(
this);
62 process_range_lists();
64 populate_public_inputs_block();
65 circuit_finalized =
true;
68 info(
"WARNING: Redundant call to finalize_circuit(). Is this intentional?");
80 for (
const auto& idx : this->public_inputs()) {
82 blocks.pub_inputs.populate_wires(idx, idx, this->zero_idx(), this->zero_idx());
83 for (
auto& selector : this->blocks.pub_inputs.get_selectors()) {
84 selector.emplace_back(0);
97template <
typename ExecutionTrace>
101 blocks.arithmetic.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
102 blocks.arithmetic.q_m().emplace_back(1);
103 blocks.arithmetic.q_1().emplace_back(1);
104 blocks.arithmetic.q_2().emplace_back(1);
105 blocks.arithmetic.q_3().emplace_back(1);
106 blocks.arithmetic.q_4().emplace_back(1);
107 blocks.arithmetic.q_c().emplace_back(0);
108 blocks.arithmetic.set_gate_selector(0);
109 check_selector_length_consistency();
110 this->increment_num_gates();
113 blocks.delta_range.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
114 blocks.delta_range.q_m().emplace_back(0);
115 blocks.delta_range.q_1().emplace_back(0);
116 blocks.delta_range.q_2().emplace_back(0);
117 blocks.delta_range.q_3().emplace_back(0);
118 blocks.delta_range.q_4().emplace_back(0);
119 blocks.delta_range.q_c().emplace_back(0);
120 blocks.delta_range.set_gate_selector(1);
122 check_selector_length_consistency();
123 this->increment_num_gates();
124 create_unconstrained_gate(
125 blocks.delta_range, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
128 blocks.elliptic.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
129 blocks.elliptic.q_m().emplace_back(0);
130 blocks.elliptic.q_1().emplace_back(0);
131 blocks.elliptic.q_2().emplace_back(0);
132 blocks.elliptic.q_3().emplace_back(0);
133 blocks.elliptic.q_4().emplace_back(0);
134 blocks.elliptic.q_c().emplace_back(0);
135 blocks.elliptic.set_gate_selector(1);
136 check_selector_length_consistency();
137 this->increment_num_gates();
138 create_unconstrained_gate(blocks.elliptic, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
141 blocks.memory.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
142 blocks.memory.q_m().emplace_back(0);
143 blocks.memory.q_1().emplace_back(0);
144 blocks.memory.q_2().emplace_back(0);
145 blocks.memory.q_3().emplace_back(0);
146 blocks.memory.q_4().emplace_back(0);
147 blocks.memory.q_c().emplace_back(0);
148 blocks.memory.set_gate_selector(1);
149 check_selector_length_consistency();
150 this->increment_num_gates();
151 create_unconstrained_gate(blocks.memory, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
154 blocks.nnf.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
155 blocks.nnf.q_m().emplace_back(0);
156 blocks.nnf.q_1().emplace_back(0);
157 blocks.nnf.q_2().emplace_back(0);
158 blocks.nnf.q_3().emplace_back(0);
159 blocks.nnf.q_4().emplace_back(0);
160 blocks.nnf.q_c().emplace_back(0);
161 blocks.nnf.set_gate_selector(1);
162 check_selector_length_consistency();
163 this->increment_num_gates();
164 create_unconstrained_gate(blocks.nnf, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
167 uint32_t one_idx = put_constant_variable(
FF::one());
168 create_big_add_gate({ this->zero_idx(), this->zero_idx(), this->zero_idx(), one_idx, 0, 0, 0, 1, -1 });
177 uint32_t left_value = 3;
178 uint32_t right_value = 3;
183 uint32_t left_witness_index = this->add_variable(left_witness_value);
184 uint32_t right_witness_index = this->add_variable(right_witness_value);
187 auto read_data = create_gates_from_plookup_accumulators(
190 update_used_witnesses(left_witness_index);
191 update_used_witnesses(right_witness_index);
195 for (
const auto& column : parse_read_data) {
196 update_used_witnesses(column);
197 update_finalize_witnesses(column);
201 blocks.poseidon2_external.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
202 blocks.poseidon2_external.q_m().emplace_back(0);
203 blocks.poseidon2_external.q_1().emplace_back(0);
204 blocks.poseidon2_external.q_2().emplace_back(0);
205 blocks.poseidon2_external.q_3().emplace_back(0);
206 blocks.poseidon2_external.q_c().emplace_back(0);
207 blocks.poseidon2_external.q_4().emplace_back(0);
208 blocks.poseidon2_external.set_gate_selector(1);
209 check_selector_length_consistency();
210 this->increment_num_gates();
213 create_unconstrained_gate(
214 blocks.poseidon2_external, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
217 blocks.poseidon2_internal.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
218 blocks.poseidon2_internal.q_m().emplace_back(0);
219 blocks.poseidon2_internal.q_1().emplace_back(0);
220 blocks.poseidon2_internal.q_2().emplace_back(0);
221 blocks.poseidon2_internal.q_3().emplace_back(0);
222 blocks.poseidon2_internal.q_c().emplace_back(0);
223 blocks.poseidon2_internal.q_4().emplace_back(0);
224 blocks.poseidon2_internal.set_gate_selector(1);
225 check_selector_length_consistency();
226 this->increment_num_gates();
229 create_unconstrained_gate(
230 blocks.poseidon2_internal, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
244 create_big_add_gate({ .a = in.
a,
247 .d = this->zero_idx(),
263template <
typename ExecutionTrace>
265 const bool include_next_gate_w_4)
267 this->assert_valid_variables({ in.
a, in.
b, in.
c, in.
d });
268 blocks.arithmetic.populate_wires(in.
a, in.
b, in.
c, in.
d);
273 blocks.arithmetic.q_m().emplace_back(mul_scaling);
274 blocks.arithmetic.q_1().emplace_back(in.
a_scaling);
275 blocks.arithmetic.q_2().emplace_back(in.
b_scaling);
276 blocks.arithmetic.q_3().emplace_back(in.
c_scaling);
278 blocks.arithmetic.q_4().emplace_back(in.
d_scaling);
279 blocks.arithmetic.set_gate_selector(include_next_gate_w_4 ? 2 : 1);
280 check_selector_length_consistency();
281 this->increment_num_gates();
292template <
typename ExecutionTrace>
294 const bool include_next_gate_w_4)
296 this->assert_valid_variables({ in.
a, in.
b, in.
c, in.
d });
297 blocks.arithmetic.populate_wires(in.
a, in.
b, in.
c, in.
d);
298 blocks.arithmetic.q_m().emplace_back(0);
300 blocks.arithmetic.q_2().emplace_back(in.
b_scaling);
303 blocks.arithmetic.q_4().emplace_back(in.
d_scaling);
304 blocks.arithmetic.set_gate_selector(include_next_gate_w_4 ? 2 : 1);
305 check_selector_length_consistency();
306 this->increment_num_gates();
314template <
typename ExecutionTrace>
317 this->assert_valid_variables({ variable_index });
319 blocks.arithmetic.populate_wires(variable_index, variable_index, this->zero_idx(), this->zero_idx());
320 blocks.arithmetic.q_m().emplace_back(1);
321 blocks.arithmetic.q_1().emplace_back(-1);
322 blocks.arithmetic.q_2().emplace_back(0);
323 blocks.arithmetic.q_3().emplace_back(0);
324 blocks.arithmetic.q_c().emplace_back(0);
325 blocks.arithmetic.q_4().emplace_back(0);
326 blocks.arithmetic.set_gate_selector(1);
327 check_selector_length_consistency();
328 this->increment_num_gates();
337template <
typename ExecutionTrace>
340 this->assert_valid_variables({ in.
a, in.
b, in.
c });
342 blocks.arithmetic.populate_wires(in.
a, in.
b, in.
c, this->zero_idx());
343 blocks.arithmetic.q_m().emplace_back(in.
q_m);
344 blocks.arithmetic.q_1().emplace_back(in.
q_l);
345 blocks.arithmetic.q_2().emplace_back(in.
q_r);
346 blocks.arithmetic.q_3().emplace_back(in.
q_o);
347 blocks.arithmetic.q_c().emplace_back(in.
q_c);
348 blocks.arithmetic.q_4().emplace_back(0);
349 blocks.arithmetic.set_gate_selector(1);
350 check_selector_length_consistency();
351 this->increment_num_gates();
370template <
typename ExecutionTrace>
373 this->assert_valid_variables({ in.
x1, in.
x2, in.
x3, in.
y1, in.
y2, in.
y3 });
375 auto& block = blocks.elliptic;
378 bool can_fuse_into_previous_gate =
380 block.w_r()[block.size() - 1] == in.
x1 &&
381 block.w_o()[block.size() - 1] == in.
y1;
383 if (can_fuse_into_previous_gate) {
385 block.q_elliptic().set(block.size() - 1, 1);
387 block.populate_wires(this->zero_idx(), in.
x1, in.
y1, this->zero_idx());
388 block.q_3().emplace_back(0);
389 block.q_4().emplace_back(0);
392 block.q_2().emplace_back(0);
393 block.q_m().emplace_back(0);
394 block.q_c().emplace_back(0);
395 block.set_gate_selector(1);
396 check_selector_length_consistency();
397 this->increment_num_gates();
400 create_unconstrained_gate(block, in.
x2, in.
x3, in.
y3, in.
y2);
419template <
typename ExecutionTrace>
422 this->assert_valid_variables({ in.
x1, in.
x3, in.
y1, in.
y3 });
424 auto& block = blocks.elliptic;
427 bool can_fuse_into_previous_gate =
429 block.w_r()[block.size() - 1] == in.
x1 &&
430 block.w_o()[block.size() - 1] == in.
y1;
433 if (can_fuse_into_previous_gate) {
434 block.q_elliptic().set(block.size() - 1, 1);
435 block.q_m().set(block.size() - 1, 1);
437 block.populate_wires(this->zero_idx(), in.
x1, in.
y1, this->zero_idx());
438 block.q_m().emplace_back(1);
439 block.q_1().emplace_back(0);
440 block.q_2().emplace_back(0);
441 block.q_3().emplace_back(0);
442 block.q_c().emplace_back(0);
443 block.q_4().emplace_back(0);
444 block.set_gate_selector(1);
445 check_selector_length_consistency();
446 this->increment_num_gates();
449 create_unconstrained_gate(block, this->zero_idx(), in.
x3, in.
y3, this->zero_idx());
458template <
typename ExecutionTrace>
461 this->assert_valid_variables({ witness_index });
463 blocks.arithmetic.populate_wires(witness_index, this->zero_idx(), this->zero_idx(), this->zero_idx());
464 blocks.arithmetic.q_m().emplace_back(0);
465 blocks.arithmetic.q_1().emplace_back(1);
466 blocks.arithmetic.q_2().emplace_back(0);
467 blocks.arithmetic.q_3().emplace_back(0);
468 blocks.arithmetic.q_c().emplace_back(-witness_value);
469 blocks.arithmetic.q_4().emplace_back(0);
470 blocks.arithmetic.set_gate_selector(1);
471 check_selector_length_consistency();
472 this->increment_num_gates();
475template <
typename ExecutionTrace>
478 if (constant_variable_indices.contains(variable)) {
479 return constant_variable_indices.at(variable);
481 uint32_t variable_index = this->add_variable(variable);
482 fix_witness(variable_index, variable);
483 constant_variable_indices.insert({ variable, variable_index });
484 return variable_index;
496template <
typename ExecutionTrace>
500 if (table.id ==
id) {
506 return lookup_tables.back();
535template <
typename ExecutionTrace>
539 const uint32_t key_a_index,
545 const size_t num_lookups = read_values[ColumnIdx::C1].size();
548 for (
size_t i = 0; i < num_lookups; ++i) {
549 const bool is_first_lookup = (i == 0);
550 const bool is_last_lookup = (i == num_lookups - 1);
557 const auto first_idx = is_first_lookup ? key_a_index : this->add_variable(read_values[ColumnIdx::C1][i]);
558 const auto second_idx = (is_first_lookup && key_b_index.has_value())
560 : this->add_variable(read_values[ColumnIdx::C2][i]);
561 const auto third_idx = this->add_variable(read_values[ColumnIdx::C3][i]);
563 read_data[ColumnIdx::C1].push_back(first_idx);
564 read_data[ColumnIdx::C2].push_back(second_idx);
565 read_data[ColumnIdx::C3].push_back(third_idx);
566 this->assert_valid_variables({ first_idx, second_idx, third_idx });
569 blocks.lookup.populate_wires(first_idx, second_idx, third_idx, this->zero_idx());
570 blocks.lookup.set_gate_selector(1);
573 blocks.lookup.q_2().emplace_back(is_last_lookup ? 0 : -multi_table.column_1_step_sizes[i + 1]);
574 blocks.lookup.q_m().emplace_back(is_last_lookup ? 0 : -multi_table.column_2_step_sizes[i + 1]);
575 blocks.lookup.q_c().emplace_back(is_last_lookup ? 0 : -multi_table.column_3_step_sizes[i + 1]);
576 blocks.lookup.q_1().emplace_back(0);
577 blocks.lookup.q_4().emplace_back(0);
579 check_selector_length_consistency();
580 this->increment_num_gates();
588template <
typename ExecutionTrace>
590 const uint64_t target_range)
593 const auto range_tag = get_new_tag();
594 const auto tau_tag = get_new_tag();
595 set_tau_transposition(range_tag, tau_tag);
600 uint64_t num_multiples_of_three = (target_range / DEFAULT_PLOOKUP_RANGE_STEP_SIZE);
604 for (uint64_t i = 0; i <= num_multiples_of_three; ++i) {
605 const uint32_t
index = this->add_variable(
fr(i * DEFAULT_PLOOKUP_RANGE_STEP_SIZE));
610 const uint32_t
index = this->add_variable(
fr(target_range));
622template <
typename ExecutionTrace>
624 const uint32_t variable_index,
const uint64_t num_bits,
const uint64_t target_range_bitnum, std::string
const& msg)
626 this->assert_valid_variables({ variable_index });
633 if (val.
get_msb() >= num_bits && !this->failed()) {
637 const uint64_t sublimb_mask = (1ULL << target_range_bitnum) - 1;
652 std::vector<uint64_t> sublimbs;
653 std::vector<uint32_t> sublimb_indices;
655 const bool has_remainder_bits = (num_bits % target_range_bitnum != 0);
656 const uint64_t num_limbs = (num_bits / target_range_bitnum) + has_remainder_bits;
657 const uint64_t last_limb_size = num_bits - ((num_bits / target_range_bitnum) * target_range_bitnum);
658 const uint64_t last_limb_range = ((uint64_t)1 << last_limb_size) - 1;
661 for (
size_t i = 0; i < num_limbs; ++i) {
662 sublimbs.push_back(accumulator.
data[0] & sublimb_mask);
663 accumulator = accumulator >> target_range_bitnum;
665 for (
size_t i = 0; i < sublimbs.size(); ++i) {
666 const auto limb_idx = this->add_variable(
bb::fr(sublimbs[i]));
667 sublimb_indices.emplace_back(limb_idx);
668 if ((i == sublimbs.size() - 1) && has_remainder_bits) {
669 create_new_range_constraint(limb_idx, last_limb_range);
671 create_new_range_constraint(limb_idx, sublimb_mask);
675 const uint64_t num_limb_triples = (num_limbs / 3) + ((num_limbs % 3) != 0);
676 const uint64_t leftovers = (num_limbs % 3) == 0 ? 3 : (num_limbs % 3);
679 uint32_t accumulator_idx = variable_index;
681 for (
size_t i = 0; i < num_limb_triples; ++i) {
682 const bool real_limbs[3]{
683 (i == (num_limb_triples - 1) && (leftovers < 1)) ?
false : true,
684 (i == (num_limb_triples - 1) && (leftovers < 2)) ? false : true,
685 (i == (num_limb_triples - 1) && (leftovers < 3)) ? false : true,
688 const uint64_t round_sublimbs[3]{
689 real_limbs[0] ? sublimbs[3 * i] : 0,
690 real_limbs[1] ? sublimbs[3 * i + 1] : 0,
691 real_limbs[2] ? sublimbs[3 * i + 2] : 0,
693 const uint32_t new_limbs[3]{
694 real_limbs[0] ? sublimb_indices[3 * i] : this->zero_idx(),
695 real_limbs[1] ? sublimb_indices[3 * i + 1] : this->zero_idx(),
696 real_limbs[2] ? sublimb_indices[3 * i + 2] : this->zero_idx(),
698 const uint64_t shifts[3]{
699 target_range_bitnum * (3 * i),
700 target_range_bitnum * (3 * i + 1),
701 target_range_bitnum * (3 * i + 2),
703 uint256_t new_accumulator = accumulator - (
uint256_t(round_sublimbs[0]) << shifts[0]) -
704 (
uint256_t(round_sublimbs[1]) << shifts[1]) -
705 (
uint256_t(round_sublimbs[2]) << shifts[2]);
719 ((i == num_limb_triples - 1) ?
false : true));
722 accumulator_idx = this->add_variable(
fr(new_accumulator));
723 accumulator = new_accumulator;
725 return sublimb_indices;
737template <
typename ExecutionTrace>
739 const uint64_t target_range,
740 std::string
const msg)
742 const bool is_out_of_range = (
uint256_t(this->get_variable(variable_index)).
data[0] > target_range);
743 if (is_out_of_range && !this->failed()) {
746 if (range_lists.count(target_range) == 0) {
747 range_lists.insert({ target_range, create_range_list(target_range) });
750 const auto existing_tag = this->real_variable_tags[this->real_variable_index[variable_index]];
751 auto& list = range_lists[target_range];
754 if (existing_tag != list.range_tag) {
757 if (existing_tag != DUMMY_TAG) {
758 bool found_tag =
false;
759 for (
const auto& r : range_lists) {
760 if (r.second.range_tag == existing_tag) {
762 if (r.first < target_range) {
769 const uint32_t copied_witness = this->add_variable(this->get_variable(variable_index));
770 create_add_gate({ .a = variable_index,
772 .c = this->zero_idx(),
776 .const_scaling = 0 });
778 create_new_range_constraint(copied_witness, target_range, msg);
785 assign_tag(variable_index, list.range_tag);
786 list.variable_indices.emplace_back(variable_index);
800 x = this->real_variable_index[x];
810 std::vector<uint32_t> sorted_list;
813 const auto& field_element = this->get_variable(variable_index);
814 const uint32_t shrinked_value = (uint32_t)field_element.from_montgomery_form().data[0];
815 sorted_list.emplace_back(shrinked_value);
819 std::sort(sorted_list.begin(), sorted_list.end());
821 std::sort(std::execution::par_unseq, sorted_list.begin(), sorted_list.end());
824 constexpr size_t gate_width = NUM_WIRES;
825 size_t padding = (gate_width - (list.
variable_indices.size() % gate_width)) % gate_width;
827 std::vector<uint32_t> indices;
828 indices.reserve(padding + sorted_list.size());
831 padding += gate_width;
833 for (
size_t i = 0; i < padding; ++i) {
834 indices.emplace_back(this->zero_idx());
836 for (
const auto sorted_value : sorted_list) {
837 const uint32_t
index = this->add_variable(
fr(sorted_value));
839 indices.emplace_back(
index);
841 create_sort_constraint_with_edges(indices, 0, list.
target_range);
846 for (
auto& i : range_lists) {
847 process_range_list(i.second);
864template <
typename ExecutionTrace>
867 constexpr size_t gate_width = NUM_WIRES;
869 this->assert_valid_variables(variable_index);
871 for (
size_t i = 0; i < variable_index.size(); i += gate_width) {
872 blocks.delta_range.populate_wires(
873 variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]);
875 this->increment_num_gates();
876 blocks.delta_range.q_m().emplace_back(0);
877 blocks.delta_range.q_1().emplace_back(0);
878 blocks.delta_range.q_2().emplace_back(0);
879 blocks.delta_range.q_3().emplace_back(0);
880 blocks.delta_range.q_c().emplace_back(0);
881 blocks.delta_range.q_4().emplace_back(0);
882 blocks.delta_range.set_gate_selector(1);
883 check_selector_length_consistency();
886 create_unconstrained_gate(blocks.delta_range,
887 variable_index[variable_index.size() - 1],
895template <
typename ExecutionTrace>
898 std::vector<uint32_t> padded_list = variable_index;
899 constexpr size_t gate_width = NUM_WIRES;
900 const uint64_t padding = (gate_width - (padded_list.size() % gate_width)) % gate_width;
901 for (uint64_t i = 0; i < padding; ++i) {
902 padded_list.emplace_back(this->zero_idx());
904 this->assert_valid_variables(variable_index);
905 this->assert_valid_variables(padded_list);
907 for (
size_t i = 0; i < padded_list.size(); i += gate_width) {
908 create_unconstrained_gate(
909 blocks.arithmetic, padded_list[i], padded_list[i + 1], padded_list[i + 2], padded_list[i + 3]);
914template <
typename ExecutionTrace>
916 const std::vector<uint32_t>& variable_index,
const FF& start,
const FF& end)
919 constexpr size_t gate_width = NUM_WIRES;
922 this->assert_valid_variables(variable_index);
924 auto& block = blocks.delta_range;
927 create_add_gate({ variable_index[0], this->zero_idx(), this->zero_idx(), 1, 0, 0, -start });
930 for (
size_t i = 0; i < variable_index.size() - gate_width; i += gate_width) {
932 block.populate_wires(variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]);
933 this->increment_num_gates();
934 block.q_m().emplace_back(0);
935 block.q_1().emplace_back(0);
936 block.q_2().emplace_back(0);
937 block.q_3().emplace_back(0);
938 block.q_c().emplace_back(0);
939 block.q_4().emplace_back(0);
940 block.set_gate_selector(1);
941 check_selector_length_consistency();
944 if (variable_index.size() > gate_width) {
945 block.populate_wires(variable_index[variable_index.size() - 4],
946 variable_index[variable_index.size() - 3],
947 variable_index[variable_index.size() - 2],
948 variable_index[variable_index.size() - 1]);
949 this->increment_num_gates();
950 block.q_m().emplace_back(0);
951 block.q_1().emplace_back(0);
952 block.q_2().emplace_back(0);
953 block.q_3().emplace_back(0);
954 block.q_c().emplace_back(0);
955 block.q_4().emplace_back(0);
956 block.set_gate_selector(1);
957 check_selector_length_consistency();
964 create_unconstrained_gate(
965 block, variable_index[variable_index.size() - 1], this->zero_idx(), this->zero_idx(), this->zero_idx());
966 create_add_gate({ variable_index[variable_index.size() - 1], this->zero_idx(), this->zero_idx(), 1, 0, 0, -end });
991template <
typename ExecutionTrace>
994 auto& block = blocks.memory;
995 block.set_gate_selector(
type == MEMORY_SELECTORS::MEM_NONE ? 0 : 1);
997 case MEMORY_SELECTORS::ROM_CONSISTENCY_CHECK: {
1002 block.q_1().emplace_back(1);
1003 block.q_2().emplace_back(1);
1004 block.q_3().emplace_back(0);
1005 block.q_4().emplace_back(0);
1006 block.q_m().emplace_back(0);
1007 block.q_c().emplace_back(0);
1008 check_selector_length_consistency();
1011 case MEMORY_SELECTORS::RAM_CONSISTENCY_CHECK: {
1017 block.q_1().emplace_back(0);
1018 block.q_2().emplace_back(0);
1019 block.q_3().emplace_back(1);
1020 block.q_4().emplace_back(0);
1021 block.q_m().emplace_back(0);
1022 block.q_c().emplace_back(0);
1023 check_selector_length_consistency();
1026 case MEMORY_SELECTORS::RAM_TIMESTAMP_CHECK: {
1029 block.q_1().emplace_back(1);
1030 block.q_2().emplace_back(0);
1031 block.q_3().emplace_back(0);
1032 block.q_4().emplace_back(1);
1033 block.q_m().emplace_back(0);
1034 block.q_c().emplace_back(0);
1035 check_selector_length_consistency();
1038 case MEMORY_SELECTORS::ROM_READ: {
1042 block.q_1().emplace_back(1);
1043 block.q_2().emplace_back(0);
1044 block.q_3().emplace_back(0);
1045 block.q_4().emplace_back(0);
1046 block.q_m().emplace_back(1);
1047 block.q_c().emplace_back(0);
1048 check_selector_length_consistency();
1051 case MEMORY_SELECTORS::RAM_READ: {
1055 block.q_1().emplace_back(1);
1056 block.q_2().emplace_back(0);
1057 block.q_3().emplace_back(0);
1058 block.q_4().emplace_back(0);
1059 block.q_m().emplace_back(1);
1060 block.q_c().emplace_back(0);
1061 check_selector_length_consistency();
1064 case MEMORY_SELECTORS::RAM_WRITE: {
1068 block.q_1().emplace_back(1);
1069 block.q_2().emplace_back(0);
1070 block.q_3().emplace_back(0);
1071 block.q_4().emplace_back(0);
1072 block.q_m().emplace_back(1);
1073 block.q_c().emplace_back(1);
1074 check_selector_length_consistency();
1078 block.q_1().emplace_back(0);
1079 block.q_2().emplace_back(0);
1080 block.q_3().emplace_back(0);
1081 block.q_4().emplace_back(0);
1082 block.q_m().emplace_back(0);
1083 block.q_c().emplace_back(0);
1084 check_selector_length_consistency();
1113template <
typename ExecutionTrace>
1116 auto& block = blocks.nnf;
1117 block.set_gate_selector(
type == NNF_SELECTORS::NNF_NONE ? 0 : 1);
1119 case NNF_SELECTORS::LIMB_ACCUMULATE_1: {
1120 block.q_1().emplace_back(0);
1121 block.q_2().emplace_back(0);
1122 block.q_3().emplace_back(1);
1123 block.q_4().emplace_back(1);
1124 block.q_m().emplace_back(0);
1125 block.q_c().emplace_back(0);
1126 check_selector_length_consistency();
1129 case NNF_SELECTORS::LIMB_ACCUMULATE_2: {
1130 block.q_1().emplace_back(0);
1131 block.q_2().emplace_back(0);
1132 block.q_3().emplace_back(1);
1133 block.q_4().emplace_back(0);
1134 block.q_m().emplace_back(1);
1135 block.q_c().emplace_back(0);
1136 check_selector_length_consistency();
1139 case NNF_SELECTORS::NON_NATIVE_FIELD_1: {
1140 block.q_1().emplace_back(0);
1141 block.q_2().emplace_back(1);
1142 block.q_3().emplace_back(1);
1143 block.q_4().emplace_back(0);
1144 block.q_m().emplace_back(0);
1145 block.q_c().emplace_back(0);
1146 check_selector_length_consistency();
1149 case NNF_SELECTORS::NON_NATIVE_FIELD_2: {
1150 block.q_1().emplace_back(0);
1151 block.q_2().emplace_back(1);
1152 block.q_3().emplace_back(0);
1153 block.q_4().emplace_back(1);
1154 block.q_m().emplace_back(0);
1155 block.q_c().emplace_back(0);
1156 check_selector_length_consistency();
1159 case NNF_SELECTORS::NON_NATIVE_FIELD_3: {
1160 block.q_1().emplace_back(0);
1161 block.q_2().emplace_back(1);
1162 block.q_3().emplace_back(0);
1163 block.q_4().emplace_back(0);
1164 block.q_m().emplace_back(1);
1165 block.q_c().emplace_back(0);
1166 check_selector_length_consistency();
1170 block.q_1().emplace_back(0);
1171 block.q_2().emplace_back(0);
1172 block.q_3().emplace_back(0);
1173 block.q_4().emplace_back(0);
1174 block.q_m().emplace_back(0);
1175 block.q_c().emplace_back(0);
1176 check_selector_length_consistency();
1192template <
typename ExecutionTrace>
1194 const uint32_t hi_idx,
1195 const size_t lo_limb_bits,
1196 const size_t hi_limb_bits,
1197 std::string
const& msg)
1205 const bool is_lo_out_of_range = (
uint256_t(this->get_variable(lo_idx)) >= (
uint256_t(1) << lo_limb_bits));
1206 if (is_lo_out_of_range && !this->failed()) {
1207 this->failure(msg +
": lo limb.");
1209 const bool is_hi_out_of_range = (
uint256_t(this->get_variable(hi_idx)) >= (
uint256_t(1) << hi_limb_bits));
1210 if (is_hi_out_of_range && !this->failed()) {
1211 this->failure(msg +
": hi limb.");
1215 const auto get_sublimbs = [&](
const uint32_t& limb_idx,
const std::array<uint64_t, 5>& sublimb_masks) {
1216 const uint256_t limb = this->get_variable(limb_idx);
1222 sublimb_indices[0] = sublimb_masks[0] != 0 ? this->add_variable(
fr(limb & MAX_SUBLIMB_MASK)) : this->zero_idx();
1223 sublimb_indices[1] =
1224 sublimb_masks[1] != 0 ? this->add_variable(
fr((limb >> 14) & MAX_SUBLIMB_MASK)) : this->zero_idx();
1225 sublimb_indices[2] =
1226 sublimb_masks[2] != 0 ? this->add_variable(
fr((limb >> 28) & MAX_SUBLIMB_MASK)) : this->zero_idx();
1227 sublimb_indices[3] =
1228 sublimb_masks[3] != 0 ? this->add_variable(
fr((limb >> 42) & MAX_SUBLIMB_MASK)) : this->zero_idx();
1229 sublimb_indices[4] =
1230 sublimb_masks[4] != 0 ? this->add_variable(
fr((limb >> 56) & MAX_SUBLIMB_MASK)) : this->zero_idx();
1231 return sublimb_indices;
1234 const auto get_limb_masks = [](
size_t limb_bits) {
1235 std::array<uint64_t, 5> sublimb_masks;
1236 sublimb_masks[0] = limb_bits >= 14 ? 14 : limb_bits;
1237 sublimb_masks[1] = limb_bits >= 28 ? 14 : (limb_bits > 14 ? limb_bits - 14 : 0);
1238 sublimb_masks[2] = limb_bits >= 42 ? 14 : (limb_bits > 28 ? limb_bits - 28 : 0);
1239 sublimb_masks[3] = limb_bits >= 56 ? 14 : (limb_bits > 42 ? limb_bits - 42 : 0);
1240 sublimb_masks[4] = (limb_bits > 56 ? limb_bits - 56 : 0);
1242 for (
auto& mask : sublimb_masks) {
1243 mask = (1ULL << mask) - 1ULL;
1245 return sublimb_masks;
1248 const auto lo_masks = get_limb_masks(lo_limb_bits);
1249 const auto hi_masks = get_limb_masks(hi_limb_bits);
1253 blocks.nnf.populate_wires(lo_sublimbs[0], lo_sublimbs[1], lo_sublimbs[2], lo_idx);
1254 blocks.nnf.populate_wires(lo_sublimbs[3], lo_sublimbs[4], hi_sublimbs[0], hi_sublimbs[1]);
1255 blocks.nnf.populate_wires(hi_sublimbs[2], hi_sublimbs[3], hi_sublimbs[4], hi_idx);
1257 apply_nnf_selectors(NNF_SELECTORS::LIMB_ACCUMULATE_1);
1258 apply_nnf_selectors(NNF_SELECTORS::LIMB_ACCUMULATE_2);
1259 apply_nnf_selectors(NNF_SELECTORS::NNF_NONE);
1260 this->increment_num_gates(3);
1262 for (
size_t i = 0; i < 5; i++) {
1263 if (lo_masks[i] != 0) {
1264 create_new_range_constraint(lo_sublimbs[i], lo_masks[i],
"ultra_circuit_builder: sublimb of low too large");
1266 if (hi_masks[i] != 0) {
1267 create_new_range_constraint(hi_sublimbs[i], hi_masks[i],
"ultra_circuit_builder: sublimb of hi too large");
1287template <
typename ExecutionTrace>
1291 const auto [a0, a1, a2, a3] = std::array{ this->get_variable(input.
a[0]),
1292 this->get_variable(input.
a[1]),
1293 this->get_variable(input.
a[2]),
1294 this->get_variable(input.
a[3]) };
1295 const auto [b0, b1, b2, b3] = std::array{ this->get_variable(input.
b[0]),
1296 this->get_variable(input.
b[1]),
1297 this->get_variable(input.
b[2]),
1298 this->get_variable(input.
b[3]) };
1299 const auto [q0, q1, q2, q3] = std::array{ this->get_variable(input.
q[0]),
1300 this->get_variable(input.
q[1]),
1301 this->get_variable(input.
q[2]),
1302 this->get_variable(input.
q[3]) };
1303 const auto [r0, r1, r2, r3] = std::array{ this->get_variable(input.
r[0]),
1304 this->get_variable(input.
r[1]),
1305 this->get_variable(input.
r[2]),
1306 this->get_variable(input.
r[3]) };
1309 constexpr FF LIMB_SHIFT =
uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS;
1310 constexpr FF LIMB_RSHIFT =
FF(1) /
FF(
uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS);
1311 constexpr FF LIMB_RSHIFT_2 =
FF(1) /
FF(
uint256_t(1) << (2 * DEFAULT_NON_NATIVE_FIELD_LIMB_BITS));
1314 FF lo_0 = (a0 * b0 - r0) + (a1 * b0 + a0 * b1) * LIMB_SHIFT;
1316 FF lo_1 = (lo_0 + q0 * p_neg[0] + (q1 * p_neg[0] + q0 * p_neg[1] - r1) * LIMB_SHIFT) * LIMB_RSHIFT_2;
1319 FF hi_0 = (a2 * b0 + a0 * b2) + (a0 * b3 + a3 * b0 - r3) * LIMB_SHIFT;
1321 FF hi_1 = hi_0 + (a1 * b1 - r2) + (a1 * b2 + a2 * b1) * LIMB_SHIFT;
1323 FF hi_2 = hi_1 + lo_1 + q2 * p_neg[0] + (q3 * p_neg[0] + q2 * p_neg[1]) * LIMB_SHIFT;
1325 FF hi_3 = (hi_2 + q0 * p_neg[2] + q1 * p_neg[1] + (q0 * p_neg[3] + q1 * p_neg[2]) * LIMB_SHIFT) * LIMB_RSHIFT_2;
1327 const uint32_t lo_0_idx = this->add_variable(lo_0);
1328 const uint32_t lo_1_idx = this->add_variable(lo_1);
1329 const uint32_t hi_0_idx = this->add_variable(hi_0);
1330 const uint32_t hi_1_idx = this->add_variable(hi_1);
1331 const uint32_t hi_2_idx = this->add_variable(hi_2);
1332 const uint32_t hi_3_idx = this->add_variable(hi_3);
1339 create_big_add_gate({ input.
q[0],
1350 create_unconstrained_gate(blocks.arithmetic, this->zero_idx(), this->zero_idx(), this->zero_idx(), lo_0_idx);
1367 blocks.nnf.populate_wires(input.
a[1], input.
b[1], input.
r[0], lo_0_idx);
1368 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_1);
1369 this->increment_num_gates();
1382 blocks.nnf.populate_wires(input.
a[0], input.
b[0], input.
a[3], input.
b[3]);
1383 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_2);
1384 this->increment_num_gates();
1397 blocks.nnf.populate_wires(input.
a[2], input.
b[2], input.
r[3], hi_0_idx);
1398 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_3);
1399 this->increment_num_gates();
1405 blocks.nnf.populate_wires(input.
a[1], input.
b[1], input.
r[2], hi_1_idx);
1406 apply_nnf_selectors(NNF_SELECTORS::NNF_NONE);
1407 this->increment_num_gates();
1414 create_big_add_gate(
1433 create_big_add_gate({
1445 return std::array<uint32_t, 2>{ lo_1_idx, hi_3_idx };
1456 for (
size_t i = 0; i < cached_partial_non_native_field_multiplications.size(); ++i) {
1457 auto& c = cached_partial_non_native_field_multiplications[i];
1458 for (
size_t j = 0; j < c.a.size(); ++j) {
1459 c.a[j] = this->real_variable_index[c.a[j]];
1460 c.b[j] = this->real_variable_index[c.b[j]];
1463 cached_partial_non_native_field_multiplication::deduplicate(cached_partial_non_native_field_multiplications,
this);
1466 for (
const auto& input : cached_partial_non_native_field_multiplications) {
1468 blocks.nnf.populate_wires(input.a[1], input.b[1], this->zero_idx(), input.lo_0);
1469 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_1);
1470 this->increment_num_gates();
1472 blocks.nnf.populate_wires(input.a[0], input.b[0], input.a[3], input.b[3]);
1473 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_2);
1474 this->increment_num_gates();
1476 blocks.nnf.populate_wires(input.a[2], input.b[2], this->zero_idx(), input.hi_0);
1477 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_3);
1478 this->increment_num_gates();
1480 blocks.nnf.populate_wires(input.a[1], input.b[1], this->zero_idx(), input.hi_1);
1481 apply_nnf_selectors(NNF_SELECTORS::NNF_NONE);
1482 this->increment_num_gates();
1492template <
typename ExecutionTrace>
1497 this->get_variable(input.
a[0]),
1498 this->get_variable(input.
a[1]),
1499 this->get_variable(input.
a[2]),
1500 this->get_variable(input.
a[3]),
1503 this->get_variable(input.
b[0]),
1504 this->get_variable(input.
b[1]),
1505 this->get_variable(input.
b[2]),
1506 this->get_variable(input.
b[3]),
1509 constexpr FF LIMB_SHIFT =
uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS;
1511 FF lo_0 =
a[0] *
b[0] + ((
a[1] *
b[0] +
a[0] *
b[1]) * LIMB_SHIFT);
1512 FF hi_0 =
a[2] *
b[0] +
a[0] *
b[2] + ((
a[0] *
b[3] +
a[3] *
b[0]) * LIMB_SHIFT);
1513 FF hi_1 = hi_0 +
a[1] *
b[1] + ((
a[1] *
b[2] +
a[2] *
b[1]) * LIMB_SHIFT);
1515 const uint32_t lo_0_idx = this->add_variable(lo_0);
1516 const uint32_t hi_0_idx = this->add_variable(hi_0);
1517 const uint32_t hi_1_idx = this->add_variable(hi_1);
1527 cached_partial_non_native_field_multiplications.emplace_back(cache_entry);
1528 return std::array<uint32_t, 2>{ lo_0_idx, hi_1_idx };
1536template <
typename ExecutionTrace>
1570 const FF z_0value = (this->get_variable(x_0) * x_mulconst0) + (this->get_variable(y_0) * y_mulconst0) + addconst0;
1571 const FF z_1value = (this->get_variable(x_1) * x_mulconst1) + (this->get_variable(y_1) * y_mulconst1) + addconst1;
1572 const FF z_2value = (this->get_variable(x_2) * x_mulconst2) + (this->get_variable(y_2) * y_mulconst2) + addconst2;
1573 const FF z_3value = (this->get_variable(x_3) * x_mulconst3) + (this->get_variable(y_3) * y_mulconst3) + addconst3;
1574 const FF z_pvalue = this->get_variable(x_p) + this->get_variable(y_p) + addconstp;
1576 const uint32_t z_0 = this->add_variable(z_0value);
1577 const uint32_t z_1 = this->add_variable(z_1value);
1578 const uint32_t z_2 = this->add_variable(z_2value);
1579 const uint32_t z_3 = this->add_variable(z_3value);
1580 const uint32_t z_p = this->add_variable(z_pvalue);
1603 auto& block = blocks.arithmetic;
1604 block.populate_wires(y_p, x_0, y_0, x_p);
1605 block.populate_wires(z_p, x_1, y_1, z_0);
1606 block.populate_wires(x_2, y_2, z_2, z_1);
1607 block.populate_wires(x_3, y_3, z_3, this->zero_idx());
1612 const FF linear_term_scale_factor = 2;
1613 block.q_m().emplace_back(addconstp);
1614 block.q_1().emplace_back(0);
1615 block.q_2().emplace_back(-x_mulconst0 * linear_term_scale_factor);
1616 block.q_3().emplace_back(-y_mulconst0 * linear_term_scale_factor);
1617 block.q_4().emplace_back(0);
1618 block.q_c().emplace_back(-addconst0 * linear_term_scale_factor);
1619 block.set_gate_selector(3);
1621 block.q_m().emplace_back(0);
1622 block.q_1().emplace_back(0);
1623 block.q_2().emplace_back(-x_mulconst1);
1624 block.q_3().emplace_back(-y_mulconst1);
1625 block.q_4().emplace_back(0);
1626 block.q_c().emplace_back(-addconst1);
1627 block.set_gate_selector(2);
1629 block.q_m().emplace_back(0);
1630 block.q_1().emplace_back(-x_mulconst2);
1631 block.q_2().emplace_back(-y_mulconst2);
1632 block.q_3().emplace_back(1);
1633 block.q_4().emplace_back(0);
1634 block.q_c().emplace_back(-addconst2);
1635 block.set_gate_selector(1);
1637 block.q_m().emplace_back(0);
1638 block.q_1().emplace_back(-x_mulconst3);
1639 block.q_2().emplace_back(-y_mulconst3);
1640 block.q_3().emplace_back(1);
1641 block.q_4().emplace_back(0);
1642 block.q_c().emplace_back(-addconst3);
1643 block.set_gate_selector(1);
1645 check_selector_length_consistency();
1647 this->increment_num_gates(4);
1649 z_0, z_1, z_2, z_3, z_p,
1658template <
typename ExecutionTrace>
1692 const FF z_0value = (this->get_variable(x_0) * x_mulconst0) - (this->get_variable(y_0) * y_mulconst0) + addconst0;
1693 const FF z_1value = (this->get_variable(x_1) * x_mulconst1) - (this->get_variable(y_1) * y_mulconst1) + addconst1;
1694 const FF z_2value = (this->get_variable(x_2) * x_mulconst2) - (this->get_variable(y_2) * y_mulconst2) + addconst2;
1695 const FF z_3value = (this->get_variable(x_3) * x_mulconst3) - (this->get_variable(y_3) * y_mulconst3) + addconst3;
1696 const FF z_pvalue = this->get_variable(x_p) - this->get_variable(y_p) + addconstp;
1698 const uint32_t z_0 = this->add_variable(z_0value);
1699 const uint32_t z_1 = this->add_variable(z_1value);
1700 const uint32_t z_2 = this->add_variable(z_2value);
1701 const uint32_t z_3 = this->add_variable(z_3value);
1702 const uint32_t z_p = this->add_variable(z_pvalue);
1728 auto& block = blocks.arithmetic;
1729 block.populate_wires(y_p, x_0, y_0, z_p);
1730 block.populate_wires(x_p, x_1, y_1, z_0);
1731 block.populate_wires(x_2, y_2, z_2, z_1);
1732 block.populate_wires(x_3, y_3, z_3, this->zero_idx());
1737 const FF linear_term_scale_factor = 2;
1738 block.q_m().emplace_back(-addconstp);
1739 block.q_1().emplace_back(0);
1740 block.q_2().emplace_back(-x_mulconst0 * linear_term_scale_factor);
1741 block.q_3().emplace_back(y_mulconst0 * linear_term_scale_factor);
1742 block.q_4().emplace_back(0);
1743 block.q_c().emplace_back(-addconst0 * linear_term_scale_factor);
1744 block.set_gate_selector(3);
1746 block.q_m().emplace_back(0);
1747 block.q_1().emplace_back(0);
1748 block.q_2().emplace_back(-x_mulconst1);
1749 block.q_3().emplace_back(y_mulconst1);
1750 block.q_4().emplace_back(0);
1751 block.q_c().emplace_back(-addconst1);
1752 block.set_gate_selector(2);
1754 block.q_m().emplace_back(0);
1755 block.q_1().emplace_back(-x_mulconst2);
1756 block.q_2().emplace_back(y_mulconst2);
1757 block.q_3().emplace_back(1);
1758 block.q_4().emplace_back(0);
1759 block.q_c().emplace_back(-addconst2);
1760 block.set_gate_selector(1);
1762 block.q_m().emplace_back(0);
1763 block.q_1().emplace_back(-x_mulconst3);
1764 block.q_2().emplace_back(y_mulconst3);
1765 block.q_3().emplace_back(1);
1766 block.q_4().emplace_back(0);
1767 block.q_c().emplace_back(-addconst3);
1768 block.set_gate_selector(1);
1770 check_selector_length_consistency();
1772 this->increment_num_gates(4);
1774 z_0, z_1, z_2, z_3, z_p,
1787template <
typename ExecutionTrace>
1790 return this->rom_ram_logic.create_ROM_array(array_size);
1802template <
typename ExecutionTrace>
1805 return this->rom_ram_logic.create_RAM_array(array_size);
1815template <
typename ExecutionTrace>
1817 const size_t index_value,
1818 const uint32_t value_witness)
1820 this->rom_ram_logic.init_RAM_element(
this, ram_id, index_value, value_witness);
1823template <
typename ExecutionTrace>
1826 return this->rom_ram_logic.read_RAM_array(
this, ram_id, index_witness);
1829template <
typename ExecutionTrace>
1831 const uint32_t index_witness,
1832 const uint32_t value_witness)
1834 this->rom_ram_logic.write_RAM_array(
this, ram_id, index_witness, value_witness);
1852template <
typename ExecutionTrace>
1854 const size_t index_value,
1855 const uint32_t value_witness)
1857 this->rom_ram_logic.set_ROM_element(
this, rom_id, index_value, value_witness);
1867template <
typename ExecutionTrace>
1869 const size_t index_value,
1870 const std::array<uint32_t, 2>& value_witnesses)
1872 this->rom_ram_logic.set_ROM_element_pair(
this, rom_id, index_value, value_witnesses);
1882template <
typename ExecutionTrace>
1885 return this->rom_ram_logic.read_ROM_array(
this, rom_id, index_witness);
1895template <
typename ExecutionTrace>
1897 const uint32_t index_witness)
1899 return this->rom_ram_logic.read_ROM_array_pair(
this, rom_id, index_witness);
1905template <
typename FF>
1908 auto& block = this->blocks.poseidon2_external;
1909 block.populate_wires(in.
a, in.
b, in.
c, in.
d);
1910 block.q_m().emplace_back(0);
1914 block.q_c().emplace_back(0);
1916 block.set_gate_selector(1);
1917 this->check_selector_length_consistency();
1918 this->increment_num_gates();
1924template <
typename FF>
1927 auto& block = this->blocks.poseidon2_internal;
1928 block.populate_wires(in.
a, in.
b, in.
c, in.
d);
1929 block.q_m().emplace_back(0);
1931 block.q_2().emplace_back(0);
1932 block.q_3().emplace_back(0);
1933 block.q_c().emplace_back(0);
1934 block.q_4().emplace_back(0);
1935 block.set_gate_selector(1);
1936 this->check_selector_length_consistency();
1937 this->increment_num_gates();
1950 auto first_zero_idx = this->get_first_variable_in_class(this->zero_idx());
1951 if (!this->variable_names.contains(first_zero_idx)) {
1952 this->set_variable_name(this->zero_idx(),
"zero");
1954 this->variable_names[first_zero_idx] =
"zero";
1960 FF::Params::modulus_0, FF::Params::modulus_1, FF::Params::modulus_2, FF::Params::modulus_3
1962 std::stringstream
buf;
1964 << modulus[1] <<
std::setw(16) << modulus[0];
1968 for (uint32_t i = 0; i < this->num_public_inputs(); i++) {
1969 cir.
public_inps.push_back(this->real_variable_index[this->public_inputs()[i]]);
1972 for (
auto& tup : base::variable_names) {
1973 cir.
vars_of_interest.insert({ this->real_variable_index[tup.first], tup.second });
1976 for (
const auto& var : this->get_variables()) {
1989 for (
auto& block : blocks.get()) {
1992 for (
size_t idx = 0; idx < block.size(); ++idx) {
1993 std::vector<FF> tmp_sel = { block.q_m()[idx],
1999 block.q_arith()[idx],
2000 block.q_delta_range()[idx],
2001 block.q_elliptic()[idx],
2002 block.q_memory()[idx],
2004 block.q_lookup()[idx],
2007 std::vector<uint32_t> tmp_w = {
2008 this->real_variable_index[block.w_l()[idx]],
2009 this->real_variable_index[block.w_r()[idx]],
2010 this->real_variable_index[block.w_o()[idx]],
2011 this->real_variable_index[block.w_4()[idx]],
2014 if (idx < block.size() - 1) {
2015 tmp_w.push_back(block.w_l()[idx + 1]);
2016 tmp_w.push_back(block.w_r()[idx + 1]);
2017 tmp_w.push_back(block.w_o()[idx + 1]);
2018 tmp_w.push_back(block.w_4()[idx + 1]);
2026 block_selectors.push_back(tmp_sel);
2027 block_wires.push_back(tmp_w);
2029 cir.
selectors.push_back(block_selectors);
2030 cir.
wires.push_back(block_wires);
2035 for (
const auto& table : this->lookup_tables) {
2039 for (
size_t i = 0; i < table.
size(); ++i) {
2047 for (
const auto& list : range_lists) {
2048 cir.
range_tags[list.second.range_tag] = list.first;
2051 for (
auto& rom_table : this->rom_ram_logic.rom_arrays) {
2052 std::sort(rom_table.records.begin(), rom_table.records.end());
2055 table.reserve(rom_table.records.size());
2056 for (
const auto& rom_entry : rom_table.records) {
2058 this->real_variable_index[rom_entry.index_witness],
2059 this->real_variable_index[rom_entry.value_column1_witness],
2060 this->real_variable_index[rom_entry.value_column2_witness],
2067 for (
auto& ram_table : this->rom_ram_logic.ram_arrays) {
2068 std::sort(ram_table.records.begin(), ram_table.records.end());
2071 table.reserve(ram_table.records.size());
2072 for (
const auto& ram_entry : ram_table.records) {
2073 table.push_back({ this->real_variable_index[ram_entry.index_witness],
2074 this->real_variable_index[ram_entry.value_witness],
2075 this->real_variable_index[ram_entry.timestamp_witness],
2076 ram_entry.access_type });
2085 msgpack::pack(
buffer, cir);
#define BB_ASSERT(expression,...)
#define BB_ASSERT_GT(left, right,...)
#define BB_ASSERT_EQ(actual, expected,...)
#define BB_ASSERT_LTE(left, right,...)
bb::field< bb::Bn254FrParams > FF
#define BB_BENCH_NAME(name)
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
void create_ecc_dbl_gate(const ecc_dbl_gate_< FF > &in)
Create an elliptic curve doubling gate.
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 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.
size_t create_RAM_array(const size_t array_size)
Create a new updatable memory region.
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::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")
msgpack::sbuffer export_circuit() override
void create_sort_constraint_with_edges(const std::vector< uint32_t > &variable_index, const FF &, const FF &)
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....
typename ExecutionTrace::FF FF
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.
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...
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 ...
void apply_nnf_selectors(const NNF_SELECTORS type)
Enable the nnf gate of particular type.
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_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)
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 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.
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 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::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.
void apply_memory_selectors(const MEMORY_SELECTORS type)
Enable the memory gate of particular type.
void process_non_native_field_multiplications()
Iterates over the cached_non_native_field_multiplication objects, removes duplicates,...
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.
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.
static constexpr Fq curve_b
constexpr uint64_t get_msb() const
Container type for lookup table reads.
std::vector< BasicTable::LookupEntry > lookup_entries
uint8_t buffer[RANDOM_BUFFER_SIZE]
ReadData< bb::fr > get_lookup_accumulators(const MultiTableId id, const fr &key_a, const fr &key_b, const bool is_2_to_1_lookup)
Given a table ID and the key(s) for a key-value lookup, return the lookup accumulators.
BasicTable create_basic_table(const BasicTableId id, const size_t index)
const MultiTable & get_multitable(const MultiTableId id)
Return the multitable with the provided ID; construct all MultiTables if not constructed already.
Entry point for Barretenberg command-line interface.
field< Bn254FrParams > fr
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Serialized state of a circuit.
std::vector< std::vector< std::vector< FF > > > selectors
std::vector< uint32_t > real_variable_index
std::unordered_map< uint32_t, uint64_t > range_tags
std::unordered_map< uint32_t, std::string > vars_of_interest
std::vector< std::vector< uint32_t > > ram_states
std::vector< std::vector< std::array< uint32_t, 2 > > > rom_states
std::vector< std::vector< std::vector< uint32_t > > > ram_records
std::vector< std::vector< std::vector< uint32_t > > > rom_records
std::vector< std::vector< std::vector< FF > > > lookup_tables
std::vector< uint32_t > real_variable_tags
std::vector< uint32_t > public_inps
std::vector< FF > variables
std::vector< std::vector< std::vector< uint32_t > > > wires
std::vector< uint32_t > variable_indices
Used to store instructions to create partial_non_native_field_multiplication gates.
std::array< uint32_t, 4 > a
static constexpr std::array< std::array< FF, t >, rounds_f+rounds_p > round_constants
static constexpr field one()
static constexpr uint256_t modulus
BB_INLINE constexpr field to_montgomery_form() const noexcept
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)
std::vector< LookupEntry > lookup_gates
std::vector< bb::fr > column_3
std::vector< bb::fr > column_2
std::vector< bb::fr > column_1