37template <
typename FF,
typename CircuitBuilder>
42 auto unique_variables = std::unique(gate_variables.begin(), gate_variables.end());
43 gate_variables.erase(unique_variables, gate_variables.end());
44 if (gate_variables.empty()) {
47 for (
auto& var_idx : gate_variables) {
49 variable_gates[
key].emplace_back(gate_index);
51 for (
const auto& variable_index : gate_variables) {
52 variables_gate_counts[variable_index] += 1;
68template <
typename FF,
typename CircuitBuilder>
69template <
typename Block>
81 std::vector<uint32_t> gate_variables = extract_wires(blk,
index, pattern, selectors);
84 gate_variables = to_real(gate_variables);
85 process_gate_variables(gate_variables,
index, blk);
86 return gate_variables;
96template <
typename FF,
typename CircuitBuilder>
104 std::vector<uint32_t> rom_table_variables;
105 auto& memory_block = circuit_builder.blocks.memory;
106 for (
const auto& record : rom_array.
records) {
107 std::vector<uint32_t> gate_variables;
108 size_t gate_index = record.gate_index;
110 auto q_1 = memory_block.q_1()[gate_index];
111 auto q_2 = memory_block.q_2()[gate_index];
112 auto q_3 = memory_block.q_3()[gate_index];
113 auto q_4 = memory_block.q_4()[gate_index];
114 auto q_m = memory_block.q_m()[gate_index];
115 auto q_c = memory_block.q_c()[gate_index];
117 auto index_witness = record.index_witness;
118 auto vc1_witness = record.value_column1_witness;
119 auto vc2_witness = record.value_column2_witness;
120 auto record_witness = record.record_witness;
122 if (q_1 ==
FF::one() && q_m ==
FF::one() && q_2.
is_zero() && q_3.is_zero() && q_4.is_zero() && q_c.is_zero()) {
125 gate_variables.emplace_back(index_witness);
126 if (vc1_witness != circuit_builder.zero_idx()) {
127 gate_variables.emplace_back(vc1_witness);
129 if (vc2_witness != circuit_builder.zero_idx()) {
130 gate_variables.emplace_back(vc2_witness);
132 gate_variables.emplace_back(record_witness);
134 gate_variables = to_real(gate_variables);
135 process_gate_variables(gate_variables, gate_index, memory_block);
138 if (!gate_variables.empty()) {
139 rom_table_variables.insert(rom_table_variables.end(), gate_variables.begin(), gate_variables.end());
142 return rom_table_variables;
152template <
typename FF,
typename CircuitBuilder>
156 std::vector<uint32_t> ram_table_variables;
157 auto& memory_block = circuit_builder.blocks.memory;
158 for (
const auto& record : ram_array.
records) {
159 std::vector<uint32_t> gate_variables;
160 size_t gate_index = record.gate_index;
162 auto q_1 = memory_block.q_1()[gate_index];
163 auto q_2 = memory_block.q_2()[gate_index];
164 auto q_3 = memory_block.q_3()[gate_index];
165 auto q_4 = memory_block.q_4()[gate_index];
166 auto q_m = memory_block.q_m()[gate_index];
167 auto q_c = memory_block.q_c()[gate_index];
169 auto index_witness = record.index_witness;
170 auto timestamp_witness = record.timestamp_witness;
171 auto value_witness = record.value_witness;
172 auto record_witness = record.record_witness;
175 (q_c.is_zero() || q_c ==
FF::one())) {
178 gate_variables.emplace_back(index_witness);
179 if (timestamp_witness != circuit_builder.zero_idx()) {
180 gate_variables.emplace_back(timestamp_witness);
182 if (value_witness != circuit_builder.zero_idx()) {
183 gate_variables.emplace_back(value_witness);
185 gate_variables.emplace_back(record_witness);
187 gate_variables = to_real(gate_variables);
188 process_gate_variables(gate_variables, gate_index, memory_block);
191 ram_table_variables.insert(ram_table_variables.end(), gate_variables.begin(), gate_variables.end());
193 return ram_table_variables;
207template <
typename FF,
typename CircuitBuilder>
211 std::vector<uint32_t> gate_variables;
215 if (&blk != &circuit_builder.blocks.ecc_op) {
216 return gate_variables;
220 std::vector<uint32_t> first_row_variables;
221 std::vector<uint32_t> second_row_variables;
222 auto w1 = blk.w_l()[
index];
224 if (w1 != circuit_builder.zero_idx()) {
226 first_row_variables.insert(
227 first_row_variables.end(),
229 if (
index < blk.size() - 1) {
230 second_row_variables.insert(
231 second_row_variables.end(),
234 first_row_variables = to_real(first_row_variables);
235 second_row_variables = to_real(second_row_variables);
236 process_gate_variables(first_row_variables,
index, blk);
237 process_gate_variables(second_row_variables,
index, blk);
239 if (!first_row_variables.empty()) {
240 gate_variables.insert(gate_variables.end(), first_row_variables.cbegin(), first_row_variables.cend());
242 if (!second_row_variables.empty()) {
243 gate_variables.insert(gate_variables.end(), second_row_variables.cbegin(), second_row_variables.cend());
245 return gate_variables;
252 for (
auto& blk : circuit_builder.blocks.get()) {
253 if (blk.size() == 0 || &blk == &circuit_builder.blocks.pub_inputs) {
257 std::vector<uint32_t> eccop_variables;
258 for (
size_t gate_idx = 0; gate_idx < blk.size(); gate_idx++) {
260 std::vector<uint32_t> cc;
263 cc = extract_gate_variables(gate_idx, blk, pattern, kind);
268 try_pattern(ARITHMETIC, GateKind::Arith);
269 try_pattern(ELLIPTIC, GateKind::Elliptic);
270 try_pattern(LOOKUP, GateKind::Lookup);
271 try_pattern(POSEIDON2_EXTERNAL, GateKind::Poseidon2Ext);
273 try_pattern(POSEIDON2_QUAD_INTERNAL, GateKind::Poseidon2QuadInt);
274 try_pattern(POSEIDON2_QUAD_INTERNAL_TERMINAL, GateKind::Poseidon2QuadIntTerminal);
275 try_pattern(POSEIDON2_TRANSITION_ENTRY, GateKind::Poseidon2TransitionEntry);
276 try_pattern(POSEIDON2_INITIAL_EXTERNAL, GateKind::Poseidon2ExtInitial);
278 try_pattern(POSEIDON2_INTERNAL, GateKind::Poseidon2Int);
280 try_pattern(NON_NATIVE_FIELD, GateKind::Nnf);
281 try_pattern(MEMORY, GateKind::Memory);
282 try_pattern(DELTA_RANGE, GateKind::DeltaRange);
284 if (!cc.empty() && connect_variables) {
285 connect_all_variables_in_vector(cc);
290 auto databus_cc = extract_gate_variables(gate_idx, blk, DATABUS, GateKind::BusRead);
291 if (!databus_cc.empty() && connect_variables) {
292 connect_all_variables_in_vector(databus_cc);
295 auto eccop_cc = get_eccop_part_connected_component(gate_idx, blk);
296 if (!eccop_cc.empty() && connect_variables) {
297 eccop_variables.insert(eccop_variables.end(), eccop_cc.begin(), eccop_cc.end());
298 if (eccop_cc[0] == circuit_builder.equality_op_idx) {
299 connect_all_variables_in_vector(eccop_variables);
300 eccop_variables.clear();
307 const auto& rom_arrays = circuit_builder.rom_ram_logic.rom_arrays;
308 if (!rom_arrays.empty()) {
309 for (
const auto& rom_array : rom_arrays) {
310 std::vector<uint32_t> variable_indices = get_rom_table_connected_component(rom_array);
311 if (connect_variables) {
312 connect_all_variables_in_vector(variable_indices);
317 const auto& ram_arrays = circuit_builder.rom_ram_logic.ram_arrays;
318 if (!ram_arrays.empty()) {
319 for (
const auto& ram_array : ram_arrays) {
320 std::vector<uint32_t> variable_indices = get_ram_table_connected_component(ram_array);
321 if (connect_variables) {
322 connect_all_variables_in_vector(variable_indices);
350template <
typename FF,
typename CircuitBuilder>
352 : circuit_builder(circuit_builder)
353 , connect_variables(connect_variables)
376template <
typename FF,
typename CircuitBuilder>
379 constant_variable_indices_set.clear();
380 const auto& constant_variable_indices = circuit_builder.constant_variable_indices;
381 for (
const auto& pair : constant_variable_indices) {
382 constant_variable_indices_set.insert(pair.second);
393template <
typename FF,
typename CircuitBuilder>
396 uint32_t real_variable_index = circuit_builder.real_variable_index[variable_index];
397 return constant_variable_indices_set.find(real_variable_index) == constant_variable_indices_set.end();
410template <
typename FF,
typename CircuitBuilder>
413 if (variables_vector.empty()) {
416 std::vector<uint32_t> filtered_variables_vector;
417 filtered_variables_vector.reserve(variables_vector.size());
420 variables_vector.end(),
422 [&](uint32_t variable_index) {
423 return variable_index != circuit_builder.zero_idx() &&
424 this->check_is_not_constant_variable(variable_index);
427 auto unique_pointer = std::unique(filtered_variables_vector.begin(), filtered_variables_vector.end());
428 filtered_variables_vector.erase(unique_pointer, filtered_variables_vector.end());
429 if (filtered_variables_vector.size() < 2) {
432 for (
size_t i = 0; i < filtered_variables_vector.size() - 1; i++) {
433 add_new_edge(filtered_variables_vector[i], filtered_variables_vector[i + 1]);
445template <
typename FF,
typename CircuitBuilder>
447 const uint32_t& second_variable_index)
449 variable_adjacency_lists[first_variable_index].emplace_back(second_variable_index);
450 variable_adjacency_lists[second_variable_index].emplace_back(first_variable_index);
451 variables_degree[first_variable_index] += 1;
452 variables_degree[second_variable_index] += 1;
464template <
typename FF,
typename CircuitBuilder>
466 std::unordered_set<uint32_t>& is_used,
467 std::vector<uint32_t>& connected_component)
469 std::stack<uint32_t> variable_stack;
470 variable_stack.push(variable_index);
471 while (!variable_stack.empty()) {
472 uint32_t current_index = variable_stack.top();
473 variable_stack.pop();
474 if (!is_used.contains(current_index)) {
475 is_used.insert(current_index);
476 connected_component.emplace_back(current_index);
477 for (
const auto& it : variable_adjacency_lists[current_index]) {
478 variable_stack.push(it);
493template <
typename FF,
typename CircuitBuilder>
496 if (!connect_variables) {
497 throw_or_abort(
"find_connected_components() can only be called when connect_variables is true");
499 connected_components.clear();
500 std::unordered_set<uint32_t> visited;
501 for (
const auto& pair : variable_adjacency_lists) {
502 if (pair.first != 0 && variables_degree[pair.first] > 0) {
503 if (!visited.contains(pair.first)) {
504 std::vector<uint32_t> variable_indices;
505 depth_first_search(pair.first, visited, variable_indices);
506 std::sort(variable_indices.begin(), variable_indices.end());
511 mark_range_list_connected_components();
512 mark_finalize_connected_components();
513 mark_process_rom_connected_component();
514 return connected_components;
525template <
typename FF,
typename CircuitBuilder>
528 return memory_block.gate_selector_for(GateKind::Memory)[gate_idx] ==
FF::one() &&
529 memory_block.q_1()[gate_idx] ==
FF::one() && memory_block.q_2()[gate_idx] ==
FF::one();
540template <
typename FF,
typename CircuitBuilder>
545 auto it = variable_gates.find(
key);
546 if (it != variable_gates.end()) {
547 const auto& gates = it->second;
549 gates.begin(), gates.end(), [
this, &blk](
size_t gate_idx) { return is_gate_sorted_rom(blk, gate_idx); });
563template <
typename FF,
typename CircuitBuilder>
566 auto& memory_block = circuit_builder.blocks.memory;
567 for (
auto& cc : connected_components) {
568 const std::vector<uint32_t>& variables = cc.vars();
569 cc.is_process_rom_cc =
570 std::all_of(variables.begin(), variables.end(), [
this, &memory_block](uint32_t real_var_idx) {
571 return variable_only_in_sorted_rom_gates(real_var_idx, memory_block);
585template <
typename FF,
typename CircuitBuilder>
588 const auto& tags = circuit_builder.real_variable_tags;
589 std::unordered_set<uint32_t> tau_tags;
590 for (
const auto& pair : circuit_builder.range_lists) {
591 tau_tags.insert(pair.second.tau_tag);
593 for (
auto& cc : connected_components) {
594 const auto& variables = cc.variable_indices;
595 const uint32_t first_tag = tags[variables[0]];
596 if (tau_tags.contains(first_tag)) {
597 cc.is_range_list_cc =
598 std::all_of(variables.begin() + 1, variables.end(), [&tags, first_tag](uint32_t var_idx) {
599 return tags[var_idx] == first_tag;
613template <
typename FF,
typename CircuitBuilder>
616 const auto& finalize_witnesses = circuit_builder.get_finalize_witnesses();
617 for (
auto& cc : connected_components) {
618 const auto& vars = cc.vars();
619 cc.is_finalize_cc =
std::all_of(vars.begin(), vars.end(), [&finalize_witnesses](uint32_t var_idx) {
620 return finalize_witnesses.contains(var_idx);
641template <
typename FF,
typename CircuitBuilder>
644 auto& arithmetic_block = circuit_builder.blocks.arithmetic;
645 auto zero_idx = circuit_builder.zero_idx();
646 size_t current_index =
index;
647 std::vector<uint32_t> accumulators_indices;
651 auto fourth_idx = arithmetic_block.w_4()[current_index];
652 accumulators_indices.emplace_back(this->to_real(fourth_idx));
653 auto left_idx = arithmetic_block.w_l()[current_index];
654 if (left_idx != zero_idx) {
655 variables_in_one_gate.erase(this->to_real(left_idx));
657 auto right_idx = arithmetic_block.w_r()[current_index];
658 if (right_idx != zero_idx) {
659 variables_in_one_gate.erase(this->to_real(right_idx));
661 auto out_idx = arithmetic_block.w_o()[current_index];
662 if (out_idx != zero_idx) {
663 variables_in_one_gate.erase(this->to_real(out_idx));
665 auto q_arith = arithmetic_block.gate_selector_for(GateKind::Arith)[current_index];
666 if (q_arith == 1 || current_index == arithmetic_block.size() - 1) {
672 for (
size_t i = 0; i < accumulators_indices.size(); i++) {
676 variables_gate_counts[accumulators_indices[i]] -= 1;
680 variables_gate_counts[accumulators_indices[i]] = 0;
684 return current_index;
694template <
typename FF,
typename CircuitBuilder>
696 const std::unordered_set<uint32_t>& decompose_variables)
698 auto is_power_two = [&](
const uint256_t& number) {
return number > 0 && ((number & (number - 1)) == 0); };
699 auto find_position = [&](uint32_t variable_index) {
700 return decompose_variables.contains(this->to_real(variable_index));
702 auto& arithmetic_block = circuit_builder.blocks.arithmetic;
703 if (arithmetic_block.size() > 0) {
704 for (
size_t i = 0; i < arithmetic_block.size(); i++) {
705 auto q_1 = arithmetic_block.q_1()[i];
706 auto q_2 = arithmetic_block.q_2()[i];
707 auto q_3 = arithmetic_block.q_3()[i];
714 bool q_1_is_power_two = is_power_two(q_1);
715 bool q_2_is_power_two = is_power_two(q_2);
716 bool q_3_is_power_two = is_power_two(q_3);
717 if (q_2 * q_2 == q_1 * q_3 && q_1_is_power_two && q_2_is_power_two && q_3_is_power_two) {
718 uint32_t left_idx = arithmetic_block.w_l()[i];
719 uint32_t right_idx = arithmetic_block.w_r()[i];
720 uint32_t out_idx = arithmetic_block.w_o()[i];
721 uint32_t fourth_idx = arithmetic_block.w_4()[i];
722 bool find_left = find_position(left_idx);
723 bool find_right = find_position(right_idx);
724 bool find_out = find_position(out_idx);
725 bool find_fourth = find_position(fourth_idx);
726 if (((find_left && find_right && find_out) || (find_left && find_right && !find_out) ||
727 (find_left && find_right && !find_out) || (find_left && !find_right && !find_out)) &&
729 i = this->process_current_decompose_chain(i);
744template <
typename FF,
typename CircuitBuilder>
747 const auto& range_lists = circuit_builder.range_lists;
748 std::unordered_set<uint32_t> range_lists_tau_tags;
749 std::unordered_set<uint32_t> range_lists_range_tags;
750 const auto& real_variable_tags = circuit_builder.real_variable_tags;
751 for (
const auto& pair : range_lists) {
752 typename CircuitBuilder::RangeList list = pair.second;
753 range_lists_tau_tags.insert(list.tau_tag);
754 range_lists_range_tags.insert(list.range_tag);
756 for (uint32_t real_index = 0; real_index < real_variable_tags.size(); real_index++) {
757 if (variables_in_one_gate.contains(real_index)) {
760 if (range_lists_tau_tags.contains(real_variable_tags[real_index])) {
761 variables_in_one_gate.erase(real_index);
765 if (range_lists_range_tags.contains(real_variable_tags[real_index])) {
766 variables_in_one_gate.erase(real_index);
782template <
typename FF,
typename CircuitBuilder>
787 auto find_position = [&](uint32_t real_variable_index) {
788 return variables_in_one_gate.contains(real_variable_index);
791 BasicTableId::AES_SPARSE_MAP,
792 BasicTableId::AES_SPARSE_NORMALIZE };
793 auto& lookup_block = circuit_builder.blocks.lookup;
794 if (aes_plookup_tables.contains(table_id)) {
795 uint32_t real_out_idx = this->to_real(lookup_block.w_o()[gate_index]);
796 uint32_t real_right_idx = this->to_real(lookup_block.w_r()[gate_index]);
797 if (variables_gate_counts[real_out_idx] != 1 || variables_gate_counts[real_right_idx] != 1) {
798 bool find_out = find_position(real_out_idx);
799 auto q_c = lookup_block.q_c()[gate_index];
802 variables_in_one_gate.erase(real_out_idx);
820template <
typename FF,
typename CircuitBuilder>
824 auto find_position = [&](uint32_t real_variable_index) {
825 return variables_in_one_gate.contains(real_variable_index);
827 auto& lookup_block = circuit_builder.blocks.lookup;
829 BasicTableId::SHA256_WITNESS_SLICE_7_ROTATE_4,
830 BasicTableId::SHA256_WITNESS_SLICE_8_ROTATE_7,
831 BasicTableId::SHA256_WITNESS_SLICE_14_ROTATE_1,
832 BasicTableId::SHA256_BASE16,
833 BasicTableId::SHA256_BASE16_ROTATE2,
834 BasicTableId::SHA256_BASE28,
835 BasicTableId::SHA256_BASE28_ROTATE3,
836 BasicTableId::SHA256_BASE28_ROTATE6 };
837 if (sha256_plookup_tables.contains(table_id)) {
838 uint32_t real_right_idx = this->to_real(lookup_block.w_r()[gate_index]);
839 uint32_t real_out_idx = this->to_real(lookup_block.w_o()[gate_index]);
840 if (variables_gate_counts[real_out_idx] != 1 || variables_gate_counts[real_right_idx] != 1) {
842 auto q_c = lookup_block.q_c()[gate_index];
843 bool find_out = find_position(real_out_idx);
847 variables_in_one_gate.erase(real_out_idx);
853 variables_in_one_gate.erase(real_out_idx);
868template <
typename FF,
typename CircuitBuilder>
872 auto find_position = [&](uint32_t real_variable_index) {
873 return variables_in_one_gate.contains(real_variable_index);
877 BasicTableId::KECCAK_INPUT, BasicTableId::KECCAK_OUTPUT, BasicTableId::KECCAK_CHI, BasicTableId::KECCAK_THETA,
878 BasicTableId::KECCAK_RHO, BasicTableId::KECCAK_RHO_1, BasicTableId::KECCAK_RHO_2, BasicTableId::KECCAK_RHO_3,
879 BasicTableId::KECCAK_RHO_4, BasicTableId::KECCAK_RHO_5, BasicTableId::KECCAK_RHO_6, BasicTableId::KECCAK_RHO_7,
880 BasicTableId::KECCAK_RHO_8, BasicTableId::KECCAK_RHO_9
883 auto& lookup_block = circuit_builder.blocks.lookup;
885 if (keccak_plookup_tables.contains(table_id)) {
886 uint32_t real_out_idx = this->to_real(lookup_block.w_o()[gate_index]);
887 uint32_t real_right_idx = this->to_real(lookup_block.w_r()[gate_index]);
888 if (variables_gate_counts[real_out_idx] != 1 || variables_gate_counts[real_right_idx] != 1) {
889 bool find_out = find_position(real_out_idx);
890 auto q_c = lookup_block.q_c()[gate_index];
893 variables_in_one_gate.erase(real_out_idx);
909template <
typename FF,
typename CircuitBuilder>
912 auto find_position = [&](uint32_t real_variable_index) {
913 return variables_in_one_gate.contains(real_variable_index);
915 auto& lookup_block = circuit_builder.blocks.lookup;
916 auto& lookup_tables = circuit_builder.get_lookup_tables();
917 auto table_index =
static_cast<size_t>(
static_cast<uint256_t>(lookup_block.q_3()[gate_index]));
918 for (
const auto& table : lookup_tables) {
919 if (table.table_index == table_index) {
925 this->remove_unnecessary_aes_plookup_variables(table_id, gate_index);
927 this->remove_unnecessary_sha256_plookup_variables(table_id, gate_index);
929 this->remove_unnecessary_keccak_plookup_variables(table_id, gate_index);
932 if (column_1.size() == 1) {
933 uint32_t left_idx = lookup_block.w_l()[gate_index];
934 uint32_t real_left_idx = this->to_real(left_idx);
935 bool find_left = find_position(real_left_idx);
937 variables_in_one_gate.erase(real_left_idx);
940 if (column_2.size() == 1) {
941 uint32_t real_right_idx = this->to_real(lookup_block.w_r()[gate_index]);
942 bool find_right = find_position(real_right_idx);
944 variables_in_one_gate.erase(real_right_idx);
947 if (column_3.size() == 1) {
948 uint32_t real_out_idx = this->to_real(lookup_block.w_o()[gate_index]);
949 bool find_out = find_position(real_out_idx);
951 variables_in_one_gate.erase(real_out_idx);
964template <
typename FF,
typename CircuitBuilder>
967 auto& lookup_block = circuit_builder.blocks.lookup;
968 if (lookup_block.size() > 0) {
969 for (
size_t i = 0; i < lookup_block.size(); i++) {
970 this->process_current_plookup_gate(i);
983template <
typename FF,
typename CircuitBuilder>
986 auto& memory_block = circuit_builder.blocks.memory;
987 std::vector<uint32_t> to_remove;
988 for (
const auto& var_idx : variables_in_one_gate) {
990 if (
auto search = variable_gates.find(
key); search != variable_gates.end()) {
991 std::vector<size_t> gate_indexes = variable_gates[
key];
993 size_t gate_idx = gate_indexes[0];
994 auto q_1 = memory_block.q_1()[gate_idx];
995 auto q_2 = memory_block.q_2()[gate_idx];
996 auto q_3 = memory_block.q_3()[gate_idx];
997 auto q_4 = memory_block.q_4()[gate_idx];
998 auto q_m = memory_block.q_m()[gate_idx];
1001 q_arith.is_zero()) {
1005 if (this->to_real(memory_block.w_4()[gate_idx]) == var_idx) {
1006 to_remove.emplace_back(var_idx);
1011 for (
const auto& elem : to_remove) {
1012 variables_in_one_gate.erase(elem);
1023template <
typename FF,
typename CircuitBuilder>
1026 variables_in_one_gate.clear();
1027 for (
const auto& pair : variables_gate_counts) {
1028 bool is_not_constant_variable = check_is_not_constant_variable(pair.first);
1029 if (pair.second == 1 && pair.first != 0 && is_not_constant_variable) {
1030 variables_in_one_gate.insert(pair.first);
1033 auto range_lists = circuit_builder.range_lists;
1034 std::unordered_set<uint32_t> decompose_variables;
1035 for (
auto& pair : range_lists) {
1036 for (
auto& elem : pair.second.variable_indices) {
1037 bool is_not_constant_variable = check_is_not_constant_variable(elem);
1038 if (variables_gate_counts[circuit_builder.real_variable_index[elem]] == 1 && is_not_constant_variable) {
1039 decompose_variables.insert(circuit_builder.real_variable_index[elem]);
1043 remove_unnecessary_decompose_variables(decompose_variables);
1044 remove_unnecessary_plookup_variables();
1045 remove_unnecessary_range_constrains_variables();
1053 for (
const auto& elem : circuit_builder.get_used_witnesses()) {
1054 variables_in_one_gate.erase(elem);
1056 remove_record_witness_variables();
1061 auto& memory_block = circuit_builder.blocks.memory;
1062 std::vector<uint32_t> to_remove;
1063 for (
const auto& var_idx : variables_in_one_gate) {
1064 if (variable_only_in_sorted_rom_gates(var_idx, memory_block)) {
1065 to_remove.emplace_back(var_idx);
1068 for (
const auto& elem : to_remove) {
1069 variables_in_one_gate.erase(elem);
1072 return variables_in_one_gate;
1080template <
typename FF,
typename CircuitBuilder>
1083 info(
"╔═══════╦═══════╦═════════════╦═══════════╦══════════════╗");
1084 info(
"║ CC# ║ Size ║ Range List ║ Finalize ║ Process ROM ║");
1085 info(
"╠═══════╬═══════╬═════════════╬═══════════╬══════════════╣");
1087 for (
size_t i = 0; i < connected_components.size(); i++) {
1088 const auto& cc = connected_components[i];
1089 std::ostringstream line;
1091 line <<
"║ " <<
std::setw(5) << std::right << (i + 1) <<
" ║ " <<
std::setw(5) << std::right << cc.size()
1092 <<
" ║ " <<
std::setw(11) << std::left << (cc.is_range_list_cc ?
"Yes" :
"No") <<
" ║ " <<
std::setw(9)
1093 << std::left << (cc.is_finalize_cc ?
"Yes" :
"No") <<
" ║ " <<
std::setw(12) << std::left
1094 << (cc.is_process_rom_cc ?
"Yes" :
"No") <<
" ║";
1097 info(
"╚═══════╩═══════╩═════════════╩═══════════╩══════════════╝");
1098 info(
"Total connected components: ", connected_components.size());
1109 for (
const auto& it : variables_gate_counts) {
1110 info(
"number of gates with variables ", it.first,
" == ", it.second);
1121template <
typename FF,
typename CircuitBuilder>
1125 if (!q_arith.is_zero()) {
1126 info(
"q_arith == ", q_arith);
1128 info(
"q_m == ", block.q_m()[gate_index]);
1129 info(
"q1 == ", block.q_1()[gate_index]);
1130 info(
"q2 == ", block.q_2()[gate_index]);
1131 info(
"q3 == ", block.q_3()[gate_index]);
1132 info(
"q4 == ", block.q_4()[gate_index]);
1133 info(
"q_c == ", block.q_c()[gate_index]);
1135 if (q_arith ==
FF(2)) {
1137 info(
"w_4_shift == ", block.w_4()[gate_index + 1]);
1139 if (q_arith ==
FF(3)) {
1141 info(
"w_1_shift == ", block.w_l()[gate_index + 1]);
1142 info(
"w_4_shift == ", block.w_4()[gate_index + 1]);
1156template <
typename FF,
typename CircuitBuilder>
1160 if (!q_elliptic.is_zero()) {
1161 info(
"q_elliptic == ", q_elliptic);
1162 info(
"q_1 == ", block.q_1()[gate_index]);
1163 info(
"q_m == ", block.q_m()[gate_index]);
1164 bool is_elliptic_add_gate = !block.q_1()[gate_index].is_zero() && block.q_m()[gate_index].is_zero();
1165 bool is_elliptic_dbl_gate = block.q_1()[gate_index].is_zero() && block.q_m()[gate_index] ==
FF::one();
1166 if (is_elliptic_add_gate) {
1167 info(
"x2 == ", block.w_l()[gate_index + 1]);
1168 info(
"x3 == ", block.w_r()[gate_index + 1]);
1169 info(
"y3 == ", block.w_o()[gate_index + 1]);
1170 info(
"y2 == ", block.w_4()[gate_index + 1]);
1172 if (is_elliptic_dbl_gate) {
1173 info(
"x3 == ", block.w_r()[gate_index + 1]);
1174 info(
"y3 == ", block.w_o()[gate_index + 1]);
1189template <
typename FF,
typename CircuitBuilder>
1193 if (!q_lookup.is_zero()) {
1194 info(
"q_lookup == ", q_lookup);
1195 auto q_2 = block.q_2()[gate_index];
1196 auto q_m = block.q_m()[gate_index];
1197 auto q_c = block.q_c()[gate_index];
1198 info(
"q_2 == ", q_2);
1199 info(
"q_m == ", q_m);
1200 info(
"q_c == ", q_c);
1201 if (!q_2.is_zero()) {
1202 info(
"w_1_shift == ", block.w_l()[gate_index + 1]);
1204 if (!q_m.is_zero()) {
1205 info(
"w_2_shift == ", block.w_r()[gate_index + 1]);
1207 if (!q_c.is_zero()) {
1208 info(
"w_3_shift == ", block.w_o()[gate_index + 1]);
1223template <
typename FF,
typename CircuitBuilder>
1227 if (!q_delta_range.is_zero()) {
1228 info(
"q_delta_range == ", q_delta_range);
1229 info(
"w_1 == ", block.w_l()[gate_index]);
1230 info(
"w_2 == ", block.w_r()[gate_index]);
1231 info(
"w_3 == ", block.w_o()[gate_index]);
1232 info(
"w_4 == ", block.w_4()[gate_index]);
1233 info(
"w_1_shift == ", block.w_l()[gate_index]);
1247template <
typename FF,
typename CircuitBuilder>
1250 auto external_selector =
read_gate_selector(block, GateKind::Poseidon2Ext, gate_index);
1251 bool nonzero = !external_selector.is_zero();
1259 info(
"q_poseidon2_external == ", external_selector);
1261 info(
"q_poseidon2_external_initial == ",
1263 info(
"q_poseidon2_quad_internal == ",
read_gate_selector(block, GateKind::Poseidon2QuadInt, gate_index));
1267 info(
"w_1 == ", block.w_l()[gate_index]);
1268 info(
"w_2 == ", block.w_r()[gate_index]);
1269 info(
"w_3 == ", block.w_o()[gate_index]);
1270 info(
"w_4 == ", block.w_4()[gate_index]);
1271 info(
"w_1_shift == ", block.w_l()[gate_index + 1]);
1272 info(
"w_2_shift == ", block.w_r()[gate_index + 1]);
1273 info(
"w_3_shift == ", block.w_o()[gate_index + 1]);
1274 info(
"w_4_shift == ", block.w_4()[gate_index + 1]);
1288template <
typename FF,
typename CircuitBuilder>
1292 if (!q_nnf.is_zero()) {
1293 info(
"q_nnf == ", q_nnf);
1294 auto q_2 = block.q_2()[gate_idx];
1295 auto q_3 = block.q_3()[gate_idx];
1296 auto q_4 = block.q_4()[gate_idx];
1297 auto q_m = block.q_m()[gate_idx];
1299 info(
"w_1_shift == ", block.w_l()[gate_idx + 1]);
1300 info(
"w_2_shift == ", block.w_r()[gate_idx + 1]);
1303 info(
"w_1_shift == ", block.w_l()[gate_idx + 1]);
1304 info(
"w_2_shift == ", block.w_r()[gate_idx + 1]);
1305 info(
"w_3_shift == ", block.w_o()[gate_idx + 1]);
1306 info(
"w_4_shift == ", block.w_4()[gate_idx + 1]);
1308 info(
"w_1_shift == ", block.w_l()[gate_idx + 1]);
1309 info(
"w_2_shift == ", block.w_r()[gate_idx + 1]);
1311 info(
"w_3_shift == ", block.w_o()[gate_idx + 1]);
1312 info(
"w_4_shift == ", block.w_4()[gate_idx + 1]);
1328template <
typename FF,
typename CircuitBuilder>
1332 if (!q_memory.is_zero()) {
1333 info(
"q_memory == ", q_memory);
1334 auto q_1 = block.q_1()[gate_index];
1335 auto q_2 = block.q_2()[gate_index];
1336 auto q_3 = block.q_3()[gate_index];
1337 auto q_4 = block.q_4()[gate_index];
1339 info(
"q_1 == ", q_1);
1340 info(
"q_4 == ", q_4);
1341 info(
"w_1_shift == ", block.w_l()[gate_index + 1]);
1342 info(
"w_2_shift == ", block.w_r()[gate_index + 1]);
1344 info(
"q_1 == ", q_1);
1345 info(
"q_2 == ", q_2);
1346 info(
"w_1_shift == ", block.w_l()[gate_index + 1]);
1347 info(
"w_4_shift == ", block.w_4()[gate_index + 1]);
1348 }
else if (!q_3.is_zero()) {
1349 info(
"q_3 == ", q_3);
1350 info(
"w_1_shift == ", block.w_l()[gate_index + 1]);
1351 info(
"w_2_shift == ", block.w_r()[gate_index + 1]);
1352 info(
"w_3_shift == ", block.w_o()[gate_index + 1]);
1353 info(
"w_4_shift == ", block.w_4()[gate_index + 1]);
1367template <
typename FF,
typename CircuitBuilder>
1371 for (
const auto& [
key, gates] : variable_gates) {
1372 if (
key.first == real_idx) {
1373 for (
size_t i = 0; i < gates.size(); i++) {
1374 size_t gate_index = gates[i];
1376 auto& block = *
const_cast<BlockType*
>(
static_cast<const BlockType*
>(
key.second));
1377 info(
"---- printing variables in this gate");
1379 block.w_l()[gate_index],
1381 block.w_r()[gate_index],
1383 block.w_o()[gate_index],
1385 block.w_4()[gate_index]);
1386 info(
"---- printing gate info where variable with index ",
key.first,
" was found ----");
1387 print_arithmetic_gate_info(gate_index, block);
1388 print_elliptic_gate_info(gate_index, block);
1389 print_plookup_gate_info(gate_index, block);
1390 print_poseidon2s_gate_info(gate_index, block);
1391 print_delta_range_gate_info(gate_index, block);
1392 print_nnf_gate_info(gate_index, block);
1393 print_memory_gate_info(gate_index, block);
1396 if (!q_databus.is_zero()) {
1397 info(
"q_databus == ", q_databus);
1400 info(
"---- finished printing ----");
1415template <
typename FF,
typename CircuitBuilder>
1419 auto variables_in_one_gate = get_variables_in_one_gate();
1420 find_connected_components();
1423 main_connected_components.reserve(connected_components.size());
1424 for (
auto& cc : connected_components) {
1425 if (!cc.is_range_list_cc && !cc.is_finalize_cc && !cc.is_process_rom_cc) {
1426 main_connected_components.emplace_back(cc);
#define BB_ASSERT_EQ(actual, expected,...)
std::vector< uint32_t > real_variable_index
Map from witness index to real variable index.
TranslatorCircuitBuilder creates a circuit that evaluates the correctness of the evaluation of EccOpQ...
void print_delta_range_gate_info(size_t gate_idx, auto &block)
this method prints all information about range constrain gate where variable was found
void process_execution_trace()
void print_memory_gate_info(size_t gate_idx, auto &block)
this method prints all information about memory gate where variable was found
void print_plookup_gate_info(size_t gate_idx, auto &block)
this method prints all information about plookup gate where variable was found
std::vector< uint32_t > get_ram_table_connected_component(const bb::RamTranscript &ram_array)
this method gets the RAM table connected component by processing RAM transcript records
std::unordered_map< uint32_t, std::vector< uint32_t > > variable_adjacency_lists
void remove_unnecessary_decompose_variables(const std::unordered_set< uint32_t > &decompose_variables)
this method removes unnecessary variables from decompose chains
std::vector< ConnectedComponent > find_connected_components()
this methond finds all connected components in the graph described by adjacency lists and marks some ...
void depth_first_search(const uint32_t &variable_index, std::unordered_set< uint32_t > &is_used, std::vector< uint32_t > &connected_component)
this method implements depth-first search algorithm for undirected graphs
bool check_is_not_constant_variable(const uint32_t &variable_index)
this method checks whether the variable with given index is not constant
void remove_unnecessary_sha256_plookup_variables(bb::plookup::BasicTableId &table_id, size_t gate_index)
this method removes false cases in sha256 lookup tables. tables which are enumerated in the unordered...
std::unordered_set< uint32_t > get_variables_in_one_gate()
this method returns a final set of variables that were in one gate
void remove_record_witness_variables()
this method removes record witness variables from variables in one gate. initially record witness is ...
void print_variable_info(const uint32_t real_idx)
this method prints all information about gates where variable was found
void remove_unnecessary_range_constrains_variables()
this method removes variables from range constraints that are not security critical
std::pair< std::vector< ConnectedComponent >, std::unordered_set< uint32_t > > analyze_circuit(bool filter_cc=true)
this functions was made for more convenient testing process
void print_elliptic_gate_info(size_t gate_idx, auto &block)
this method prints all information about elliptic gate where variable was found
StaticAnalyzer_()=default
void process_gate_variables(std::vector< uint32_t > &gate_variables, size_t gate_index, auto &blk)
this method processes variables from a gate by removing duplicates and updating tracking structures
void connect_all_variables_in_vector(const std::vector< uint32_t > &variables_vector)
this method connects 2 variables if they are in one gate and 1) have different indices,...
bool is_gate_sorted_rom(auto &memory_block, size_t gate_idx) const
this method checks if current gate is sorted ROM gate
void print_connected_components_info()
this method prints additional information about connected components that were found in the graph
std::vector< uint32_t > get_rom_table_connected_component(const bb::RomTranscript &rom_array)
this method gets the ROM table connected component by processing ROM transcript records
void print_poseidon2s_gate_info(size_t gate_idx, auto &block)
this method prints all information about poseidon2s gate where variable was found
std::unordered_map< uint32_t, size_t > variables_gate_counts
void save_constant_variable_indices()
this method needs to save all constant variables indices in one data structure in order to not go thr...
void remove_unnecessary_aes_plookup_variables(bb::plookup::BasicTableId &table_id, size_t gate_index)
this method removes false positive cases variables from aes plookup tables. AES_SBOX_MAP,...
CircuitBuilder & circuit_builder
void remove_unnecessary_plookup_variables()
this method removes false cases plookup variables from variables in one gate
void print_nnf_gate_info(size_t gate_idx, auto &block)
this method prints all information about non natife field gate where variable was found
void print_arithmetic_gate_info(size_t gate_idx, auto &block)
this method prints all information about arithmetic gate where variable was found
void process_current_plookup_gate(size_t gate_index)
this method removes false cases in lookup table for a given gate. it uses all functions above for loo...
std::vector< uint32_t > extract_gate_variables(size_t index, Block &blk, const bb::gate_patterns::GatePattern &pattern, bb::GateKind kind)
Extract gate variables using a declarative pattern.
std::vector< uint32_t > get_eccop_part_connected_component(size_t index, auto &blk)
this method creates connected components from elliptic curve operation gates
void mark_range_list_connected_components()
this method marks some connected componets like they represent range lists tool needs this method to ...
void print_variables_gate_counts()
this method prints a number of gates for each variable
void mark_process_rom_connected_component()
this method marks some connected components if they were created by function process_rom_array....
std::unordered_map< uint32_t, size_t > variables_degree
void remove_unnecessary_keccak_plookup_variables(bb::plookup::BasicTableId &table_id, size_t gate_index)
This method removes false positive cases from keccak lookup tables. Tables which are enumerated in ke...
size_t process_current_decompose_chain(size_t index)
this method removes variables that were created in a function decompose_into_default_range because th...
void add_new_edge(const uint32_t &first_variable_index, const uint32_t &second_variable_index)
this method creates an edge between two variables in graph. All needed checks in a function above
void mark_finalize_connected_components()
this method marks some connected components like they represent separated finalize blocks the point i...
bool variable_only_in_sorted_rom_gates(uint32_t var_idx, auto &blk) const
this method checks that every gate for given variable in a given block is sorted ROM gate
Entry point for Barretenberg command-line interface.
ExecutionTraceBlock< fr, 4 > MegaTraceBlock
FF read_gate_selector(const ExecutionTraceBlock< FF, NUM_WIRES > &block, GateKind kind, size_t idx)
Gate-selector value at (block, idx) for kind, returning zero if block does not own this kind....
GateKind
Tag identifying which gate selector a block owns. Used by cross-block readers to decide whether (bloc...
std::pair< uint32_t, const void * > KeyPair
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
RamTranscript contains the RamRecords for a particular RAM table (recording READ and WRITE operations...
std::vector< RamRecord > records
RomTranscript contains the RomRecords for a particular ROM table as well as the vector whose ith entr...
std::vector< RomRecord > records
static constexpr field one()
BB_INLINE constexpr bool is_zero() const noexcept
Pattern defining which wires are constrained by a gate type.
Selector values read from a gate.
void throw_or_abort(std::string const &err)