Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
graph.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#include "./graph.hpp"
8#include "./gate_patterns.hpp"
12#include <algorithm>
13#include <array>
14#include <iomanip>
15#include <optional>
16#include <stack>
17
18using namespace bb::plookup;
19using namespace bb;
20
21namespace cdg {
22
37template <typename FF, typename CircuitBuilder>
38inline void StaticAnalyzer_<FF, CircuitBuilder>::process_gate_variables(std::vector<uint32_t>& gate_variables,
39 size_t gate_index,
40 auto& blk)
41{
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()) {
45 return;
46 }
47 for (auto& var_idx : gate_variables) {
48 KeyPair key = std::make_pair(var_idx, &blk);
49 variable_gates[key].emplace_back(gate_index);
50 }
51 for (const auto& variable_index : gate_variables) {
52 variables_gate_counts[variable_index] += 1;
53 }
54}
55
68template <typename FF, typename CircuitBuilder>
69template <typename Block, typename GateSelectorColumn>
71 size_t index,
72 Block& blk,
73 const bb::gate_patterns::GatePattern& pattern,
74 const GateSelectorColumn& gate_selector_column)
75{
76 using namespace bb::gate_patterns;
77
78 // Check if gate selector is active
79 if (gate_selector_column[index].is_zero()) {
80 return {};
81 }
82
83 // Read selectors and extract wire indices using the pattern
84 Selectors selectors = read_selectors(blk, index, gate_selector_column);
85 std::vector<uint32_t> gate_variables = extract_wires(blk, index, pattern, selectors);
86
87 // Convert to real indices and process
88 gate_variables = to_real(gate_variables);
89 process_gate_variables(gate_variables, index, blk);
90 return gate_variables;
91}
92
100template <typename FF, typename CircuitBuilder>
102 const bb::RomTranscript& rom_array)
103{
104 // Every RomTranscript data structure has 2 main components that are interested for static analyzer:
105 // 1) records contains values that were put in the gate, we can use them to create connections between variables
106 // 2) states contains values witness indexes that we can find in the ROM record in the RomTrascript, so we can
107 // ignore state of the ROM transcript, because we still can connect all variables using variables from records.
108 std::vector<uint32_t> rom_table_variables;
109 auto& memory_block = circuit_builder.blocks.memory;
110 for (const auto& record : rom_array.records) {
111 std::vector<uint32_t> gate_variables;
112 size_t gate_index = record.gate_index;
113
114 auto q_1 = memory_block.q_1()[gate_index];
115 auto q_2 = memory_block.q_2()[gate_index];
116 auto q_3 = memory_block.q_3()[gate_index];
117 auto q_4 = memory_block.q_4()[gate_index];
118 auto q_m = memory_block.q_m()[gate_index];
119 auto q_c = memory_block.q_c()[gate_index];
120
121 auto index_witness = record.index_witness;
122 auto vc1_witness = record.value_column1_witness; // state[0] from RomTranscript
123 auto vc2_witness = record.value_column2_witness; // state[1] from RomTranscript
124 auto record_witness = record.record_witness;
125
126 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()) {
127 // By default ROM read gate uses variables (w_1, w_2, w_3, w_4) = (index_witness, vc1_witness,
128 // vc2_witness, record_witness) So we can update all of them
129 gate_variables.emplace_back(index_witness);
130 if (vc1_witness != circuit_builder.zero_idx()) {
131 gate_variables.emplace_back(vc1_witness);
132 }
133 if (vc2_witness != circuit_builder.zero_idx()) {
134 gate_variables.emplace_back(vc2_witness);
135 }
136 gate_variables.emplace_back(record_witness);
137 }
138 gate_variables = to_real(gate_variables);
139 process_gate_variables(gate_variables, gate_index, memory_block);
140 // after process_gate_variables function gate_variables constists of real variables indexes, so we can
141 // add all this variables in the final vector to connect all of them
142 if (!gate_variables.empty()) {
143 rom_table_variables.insert(rom_table_variables.end(), gate_variables.begin(), gate_variables.end());
144 }
145 }
146 return rom_table_variables;
147}
148
156template <typename FF, typename CircuitBuilder>
158 const bb::RamTranscript& ram_array)
159{
160 std::vector<uint32_t> ram_table_variables;
161 auto& memory_block = circuit_builder.blocks.memory;
162 for (const auto& record : ram_array.records) {
163 std::vector<uint32_t> gate_variables;
164 size_t gate_index = record.gate_index;
165
166 auto q_1 = memory_block.q_1()[gate_index];
167 auto q_2 = memory_block.q_2()[gate_index];
168 auto q_3 = memory_block.q_3()[gate_index];
169 auto q_4 = memory_block.q_4()[gate_index];
170 auto q_m = memory_block.q_m()[gate_index];
171 auto q_c = memory_block.q_c()[gate_index];
172
173 auto index_witness = record.index_witness;
174 auto timestamp_witness = record.timestamp_witness;
175 auto value_witness = record.value_witness;
176 auto record_witness = record.record_witness;
177
178 if (q_1 == FF::one() && q_m == FF::one() && q_2.is_zero() && q_3.is_zero() && q_4.is_zero() &&
179 (q_c.is_zero() || q_c == FF::one())) {
180 // By default RAM read/write gate uses variables (w_1, w_2, w_3, w_4) = (index_witness,
181 // timestamp_witness, value_witness, record_witness) So we can update all of them
182 gate_variables.emplace_back(index_witness);
183 if (timestamp_witness != circuit_builder.zero_idx()) {
184 gate_variables.emplace_back(timestamp_witness);
185 }
186 if (value_witness != circuit_builder.zero_idx()) {
187 gate_variables.emplace_back(value_witness);
188 }
189 gate_variables.emplace_back(record_witness);
190 }
191 gate_variables = to_real(gate_variables);
192 process_gate_variables(gate_variables, gate_index, memory_block);
193 // after process_gate_variables function gate_variables constists of real variables indexes, so we can add
194 // all these variables in the final vector to connect all of them
195 ram_table_variables.insert(ram_table_variables.end(), gate_variables.begin(), gate_variables.end());
196 }
197 return ram_table_variables;
198}
199
211template <typename FF, typename CircuitBuilder>
213 auto& blk)
214{
215 std::vector<uint32_t> gate_variables;
216
217 // Only process gates in the ecc_op block, otherwise return early
218 if constexpr (IsMegaBuilder<CircuitBuilder>) {
219 if (&blk != &circuit_builder.blocks.ecc_op) {
220 return gate_variables;
221 }
222 }
223
224 std::vector<uint32_t> first_row_variables;
225 std::vector<uint32_t> second_row_variables;
226 auto w1 = blk.w_l()[index]; // get opcode of operation, because function get_ecc_op_idx returns type
227 // uint32_t and it adds as w1
228 if (w1 != circuit_builder.zero_idx()) {
229 // this is opcode and start of the UltraOp element
230 first_row_variables.insert(
231 first_row_variables.end(),
232 { w1, blk.w_r()[index], blk.w_o()[index], blk.w_4()[index] }); // add op, x_lo, x_hi, y_lo
233 if (index < blk.size() - 1) {
234 second_row_variables.insert(
235 second_row_variables.end(),
236 { blk.w_r()[index + 1], blk.w_o()[index + 1], blk.w_4()[index + 1] }); // add y_hi, z1, z2
237 }
238 first_row_variables = to_real(first_row_variables);
239 second_row_variables = to_real(second_row_variables);
240 process_gate_variables(first_row_variables, index, blk);
241 process_gate_variables(second_row_variables, index, blk);
242 }
243 if (!first_row_variables.empty()) {
244 gate_variables.insert(gate_variables.end(), first_row_variables.cbegin(), first_row_variables.cend());
245 }
246 if (!second_row_variables.empty()) {
247 gate_variables.insert(gate_variables.end(), second_row_variables.cbegin(), second_row_variables.cend());
248 }
249 return gate_variables;
250}
251
252template <typename FF, typename CircuitBuilder> void StaticAnalyzer_<FF, CircuitBuilder>::process_execution_trace()
253{
254 using namespace bb::gate_patterns;
255
256 for (auto& blk : circuit_builder.blocks.get()) {
257 if (blk.size() == 0 || &blk == &circuit_builder.blocks.pub_inputs) {
258 continue;
259 }
260
261 std::vector<uint32_t> eccop_variables;
262 for (size_t gate_idx = 0; gate_idx < blk.size(); gate_idx++) {
263 // Try each pattern until one matches (returns non-empty)
264 std::vector<uint32_t> cc;
265 auto try_pattern = [&](const GatePattern& pattern, const auto& selector) {
266 if (cc.empty()) {
267 cc = extract_gate_variables(gate_idx, blk, pattern, selector);
268 }
269 };
270
271 // Standard gate patterns (mutually exclusive - at most one will match)
272 try_pattern(ARITHMETIC, blk.q_arith());
273 try_pattern(ELLIPTIC, blk.q_elliptic());
274 try_pattern(LOOKUP, blk.q_lookup());
275 try_pattern(POSEIDON2_INTERNAL, blk.q_poseidon2_internal());
276 try_pattern(POSEIDON2_EXTERNAL, blk.q_poseidon2_external());
277 try_pattern(NON_NATIVE_FIELD, blk.q_nnf());
278 try_pattern(MEMORY, blk.q_memory()); // consistency gates only; access gates via ROM/RAM transcripts
279 try_pattern(DELTA_RANGE, blk.q_delta_range());
280
281 if (!cc.empty() && connect_variables) {
282 connect_all_variables_in_vector(cc);
283 }
284
285 // MegaBuilder-specific patterns
286 if constexpr (IsMegaBuilder<CircuitBuilder>) {
287 auto databus_cc = extract_gate_variables(gate_idx, blk, DATABUS, blk.q_busread());
288 if (!databus_cc.empty() && connect_variables) {
289 connect_all_variables_in_vector(databus_cc);
290 }
291
292 auto eccop_cc = get_eccop_part_connected_component(gate_idx, blk);
293 if (!eccop_cc.empty() && connect_variables) {
294 eccop_variables.insert(eccop_variables.end(), eccop_cc.begin(), eccop_cc.end());
295 if (eccop_cc[0] == circuit_builder.equality_op_idx) {
296 connect_all_variables_in_vector(eccop_variables);
297 eccop_variables.clear();
298 }
299 }
300 }
301 }
302 }
303
304 const auto& rom_arrays = circuit_builder.rom_ram_logic.rom_arrays;
305 if (!rom_arrays.empty()) {
306 for (const auto& rom_array : rom_arrays) {
307 std::vector<uint32_t> variable_indices = get_rom_table_connected_component(rom_array);
308 if (connect_variables) {
309 connect_all_variables_in_vector(variable_indices);
310 }
311 }
312 }
313
314 const auto& ram_arrays = circuit_builder.rom_ram_logic.ram_arrays;
315 if (!ram_arrays.empty()) {
316 for (const auto& ram_array : ram_arrays) {
317 std::vector<uint32_t> variable_indices = get_ram_table_connected_component(ram_array);
318 if (connect_variables) {
319 connect_all_variables_in_vector(variable_indices);
320 }
321 }
322 }
323}
324
347template <typename FF, typename CircuitBuilder>
349 : circuit_builder(circuit_builder)
350 , connect_variables(connect_variables)
351{
352 variables_gate_counts = std::unordered_map<uint32_t, size_t>(circuit_builder.real_variable_index.size());
355 variables_degree = std::unordered_map<uint32_t, size_t>(circuit_builder.real_variable_index.size());
356 for (const auto& variable_index : circuit_builder.real_variable_index) {
357 variables_gate_counts[variable_index] = 0;
358 variables_degree[variable_index] = 0;
359 variable_adjacency_lists[variable_index] = {};
360 }
363}
364
373template <typename FF, typename CircuitBuilder>
375{
376 constant_variable_indices_set.clear();
377 const auto& constant_variable_indices = circuit_builder.constant_variable_indices;
378 for (const auto& pair : constant_variable_indices) {
379 constant_variable_indices_set.insert(pair.second);
380 }
381}
382
390template <typename FF, typename CircuitBuilder>
392{
393 uint32_t real_variable_index = circuit_builder.real_variable_index[variable_index];
394 return constant_variable_indices_set.find(real_variable_index) == constant_variable_indices_set.end();
395}
396
407template <typename FF, typename CircuitBuilder>
408void StaticAnalyzer_<FF, CircuitBuilder>::connect_all_variables_in_vector(const std::vector<uint32_t>& variables_vector)
409{
410 if (variables_vector.empty()) {
411 return;
412 }
413 std::vector<uint32_t> filtered_variables_vector;
414 filtered_variables_vector.reserve(variables_vector.size());
415 // Only copy non-zero and non-constant variables
416 std::copy_if(variables_vector.begin(),
417 variables_vector.end(),
418 std::back_inserter(filtered_variables_vector),
419 [&](uint32_t variable_index) {
420 return variable_index != circuit_builder.zero_idx() &&
421 this->check_is_not_constant_variable(variable_index);
422 });
423 // Remove duplicates
424 auto unique_pointer = std::unique(filtered_variables_vector.begin(), filtered_variables_vector.end());
425 filtered_variables_vector.erase(unique_pointer, filtered_variables_vector.end());
426 if (filtered_variables_vector.size() < 2) {
427 return;
428 }
429 for (size_t i = 0; i < filtered_variables_vector.size() - 1; i++) {
430 add_new_edge(filtered_variables_vector[i], filtered_variables_vector[i + 1]);
431 }
432}
433
442template <typename FF, typename CircuitBuilder>
443void StaticAnalyzer_<FF, CircuitBuilder>::add_new_edge(const uint32_t& first_variable_index,
444 const uint32_t& second_variable_index)
445{
446 variable_adjacency_lists[first_variable_index].emplace_back(second_variable_index);
447 variable_adjacency_lists[second_variable_index].emplace_back(first_variable_index);
448 variables_degree[first_variable_index] += 1;
449 variables_degree[second_variable_index] += 1;
450}
451
461template <typename FF, typename CircuitBuilder>
463 std::unordered_set<uint32_t>& is_used,
464 std::vector<uint32_t>& connected_component)
465{
466 std::stack<uint32_t> variable_stack;
467 variable_stack.push(variable_index);
468 while (!variable_stack.empty()) {
469 uint32_t current_index = variable_stack.top();
470 variable_stack.pop();
471 if (!is_used.contains(current_index)) {
472 is_used.insert(current_index);
473 connected_component.emplace_back(current_index);
474 for (const auto& it : variable_adjacency_lists[current_index]) {
475 variable_stack.push(it);
476 }
477 }
478 }
479}
480
490template <typename FF, typename CircuitBuilder>
492{
493 if (!connect_variables) {
494 throw_or_abort("find_connected_components() can only be called when connect_variables is true");
495 }
496 connected_components.clear();
497 std::unordered_set<uint32_t> visited;
498 for (const auto& pair : variable_adjacency_lists) {
499 if (pair.first != 0 && variables_degree[pair.first] > 0) {
500 if (!visited.contains(pair.first)) {
501 std::vector<uint32_t> variable_indices;
502 depth_first_search(pair.first, visited, variable_indices);
503 std::sort(variable_indices.begin(), variable_indices.end());
504 connected_components.emplace_back(ConnectedComponent(variable_indices));
505 }
506 }
507 }
508 mark_range_list_connected_components();
509 mark_finalize_connected_components();
510 mark_process_rom_connected_component();
511 return connected_components;
512}
513
522template <typename FF, typename CircuitBuilder>
523bool StaticAnalyzer_<FF, CircuitBuilder>::is_gate_sorted_rom(auto& memory_block, size_t gate_idx) const
524{
525 return memory_block.q_memory()[gate_idx] == FF::one() && memory_block.q_1()[gate_idx] == FF::one() &&
526 memory_block.q_2()[gate_idx] == FF::one();
527}
528
537template <typename FF, typename CircuitBuilder>
539{
540 bool result = false;
541 KeyPair key = { var_idx, &blk };
542 auto it = variable_gates.find(key);
543 if (it != variable_gates.end()) {
544 const auto& gates = it->second;
545 result = std::all_of(
546 gates.begin(), gates.end(), [this, &blk](size_t gate_idx) { return is_gate_sorted_rom(blk, gate_idx); });
547 }
548 return result;
549}
550
560template <typename FF, typename CircuitBuilder>
562{
563 auto& memory_block = circuit_builder.blocks.memory;
564 for (auto& cc : connected_components) {
565 const std::vector<uint32_t>& variables = cc.vars();
566 cc.is_process_rom_cc =
567 std::all_of(variables.begin(), variables.end(), [this, &memory_block](uint32_t real_var_idx) {
568 return variable_only_in_sorted_rom_gates(real_var_idx, memory_block);
569 });
570 }
571}
572
582template <typename FF, typename CircuitBuilder>
584{
585 const auto& tags = circuit_builder.real_variable_tags;
586 std::unordered_set<uint32_t> tau_tags;
587 for (const auto& pair : circuit_builder.range_lists) {
588 tau_tags.insert(pair.second.tau_tag);
589 }
590 for (auto& cc : connected_components) {
591 const auto& variables = cc.variable_indices;
592 const uint32_t first_tag = tags[variables[0]];
593 if (tau_tags.contains(first_tag)) {
594 cc.is_range_list_cc =
595 std::all_of(variables.begin() + 1, variables.end(), [&tags, first_tag](uint32_t var_idx) {
596 return tags[var_idx] == first_tag;
597 });
598 }
599 }
600}
601
610template <typename FF, typename CircuitBuilder>
612{
613 const auto& finalize_witnesses = circuit_builder.get_finalize_witnesses();
614 for (auto& cc : connected_components) {
615 const auto& vars = cc.vars();
616 cc.is_finalize_cc = std::all_of(vars.begin(), vars.end(), [&finalize_witnesses](uint32_t var_idx) {
617 return finalize_witnesses.contains(var_idx);
618 });
619 }
620}
621
638template <typename FF, typename CircuitBuilder>
640{
641 auto& arithmetic_block = circuit_builder.blocks.arithmetic;
642 auto zero_idx = circuit_builder.zero_idx();
643 size_t current_index = index;
644 std::vector<uint32_t> accumulators_indices;
645 while (true) {
646 // we have to remove left, right and output wires of the current gate, cause they'are new_limbs, and they
647 // are useless for the analyzer
648 auto fourth_idx = arithmetic_block.w_4()[current_index];
649 accumulators_indices.emplace_back(this->to_real(fourth_idx));
650 auto left_idx = arithmetic_block.w_l()[current_index];
651 if (left_idx != zero_idx) {
652 variables_in_one_gate.erase(this->to_real(left_idx));
653 }
654 auto right_idx = arithmetic_block.w_r()[current_index];
655 if (right_idx != zero_idx) {
656 variables_in_one_gate.erase(this->to_real(right_idx));
657 }
658 auto out_idx = arithmetic_block.w_o()[current_index];
659 if (out_idx != zero_idx) {
660 variables_in_one_gate.erase(this->to_real(out_idx));
661 }
662 auto q_arith = arithmetic_block.q_arith()[current_index];
663 if (q_arith == 1 || current_index == arithmetic_block.size() - 1) {
664 // this is the last gate in this chain, or we can't go next, so we have to stop a loop
665 break;
666 }
667 current_index++;
668 }
669 for (size_t i = 0; i < accumulators_indices.size(); i++) {
670 if (i == 0) {
671 // the first variable in accumulators is the variable which decompose was created. So, we have to
672 // decrement variable_gate_counts for this variable
673 variables_gate_counts[accumulators_indices[i]] -= 1;
674 } else {
675 // next accumulators are useless variables that are not interested for the analyzer. So, for these
676 // variables we can nullify variables_gate_counts
677 variables_gate_counts[accumulators_indices[i]] = 0;
678 }
679 }
680 // we don't want to make variables_gate_counts for intermediate variables negative, so, can go to the next gates
681 return current_index;
682}
683
691template <typename FF, typename CircuitBuilder>
693 const std::unordered_set<uint32_t>& decompose_variables)
694{
695 auto is_power_two = [&](const uint256_t& number) { return number > 0 && ((number & (number - 1)) == 0); };
696 auto find_position = [&](uint32_t variable_index) {
697 return decompose_variables.contains(this->to_real(variable_index));
698 };
699 auto& arithmetic_block = circuit_builder.blocks.arithmetic;
700 if (arithmetic_block.size() > 0) {
701 for (size_t i = 0; i < arithmetic_block.size(); i++) {
702 auto q_1 = arithmetic_block.q_1()[i];
703 auto q_2 = arithmetic_block.q_2()[i];
704 auto q_3 = arithmetic_block.q_3()[i];
705 // big addition gate from decompose has selectors, which have the next property:
706 // q_1 = (1) << shifts[0], target_range_bitnum * (3 * i),
707 // q_2 = (1) << shifts[1], target_range_bitnum * (3 * i + 1),
708 // q_3 = (1) << shifts[2], target_range_bitnum * (3 * i + 2)
709 // so, they are power of two and satisfying the following equality: q_2 * q_2 = q_1 * q_3
710 // this way we can differ them from other arithmetic gates
711 bool q_1_is_power_two = is_power_two(q_1);
712 bool q_2_is_power_two = is_power_two(q_2);
713 bool q_3_is_power_two = is_power_two(q_3);
714 if (q_2 * q_2 == q_1 * q_3 && q_1_is_power_two && q_2_is_power_two && q_3_is_power_two) {
715 uint32_t left_idx = arithmetic_block.w_l()[i];
716 uint32_t right_idx = arithmetic_block.w_r()[i];
717 uint32_t out_idx = arithmetic_block.w_o()[i];
718 uint32_t fourth_idx = arithmetic_block.w_4()[i];
719 bool find_left = find_position(left_idx);
720 bool find_right = find_position(right_idx);
721 bool find_out = find_position(out_idx);
722 bool find_fourth = find_position(fourth_idx);
723 if (((find_left && find_right && find_out) || (find_left && find_right && !find_out) ||
724 (find_left && find_right && !find_out) || (find_left && !find_right && !find_out)) &&
725 !find_fourth) {
726 i = this->process_current_decompose_chain(i);
727 }
728 }
729 }
730 }
731}
732
741template <typename FF, typename CircuitBuilder>
743{
744 const auto& range_lists = circuit_builder.range_lists;
745 std::unordered_set<uint32_t> range_lists_tau_tags;
746 std::unordered_set<uint32_t> range_lists_range_tags;
747 const auto& real_variable_tags = circuit_builder.real_variable_tags;
748 for (const auto& pair : range_lists) {
749 typename CircuitBuilder::RangeList list = pair.second;
750 range_lists_tau_tags.insert(list.tau_tag);
751 range_lists_range_tags.insert(list.range_tag);
752 }
753 for (uint32_t real_index = 0; real_index < real_variable_tags.size(); real_index++) {
754 if (variables_in_one_gate.contains(real_index)) {
755 // this if helps us to remove variables from delta_range_constraints when finalize_circuit() function
756 // was called
757 if (range_lists_tau_tags.contains(real_variable_tags[real_index])) {
758 variables_in_one_gate.erase(real_index);
759 }
760 // this if helps us to remove variables from range_constraints when range_constraint_into_two_limbs
761 // function was called
762 if (range_lists_range_tags.contains(real_variable_tags[real_index])) {
763 variables_in_one_gate.erase(real_index);
764 }
765 }
766 }
767}
768
779template <typename FF, typename CircuitBuilder>
781 size_t gate_index)
782{
783
784 auto find_position = [&](uint32_t real_variable_index) {
785 return variables_in_one_gate.contains(real_variable_index);
786 };
787 std::unordered_set<BasicTableId> aes_plookup_tables{ BasicTableId::AES_SBOX_MAP,
788 BasicTableId::AES_SPARSE_MAP,
789 BasicTableId::AES_SPARSE_NORMALIZE };
790 auto& lookup_block = circuit_builder.blocks.lookup;
791 if (aes_plookup_tables.contains(table_id)) {
792 uint32_t real_out_idx = this->to_real(lookup_block.w_o()[gate_index]);
793 uint32_t real_right_idx = this->to_real(lookup_block.w_r()[gate_index]);
794 if (variables_gate_counts[real_out_idx] != 1 || variables_gate_counts[real_right_idx] != 1) {
795 bool find_out = find_position(real_out_idx);
796 auto q_c = lookup_block.q_c()[gate_index];
797 if (q_c.is_zero()) {
798 if (find_out) {
799 variables_in_one_gate.erase(real_out_idx);
800 }
801 }
802 }
803 }
804}
805
817template <typename FF, typename CircuitBuilder>
819 size_t gate_index)
820{
821 auto find_position = [&](uint32_t real_variable_index) {
822 return variables_in_one_gate.contains(real_variable_index);
823 };
824 auto& lookup_block = circuit_builder.blocks.lookup;
825 std::unordered_set<BasicTableId> sha256_plookup_tables{ BasicTableId::SHA256_WITNESS_SLICE_3,
826 BasicTableId::SHA256_WITNESS_SLICE_7_ROTATE_4,
827 BasicTableId::SHA256_WITNESS_SLICE_8_ROTATE_7,
828 BasicTableId::SHA256_WITNESS_SLICE_14_ROTATE_1,
829 BasicTableId::SHA256_BASE16,
830 BasicTableId::SHA256_BASE16_ROTATE2,
831 BasicTableId::SHA256_BASE28,
832 BasicTableId::SHA256_BASE28_ROTATE3,
833 BasicTableId::SHA256_BASE28_ROTATE6 };
834 if (sha256_plookup_tables.contains(table_id)) {
835 uint32_t real_right_idx = this->to_real(lookup_block.w_r()[gate_index]);
836 uint32_t real_out_idx = this->to_real(lookup_block.w_o()[gate_index]);
837 if (variables_gate_counts[real_out_idx] != 1 || variables_gate_counts[real_right_idx] != 1) {
838 // auto q_m = lookup_block.q_m()[gate_index];
839 auto q_c = lookup_block.q_c()[gate_index];
840 bool find_out = find_position(real_out_idx);
841 // bool find_right = find_position(real_right_idx);
842 if (q_c.is_zero()) {
843 if (find_out) {
844 variables_in_one_gate.erase(real_out_idx);
845 }
846 }
847 if (table_id == SHA256_BASE16_ROTATE2 || table_id == SHA256_BASE28_ROTATE6) {
848 // we want to remove false cases for special tables even though their selectors != 0
849 // because they are used in read_from_1_to_2_table function, and they aren't dangerous
850 variables_in_one_gate.erase(real_out_idx);
851 }
852 }
853 }
854}
855
865template <typename FF, typename CircuitBuilder>
867 size_t gate_index)
868{
869 auto find_position = [&](uint32_t real_variable_index) {
870 return variables_in_one_gate.contains(real_variable_index);
871 };
872
873 std::unordered_set<BasicTableId> keccak_plookup_tables{
874 BasicTableId::KECCAK_INPUT, BasicTableId::KECCAK_OUTPUT, BasicTableId::KECCAK_CHI, BasicTableId::KECCAK_THETA,
875 BasicTableId::KECCAK_RHO, BasicTableId::KECCAK_RHO_1, BasicTableId::KECCAK_RHO_2, BasicTableId::KECCAK_RHO_3,
876 BasicTableId::KECCAK_RHO_4, BasicTableId::KECCAK_RHO_5, BasicTableId::KECCAK_RHO_6, BasicTableId::KECCAK_RHO_7,
877 BasicTableId::KECCAK_RHO_8, BasicTableId::KECCAK_RHO_9
878 };
879
880 auto& lookup_block = circuit_builder.blocks.lookup;
881
882 if (keccak_plookup_tables.contains(table_id)) {
883 uint32_t real_out_idx = this->to_real(lookup_block.w_o()[gate_index]);
884 uint32_t real_right_idx = this->to_real(lookup_block.w_r()[gate_index]);
885 if (variables_gate_counts[real_out_idx] != 1 || variables_gate_counts[real_right_idx] != 1) {
886 bool find_out = find_position(real_out_idx);
887 auto q_c = lookup_block.q_c()[gate_index];
888 if (q_c.is_zero()) {
889 if (find_out) {
890 variables_in_one_gate.erase(real_out_idx);
891 }
892 }
893 }
894 }
895}
896
906template <typename FF, typename CircuitBuilder>
908{
909 auto find_position = [&](uint32_t real_variable_index) {
910 return variables_in_one_gate.contains(real_variable_index);
911 };
912 auto& lookup_block = circuit_builder.blocks.lookup;
913 auto& lookup_tables = circuit_builder.get_lookup_tables();
914 auto table_index = static_cast<size_t>(static_cast<uint256_t>(lookup_block.q_3()[gate_index]));
915 for (const auto& table : lookup_tables) {
916 if (table.table_index == table_index) {
917 std::unordered_set<bb::fr> column_1(table.column_1.begin(), table.column_1.end());
918 std::unordered_set<bb::fr> column_2(table.column_2.begin(), table.column_2.end());
919 std::unordered_set<bb::fr> column_3(table.column_3.begin(), table.column_3.end());
920 bb::plookup::BasicTableId table_id = table.id;
921 // false cases for AES
922 this->remove_unnecessary_aes_plookup_variables(table_id, gate_index);
923 // false cases for sha256
924 this->remove_unnecessary_sha256_plookup_variables(table_id, gate_index);
925 // false cases for keccak
926 this->remove_unnecessary_keccak_plookup_variables(table_id, gate_index);
927 // if the amount of unique elements from columns of plookup tables = 1, it means that
928 // variable from this column aren't used and we can remove it.
929 if (column_1.size() == 1) {
930 uint32_t left_idx = lookup_block.w_l()[gate_index];
931 uint32_t real_left_idx = this->to_real(left_idx);
932 bool find_left = find_position(real_left_idx);
933 if (find_left) {
934 variables_in_one_gate.erase(real_left_idx);
935 }
936 }
937 if (column_2.size() == 1) {
938 uint32_t real_right_idx = this->to_real(lookup_block.w_r()[gate_index]);
939 bool find_right = find_position(real_right_idx);
940 if (find_right) {
941 variables_in_one_gate.erase(real_right_idx);
942 }
943 }
944 if (column_3.size() == 1) {
945 uint32_t real_out_idx = this->to_real(lookup_block.w_o()[gate_index]);
946 bool find_out = find_position(real_out_idx);
947 if (find_out) {
948 variables_in_one_gate.erase(real_out_idx);
949 }
950 }
951 }
952 }
953}
954
961template <typename FF, typename CircuitBuilder>
963{
964 auto& lookup_block = circuit_builder.blocks.lookup;
965 if (lookup_block.size() > 0) {
966 for (size_t i = 0; i < lookup_block.size(); i++) {
967 this->process_current_plookup_gate(i);
968 }
969 }
970}
971
980template <typename FF, typename CircuitBuilder>
982{
983 auto& memory_block = circuit_builder.blocks.memory;
984 std::vector<uint32_t> to_remove;
985 for (const auto& var_idx : variables_in_one_gate) {
986 KeyPair key = { var_idx, &memory_block };
987 if (auto search = variable_gates.find(key); search != variable_gates.end()) {
988 std::vector<size_t> gate_indexes = variable_gates[key];
989 BB_ASSERT_EQ(gate_indexes.size(), 1U);
990 size_t gate_idx = gate_indexes[0];
991 auto q_1 = memory_block.q_1()[gate_idx];
992 auto q_2 = memory_block.q_2()[gate_idx];
993 auto q_3 = memory_block.q_3()[gate_idx];
994 auto q_4 = memory_block.q_4()[gate_idx];
995 auto q_m = memory_block.q_m()[gate_idx];
996 auto q_arith = memory_block.q_arith()[gate_idx];
997 if (q_1 == FF::one() && q_m == FF::one() && q_2.is_zero() && q_3.is_zero() && q_4.is_zero() &&
998 q_arith.is_zero()) {
999 // record witness can be in both ROM and RAM gates, so we can ignore q_c
1000 // record witness is written as 4th variable in RAM/ROM read/write gate, so we can get 4th
1001 // wire value and check it with our variable
1002 if (this->to_real(memory_block.w_4()[gate_idx]) == var_idx) {
1003 to_remove.emplace_back(var_idx);
1004 }
1005 }
1006 }
1007 }
1008 for (const auto& elem : to_remove) {
1009 variables_in_one_gate.erase(elem);
1010 }
1011}
1012
1020template <typename FF, typename CircuitBuilder>
1022{
1023 variables_in_one_gate.clear();
1024 for (const auto& pair : variables_gate_counts) {
1025 bool is_not_constant_variable = check_is_not_constant_variable(pair.first);
1026 if (pair.second == 1 && pair.first != 0 && is_not_constant_variable) {
1027 variables_in_one_gate.insert(pair.first);
1028 }
1029 }
1030 auto range_lists = circuit_builder.range_lists;
1031 std::unordered_set<uint32_t> decompose_variables;
1032 for (auto& pair : range_lists) {
1033 for (auto& elem : pair.second.variable_indices) {
1034 bool is_not_constant_variable = check_is_not_constant_variable(elem);
1035 if (variables_gate_counts[circuit_builder.real_variable_index[elem]] == 1 && is_not_constant_variable) {
1036 decompose_variables.insert(circuit_builder.real_variable_index[elem]);
1037 }
1038 }
1039 }
1040 remove_unnecessary_decompose_variables(decompose_variables);
1041 remove_unnecessary_plookup_variables();
1042 remove_unnecessary_range_constrains_variables();
1043
1044 // Remove variables that are intentionally in one gate (e.g., fix_witness, inverse checks).
1045 // These are marked at the source via update_used_witnesses().
1046 // AUDITTODO: used_witnesses stores raw witness indices, but variables_in_one_gate contains
1047 // real_variable_index values. If a witness is copy-constrained (aliased), its raw index may
1048 // differ from its real_variable_index, causing the erase to fail silently. Should convert:
1049 // variables_in_one_gate.erase(circuit_builder.real_variable_index[elem]);
1050 for (const auto& elem : circuit_builder.get_used_witnesses()) {
1051 variables_in_one_gate.erase(elem);
1052 }
1053 remove_record_witness_variables();
1054
1055 // Remove variables that only appear in sorted ROM gates - these are constrained via tau tags
1056 // (permutation argument) rather than copy constraints, matching how connected components
1057 // are filtered with is_process_rom_cc
1058 auto& memory_block = circuit_builder.blocks.memory;
1059 std::vector<uint32_t> to_remove;
1060 for (const auto& var_idx : variables_in_one_gate) {
1061 if (variable_only_in_sorted_rom_gates(var_idx, memory_block)) {
1062 to_remove.emplace_back(var_idx);
1063 }
1064 }
1065 for (const auto& elem : to_remove) {
1066 variables_in_one_gate.erase(elem);
1067 }
1068
1069 return variables_in_one_gate;
1070}
1071
1077template <typename FF, typename CircuitBuilder>
1079{
1080 info("╔═══════╦═══════╦═════════════╦═══════════╦══════════════╗");
1081 info("║ CC# ║ Size ║ Range List ║ Finalize ║ Process ROM ║");
1082 info("╠═══════╬═══════╬═════════════╬═══════════╬══════════════╣");
1083
1084 for (size_t i = 0; i < connected_components.size(); i++) {
1085 const auto& cc = connected_components[i];
1086 std::ostringstream line;
1087
1088 line << "║ " << std::setw(5) << std::right << (i + 1) << " ║ " << std::setw(5) << std::right << cc.size()
1089 << " ║ " << std::setw(11) << std::left << (cc.is_range_list_cc ? "Yes" : "No") << " ║ " << std::setw(9)
1090 << std::left << (cc.is_finalize_cc ? "Yes" : "No") << " ║ " << std::setw(12) << std::left
1091 << (cc.is_process_rom_cc ? "Yes" : "No") << " ║";
1092 info(line.str());
1093 }
1094 info("╚═══════╩═══════╩═════════════╩═══════════╩══════════════╝");
1095 info("Total connected components: ", connected_components.size());
1096}
1097
1104template <typename FF, typename CircuitBuilder> void StaticAnalyzer_<FF, CircuitBuilder>::print_variables_gate_counts()
1105{
1106 for (const auto& it : variables_gate_counts) {
1107 info("number of gates with variables ", it.first, " == ", it.second);
1108 }
1109}
1110
1118template <typename FF, typename CircuitBuilder>
1120{
1121 auto q_arith = block.q_arith()[gate_index];
1122 if (!q_arith.is_zero()) {
1123 info("q_arith == ", q_arith);
1124 // fisrtly, print selectors for standard plonk gate
1125 info("q_m == ", block.q_m()[gate_index]);
1126 info("q1 == ", block.q_1()[gate_index]);
1127 info("q2 == ", block.q_2()[gate_index]);
1128 info("q3 == ", block.q_3()[gate_index]);
1129 info("q4 == ", block.q_4()[gate_index]);
1130 info("q_c == ", block.q_c()[gate_index]);
1131
1132 if (q_arith == FF(2)) {
1133 // we have to print w_4_shift from next gate
1134 info("w_4_shift == ", block.w_4()[gate_index + 1]);
1135 }
1136 if (q_arith == FF(3)) {
1137 // we have to print w_4_shift and w_1_shift from the next gate
1138 info("w_1_shift == ", block.w_l()[gate_index + 1]);
1139 info("w_4_shift == ", block.w_4()[gate_index + 1]);
1140 }
1141 } else {
1142 return;
1143 }
1144}
1145
1153template <typename FF, typename CircuitBuilder>
1155{
1156 auto q_elliptic = block.q_elliptic()[gate_index];
1157 if (!q_elliptic.is_zero()) {
1158 info("q_elliptic == ", q_elliptic);
1159 info("q_1 == ", block.q_1()[gate_index]);
1160 info("q_m == ", block.q_m()[gate_index]);
1161 bool is_elliptic_add_gate = !block.q_1()[gate_index].is_zero() && block.q_m()[gate_index].is_zero();
1162 bool is_elliptic_dbl_gate = block.q_1()[gate_index].is_zero() && block.q_m()[gate_index] == FF::one();
1163 if (is_elliptic_add_gate) {
1164 info("x2 == ", block.w_l()[gate_index + 1]);
1165 info("x3 == ", block.w_r()[gate_index + 1]);
1166 info("y3 == ", block.w_o()[gate_index + 1]);
1167 info("y2 == ", block.w_4()[gate_index + 1]);
1168 }
1169 if (is_elliptic_dbl_gate) {
1170 info("x3 == ", block.w_r()[gate_index + 1]);
1171 info("y3 == ", block.w_o()[gate_index + 1]);
1172 }
1173 } else {
1174 return;
1175 }
1176}
1177
1186template <typename FF, typename CircuitBuilder>
1188{
1189 auto q_lookup = block.q_lookup()[gate_index];
1190 if (!q_lookup.is_zero()) {
1191 info("q_lookup == ", q_lookup);
1192 auto q_2 = block.q_2()[gate_index];
1193 auto q_m = block.q_m()[gate_index];
1194 auto q_c = block.q_c()[gate_index];
1195 info("q_2 == ", q_2);
1196 info("q_m == ", q_m);
1197 info("q_c == ", q_c);
1198 if (!q_2.is_zero()) {
1199 info("w_1_shift == ", block.w_l()[gate_index + 1]);
1200 }
1201 if (!q_m.is_zero()) {
1202 info("w_2_shift == ", block.w_r()[gate_index + 1]);
1203 }
1204 if (!q_c.is_zero()) {
1205 info("w_3_shift == ", block.w_o()[gate_index + 1]);
1206 }
1207 } else {
1208 return;
1209 }
1210}
1211
1220template <typename FF, typename CircuitBuilder>
1222{
1223 auto q_delta_range = block.q_delta_range()[gate_index];
1224 if (!q_delta_range.is_zero()) {
1225 info("q_delta_range == ", q_delta_range);
1226 info("w_1 == ", block.w_l()[gate_index]);
1227 info("w_2 == ", block.w_r()[gate_index]);
1228 info("w_3 == ", block.w_o()[gate_index]);
1229 info("w_4 == ", block.w_4()[gate_index]);
1230 info("w_1_shift == ", block.w_l()[gate_index]);
1231 } else {
1232 return;
1233 }
1234}
1235
1244template <typename FF, typename CircuitBuilder>
1246{
1247 auto internal_selector = block.q_poseidon2_internal()[gate_index];
1248 auto external_selector = block.q_poseidon2_external()[gate_index];
1249 if (!internal_selector.is_zero() || !external_selector.is_zero()) {
1250 info("q_poseidon2_internal == ", internal_selector);
1251 info("q_poseidon2_external == ", external_selector);
1252 info("w_1 == ", block.w_l()[gate_index]);
1253 info("w_2 == ", block.w_r()[gate_index]);
1254 info("w_3 == ", block.w_o()[gate_index]);
1255 info("w_4 == ", block.w_4()[gate_index]);
1256 info("w_1_shift == ", block.w_l()[gate_index + 1]);
1257 info("w_2_shift == ", block.w_r()[gate_index + 1]);
1258 info("w_3_shift == ", block.w_o()[gate_index + 1]);
1259 info("w_4_shift == ", block.w_4()[gate_index + 1]);
1260 } else {
1261 return;
1262 }
1263}
1264
1273template <typename FF, typename CircuitBuilder>
1275{
1276 auto q_nnf = block.q_nnf()[gate_idx];
1277 if (!q_nnf.is_zero()) {
1278 info("q_nnf == ", q_nnf);
1279 auto q_2 = block.q_2()[gate_idx];
1280 auto q_3 = block.q_3()[gate_idx];
1281 auto q_4 = block.q_4()[gate_idx];
1282 auto q_m = block.q_m()[gate_idx];
1283 if (q_3 == FF::one() && q_4 == FF::one()) {
1284 info("w_1_shift == ", block.w_l()[gate_idx + 1]);
1285 info("w_2_shift == ", block.w_r()[gate_idx + 1]);
1286
1287 } else if (q_3 == FF::one() && q_m == FF::one()) {
1288 info("w_1_shift == ", block.w_l()[gate_idx + 1]);
1289 info("w_2_shift == ", block.w_r()[gate_idx + 1]);
1290 info("w_3_shift == ", block.w_o()[gate_idx + 1]);
1291 info("w_4_shift == ", block.w_4()[gate_idx + 1]);
1292 } else if (q_2 == FF::one() && (q_3 == FF::one() || q_4 == FF::one() || q_m == FF::one())) {
1293 info("w_1_shift == ", block.w_l()[gate_idx + 1]);
1294 info("w_2_shift == ", block.w_r()[gate_idx + 1]);
1295 if (q_4 == FF::one() || q_m == FF::one()) {
1296 info("w_3_shift == ", block.w_o()[gate_idx + 1]);
1297 info("w_4_shift == ", block.w_4()[gate_idx + 1]);
1298 }
1299 }
1300 } else {
1301 return;
1302 }
1303}
1304
1313template <typename FF, typename CircuitBuilder>
1315{
1316 auto q_memory = block.q_memory()[gate_index];
1317 if (!q_memory.is_zero()) {
1318 info("q_memory == ", q_memory);
1319 auto q_1 = block.q_1()[gate_index];
1320 auto q_2 = block.q_2()[gate_index];
1321 auto q_3 = block.q_3()[gate_index];
1322 auto q_4 = block.q_4()[gate_index];
1323 if (q_1 == FF::one() && q_4 == FF::one()) {
1324 info("q_1 == ", q_1);
1325 info("q_4 == ", q_4);
1326 info("w_1_shift == ", block.w_l()[gate_index + 1]);
1327 info("w_2_shift == ", block.w_r()[gate_index + 1]);
1328 } else if (q_1 == FF::one() && q_2 == FF::one()) {
1329 info("q_1 == ", q_1);
1330 info("q_2 == ", q_2);
1331 info("w_1_shift == ", block.w_l()[gate_index + 1]);
1332 info("w_4_shift == ", block.w_4()[gate_index + 1]);
1333 } else if (!q_3.is_zero()) {
1334 info("q_3 == ", q_3);
1335 info("w_1_shift == ", block.w_l()[gate_index + 1]);
1336 info("w_2_shift == ", block.w_r()[gate_index + 1]);
1337 info("w_3_shift == ", block.w_o()[gate_index + 1]);
1338 info("w_4_shift == ", block.w_4()[gate_index + 1]);
1339 }
1340 } else {
1341 return;
1342 }
1343}
1344
1352template <typename FF, typename CircuitBuilder>
1354{
1356 for (const auto& [key, gates] : variable_gates) {
1357 if (key.first == real_idx) {
1358 for (size_t i = 0; i < gates.size(); i++) {
1359 size_t gate_index = gates[i];
1360 // key.second is a pointer to the block
1361 auto& block = *const_cast<BlockType*>(static_cast<const BlockType*>(key.second));
1362 info("---- printing variables in this gate");
1363 info("w_l == ",
1364 block.w_l()[gate_index],
1365 " w_r == ",
1366 block.w_r()[gate_index],
1367 " w_o == ",
1368 block.w_o()[gate_index],
1369 " w_4 == ",
1370 block.w_4()[gate_index]);
1371 info("---- printing gate info where variable with index ", key.first, " was found ----");
1372 print_arithmetic_gate_info(gate_index, block);
1373 print_elliptic_gate_info(gate_index, block);
1374 print_plookup_gate_info(gate_index, block);
1375 print_poseidon2s_gate_info(gate_index, block);
1376 print_delta_range_gate_info(gate_index, block);
1377 print_nnf_gate_info(gate_index, block);
1378 print_memory_gate_info(gate_index, block);
1379 if constexpr (IsMegaBuilder<CircuitBuilder>) {
1380 auto q_databus = block.q_busread()[gate_index];
1381 if (!q_databus.is_zero()) {
1382 info("q_databus == ", q_databus);
1383 }
1384 }
1385 info("---- finished printing ----");
1386 }
1387 }
1388 }
1389}
1390
1400template <typename FF, typename CircuitBuilder>
1402 analyze_circuit(bool filter_cc)
1403{
1404 auto variables_in_one_gate = get_variables_in_one_gate();
1405 find_connected_components();
1406 if (filter_cc) {
1407 std::vector<ConnectedComponent> main_connected_components;
1408 main_connected_components.reserve(connected_components.size());
1409 for (auto& cc : connected_components) {
1410 if (!cc.is_range_list_cc && !cc.is_finalize_cc && !cc.is_process_rom_cc) {
1411 main_connected_components.emplace_back(cc);
1412 }
1413 }
1414 return std::make_pair(std::move(main_connected_components), std::move(variables_in_one_gate));
1415 }
1416 return std::make_pair(connected_components, std::move(variables_in_one_gate));
1417}
1418
1421
1422} // namespace cdg
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
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
Definition graph.cpp:1221
void process_execution_trace()
Definition graph.cpp:252
void print_memory_gate_info(size_t gate_idx, auto &block)
this method prints all information about memory gate where variable was found
Definition graph.cpp:1314
void print_plookup_gate_info(size_t gate_idx, auto &block)
this method prints all information about plookup gate where variable was found
Definition graph.cpp:1187
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
Definition graph.cpp:157
std::unordered_map< uint32_t, std::vector< uint32_t > > variable_adjacency_lists
Definition graph.hpp:172
void remove_unnecessary_decompose_variables(const std::unordered_set< uint32_t > &decompose_variables)
this method removes unnecessary variables from decompose chains
Definition graph.cpp:692
std::vector< ConnectedComponent > find_connected_components()
this methond finds all connected components in the graph described by adjacency lists and marks some ...
Definition graph.cpp:491
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
Definition graph.cpp:462
bool check_is_not_constant_variable(const uint32_t &variable_index)
this method checks whether the variable with given index is not constant
Definition graph.cpp:391
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...
Definition graph.cpp:818
std::unordered_set< uint32_t > get_variables_in_one_gate()
this method returns a final set of variables that were in one gate
Definition graph.cpp:1021
void remove_record_witness_variables()
this method removes record witness variables from variables in one gate. initially record witness is ...
Definition graph.cpp:981
void print_variable_info(const uint32_t real_idx)
this method prints all information about gates where variable was found
Definition graph.cpp:1353
void remove_unnecessary_range_constrains_variables()
this method removes variables from range constraints that are not security critical
Definition graph.cpp:742
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
Definition graph.cpp:1402
void print_elliptic_gate_info(size_t gate_idx, auto &block)
this method prints all information about elliptic gate where variable was found
Definition graph.cpp:1154
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
Definition graph.cpp:38
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,...
Definition graph.cpp:408
bool is_gate_sorted_rom(auto &memory_block, size_t gate_idx) const
this method checks if current gate is sorted ROM gate
Definition graph.cpp:523
void print_connected_components_info()
this method prints additional information about connected components that were found in the graph
Definition graph.cpp:1078
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
Definition graph.cpp:101
void print_poseidon2s_gate_info(size_t gate_idx, auto &block)
this method prints all information about poseidon2s gate where variable was found
Definition graph.cpp:1245
std::unordered_map< uint32_t, size_t > variables_gate_counts
Definition graph.hpp:175
void save_constant_variable_indices()
this method needs to save all constant variables indices in one data structure in order to not go thr...
Definition graph.cpp:374
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,...
Definition graph.cpp:780
CircuitBuilder & circuit_builder
Definition graph.hpp:168
void remove_unnecessary_plookup_variables()
this method removes false cases plookup variables from variables in one gate
Definition graph.cpp:962
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
Definition graph.cpp:1274
void print_arithmetic_gate_info(size_t gate_idx, auto &block)
this method prints all information about arithmetic gate where variable was found
Definition graph.cpp:1119
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...
Definition graph.cpp:907
std::vector< uint32_t > get_eccop_part_connected_component(size_t index, auto &blk)
this method creates connected components from elliptic curve operation gates
Definition graph.cpp:212
void mark_range_list_connected_components()
this method marks some connected componets like they represent range lists tool needs this method to ...
Definition graph.cpp:583
void print_variables_gate_counts()
this method prints a number of gates for each variable
Definition graph.cpp:1104
void mark_process_rom_connected_component()
this method marks some connected components if they were created by function process_rom_array....
Definition graph.cpp:561
std::unordered_map< uint32_t, size_t > variables_degree
Definition graph.hpp:177
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...
Definition graph.cpp:866
std::vector< uint32_t > extract_gate_variables(size_t index, Block &blk, const bb::gate_patterns::GatePattern &pattern, const GateSelectorColumn &gate_selector_column)
Extract gate variables using a declarative pattern.
Definition graph.cpp:70
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...
Definition graph.cpp:639
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
Definition graph.cpp:443
void mark_finalize_connected_components()
this method marks some connected components like they represent separated finalize blocks the point i...
Definition graph.cpp:611
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
Definition graph.cpp:538
#define info(...)
Definition log.hpp:93
@ SHA256_BASE16_ROTATE2
Definition types.hpp:49
@ SHA256_BASE28_ROTATE6
Definition types.hpp:46
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
Definition graph.cpp:21
std::pair< uint32_t, const void * > KeyPair
Definition graph.hpp:33
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
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
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)