diff --git a/barretenberg/barretenberg.code-workspace b/barretenberg/barretenberg.code-workspace
index cd08c7a3166..c150125270a 100644
--- a/barretenberg/barretenberg.code-workspace
+++ b/barretenberg/barretenberg.code-workspace
@@ -145,6 +145,6 @@
             "cwd": "${command:cmake.buildDirectory}",
             "internalConsoleOptions": "openOnSessionStart",
             "console": "internalConsole",
-        }    
+        }
     },
 }
\ No newline at end of file
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/CMakeLists.txt
index dae39eee2de..3b7f86dca34 100644
--- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/CMakeLists.txt
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/CMakeLists.txt
@@ -1 +1 @@
-barretenberg_module(boomerang_value_detection stdlib_circuit_builders circuit_checker stdlib_primitives numeric stdlib_aes128 stdlib_sha256 stdlib_blake2s stdlib_blake3s)
\ No newline at end of file
+barretenberg_module(boomerang_value_detection stdlib_circuit_builders circuit_checker stdlib_primitives numeric stdlib_aes128 stdlib_sha256 stdlib_blake2s stdlib_blake3s stdlib_poseidon2 stdlib_primitives)
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp
index 03c31e53137..442ff9cb755 100644
--- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp
@@ -1,27 +1,64 @@
-#include "graph.hpp"
+#include "./graph.hpp"
+#include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp"
 #include <algorithm>
 #include <stack>
 
 using namespace bb::plookup;
 using namespace bb;
 
+namespace cdg {
+
 /**
- * @brief this method removes duplicate variables from a gate,
- * converts variables from a gate to real variables, and then
- * updates variable gates count for real variable indexes
+ * @brief this method finds index of the block in circuit builder by comparing pointers to blocks
+ * @tparam FF field type
+ * @param ultra_builder circuit builder containing the blocks
+ * @param block block to find
+ * @return size_t index of the found block
  */
+template <typename FF>
+size_t Graph_<FF>::find_block_index(UltraCircuitBuilder& ultra_builder, const UltraBlock& block) {
+    auto gate_blocks = ultra_builder.blocks.get_gate_blocks(); 
+    size_t index = 0;
+    for (size_t i = 0; i < gate_blocks.size(); i++) {
+        if ((void*)(&gate_blocks[i]) == (void*)(&block)) {
+            index = i;
+            break;
+        }
+    }
+    return index;
+}
+
 
+/**
+ * @brief this method processes variables from a gate by removing duplicates and updating tracking structures
+ * @tparam FF field type
+ * @param ultra_circuit_builder circuit builder containing the variables
+ * @param gate_variables vector of variables to process
+ * @param gate_index index of the current gate
+ * @param block_idx index of the current block
+ * @details The method performs several operations:
+ *          1) Removes duplicate variables from the input vector
+ *          2) Converts each variable to its real index using to_real
+ *          3) Creates key-value pairs of (variable_index, block_index) for tracking
+ *          4) Updates variable_gates map with gate indices for each variable
+ *          5) Increments the gate count for each processed variable
+ */
 template <typename FF>
 inline void Graph_<FF>::process_gate_variables(UltraCircuitBuilder& ultra_circuit_builder,
-                                               std::vector<uint32_t>& gate_variables)
+                                               std::vector<uint32_t>& gate_variables,
+                                               size_t gate_index,
+                                               size_t block_idx)
 {
     auto unique_variables = std::unique(gate_variables.begin(), gate_variables.end());
     gate_variables.erase(unique_variables, gate_variables.end());
     if (gate_variables.empty()) {
         return;
     }
-    for (size_t i = 0; i < gate_variables.size(); i++) {
-        gate_variables[i] = this->to_real(ultra_circuit_builder, gate_variables[i]);
+    for (auto& var_idx: gate_variables) {
+        var_idx = this->to_real(ultra_circuit_builder, var_idx);
+        KeyPair key = std::make_pair(var_idx, block_idx);
+        variable_gates[key].emplace_back(gate_index);
+        
     }
     for (const auto& variable_index : gate_variables) {
         variables_gate_counts[variable_index] += 1;
@@ -29,31 +66,41 @@ inline void Graph_<FF>::process_gate_variables(UltraCircuitBuilder& ultra_circui
 }
 
 /**
- * @brief this method implements connected components from arithmetic gates
- * @tparam FF
- * @param ultra_circuit_builder
- * @param index
- * @return std::vector<uint32_t>
+ * @brief this method creates connected components from arithmetic gates
+ * @tparam FF field type
+ * @param ultra_circuit_builder circuit builder containing the gates
+ * @param index index of the current gate
+ * @param block_idx index of the current block
+ * @param blk block containing the gates
+ * @return std::vector<std::vector<uint32_t>> vector of connected components from the gate and minigate
+ * @details Processes both regular arithmetic gates and minigates, handling fixed witness gates
+ *          and different arithmetic operations based on selector values
  */
-
 template <typename FF>
-inline std::vector<uint32_t> Graph_<FF>::get_arithmetic_gate_connected_component(
-    bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index)
+inline std::vector<std::vector<uint32_t>> Graph_<FF>::get_arithmetic_gate_connected_component(
+    bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t block_idx, UltraBlock& blk)
 {
-    auto& arithmetic_block = ultra_circuit_builder.blocks.arithmetic;
-    uint32_t left_idx = arithmetic_block.w_l()[index];
-    uint32_t right_idx = arithmetic_block.w_r()[index];
-    uint32_t out_idx = arithmetic_block.w_o()[index];
-    uint32_t fourth_idx = arithmetic_block.w_4()[index];
-    auto q_m = arithmetic_block.q_m()[index];
-    auto q_1 = arithmetic_block.q_1()[index];
-    auto q_2 = arithmetic_block.q_2()[index];
-    auto q_3 = arithmetic_block.q_3()[index];
-    auto q_4 = arithmetic_block.q_4()[index];
-    std::vector<uint32_t> gate_variables = {};
-    if (q_m != 0 || q_1 != 1 || q_2 != 0 || q_3 != 0 || q_4 != 0) {
-        // this is not the gate for fix_witness, so we have to process this gate
-        if (arithmetic_block.q_arith()[index] > 0) {
+    auto q_arith = blk.q_arith()[index];
+    std::vector<uint32_t> gate_variables;
+    std::vector<uint32_t> minigate_variables;
+    std::vector<std::vector<uint32_t>> all_gates_variables;
+    if (!q_arith.is_zero()) {
+        auto q_m = blk.q_m()[index];
+        auto q_1 = blk.q_1()[index];
+        auto q_2 = blk.q_2()[index];
+        auto q_3 = blk.q_3()[index];
+        auto q_4 = blk.q_4()[index];
+
+        uint32_t left_idx = blk.w_l()[index];
+        uint32_t right_idx = blk.w_r()[index];
+        uint32_t out_idx = blk.w_o()[index];
+        uint32_t fourth_idx = blk.w_4()[index];
+        if (q_m == 0 && q_1 == 1 && q_2 == 0 && q_3 == 0 && q_4 == 0 && q_arith == 1) {
+            //this is fixed_witness gate. So, variable index contains in left wire. So, we have to take only it.
+            fixed_variables.insert(this->to_real(ultra_circuit_builder, left_idx));
+        }
+        else if (q_m != 0 || q_1 != 1 || q_2 != 0 || q_3 != 0 || q_4 != 0) {
+            // this is not the gate for fix_witness, so we have to process this gate
             if (q_m != 0) {
                 gate_variables.emplace_back(left_idx);
                 gate_variables.emplace_back(right_idx);
@@ -70,140 +117,441 @@ inline std::vector<uint32_t> Graph_<FF>::get_arithmetic_gate_connected_component
             if (q_4 != 0) {
                 gate_variables.emplace_back(fourth_idx);
             }
-            if (arithmetic_block.q_arith()[index] == 2) {
+            if (q_arith == 2) {
                 // We have to use w_4_shift from the next gate
                 // if and only if the current gate isn't last, cause we can't
                 // look into the next gate
-                if (index != arithmetic_block.size() - 1) {
-                    uint32_t fourth_shift_idx = arithmetic_block.w_4()[index + 1];
-                    gate_variables.emplace_back(fourth_shift_idx);
+                if (index != blk.size() - 1) {
+                    gate_variables.emplace_back(blk.w_4()[index + 1]);
                 }
             }
-            if (arithmetic_block.q_arith()[index] == 3) {
-                // TODO(daniel): want to process this case later
-                ASSERT(false);
+            if (q_arith == 3) {
+                //In this gate mini gate is enabled, we have 2 equations: 
+                //q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0
+                //w_1 + w_4 - w_1_omega + q_m = 0  
+                minigate_variables.insert(minigate_variables.end(), {left_idx, fourth_idx});
+                if (index != blk.size() - 1) {
+                    gate_variables.emplace_back(blk.w_4()[index + 1]);
+                    minigate_variables.emplace_back(blk.w_l()[index + 1]);
+                }
             }
         }
+        this->process_gate_variables(ultra_circuit_builder, gate_variables, index, block_idx);
+        this->process_gate_variables(ultra_circuit_builder, minigate_variables, index, block_idx);
+        all_gates_variables.emplace_back(gate_variables);
+        if (!minigate_variables.empty()) {
+            all_gates_variables.emplace_back(minigate_variables);
+        }
     }
-    this->process_gate_variables(ultra_circuit_builder, gate_variables);
-    return gate_variables;
+    return all_gates_variables;
 }
 
 /**
  * @brief this method creates connected components from elliptic gates
- * @tparam FF
- * @param ultra_circuit_builder
- * @param index
- * @return std::vector<uint32_t>
+ * @tparam FF field type
+ * @param ultra_circuit_builder circuit builder containing the gates
+ * @param index index of the current gate
+ * @param block_idx index of the current block
+ * @param blk block containing the gates
+ * @return std::vector<uint32_t> vector of connected variables from the gate
+ * @details Handles both elliptic curve addition and doubling operations,
+ *          collecting variables from current and next gates as needed
  */
-
 template <typename FF>
 inline std::vector<uint32_t> Graph_<FF>::get_elliptic_gate_connected_component(
-    bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index)
+    bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t block_idx, UltraBlock& blk)
 {
-    auto& elliptic_block = ultra_circuit_builder.blocks.elliptic;
     std::vector<uint32_t> gate_variables = {};
-    bool is_elliptic_gate = elliptic_block.q_elliptic()[index] == 1;
-    bool is_elliptic_add_gate = elliptic_block.q_1()[index] != 0 && elliptic_block.q_m()[index] == 0;
-    bool is_elliptic_dbl_gate = elliptic_block.q_1()[index] == 0 && elliptic_block.q_m()[index] == 1;
-    if (is_elliptic_gate) {
-        auto right_idx = elliptic_block.w_r()[index];
-        auto out_idx = elliptic_block.w_o()[index];
+    if (!blk.q_elliptic()[index].is_zero()) {
+        bool is_elliptic_add_gate = blk.q_1()[index] != 0 && blk.q_m()[index] == 0;
+        bool is_elliptic_dbl_gate = blk.q_1()[index] == 0 && blk.q_m()[index] == 1;
+        auto right_idx = blk.w_r()[index];
+        auto out_idx = blk.w_o()[index];
         gate_variables.emplace_back(right_idx);
         gate_variables.emplace_back(out_idx);
-        if (index != elliptic_block.size() - 1) {
+        if (index != blk.size() - 1) {
             if (is_elliptic_add_gate) {
                 // if this gate is ecc_add_gate, we have to get indices x2, x3, y3, y2 from the next gate
-                gate_variables.emplace_back(elliptic_block.w_l()[index + 1]);
-                gate_variables.emplace_back(elliptic_block.w_r()[index + 1]);
-                gate_variables.emplace_back(elliptic_block.w_o()[index + 1]);
-                gate_variables.emplace_back(elliptic_block.w_4()[index + 1]);
+                gate_variables.emplace_back(blk.w_l()[index + 1]);
+                gate_variables.emplace_back(blk.w_r()[index + 1]);
+                gate_variables.emplace_back(blk.w_o()[index + 1]);
+                gate_variables.emplace_back(blk.w_4()[index + 1]);
             }
             if (is_elliptic_dbl_gate) {
                 // if this gate is ecc_dbl_gate, we have to indices x3, y3 from right and output wires
-                gate_variables.emplace_back(elliptic_block.w_r()[index + 1]);
-                gate_variables.emplace_back(elliptic_block.w_o()[index + 1]);
+                gate_variables.emplace_back(blk.w_r()[index + 1]);
+                gate_variables.emplace_back(blk.w_o()[index + 1]);
             }
         }
+        this->process_gate_variables(ultra_circuit_builder, gate_variables, index, block_idx);
     }
-    this->process_gate_variables(ultra_circuit_builder, gate_variables);
     return gate_variables;
 }
 
 /**
  * @brief this method creates connected components from sorted constraints
- *
- * @tparam FF
- * @param ultra_circuit_builder
- * @param index
- * @return std::vector<uint32_t>
+ * @tparam FF field type
+ * @param ultra_circuit_builder circuit builder containing the gates
+ * @param index index of the current gate
+ * @param block_idx index of the current block
+ * @param block block containing the gates
+ * @return std::vector<uint32_t> vector of connected variables from the gate
+ * @details Processes delta range constraints by collecting all wire indices
+ *          from the current gate
  */
-
 template <typename FF>
 inline std::vector<uint32_t> Graph_<FF>::get_sort_constraint_connected_component(
-    bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index)
+    bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t blk_idx, UltraBlock& block)
 {
-    auto& delta_range_block = ultra_circuit_builder.blocks.delta_range;
     std::vector<uint32_t> gate_variables = {};
-    if (delta_range_block.q_delta_range()[index] == 1) {
-        auto left_idx = delta_range_block.w_l()[index];
-        auto right_idx = delta_range_block.w_r()[index];
-        auto out_idx = delta_range_block.w_o()[index];
-        auto fourth_idx = delta_range_block.w_4()[index];
+    if (!block.q_delta_range()[index].is_zero()) {
+        auto left_idx = block.w_l()[index];
+        auto right_idx = block.w_r()[index];
+        auto out_idx = block.w_o()[index];
+        auto fourth_idx = block.w_4()[index];
         gate_variables.insert(gate_variables.end(), { left_idx, right_idx, out_idx, fourth_idx });
     }
-    this->process_gate_variables(ultra_circuit_builder, gate_variables);
+    this->process_gate_variables(ultra_circuit_builder, gate_variables, index, blk_idx);
     return gate_variables;
 }
 
 /**
  * @brief this method creates connected components from plookup gates
- *
- * @tparam FF
- * @param ultra_circuit_builder
- * @param index
- * @return std::vector<uint32_t>
+ * @tparam FF field type
+ * @param ultra_circuit_builder circuit builder containing the gates
+ * @param index index of the current gate
+ * @param block_idx index of the current block
+ * @param block block containing the gates
+ * @return std::vector<uint32_t> vector of connected variables from the gate
+ * @details Processes plookup gates by collecting variables based on selector values,
+ *          including variables from the next gate when necessary
  */
-
 template <typename FF>
 inline std::vector<uint32_t> Graph_<FF>::get_plookup_gate_connected_component(
-    bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index)
+    bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t blk_idx, UltraBlock& block)
 {
     std::vector<uint32_t> gate_variables;
-    auto& lookup_block = ultra_circuit_builder.blocks.lookup;
-    auto q_2 = lookup_block.q_2()[index];
-    auto q_m = lookup_block.q_m()[index];
-    auto q_c = lookup_block.q_c()[index];
-    auto left_idx = lookup_block.w_l()[index];
-    auto right_idx = lookup_block.w_r()[index];
-    auto out_idx = lookup_block.w_o()[index];
-    gate_variables.emplace_back(left_idx);
-    gate_variables.emplace_back(right_idx);
-    gate_variables.emplace_back(out_idx);
-    if (index < lookup_block.size() - 1) {
-        if (q_2 != 0 || q_m != 0 || q_c != 0) {
-            if (q_2 != 0) {
-                gate_variables.emplace_back(lookup_block.w_l()[index + 1]);
+    auto q_lookup_type = block.q_lookup_type()[index];
+    if (!q_lookup_type.is_zero()) {
+        auto q_2 = block.q_2()[index];
+        auto q_m = block.q_m()[index];
+        auto q_c = block.q_c()[index];
+        auto left_idx = block.w_l()[index];
+        auto right_idx = block.w_r()[index];
+        auto out_idx = block.w_o()[index];
+        gate_variables.emplace_back(left_idx);
+        gate_variables.emplace_back(right_idx);
+        gate_variables.emplace_back(out_idx);
+        if (index < block.size() - 1) {
+            if (q_2 != 0 || q_m != 0 || q_c != 0) {
+                if (q_2 != 0) {
+                    gate_variables.emplace_back(block.w_l()[index + 1]);
+                }
+                if (q_m != 0) {
+                    gate_variables.emplace_back(block.w_r()[index + 1]);
+                }
+                if (q_c != 0) {
+                    gate_variables.emplace_back(block.w_o()[index + 1]);
+                }
             }
-            if (q_m != 0) {
-                gate_variables.emplace_back(lookup_block.w_r()[index + 1]);
+        }
+        this->process_gate_variables(ultra_circuit_builder, gate_variables, index, blk_idx);
+    }
+    return gate_variables;
+}
+
+/**
+ * @brief this method creates connected components from poseidon2 gates
+ * @tparam FF field type
+ * @param ultra_circuit_builder circuit builder containing the gates
+ * @param index index of the current gate
+ * @param blk_idx index of the current block
+ * @param block block containing the gates
+ * @return std::vector<uint32_t> vector of connected variables from the gate
+ */
+template <typename FF>
+inline std::vector<uint32_t> Graph_<FF>::get_poseido2s_gate_connected_component(
+    bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t blk_idx, UltraBlock& block)
+{
+    std::vector<uint32_t> gate_variables;
+    auto internal_selector = block.q_poseidon2_internal()[index];
+    auto external_selector = block.q_poseidon2_external()[index];
+    if (!internal_selector.is_zero() || !external_selector.is_zero()) {
+        gate_variables.insert(gate_variables.end(),
+                              { block.w_l()[index], block.w_r()[index], block.w_o()[index], block.w_4()[index] });
+        if (index != block.size() - 1) {
+            gate_variables.insert(
+                gate_variables.end(),
+                { block.w_l()[index + 1], block.w_r()[index + 1], block.w_o()[index + 1], block.w_4()[index + 1] });
+        }
+        this->process_gate_variables(ultra_circuit_builder, gate_variables, index, blk_idx);
+    }
+    return gate_variables;
+}
+
+/**
+ * @brief this method creates connected components from auxiliary gates, including bigfield operations,
+ *        RAM and ROM consistency checks
+ * @tparam FF field type
+ * @param ultra_builder circuit builder containing the gates
+ * @param index index of the current gate
+ * @param blk_idx index of the current block
+ * @param block block containing the gates
+ * @return std::vector<uint32_t> vector of connected variables from the gate
+ */
+template <typename FF>
+inline std::vector<uint32_t> Graph_<FF>::get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_builder,
+                                                                                size_t index, size_t blk_idx, UltraBlock& block)
+{
+    std::vector<uint32_t> gate_variables;
+    if (!block.q_aux()[index].is_zero()) {
+        auto q_1 = block.q_1()[index];
+        auto q_2 = block.q_2()[index];
+        auto q_3 = block.q_3()[index];
+        auto q_4 = block.q_4()[index];
+        auto q_m = block.q_m()[index];
+        auto q_arith = block.q_arith()[index];
+        [[maybe_unused]]auto q_c = block.q_c()[index];
+
+        auto w_l = block.w_l()[index];
+        auto w_r = block.w_r()[index];
+        auto w_o = block.w_o()[index];
+        auto w_4 = block.w_4()[index];
+        if (q_3 == 1 && q_4 == 1) {
+            // bigfield limb accumulation 1
+            ASSERT(q_arith.is_zero());
+            if (index < block.size() - 1) {
+                gate_variables.insert(gate_variables.end(),
+                                     {  w_l,
+                                        w_r,
+                                        w_o,
+                                        w_4,
+                                        block.w_l()[index + 1],
+                                        block.w_r()[index + 1] });
+            }
+        }
+        else if (q_3 == 1 && q_m == 1) {
+            ASSERT(q_arith.is_zero());
+            // bigfield limb accumulation 2
+            if (index < block.size() - 1) {
+                gate_variables.insert(gate_variables.end(),
+                                      { w_o,
+                                        w_4,
+                                        block.w_l()[index + 1],
+                                        block.w_r()[index + 1],
+                                        block.w_o()[index + 1],
+                                        block.w_4()[index + 1] });
+            }
+        }
+        else if (q_2 == 1 && (q_3 == 1 || q_4 == 1 || q_m == 1)) {
+            ASSERT(q_arith.is_zero());
+            // bigfield product cases
+            if (index < block.size() - 1) {
+                std::vector<uint32_t> limb_subproduct_vars = {
+                    w_l, w_r, block.w_l()[index + 1], block.w_r()[index + 1]
+                };
+                if (q_3 == 1) {
+                    // bigfield product 1
+                    ASSERT(q_4.is_zero() && q_m.is_zero());
+                    gate_variables.insert(
+                        gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end());
+                    gate_variables.insert(gate_variables.end(), { w_o, w_4 });
+                }
+                if (q_4 == 1) {
+                    // bigfield product 2
+                    ASSERT(q_3.is_zero() && q_m.is_zero());
+                    std::vector<uint32_t> non_native_field_gate_2 = { w_l,
+                                                                      w_4,
+                                                                      w_r,
+                                                                      w_o,
+                                                                      block.w_o()[index + 1] };
+                    gate_variables.insert(
+                        gate_variables.end(), non_native_field_gate_2.begin(), non_native_field_gate_2.end());
+                    gate_variables.emplace_back(block.w_4()[index + 1]);
+                    gate_variables.insert(
+                        gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end());
+                }
+                if (q_m == 1) {
+                    // bigfield product 3
+                    ASSERT(q_4.is_zero() && q_3.is_zero());
+                    gate_variables.insert(
+                        gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end());
+                    gate_variables.insert(gate_variables.end(),
+                                          { w_4, block.w_o()[index + 1], block.w_4()[index + 1] });
+                }
+            }
+        }
+        else if (q_1 == 1 && q_4 == 1) {
+            ASSERT(q_arith.is_zero());
+            // ram timestamp check
+            if (index < block.size() - 1) {
+                gate_variables.insert(gate_variables.end(),
+                                      { block.w_r()[index + 1],
+                                        block.w_r()[index],
+                                        block.w_l()[index],
+                                        block.w_l()[index + 1],
+                                        block.w_o()[index] });
             }
-            if (q_c != 0) {
-                gate_variables.emplace_back(lookup_block.w_o()[index + 1]);
+        }
+        else if (q_1 == 1 && q_2 == 1) {
+            ASSERT(q_arith.is_zero());
+            // rom constitency check
+            if (index < block.size() - 1) {
+                gate_variables.insert(
+                    gate_variables.end(),
+                    { block.w_l()[index], block.w_l()[index + 1], block.w_4()[index], block.w_4()[index + 1] });
+            }
+        }
+        else {
+            // ram constitency check
+            if (!q_arith.is_zero()) { 
+                if (index < block.size() - 1) {
+                    gate_variables.insert(gate_variables.end(),
+                                        { block.w_o()[index],
+                                            block.w_4()[index],
+                                            block.w_l()[index + 1],
+                                            block.w_r()[index + 1],
+                                            block.w_o()[index + 1],
+                                            block.w_4()[index + 1] });
+                }
             }
         }
     }
-    this->process_gate_variables(ultra_circuit_builder, gate_variables);
+    this->process_gate_variables(ultra_builder, gate_variables, index, blk_idx);
     return gate_variables;
 }
 
 /**
- * @brief Construct a new Graph from Ultra Circuit Builder
- * @tparam FF
- * @param ultra_circuit_constructor
+ * @brief this method gets the ROM table connected component by processing ROM transcript records
+ * @tparam FF field type
+ * @param ultra_builder circuit builder containing the gates
+ * @param rom_array ROM transcript containing records with witness indices and gate information
+ * @return std::vector<uint32_t> vector of connected variables from ROM table gates
  */
+template <typename FF>
+inline std::vector<uint32_t> Graph_<FF>::get_rom_table_connected_component(
+    bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RomTranscript& rom_array)
+{
+    size_t block_index = find_block_index(ultra_builder, ultra_builder.blocks.aux);
+    ASSERT(block_index == 3);
 
-template <typename FF> Graph_<FF>::Graph_(bb::UltraCircuitBuilder& ultra_circuit_constructor)
+    // Every RomTranscript data structure has 2 main components that are interested for static analyzer:
+    // 1) records contains values that were put in the gate, we can use them to create connections between variables
+    // 2) states contains values witness indexes that we can find in the ROM record in the RomTrascript, so we can ignore
+    // state of the ROM transcript, because we still can connect all variables using variables from records.
+    std::vector<uint32_t> rom_table_variables; 
+
+    for (const auto& record : rom_array.records) {
+        std::vector<uint32_t> gate_variables;
+        size_t gate_index = record.gate_index;
+
+        auto q_1 = ultra_builder.blocks.aux.q_1()[gate_index];
+        auto q_2 = ultra_builder.blocks.aux.q_2()[gate_index];
+        auto q_3 = ultra_builder.blocks.aux.q_3()[gate_index];
+        auto q_4 = ultra_builder.blocks.aux.q_4()[gate_index];
+        auto q_m = ultra_builder.blocks.aux.q_m()[gate_index];
+        auto q_arith = ultra_builder.blocks.aux.q_arith()[gate_index];
+        auto q_c = ultra_builder.blocks.aux.q_c()[gate_index];
+
+        auto index_witness = record.index_witness;
+        auto vc1_witness = record.value_column1_witness; //state[0] from RomTranscript
+        auto vc2_witness = record.value_column2_witness; //state[1] from RomTranscript
+        auto record_witness = record.record_witness;
+
+        if (q_1 == 1 && q_m == 1 && q_2 == 0 && q_3 == 0 && q_4 == 0 && q_c == 0 && q_arith == 0) {
+            //By default ROM read gate uses variables (w_1, w_2, w_3, w_4) = (index_witness, vc1_witness, vc2_witness, record_witness)
+            //So we can update all of them 
+            gate_variables.emplace_back(index_witness);
+            if (vc1_witness != ultra_builder.zero_idx) {
+                gate_variables.emplace_back(vc1_witness);
+            }
+            if (vc2_witness != ultra_builder.zero_idx) {
+                gate_variables.emplace_back(vc2_witness);
+            }
+            gate_variables.emplace_back(record_witness);
+        }
+        this->process_gate_variables(ultra_builder, gate_variables, gate_index, block_index);
+        //after process_gate_variables function gate_variables constists of real variables indexes, so we can add all this variables in the 
+        //final vector to connect all of them
+        if (!gate_variables.empty()) {
+            rom_table_variables.insert(rom_table_variables.end(), gate_variables.begin(), gate_variables.end());
+        }
+    } 
+    return rom_table_variables;
+}
+
+/**
+ * @brief this method gets the RAM table connected component by processing RAM transcript records
+ * @tparam FF field type
+ * @param ultra_builder circuit builder containing the gates
+ * @param ram_array RAM transcript containing records with witness indices and gate information
+ * @return std::vector<uint32_t> vector of connected variables from RAM table gates
+ */
+template <typename FF>
+inline std::vector<uint32_t> Graph_<FF>::get_ram_table_connected_component(
+    bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RamTranscript& ram_array)
+{
+    size_t block_index = find_block_index(ultra_builder, ultra_builder.blocks.aux);
+    ASSERT(block_index == 3);
+    std::vector<uint32_t> ram_table_variables;
+    for (const auto& record : ram_array.records) {
+        std::vector<uint32_t> gate_variables;
+        size_t gate_index = record.gate_index;
+
+        auto q_1 = ultra_builder.blocks.aux.q_1()[gate_index];
+        auto q_2 = ultra_builder.blocks.aux.q_2()[gate_index];
+        auto q_3 = ultra_builder.blocks.aux.q_3()[gate_index];
+        auto q_4 = ultra_builder.blocks.aux.q_4()[gate_index];
+        auto q_m = ultra_builder.blocks.aux.q_m()[gate_index];
+        auto q_arith = ultra_builder.blocks.aux.q_arith()[gate_index];
+        auto q_c = ultra_builder.blocks.aux.q_c()[gate_index];
+
+        auto index_witness = record.index_witness;
+        auto timestamp_witness = record.timestamp_witness; 
+        auto value_witness = record.value_witness; 
+        auto record_witness = record.record_witness;
+
+        if (q_1 == 1 && q_m == 1 && q_2 == 0 && q_3 == 0 && q_4 == 0 && q_arith == 0 && (q_c == 0 || q_c == 1)) {
+            //By default RAM read/write gate uses variables (w_1, w_2, w_3, w_4) = (index_witness, timestamp_witness, value_witness, record_witness)
+            //So we can update all of them 
+            gate_variables.emplace_back(index_witness);
+            if (timestamp_witness != ultra_builder.zero_idx) {
+                gate_variables.emplace_back(timestamp_witness);
+            }
+            if (value_witness != ultra_builder.zero_idx) {
+                gate_variables.emplace_back(value_witness);
+            }
+            gate_variables.emplace_back(record_witness);
+        }
+        this->process_gate_variables(ultra_builder, gate_variables, gate_index, block_index);
+        //after process_gate_variables function gate_variables constists of real variables indexes, so we can add all these variables in the 
+        //final vector to connect all of them
+        ram_table_variables.insert(ram_table_variables.end(), gate_variables.begin(), gate_variables.end());
+    }
+    return ram_table_variables;
+}
+
+/**
+ * @brief Construct a new Graph from Ultra Circuit Builder
+ * @tparam FF field type used in the circuit
+ * @param ultra_circuit_constructor circuit builder containing all gates and variables
+ * @details This constructor initializes the graph structure by:
+ *          1) Creating data structures for tracking:
+ *             - Number of gates each variable appears in (variables_gate_counts)
+ *             - Adjacency lists for each variable (variable_adjacency_lists)
+ *             - Degree of each variable (variables_degree)
+ *          2) Processing different types of gates:
+ *             - Arithmetic gates
+ *             - Elliptic curve gates
+ *             - Plookup gates
+ *             - Poseidon2 gates
+ *             - Auxiliary gates
+ *             - Delta range gates
+ *          3) Creating connections between variables that appear in the same gate
+ *          4) Special handling for sorted constraints in delta range blocks
+ */
+template <typename FF> 
+Graph_<FF>::Graph_(bb::UltraCircuitBuilder& ultra_circuit_constructor)
 {
     this->variables_gate_counts =
         std::unordered_map<uint32_t, size_t>(ultra_circuit_constructor.real_variable_index.size());
@@ -217,49 +565,62 @@ template <typename FF> Graph_<FF>::Graph_(bb::UltraCircuitBuilder& ultra_circuit
     }
 
     std::map<FF, uint32_t> constant_variable_indices = ultra_circuit_constructor.constant_variable_indices;
-    const auto& arithmetic_block = ultra_circuit_constructor.blocks.arithmetic;
-    auto arithmetic_gates_numbers = arithmetic_block.size();
-    bool arithmetic_gates_exist = arithmetic_gates_numbers > 0;
-    if (arithmetic_gates_exist) {
-        for (size_t i = 0; i < arithmetic_gates_numbers; i++) {
-            auto gate_variables = this->get_arithmetic_gate_connected_component(ultra_circuit_constructor, i);
-            this->connect_all_variables_in_vector(ultra_circuit_constructor, gate_variables, false);
-        }
-    }
-    const auto& elliptic_block = ultra_circuit_constructor.blocks.elliptic;
-    auto elliptic_gates_numbers = elliptic_block.size();
-    bool elliptic_gates_exist = elliptic_gates_numbers > 0;
-    if (elliptic_gates_exist) {
-        for (size_t i = 0; i < elliptic_gates_numbers; i++) {
-            std::vector<uint32_t> gate_variables =
-                this->get_elliptic_gate_connected_component(ultra_circuit_constructor, i);
-            this->connect_all_variables_in_vector(ultra_circuit_constructor, gate_variables, false);
-        }
-    }
-    const auto& range_block = ultra_circuit_constructor.blocks.delta_range;
-    auto range_gates = range_block.size();
-    bool range_gates_exists = range_gates > 0;
-    if (range_gates_exists) {
-        std::vector<uint32_t> sorted_variables;
-        for (size_t i = 0; i < range_gates; i++) {
-            auto current_gate = this->get_sort_constraint_connected_component(ultra_circuit_constructor, i);
-            if (current_gate.empty()) {
-                this->connect_all_variables_in_vector(ultra_circuit_constructor, sorted_variables, true);
-                sorted_variables.clear();
-            } else {
-                sorted_variables.insert(sorted_variables.end(), current_gate.begin(), current_gate.end());
-            }
-        }
-    }
-
-    const auto& lookup_block = ultra_circuit_constructor.blocks.lookup;
-    auto lookup_gates = lookup_block.size();
-    bool lookup_gates_exists = lookup_gates > 0;
-    if (lookup_gates_exists) {
-        for (size_t i = 0; i < lookup_gates; i++) {
+    auto gate_blocks = ultra_circuit_constructor.blocks.get_gate_blocks(); 
+    for (size_t blk_idx = 0; blk_idx < gate_blocks.size(); blk_idx++) {
+        if (gate_blocks[blk_idx].size() > 0) {
+            std::vector<uint32_t> sorted_variables;
+            for (size_t gate_idx = 0; gate_idx < gate_blocks[blk_idx].size(); gate_idx++) {
+                auto arithmetic_gates_variables = get_arithmetic_gate_connected_component(ultra_circuit_constructor, gate_idx, blk_idx, gate_blocks[blk_idx]);
+                if (!arithmetic_gates_variables.empty()) {
+                    for (const auto& gate_variables: arithmetic_gates_variables) {
+                        //info("size of arithmetic_gate == ", gate_variables.size());
+                        connect_all_variables_in_vector(ultra_circuit_constructor, gate_variables, /*is_sorted_variables=*/false);
+                    }
+                }
+                auto elliptic_gate_variables = get_elliptic_gate_connected_component(ultra_circuit_constructor, gate_idx, blk_idx, gate_blocks[blk_idx]);
+                //info("size of elliptic_gate == ", elliptic_gate_variables.size());
+                connect_all_variables_in_vector(ultra_circuit_constructor, elliptic_gate_variables, /*is_sorted_variables=*/false);
+                auto lookup_gate_variables = get_plookup_gate_connected_component(ultra_circuit_constructor, gate_idx, blk_idx, gate_blocks[blk_idx]);
+                //info("size of lookup_gate == ", lookup_gate_variables.size());
+                connect_all_variables_in_vector(ultra_circuit_constructor, lookup_gate_variables, /*is_sorted_variables=*/false);
+                auto poseidon2_gate_variables = get_poseido2s_gate_connected_component(ultra_circuit_constructor, gate_idx, blk_idx, gate_blocks[blk_idx]);
+                //info("size of poseidon2_gate == ", poseidon2_gate_variables.size());
+                connect_all_variables_in_vector(ultra_circuit_constructor, poseidon2_gate_variables, /*is_sorted_variables=*/false);
+                auto aux_gate_variables = get_auxiliary_gate_connected_component(ultra_circuit_constructor, gate_idx, blk_idx, gate_blocks[blk_idx]);
+                //info("size of aux_gate == ", aux_gate_variables.size());
+                connect_all_variables_in_vector(ultra_circuit_constructor, aux_gate_variables, /*is_sorted_variables=*/false);
+                if (arithmetic_gates_variables.empty() && elliptic_gate_variables.empty() && lookup_gate_variables.empty() && poseidon2_gate_variables.empty() && aux_gate_variables.empty()) {
+                    //if all vectors are empty it means that current block is delta range, and it needs another processing method
+                    auto delta_range_gate_variables = get_sort_constraint_connected_component(ultra_circuit_constructor, gate_idx, blk_idx, gate_blocks[blk_idx]);
+                    if (delta_range_gate_variables.empty()) {
+                        connect_all_variables_in_vector(ultra_circuit_constructor, sorted_variables, /*is_sorted_variables=*/true);
+                        sorted_variables.clear();
+                    }
+                    else {
+                        sorted_variables.insert(sorted_variables.end(), delta_range_gate_variables.begin(), delta_range_gate_variables.end());
+                    }
+                }
+            }
+        }
+    }
+
+    const auto& rom_arrays = ultra_circuit_constructor.rom_arrays;
+    if (rom_arrays.size() > 0) {
+        for (size_t i = 0; i < rom_arrays.size(); i++) {
+            std::vector<uint32_t> variable_indices =
+                this->get_rom_table_connected_component(ultra_circuit_constructor, rom_arrays[i]);
+            this->connect_all_variables_in_vector(
+                ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false);
+        }
+    }
+
+    const auto& ram_arrays = ultra_circuit_constructor.ram_arrays;
+    if (ram_arrays.size() > 0) {
+        for (size_t i = 0; i < ram_arrays.size(); i++) {
             std::vector<uint32_t> variable_indices =
-                this->get_plookup_gate_connected_component(ultra_circuit_constructor, i);
-            this->connect_all_variables_in_vector(ultra_circuit_constructor, variable_indices, false);
+                this->get_ram_table_connected_component(ultra_circuit_constructor, ram_arrays[i]);
+            this->connect_all_variables_in_vector(
+                ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false);
         }
     }
 }
@@ -289,7 +650,7 @@ bool Graph_<FF>::check_is_not_constant_variable(bb::UltraCircuitBuilder& ultra_c
 }
 
 /**
- * @brief this method adds connection between 2 variables, if they are in one gate, they are not constraint variables,
+ * @brief this method adds connection between 2 variables, if they are in one gate, they are not constrant variables,
  * and they have different indexes
  * @tparam FF
  * @param ultra_circuit_builder
@@ -388,7 +749,7 @@ void Graph_<FF>::depth_first_search(const uint32_t& variable_index,
 /**
  * @brief this methond finds all connected components in the graph described by adjacency lists
  * @tparam FF
- * @return std::vector<std::vector<uint32_t>>
+ * @return std::vector<std::vector<uint32_t>> list of connected components where each component is a vector of variable indices
  */
 
 template <typename FF> std::vector<std::vector<uint32_t>> Graph_<FF>::find_connected_components()
@@ -472,8 +833,7 @@ inline size_t Graph_<FF>::process_current_decompose_chain(bb::UltraCircuitBuilde
 }
 
 /**
- * @brief this method gets the endpoints of the decompose chains. For that it has to clean variable_index
- from unnecessary variables for example, left, right, output wires and go through all decompose chain
+ * @brief this method removes unnecessary variables from decompose chains
  * @tparam FF
  * @param ultra_circuit_builder
  * @param variables_in_one_gate
@@ -522,8 +882,42 @@ inline void Graph_<FF>::remove_unnecessary_decompose_variables(bb::UltraCircuitB
         }
     }
 }
+
 /**
- * @brief this method removes false positive cass variables from aes plookup tables.
+ * @brief this method removes variables from range constraints that are not security critical
+ * @tparam FF field type
+ * @param ultra_builder circuit builder containing the range lists
+ * @details Right now static analyzer removes two types of variables:
+ *          1) Variables from delta_range_constraints created by finalize_circuit()
+ *          2) Variables from range_constraints created by range_constraint_into_two_limbs
+ */
+template <typename FF>
+void Graph_<FF>::remove_unnecessary_range_constrains_variables(bb::UltraCircuitBuilder& ultra_builder) {    
+    std::map<uint64_t, UltraCircuitBuilder::RangeList> range_lists = ultra_builder.range_lists;
+    std::unordered_set<uint32_t> range_lists_tau_tags;
+    std::unordered_set<uint32_t> range_lists_range_tags;
+    std::vector<uint32_t> real_variable_tags = ultra_builder.real_variable_tags;
+    for (const auto& pair: range_lists) {
+        UltraCircuitBuilder::RangeList list = pair.second;
+        range_lists_tau_tags.insert(list.tau_tag);
+        range_lists_range_tags.insert(list.range_tag);
+    }
+    for (uint32_t real_index = 0; real_index < real_variable_tags.size(); real_index++) {
+        if (variables_in_one_gate.contains(real_index)) {
+            //this if helps us to remove variables from delta_range_constraints when finalize_circuit() function was called
+            if (range_lists_tau_tags.contains(real_variable_tags[real_index])) {
+                variables_in_one_gate.erase(real_index);
+            }
+            //this if helps us to remove variables from range_constraints when range_constraint_into_two_limbs function was called
+            if (range_lists_range_tags.contains(real_variable_tags[real_index])) {
+                variables_in_one_gate.erase(real_index);
+            }
+        }
+    }
+}
+
+/**
+ * @brief this method removes false cases variables from aes plookup tables.
  * AES_SBOX_MAP, AES_SPARSE_MAP, AES_SPARSE_NORMALIZE tables are used in read_from_1_to_2_table function which
  * return values C2[0], so C3[0] isn't used anymore in these cases, but this situation isn't dangerous.
  * So, we have to remove these variables.
@@ -699,21 +1093,60 @@ inline void Graph_<FF>::remove_unnecessary_plookup_variables(bb::UltraCircuitBui
     }
 }
 
+/**
+ * @brief this method removes record witness variables from variables in one gate.
+ * initially record witness is added in the circuit as ctx->add_variable(0), where ctx -- circuit builder.
+ * then aren't used anymore, so we can remove from the static analyzer.
+ * @tparam FF 
+ * @param ultra_builder 
+ */
+
+template <typename FF>
+inline void Graph_<FF>::remove_record_witness_variables(bb::UltraCircuitBuilder& ultra_builder) {
+    const auto& gate_blocks = ultra_builder.blocks.get_gate_blocks();
+    size_t blk_idx = find_block_index(ultra_builder, ultra_builder.blocks.aux);
+    std::vector<uint32_t> to_remove;
+    ASSERT(blk_idx == 3);
+    for (const auto& var_idx: variables_in_one_gate) {
+        KeyPair key = {var_idx, blk_idx};
+        if (auto search = variable_gates.find(key); search != variable_gates.end()) {
+            std::vector<size_t> gate_indexes = variable_gates[key];
+            ASSERT(gate_indexes.size() == 1);
+            size_t gate_idx = gate_indexes[0];
+            auto q_1 = gate_blocks[blk_idx].q_1()[gate_idx];
+            auto q_2 = gate_blocks[blk_idx].q_2()[gate_idx];
+            auto q_3 = gate_blocks[blk_idx].q_3()[gate_idx];
+            auto q_4 = gate_blocks[blk_idx].q_4()[gate_idx];
+            auto q_m = gate_blocks[blk_idx].q_m()[gate_idx];
+            auto q_arith = gate_blocks[blk_idx].q_arith()[gate_idx];
+            if (q_1 == 1 && q_m == 1 && q_2 == 0 && q_3 == 0 && q_4 == 0 && q_arith == 0) {
+                //record witness can be in both ROM and RAM gates, so we can ignore q_c 
+                //record witness is written as 4th variable in RAM/ROM read/write gate, so we can get 4th wire value and check it with our variable
+                if (this->to_real(ultra_builder, gate_blocks[blk_idx].w_4()[gate_idx]) == var_idx) {
+                    to_remove.emplace_back(var_idx);
+                } 
+            }
+        }
+    }
+    for (const auto& elem: to_remove) {
+        variables_in_one_gate.erase(elem);
+    }
+}
+
 /**
  * @brief this method returns a final set of variables that were in one gate
  * @tparam FF
- * @param ultra_circuit_builder
- * @return std::unordered_set<uint32_t>
+ * @param ultra_circuit_builder circuit builder containing the variables
+ * @return std::unordered_set<uint32_t> set of variable indices
  */
 
 template <typename FF>
 std::unordered_set<uint32_t> Graph_<FF>::show_variables_in_one_gate(bb::UltraCircuitBuilder& ultra_circuit_builder)
 {
-    std::unordered_set<uint32_t> variables_in_one_gate;
     for (const auto& pair : variables_gate_counts) {
         bool is_not_constant_variable = this->check_is_not_constant_variable(ultra_circuit_builder, pair.first);
         if (pair.second == 1 && pair.first != 0 && is_not_constant_variable) {
-            variables_in_one_gate.insert(pair.first);
+            this->variables_in_one_gate.insert(pair.first);
         }
     }
     auto range_lists = ultra_circuit_builder.range_lists;
@@ -727,18 +1160,22 @@ std::unordered_set<uint32_t> Graph_<FF>::show_variables_in_one_gate(bb::UltraCir
             }
         }
     }
-    this->remove_unnecessary_decompose_variables(ultra_circuit_builder, variables_in_one_gate, decompose_varialbes);
-    this->remove_unnecessary_plookup_variables(ultra_circuit_builder, variables_in_one_gate);
+    this->remove_unnecessary_decompose_variables(
+        ultra_circuit_builder, this->variables_in_one_gate, decompose_varialbes);
+    this->remove_unnecessary_plookup_variables(ultra_circuit_builder, this->variables_in_one_gate);
+    this->remove_unnecessary_range_constrains_variables(ultra_circuit_builder);
+    for (const auto& elem: this->fixed_variables) {
+        this->variables_in_one_gate.erase(elem);
+    }
+    this->remove_record_witness_variables(ultra_circuit_builder);
     return variables_in_one_gate;
 }
 
 /**
- * @brief this method returns connected component with a given index and size of this component
- * sometimes for debugging we want to check the size one of the connected component, so it would be
- * useful to know its size
- * @param connected_components
- * @param index
- * @return std::pair<std::vector<uint32_t>, size_t>
+ * @brief this method returns connected component with a given index and its size
+ * @param connected_components vector of all connected components
+ * @param index index of required component
+ * @return std::pair<std::vector<uint32_t>, size_t> pair of component and its size
  */
 
 std::pair<std::vector<uint32_t>, size_t> get_connected_component_with_index(
@@ -763,7 +1200,7 @@ std::pair<std::vector<uint32_t>, size_t> get_connected_component_with_index(
 template <typename FF> void Graph_<FF>::print_graph()
 {
     for (const auto& elem : variable_adjacency_lists) {
-        info("variable with index", elem.first);
+        info("variable with index ", elem.first);
         if (variable_adjacency_lists[elem.first].empty()) {
             info("is isolated");
         } else {
@@ -791,9 +1228,7 @@ template <typename FF> void Graph_<FF>::print_connected_components()
 }
 
 /**
- * @brief this method prints a number of gates for each variable.
- * while processing the arithmetic circuit, we count for each variable the number of gates it has participated in.
- * sometimes for debugging purposes it is useful to see how many gates each variable has participated in.
+ * @brief this method prints a number of gates for each variable
  * @tparam FF
  */
 
@@ -805,20 +1240,38 @@ template <typename FF> void Graph_<FF>::print_variables_gate_counts()
 }
 
 /**
- * @brief this method prints a number of edges for each variable.
- * while processing the arithmetic circuit, we conut for each variable the number of edges, i.e. connections with other
- * variables though the gates. perhaps in the future counting the number of edges for each vertex can be useful for
- * analysis, and this function will be used for debugging.
- * @tparam FF
+ * @brief this method prints a number of edges for each variable
+ * @tparam FF 
+ * @param ultra_builder 
  */
 
-template <typename FF> void Graph_<FF>::print_variables_edge_counts()
-{
-    for (const auto& it : variables_degree) {
-        if (it.first != 0) {
-            info("variable index = ", it.first, "number of edges for this variable = ", it.second);
-        }
-    }
-}
+ template <typename FF> void Graph_<FF>::print_variables_in_one_gate(bb::UltraCircuitBuilder& ultra_builder)
+ {
+     const auto& gate_blocks = ultra_builder.blocks.get_gate_blocks();
+     for (const auto& [key, gates]: variable_gates) {
+         if (variables_in_one_gate.contains(key.first)) {
+             ASSERT(gates.size() == 1);
+             size_t gate_index = gates[0];
+             UltraBlock block = gate_blocks[key.second];
+             info("---- printing gate selectors where variable with index ", key.first, " was found ----");
+             info("q_m == ", block.q_m()[gate_index]);
+             info("q_c == ", block.q_c()[gate_index]);
+             info("q_1 == ", block.q_1()[gate_index]);
+             info("q_2 == ", block.q_2()[gate_index]);
+             info("q_3 == ", block.q_3()[gate_index]);
+             info("q_4 == ", block.q_4()[gate_index]);
+             info("q_arith == ", block.q_arith()[gate_index]);
+             info("q_delta_range == ", block.q_delta_range()[gate_index]);
+             info("q_elliptic == ", block.q_elliptic()[gate_index]);
+             info("q_aux == ", block.q_aux()[gate_index]);
+             info("q_lookup_type == ", block.q_lookup_type()[gate_index]);
+             info("q_poseidon2_external == ", block.q_poseidon2_external()[gate_index]);
+             info("q_poseidon2_internal == ", block.q_poseidon2_internal()[gate_index]);
+             info("---- finished printing ----");
+         }
+     }
+ }
 
 template class Graph_<bb::fr>;
+
+} //namespace cdg
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp
index c4c88e1e159..13ee090ee47 100644
--- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp
@@ -7,6 +7,7 @@
 #include <unordered_set>
 #include <utility>
 #include <vector>
+#include <typeinfo>
 
 /*
  * this class describes arithmetic circuit as an undirected graph, where vertices are variables from circuit.
@@ -16,6 +17,38 @@
  * constrained properly. if number of connected components > 1, it means that there were missed some connections between
  * variables.
  */
+
+namespace cdg {
+
+/*
+ * we add a new feature for static analyzer, now it contains gates where it found every variable. This may be helpful, if we want to do functions that
+ * remove false-positive variables from the analyzer using selectors in the gate + some additional knowledge about this variable, for example, tau or range tags.
+ * this info contains in unordered map with key as std::pair<uint32_t, size_t>, where uint32_t -- real variable index and size_t -- index of UltraTraceBlock in 
+ * Reference Array with all TraceBlocks, that Ultra Circuit Builder contains inside. But there was a problem with unordered map -- it doesn't have default hash function and 
+ * function for checking equivalence for std::pair as a key, so we had to implement it ourselves. We decided to choose approach based on function hash_combine from boost library
+ * for C++, and it's not so difficult to hash 2 elements in pair and check their equivalence. 
+*/   
+using UltraBlock = bb::UltraCircuitBuilder::Arithmetization::UltraTraceBlock;
+using KeyPair = std::pair<uint32_t, size_t>;
+
+struct KeyHasher{
+    size_t operator()(const KeyPair& pair) const {
+        size_t combined_hash = 0;
+        auto hash_combiner = [](size_t lhs, size_t rhs) {
+            return lhs ^ (rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2));
+        };
+        combined_hash = hash_combiner(combined_hash, std::hash<uint32_t>()(pair.first));
+        combined_hash = hash_combiner(combined_hash, std::hash<size_t>()(pair.second));
+        return combined_hash;
+    }
+};
+
+struct KeyEquals{
+    bool operator()(const KeyPair& p1, const KeyPair& p2) const {
+        return (p1.first == p2.first && p1.second == p2.second);
+    }
+};
+
 template <typename FF> class Graph_ {
   public:
     Graph_() = default;
@@ -25,24 +58,36 @@ template <typename FF> class Graph_ {
     Graph_&& operator=(Graph_&& other) = delete;
     Graph_(const bb::StandardCircuitBuilder_<FF>& circuit_constructor);
     Graph_(bb::UltraCircuitBuilder& ultra_circuit_constructor);
-
+    
     uint32_t to_real(bb::UltraCircuitBuilder& ultra_circuit_constructor, const uint32_t& variable_index)
     {
         return ultra_circuit_constructor.real_variable_index[variable_index];
     };
+    size_t find_block_index(bb::UltraCircuitBuilder& ultra_builder, const UltraBlock& block);
     void process_gate_variables(bb::UltraCircuitBuilder& ultra_circuit_constructor,
-                                std::vector<uint32_t>& gate_variables);
-
+                                std::vector<uint32_t>& gate_variables,
+                                size_t gate_index,
+                                size_t blk_idx);
     std::unordered_map<uint32_t, size_t> get_variables_gate_counts() { return this->variables_gate_counts; };
 
-    std::vector<uint32_t> get_arithmetic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder,
-                                                                  size_t index);
+    std::vector<std::vector<uint32_t>> get_arithmetic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder,
+                                                                  size_t index, size_t block_idx, UltraBlock& blk);
     std::vector<uint32_t> get_elliptic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder,
-                                                                size_t index);
+                                                                size_t index, size_t block_idx, UltraBlock& blk);
     std::vector<uint32_t> get_plookup_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder,
-                                                               size_t index);
+                                                               size_t index, size_t block_idx, UltraBlock& blk);
     std::vector<uint32_t> get_sort_constraint_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder,
-                                                                  size_t index);
+                                                                  size_t index, size_t block_idx, UltraBlock& blk);
+    std::vector<uint32_t> get_poseido2s_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder,
+                                                                 size_t index,
+                                                                 size_t block_idx,
+                                                                 UltraBlock& blk);
+    std::vector<uint32_t> get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder,
+                                                                 size_t index, size_t block_idx, UltraBlock& blk);
+    std::vector<uint32_t> get_rom_table_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder,
+                                                            const bb::UltraCircuitBuilder::RomTranscript& rom_array);
+    std::vector<uint32_t> get_ram_table_connected_component(bb::UltraCircuitBuilder& ultra_builder,
+                                                            const bb::UltraCircuitBuilder::RamTranscript& ram_array);
 
     void add_new_edge(const uint32_t& first_variable_index, const uint32_t& second_variable_index);
     std::vector<uint32_t> get_variable_adjacency_list(const uint32_t& variable_index)
@@ -89,6 +134,7 @@ template <typename FF> class Graph_ {
                                                 const std::unordered_set<uint32_t>& decompose_variables);
     void remove_unnecessary_plookup_variables(bb::UltraCircuitBuilder& ultra_circuit_builder,
                                               std::unordered_set<uint32_t>& variables_in_on_gate);
+    void remove_unnecessary_range_constrains_variables(bb::UltraCircuitBuilder& ultra_builder);
     std::unordered_set<uint32_t> show_variables_in_one_gate(bb::UltraCircuitBuilder& ultra_circuit_builder);
 
     void remove_unnecessary_aes_plookup_variables(std::unordered_set<uint32_t>& variables_in_one_gate,
@@ -99,11 +145,13 @@ template <typename FF> class Graph_ {
                                                      bb::UltraCircuitBuilder& ultra_circuit_builder,
                                                      bb::plookup::BasicTableId& table_id,
                                                      size_t gate_index);
+    void remove_record_witness_variables(bb::UltraCircuitBuilder& ultra_builder);
 
     void print_graph();
     void print_connected_components();
     void print_variables_gate_counts();
     void print_variables_edge_counts();
+    void print_variables_in_one_gate(bb::UltraCircuitBuilder& ultra_builder);
     ~Graph_() = default;
 
   private:
@@ -114,6 +162,10 @@ template <typename FF> class Graph_ {
         variables_gate_counts; // we use this data structure to count, how many gates use every variable
     std::unordered_map<uint32_t, size_t>
         variables_degree; // we use this data structure to count, how many every variable have edges
+    std::unordered_map<KeyPair, std::vector<size_t>, KeyHasher, KeyEquals> variable_gates; //we use this data structure to store gates and TraceBlocks for every variables, where static analyzer found them in the circuit.
+    std::unordered_set<uint32_t> variables_in_one_gate;
+    std::unordered_set<uint32_t> fixed_variables;
 };
 
-using Graph = Graph_<bb::fr>;
\ No newline at end of file
+using Graph = Graph_<bb::fr>;
+} //namespace cgd
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description.test.cpp
index 26f50cc8db1..e357192a347 100644
--- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description.test.cpp
@@ -11,7 +11,7 @@
 #include <gtest/gtest.h>
 
 using namespace bb;
-
+using namespace cdg;
 /**
  * @brief this test checks graph description of the circuit with arithmetic gates
     the number of connected components = the number of pair (i, j), 0<=i, j <16, i.e 256
@@ -38,10 +38,8 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_arithmetic_gates)
 
     Graph graph = Graph(circuit_constructor);
     auto connected_components = graph.find_connected_components();
-    auto num_connected_components = connected_components.size();
-    auto variables_in_one_gate = graph.show_variables_in_one_gate(circuit_constructor);
-    bool result = num_connected_components == 256;
-    EXPECT_EQ(result, true);
+    [[maybe_unused]]auto variables_in_one_gate = graph.show_variables_in_one_gate(circuit_constructor);
+    EXPECT_EQ(connected_components.size(), 256);
 }
 
 /**
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_aes128.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_aes128.test.cpp
index 9db54f96429..45e458f72de 100644
--- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_aes128.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_aes128.test.cpp
@@ -12,19 +12,17 @@
 
 using namespace bb;
 using namespace bb::stdlib;
+using namespace cdg;
 
 using Builder = UltraCircuitBuilder;
-typedef stdlib::field_t<UltraCircuitBuilder> field_pt;
-typedef stdlib::witness_t<bb::UltraCircuitBuilder> witness_pt;
+using field_pt = stdlib::field_t<UltraCircuitBuilder>;
+using witness_pt = stdlib::witness_t<bb::UltraCircuitBuilder>;
 
-bool check_in_vector(const std::vector<field_pt>& input_vector, const uint32_t& real_var_index)
+void fix_vector_witness(std::vector<field_pt>& input_vector)
 {
-    for (const auto& elem : input_vector) {
-        if (elem.witness_index == real_var_index) {
-            return true;
-        }
+    for (auto& elem : input_vector) {
+        elem.fix_witness();
     }
-    return false;
 }
 
 /**
@@ -41,7 +39,7 @@ TEST(boomerang_stdlib_aes, test_graph_for_aes_64_bytes)
                     0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
                     0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 };
 
-    const auto convert_bytes = [](uint8_t* data) {
+    auto convert_bytes = [](uint8_t* data) {
         uint256_t converted(0);
         for (uint64_t i = 0; i < 16; ++i) {
             uint256_t to_add = uint256_t((uint64_t)(data[i])) << uint256_t((15 - i) * 8);
@@ -59,17 +57,21 @@ TEST(boomerang_stdlib_aes, test_graph_for_aes_64_bytes)
         witness_pt(&builder, fr(convert_bytes(in + 48))),
     };
 
+    fix_vector_witness(in_field);
+
     field_pt key_field(witness_pt(&builder, fr(convert_bytes(key))));
     field_pt iv_field(witness_pt(&builder, fr(convert_bytes(iv))));
+    key_field.fix_witness();
+    iv_field.fix_witness();
 
-    const auto result = stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field);
+    auto result = stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field);
+    fix_vector_witness(result);
 
     Graph graph = Graph(builder);
     auto connected_components = graph.find_connected_components();
-    auto num_connected_components = connected_components.size();
-    bool graph_result = num_connected_components == 1;
-
-    EXPECT_EQ(graph_result, true);
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
 }
 
 /**
@@ -88,7 +90,7 @@ TEST(boomerang_stdlib_aes, test_variable_gates_count_for_aes128cbc)
                     0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
                     0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 };
 
-    const auto convert_bytes = [](uint8_t* data) {
+    auto convert_bytes = [](uint8_t* data) {
         uint256_t converted(0);
         for (uint64_t i = 0; i < 16; ++i) {
             uint256_t to_add = uint256_t((uint64_t)(data[i])) << uint256_t((15 - i) * 8);
@@ -106,18 +108,19 @@ TEST(boomerang_stdlib_aes, test_variable_gates_count_for_aes128cbc)
         witness_pt(&builder, fr(convert_bytes(in + 48))),
     };
 
+    fix_vector_witness(in_field);
+
     field_pt key_field(witness_pt(&builder, fr(convert_bytes(key))));
     field_pt iv_field(witness_pt(&builder, fr(convert_bytes(iv))));
+    key_field.fix_witness();
+    iv_field.fix_witness();
 
-    const auto result = stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field);
+    auto result = stdlib::aes128::encrypt_buffer_cbc(in_field, iv_field, key_field);
+    fix_vector_witness(result);
 
     Graph graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
     std::unordered_set<uint32_t> variables_in_one_gate = graph.show_variables_in_one_gate(builder);
-    for (const auto& elem : variables_in_one_gate) {
-        bool result1 = check_in_vector(in_field, elem);
-        bool result2 = check_in_vector(result, elem);
-        bool check =
-            (result1 == 1) || (result2 == 1) || (elem == key_field.witness_index) || (elem == iv_field.witness_index);
-        EXPECT_EQ(check, true);
-    }
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
 }
\ No newline at end of file
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_bigfield.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_bigfield.test.cpp
new file mode 100644
index 00000000000..cfdf030c58a
--- /dev/null
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_bigfield.test.cpp
@@ -0,0 +1,397 @@
+#include "barretenberg/boomerang_value_detection/graph.hpp"
+#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp"
+#include "barretenberg/numeric/random/engine.hpp"
+
+#include "barretenberg/ecc/curves/bn254/fq.hpp"
+#include "barretenberg/ecc/curves/bn254/fr.hpp"
+
+#include "barretenberg/stdlib/primitives/bool/bool.hpp"
+#include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp"
+#include "barretenberg/stdlib/primitives/field/field.hpp"
+#include "barretenberg/circuit_checker/circuit_checker.hpp"
+#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp"
+#include "barretenberg/stdlib/primitives/curves/bn254.hpp"
+#include "barretenberg/transcript/origin_tag.hpp"
+#include "barretenberg/common/test.hpp"
+#include <memory>
+#include <utility>
+
+using namespace bb;
+using namespace cdg;
+
+namespace {
+auto& engine = numeric::get_debug_randomness();
+}
+
+using Builder = UltraCircuitBuilder;
+using bn254 = stdlib::bn254<Builder>;
+using fr_ct = bn254::ScalarField;
+using fq_ct = bn254::BaseField;
+using public_witness_ct = bn254::public_witness_ct;
+using witness_ct = bn254::witness_ct;
+
+void fix_bigfield_element(const fq_ct& element) {
+    for (int i = 0; i < 4; i++) {
+        element.binary_basis_limbs[i].element.fix_witness();
+    }
+    element.prime_basis_limb.fix_witness();
+}
+
+/**
+ * @brief this test checks graph description for bigfield constructors
+ * The result is one connected component with one variable in one gate,
+ * testing different types of bigfield construction
+ * @details Tests construction of:
+ *          - Constant value
+ *          - Witness from u512
+ *          - Small field witness
+ *          - Mixed construction with lower limb addition
+ */
+TEST(boomerang_bigfield, test_graph_description_bigfield_constructors) { 
+    Builder builder;
+    [[maybe_unused]]fq_ct constant = fq_ct(1);
+    [[maybe_unused]]fq_ct var = fq_ct::create_from_u512_as_witness(&builder, 1);
+    [[maybe_unused]]fr_ct small_var = witness_ct(&builder, fr(1));
+    [[maybe_unused]]fq_ct mixed = fq_ct(1).add_to_lower_limb(small_var, 1);
+    [[maybe_unused]]fq_ct r;
+
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 1);
+}
+
+/**
+ * @brief this test checks graph description for bigfield addition operations
+ * The result is one connected component with no variables in one gate,
+ * testing various addition combinations with fix_bigfield_element
+ */
+TEST(boomerang_bigfield, test_graph_description_bigfield_addition) {
+    Builder builder;
+    [[maybe_unused]]fq_ct var = fq_ct::create_from_u512_as_witness(&builder, 1);
+    [[maybe_unused]]fr_ct small_var = witness_ct(&builder, fr(1));
+    [[maybe_unused]]fq_ct mixed = fq_ct(1).add_to_lower_limb(small_var, 1);
+    [[maybe_unused]]fq_ct r;
+    [[maybe_unused]]fq_ct r1;
+    [[maybe_unused]]fq_ct r2;
+
+    r = mixed + var;
+    fix_bigfield_element(r);
+    r1 = r + mixed;
+    fix_bigfield_element(r1);
+    r2 = r + var;
+    fix_bigfield_element(r2);
+
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+/**
+ * @brief this test checks graph description for bigfield subtraction operations
+ * The result is one connected component with no variables in one gate,
+ * testing all possible subtraction combinations between mixed, constant, and variable values
+ */
+TEST(boomerang_bigfield, test_graph_description_bigfield_substraction) {
+    Builder builder;
+    [[maybe_unused]]fq_ct constant = fq_ct(1);
+    [[maybe_unused]]fq_ct var = fq_ct::create_from_u512_as_witness(&builder, 1);
+    [[maybe_unused]]fr_ct small_var = witness_ct(&builder, fr(1));
+    [[maybe_unused]]fq_ct mixed = fq_ct(1).add_to_lower_limb(small_var, 1);
+    [[maybe_unused]]fq_ct r;
+
+    r = mixed - mixed;
+    fix_bigfield_element(r);
+    r = mixed - constant;
+    fix_bigfield_element(r);
+    r = mixed - var;
+    fix_bigfield_element(r);
+    r = var - mixed;
+    fix_bigfield_element(r);
+
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+    for (const auto& elem: variables_in_one_gate) {
+        info("elem == ", elem);
+    }
+}
+
+/**
+ * @brief this test checks graph description for bigfield multiplication operations
+ * The result is one connected component with no variables in one gate,
+ * testing all possible multiplication combinations
+ */
+TEST(boomerang_bigfield, test_graph_description_bigfield_multiplication) {
+    Builder builder;
+    [[maybe_unused]]fq_ct constant = fq_ct(1);
+    [[maybe_unused]]fq_ct var = fq_ct::create_from_u512_as_witness(&builder, 1);
+    [[maybe_unused]]fr_ct small_var = witness_ct(&builder, fr(1));
+    [[maybe_unused]]fq_ct mixed = fq_ct(1).add_to_lower_limb(small_var, 1);
+    [[maybe_unused]]fq_ct r;
+
+    r = var * constant;
+    r = constant * constant;
+    r = mixed * var;
+    r = mixed * constant;
+    r = mixed * mixed;
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+/**
+ * @brief this test checks graph description for bigfield division operations
+ * The result is one connected component with three variables in one gate,
+ * testing division operations with circuit checking
+ * @details Each division operator creates one inverse variable for polynomial gate check (a * a_inv - 1 = 0)
+ */
+TEST(boomerang_bigfield, test_graph_description_bigfield_division) {
+    Builder builder;
+    [[maybe_unused]]fq_ct constant = fq_ct(1);
+    [[maybe_unused]]fq_ct var = fq_ct::create_from_u512_as_witness(&builder, 1);
+    [[maybe_unused]]fr_ct small_var = witness_ct(&builder, fr(1));
+    [[maybe_unused]]fq_ct mixed = fq_ct(1).add_to_lower_limb(small_var, 1);
+    [[maybe_unused]]fq_ct r;
+
+    r = constant / var;
+    fix_bigfield_element(r);
+    r = constant / constant;
+    r = mixed / mixed;
+    fix_bigfield_element(r);
+    r = mixed / var;
+    fix_bigfield_element(r);
+
+    CircuitChecker::check(builder);
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    //every operator / in bigfield creates one inverse variable for poly gate to check a * a_inv - 1 = 0. 
+    //it is the false case, but it will be secure just to check that there are no other variables except for them
+    //otherwise there is a possibility to remove dangerous variables from other functions.
+    EXPECT_EQ(variables_in_one_gate.size(), 3);     
+}
+
+/**
+ * @brief this test checks graph description for mixed bigfield operations
+ * The result is one connected component with two variables in one gate,
+ * testing combinations of addition, subtraction, multiplication and division
+ */
+TEST(boomerang_bigfield, test_graph_description_bigfield_mix_operations) {
+    auto builder = Builder();
+    fq_ct constant = fq_ct(1);
+    fq_ct var = fq_ct::create_from_u512_as_witness(&builder, 1);
+    fr_ct small_var = witness_ct(&builder, fr(1));
+    fq_ct mixed = fq_ct(1).add_to_lower_limb(small_var, 1);
+    fq_ct r;
+
+    r = mixed + mixed;
+    fix_bigfield_element(r);
+    r = mixed - mixed;
+    fix_bigfield_element(r);
+    r = mixed + var;
+    fix_bigfield_element(r);
+    r = mixed + constant;
+    fix_bigfield_element(r);
+    r = mixed - var;
+    fix_bigfield_element(r);
+    r = mixed - constant;
+    fix_bigfield_element(r);
+    r = var - mixed;
+    fix_bigfield_element(r);
+
+    r = var * constant;
+    fix_bigfield_element(r);
+    r = constant / var;
+    fix_bigfield_element(r);
+    r = constant * constant;
+    r = constant / constant;
+
+    r = mixed * var;
+    fix_bigfield_element(r);
+    r = mixed / var;
+    fix_bigfield_element(r);
+    r = mixed * mixed;
+    fix_bigfield_element(r);
+    r = mixed * constant;
+    fix_bigfield_element(r);
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 2);
+}
+
+/**
+ * @brief this test checks graph description for high/low bits constructor and operations
+ * The result is one connected component with no variables in one gate,
+ * testing bit-sliced construction and repeated additions
+ */
+TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits_and_operations) {
+    auto builder = Builder();
+    size_t num_repetitions = 3;
+    fq inputs[2]{ fq::random_element(), fq::random_element() };
+    fq_ct a(witness_ct(&builder, fr(uint256_t(inputs[0]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
+            witness_ct(&builder, fr(uint256_t(inputs[0]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
+    fq_ct b(witness_ct(&builder, fr(uint256_t(inputs[1]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
+            witness_ct(&builder, fr(uint256_t(inputs[1]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
+    fq_ct c = a * b;
+    for (size_t i = 0; i < num_repetitions; ++i) {
+        fq d = fq::random_element();
+        fq_ct d1(witness_ct(&builder, fr(uint256_t(d).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
+                 witness_ct(&builder, fr(uint256_t(d).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
+        c = c + d1;
+    }
+    fix_bigfield_element(c);
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1); 
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+/**
+ * @brief this test checks graph description for multiple multiplication operations
+ * The result is num_repetitions connected components with no variables in one gate,
+ * testing independent multiplication operations
+ */
+TEST(boomerang_bigfield, test_graph_description_mul_function) {
+    auto builder = Builder();
+    size_t num_repetitions = 4;
+    for (size_t i = 0; i < num_repetitions; ++i) {
+        fq inputs[2]{ fq::random_element(), fq::random_element()};
+        fq_ct a(witness_ct(&builder, fr(uint256_t(inputs[0]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
+                witness_ct(&builder, fr(uint256_t(inputs[0]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
+        fq_ct b(witness_ct(&builder, fr(uint256_t(inputs[1]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
+                witness_ct(&builder, fr(uint256_t(inputs[1]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
+
+        fq_ct c = a * b;
+        fix_bigfield_element(c);
+    }
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), num_repetitions);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+/**
+ * @brief this test checks graph description for square operations
+ * The result is num_repetitions connected components with no variables in one gate,
+ * testing repeated squaring operations on random inputs
+ */
+TEST(boomerang_bigfield, test_graph_description_sqr_function) {
+    auto builder = Builder();
+    size_t num_repetitions = 10;
+    for (size_t i = 0; i < num_repetitions; ++i) {
+        fq input = fq::random_element();
+        fq_ct a(witness_ct(&builder, fr(uint256_t(input).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
+                witness_ct(&builder, fr(uint256_t(input).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
+        fq_ct c = a.sqr();
+        fix_bigfield_element(c);
+    }
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), num_repetitions);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+/**
+ * @brief this test checks graph description for multiply-add operations
+ * The result is num_repetitions connected components with no variables in one gate,
+ * testing multiply-add operations with three inputs
+ */
+TEST(boomerang_bigfield, test_graph_description_madd_function) {
+    auto builder = Builder();
+    size_t num_repetitions = 5;
+    for (size_t i = 0; i < num_repetitions; ++i) {
+        fq inputs[3]{ fq::random_element(), fq::random_element(), fq::random_element() };
+        fq_ct a(witness_ct(&builder, fr(uint256_t(inputs[0]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
+                witness_ct(&builder, fr(uint256_t(inputs[0]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
+        fq_ct b(witness_ct(&builder, fr(uint256_t(inputs[1]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
+                witness_ct(&builder, fr(uint256_t(inputs[1]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
+        fq_ct c(witness_ct(&builder, fr(uint256_t(inputs[2]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
+                witness_ct(&builder, fr(uint256_t(inputs[2]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
+        [[maybe_unused]]fq_ct d = a.madd(b, { c }); 
+        fix_bigfield_element(d);
+    }
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), num_repetitions);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+/**
+ * @brief this test checks graph description for multiple multiply-add operations
+ * The result is connected components with no variables in one gate,
+ * testing batch multiply-add operations with multiple inputs
+ * @details Uses arrays of size number_of_madds=16 for left multiply, right multiply and add values
+ */
+TEST(boomerang_bigfield, test_graph_description_mult_madd_function) {
+
+    auto builder = Builder();
+    size_t num_repetitions = 1;
+    const size_t number_of_madds = 16;
+    for (size_t i = 0; i < num_repetitions; ++i) {
+        fq mul_left_values[number_of_madds];
+        fq mul_right_values[number_of_madds];
+        fq to_add_values[number_of_madds];
+
+        std::vector<fq_ct> mul_left;
+        std::vector<fq_ct> mul_right;
+        std::vector<fq_ct> to_add;
+        mul_left.reserve(number_of_madds);
+        mul_right.reserve(number_of_madds);
+        to_add.reserve(number_of_madds);
+        for (size_t j = 0; j < number_of_madds; j++) {
+            mul_left_values[j] = fq::random_element();
+            mul_right_values[j] = fq::random_element();
+            mul_left.emplace_back(
+                fq_ct::create_from_u512_as_witness(&builder, uint512_t(uint256_t(mul_left_values[j]))));
+            mul_right.emplace_back(
+                fq_ct::create_from_u512_as_witness(&builder, uint512_t(uint256_t(mul_right_values[j]))));
+            to_add_values[j] = fq::random_element();
+            to_add.emplace_back(
+                fq_ct::create_from_u512_as_witness(&builder, uint512_t(uint256_t(to_add_values[j]))));
+        }
+        fq_ct f = fq_ct::mult_madd(mul_left, mul_right, to_add);
+        fix_bigfield_element(f);
+    }
+    builder.finalize_circuit(false);
+    auto graph = Graph(builder);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0); 
+}
+
+/**
+ * @brief this test checks graph description for high/low bits constructor
+ * The result is connected components with no variables in one gate,
+ * testing basic multiplication with bit-sliced construction
+ */
+TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits)
+{
+    auto builder = Builder();
+    fq mul_left_value = fq::random_element();
+    fq mul_right_value = fq::random_element();
+    //fq mul_right_value = fq::random_element();
+    [[maybe_unused]]fq_ct mul_left = fq_ct::create_from_u512_as_witness(&builder, uint512_t(uint256_t(mul_left_value)));
+    [[maybe_unused]]fq_ct mul_right = fq_ct::create_from_u512_as_witness(&builder, uint512_t(uint256_t(mul_right_value)));
+    fq_ct product = mul_left * mul_right;
+    fix_bigfield_element(product);
+    builder.finalize_circuit(false);
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_blake2s.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_blake2s.test.cpp
index 934e92b568a..a7711330f04 100644
--- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_blake2s.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_blake2s.test.cpp
@@ -10,6 +10,10 @@
 
 using namespace bb;
 using namespace bb::stdlib;
+<<<<<<< HEAD
+using namespace cdg;
+=======
+>>>>>>> a86b797d059502fbd402550492f9ad13bd4ede1c
 
 using Builder = UltraCircuitBuilder;
 
@@ -21,7 +25,7 @@ using public_witness_t = public_witness_t<Builder>;
 
 /**
  * @brief this tests check graph description of circuit for blake2s for one and two blocks.
- * all graphs must have one connected component.
+ * all graphs must have one connected component and 0 variables in one gate.
  */
 
 TEST(boomerang_stdlib_blake2s, test_graph_for_blake2s_single_block_plookup)
@@ -36,6 +40,8 @@ TEST(boomerang_stdlib_blake2s, test_graph_for_blake2s_single_block_plookup)
     Graph graph = Graph(builder);
     auto connected_components = graph.find_connected_components();
     EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
 }
 
 TEST(boomerang_stdlib_blake2s, test_graph_for_blake2s_double_block_plookup)
@@ -54,4 +60,6 @@ TEST(boomerang_stdlib_blake2s, test_graph_for_blake2s_double_block_plookup)
     Graph graph = Graph(builder);
     auto connected_components = graph.find_connected_components();
     EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
 }
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_blake3s.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_blake3s.test.cpp
index d826f1e080b..c8729d3ef44 100644
--- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_blake3s.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_blake3s.test.cpp
@@ -9,6 +9,10 @@
 #include <gtest/gtest.h>
 
 using namespace bb;
+<<<<<<< HEAD
+using namespace cdg;
+=======
+>>>>>>> a86b797d059502fbd402550492f9ad13bd4ede1c
 
 using byte_array = stdlib::byte_array<bb::StandardCircuitBuilder>;
 using public_witness_t = stdlib::public_witness_t<bb::StandardCircuitBuilder>;
@@ -26,17 +30,14 @@ TEST(boomerang_stdlib_blake3s, test_single_block_plookup)
     auto builder = UltraBuilder();
     std::string input = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01";
     std::vector<uint8_t> input_v(input.begin(), input.end());
-
     byte_array_plookup input_arr(&builder, input_v);
     byte_array_plookup output = stdlib::blake3s(input_arr);
-
     std::vector<uint8_t> expected = blake3::blake3s(input_v);
-
-    EXPECT_EQ(output.get_value(), expected);
-
     Graph graph = Graph(builder);
     auto connected_components = graph.find_connected_components();
     EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
 }
 
 TEST(boomerang_stdlib_blake3s, test_double_block_plookup)
@@ -50,9 +51,9 @@ TEST(boomerang_stdlib_blake3s, test_double_block_plookup)
 
     std::vector<uint8_t> expected = blake3::blake3s(input_v);
 
-    EXPECT_EQ(output.get_value(), expected);
-
     Graph graph = Graph(builder);
     auto connected_components = graph.find_connected_components();
     EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
 }
\ No newline at end of file
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_dynamic_array.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_dynamic_array.test.cpp
new file mode 100644
index 00000000000..3fba4f8b37d
--- /dev/null
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_dynamic_array.test.cpp
@@ -0,0 +1,89 @@
+#include "barretenberg/boomerang_value_detection/graph.hpp"
+#include "barretenberg/common/test.hpp"
+#include "barretenberg/numeric/random/engine.hpp"
+#include "barretenberg/stdlib/primitives/bool/bool.hpp"
+#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp"
+#include "barretenberg/stdlib/primitives/memory/dynamic_array.hpp"
+
+using namespace bb;
+using namespace cdg;
+namespace {
+auto& engine = bb::numeric::get_debug_randomness();
+}
+
+// Defining ultra-specific types for local testing.
+using Builder = UltraCircuitBuilder;
+using bool_ct = stdlib::bool_t<Builder>;
+using field_ct = stdlib::field_t<Builder>;
+using witness_ct = stdlib::witness_t<Builder>;
+using DynamicArray_ct = stdlib::DynamicArray<Builder>;
+
+/**
+ * @brief this test checks graph description for dynamic array resize operation
+ * The result is one connected component with one variable in one gate,
+ * testing array initialization, pushing elements, and resizing operations
+ * @details Test includes:
+ *          - Array initialization with max size
+ *          - Sequential push of witness elements
+ *          - Resize operation with witness size
+ */
+TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_method_resize_test)
+{
+
+    Builder builder;
+    const size_t max_size = 10;
+
+    DynamicArray_ct array(&builder, max_size);
+
+    field_ct next_size = field_ct(witness_ct(&builder, (uint256_t)(max_size - 1)));
+    for (size_t i = 0; i < max_size; ++i) {
+        array.push(field_ct::from_witness(&builder, i));
+    }
+
+    array.resize(next_size, 7);
+    Graph graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(connected_components.size(), 1);
+    EXPECT_EQ(variables_in_one_gate.size(), max_size);
+}
+
+
+/**
+ * @brief this test checks graph description for dynamic array consistency methods
+ * The result is one connected component with no variables in one gate,
+ * testing all array manipulation operations
+ * @details Test includes sequence of operations:
+ *          - Sequential push of witness elements
+ *          - Sequential pop of all elements
+ *          - Array resize
+ *          - Conditional push operations (true and false cases)
+ *          - Conditional pop operations (true and false cases)
+ */
+TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_consistency_methods) 
+{
+    Builder builder;
+    const size_t max_size = 10;
+
+    DynamicArray_ct array(&builder, max_size);
+
+    for (size_t i = 0; i < max_size; ++i) {
+        array.push(field_ct::from_witness(&builder, i));
+    }
+
+    for (size_t i = 0; i < max_size; ++i) {
+        array.pop();
+    }
+
+    array.resize(max_size - 1, 7);
+
+    array.conditional_push(false, 100);
+    array.conditional_push(true, 100);
+    array.conditional_pop(false);
+    array.conditional_pop(true);
+    Graph graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), max_size);
+}
\ No newline at end of file
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_poseidon2s_permutation.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_poseidon2s_permutation.test.cpp
new file mode 100644
index 00000000000..2fd690d4f32
--- /dev/null
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_poseidon2s_permutation.test.cpp
@@ -0,0 +1,215 @@
+#include "barretenberg/boomerang_value_detection/graph.hpp"
+
+#include "barretenberg/crypto/poseidon2/poseidon2.hpp"
+#include "barretenberg/crypto/poseidon2/poseidon2_params.hpp"
+#include "barretenberg/stdlib/hash/poseidon2/poseidon2.hpp"
+#include "barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp"
+
+#include "barretenberg/plonk_honk_shared/arithmetization/gate_data.hpp"
+#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp"
+#include "barretenberg/stdlib/primitives/curves/bn254.hpp"
+
+#include "barretenberg/circuit_checker/circuit_checker.hpp"
+#include "barretenberg/common/test.hpp"
+#include "barretenberg/numeric/random/engine.hpp"
+using namespace bb;
+using namespace cdg;
+
+namespace {
+auto& engine = numeric::get_debug_randomness();
+}
+
+using Params = crypto::Poseidon2Bn254ScalarFieldParams;
+using Builder = UltraCircuitBuilder;
+using Permutation = stdlib::Poseidon2Permutation<Params, Builder>;
+using field_t = stdlib::field_t<Builder>;
+using witness_t = stdlib::witness_t<Builder>;
+using _curve = stdlib::bn254<Builder>;
+using byte_array_ct = _curve::byte_array_ct;
+using fr_ct = typename _curve::ScalarField;
+using witness_ct = typename _curve::witness_ct;
+
+
+bool check_in_input_vector(const std::vector<field_t>& input_vector, const uint32_t& real_var_index)
+{
+    for (const auto& elem : input_vector) {
+        if (elem.witness_index == real_var_index) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * @brief this test checks graph description for poseidon2 hash with random inputs
+ * The result is one connected component, and all output variables must be in one gate
+ */
+void test_poseidon2s_circuit(size_t num_inputs = 5)
+{
+    auto builder = Builder();
+    std::vector<field_t> inputs;
+
+    for (size_t i = 0; i < num_inputs; ++i) {
+        auto element = fr::random_element(&engine);
+        inputs.emplace_back(field_t(witness_t(&builder, element)));
+    }
+
+    for (auto& elem: inputs) {
+        elem.fix_witness();
+    }
+    [[maybe_unused]]auto result = stdlib::poseidon2<Builder>::hash(builder, inputs);
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    std::unordered_set<uint32_t> outputs{result.witness_index, result.witness_index + 1, result.witness_index + 2, result.witness_index + 3};
+    for (const auto& elem: variables_in_one_gate) {
+        EXPECT_EQ(outputs.contains(elem), true);
+    }
+}
+
+/**
+ * @brief this test checks graph description for poseidon2 hash with byte array input
+ * The result is one connected component, and all output variables must be in one gate
+ */
+void test_poseidon2s_hash_byte_array(size_t num_inputs = 5) 
+{
+    Builder builder;
+
+    std::vector<uint8_t> input;
+    input.reserve(num_inputs);
+    for (size_t i = 0; i < num_inputs; ++i) {
+        input.push_back(engine.get_random_uint8());
+    }
+
+    byte_array_ct circuit_input(&builder, input);
+    auto result = stdlib::poseidon2<Builder>::hash_buffer(builder, circuit_input);
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    std::unordered_set<uint32_t> outputs{result.witness_index, result.witness_index + 1, result.witness_index + 2, result.witness_index + 3};
+    for (const auto& elem: variables_in_one_gate) {
+        EXPECT_EQ(outputs.contains(elem), true);
+    }
+}
+
+/**
+ * @brief this test checks graph description for repeated poseidon2 hash operations
+ * The result is one connected component with repeated hashing of pairs,
+ * all output variables from each hash operation must be in one gate
+ */
+void test_poseidon2s_hash_repeated_pairs(size_t num_inputs = 5) 
+{
+    Builder builder;
+
+    fr left_in = fr::random_element();
+    fr right_in = fr::random_element();
+
+    fr_ct left = witness_ct(&builder, left_in);
+    fr_ct right = witness_ct(&builder, right_in);
+    right.fix_witness();
+    std::unordered_set<uint32_t> outputs{left.witness_index};
+    // num_inputs - 1 iterations since the first hash hashes two elements
+    for (size_t i = 0; i < num_inputs - 1; ++i) {
+        left = stdlib::poseidon2<Builder>::hash(builder, { left, right });
+        outputs.insert(left.witness_index + 1);
+        outputs.insert(left.witness_index + 2);
+        outputs.insert(left.witness_index + 3); 
+    }
+    left.fix_witness();
+
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    for (const auto& elem: variables_in_one_gate) {
+        EXPECT_EQ(outputs.contains(elem), true);
+    }
+}
+
+/**
+ * @brief this test checks graph description for a single poseidon2 permutation
+ * The result is one connected component with no variables in one gate,
+ * as permutation connects all variables through its internal structure
+ */
+TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_one_permutation)
+{
+    std::array<field_t, Params::t> inputs;
+    auto builder = Builder();
+
+    for (size_t i = 0; i < Params::t; ++i) {
+        const auto element = fr::random_element(&engine);
+        inputs[i] = field_t(witness_t(&builder, element));
+    }
+
+    auto poseidon2permutation = Permutation();
+    [[maybe_unused]] auto new_state = poseidon2permutation.permutation(&builder, inputs);
+    for (auto& elem: new_state) {
+        elem.fix_witness();
+    }
+
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+/**
+ * @brief this test checks graph description for two separate poseidon2 permutations
+ * The result is two connected components (one for each permutation) with no variables in one gate,
+ * verifying that different input sets create separate components
+ */
+TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_two_permutations)
+{
+    // we want to check that 2 permutations for different inputs give different connected components
+    std::array<field_t, Params::t> input1;
+    std::array<field_t, Params::t> input2;
+    auto builder = Builder();
+
+    for (size_t i = 0; i < Params::t; ++i) {
+        const auto el1 = fr::random_element(&engine);
+        input1[i] = field_t(witness_t(&builder, el1));
+        const auto el2 = fr::random_element(&engine);
+        input2[i] = field_t(witness_t(&builder, el2));
+    }
+
+    auto poseidon2permutation = Permutation();
+    [[maybe_unused]] auto state1 = poseidon2permutation.permutation(&builder, input1);
+    [[maybe_unused]] auto state2 = poseidon2permutation.permutation(&builder, input2);
+    for (auto& elem: state1) {
+        elem.fix_witness();
+    }
+    for (auto& elem: state2) {
+        elem.fix_witness();
+    }
+    auto graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 2);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+TEST(boomerang_poseidon2s, test_graph_for_poseidon2s)
+{
+    for (size_t num_inputs = 6; num_inputs < 100; num_inputs++) {
+        test_poseidon2s_circuit(num_inputs);
+    }
+}
+
+TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_for_one_input_size)
+{
+    test_poseidon2s_circuit();
+}
+
+TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_hash_byte_array) {
+    for (size_t num_inputs = 6; num_inputs < 100; num_inputs++) {    
+        test_poseidon2s_hash_byte_array(num_inputs);
+    }
+}
+
+TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_hash_repeated_pairs)
+{
+    test_poseidon2s_hash_repeated_pairs();
+}
\ No newline at end of file
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_ram_rom.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_ram_rom.test.cpp
new file mode 100644
index 00000000000..9bb96666f81
--- /dev/null
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_ram_rom.test.cpp
@@ -0,0 +1,166 @@
+#include "barretenberg/boomerang_value_detection/graph.hpp"
+#include "barretenberg/common/test.hpp"
+#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp"
+#include "barretenberg/stdlib/primitives/memory/ram_table.hpp"
+#include "barretenberg/stdlib/primitives/memory/rom_table.hpp"
+
+using namespace bb;
+using namespace cdg;
+namespace {
+auto& engine = numeric::get_debug_randomness();
+}
+
+using Builder = UltraCircuitBuilder;
+using field_ct = stdlib::field_t<Builder>;
+using witness_ct = stdlib::witness_t<Builder>;
+using rom_table_ct = stdlib::rom_table<Builder>;
+using ram_table_ct = stdlib::ram_table<Builder>;
+
+/**
+ * @brief this test checks graph description for ROM table operations
+ * The result is one connected component from reading random values at sequential indices,
+ * with no variables in one gate due to connections through table accesses
+ */
+TEST(boomerang_rom_ram_table, graph_description_rom_table)
+{
+    Builder builder;
+
+    std::vector<field_ct> table_values;
+    const size_t table_size = 10;
+    for (size_t i = 0; i < table_size; ++i) {
+        table_values.emplace_back(witness_ct(&builder, bb::fr::random_element()));
+    }
+    for (auto& elem: table_values) {
+        elem.fix_witness();
+    }
+
+    rom_table_ct table(table_values);
+    std::unordered_set<uint32_t> safety_variables;
+
+    field_ct result = field_ct(witness_ct(&builder, (uint64_t)0));
+
+    for (size_t i = 0; i < 10; ++i) {
+        safety_variables.insert(result.witness_index);
+        field_ct index(witness_ct(&builder, (uint64_t)i));
+        index.fix_witness();
+        result += table[index];
+    }
+
+    result.fix_witness();
+    Graph graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    for (const auto& elem: variables_in_one_gate) {
+        EXPECT_EQ(variables_in_one_gate.contains(elem), true);
+    } 
+}
+
+/**
+ * @brief this test checks graph description for RAM table read operations
+ * The result is one connected component from reading random values at sequential indices,
+ * with no variables in one gate due to connections through table reads
+ */
+TEST(boomerang_rom_ram_table, graph_description_ram_table_read)
+{
+    Builder builder;
+
+    std::vector<field_ct> table_values;
+    const size_t table_size = 10;
+    for (size_t i = 0; i < table_size; ++i) {
+        table_values.emplace_back(witness_ct(&builder, bb::fr::random_element()));
+    }
+
+    for (auto& elem: table_values) {
+        elem.fix_witness();
+    }
+
+    ram_table_ct table(table_values);
+    field_ct result = field_ct(witness_ct(&builder, (uint64_t)0));
+    std::unordered_set<uint32_t> safety_variables;
+
+    for (size_t i = 0; i < 10; ++i) {
+        safety_variables.insert(result.witness_index);
+        field_ct index(witness_ct(&builder, (uint64_t)i));
+        index.fix_witness();
+        result += table.read(index);
+    }
+
+    result.fix_witness();
+    Graph graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    for (const auto& elem: variables_in_one_gate) {
+        EXPECT_EQ(safety_variables.contains(elem), true);
+    }
+}
+
+/**
+ * @brief this test checks graph description for RAM table write and read operations
+ * The result is one connected component from alternating write and read operations,
+ * with non-sequential access patterns and no variables in one gate.
+ * @details Test includes:
+ *          - Initial zero initialization
+ *          - Multiple update-read cycles
+ *          - Non-sequential read access pattern
+ */
+TEST(boomerang_rom_ram_table, graph_description_ram_table_write)
+{
+    Builder builder;
+    const size_t table_size = 10;
+
+    std::vector<fr> table_values(table_size);
+    ram_table_ct table(&builder, table_size);
+
+    for (size_t i = 0; i < table_size; ++i) {
+        table.write(i, 0);
+    }
+    std::unordered_set<uint32_t> safety_variables;
+    field_ct result(0);
+    safety_variables.insert(result.witness_index);
+
+    const auto update = [&]() {
+        for (size_t i = 0; i < table_size / 2; ++i) {
+            table_values[2 * i] = fr::random_element();
+            table_values[2 * i + 1] = fr::random_element();
+
+            // init with both constant and variable values
+            field_ct value1(witness_ct(&builder, table_values[2 * i]));
+            field_ct value2(witness_ct(&builder, table_values[2 * i + 1]));
+            value1.fix_witness();
+            value2.fix_witness();
+            table.write(2 * i, value1);
+            table.write(2 * i + 1, value2);
+        }
+    };
+
+    const auto read = [&]() {
+        for (size_t i = 0; i < table_size / 2; ++i) {
+            const size_t index = table_size - 2 - (i * 2); // access in something other than basic incremental order
+            field_ct index1(witness_ct(&builder, index));
+            field_ct index2(witness_ct(&builder, index + 1));
+            index1.fix_witness();
+            index2.fix_witness();
+            result += table.read(index1);
+            safety_variables.insert(result.witness_index);
+            result += table.read(index2);
+            safety_variables.insert(result.witness_index);
+        }
+    };
+
+    update();
+    read();
+    update();
+    read();
+    update();
+
+    result.fix_witness();
+    Graph graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    for (const auto& elem: variables_in_one_gate) {
+        EXPECT_EQ(safety_variables.contains(elem), true);
+    }
+}
\ No newline at end of file
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_sha256.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_sha256.test.cpp
index 0370398d81d..4f641447c71 100644
--- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_sha256.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_sha256.test.cpp
@@ -14,12 +14,24 @@
 
 using namespace bb;
 using namespace bb::stdlib;
+using namespace cdg;
 
 using Builder = UltraCircuitBuilder;
+using byte_array_pt = byte_array<Builder>;
+using packed_byte_array_pt = packed_byte_array<Builder>;
+using field_pt = field_t<Builder>;
+
+void fix_vector(std::vector<field_pt>& vector) {
+    for (auto& elem: vector) {
+        elem.fix_witness();
+    }
+}
+
+void fix_byte_array(packed_byte_array_pt& input) {
+    std::vector<field_pt> limbs = input.get_limbs();
+    fix_vector(limbs);
+}
 
-using byte_array_ct = byte_array<Builder>;
-using packed_byte_array_ct = packed_byte_array<Builder>;
-using field_ct = field_t<Builder>;
 
 /**
  all these tests check graph description for sha256 circuits. All circuits have to consist from 1 connected component
@@ -30,23 +42,29 @@ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_55_bytes)
     // 55 bytes is the largest number of bytes that can be hashed in a single block,
     // accounting for the single padding bit, and the 64 size bits required by the SHA-256 standard.
     auto builder = Builder();
-    packed_byte_array_ct input(&builder, "An 8 character password? Snow White and the 7 Dwarves..");
+    packed_byte_array_pt input(&builder, "An 8 character password? Snow White and the 7 Dwarves..");
+    fix_byte_array(input);
 
-    packed_byte_array_ct output_bits = stdlib::sha256(input);
+    packed_byte_array_pt output_bits = stdlib::sha256(input);
 
-    std::vector<field_ct> output = output_bits.to_unverified_byte_slices(4);
+    std::vector<field_pt> output = output_bits.to_unverified_byte_slices(4);
+    fix_vector(output);
 
     Graph graph = Graph(builder);
     auto connected_components = graph.find_connected_components();
     EXPECT_EQ(connected_components.size(), 1);
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+    if (variables_in_one_gate.size() > 0) {
+        for (const auto& elem: variables_in_one_gate) {
+            info("elem == ", elem);
+        }
+    }
 }
 
 HEAVY_TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_five)
 {
-    typedef stdlib::field_t<UltraCircuitBuilder> field_pt;
-    typedef stdlib::packed_byte_array<UltraCircuitBuilder> packed_byte_array_pt;
-
-    auto builder = UltraCircuitBuilder();
+    auto builder = Builder();
 
     packed_byte_array_pt input(
         &builder,
@@ -61,11 +79,77 @@ HEAVY_TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_five)
         "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
         "AAAAAAAAAA");
 
+    fix_byte_array(input);
     packed_byte_array_pt output_bits = stdlib::sha256<bb::UltraCircuitBuilder>(input);
-
+    
     std::vector<field_pt> output = output_bits.to_unverified_byte_slices(4);
+    fix_vector(output);
+
+    info("start creating the Graph");
+    Graph graph = Graph(builder);
+    info("graph creating is ended");
+    auto connected_components = graph.find_connected_components();
+    auto variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+    EXPECT_EQ(connected_components.size(), 1);
+}
+
+TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_one)
+{
+    auto builder = Builder();
+    packed_byte_array_pt input(&builder, "abc");
+    fix_byte_array(input);
+    packed_byte_array_pt output_bits = stdlib::sha256(input);
+    fix_byte_array(output_bits);
+    Graph graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    std::unordered_set<uint32_t> variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_two)
+{
+    auto builder = Builder();
+    packed_byte_array_pt input(&builder, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
+    fix_byte_array(input);
+    packed_byte_array_pt output_bits = stdlib::sha256(input);
+    fix_byte_array(output_bits);
+    Graph graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    std::unordered_set<uint32_t> variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_three)
+{
+    auto builder = Builder();
+
+    // one byte, 0xbd
+    packed_byte_array_pt input(&builder, std::vector<uint8_t>{ 0xbd });
+    fix_byte_array(input);
+    packed_byte_array_pt output_bits = stdlib::sha256(input);
+    fix_byte_array(output_bits);
+    Graph graph = Graph(builder);
+    auto connected_components = graph.find_connected_components();
+    EXPECT_EQ(connected_components.size(), 1);
+    std::unordered_set<uint32_t> variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
+}
+
+TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_four)
+{
+    auto builder = Builder();
 
+    // 4 bytes, 0xc98c8e55
+    packed_byte_array_pt input(&builder, std::vector<uint8_t>{ 0xc9, 0x8c, 0x8e, 0x55 });
+    fix_byte_array(input);
+    packed_byte_array_pt output_bits = stdlib::sha256<Builder>(input);
+    fix_byte_array(output_bits);
     Graph graph = Graph(builder);
     auto connected_components = graph.find_connected_components();
     EXPECT_EQ(connected_components.size(), 1);
+    std::unordered_set<uint32_t> variables_in_one_gate = graph.show_variables_in_one_gate(builder);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
 }
\ No newline at end of file
diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variable_gates_count.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variable_gates_count.test.cpp
index d07ebeeac4f..df54296651a 100644
--- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variable_gates_count.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variable_gates_count.test.cpp
@@ -10,8 +10,9 @@
 #include <gtest/gtest.h>
 
 using namespace bb;
+using namespace cdg;
 
-TEST(boomerang_ultra_circuit_constructor, test_variable_gates_count_for_decompose)
+TEST(ultra_circuit_constructor, test_variable_gates_count_for_decompose)
 {
     UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder();
     auto c = fr::random_element();
@@ -24,10 +25,10 @@ TEST(boomerang_ultra_circuit_constructor, test_variable_gates_count_for_decompos
 
     Graph graph = Graph(circuit_constructor);
     std::unordered_set<uint32_t> variables_in_on_gate = graph.show_variables_in_one_gate(circuit_constructor);
-    EXPECT_EQ(variables_in_on_gate.size(), 1);
+    EXPECT_EQ(variables_in_on_gate.size(), 0);
 }
 
-TEST(boomerang_ultra_circuit_constructor, test_variable_gates_count_for_decompose2)
+TEST(ultra_circuit_constructor, test_variable_gates_count_for_decompose2)
 {
     UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder();
     auto c = fr::random_element();
@@ -40,10 +41,10 @@ TEST(boomerang_ultra_circuit_constructor, test_variable_gates_count_for_decompos
 
     Graph graph = Graph(circuit_constructor);
     auto variables_in_on_gate = graph.show_variables_in_one_gate(circuit_constructor);
-    EXPECT_EQ(variables_in_on_gate.size(), 1);
+    EXPECT_EQ(variables_in_on_gate.size(), 0);
 }
 
-TEST(boomerang_utils, test_selectors_for_decompose)
+TEST(utils, test_selectors_for_decompose)
 {
     auto is_power_two = [&](const uint256_t& number) { return number > 0 && ((number & (number - 1)) == 0); };
     const uint64_t target_range_bitnum = 14;
@@ -65,7 +66,7 @@ TEST(boomerang_utils, test_selectors_for_decompose)
     EXPECT_EQ(q_3_is_power_two, true);
 }
 
-TEST(boomerang_ultra_circuit_constructor, test_variable_gates_count_for_two_decomposes)
+TEST(ultra_circuit_constructor, test_variable_gates_count_for_two_decomposes)
 {
     UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder();
     auto c1 = fr::random_element();
@@ -85,10 +86,10 @@ TEST(boomerang_ultra_circuit_constructor, test_variable_gates_count_for_two_deco
 
     Graph graph = Graph(circuit_constructor);
     std::unordered_set<uint32_t> variables_in_one_gate = graph.show_variables_in_one_gate(circuit_constructor);
-    EXPECT_EQ(variables_in_one_gate.size(), 2);
+    EXPECT_EQ(variables_in_one_gate.size(), 0);
 }
 
-TEST(boomerang_ultra_circuit_constructor, test_decompose_with_boolean_gates)
+TEST(ultra_circuit_constructor, test_decompose_with_boolean_gates)
 {
     UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder();
     auto c1 = fr::random_element();
@@ -126,5 +127,5 @@ TEST(boomerang_ultra_circuit_constructor, test_decompose_for_6_bit_number)
 
     Graph graph = Graph(circuit_constructor);
     std::unordered_set<uint32_t> variables_in_on_gate = graph.show_variables_in_one_gate(circuit_constructor);
-    EXPECT_EQ(variables_in_on_gate.size(), 1);
+    EXPECT_EQ(variables_in_on_gate.size(), 0);
 }
diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_builder.test.cpp
index 65d96e1c998..56f12a17348 100644
--- a/barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_builder.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_builder.test.cpp
@@ -465,4 +465,4 @@ TEST(standard_circuit_constructor, test_check_circuit_broken)
 
     bool result = CircuitChecker::check(circuit_constructor);
     EXPECT_EQ(result, false);
-}
+}
\ No newline at end of file
diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.cpp
index c64afbeb10d..7282f603d8c 100644
--- a/barretenberg/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.cpp
+++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.cpp
@@ -321,7 +321,6 @@ std::array<field_t<Builder>, 8> sha256_block(const std::array<field_t<Builder>,
     output[5] = add_normalize(f.normal, h_init[5]);
     output[6] = add_normalize(g.normal, h_init[6]);
     output[7] = add_normalize(h.normal, h_init[7]);
-
     /**
      * At this point, a malicilous prover could tweak the add_normalise function and the result could be 'overflowed'.
      * Thus, we need 32-bit range checks on the outputs. Note that we won't need range checks while applying the SHA-256
diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/standard_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/standard_circuit_builder.cpp
index 03effb88841..b7600b7fd6f 100644
--- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/standard_circuit_builder.cpp
+++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/standard_circuit_builder.cpp
@@ -1,11 +1,11 @@
 #include "standard_circuit_builder.hpp"
 #include "barretenberg/ecc/curves/bn254/bn254.hpp"
 #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp"
-#include <unordered_map>
-#include <unordered_set>
-
 #include "barretenberg/serialize/cbind.hpp"
 #include "barretenberg/serialize/msgpack.hpp"
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
 
 namespace bb {