From 802fa795839f2b3004ac5fe27c33871a1d706631 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Tue, 3 Dec 2024 12:12:43 +0000 Subject: [PATCH 01/27] graph description for stdlib/poseidon2 hash function + tests --- .../boomerang_value_detection/CMakeLists.txt | 2 +- .../boomerang_value_detection/graph.cpp | 46 +++++++ .../boomerang_value_detection/graph.hpp | 5 + ...escription_poseidon2s_permutation.test.cpp | 113 ++++++++++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_poseidon2s_permutation.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/CMakeLists.txt index dae39eee2de..b2c9590bf03 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) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 03c31e53137..11240b1a961 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -197,6 +197,30 @@ inline std::vector Graph_::get_plookup_gate_connected_component( return gate_variables; } +template +inline std::vector Graph_::get_poseido2s_gate_connected_component( + bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, bool is_internal_block) +{ + std::vector gate_variables; + auto& block = ultra_circuit_builder.blocks.poseidon2_internal; + auto& selector = block.q_poseidon2_internal()[index]; + if (!is_internal_block) { + block = ultra_circuit_builder.blocks.poseidon2_external; + selector = block.q_poseidon2_external()[index]; + } + if (selector == 1) { + 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); + return gate_variables; +} + /** * @brief Construct a new Graph from Ultra Circuit Builder * @tparam FF @@ -262,6 +286,28 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit this->connect_all_variables_in_vector(ultra_circuit_constructor, variable_indices, false); } } + + const auto& poseidon2_internal_block = ultra_circuit_constructor.blocks.poseidon2_internal; + auto internal_gates = poseidon2_internal_block; + if (internal_gates.size() > 0) { + for (size_t i = 0; i < internal_gates.size(); i++) { + std::vector variabled_indices = + this->get_poseido2s_gate_connected_component(ultra_circuit_constructor, i); + this->connect_all_variables_in_vector( + ultra_circuit_constructor, variabled_indices, /*is_sorted_variables=*/false); + } + } + + const auto& poseidon2_external_block = ultra_circuit_constructor.blocks.poseidon2_external; + auto external_gates = poseidon2_external_block; + if (external_gates.size() > 0) { + for (size_t i = 0; i < external_gates.size(); i++) { + std::vector variable_indices = + this->get_poseido2s_gate_connected_component(ultra_circuit_constructor, i, /*is_internal_block=*/false); + this->connect_all_variables_in_vector( + ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false); + } + } } /** diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp index c4c88e1e159..5e3331a0a05 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp @@ -43,6 +43,11 @@ template class Graph_ { size_t index); std::vector get_sort_constraint_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index); + std::vector get_poseido2s_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, + size_t index, + bool is_internal_block = true); + std::vector get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, + size_t index); void add_new_edge(const uint32_t& first_variable_index, const uint32_t& second_variable_index); std::vector get_variable_adjacency_list(const uint32_t& variable_index) 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..9337c926443 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_poseidon2s_permutation.test.cpp @@ -0,0 +1,113 @@ +#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; + +namespace { +auto& engine = numeric::get_debug_randomness(); +} + +using Params = crypto::Poseidon2Bn254ScalarFieldParams; +using Builder = UltraCircuitBuilder; +using Permutation = stdlib::Poseidon2Permutation; +using field_t = stdlib::field_t; +using witness_t = stdlib::witness_t; + +bool check_in_input_vector(const std::vector& 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; +} + +void test_poseidon2s_circuit(size_t num_inputs = 5) +{ + auto builder = Builder(); + std::vector inputs; + + for (size_t i = 0; i < num_inputs; ++i) { + const auto element = fr::random_element(&engine); + inputs.emplace_back(field_t(witness_t(&builder, element))); + } + + auto result = stdlib::poseidon2::hash(builder, inputs); + auto res_index = result.witness_index; + 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) { + if (!check_in_input_vector(inputs, elem) && elem != res_index) { + bool check = (elem - res_index == 1) || (elem - res_index == 2) || (elem - res_index == 3); + EXPECT_EQ(check, true); + } + } +} + +TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_one_permutation) +{ + std::array 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); + //(void)new_state; + + auto graph = Graph(builder); + auto connected_components = graph.find_connected_components(); + EXPECT_EQ(connected_components.size(), 1); + graph.print_connected_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 input1; + std::array 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(); + poseidon2permutation.permutation(&builder, input1); + poseidon2permutation.permutation(&builder, input2); + auto graph = Graph(builder); + auto connected_components = graph.find_connected_components(); + EXPECT_EQ(connected_components.size(), 2); +} + +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(5); +} From 3347d0cee7f6f21667dffbf81c1087141c429678 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 4 Dec 2024 19:57:20 +0000 Subject: [PATCH 02/27] first steps for auxiliary gates --- .../boomerang_value_detection/graph.cpp | 89 +++++++++++++++++++ ...escription_poseidon2s_permutation.test.cpp | 2 + 2 files changed, 91 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 11240b1a961..05aa286002a 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -221,6 +221,95 @@ inline std::vector Graph_::get_poseido2s_gate_connected_component( return gate_variables; } +template +inline std::vector Graph_::get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_builder, + size_t index) +{ + std::vector gate_variables; + auto& block = ultra_builder.blocks.aux; + if (block.q_aux()[index] == 1) { + 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_c()[index]; + + if (q_3 == 1 && q_4 == 1) { + // bigfield limb accumulation 1 + if (index < block.size() - 1) { + gate_variables.insert(gate_variables.end(), + { block.w_l()[index], + block.w_r()[index], + block.w_o()[index], + block.w_4()[index], + block.w_l()[index], + block.w_l()[index + 1], + block.w_r()[index + 1] }); + } + } + if (q_3 == 1 && q_m == 1) { + // bigfield limb accumulation 2 + 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] }); + } + } + if (q_2 == 1 && q_3 == 1) { + // bigfield product 1 + } + if (q_2 == 1 && q_4 == 1) { + // bigfield product 2 + } + if (q_2 == 1 && q_m == 1) { + // bigfield product 3 + } + if (q_1 == 1 && q_m == 1) { + // ram/rom access gate + gate_variables.insert(gate_variables.end(), + { block.w_l()[index], block.w_r()[index], block.w_o()[index], block.w_4()[index] }); + } + if (q_1 == 1 && q_4 == 1) { + // 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_1 == 1 && q_2 == 1) { + // 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] }); + } + } + if (q_arith == 1) { + // ram constitency check + 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_builder, gate_variables); + return gate_variables; +} + /** * @brief Construct a new Graph from Ultra Circuit Builder * @tparam FF 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 index 9337c926443..15ebddb4868 100644 --- 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 @@ -51,6 +51,7 @@ void test_poseidon2s_circuit(size_t num_inputs = 5) 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) { + info("elem = ", elem); if (!check_in_input_vector(inputs, elem) && elem != res_index) { bool check = (elem - res_index == 1) || (elem - res_index == 2) || (elem - res_index == 3); EXPECT_EQ(check, true); @@ -98,6 +99,7 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_two_permutations) auto graph = Graph(builder); auto connected_components = graph.find_connected_components(); EXPECT_EQ(connected_components.size(), 2); + graph.print_connected_components(); } TEST(boomerang_poseidon2s, test_graph_for_poseidon2s) From ee7b268a96bff585403774dca6cdc21531ff9368 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 9 Dec 2024 13:51:40 +0000 Subject: [PATCH 03/27] add graph description for bigfield product cases --- .../boomerang_value_detection/graph.cpp | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 05aa286002a..b36ab6bd03c 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -260,14 +260,39 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( block.w_4()[index + 1] }); } } - if (q_2 == 1 && q_3 == 1) { - // bigfield product 1 - } - if (q_2 == 1 && q_4 == 1) { - // bigfield product 2 - } - if (q_2 == 1 && q_m == 1) { - // bigfield product 3 + if (q_2 == 1 && (q_3 == 1 || q_4 == 1 || q_m == 1)) { + // bigfield product cases + if (index < block.size() - 1) { + std::vector limb_subproduct_vars = { + block.w_l()[index], block.w_r()[index], block.w_l()[index + 1], block.w_r()[index + 1] + }; + if (q_3 == 1) { + // bigfield product 1 + gate_variables.insert( + gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end()); + gate_variables.insert(gate_variables.end(), { block.w_o()[index], block.w_4()[index] }); + } + if (q_4 == 1) { + // bigfield product 2 + std::vector non_native_field_gate_2 = { block.w_l()[index], + block.w_4()[index], + block.w_r()[index], + block.w_o()[index], + 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 + gate_variables.insert( + gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end()); + gate_variables.insert(gate_variables.end(), + { block.w_4()[index], block.w_o()[index + 1], block.w_4()[index + 1] }); + } + } } if (q_1 == 1 && q_m == 1) { // ram/rom access gate From 84fdfd594fc566b708477caa45ba82f623b2fd5c Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 11 Dec 2024 20:05:21 +0000 Subject: [PATCH 04/27] add auxiliary block graph creation + resize method test for dynamic array --- .../boomerang_value_detection/CMakeLists.txt | 2 +- .../boomerang_value_detection/graph.cpp | 16 ++++++- .../graph_description_dynamic_array.test.cpp | 46 +++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_dynamic_array.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/CMakeLists.txt index b2c9590bf03..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 stdlib_poseidon2) \ 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 b36ab6bd03c..8c970a42cb7 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -268,12 +268,14 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( }; if (q_3 == 1) { // bigfield product 1 + assert(q_4 == 0 && q_m == 0); gate_variables.insert( gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end()); gate_variables.insert(gate_variables.end(), { block.w_o()[index], block.w_4()[index] }); } if (q_4 == 1) { // bigfield product 2 + assert(q_3 == 0 && q_m == 0); std::vector non_native_field_gate_2 = { block.w_l()[index], block.w_4()[index], block.w_r()[index], @@ -287,6 +289,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } if (q_m == 1) { // bigfield product 3 + assert(q_4 == 0 && q_3 == 0); gate_variables.insert( gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end()); gate_variables.insert(gate_variables.end(), @@ -405,10 +408,10 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit auto internal_gates = poseidon2_internal_block; if (internal_gates.size() > 0) { for (size_t i = 0; i < internal_gates.size(); i++) { - std::vector variabled_indices = + std::vector variable_indices = this->get_poseido2s_gate_connected_component(ultra_circuit_constructor, i); this->connect_all_variables_in_vector( - ultra_circuit_constructor, variabled_indices, /*is_sorted_variables=*/false); + ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false); } } @@ -422,6 +425,15 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false); } } + const auto& aux_block = ultra_circuit_constructor.blocks.aux; + if (aux_block.size() > 0) { + for (size_t i = 0; i < aux_block.size(); i++) { + std::vector variable_indices = + this->get_auxiliary_gate_connected_component(ultra_circuit_constructor, i); + this->connect_all_variables_in_vector( + ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false); + } + } } /** 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..d48269d72cf --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_dynamic_array.test.cpp @@ -0,0 +1,46 @@ +#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; +namespace { +auto& engine = bb::numeric::get_debug_randomness(); +} + +// Defining ultra-specific types for local testing. +using Builder = UltraCircuitBuilder; +using bool_ct = stdlib::bool_t; +using field_ct = stdlib::field_t; +using witness_ct = stdlib::witness_t; +using DynamicArray_ct = stdlib::DynamicArray; + +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); + if (variables_in_one_gate.size() > 0) { + for (const auto& elem : variables_in_one_gate) { + info("elem = ", elem); + } + } else { + info("variables_in_one_gate is empty"); + } + EXPECT_EQ(connected_components.size(), 1); + // EXPECT_EQ(variables_in_one_gate.size(), max_size * 2); +} \ No newline at end of file From e3df3b102a52e5fcb1de477870612132c051d5c4 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 18 Dec 2024 15:05:28 +0000 Subject: [PATCH 05/27] rarewrite graph description fro or ram and rom tables + tests --- .../boomerang_value_detection/graph.cpp | 127 ++++++++++++++++-- .../boomerang_value_detection/graph.hpp | 7 + .../graph_description_ram_rom.test.cpp | 113 ++++++++++++++++ 3 files changed, 236 insertions(+), 11 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_ram_rom.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 8c970a42cb7..2904229c92c 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -1,4 +1,5 @@ -#include "graph.hpp" +#include "./graph.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" #include #include @@ -233,10 +234,12 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( 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_c()[index]; + auto q_arith = block.q_arith()[index]; + auto q_c = block.q_c()[index]; if (q_3 == 1 && q_4 == 1) { // bigfield limb accumulation 1 + ASSERT(q_arith == 0); if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), { block.w_l()[index], @@ -249,6 +252,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } } if (q_3 == 1 && q_m == 1) { + ASSERT(q_arith == 0); // bigfield limb accumulation 2 if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), @@ -261,6 +265,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } } if (q_2 == 1 && (q_3 == 1 || q_4 == 1 || q_m == 1)) { + ASSERT(q_arith == 0); // bigfield product cases if (index < block.size() - 1) { std::vector limb_subproduct_vars = { @@ -268,14 +273,14 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( }; if (q_3 == 1) { // bigfield product 1 - assert(q_4 == 0 && q_m == 0); + ASSERT(q_4 == 0 && q_m == 0); gate_variables.insert( gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end()); gate_variables.insert(gate_variables.end(), { block.w_o()[index], block.w_4()[index] }); } if (q_4 == 1) { // bigfield product 2 - assert(q_3 == 0 && q_m == 0); + ASSERT(q_3 == 0 && q_m == 0 && q_arith == 0); std::vector non_native_field_gate_2 = { block.w_l()[index], block.w_4()[index], block.w_r()[index], @@ -289,7 +294,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } if (q_m == 1) { // bigfield product 3 - assert(q_4 == 0 && q_3 == 0); + ASSERT(q_4 == 0 && q_3 == 0); gate_variables.insert( gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end()); gate_variables.insert(gate_variables.end(), @@ -298,11 +303,18 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } } if (q_1 == 1 && q_m == 1) { + ASSERT(q_arith == 0); // ram/rom access gate - gate_variables.insert(gate_variables.end(), - { block.w_l()[index], block.w_r()[index], block.w_o()[index], block.w_4()[index] }); + // no we use special function for processing rom tables + // may be I will remove this case in the future btw + if (q_c != 0) { + gate_variables.insert( + gate_variables.end(), + { block.w_l()[index], block.w_r()[index], block.w_o()[index], block.w_4()[index] }); + } } if (q_1 == 1 && q_4 == 1) { + ASSERT(q_arith == 0); // ram timestamp check if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), @@ -314,6 +326,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } } if (q_1 == 1 && q_2 == 1) { + ASSERT(q_arith == 0); // rom constitency check if (index < block.size() - 1) { gate_variables.insert( @@ -338,6 +351,66 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( return gate_variables; } +template +inline std::vector Graph_::get_rom_table_connected_component( + bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RomTranscript& rom_array) +{ + std::vector gate_variables; + for (const auto& elem : rom_array.state) { + gate_variables.emplace_back(elem[0]); + if (elem[1] != ultra_builder.zero_idx) { + gate_variables.emplace_back(elem[1]); + } + } + for (const auto& record : rom_array.records) { + gate_variables.insert(gate_variables.end(), + { record.index_witness, + record.value_column1_witness, + record.value_column2_witness, + record.record_witness }); + size_t gate_index = record.gate_index; + variables_gates[ultra_builder.real_variable_index[record.index_witness]].emplace_back(gate_index); + variables_gates[ultra_builder.real_variable_index[record.value_column1_witness]].emplace_back(gate_index); + variables_gates[ultra_builder.real_variable_index[record.value_column2_witness]].emplace_back(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]; + ASSERT(q_1 == 1 && q_m == 1 && q_2 == 0 && q_3 == 0 && q_4 == 0 && q_c == 0 && q_arith == 0); + } + this->process_gate_variables(ultra_builder, gate_variables); + return gate_variables; +} + +template +inline std::vector Graph_::get_ram_table_connected_component( + bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RamTranscript& ram_array) +{ + std::vector gate_variables; + for (const auto& record : ram_array.records) { + gate_variables.insert( + gate_variables.end(), + { record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness }); + size_t gate_index = record.gate_index; + variables_gates[ultra_builder.real_variable_index[record.index_witness]].emplace_back(gate_index); + variables_gates[ultra_builder.real_variable_index[record.timestamp_witness]].emplace_back(gate_index); + variables_gates[ultra_builder.real_variable_index[record.value_witness]].emplace_back(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]; + ASSERT(q_1 == 1 && q_m == 1 && q_2 == 0 && q_3 == 0 && q_4 == 0 && q_arith == 0 && (q_c == 0 || q_c == 1)); + } + this->process_gate_variables(ultra_builder, gate_variables); + return gate_variables; +} + /** * @brief Construct a new Graph from Ultra Circuit Builder * @tparam FF @@ -348,6 +421,8 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit { this->variables_gate_counts = std::unordered_map(ultra_circuit_constructor.real_variable_index.size()); + this->variables_gates = + std::unordered_map>(ultra_circuit_constructor.real_variable_index.size()); this->variable_adjacency_lists = std::unordered_map>(ultra_circuit_constructor.real_variable_index.size()); this->variables_degree = std::unordered_map(ultra_circuit_constructor.real_variable_index.size()); @@ -434,6 +509,24 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false); } } + 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 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 variable_indices = + 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); + } + } } /** @@ -881,11 +974,10 @@ inline void Graph_::remove_unnecessary_plookup_variables(bb::UltraCircuitBui template std::unordered_set Graph_::show_variables_in_one_gate(bb::UltraCircuitBuilder& ultra_circuit_builder) { - std::unordered_set 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; @@ -899,8 +991,9 @@ std::unordered_set Graph_::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); return variables_in_one_gate; } @@ -993,4 +1086,16 @@ template void Graph_::print_variables_edge_counts() } } +template void Graph_::print_variables_in_one_gate() +{ + for (const auto& elem : variables_in_one_gate) { + ASSERT(variables_gates[elem].size() <= 1); + if (variables_gates[elem].size() == 1) { + info("for variable with index ", elem, " gate index == ", variables_gates[elem][0]); + } else { + info("variable's gate with index ", elem, " hasn't processed yet"); + } + } +} + template class Graph_; diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp index 5e3331a0a05..ef6f1be43fa 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp @@ -48,6 +48,10 @@ template class Graph_ { bool is_internal_block = true); std::vector get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index); + std::vector get_rom_table_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, + const bb::UltraCircuitBuilder::RomTranscript& rom_array); + std::vector 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 get_variable_adjacency_list(const uint32_t& variable_index) @@ -109,6 +113,7 @@ template class Graph_ { void print_connected_components(); void print_variables_gate_counts(); void print_variables_edge_counts(); + void print_variables_in_one_gate(); ~Graph_() = default; private: @@ -119,6 +124,8 @@ template class Graph_ { variables_gate_counts; // we use this data structure to count, how many gates use every variable std::unordered_map variables_degree; // we use this data structure to count, how many every variable have edges + std::unordered_map> variables_gates; + std::unordered_set variables_in_one_gate; }; using Graph = Graph_; \ 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..fde8aaf33f6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_ram_rom.test.cpp @@ -0,0 +1,113 @@ +#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; +namespace { +auto& engine = numeric::get_debug_randomness(); +} + +using Builder = UltraCircuitBuilder; +using field_ct = stdlib::field_t; +using witness_ct = stdlib::witness_t; +using rom_table_ct = stdlib::rom_table; +using ram_table_ct = stdlib::ram_table; + +TEST(boomerang_rom_table, graph_description_rom_table) +{ + Builder builder; + + std::vector 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())); + } + + rom_table_ct table(table_values); + + field_ct result = field_ct(witness_ct(&builder, (uint64_t)0)); + info("result witness index == ", result.witness_index); + + for (size_t i = 0; i < 10; ++i) { + field_ct index(witness_ct(&builder, (uint64_t)i)); + result += table[index]; + } + + 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); + graph.print_variables_in_one_gate(); +} + +TEST(boomerang_ram_table, graph_description_ram_table_read) +{ + Builder builder; + + std::vector 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())); + } + + ram_table_ct table(table_values); + field_ct result = field_ct(witness_ct(&builder, (uint64_t)0)); + + for (size_t i = 0; i < 10; ++i) { + field_ct index(witness_ct(&builder, (uint64_t)i)); + result += table.read(index); + } + 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); + graph.print_variables_in_one_gate(); +} + +TEST(boomerang_ram_table, graph_description_ram_table_write) +{ + Builder builder; + const size_t table_size = 10; + + std::vector table_values(table_size); + + ram_table_ct table(&builder, table_size); + + for (size_t i = 0; i < table_size; ++i) { + table.write(i, 0); + } + field_ct result(0); + + 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 + table.write(2 * i, witness_ct(&builder, table_values[2 * i])); + table.write(2 * i + 1, witness_ct(&builder, table_values[2 * i + 1])); + } + }; + + 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 + result += table.read(witness_ct(&builder, index)); + result += table.read(index + 1); + } + }; + + update(); + read(); + // update(); + // read(); + // update(); + + 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); + graph.print_variables_in_one_gate(); +} \ No newline at end of file From 8fca4ae1670886958e9b9ddc8dd7e306ec960781 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 23 Dec 2024 16:33:54 +0000 Subject: [PATCH 06/27] tests for dynamic array + ram_rom --- .../boomerang_value_detection/graph.cpp | 5 ++-- .../graph_description_dynamic_array.test.cpp | 29 ++++++++++++++++++- .../graph_description_ram_rom.test.cpp | 12 ++++---- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 2904229c92c..0093a50939e 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -1092,9 +1092,10 @@ template void Graph_::print_variables_in_one_gate() ASSERT(variables_gates[elem].size() <= 1); if (variables_gates[elem].size() == 1) { info("for variable with index ", elem, " gate index == ", variables_gates[elem][0]); - } else { - info("variable's gate with index ", elem, " hasn't processed yet"); } + else { + info("variable with index ", elem, " may be false case"); + } } } 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 index d48269d72cf..2c180213b51 100644 --- 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 @@ -42,5 +42,32 @@ TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_method_resi info("variables_in_one_gate is empty"); } EXPECT_EQ(connected_components.size(), 1); - // EXPECT_EQ(variables_in_one_gate.size(), max_size * 2); +} + +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); + graph.print_variables_in_one_gate(); } \ 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 index fde8aaf33f6..58dbe15320e 100644 --- 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 @@ -15,7 +15,7 @@ using witness_ct = stdlib::witness_t; using rom_table_ct = stdlib::rom_table; using ram_table_ct = stdlib::ram_table; -TEST(boomerang_rom_table, graph_description_rom_table) +TEST(boomerang_rom_ram_table, graph_description_rom_table) { Builder builder; @@ -42,7 +42,7 @@ TEST(boomerang_rom_table, graph_description_rom_table) graph.print_variables_in_one_gate(); } -TEST(boomerang_ram_table, graph_description_ram_table_read) +TEST(boomerang_rom_ram_table, graph_description_ram_table_read) { Builder builder; @@ -66,7 +66,7 @@ TEST(boomerang_ram_table, graph_description_ram_table_read) graph.print_variables_in_one_gate(); } -TEST(boomerang_ram_table, graph_description_ram_table_write) +TEST(boomerang_rom_ram_table, graph_description_ram_table_write) { Builder builder; const size_t table_size = 10; @@ -101,9 +101,9 @@ TEST(boomerang_ram_table, graph_description_ram_table_write) update(); read(); - // update(); - // read(); - // update(); + update(); + read(); + update(); Graph graph = Graph(builder); auto connected_components = graph.find_connected_components(); From b4fbfa8c411acccadc7b7d7c6a0ae66263535fad Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 3 Feb 2025 14:25:38 +0000 Subject: [PATCH 07/27] fix error of graph creation for q_arith == 3 --- .../boomerang_value_detection/graph.cpp | 81 +++++++++++++------ .../boomerang_value_detection/graph.hpp | 4 +- 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 0093a50939e..630efc1bd7c 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -38,7 +38,7 @@ inline void Graph_::process_gate_variables(UltraCircuitBuilder& ultra_circui */ template -inline std::vector Graph_::get_arithmetic_gate_connected_component( +inline std::vector> Graph_::get_arithmetic_gate_connected_component( bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index) { auto& arithmetic_block = ultra_circuit_builder.blocks.arithmetic; @@ -51,10 +51,16 @@ inline std::vector Graph_::get_arithmetic_gate_connected_component 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 gate_variables = {}; + auto q_arith = arithmetic_block.q_arith()[index]; + std::vector gate_variables; + std::vector minigate_variables; + 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)); + } 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) { + if (q_arith > 0) { if (q_m != 0) { gate_variables.emplace_back(left_idx); gate_variables.emplace_back(right_idx); @@ -71,23 +77,34 @@ inline std::vector Graph_::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); + gate_variables.emplace_back(arithmetic_block.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 != arithmetic_block.size() - 1) { + gate_variables.emplace_back(arithmetic_block.w_4()[index + 1]); + minigate_variables.emplace_back(arithmetic_block.w_l()[index + 1]); + } } } } + std::vector> all_gates_variables; this->process_gate_variables(ultra_circuit_builder, gate_variables); - return gate_variables; + this->process_gate_variables(ultra_circuit_builder, minigate_variables); + all_gates_variables.emplace_back(gate_variables); + if (!minigate_variables.empty()) { + all_gates_variables.emplace_back(minigate_variables); + } + return all_gates_variables; } /** @@ -235,7 +252,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( auto q_4 = block.q_4()[index]; auto q_m = block.q_m()[index]; auto q_arith = block.q_arith()[index]; - auto q_c = block.q_c()[index]; + [[maybe_unused]]auto q_c = block.q_c()[index]; if (q_3 == 1 && q_4 == 1) { // bigfield limb accumulation 1 @@ -302,17 +319,6 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } } } - if (q_1 == 1 && q_m == 1) { - ASSERT(q_arith == 0); - // ram/rom access gate - // no we use special function for processing rom tables - // may be I will remove this case in the future btw - if (q_c != 0) { - gate_variables.insert( - gate_variables.end(), - { block.w_l()[index], block.w_r()[index], block.w_o()[index], block.w_4()[index] }); - } - } if (q_1 == 1 && q_4 == 1) { ASSERT(q_arith == 0); // ram timestamp check @@ -438,8 +444,12 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit 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); + auto all_gates_variables = this->get_arithmetic_gate_connected_component(ultra_circuit_constructor, i); + for (const auto& gate_variables: all_gates_variables) { + if (!gate_variables.empty()) { + this->connect_all_variables_in_vector(ultra_circuit_constructor, gate_variables, false); + } + } } } const auto& elliptic_block = ultra_circuit_constructor.blocks.elliptic; @@ -787,6 +797,22 @@ inline void Graph_::remove_unnecessary_decompose_variables(bb::UltraCircuitB } } } + + +template +void Graph_::remove_unnecessary_range_constrains_variables(bb::UltraCircuitBuilder& ultra_builder) { + std::map range_lists = ultra_builder.range_lists; + for (const auto& pair: range_lists) { + UltraCircuitBuilder::RangeList list = pair.second; + for (const auto& elem: list.variable_indices) { + uint32_t real_variable_index = to_real(ultra_builder, elem); + if (this->variables_in_one_gate.find(real_variable_index) != this->variables_in_one_gate.end()) { + this->variables_in_one_gate.erase(real_variable_index); + } + } + } +} + /** * @brief this method removes false positive cass 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 @@ -964,6 +990,7 @@ inline void Graph_::remove_unnecessary_plookup_variables(bb::UltraCircuitBui } } + /** * @brief this method returns a final set of variables that were in one gate * @tparam FF @@ -994,6 +1021,10 @@ std::unordered_set Graph_::show_variables_in_one_gate(bb::UltraCir 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); + } return variables_in_one_gate; } @@ -1028,7 +1059,7 @@ std::pair, size_t> get_connected_component_with_index( template void Graph_::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 { diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp index ef6f1be43fa..b41d1b99ce8 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp @@ -35,7 +35,7 @@ template class Graph_ { std::unordered_map get_variables_gate_counts() { return this->variables_gate_counts; }; - std::vector get_arithmetic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, + std::vector> get_arithmetic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index); std::vector get_elliptic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index); @@ -98,6 +98,7 @@ template class Graph_ { const std::unordered_set& decompose_variables); void remove_unnecessary_plookup_variables(bb::UltraCircuitBuilder& ultra_circuit_builder, std::unordered_set& variables_in_on_gate); + void remove_unnecessary_range_constrains_variables(bb::UltraCircuitBuilder& ultra_builder); std::unordered_set show_variables_in_one_gate(bb::UltraCircuitBuilder& ultra_circuit_builder); void remove_unnecessary_aes_plookup_variables(std::unordered_set& variables_in_one_gate, @@ -126,6 +127,7 @@ template class Graph_ { variables_degree; // we use this data structure to count, how many every variable have edges std::unordered_map> variables_gates; std::unordered_set variables_in_one_gate; + std::unordered_set fixed_variables; }; using Graph = Graph_; \ No newline at end of file From 8f0d9eef02ad8fabbd7032221a5a751de025e184 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 12 Feb 2025 16:38:16 +0000 Subject: [PATCH 08/27] new graph constructor --- .../boomerang_value_detection/graph.cpp | 199 ++++++++++++------ .../boomerang_value_detection/graph.hpp | 39 +++- 2 files changed, 171 insertions(+), 67 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 630efc1bd7c..2d173b643b4 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -6,6 +6,26 @@ using namespace bb::plookup; using namespace bb; +namespace cdg { + +template +inline bool Graph_::is_equal_blocks(const UltraBlock& blk1, const UltraBlock& blk2) { + return blk1.wires == blk2.wires; +} + +template +inline size_t Graph_::find_block_index(bb::UltraCircuitBuilder& ultra_builder, const UltraBlock& block) { + const auto& gate_blocks = ultra_builder.blocks.get_gate_blocks(); + size_t blk_idx = 0; + for (size_t i = 0; i < gate_blocks.size(); i++) { + if (is_equal_blocks(gate_blocks[i], block)) { + blk_idx = i; + break; + } + } + return blk_idx; +} + /** * @brief this method removes duplicate variables from a gate, * converts variables from a gate to real variables, and then @@ -14,7 +34,9 @@ using namespace bb; template inline void Graph_::process_gate_variables(UltraCircuitBuilder& ultra_circuit_builder, - std::vector& gate_variables) + std::vector& gate_variables, + const UltraBlock& block, + size_t gate_index) { auto unique_variables = std::unique(gate_variables.begin(), gate_variables.end()); gate_variables.erase(unique_variables, gate_variables.end()); @@ -23,6 +45,14 @@ inline void Graph_::process_gate_variables(UltraCircuitBuilder& ultra_circui } for (size_t i = 0; i < gate_variables.size(); i++) { gate_variables[i] = this->to_real(ultra_circuit_builder, gate_variables[i]); + size_t block_index = 0; + if (i == 0) { + block_index = this->find_block_index(ultra_circuit_builder, block); + } + info("block index == ", block_index); + KeyPair key = std::make_pair(gate_variables[i], block_index); + variable_gates[key].emplace_back(gate_index); + } for (const auto& variable_index : gate_variables) { variables_gate_counts[variable_index] += 1; @@ -98,8 +128,8 @@ inline std::vector> Graph_::get_arithmetic_gate_connec } } std::vector> all_gates_variables; - this->process_gate_variables(ultra_circuit_builder, gate_variables); - this->process_gate_variables(ultra_circuit_builder, minigate_variables); + this->process_gate_variables(ultra_circuit_builder, gate_variables, arithmetic_block, index); + this->process_gate_variables(ultra_circuit_builder, minigate_variables, arithmetic_block, index); all_gates_variables.emplace_back(gate_variables); if (!minigate_variables.empty()) { all_gates_variables.emplace_back(minigate_variables); @@ -144,7 +174,7 @@ inline std::vector Graph_::get_elliptic_gate_connected_component( } } } - this->process_gate_variables(ultra_circuit_builder, gate_variables); + this->process_gate_variables(ultra_circuit_builder, gate_variables, elliptic_block, index); return gate_variables; } @@ -170,7 +200,7 @@ inline std::vector Graph_::get_sort_constraint_connected_component auto fourth_idx = delta_range_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, delta_range_block, index); return gate_variables; } @@ -211,7 +241,7 @@ inline std::vector Graph_::get_plookup_gate_connected_component( } } } - this->process_gate_variables(ultra_circuit_builder, gate_variables); + this->process_gate_variables(ultra_circuit_builder, gate_variables, lookup_block, index); return gate_variables; } @@ -235,7 +265,7 @@ inline std::vector Graph_::get_poseido2s_gate_connected_component( { 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_circuit_builder, gate_variables, block, index); return gate_variables; } @@ -254,16 +284,19 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( 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 == 0); if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), - { block.w_l()[index], - block.w_r()[index], - block.w_o()[index], - block.w_4()[index], - block.w_l()[index], + { w_l, + w_r, + w_o, + w_4, block.w_l()[index + 1], block.w_r()[index + 1] }); } @@ -273,8 +306,8 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( // bigfield limb accumulation 2 if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), - { block.w_o()[index], - block.w_4()[index], + { w_o, + w_4, block.w_l()[index + 1], block.w_r()[index + 1], block.w_o()[index + 1], @@ -286,22 +319,22 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( // bigfield product cases if (index < block.size() - 1) { std::vector limb_subproduct_vars = { - block.w_l()[index], block.w_r()[index], block.w_l()[index + 1], block.w_r()[index + 1] + w_l, w_r, block.w_l()[index + 1], block.w_r()[index + 1] }; if (q_3 == 1) { // bigfield product 1 ASSERT(q_4 == 0 && q_m == 0); gate_variables.insert( gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end()); - gate_variables.insert(gate_variables.end(), { block.w_o()[index], block.w_4()[index] }); + gate_variables.insert(gate_variables.end(), { w_o, w_4 }); } if (q_4 == 1) { // bigfield product 2 ASSERT(q_3 == 0 && q_m == 0 && q_arith == 0); - std::vector non_native_field_gate_2 = { block.w_l()[index], - block.w_4()[index], - block.w_r()[index], - block.w_o()[index], + std::vector 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()); @@ -315,7 +348,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( gate_variables.insert( gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end()); gate_variables.insert(gate_variables.end(), - { block.w_4()[index], block.w_o()[index + 1], block.w_4()[index + 1] }); + { w_4, block.w_o()[index + 1], block.w_4()[index + 1] }); } } } @@ -353,31 +386,26 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } } } - this->process_gate_variables(ultra_builder, gate_variables); + this->process_gate_variables(ultra_builder, gate_variables, block, index); return gate_variables; } + + template inline std::vector Graph_::get_rom_table_connected_component( bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RomTranscript& rom_array) { - std::vector gate_variables; - for (const auto& elem : rom_array.state) { - gate_variables.emplace_back(elem[0]); - if (elem[1] != ultra_builder.zero_idx) { - gate_variables.emplace_back(elem[1]); - } - } + // 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 rom_table_variables; + for (const auto& record : rom_array.records) { - gate_variables.insert(gate_variables.end(), - { record.index_witness, - record.value_column1_witness, - record.value_column2_witness, - record.record_witness }); + std::vector gate_variables; size_t gate_index = record.gate_index; - variables_gates[ultra_builder.real_variable_index[record.index_witness]].emplace_back(gate_index); - variables_gates[ultra_builder.real_variable_index[record.value_column1_witness]].emplace_back(gate_index); - variables_gates[ultra_builder.real_variable_index[record.value_column2_witness]].emplace_back(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]; @@ -385,25 +413,43 @@ inline std::vector Graph_::get_rom_table_connected_component( 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]; - ASSERT(q_1 == 1 && q_m == 1 && q_2 == 0 && q_3 == 0 && q_4 == 0 && q_c == 0 && q_arith == 0); - } - this->process_gate_variables(ultra_builder, gate_variables); - return gate_variables; + + 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 RAM/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, ultra_builder.blocks.aux, gate_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; } template inline std::vector Graph_::get_ram_table_connected_component( bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RamTranscript& ram_array) { - std::vector gate_variables; + std::vector ram_table_variables; for (const auto& record : ram_array.records) { - gate_variables.insert( - gate_variables.end(), - { record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness }); + std::vector gate_variables; size_t gate_index = record.gate_index; - variables_gates[ultra_builder.real_variable_index[record.index_witness]].emplace_back(gate_index); - variables_gates[ultra_builder.real_variable_index[record.timestamp_witness]].emplace_back(gate_index); - variables_gates[ultra_builder.real_variable_index[record.value_witness]].emplace_back(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]; @@ -411,10 +457,30 @@ inline std::vector Graph_::get_ram_table_connected_component( 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]; - ASSERT(q_1 == 1 && q_m == 1 && q_2 == 0 && q_3 == 0 && q_4 == 0 && q_arith == 0 && (q_c == 0 || q_c == 1)); + + 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/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 (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, ultra_builder.blocks.aux, gate_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()); } - this->process_gate_variables(ultra_builder, gate_variables); - return gate_variables; + return ram_table_variables; } /** @@ -427,8 +493,6 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit { this->variables_gate_counts = std::unordered_map(ultra_circuit_constructor.real_variable_index.size()); - this->variables_gates = - std::unordered_map>(ultra_circuit_constructor.real_variable_index.size()); this->variable_adjacency_lists = std::unordered_map>(ultra_circuit_constructor.real_variable_index.size()); this->variables_degree = std::unordered_map(ultra_circuit_constructor.real_variable_index.size()); @@ -480,8 +544,7 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit 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) { + if (lookup_gates > 0) { for (size_t i = 0; i < lookup_gates; i++) { std::vector variable_indices = this->get_plookup_gate_connected_component(ultra_circuit_constructor, i); @@ -802,12 +865,23 @@ inline void Graph_::remove_unnecessary_decompose_variables(bb::UltraCircuitB template void Graph_::remove_unnecessary_range_constrains_variables(bb::UltraCircuitBuilder& ultra_builder) { std::map range_lists = ultra_builder.range_lists; + std::unordered_set range_lists_tau_tags; + std::unordered_set range_lists_range_tags; + std::vector real_variable_tags = ultra_builder.real_variable_tags; for (const auto& pair: range_lists) { UltraCircuitBuilder::RangeList list = pair.second; - for (const auto& elem: list.variable_indices) { - uint32_t real_variable_index = to_real(ultra_builder, elem); - if (this->variables_in_one_gate.find(real_variable_index) != this->variables_in_one_gate.end()) { - this->variables_in_one_gate.erase(real_variable_index); + 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); } } } @@ -1117,10 +1191,9 @@ template void Graph_::print_variables_edge_counts() } } -template void Graph_::print_variables_in_one_gate() +/* template void Graph_::print_variables_in_one_gate() { for (const auto& elem : variables_in_one_gate) { - ASSERT(variables_gates[elem].size() <= 1); if (variables_gates[elem].size() == 1) { info("for variable with index ", elem, " gate index == ", variables_gates[elem][0]); } @@ -1128,6 +1201,8 @@ template void Graph_::print_variables_in_one_gate() info("variable with index ", elem, " may be false case"); } } -} +} */ template class Graph_; + +} //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 b41d1b99ce8..1c4d7984fe3 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 #include #include +#include /* * this class describes arithmetic circuit as an undirected graph, where vertices are variables from circuit. @@ -16,6 +17,30 @@ * constrained properly. if number of connected components > 1, it means that there were missed some connections between * variables. */ + +namespace cdg { + +using UltraBlock = bb::UltraCircuitBuilder::Arithmetization::UltraTraceBlock; +using KeyPair = std::pair; + +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()(pair.first)); + combined_hash = hash_combiner(combined_hash, std::hash()(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 class Graph_ { public: Graph_() = default; @@ -25,14 +50,17 @@ template class Graph_ { Graph_&& operator=(Graph_&& other) = delete; Graph_(const bb::StandardCircuitBuilder_& 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]; }; + bool is_equal_blocks(const UltraBlock& blk1, const UltraBlock& blk2); + size_t find_block_index(bb::UltraCircuitBuilder& ultra_builder, const UltraBlock& block); void process_gate_variables(bb::UltraCircuitBuilder& ultra_circuit_constructor, - std::vector& gate_variables); - + std::vector& gate_variables, + const UltraBlock& block, + size_t gate_index); std::unordered_map get_variables_gate_counts() { return this->variables_gate_counts; }; std::vector> get_arithmetic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, @@ -125,9 +153,10 @@ template class Graph_ { variables_gate_counts; // we use this data structure to count, how many gates use every variable std::unordered_map variables_degree; // we use this data structure to count, how many every variable have edges - std::unordered_map> variables_gates; + std::unordered_map, KeyHasher, KeyEquals> variable_gates; //we use this data structure to store a pair of UltraTraceBlock and gate number in this block, where every variable was found in the circuit std::unordered_set variables_in_one_gate; std::unordered_set fixed_variables; }; -using Graph = Graph_; \ No newline at end of file +using Graph = Graph_; +} //namespace cgd \ No newline at end of file From c72eba585d96e8ea5bb2fa63b1c9d87f8ff9a10b Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 12 Feb 2025 16:40:18 +0000 Subject: [PATCH 09/27] tests modification --- .../graph_description.test.cpp | 2 +- .../graph_description_aes128.test.cpp | 49 ++++---- .../graph_description_blake2s.test.cpp | 7 +- .../graph_description_blake3s.test.cpp | 12 +- .../graph_description_dynamic_array.test.cpp | 11 +- ...escription_poseidon2s_permutation.test.cpp | 1 + .../graph_description_ram_rom.test.cpp | 7 +- .../graph_description_sha256.test.cpp | 107 ++++++++++++++++-- .../variable_gates_count.test.cpp | 1 + .../variables_gate_counts.sha256.test.cpp | 1 + 10 files changed, 144 insertions(+), 54 deletions(-) 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..164a34d3093 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 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 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 field_pt; -typedef stdlib::witness_t witness_pt; +using field_pt = stdlib::field_t; +using witness_pt = stdlib::witness_t; -bool check_in_vector(const std::vector& input_vector, const uint32_t& real_var_index) +void fix_vector_witness(std::vector& 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 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_blake2s.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_blake2s.test.cpp index 934e92b568a..c2d41f1d60c 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,7 @@ using namespace bb; using namespace bb::stdlib; +using namespace cdg; using Builder = UltraCircuitBuilder; @@ -21,7 +22,7 @@ using public_witness_t = public_witness_t; /** * @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 +37,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 +57,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..c79604f4fe5 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,7 @@ #include using namespace bb; +using namespace cdg; using byte_array = stdlib::byte_array; using public_witness_t = stdlib::public_witness_t; @@ -26,17 +27,14 @@ TEST(boomerang_stdlib_blake3s, test_single_block_plookup) auto builder = UltraBuilder(); std::string input = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01"; std::vector input_v(input.begin(), input.end()); - byte_array_plookup input_arr(&builder, input_v); byte_array_plookup output = stdlib::blake3s(input_arr); - std::vector 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 +48,9 @@ TEST(boomerang_stdlib_blake3s, test_double_block_plookup) std::vector 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 index 2c180213b51..cdc55880e55 100644 --- 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 @@ -6,6 +6,7 @@ #include "barretenberg/stdlib/primitives/memory/dynamic_array.hpp" using namespace bb; +using namespace cdg; namespace { auto& engine = bb::numeric::get_debug_randomness(); } @@ -34,14 +35,8 @@ TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_method_resi Graph graph = Graph(builder); auto connected_components = graph.find_connected_components(); auto variables_in_one_gate = graph.show_variables_in_one_gate(builder); - if (variables_in_one_gate.size() > 0) { - for (const auto& elem : variables_in_one_gate) { - info("elem = ", elem); - } - } else { - info("variables_in_one_gate is empty"); - } EXPECT_EQ(connected_components.size(), 1); + EXPECT_EQ(variables_in_one_gate.size(), 1); } TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_consistency_methods) @@ -69,5 +64,5 @@ TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_consistency 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); - graph.print_variables_in_one_gate(); + 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_poseidon2s_permutation.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_poseidon2s_permutation.test.cpp index 15ebddb4868..a49ff55a044 100644 --- 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 @@ -13,6 +13,7 @@ #include "barretenberg/common/test.hpp" #include "barretenberg/numeric/random/engine.hpp" using namespace bb; +using namespace cdg; namespace { auto& engine = numeric::get_debug_randomness(); 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 index 58dbe15320e..722a57497b2 100644 --- 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 @@ -5,6 +5,7 @@ #include "barretenberg/stdlib/primitives/memory/rom_table.hpp" using namespace bb; +using namespace cdg; namespace { auto& engine = numeric::get_debug_randomness(); } @@ -39,7 +40,7 @@ TEST(boomerang_rom_ram_table, graph_description_rom_table) 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); - graph.print_variables_in_one_gate(); + EXPECT_EQ(variables_in_one_gate.size(), 0); } TEST(boomerang_rom_ram_table, graph_description_ram_table_read) @@ -63,7 +64,7 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_read) 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); - graph.print_variables_in_one_gate(); + EXPECT_EQ(variables_in_one_gate.size(), 0); } TEST(boomerang_rom_ram_table, graph_description_ram_table_write) @@ -109,5 +110,5 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_write) 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); - graph.print_variables_in_one_gate(); + 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_sha256.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_sha256.test.cpp index 0370398d81d..0f7e39212b4 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; +using packed_byte_array_pt = packed_byte_array; +using field_pt = field_t; + +void fix_vector(std::vector& vector) { + for (auto& elem: vector) { + elem.fix_witness(); + } +} + +void fix_byte_array(packed_byte_array_pt& input) { + std::vector limbs = input.get_limbs(); + fix_vector(limbs); +} -using byte_array_ct = byte_array; -using packed_byte_array_ct = packed_byte_array; -using field_ct = field_t; /** 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 output = output_bits.to_unverified_byte_slices(4); + std::vector 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 field_pt; - typedef stdlib::packed_byte_array packed_byte_array_pt; - - auto builder = UltraCircuitBuilder(); + auto builder = Builder(); packed_byte_array_pt input( &builder, @@ -61,11 +79,78 @@ 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(input); - + std::vector 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); + info("huy"); +} + +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 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 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{ 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 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{ 0xc9, 0x8c, 0x8e, 0x55 }); + 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 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..4239bdf1412 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,6 +10,7 @@ #include using namespace bb; +using namespace cdg; TEST(boomerang_ultra_circuit_constructor, test_variable_gates_count_for_decompose) { diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variables_gate_counts.sha256.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variables_gate_counts.sha256.test.cpp index c85b25a5217..8474a725c70 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variables_gate_counts.sha256.test.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variables_gate_counts.sha256.test.cpp @@ -18,6 +18,7 @@ using namespace bb; using namespace bb::stdlib; +using namespace cdg; using Builder = UltraCircuitBuilder; From 0976c5168e35ad51e502894aeca44a28f2542384 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 17 Feb 2025 11:13:21 +0000 Subject: [PATCH 10/27] redesign of the constructor for graph creation --- .../boomerang_value_detection/graph.cpp | 351 +++++++----------- .../boomerang_value_detection/graph.hpp | 18 +- 2 files changed, 152 insertions(+), 217 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 2d173b643b4..03b3dac38cb 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -8,24 +8,6 @@ using namespace bb; namespace cdg { -template -inline bool Graph_::is_equal_blocks(const UltraBlock& blk1, const UltraBlock& blk2) { - return blk1.wires == blk2.wires; -} - -template -inline size_t Graph_::find_block_index(bb::UltraCircuitBuilder& ultra_builder, const UltraBlock& block) { - const auto& gate_blocks = ultra_builder.blocks.get_gate_blocks(); - size_t blk_idx = 0; - for (size_t i = 0; i < gate_blocks.size(); i++) { - if (is_equal_blocks(gate_blocks[i], block)) { - blk_idx = i; - break; - } - } - return blk_idx; -} - /** * @brief this method removes duplicate variables from a gate, * converts variables from a gate to real variables, and then @@ -35,22 +17,17 @@ inline size_t Graph_::find_block_index(bb::UltraCircuitBuilder& ultra_builde template inline void Graph_::process_gate_variables(UltraCircuitBuilder& ultra_circuit_builder, std::vector& gate_variables, - const UltraBlock& block, - size_t gate_index) + 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]); - size_t block_index = 0; - if (i == 0) { - block_index = this->find_block_index(ultra_circuit_builder, block); - } - info("block index == ", block_index); - KeyPair key = std::make_pair(gate_variables[i], block_index); + 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); } @@ -69,28 +46,29 @@ inline void Graph_::process_gate_variables(UltraCircuitBuilder& ultra_circui template inline std::vector> Graph_::get_arithmetic_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& 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]; - auto q_arith = arithmetic_block.q_arith()[index]; + auto q_arith = blk.q_arith()[index]; std::vector gate_variables; std::vector minigate_variables; - 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)); - } - 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_arith > 0) { + std::vector> 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); @@ -111,8 +89,8 @@ inline std::vector> Graph_::get_arithmetic_gate_connec // 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) { - gate_variables.emplace_back(arithmetic_block.w_4()[index + 1]); + if (index != blk.size() - 1) { + gate_variables.emplace_back(blk.w_4()[index + 1]); } } if (q_arith == 3) { @@ -120,19 +98,18 @@ inline std::vector> Graph_::get_arithmetic_gate_connec //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 != arithmetic_block.size() - 1) { - gate_variables.emplace_back(arithmetic_block.w_4()[index + 1]); - minigate_variables.emplace_back(arithmetic_block.w_l()[index + 1]); + if (index != blk.size() - 1) { + gate_variables.emplace_back(blk.w_4()[index + 1]); + minigate_variables.emplace_back(blk.w_l()[index + 1]); } } } - } - std::vector> all_gates_variables; - this->process_gate_variables(ultra_circuit_builder, gate_variables, arithmetic_block, index); - this->process_gate_variables(ultra_circuit_builder, minigate_variables, arithmetic_block, index); - 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, 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); + } } return all_gates_variables; } @@ -147,34 +124,32 @@ inline std::vector> Graph_::get_arithmetic_gate_connec template inline std::vector Graph_::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 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, elliptic_block, index); return gate_variables; } @@ -189,18 +164,17 @@ inline std::vector Graph_::get_elliptic_gate_connected_component( template inline std::vector Graph_::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 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, delta_range_block, index); + this->process_gate_variables(ultra_circuit_builder, gate_variables, index, blk_idx); return gate_variables; } @@ -215,48 +189,46 @@ inline std::vector Graph_::get_sort_constraint_connected_component template inline std::vector Graph_::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 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]); - } - if (q_m != 0) { - gate_variables.emplace_back(lookup_block.w_r()[index + 1]); - } - if (q_c != 0) { - gate_variables.emplace_back(lookup_block.w_o()[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]); + } } } + this->process_gate_variables(ultra_circuit_builder, gate_variables, index, blk_idx); } - this->process_gate_variables(ultra_circuit_builder, gate_variables, lookup_block, index); return gate_variables; } template inline std::vector Graph_::get_poseido2s_gate_connected_component( - bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, bool is_internal_block) + bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t blk_idx, UltraBlock& block) { std::vector gate_variables; - auto& block = ultra_circuit_builder.blocks.poseidon2_internal; - auto& selector = block.q_poseidon2_internal()[index]; - if (!is_internal_block) { - block = ultra_circuit_builder.blocks.poseidon2_external; - selector = block.q_poseidon2_external()[index]; - } - if (selector == 1) { + 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) { @@ -264,18 +236,17 @@ inline std::vector Graph_::get_poseido2s_gate_connected_component( 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); } - this->process_gate_variables(ultra_circuit_builder, gate_variables, block, index); return gate_variables; } template inline std::vector Graph_::get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_builder, - size_t index) + size_t index, size_t blk_idx, UltraBlock& block) { std::vector gate_variables; - auto& block = ultra_builder.blocks.aux; - if (block.q_aux()[index] == 1) { + 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]; @@ -290,7 +261,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( auto w_4 = block.w_4()[index]; if (q_3 == 1 && q_4 == 1) { // bigfield limb accumulation 1 - ASSERT(q_arith == 0); + ASSERT(q_arith.is_zero()); if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), { w_l, @@ -301,8 +272,8 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( block.w_r()[index + 1] }); } } - if (q_3 == 1 && q_m == 1) { - ASSERT(q_arith == 0); + 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(), @@ -314,8 +285,8 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( block.w_4()[index + 1] }); } } - if (q_2 == 1 && (q_3 == 1 || q_4 == 1 || q_m == 1)) { - ASSERT(q_arith == 0); + 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 limb_subproduct_vars = { @@ -323,14 +294,14 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( }; if (q_3 == 1) { // bigfield product 1 - ASSERT(q_4 == 0 && q_m == 0); + 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 == 0 && q_m == 0 && q_arith == 0); + ASSERT(q_3.is_zero() && q_m.is_zero()); std::vector non_native_field_gate_2 = { w_l, w_4, w_r, @@ -344,7 +315,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } if (q_m == 1) { // bigfield product 3 - ASSERT(q_4 == 0 && q_3 == 0); + 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(), @@ -352,8 +323,8 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } } } - if (q_1 == 1 && q_4 == 1) { - ASSERT(q_arith == 0); + 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(), @@ -364,8 +335,8 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( block.w_o()[index] }); } } - if (q_1 == 1 && q_2 == 1) { - ASSERT(q_arith == 0); + else if (q_1 == 1 && q_2 == 1) { + ASSERT(q_arith.is_zero()); // rom constitency check if (index < block.size() - 1) { gate_variables.insert( @@ -373,8 +344,9 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( { block.w_l()[index], block.w_l()[index + 1], block.w_4()[index], block.w_4()[index + 1] }); } } - if (q_arith == 1) { + else { // ram constitency check + ASSERT(!q_arith.is_zero()); if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), { block.w_o()[index], @@ -386,7 +358,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } } } - this->process_gate_variables(ultra_builder, gate_variables, block, index); + this->process_gate_variables(ultra_builder, gate_variables, index, blk_idx); return gate_variables; } @@ -396,6 +368,7 @@ template inline std::vector Graph_::get_rom_table_connected_component( bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RomTranscript& rom_array) { + size_t block_index = 3; // 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 @@ -431,7 +404,7 @@ inline std::vector Graph_::get_rom_table_connected_component( } gate_variables.emplace_back(record_witness); } - this->process_gate_variables(ultra_builder, gate_variables, ultra_builder.blocks.aux, gate_index); + 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()) { @@ -445,6 +418,7 @@ template inline std::vector Graph_::get_ram_table_connected_component( bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RamTranscript& ram_array) { + size_t block_index = 3; std::vector ram_table_variables; for (const auto& record : ram_array.records) { std::vector gate_variables; @@ -464,7 +438,7 @@ inline std::vector Graph_::get_ram_table_connected_component( 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/ROM read gate uses variables (w_1, w_2, w_3, w_4) = (index_witness, vc1_witness, vc2_witness, record_witness) + //By default RAM/ROM read 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) { @@ -475,7 +449,7 @@ inline std::vector Graph_::get_ram_table_connected_component( } gate_variables.emplace_back(record_witness); } - this->process_gate_variables(ultra_builder, gate_variables, ultra_builder.blocks.aux, gate_index); + 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()); @@ -503,85 +477,45 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit } std::map 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 all_gates_variables = this->get_arithmetic_gate_connected_component(ultra_circuit_constructor, i); - for (const auto& gate_variables: all_gates_variables) { - if (!gate_variables.empty()) { - this->connect_all_variables_in_vector(ultra_circuit_constructor, gate_variables, false); + 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 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& 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 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 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(); - if (lookup_gates > 0) { - for (size_t i = 0; i < lookup_gates; i++) { - std::vector variable_indices = - this->get_plookup_gate_connected_component(ultra_circuit_constructor, i); - this->connect_all_variables_in_vector(ultra_circuit_constructor, variable_indices, false); - } - } - const auto& poseidon2_internal_block = ultra_circuit_constructor.blocks.poseidon2_internal; - auto internal_gates = poseidon2_internal_block; - if (internal_gates.size() > 0) { - for (size_t i = 0; i < internal_gates.size(); i++) { - std::vector variable_indices = - this->get_poseido2s_gate_connected_component(ultra_circuit_constructor, i); - this->connect_all_variables_in_vector( - ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false); - } - } - - const auto& poseidon2_external_block = ultra_circuit_constructor.blocks.poseidon2_external; - auto external_gates = poseidon2_external_block; - if (external_gates.size() > 0) { - for (size_t i = 0; i < external_gates.size(); i++) { - std::vector variable_indices = - this->get_poseido2s_gate_connected_component(ultra_circuit_constructor, i, /*is_internal_block=*/false); - this->connect_all_variables_in_vector( - ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false); - } - } - const auto& aux_block = ultra_circuit_constructor.blocks.aux; - if (aux_block.size() > 0) { - for (size_t i = 0; i < aux_block.size(); i++) { - std::vector variable_indices = - this->get_auxiliary_gate_connected_component(ultra_circuit_constructor, i); - this->connect_all_variables_in_vector( - ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false); - } - } const auto& rom_arrays = ultra_circuit_constructor.rom_arrays; if (rom_arrays.size() > 0) { for (size_t i = 0; i < rom_arrays.size(); i++) { @@ -591,6 +525,7 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit 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++) { diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp index 1c4d7984fe3..5477b3275e7 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp @@ -55,27 +55,27 @@ template class Graph_ { { return ultra_circuit_constructor.real_variable_index[variable_index]; }; - bool is_equal_blocks(const UltraBlock& blk1, const UltraBlock& blk2); size_t find_block_index(bb::UltraCircuitBuilder& ultra_builder, const UltraBlock& block); void process_gate_variables(bb::UltraCircuitBuilder& ultra_circuit_constructor, std::vector& gate_variables, - const UltraBlock& block, - size_t gate_index); + size_t gate_index, + size_t blk_idx); std::unordered_map get_variables_gate_counts() { return this->variables_gate_counts; }; std::vector> get_arithmetic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index); + size_t index, size_t block_idx, UltraBlock& blk); std::vector get_elliptic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index); + size_t index, size_t block_idx, UltraBlock& blk); std::vector get_plookup_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index); + size_t index, size_t block_idx, UltraBlock& blk); std::vector get_sort_constraint_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index); + size_t index, size_t block_idx, UltraBlock& blk); std::vector get_poseido2s_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, - bool is_internal_block = true); + size_t block_idx, + UltraBlock& blk); std::vector get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index); + size_t index, size_t block_idx, UltraBlock& blk); std::vector get_rom_table_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, const bb::UltraCircuitBuilder::RomTranscript& rom_array); std::vector get_ram_table_connected_component(bb::UltraCircuitBuilder& ultra_builder, From be07cb6f8505da2da41e346809d3236f7903debb Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 17 Feb 2025 11:14:29 +0000 Subject: [PATCH 11/27] new tests for poseidon2s + other tests redesign --- .../graph_description.test.cpp | 6 +- ...escription_poseidon2s_permutation.test.cpp | 92 ++++++++++++++++--- .../graph_description_sha256.test.cpp | 1 - 3 files changed, 82 insertions(+), 17 deletions(-) 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 164a34d3093..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 @@ -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_poseidon2s_permutation.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_poseidon2s_permutation.test.cpp index a49ff55a044..2fd213f537c 100644 --- 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 @@ -24,6 +24,11 @@ using Builder = UltraCircuitBuilder; using Permutation = stdlib::Poseidon2Permutation; using field_t = stdlib::field_t; using witness_t = stdlib::witness_t; +using _curve = stdlib::bn254; +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& input_vector, const uint32_t& real_var_index) { @@ -41,22 +46,72 @@ void test_poseidon2s_circuit(size_t num_inputs = 5) std::vector inputs; for (size_t i = 0; i < num_inputs; ++i) { - const auto element = fr::random_element(&engine); + auto element = fr::random_element(&engine); inputs.emplace_back(field_t(witness_t(&builder, element))); } - auto result = stdlib::poseidon2::hash(builder, inputs); - auto res_index = result.witness_index; + for (auto& elem: inputs) { + elem.fix_witness(); + } + [[maybe_unused]]auto result = stdlib::poseidon2::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); - for (const auto& elem : variables_in_one_gate) { - info("elem = ", elem); - if (!check_in_input_vector(inputs, elem) && elem != res_index) { - bool check = (elem - res_index == 1) || (elem - res_index == 2) || (elem - res_index == 3); - EXPECT_EQ(check, true); - } + std::unordered_set 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); + } +} + +void test_poseidon2s_hash_byte_array(size_t num_inputs = 5) +{ + Builder builder; + + std::vector 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::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 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); + } +} + +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 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::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); } } @@ -72,12 +127,12 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_one_permutation) auto poseidon2permutation = Permutation(); [[maybe_unused]] auto new_state = poseidon2permutation.permutation(&builder, inputs); - //(void)new_state; auto graph = Graph(builder); auto connected_components = graph.find_connected_components(); EXPECT_EQ(connected_components.size(), 1); - graph.print_connected_components(); + 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_two_permutations) @@ -101,6 +156,8 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_two_permutations) auto connected_components = graph.find_connected_components(); EXPECT_EQ(connected_components.size(), 2); graph.print_connected_components(); + 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) @@ -112,5 +169,16 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s) TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_for_one_input_size) { - test_poseidon2s_circuit(5); + 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_sha256.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_sha256.test.cpp index 0f7e39212b4..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 @@ -92,7 +92,6 @@ HEAVY_TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_five) 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); - info("huy"); } TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_one) From 1df6f4a2412042762deda362959aa98f5199a90b Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 17 Feb 2025 11:14:59 +0000 Subject: [PATCH 12/27] new tests for bigfield primitive --- .../graph_description_bigfield.test.cpp | 354 ++++++++++++++++++ 1 file changed, 354 insertions(+) create mode 100644 barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_bigfield.test.cpp 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..1e0b3de39e5 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_bigfield.test.cpp @@ -0,0 +1,354 @@ +#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 +#include + +using namespace bb; +using namespace cdg; + +namespace { +auto& engine = numeric::get_debug_randomness(); +} + +using Builder = UltraCircuitBuilder; +using bn254 = stdlib::bn254; +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(); +} + + +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); +} + +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); +} + +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); + } +} + +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); +} + +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); + if (variables_in_one_gate.size() > 0) { + for (const auto& elem: variables_in_one_gate) { + info("elem == ", elem); + } + } +} + +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); +} + +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); +} + +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); +} + +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); + if (variables_in_one_gate.size() > 0) { + for (const auto &elem: variables_in_one_gate) { + info("elem == ", elem); + } + } +} + +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); +} + +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 mul_left; + std::vector mul_right; + std::vector 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 connected_components = graph.find_connected_components(); + info("size of connected commponents == ", connected_components.size()); + for (size_t i = 0; i < connected_components.size(); i++) { + info("size of the ", i, " connected component == ", connected_components[i].size()); + } + 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); + } + } +} + +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); + for (const auto &elem: variables_in_one_gate) { + info("elem == ", elem); + } +} + From d865da8b6fd5274b0535f3742df50d04f6d58030 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 17 Feb 2025 12:25:23 +0000 Subject: [PATCH 13/27] add commentaries for new functions --- .../boomerang_value_detection/graph.cpp | 197 +++++++++++++----- .../boomerang_value_detection/graph.hpp | 10 +- 2 files changed, 150 insertions(+), 57 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 03b3dac38cb..03143213142 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -9,11 +9,40 @@ 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 +size_t Graph_::find_block_index(UltraCircuitBuilder& ultra_builder, const UltraBlock& block) { + auto gate_blocks = ultra_circuit_constructor.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 inline void Graph_::process_gate_variables(UltraCircuitBuilder& ultra_circuit_builder, std::vector& gate_variables, @@ -37,13 +66,16 @@ inline void Graph_::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 + * @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> 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 inline std::vector> Graph_::get_arithmetic_gate_connected_component( bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t block_idx, UltraBlock& blk) @@ -116,12 +148,15 @@ inline std::vector> Graph_::get_arithmetic_gate_connec /** * @brief this method creates connected components from elliptic gates - * @tparam FF - * @param ultra_circuit_builder - * @param index - * @return std::vector + * @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 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 inline std::vector Graph_::get_elliptic_gate_connected_component( bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t block_idx, UltraBlock& blk) @@ -155,13 +190,15 @@ inline std::vector Graph_::get_elliptic_gate_connected_component( /** * @brief this method creates connected components from sorted constraints - * - * @tparam FF - * @param ultra_circuit_builder - * @param index - * @return std::vector + * @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 vector of connected variables from the gate + * @details Processes delta range constraints by collecting all wire indices + * from the current gate */ - template inline std::vector Graph_::get_sort_constraint_connected_component( bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t blk_idx, UltraBlock& block) @@ -180,13 +217,15 @@ inline std::vector Graph_::get_sort_constraint_connected_component /** * @brief this method creates connected components from plookup gates - * - * @tparam FF - * @param ultra_circuit_builder - * @param index - * @return std::vector + * @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 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 inline std::vector Graph_::get_plookup_gate_connected_component( bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t blk_idx, UltraBlock& block) @@ -221,6 +260,15 @@ inline std::vector Graph_::get_plookup_gate_connected_component( 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 vector of connected variables from the gate + */ template inline std::vector Graph_::get_poseido2s_gate_connected_component( bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t blk_idx, UltraBlock& block) @@ -241,6 +289,16 @@ inline std::vector Graph_::get_poseido2s_gate_connected_component( 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 vector of connected variables from the gate + */ template inline std::vector Graph_::get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_builder, size_t index, size_t blk_idx, UltraBlock& block) @@ -362,13 +420,20 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( return gate_variables; } - - +/** + * @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 vector of connected variables from ROM table gates + */ template inline std::vector Graph_::get_rom_table_connected_component( bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RomTranscript& rom_array) { - size_t block_index = 3; + size_t block_index = find_block_index(ultra_builder, ultra_builder.blocks.aux); + ASSERT(block_index == 3); + // 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 @@ -393,7 +458,7 @@ inline std::vector Graph_::get_rom_table_connected_component( 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 RAM/ROM read gate uses variables (w_1, w_2, w_3, w_4) = (index_witness, vc1_witness, vc2_witness, record_witness) + //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) { @@ -414,11 +479,19 @@ inline std::vector Graph_::get_rom_table_connected_component( 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 vector of connected variables from RAM table gates + */ template inline std::vector Graph_::get_ram_table_connected_component( bb::UltraCircuitBuilder& ultra_builder, const UltraCircuitBuilder::RamTranscript& ram_array) { - size_t block_index = 3; + size_t block_index = find_block_index(ultra_builder, ultra_builder.blocks.aux); + ASSERT(block_index == 3); std::vector ram_table_variables; for (const auto& record : ram_array.records) { std::vector gate_variables; @@ -438,7 +511,7 @@ inline std::vector Graph_::get_ram_table_connected_component( 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/ROM read gate uses variables (w_1, w_2, w_3, w_4) = (index_witness, timestamp_witness, value_witness, record_witness) + //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) { @@ -459,11 +532,25 @@ inline std::vector Graph_::get_ram_table_connected_component( /** * @brief Construct a new Graph from Ultra Circuit Builder - * @tparam FF - * @param ultra_circuit_constructor + * @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 Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit_constructor) +template +Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit_constructor) { this->variables_gate_counts = std::unordered_map(ultra_circuit_constructor.real_variable_index.size()); @@ -661,7 +748,7 @@ void Graph_::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> + * @return std::vector> list of connected components where each component is a vector of variable indices */ template std::vector> Graph_::find_connected_components() @@ -745,8 +832,7 @@ inline size_t Graph_::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 @@ -796,7 +882,14 @@ inline void Graph_::remove_unnecessary_decompose_variables(bb::UltraCircuitB } } - +/** + * @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 void Graph_::remove_unnecessary_range_constrains_variables(bb::UltraCircuitBuilder& ultra_builder) { std::map range_lists = ultra_builder.range_lists; @@ -999,12 +1092,11 @@ inline void Graph_::remove_unnecessary_plookup_variables(bb::UltraCircuitBui } } - /** * @brief this method returns a final set of variables that were in one gate * @tparam FF - * @param ultra_circuit_builder - * @return std::unordered_set + * @param ultra_circuit_builder circuit builder containing the variables + * @return std::unordered_set set of variable indices */ template @@ -1038,12 +1130,10 @@ std::unordered_set Graph_::show_variables_in_one_gate(bb::UltraCir } /** - * @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, 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, size_t> pair of component and its size */ std::pair, size_t> get_connected_component_with_index( @@ -1096,9 +1186,7 @@ template void Graph_::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 */ @@ -1110,10 +1198,7 @@ template void Graph_::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. + * @brief this method prints a number of edges for each variable * @tparam FF */ diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp index 5477b3275e7..dd36c1d1099 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp @@ -20,6 +20,14 @@ 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, 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; @@ -153,7 +161,7 @@ template class Graph_ { variables_gate_counts; // we use this data structure to count, how many gates use every variable std::unordered_map variables_degree; // we use this data structure to count, how many every variable have edges - std::unordered_map, KeyHasher, KeyEquals> variable_gates; //we use this data structure to store a pair of UltraTraceBlock and gate number in this block, where every variable was found in the circuit + std::unordered_map, 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 variables_in_one_gate; std::unordered_set fixed_variables; }; From 1cc712f36010edce8e312c33b0a79a62a0199366 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 17 Feb 2025 12:31:36 +0000 Subject: [PATCH 14/27] commentaries for poseidon2s tests --- ...escription_poseidon2s_permutation.test.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) 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 index 2fd213f537c..19b3de72ed8 100644 --- 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 @@ -40,6 +40,10 @@ bool check_in_input_vector(const std::vector& input_vector, const uint3 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(); @@ -64,6 +68,10 @@ void test_poseidon2s_circuit(size_t num_inputs = 5) } } +/** + * @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; @@ -86,6 +94,11 @@ void test_poseidon2s_hash_byte_array(size_t num_inputs = 5) } } +/** + * @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; @@ -115,6 +128,11 @@ void test_poseidon2s_hash_repeated_pairs(size_t num_inputs = 5) } } +/** + * @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 inputs; @@ -135,6 +153,11 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_one_permutation) 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 From 815bcb76ff6ca7e9fa8b6647195c4fbb1ccec5bb Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 17 Feb 2025 12:33:51 +0000 Subject: [PATCH 15/27] tests descriptiion for ram/rom tables --- .../graph_description_ram_rom.test.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) 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 index 722a57497b2..cf07d502dde 100644 --- 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 @@ -16,6 +16,11 @@ using witness_ct = stdlib::witness_t; using rom_table_ct = stdlib::rom_table; using ram_table_ct = stdlib::ram_table; +/** + * @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; @@ -43,6 +48,11 @@ TEST(boomerang_rom_ram_table, graph_description_rom_table) EXPECT_EQ(variables_in_one_gate.size(), 0); } +/** + * @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; @@ -67,6 +77,15 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_read) EXPECT_EQ(variables_in_one_gate.size(), 0); } +/** + * @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; From 55b01e73571666a584bcf67f7efa30950021e62b Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 17 Feb 2025 12:42:13 +0000 Subject: [PATCH 16/27] commentaries for bigfield and dynamic array tests --- .../graph_description_bigfield.test.cpp | 68 ++++++++++++++++++- .../graph_description_dynamic_array.test.cpp | 20 ++++++ 2 files changed, 87 insertions(+), 1 deletion(-) 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 index 1e0b3de39e5..7cc36bcb242 100644 --- 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 @@ -37,7 +37,16 @@ void fix_bigfield_element(const fq_ct& element) { 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); @@ -53,6 +62,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_constructors) { 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); @@ -76,6 +90,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_addition) { 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); @@ -103,6 +122,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_substraction) { } } +/** + * @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); @@ -123,6 +147,12 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_multiplication) { 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); @@ -155,6 +185,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_division) { } } +/** + * @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); @@ -200,6 +235,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_mix_operations) { 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; @@ -223,6 +263,11 @@ TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits_and_op 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; @@ -243,6 +288,11 @@ TEST(boomerang_bigfield, test_graph_description_mul_function) { 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; @@ -265,6 +315,11 @@ TEST(boomerang_bigfield, test_graph_description_sqr_function) { } } +/** + * @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; @@ -286,6 +341,12 @@ TEST(boomerang_bigfield, test_graph_description_madd_function) { 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(); @@ -332,6 +393,11 @@ TEST(boomerang_bigfield, test_graph_description_mult_madd_function) { } } +/** + * @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(); 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 index cdc55880e55..975d2ebd1ff 100644 --- 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 @@ -18,6 +18,15 @@ using field_ct = stdlib::field_t; using witness_ct = stdlib::witness_t; using DynamicArray_ct = stdlib::DynamicArray; +/** + * @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) { @@ -39,6 +48,17 @@ TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_method_resi EXPECT_EQ(variables_in_one_gate.size(), 1); } +/** + * @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; From 38bf9986b9c977b01dc83fdcbfeeafc2919e8097 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Mon, 17 Feb 2025 12:44:50 +0000 Subject: [PATCH 17/27] this test fifile is useless now, sso we can remove it --- .../variables_gate_counts.sha256.test.cpp | 181 ------------------ 1 file changed, 181 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/boomerang_value_detection/variables_gate_counts.sha256.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variables_gate_counts.sha256.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variables_gate_counts.sha256.test.cpp deleted file mode 100644 index 8474a725c70..00000000000 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variables_gate_counts.sha256.test.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "barretenberg/boomerang_value_detection/graph.hpp" -#include "barretenberg/circuit_checker/circuit_checker.hpp" -#include "barretenberg/common/test.hpp" -#include "barretenberg/crypto/sha256/sha256.hpp" -#include "barretenberg/stdlib/hash/sha256/sha256.hpp" -#include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp" -#include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" -#include "barretenberg/stdlib_circuit_builders/plookup_tables/plookup_tables.hpp" -#include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" - -#include "barretenberg/numeric/bitop/rotate.hpp" -#include "barretenberg/numeric/bitop/sparse_form.hpp" -#include "barretenberg/numeric/random/engine.hpp" - -#include - -#include - -using namespace bb; -using namespace bb::stdlib; -using namespace cdg; - -using Builder = UltraCircuitBuilder; - -using byte_array_ct = byte_array; -using packed_byte_array_ct = packed_byte_array; -using witness_ct = stdlib::witness_t; -using field_ct = field_t; - -bool check_in_byte_array(const uint32_t& real_var_index, const packed_byte_array_ct& byte_array) -{ - std::vector> limbs = byte_array.get_limbs(); - for (const auto& elem : limbs) { - if (elem.witness_index == real_var_index) { - return true; - } - } - return false; -} - -bool check_in_range_lists(const uint32_t& real_var_index, const uint64_t& target_range, const Builder& builder) -{ - auto range_lists = builder.range_lists; - auto target_list = range_lists[target_range]; - for (const auto elem : target_list.variable_indices) { - if (elem == real_var_index) { - return true; - } - } - return false; -} - -/** - * @brief all these tests check circuits for sha256 NIST VECTORS to find variables that won't properly constrained, - * i.e. have variable gates count = 1. Some variables can be from input/output vectors or from range_constraints, - * and they are not dangerous. - */ - -TEST(boomerang_stdlib_sha256, test_variables_gate_counts_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_ct output_bits = stdlib::sha256(input); - - // std::vector output = output_bits.to_unverified_byte_slices(4); - - Graph graph = Graph(builder); - std::unordered_set variables_in_on_gate = graph.show_variables_in_one_gate(builder); - std::vector vector_variables_in_on_gate(variables_in_on_gate.begin(), variables_in_on_gate.end()); - std::sort(vector_variables_in_on_gate.begin(), vector_variables_in_on_gate.end()); - for (const auto& elem : vector_variables_in_on_gate) { - bool result1 = check_in_byte_array(elem, input); - bool result2 = check_in_byte_array(elem, output_bits); - bool result3 = check_in_range_lists(elem, 3, builder); - bool check = (result1 == 1) || (result2 == 1) || (result3 == 1); - EXPECT_EQ(check, true); - } -} - -TEST(boomerang_stdlib_sha256, test_variable_gates_count_for_sha256_NIST_vector_one) -{ - auto builder = Builder(); - packed_byte_array_ct input(&builder, "abc"); - packed_byte_array_ct output_bits = stdlib::sha256(input); - - Graph graph = Graph(builder); - std::unordered_set variables_in_one_gate = graph.show_variables_in_one_gate(builder); - for (const auto& elem : variables_in_one_gate) { - bool result1 = check_in_byte_array(elem, input); - bool result2 = check_in_byte_array(elem, output_bits); - bool result3 = check_in_range_lists(elem, 3, builder); - bool check = (result1 == 1) || (result2 == 1) || (result3 == 1); - EXPECT_EQ(check, true); - } -} - -TEST(boomerang_stdlib_sha256, test_variable_gates_count_for_sha256_NIST_vector_two) -{ - auto builder = Builder(); - - packed_byte_array_ct input(&builder, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); - - packed_byte_array_ct output_bits = stdlib::sha256(input); - Graph graph = Graph(builder); - std::unordered_set variables_in_one_gate = graph.show_variables_in_one_gate(builder); - for (const auto& elem : variables_in_one_gate) { - bool result1 = check_in_byte_array(elem, input); - bool result2 = check_in_byte_array(elem, output_bits); - bool result3 = check_in_range_lists(elem, 3, builder); - bool check = (result1 == 1) || (result2 == 1) || (result3 == 1); - EXPECT_EQ(check, true); - } -} - -TEST(boomerang_stdlib_sha256, test_variable_gates_count_sha256_NIST_vector_three) -{ - auto builder = Builder(); - - // one byte, 0xbd - packed_byte_array_ct input(&builder, std::vector{ 0xbd }); - packed_byte_array_ct output_bits = stdlib::sha256(input); - Graph graph = Graph(builder); - std::unordered_set variables_in_one_gate = graph.show_variables_in_one_gate(builder); - for (const auto& elem : variables_in_one_gate) { - bool result1 = check_in_byte_array(elem, input); - bool result2 = check_in_byte_array(elem, output_bits); - bool result3 = check_in_range_lists(elem, 3, builder); - bool check = (result1 == 1) || (result2 == 1) || (result3 == 1); - EXPECT_EQ(check, true); - } -} - -TEST(boomerang_stdlib_sha256, test_variable_gates_count_sha256_NIST_vector_four) -{ - auto builder = Builder(); - - // 4 bytes, 0xc98c8e55 - packed_byte_array_ct input(&builder, std::vector{ 0xc9, 0x8c, 0x8e, 0x55 }); - packed_byte_array_ct output_bits = stdlib::sha256(input); - Graph graph = Graph(builder); - std::unordered_set variables_in_one_gate = graph.show_variables_in_one_gate(builder); - for (const auto& elem : variables_in_one_gate) { - bool result1 = check_in_byte_array(elem, input); - bool result2 = check_in_byte_array(elem, output_bits); - bool result3 = check_in_range_lists(elem, 3, builder); - bool check = (result1 == 1) || (result2 == 1) || (result3 == 1); - EXPECT_EQ(check, true); - } -} - -HEAVY_TEST(boomerang_stdlib_sha256, test_variable_gates_count_for_sha256_NIST_vector_five) -{ - auto builder = Builder(); - - packed_byte_array_ct input( - &builder, - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAA"); - - packed_byte_array_ct output_bits = stdlib::sha256(input); - Graph graph = Graph(builder); - std::unordered_set variables_in_on_gate = graph.show_variables_in_one_gate(builder); - for (const auto& elem : variables_in_on_gate) { - bool result1 = check_in_byte_array(elem, input); - bool result2 = check_in_byte_array(elem, output_bits); - bool result3 = check_in_range_lists(elem, 3, builder); - bool check = (result1 == 1) || (result2 == 1) || (result3 == 1); - EXPECT_EQ(check, true); - } -} \ No newline at end of file From fe226d7a59bfed83108b05fa22a6d35da90948d6 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Tue, 18 Feb 2025 12:15:01 +0000 Subject: [PATCH 18/27] final graph description + removing some unnesecary information from tests --- .../boomerang_value_detection/graph.cpp | 99 +++++++++++++++---- .../boomerang_value_detection/graph.hpp | 3 +- .../graph_description_bigfield.test.cpp | 23 ----- .../graph_description_dynamic_array.test.cpp | 5 +- .../graph_description_ram_rom.test.cpp | 16 ++- 5 files changed, 101 insertions(+), 45 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 03143213142..6cc3e9fe29a 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -17,7 +17,7 @@ namespace cdg { */ template size_t Graph_::find_block_index(UltraCircuitBuilder& ultra_builder, const UltraBlock& block) { - auto gate_blocks = ultra_circuit_constructor.blocks.get_gate_blocks(); + 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)) { @@ -404,15 +404,16 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( } else { // ram constitency check - ASSERT(!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] }); + 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] }); + } } } } @@ -1092,6 +1093,46 @@ inline void Graph_::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 +inline void Graph_::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 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 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 @@ -1126,6 +1167,7 @@ std::unordered_set Graph_::show_variables_in_one_gate(bb::UltraCir 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; } @@ -1211,17 +1253,38 @@ template void Graph_::print_variables_edge_counts() } } -/* template void Graph_::print_variables_in_one_gate() +/** + * @brief this method prints information about gate's selectors for every variable in one gate + * @tparam FF + * @param ultra_builder + */ + +template void Graph_::print_variables_in_one_gate(bb::UltraCircuitBuilder& ultra_builder) { - for (const auto& elem : variables_in_one_gate) { - if (variables_gates[elem].size() == 1) { - info("for variable with index ", elem, " gate index == ", variables_gates[elem][0]); + 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 ----"); } - else { - info("variable with index ", elem, " may be false case"); - } } -} */ +} template class Graph_; diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp index dd36c1d1099..c19bc1e95aa 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp @@ -145,12 +145,13 @@ template 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(); + void print_variables_in_one_gate(bb::UltraCircuitBuilder& ultra_builder); ~Graph_() = default; private: 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 index 7cc36bcb242..cfdf030c58a 100644 --- 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 @@ -178,11 +178,6 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_division) { //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); - if (variables_in_one_gate.size() > 0) { - for (const auto& elem: variables_in_one_gate) { - info("elem == ", elem); - } - } } /** @@ -308,11 +303,6 @@ TEST(boomerang_bigfield, test_graph_description_sqr_function) { 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); - if (variables_in_one_gate.size() > 0) { - for (const auto &elem: variables_in_one_gate) { - info("elem == ", elem); - } - } } /** @@ -379,18 +369,8 @@ TEST(boomerang_bigfield, test_graph_description_mult_madd_function) { } builder.finalize_circuit(false); auto graph = Graph(builder); - auto connected_components = graph.find_connected_components(); - info("size of connected commponents == ", connected_components.size()); - for (size_t i = 0; i < connected_components.size(); i++) { - info("size of the ", i, " connected component == ", connected_components[i].size()); - } 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); - } - } } /** @@ -413,8 +393,5 @@ TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits) 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); - for (const auto &elem: variables_in_one_gate) { - info("elem == ", elem); - } } 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 index 975d2ebd1ff..3fba4f8b37d 100644 --- 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 @@ -45,9 +45,10 @@ TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_method_resi 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(), 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, @@ -84,5 +85,5 @@ TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_consistency 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); + 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_ram_rom.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_ram_rom.test.cpp index cf07d502dde..8d6cadee571 100644 --- 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 @@ -38,14 +38,21 @@ TEST(boomerang_rom_ram_table, graph_description_rom_table) for (size_t i = 0; i < 10; ++i) { 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); 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); + } + } } /** @@ -68,13 +75,17 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_read) for (size_t i = 0; i < 10; ++i) { 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); - EXPECT_EQ(variables_in_one_gate.size(), 0); + for (const auto& elem: variables_in_one_gate) { + info("elem == ", elem); + } } /** @@ -130,4 +141,7 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_write) 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); + } } \ No newline at end of file From e67ff24a1d070e161494ab7d0f7a1fb686f19f6e Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 19 Feb 2025 11:39:23 +0000 Subject: [PATCH 19/27] final tests for ran and rom tables --- .../graph_description_ram_rom.test.cpp | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) 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 index 8d6cadee571..9bb96666f81 100644 --- 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 @@ -30,13 +30,17 @@ TEST(boomerang_rom_ram_table, graph_description_rom_table) 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 safety_variables; field_ct result = field_ct(witness_ct(&builder, (uint64_t)0)); - info("result witness index == ", result.witness_index); 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]; @@ -47,12 +51,9 @@ TEST(boomerang_rom_ram_table, graph_description_rom_table) 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); - } - } + for (const auto& elem: variables_in_one_gate) { + EXPECT_EQ(variables_in_one_gate.contains(elem), true); + } } /** @@ -70,21 +71,28 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_read) 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 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) { - info("elem == ", elem); + EXPECT_EQ(safety_variables.contains(elem), true); } } @@ -103,13 +111,14 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_write) const size_t table_size = 10; std::vector 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 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) { @@ -117,16 +126,26 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_write) table_values[2 * i + 1] = fr::random_element(); // init with both constant and variable values - table.write(2 * i, witness_ct(&builder, table_values[2 * i])); - table.write(2 * i + 1, witness_ct(&builder, table_values[2 * i + 1])); + 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 - result += table.read(witness_ct(&builder, index)); - result += table.read(index + 1); + 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); } }; @@ -136,12 +155,12 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_write) 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); - EXPECT_EQ(variables_in_one_gate.size(), 0); for (const auto& elem: variables_in_one_gate) { - info("elem == ", elem); + EXPECT_EQ(safety_variables.contains(elem), true); } } \ No newline at end of file From 0c155d7958ec0811f55d393e53559c3ee8166892 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 19 Feb 2025 12:11:44 +0000 Subject: [PATCH 20/27] final tests fixes after full run --- ...aph_description_poseidon2s_permutation.test.cpp | 14 +++++++++++--- .../variable_gates_count.test.cpp | 8 ++++---- 2 files changed, 15 insertions(+), 7 deletions(-) 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 index 19b3de72ed8..2fd690d4f32 100644 --- 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 @@ -145,6 +145,9 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_one_permutation) 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(); @@ -173,12 +176,17 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_two_permutations) } auto poseidon2permutation = Permutation(); - poseidon2permutation.permutation(&builder, input1); - poseidon2permutation.permutation(&builder, input2); + [[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); - graph.print_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/variable_gates_count.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/variable_gates_count.test.cpp index 4239bdf1412..066b8f03e97 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 @@ -25,7 +25,7 @@ TEST(boomerang_ultra_circuit_constructor, test_variable_gates_count_for_decompos Graph graph = Graph(circuit_constructor); std::unordered_set 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) @@ -41,7 +41,7 @@ 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) @@ -86,7 +86,7 @@ TEST(boomerang_ultra_circuit_constructor, test_variable_gates_count_for_two_deco Graph graph = Graph(circuit_constructor); std::unordered_set 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) @@ -127,5 +127,5 @@ TEST(boomerang_ultra_circuit_constructor, test_decompose_for_6_bit_number) Graph graph = Graph(circuit_constructor); std::unordered_set 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); } From d9e375eb087be4ec4562e6e7cae5d0cd9d60d427 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 19 Feb 2025 14:43:42 +0000 Subject: [PATCH 21/27] some problems with commits --- .../boomerang_value_detection/graph.cpp | 37 ++++++++++++++----- .../boomerang_value_detection/graph.hpp | 3 +- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 6cc3e9fe29a..dbaf8a6571c 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -1241,17 +1241,36 @@ template void Graph_::print_variables_gate_counts() /** * @brief this method prints a number of edges for each variable - * @tparam FF + * @tparam FF + * @param ultra_builder */ -template void Graph_::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 void Graph_::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 ----"); + } + } + } /** * @brief this method prints information about gate's selectors for every variable in one gate diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp index c19bc1e95aa..ae1024aba13 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp @@ -168,4 +168,5 @@ template class Graph_ { }; using Graph = Graph_; -} //namespace cgd \ No newline at end of file + +} //namespace cgd From 91037798d177c230ffd5085607bd39374d2cb55c Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 19 Feb 2025 14:52:05 +0000 Subject: [PATCH 22/27] merge conflicts again --- .../cpp/src/barretenberg/boomerang_value_detection/graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index dbaf8a6571c..5d84eedb83c 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -917,7 +917,7 @@ void Graph_::remove_unnecessary_range_constrains_variables(bb::UltraCircuitB } /** - * @brief this method removes false positive cass variables from aes plookup tables. + * @brief this method removes false positive 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. From 0f785eb92c24a5ad9240d85b0057625debffd5e6 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Thu, 20 Feb 2025 06:29:26 +0000 Subject: [PATCH 23/27] some probles with merge again --- .../boomerang_value_detection/graph.cpp | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 5d84eedb83c..b28eeb4ffde 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -1272,39 +1272,6 @@ template void Graph_::print_variables_gate_counts() } } -/** - * @brief this method prints information about gate's selectors for every variable in one gate - * @tparam FF - * @param ultra_builder - */ - -template void Graph_::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_; } //namespace cdg From 86f9a35f0e53b7da97335d01e3f237cf23c27a71 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Wed, 26 Feb 2025 11:30:10 +0000 Subject: [PATCH 24/27] changes after format.sh run --- .../boomerang_value_detection/graph.cpp | 287 +++++++++--------- .../boomerang_value_detection/graph.hpp | 62 ++-- .../graph_description.test.cpp | 2 +- .../graph_description_aes128.test.cpp | 8 +- .../graph_description_bigfield.test.cpp | 158 ++++++---- .../graph_description_dynamic_array.test.cpp | 3 +- ...escription_poseidon2s_permutation.test.cpp | 45 +-- .../graph_description_ram_rom.test.cpp | 12 +- .../graph_description_sha256.test.cpp | 26 +- 9 files changed, 332 insertions(+), 271 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index b28eeb4ffde..0f2098c3372 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -1,6 +1,7 @@ #include "./graph.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" #include +#include #include using namespace bb::plookup; @@ -15,12 +16,12 @@ namespace cdg { * @param block block to find * @return size_t index of the found block */ -template -size_t Graph_::find_block_index(UltraCircuitBuilder& ultra_builder, const UltraBlock& block) { - auto gate_blocks = ultra_builder.blocks.get_gate_blocks(); +template size_t Graph_::find_block_index(UltraCircuitBuilder& ultra_builder, const UltraBlock& block) +{ + auto blocks_data = ultra_builder.blocks.get(); size_t index = 0; - for (size_t i = 0; i < gate_blocks.size(); i++) { - if ((void*)(&gate_blocks[i]) == (void*)(&block)) { + for (size_t i = 0; i < blocks_data.size(); i++) { + if ((void*)(&blocks_data[i]) == (void*)(&block)) { index = i; break; } @@ -28,7 +29,6 @@ size_t Graph_::find_block_index(UltraCircuitBuilder& ultra_builder, const Ul return index; } - /** * @brief this method processes variables from a gate by removing duplicates and updating tracking structures * @tparam FF field type @@ -54,11 +54,10 @@ inline void Graph_::process_gate_variables(UltraCircuitBuilder& ultra_circui if (gate_variables.empty()) { return; } - for (auto& var_idx: gate_variables) { + 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; @@ -96,10 +95,9 @@ inline std::vector> Graph_::get_arithmetic_gate_connec 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. + // 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) { + } 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); @@ -126,10 +124,10 @@ inline std::vector> Graph_::get_arithmetic_gate_connec } } 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}); + // 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]); @@ -301,7 +299,9 @@ inline std::vector Graph_::get_poseido2s_gate_connected_component( */ template inline std::vector Graph_::get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_builder, - size_t index, size_t blk_idx, UltraBlock& block) + size_t index, + size_t blk_idx, + UltraBlock& block) { std::vector gate_variables; if (!block.q_aux()[index].is_zero()) { @@ -311,7 +311,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( 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]; + [[maybe_unused]] auto q_c = block.q_c()[index]; auto w_l = block.w_l()[index]; auto w_r = block.w_r()[index]; @@ -322,15 +322,9 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( 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] }); + { 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) { + } else if (q_3 == 1 && q_m == 1) { ASSERT(q_arith.is_zero()); // bigfield limb accumulation 2 if (index < block.size() - 1) { @@ -342,8 +336,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( block.w_o()[index + 1], block.w_4()[index + 1] }); } - } - else if (q_2 == 1 && (q_3 == 1 || q_4 == 1 || q_m == 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) { @@ -360,11 +353,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( if (q_4 == 1) { // bigfield product 2 ASSERT(q_3.is_zero() && q_m.is_zero()); - std::vector non_native_field_gate_2 = { w_l, - w_4, - w_r, - w_o, - block.w_o()[index + 1] }; + std::vector 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]); @@ -380,8 +369,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( { w_4, block.w_o()[index + 1], block.w_4()[index + 1] }); } } - } - else if (q_1 == 1 && q_4 == 1) { + } else if (q_1 == 1 && q_4 == 1) { ASSERT(q_arith.is_zero()); // ram timestamp check if (index < block.size() - 1) { @@ -392,8 +380,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( block.w_l()[index + 1], block.w_o()[index] }); } - } - else if (q_1 == 1 && q_2 == 1) { + } else if (q_1 == 1 && q_2 == 1) { ASSERT(q_arith.is_zero()); // rom constitency check if (index < block.size() - 1) { @@ -401,13 +388,12 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( gate_variables.end(), { block.w_l()[index], block.w_l()[index + 1], block.w_4()[index], block.w_4()[index + 1] }); } - } - else { + } else { // ram constitency check - if (!q_arith.is_zero()) { + if (!q_arith.is_zero()) { if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), - { block.w_o()[index], + { block.w_o()[index], block.w_4()[index], block.w_l()[index + 1], block.w_r()[index + 1], @@ -433,13 +419,13 @@ inline std::vector Graph_::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); + ASSERT(block_index == 5); // 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 rom_table_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 rom_table_variables; for (const auto& record : rom_array.records) { std::vector gate_variables; @@ -454,13 +440,13 @@ inline std::vector Graph_::get_rom_table_connected_component( 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 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 + // 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); @@ -471,12 +457,12 @@ inline std::vector Graph_::get_rom_table_connected_component( 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 + // 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; } @@ -492,7 +478,7 @@ inline std::vector Graph_::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); + ASSERT(block_index == 5); std::vector ram_table_variables; for (const auto& record : ram_array.records) { std::vector gate_variables; @@ -507,13 +493,13 @@ inline std::vector Graph_::get_ram_table_connected_component( 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 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 + // 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); @@ -524,8 +510,8 @@ inline std::vector Graph_::get_ram_table_connected_component( 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 + // 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; @@ -550,8 +536,7 @@ inline std::vector Graph_::get_ram_table_connected_component( * 3) Creating connections between variables that appear in the same gate * 4) Special handling for sorted constraints in delta range blocks */ -template -Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit_constructor) +template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit_constructor) { this->variables_gate_counts = std::unordered_map(ultra_circuit_constructor.real_variable_index.size()); @@ -565,39 +550,54 @@ Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit_constructor) } std::map constant_variable_indices = ultra_circuit_constructor.constant_variable_indices; - 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) { + auto block_data = ultra_circuit_constructor.blocks.get(); + for (size_t blk_idx = 1; blk_idx < block_data.size() - 1; blk_idx++) { + if (block_data[blk_idx].size() > 0) { std::vector 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]); + for (size_t gate_idx = 0; gate_idx < block_data[blk_idx].size(); gate_idx++) { + auto arithmetic_gates_variables = get_arithmetic_gate_connected_component( + ultra_circuit_constructor, gate_idx, blk_idx, block_data[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); + 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]); + auto elliptic_gate_variables = get_elliptic_gate_connected_component( + ultra_circuit_constructor, gate_idx, blk_idx, block_data[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, block_data[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, block_data[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, block_data[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, block_data[blk_idx]); if (delta_range_gate_variables.empty()) { - connect_all_variables_in_vector(ultra_circuit_constructor, sorted_variables, /*is_sorted_variables=*/true); + 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()); + } else { + sorted_variables.insert(sorted_variables.end(), + delta_range_gate_variables.begin(), + delta_range_gate_variables.end()); } } } @@ -749,7 +749,8 @@ void Graph_::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> list of connected components where each component is a vector of variable indices + * @return std::vector> list of connected components where each component is a vector of variable + * indices */ template std::vector> Graph_::find_connected_components() @@ -892,23 +893,26 @@ inline void Graph_::remove_unnecessary_decompose_variables(bb::UltraCircuitB * 2) Variables from range_constraints created by range_constraint_into_two_limbs */ template -void Graph_::remove_unnecessary_range_constrains_variables(bb::UltraCircuitBuilder& ultra_builder) { +void Graph_::remove_unnecessary_range_constrains_variables(bb::UltraCircuitBuilder& ultra_builder) +{ std::map range_lists = ultra_builder.range_lists; std::unordered_set range_lists_tau_tags; std::unordered_set range_lists_range_tags; std::vector real_variable_tags = ultra_builder.real_variable_tags; - for (const auto& pair: range_lists) { + 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 + // 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 + // 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); } @@ -1097,38 +1101,39 @@ inline void Graph_::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 + * @tparam FF + * @param ultra_builder */ -template -inline void Graph_::remove_record_witness_variables(bb::UltraCircuitBuilder& ultra_builder) { - const auto& gate_blocks = ultra_builder.blocks.get_gate_blocks(); +template inline void Graph_::remove_record_witness_variables(bb::UltraCircuitBuilder& ultra_builder) +{ + auto block_data = ultra_builder.blocks.get(); size_t blk_idx = find_block_index(ultra_builder, ultra_builder.blocks.aux); std::vector to_remove; - ASSERT(blk_idx == 3); - for (const auto& var_idx: variables_in_one_gate) { - KeyPair key = {var_idx, blk_idx}; + ASSERT(blk_idx == 5); + 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 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]; + auto q_1 = block_data[blk_idx].q_1()[gate_idx]; + auto q_2 = block_data[blk_idx].q_2()[gate_idx]; + auto q_3 = block_data[blk_idx].q_3()[gate_idx]; + auto q_4 = block_data[blk_idx].q_4()[gate_idx]; + auto q_m = block_data[blk_idx].q_m()[gate_idx]; + auto q_arith = block_data[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) { + // 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, block_data[blk_idx].w_4()[gate_idx]) == var_idx) { to_remove.emplace_back(var_idx); - } + } } } } - for (const auto& elem: to_remove) { + for (const auto& elem : to_remove) { variables_in_one_gate.erase(elem); } } @@ -1164,7 +1169,7 @@ std::unordered_set Graph_::show_variables_in_one_gate(bb::UltraCir 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) { + for (const auto& elem : this->fixed_variables) { this->variables_in_one_gate.erase(elem); } this->remove_record_witness_variables(ultra_circuit_builder); @@ -1241,37 +1246,37 @@ template void Graph_::print_variables_gate_counts() /** * @brief this method prints a number of edges for each variable - * @tparam FF - * @param ultra_builder + * @tparam FF + * @param ultra_builder */ - template void Graph_::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 void Graph_::print_variables_in_one_gate(bb::UltraCircuitBuilder& ultra_builder) +{ + const auto& block_data = ultra_builder.blocks.get(); + 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 = block_data[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_; -} //namespace cdg +} // 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 ae1024aba13..414a25b4da6 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp @@ -3,11 +3,11 @@ #include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" #include #include +#include #include #include #include #include -#include /* * this class describes arithmetic circuit as an undirected graph, where vertices are variables from circuit. @@ -21,30 +21,32 @@ 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, 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; + * 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, 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::UltraTraceBlock; using KeyPair = std::pair; -struct KeyHasher{ - size_t operator()(const KeyPair& pair) const { +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)); - }; + 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()(pair.first)); combined_hash = hash_combiner(combined_hash, std::hash()(pair.second)); return combined_hash; } }; -struct KeyEquals{ - bool operator()(const KeyPair& p1, const KeyPair& p2) const { +struct KeyEquals { + bool operator()(const KeyPair& p1, const KeyPair& p2) const + { return (p1.first == p2.first && p1.second == p2.second); } }; @@ -58,7 +60,7 @@ template class Graph_ { Graph_&& operator=(Graph_&& other) = delete; Graph_(const bb::StandardCircuitBuilder_& 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]; @@ -70,20 +72,28 @@ template class Graph_ { size_t blk_idx); std::unordered_map get_variables_gate_counts() { return this->variables_gate_counts; }; - std::vector> get_arithmetic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index, size_t block_idx, UltraBlock& blk); + std::vector> get_arithmetic_gate_connected_component( + bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t block_idx, UltraBlock& blk); std::vector get_elliptic_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index, size_t block_idx, UltraBlock& blk); + size_t index, + size_t block_idx, + UltraBlock& blk); std::vector get_plookup_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index, size_t block_idx, UltraBlock& blk); + size_t index, + size_t block_idx, + UltraBlock& blk); std::vector get_sort_constraint_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index, size_t block_idx, UltraBlock& blk); + size_t index, + size_t block_idx, + UltraBlock& blk); std::vector get_poseido2s_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, size_t index, size_t block_idx, UltraBlock& blk); std::vector get_auxiliary_gate_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, - size_t index, size_t block_idx, UltraBlock& blk); + size_t index, + size_t block_idx, + UltraBlock& blk); std::vector get_rom_table_connected_component(bb::UltraCircuitBuilder& ultra_circuit_builder, const bb::UltraCircuitBuilder::RomTranscript& rom_array); std::vector get_ram_table_connected_component(bb::UltraCircuitBuilder& ultra_builder, @@ -162,11 +172,13 @@ template class Graph_ { variables_gate_counts; // we use this data structure to count, how many gates use every variable std::unordered_map variables_degree; // we use this data structure to count, how many every variable have edges - std::unordered_map, 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_map, 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 variables_in_one_gate; std::unordered_set fixed_variables; }; using Graph = Graph_; -} //namespace cgd +} // namespace cdg 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 e357192a347..ddbaf31b4c2 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 @@ -38,7 +38,7 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_arithmetic_gates) Graph graph = Graph(circuit_constructor); auto connected_components = graph.find_connected_components(); - [[maybe_unused]]auto variables_in_one_gate = graph.show_variables_in_one_gate(circuit_constructor); + [[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 45e458f72de..c968fa5a065 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 @@ -18,6 +18,12 @@ using Builder = UltraCircuitBuilder; using field_pt = stdlib::field_t; using witness_pt = stdlib::witness_t; +/** + static analyzer usually prints input and output variables as variables in one gate. In tests these variables + are not dangerous and usually we can filter them by adding gate for fixing witness. Then these variables will be + in 2 gates, and static analyzer won't print them. functions fix_vector_witness doest it for vector in_field + */ + void fix_vector_witness(std::vector& input_vector) { for (auto& elem : input_vector) { @@ -123,4 +129,4 @@ TEST(boomerang_stdlib_aes, test_variable_gates_count_for_aes128cbc) EXPECT_EQ(connected_components.size(), 1); std::unordered_set 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_bigfield.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_bigfield.test.cpp index cfdf030c58a..6712b6fcd33 100644 --- 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 @@ -1,18 +1,18 @@ #include "barretenberg/boomerang_value_detection/graph.hpp" -#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" #include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" #include "barretenberg/ecc/curves/bn254/fq.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" +#include "barretenberg/common/test.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/stdlib/primitives/field/field.hpp" #include "barretenberg/transcript/origin_tag.hpp" -#include "barretenberg/common/test.hpp" #include #include @@ -30,7 +30,15 @@ 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) { +/** + static analyzer usually prints input and output variables as variables in one gate. In tests these variables + are not dangerous and usually we can filter them by adding gate for fixing witness. Then these variables will be + in 2 gates, and static analyzer won't print them. function fix_bigfield_element does it + for bigfield element + */ + +void fix_bigfield_element(const fq_ct& element) +{ for (int i = 0; i < 4; i++) { element.binary_basis_limbs[i].element.fix_witness(); } @@ -47,13 +55,14 @@ void fix_bigfield_element(const fq_ct& element) { * - Small field witness * - Mixed construction with lower limb addition */ -TEST(boomerang_bigfield, test_graph_description_bigfield_constructors) { +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; + [[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(); @@ -67,14 +76,15 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_constructors) { * 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) { +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; + [[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); @@ -95,13 +105,14 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_addition) { * 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) { +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; + [[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); @@ -117,7 +128,7 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_substraction) { 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) { + for (const auto& elem : variables_in_one_gate) { info("elem == ", elem); } } @@ -127,13 +138,14 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_substraction) { * 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) { +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; + [[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; @@ -153,13 +165,14 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_multiplication) { * 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) { +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; + [[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); @@ -174,10 +187,10 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_division) { 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); + // 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); } /** @@ -185,7 +198,8 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_division) { * 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) { +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); @@ -235,7 +249,8 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_mix_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) { +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() }; @@ -253,7 +268,7 @@ TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits_and_op fix_bigfield_element(c); auto graph = Graph(builder); auto connected_components = graph.find_connected_components(); - EXPECT_EQ(connected_components.size(), 1); + 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); } @@ -263,15 +278,18 @@ TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits_and_op * 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) { +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 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); @@ -288,7 +306,8 @@ TEST(boomerang_bigfield, test_graph_description_mul_function) { * 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) { +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) { @@ -310,18 +329,22 @@ TEST(boomerang_bigfield, test_graph_description_sqr_function) { * 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) { +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 }); + 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); @@ -337,7 +360,8 @@ TEST(boomerang_bigfield, test_graph_description_madd_function) { * 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) { +TEST(boomerang_bigfield, test_graph_description_mult_madd_function) +{ auto builder = Builder(); size_t num_repetitions = 1; @@ -361,8 +385,7 @@ TEST(boomerang_bigfield, test_graph_description_mult_madd_function) { 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])))); + 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); @@ -370,7 +393,7 @@ TEST(boomerang_bigfield, test_graph_description_mult_madd_function) { 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); + EXPECT_EQ(variables_in_one_gate.size(), 0); } /** @@ -383,9 +406,11 @@ 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 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); @@ -394,4 +419,3 @@ TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits) 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_dynamic_array.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_dynamic_array.test.cpp index 3fba4f8b37d..a8767b90397 100644 --- 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 @@ -48,7 +48,6 @@ TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_method_resi 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, @@ -60,7 +59,7 @@ TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_method_resi * - 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) +TEST(boomerang_stdlib_dynamic_array, graph_description_dynamic_array_consistency_methods) { Builder builder; const size_t max_size = 10; 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 index 2fd690d4f32..0f3b2a23258 100644 --- 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 @@ -5,7 +5,6 @@ #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" @@ -29,6 +28,11 @@ using byte_array_ct = _curve::byte_array_ct; using fr_ct = typename _curve::ScalarField; using witness_ct = typename _curve::witness_ct; +/** + static analyzer usually prints input and output variables as variables in one gate. In these tests output variables + are not dangerous we can filter them by checking that difference beetween their witness indexes and witness index + of result <= 3 + */ bool check_in_input_vector(const std::vector& input_vector, const uint32_t& real_var_index) { @@ -54,16 +58,18 @@ void test_poseidon2s_circuit(size_t num_inputs = 5) inputs.emplace_back(field_t(witness_t(&builder, element))); } - for (auto& elem: inputs) { + for (auto& elem : inputs) { elem.fix_witness(); } - [[maybe_unused]]auto result = stdlib::poseidon2::hash(builder, inputs); + [[maybe_unused]] auto result = stdlib::poseidon2::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 outputs{result.witness_index, result.witness_index + 1, result.witness_index + 2, result.witness_index + 3}; - for (const auto& elem: variables_in_one_gate) { + std::unordered_set 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); } } @@ -72,7 +78,7 @@ void test_poseidon2s_circuit(size_t num_inputs = 5) * @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) +void test_poseidon2s_hash_byte_array(size_t num_inputs = 5) { Builder builder; @@ -88,8 +94,10 @@ void test_poseidon2s_hash_byte_array(size_t num_inputs = 5) 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 outputs{result.witness_index, result.witness_index + 1, result.witness_index + 2, result.witness_index + 3}; - for (const auto& elem: variables_in_one_gate) { + std::unordered_set 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); } } @@ -99,7 +107,7 @@ void test_poseidon2s_hash_byte_array(size_t num_inputs = 5) * 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) +void test_poseidon2s_hash_repeated_pairs(size_t num_inputs = 5) { Builder builder; @@ -109,13 +117,13 @@ void test_poseidon2s_hash_repeated_pairs(size_t num_inputs = 5) fr_ct left = witness_ct(&builder, left_in); fr_ct right = witness_ct(&builder, right_in); right.fix_witness(); - std::unordered_set outputs{left.witness_index}; + std::unordered_set 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::hash(builder, { left, right }); outputs.insert(left.witness_index + 1); outputs.insert(left.witness_index + 2); - outputs.insert(left.witness_index + 3); + outputs.insert(left.witness_index + 3); } left.fix_witness(); @@ -123,7 +131,7 @@ void test_poseidon2s_hash_repeated_pairs(size_t num_inputs = 5) 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) { + for (const auto& elem : variables_in_one_gate) { EXPECT_EQ(outputs.contains(elem), true); } } @@ -145,7 +153,7 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_one_permutation) auto poseidon2permutation = Permutation(); [[maybe_unused]] auto new_state = poseidon2permutation.permutation(&builder, inputs); - for (auto& elem: new_state) { + for (auto& elem : new_state) { elem.fix_witness(); } @@ -178,10 +186,10 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_two_permutations) auto poseidon2permutation = Permutation(); [[maybe_unused]] auto state1 = poseidon2permutation.permutation(&builder, input1); [[maybe_unused]] auto state2 = poseidon2permutation.permutation(&builder, input2); - for (auto& elem: state1) { + for (auto& elem : state1) { elem.fix_witness(); } - for (auto& elem: state2) { + for (auto& elem : state2) { elem.fix_witness(); } auto graph = Graph(builder); @@ -203,8 +211,9 @@ 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(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); } } @@ -212,4 +221,4 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_hash_byte_array) { 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 index 9bb96666f81..4a856a9c918 100644 --- 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 @@ -30,7 +30,7 @@ TEST(boomerang_rom_ram_table, graph_description_rom_table) 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) { + for (auto& elem : table_values) { elem.fix_witness(); } @@ -51,9 +51,9 @@ TEST(boomerang_rom_ram_table, graph_description_rom_table) 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) { + for (const auto& elem : variables_in_one_gate) { EXPECT_EQ(variables_in_one_gate.contains(elem), true); - } + } } /** @@ -71,7 +71,7 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_read) table_values.emplace_back(witness_ct(&builder, bb::fr::random_element())); } - for (auto& elem: table_values) { + for (auto& elem : table_values) { elem.fix_witness(); } @@ -91,7 +91,7 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_read) 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) { + for (const auto& elem : variables_in_one_gate) { EXPECT_EQ(safety_variables.contains(elem), true); } } @@ -160,7 +160,7 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_write) 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) { + 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 4f641447c71..866c12aa7cb 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 @@ -21,20 +21,28 @@ using byte_array_pt = byte_array; using packed_byte_array_pt = packed_byte_array; using field_pt = field_t; -void fix_vector(std::vector& vector) { - for (auto& elem: vector) { +/** + static analyzer usually prints input and output variables as variables in one gate. In tests these variables + are not dangerous and usually we can filter them by adding gate for fixing witness. Then these variables will be + in 2 gates, and static analyzer won't print them. functions fix_vector and fix_byte_array do it + for vector of variables and packed_byte_array respectively +*/ + +void fix_vector(std::vector& vector) +{ + for (auto& elem : vector) { elem.fix_witness(); } } -void fix_byte_array(packed_byte_array_pt& input) { +void fix_byte_array(packed_byte_array_pt& input) +{ std::vector limbs = input.get_limbs(); fix_vector(limbs); } - /** - all these tests check graph description for sha256 circuits. All circuits have to consist from 1 connected component + all these tests check graph description for sha256 circuits. All circuits have to consist of 1 connected component */ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_55_bytes) @@ -56,7 +64,7 @@ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_55_bytes) 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) { + for (const auto& elem : variables_in_one_gate) { info("elem == ", elem); } } @@ -81,13 +89,11 @@ HEAVY_TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_five) fix_byte_array(input); packed_byte_array_pt output_bits = stdlib::sha256(input); - + std::vector 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); @@ -152,4 +158,4 @@ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_four) EXPECT_EQ(connected_components.size(), 1); std::unordered_set 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 +} From fd4dd1cbb9fe95c0fdd12642c3d817b360e08d21 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Thu, 27 Feb 2025 18:27:18 +0000 Subject: [PATCH 25/27] Automatic doc rewriting --- .../graph_description_aes128.test.cpp | 32 ++++++---- .../graph_description_blake2s.test.cpp | 49 ++++++++------- .../graph_description_blake3s.test.cpp | 18 +++++- ...escription_poseidon2s_permutation.test.cpp | 59 ++++++++++++++----- .../graph_description_ram_rom.test.cpp | 34 +++++++---- .../graph_description_sha256.test.cpp | 48 ++++++++++++++- 6 files changed, 177 insertions(+), 63 deletions(-) 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 c968fa5a065..de25c3fe690 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 @@ -19,11 +19,14 @@ using field_pt = stdlib::field_t; using witness_pt = stdlib::witness_t; /** - static analyzer usually prints input and output variables as variables in one gate. In tests these variables - are not dangerous and usually we can filter them by adding gate for fixing witness. Then these variables will be - in 2 gates, and static analyzer won't print them. functions fix_vector_witness doest it for vector in_field + * @brief Fix witness values in a vector to ensure they appear in multiple gates + * + * Static analyzer typically identifies variables in only one gate. For test input/output variables, + * we can filter them by fixing their witness values, which adds them to a second gate + * and prevents them from being flagged as potentially dangerous. + * + * @param input_vector Vector of field elements to fix */ - void fix_vector_witness(std::vector& input_vector) { for (auto& elem : input_vector) { @@ -32,10 +35,12 @@ void fix_vector_witness(std::vector& input_vector) } /** - * @brief this test checks graph description of circuit for AES128CBC - * graph must be consist from one connected component + * @brief Test graph description of AES128CBC circuit with 64 bytes of data + * + * @details This test verifies that: + * - The graph consists of one connected component + * - No variables are in only one gate */ - TEST(boomerang_stdlib_aes, test_graph_for_aes_64_bytes) { uint8_t key[16]{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; @@ -81,14 +86,17 @@ TEST(boomerang_stdlib_aes, test_graph_for_aes_64_bytes) } /** - * @brief this test checks variables gate counts for variables in circuit for AES128CBC - * Some variables can be from input/output vectors, or they are key and iv, and they have variable - * gates count = 1, because it's the circuit for test. So, we can ignore these variables + * @brief Test variable gate counts for AES128CBC circuit + * + * @details This test verifies that: + * - The graph consists of one connected component + * - No variables appear in only one gate + * + * Note: Input/output vectors, key, and IV variables might normally appear in only one gate, + * but we fix their witness values to ensure they appear in multiple gates. */ - TEST(boomerang_stdlib_aes, test_variable_gates_count_for_aes128cbc) { - uint8_t key[16]{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; uint8_t iv[16]{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; uint8_t in[64]{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 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 c2d41f1d60c..b25381f4ab7 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 @@ -1,38 +1,38 @@ +#include "barretenberg/boomerang_value_detection/graph.hpp" #include "barretenberg/circuit_checker/circuit_checker.hpp" +#include "barretenberg/common/test.hpp" #include "barretenberg/crypto/blake2s/blake2s.hpp" +#include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/stdlib/hash/blake2s/blake2s.hpp" #include "barretenberg/stdlib/hash/blake2s/blake2s_plookup.hpp" #include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp" +#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" #include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" -#include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" -#include "graph.hpp" -#include using namespace bb; -using namespace bb::stdlib; using namespace cdg; - using Builder = UltraCircuitBuilder; - -using field_ct = field_t; -using witness_ct = witness_t; -using byte_array_ct = byte_array; -using byte_array_plookup = byte_array; -using public_witness_t = public_witness_t; +using field_ct = stdlib::field_t; +using witness_ct = stdlib::witness_t; +using byte_array_ct = stdlib::byte_array; +using public_witness_t = stdlib::public_witness_t; /** - * @brief this tests check graph description of circuit for blake2s for one and two blocks. - * all graphs must have one connected component and 0 variables in one gate. + * @brief Test graph description for Blake2s hash with single block input + * + * @details This test verifies that: + * - The graph has one connected component + * - No variables are in one gate + * - The plookup implementation correctly processes a single block input */ - -TEST(boomerang_stdlib_blake2s, test_graph_for_blake2s_single_block_plookup) +TEST(boomerang_stdlib_blake2s, graph_description_single_block_plookup) { Builder builder; std::string input = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01"; std::vector input_v(input.begin(), input.end()); - byte_array_plookup input_arr(&builder, input_v); - byte_array_plookup output = blake2s(input_arr); + byte_array_ct input_arr(&builder, input_v); + byte_array_ct output = stdlib::blake2s(input_arr); Graph graph = Graph(builder); auto connected_components = graph.find_connected_components(); @@ -41,14 +41,23 @@ TEST(boomerang_stdlib_blake2s, test_graph_for_blake2s_single_block_plookup) EXPECT_EQ(variables_in_one_gate.size(), 0); } -TEST(boomerang_stdlib_blake2s, test_graph_for_blake2s_double_block_plookup) +/** + * @brief Test graph description for Blake2s hash with double block input + * + * @details This test verifies that: + * - The graph has one connected component + * - No variables are in one gate + * - The plookup implementation correctly processes a multi-block input + * - The output matches the expected cryptographic hash + */ +TEST(boomerang_stdlib_blake2s, graph_description_double_block_plookup) { Builder builder; std::string input = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789"; std::vector input_v(input.begin(), input.end()); - byte_array_plookup input_arr(&builder, input_v); - byte_array_plookup output = blake2s(input_arr); + byte_array_ct input_arr(&builder, input_v); + byte_array_ct output = stdlib::blake2s(input_arr); auto expected = crypto::blake2s(input_v); 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 c79604f4fe5..940a33951a2 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 @@ -18,10 +18,18 @@ using public_witness_t_plookup = stdlib::public_witness_t& input_vector, const uint32_t& real_var_index) { for (const auto& elem : input_vector) { @@ -45,8 +51,11 @@ bool check_in_input_vector(const std::vector& input_vector, const uint3 } /** - * @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 + * @brief Test graph description for poseidon2 hash with random inputs + * + * The result should be one connected component, and only output variables must be in one gate + * + * @param num_inputs Number of random inputs to generate */ void test_poseidon2s_circuit(size_t num_inputs = 5) { @@ -75,8 +84,11 @@ void test_poseidon2s_circuit(size_t num_inputs = 5) } /** - * @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 + * @brief Test graph description for poseidon2 hash with byte array input + * + * The result should be one connected component, and only output variables must be in one gate + * + * @param num_inputs Number of random bytes to generate */ void test_poseidon2s_hash_byte_array(size_t num_inputs = 5) { @@ -103,9 +115,12 @@ void test_poseidon2s_hash_byte_array(size_t num_inputs = 5) } /** - * @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 + * @brief Test graph description for repeated poseidon2 hash operations + * + * The result should be one connected component with repeated hashing of pairs, + * only output variables from each hash operation must be in one gate + * + * @param num_inputs Number of hash iterations to perform */ void test_poseidon2s_hash_repeated_pairs(size_t num_inputs = 5) { @@ -137,8 +152,9 @@ void test_poseidon2s_hash_repeated_pairs(size_t num_inputs = 5) } /** - * @brief this test checks graph description for a single poseidon2 permutation - * The result is one connected component with no variables in one gate, + * @brief Test graph description for a single poseidon2 permutation + * + * The result should be 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) @@ -165,8 +181,9 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_one_permutation) } /** - * @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, + * @brief Test graph description for two separate poseidon2 permutations + * + * The result should be 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) @@ -199,6 +216,9 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_two_permutations) EXPECT_EQ(variables_in_one_gate.size(), 0); } +/** + * @brief Test graph for poseidon2s with varying input sizes + */ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s) { for (size_t num_inputs = 6; num_inputs < 100; num_inputs++) { @@ -206,11 +226,17 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s) } } +/** + * @brief Test graph for poseidon2s with default input size + */ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_for_one_input_size) { test_poseidon2s_circuit(); } +/** + * @brief Test graph for poseidon2s hash with byte arrays of varying sizes + */ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_hash_byte_array) { for (size_t num_inputs = 6; num_inputs < 100; num_inputs++) { @@ -218,6 +244,9 @@ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_hash_byte_array) } } +/** + * @brief Test graph for poseidon2s with repeated hash operations + */ TEST(boomerang_poseidon2s, test_graph_for_poseidon2s_hash_repeated_pairs) { test_poseidon2s_hash_repeated_pairs(); 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 index 4a856a9c918..1abdb9cc74b 100644 --- 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 @@ -17,9 +17,11 @@ using rom_table_ct = stdlib::rom_table; using ram_table_ct = stdlib::ram_table; /** - * @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 + * @brief Test graph description for ROM table operations + * + * @details This test verifies that: + * - Reading random values at sequential indices creates one connected component + * - No variables are in one gate due to connections through table accesses */ TEST(boomerang_rom_ram_table, graph_description_rom_table) { @@ -57,9 +59,11 @@ TEST(boomerang_rom_ram_table, graph_description_rom_table) } /** - * @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 + * @brief Test graph description for RAM table read operations + * + * @details This test verifies that: + * - Reading random values at sequential indices creates one connected component + * - No variables are in one gate due to connections through table reads */ TEST(boomerang_rom_ram_table, graph_description_ram_table_read) { @@ -97,13 +101,17 @@ TEST(boomerang_rom_ram_table, graph_description_ram_table_read) } /** - * @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 + * @brief Test graph description for RAM table write and read operations + * + * @details This test verifies that: + * - Alternating write and read operations create one connected component + * - Non-sequential access patterns work correctly + * - No variables are in one gate + * + * The test includes: + * - Initial zero initialization + * - Multiple update-read cycles + * - Non-sequential read access pattern */ TEST(boomerang_rom_ram_table, graph_description_ram_table_write) { 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 866c12aa7cb..3a534e6aefa 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 @@ -42,7 +42,12 @@ void fix_byte_array(packed_byte_array_pt& input) } /** - all these tests check graph description for sha256 circuits. All circuits have to consist of 1 connected component + * @brief Test for SHA256 circuit graph analysis + * + * These tests verify that SHA256 circuits have the expected graph structure: + * - Each circuit should consist of exactly 1 connected component + * - Each variable should appear in multiple gates after witness fixing + * The test mirrors the test in stdlib. */ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_55_bytes) @@ -70,6 +75,19 @@ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_55_bytes) } } +/** + * @brief Test SHA256 circuit graph analysis with NIST test vector 5 + * + * This test verifies the graph structure of a SHA256 circuit when processing + * a large input of 1000 repeated 'A' characters (NIST test vector 5). + * + * The test checks that: + * - The circuit consists of exactly 1 connected component + * - No variables appear in only one gate after witness fixing + * + * This is marked as a HEAVY_TEST due to the large input size requiring + * significant computation. + */ HEAVY_TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_five) { auto builder = Builder(); @@ -100,6 +118,16 @@ HEAVY_TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_five) EXPECT_EQ(connected_components.size(), 1); } +/** + * @brief Test SHA256 circuit graph analysis with NIST test vector 1 + * + * This test verifies the graph structure of a SHA256 circuit when processing + * the input string "abc" (NIST test vector 1). + * + * The test checks that: + * - The circuit consists of exactly 1 connected component + * - No variables appear in only one gate after witness fixing + */ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_one) { auto builder = Builder(); @@ -114,6 +142,12 @@ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_one) EXPECT_EQ(variables_in_one_gate.size(), 0); } +/** + * @brief Test SHA256 circuit graph analysis with NIST test vector 2 + * + * This test verifies the graph structure of a SHA256 circuit when processing + * the input string "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" (NIST test vector 2). + */ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_two) { auto builder = Builder(); @@ -128,6 +162,12 @@ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_two) EXPECT_EQ(variables_in_one_gate.size(), 0); } +/** + * @brief Test SHA256 circuit graph analysis with NIST test vector 3 + * + * This test verifies the graph structure of a SHA256 circuit when processing + * the input byte 0xbd + */ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_three) { auto builder = Builder(); @@ -144,6 +184,12 @@ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_three) EXPECT_EQ(variables_in_one_gate.size(), 0); } +/** + * @brief Test SHA256 circuit graph analysis with NIST test vector 4 + * + * This test verifies the graph structure of a SHA256 circuit when processing + * 4 bytes "c98c8e55" (NIST test vector 4). + */ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_NIST_vector_four) { auto builder = Builder(); From 648d19e3eb0e33e1b6bd2fbf2d8fc4e729744458 Mon Sep 17 00:00:00 2001 From: DanielKotov Date: Fri, 28 Feb 2025 10:58:41 +0000 Subject: [PATCH 26/27] =?UTF-8?q?=D1=81orrection=20of=20Kesha's=20remarks?= =?UTF-8?q?=20in=20tests=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../graph_description.test.cpp | 3 +- .../graph_description_bigfield.test.cpp | 127 ++++++++---------- .../graph_description_sha256.test.cpp | 5 - 3 files changed, 58 insertions(+), 77 deletions(-) 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 ddbaf31b4c2..05b236b9eed 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 @@ -38,7 +38,8 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_arithmetic_gates) Graph graph = Graph(circuit_constructor); auto connected_components = graph.find_connected_components(); - [[maybe_unused]] auto variables_in_one_gate = graph.show_variables_in_one_gate(circuit_constructor); + auto variables_in_one_gate = graph.show_variables_in_one_gate(circuit_constructor); + EXPECT_EQ(variables_in_one_gate.size(), 1024); EXPECT_EQ(connected_components.size(), 256); } 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 index 6712b6fcd33..6c621819c56 100644 --- 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 @@ -197,6 +197,8 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_division) * @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 + * @details Each division operator creates one inverse variable for polynomial gate check (a * a_inv - 1 = 0) + * except for division constant / constant, so size of the variables_in_one_gate = 2. */ TEST(boomerang_bigfield, test_graph_description_bigfield_mix_operations) { @@ -252,19 +254,16 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_mix_operations) 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; - } + 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(); @@ -281,22 +280,18 @@ TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits_and_op 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); - } + 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); + 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); } @@ -309,17 +304,14 @@ TEST(boomerang_bigfield, test_graph_description_mul_function) 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); - } + 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); + 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); } @@ -332,24 +324,21 @@ TEST(boomerang_bigfield, test_graph_description_sqr_function) 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); - } + 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)))); + 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); + 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); } @@ -362,34 +351,30 @@ TEST(boomerang_bigfield, test_graph_description_madd_function) */ 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 mul_left; - std::vector mul_right; - std::vector 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); + fq mul_left_values[number_of_madds]; + fq mul_right_values[number_of_madds]; + fq to_add_values[number_of_madds]; + + std::vector mul_left; + std::vector mul_right; + std::vector 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); 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 3a534e6aefa..2d8a2f264ef 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 @@ -68,11 +68,6 @@ TEST(boomerang_stdlib_sha256, test_graph_for_sha256_55_bytes) 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); - } - } } /** From 73c6062e1217546cf0612772e86b6e49d40ddd46 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Wed, 5 Mar 2025 18:30:13 +0000 Subject: [PATCH 27/27] More fixes --- .../boomerang_value_detection/graph.cpp | 171 +++++++++--------- .../boomerang_value_detection/graph.hpp | 47 +++-- .../graph_description.test.cpp | 158 ++++++++++------ .../graph_description_bigfield.test.cpp | 147 ++++++++------- 4 files changed, 294 insertions(+), 229 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 0f2098c3372..34b6c183782 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -83,64 +83,68 @@ inline std::vector> Graph_::get_arithmetic_gate_connec std::vector gate_variables; std::vector minigate_variables; std::vector> 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); - } - if (q_1 != 0) { + if (q_arith.is_zero()) { + return {}; + } + 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.is_zero() && q_1 == 1 && q_2.is_zero() && q_3.is_zero() && q_4.is_zero() && q_arith == FF::one()) { + // 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.is_zero() || q_1 != FF::one() || !q_2.is_zero() || !q_3.is_zero() || !q_4.is_zero()) { + // this is not the gate for fix_witness, so we have to process this gate + if (!q_m.is_zero()) { + gate_variables.emplace_back(left_idx); + gate_variables.emplace_back(right_idx); + } else { + if (!q_1.is_zero()) { gate_variables.emplace_back(left_idx); } - if (q_2 != 0) { + if (!q_2.is_zero()) { gate_variables.emplace_back(right_idx); } - if (q_3 != 0) { - gate_variables.emplace_back(out_idx); - } - if (q_4 != 0) { - gate_variables.emplace_back(fourth_idx); - } - 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 != blk.size() - 1) { - gate_variables.emplace_back(blk.w_4()[index + 1]); - } - } - 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]); - } + } + + if (!q_3.is_zero()) { + gate_variables.emplace_back(out_idx); + } + if (!q_4.is_zero()) { + gate_variables.emplace_back(fourth_idx); + } + if (q_arith == FF(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 != blk.size() - 1) { + gate_variables.emplace_back(blk.w_4()[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); + if (q_arith == FF(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); + } + return all_gates_variables; } @@ -161,8 +165,8 @@ inline std::vector Graph_::get_elliptic_gate_connected_component( { std::vector gate_variables = {}; 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; + bool is_elliptic_add_gate = !blk.q_1()[index].is_zero() && blk.q_m()[index].is_zero(); + bool is_elliptic_dbl_gate = blk.q_1()[index].is_zero() && blk.q_m()[index] == FF::one(); auto right_idx = blk.w_r()[index]; auto out_idx = blk.w_o()[index]; gate_variables.emplace_back(right_idx); @@ -241,16 +245,14 @@ inline std::vector Graph_::get_plookup_gate_connected_component( 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_2.is_zero()) { + gate_variables.emplace_back(block.w_l()[index + 1]); + } + if (!q_m.is_zero()) { + gate_variables.emplace_back(block.w_r()[index + 1]); + } + if (!q_c.is_zero()) { + gate_variables.emplace_back(block.w_o()[index + 1]); } } this->process_gate_variables(ultra_circuit_builder, gate_variables, index, blk_idx); @@ -317,14 +319,14 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( 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) { + if (q_3 == FF::one() && q_4 == FF::one()) { // 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) { + } else if (q_3 == FF::one() && q_m == FF::one()) { ASSERT(q_arith.is_zero()); // bigfield limb accumulation 2 if (index < block.size() - 1) { @@ -336,21 +338,21 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( block.w_o()[index + 1], block.w_4()[index + 1] }); } - } else if (q_2 == 1 && (q_3 == 1 || q_4 == 1 || q_m == 1)) { + } else if (q_2 == FF::one() && (q_3 == FF::one() || q_4 == FF::one() || q_m == FF::one())) { ASSERT(q_arith.is_zero()); // bigfield product cases if (index < block.size() - 1) { std::vector limb_subproduct_vars = { w_l, w_r, block.w_l()[index + 1], block.w_r()[index + 1] }; - if (q_3 == 1) { + if (q_3 == FF::one()) { // 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) { + if (q_4 == FF::one()) { // bigfield product 2 ASSERT(q_3.is_zero() && q_m.is_zero()); std::vector non_native_field_gate_2 = { w_l, w_4, w_r, w_o, block.w_o()[index + 1] }; @@ -360,7 +362,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( gate_variables.insert( gate_variables.end(), limb_subproduct_vars.begin(), limb_subproduct_vars.end()); } - if (q_m == 1) { + if (q_m == FF::one()) { // bigfield product 3 ASSERT(q_4.is_zero() && q_3.is_zero()); gate_variables.insert( @@ -369,7 +371,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( { w_4, block.w_o()[index + 1], block.w_4()[index + 1] }); } } - } else if (q_1 == 1 && q_4 == 1) { + } else if (q_1 == FF::one() && q_4 == FF::one()) { ASSERT(q_arith.is_zero()); // ram timestamp check if (index < block.size() - 1) { @@ -380,7 +382,7 @@ inline std::vector Graph_::get_auxiliary_gate_connected_component( block.w_l()[index + 1], block.w_o()[index] }); } - } else if (q_1 == 1 && q_2 == 1) { + } else if (q_1 == FF::one() && q_2 == FF::one()) { ASSERT(q_arith.is_zero()); // rom constitency check if (index < block.size() - 1) { @@ -444,7 +446,8 @@ inline std::vector Graph_::get_rom_table_connected_component( 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) { + if (q_1 == FF::one() && q_m == FF::one() && q_2.is_zero() && q_3.is_zero() && q_4.is_zero() && q_c.is_zero() && + q_arith.is_zero()) { // 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); @@ -497,7 +500,8 @@ inline std::vector Graph_::get_ram_table_connected_component( 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)) { + if (q_1 == FF::one() && q_m == FF::one() && q_2.is_zero() && q_3.is_zero() && q_4.is_zero() && + q_arith.is_zero() && (q_c.is_zero() || q_c == FF::one())) { // 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); @@ -566,22 +570,18 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit } auto elliptic_gate_variables = get_elliptic_gate_connected_component( ultra_circuit_constructor, gate_idx, blk_idx, block_data[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, block_data[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, block_data[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, block_data[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() && @@ -605,20 +605,20 @@ template Graph_::Graph_(bb::UltraCircuitBuilder& ultra_circuit } const auto& rom_arrays = ultra_circuit_constructor.rom_arrays; - if (rom_arrays.size() > 0) { - for (size_t i = 0; i < rom_arrays.size(); i++) { + if (!rom_arrays.empty()) { + for (const auto& rom_array : rom_arrays) { std::vector variable_indices = - this->get_rom_table_connected_component(ultra_circuit_constructor, rom_arrays[i]); + this->get_rom_table_connected_component(ultra_circuit_constructor, rom_array); 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++) { + if (!ram_arrays.empty()) { + for (const auto& ram_array : ram_arrays) { std::vector variable_indices = - this->get_ram_table_connected_component(ultra_circuit_constructor, ram_arrays[i]); + this->get_ram_table_connected_component(ultra_circuit_constructor, ram_array); this->connect_all_variables_in_vector( ultra_circuit_constructor, variable_indices, /*is_sorted_variables=*/false); } @@ -951,7 +951,7 @@ inline void Graph_::remove_unnecessary_aes_plookup_variables(std::unordered_ if (variables_gate_counts[real_out_idx] != 1 || variables_gate_counts[real_right_idx] != 1) { bool find_out = find_position(real_out_idx); auto q_c = lookup_block.q_c()[gate_index]; - if (q_c == 0) { + if (q_c.is_zero()) { if (find_out) { variables_in_one_gate.erase(real_out_idx); } @@ -1003,7 +1003,7 @@ inline void Graph_::remove_unnecessary_sha256_plookup_variables(std::unorder auto q_c = lookup_block.q_c()[gate_index]; bool find_out = find_position(real_out_idx); // bool find_right = find_position(real_right_idx); - if (q_c == 0) { + if (q_c.is_zero()) { if (find_out) { variables_in_one_gate.erase(real_out_idx); } @@ -1123,7 +1123,8 @@ template inline void Graph_::remove_record_witness_variables(b auto q_4 = block_data[blk_idx].q_4()[gate_idx]; auto q_m = block_data[blk_idx].q_m()[gate_idx]; auto q_arith = block_data[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) { + if (q_1 == FF::one() && q_m == FF::one() && q_2.is_zero() && q_3.is_zero() && q_4.is_zero() && + q_arith.is_zero()) { // 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 diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp index 414a25b4da6..a15bc0566f0 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.hpp @@ -9,35 +9,34 @@ #include #include -/* - * this class describes arithmetic circuit as an undirected graph, where vertices are variables from circuit. - * edges describe connections between variables through gates. We want to find variables that weren't properly - * constrainted/some connections were missed using additional metrics, like in how much gate variable was and number of - * connected components in the graph. if variable was in one connected component, it means that this variable wasn't - * 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, 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::UltraTraceBlock; +/** + * We've added a new feature to the static analyzer that tracks which gates contain each variable. + * This is helpful for removing false-positive variables from the analyzer by using gate selectors + * combined with additional knowledge about variables (e.g., tau or range tags). + * + * This information is stored in an unordered map with keys of type std::pair, where: + * - uint32_t represents the real variable index + * - size_t represents the index of the UltraTraceBlock in the reference array of TraceBlocks + * contained within the Ultra Circuit Builder + * + * Since std::unordered_map doesn't provide default hash and equality functions for std::pair keys, + * we've implemented these ourselves. Our approach is based on the hash_combine function from the + * Boost library, which efficiently combines hashes of the two elements in the pair. + */ using KeyPair = std::pair; 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)); }; + // Golden ratio constant (2^32 / phi) used in hash combining for better distribution + constexpr size_t HASH_COMBINE_CONSTANT = 0x9e3779b9; + auto hash_combiner = [](size_t lhs, size_t rhs) { + return lhs ^ (rhs + HASH_COMBINE_CONSTANT + (lhs << 6) + (lhs >> 2)); + }; combined_hash = hash_combiner(combined_hash, std::hash()(pair.first)); combined_hash = hash_combiner(combined_hash, std::hash()(pair.second)); return combined_hash; @@ -51,6 +50,14 @@ struct KeyEquals { } }; +/* + * This class describes an arithmetic circuit as an undirected graph, where vertices are variables from the circuit. + * Edges describe connections between variables through gates. We want to find variables that weren't properly + * constrained or where some connections were missed using additional metrics, such as how many gates a variable appears + * in and the number of connected components in the graph. If a variable appears in only one gate, it means that this + * variable wasn't constrained properly. If the number of connected components > 1, it means that there were some missed + * connections between variables. + */ template class Graph_ { public: Graph_() = default; 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 05b236b9eed..e2234cae86d 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 @@ -12,11 +12,14 @@ 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 + * @brief Test graph description of circuit with arithmetic gates + * + * @details This test verifies that: + * - The number of connected components equals the number of pairs (i,j), where 0<=i,j<16 + * - Each pair creates an isolated component, resulting in 256 total components */ - TEST(boomerang_ultra_circuit_constructor, test_graph_for_arithmetic_gates) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); @@ -44,10 +47,12 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_arithmetic_gates) } /** - * @brief This test checks graph description of Ultra Circuit Builder with arithmetic gates with shifts - * It must be one connected component, cause all gates have shifts + * @brief Test graph description of Ultra Circuit Builder with arithmetic gates with shifts + * + * @details This test verifies that: + * - When all gates have shifts, they form a single connected component + * - The shift operation connects all variables in the circuit */ - TEST(boomerang_ultra_circuit_constructor, test_graph_for_arithmetic_gates_with_shifts) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); @@ -74,10 +79,13 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_arithmetic_gates_with_s } /** - * @brief this test checks graph description of the circuit with boolean gates. - all variables must be isolated and the number of connected components = 0, all variables in one gate + * @brief Test graph description of circuit with boolean gates + * + * @details This test verifies that: + * - All variables are isolated with boolean gates + * - The number of connected components is 0 + * - All variables are in one gate */ - TEST(boomerang_ultra_circuit_constructor, test_graph_for_boolean_gates) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); @@ -98,11 +106,13 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_boolean_gates) } /** - * @brief this test checks graph decription for the circuit with one elliptic addition gate. - * The result is one connected component for 6 variables: - * x1, y1, x2, y2, x3, y3 + * @brief Test graph description for circuit with one elliptic addition gate + * + * @details This test verifies that: + * - The circuit forms one connected component containing 6 variables + * - The variables represent the coordinates of three points: (x1,y1), (x2,y2), (x3,y3) + * - Where (x3,y3) is the result of adding (x1,y1) and (x2,y2) */ - TEST(boomerang_ultra_circuit_constructor, test_graph_for_elliptic_add_gate) { typedef grumpkin::g1::affine_element affine_element; @@ -131,11 +141,13 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_elliptic_add_gate) } /** - * @brief this test checks graph description of the circuit with one elliptic double gate. - The result is one connected component for 4 variables: - x1, y1, x3, y3 + * @brief Test graph description for circuit with one elliptic double gate + * + * @details This test verifies that: + * - The circuit forms one connected component containing 4 variables + * - The variables represent the coordinates of two points: (x1,y1) and (x3,y3) + * - Where (x3,y3) is the result of doubling (x1,y1) */ - TEST(boomerang_ultra_circuit_constructor, test_graph_for_elliptic_double_gate) { typedef grumpkin::g1::affine_element affine_element; @@ -160,12 +172,14 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_elliptic_double_gate) } /** - * @brief this test checks the graph description of the circuit has elliptic addition and multiplication - gates together. The result is 2 connected components: - x1, y1, x2, y2, x3, y3, x4, y4 - x5, y5, x6, y6, x7, y7, x8, y8 + * @brief Test graph description for circuit with elliptic addition and multiplication gates + * + * @details This test verifies that: + * - The circuit forms 2 connected components + * - First component contains: x1, y1, x2, y2, x3, y3, x4, y4 + * - Second component contains: x5, y5, x6, y6, x7, y7, x8, y8 + * - Each component represents a separate elliptic curve operation sequence */ - TEST(boomerang_ultra_circuit_constructor, test_graph_for_elliptic_together) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); @@ -215,11 +229,14 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_elliptic_together) } /** - * @brief this test check graph description of the circuit with 2 sort_constraint. The result is 2 connected components: - a_idx, b_idx, c_idx, d_idx - e_idx, f_idx, g_idx, h_idx + * @brief Test graph description for circuit with 2 sort constraints + * + * @details This test verifies that: + * - The circuit forms 2 connected components + * - First component contains: a_idx, b_idx, c_idx, d_idx + * - Second component contains: e_idx, f_idx, g_idx, h_idx + * - Each sort constraint creates its own connected component */ - TEST(boomerang_ultra_circuit_constructor, test_graph_for_sort_constraints) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); @@ -252,12 +269,14 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_sort_constraints) } /** - * @brief this test checks graph description of the circuit with 2 sorted_constraints with edges. - The result is 2 connected components: - a_idx, b_idx, ... , h_idx - a1_idx, b1_idx, ..., h1_idx + * @brief Test graph description for circuit with 2 sorted constraints with edges + * + * @details This test verifies that: + * - The circuit forms 2 connected components + * - First component contains: a_idx through h_idx + * - Second component contains: a1_idx through h1_idx + * - Each sort constraint with edges creates its own connected component */ - TEST(boomerang_ultra_circuit_constructor, test_graph_for_sort_constraints_with_edges) { fr a = fr::one(); @@ -309,10 +328,12 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_sort_constraints_with_e } /** - * @brief this test checks graph decription for circuit with gates that were created from plookup accumulators - the result is one connected component + * @brief Test graph description for circuit with gates created from plookup accumulators + * + * @details This test verifies that: + * - The circuit forms one connected component + * - Plookup accumulator gates connect all variables in the circuit */ - TEST(boomerang_ultra_circuit_constructor, test_graph_with_plookup_accumulators) { UltraCircuitBuilder circuit_builder = UltraCircuitBuilder(); @@ -338,10 +359,12 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_with_plookup_accumulators) } /** - * @brief this test checks variable gates counts for variable from arithmetic gates without shifts - in circuit + * @brief Test variable gate counts for variables from arithmetic gates without shifts + * + * @details This test verifies that: + * - Each variable (except index 0) appears in exactly one gate + * - Variables with index 0 appear in no gates */ - TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_arithmetic_gate) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); @@ -371,11 +394,13 @@ TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_arithm } /** - * @brief this test checks variables gates count for variable in circuit with gates with shifts. - * All variables except for zero index, which index == 0 mod 4 and index != 4 have gates count == 2. - * Other variables have gates count = 1. + * @brief Test variable gate counts for variables in circuit with gates with shifts + * + * @details This test verifies that: + * - Variables with index == 0 mod 4 and index != 4 have gate count == 2 + * - All other variables (except index 0) have gate count == 1 + * - Variables with index 0 have gate count == 0 */ - TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_arithmetic_gate_with_shifts) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); @@ -409,10 +434,12 @@ TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_arithm } /** - * @brief this test checks variables gates count for variables in circuit with boolean gates - * all variables except for zero index must have gates count = 1. + * @brief Test variable gate counts for variables in circuit with boolean gates + * + * @details This test verifies that: + * - All variables (except index 0) have gate count == 1 + * - Variables with index 0 have gate count == 0 */ - TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_boolean_gates) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); @@ -433,10 +460,12 @@ TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_boolea } /** - * @brief this test checks variables gate counts in circuit with sorted constraints. - * all variables in 2 connected components must have gates count = 1 + * @brief Test variable gate counts in circuit with sorted constraints + * + * @details This test verifies that: + * - All variables in both connected components have gate count == 1 + * - Each sort constraint creates a separate component with consistent gate counts */ - TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_sorted_constraints) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); @@ -477,10 +506,12 @@ TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_sorted } /** - * @brief this test checks variable gates count for variables in circuit with sorted constraints with edges - * all variables in 2 connected components must have gates count = 1 + * @brief Test variable gate counts for variables in circuit with sorted constraints with edges + * + * @details This test verifies that: + * - All variables in both connected components have gate count == 1 + * - Each sort constraint with edges creates a separate component with consistent gate counts */ - TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_sorted_constraints_with_edges) { fr a = fr::one(); @@ -540,10 +571,12 @@ TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_sorted } /** - * @brief this test checks variables gates count for variables in circuit with 1 elliptic addition gates - * all variables in connected components must have gates count = 1 + * @brief Test variable gate counts for variables in circuit with elliptic addition gates + * + * @details This test verifies that: + * - All variables in the connected component have gate count == 1 + * - The component contains the 6 variables representing the coordinates of the points */ - TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_ecc_add_gates) { typedef grumpkin::g1::affine_element affine_element; @@ -578,8 +611,11 @@ TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_ecc_ad } /** - * @brief this test checks variables gates count for variables in circuit with 1 elliptic double gates - * all variables in connected components must have gates count = 1. + * @brief Test variable gate counts for variables in circuit with elliptic double gates + * + * @details This test verifies that: + * - All variables in the connected component have gate count == 1 + * - The component contains the 4 variables representing the coordinates of the point */ TEST(boomerang_ultra_circuit_constructor, test_variables_gates_counts_for_ecc_dbl_gate) @@ -621,8 +657,10 @@ std::vector add_variables(UltraCircuitBuilder& circuit_constructor, st } /** - * @brief this test checks graph description of circuit with range constraints. - * all variables must be in one connected component. + * @brief Test graph description of circuit with range constraints + * + * @details This test verifies that: + * - All variables must be in one connected component */ TEST(boomerang_ultra_circuit_constructor, test_graph_for_range_constraints) @@ -639,8 +677,10 @@ TEST(boomerang_ultra_circuit_constructor, test_graph_for_range_constraints) } /** - * @brief this checks graph description of circuit with decompose function. - * all variables must be in one connected component + * @brief Test graph description of circuit with decompose function + * + * @details This test verifies that: + * - All variables must be in one connected component */ TEST(boomerang_ultra_circuit_constructor, composed_range_constraint) 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 index 6c621819c56..2d7b0fca267 100644 --- 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 @@ -31,12 +31,14 @@ using public_witness_ct = bn254::public_witness_ct; using witness_ct = bn254::witness_ct; /** - static analyzer usually prints input and output variables as variables in one gate. In tests these variables - are not dangerous and usually we can filter them by adding gate for fixing witness. Then these variables will be - in 2 gates, and static analyzer won't print them. function fix_bigfield_element does it - for bigfield element + * @brief Fix a bigfield element to prevent it from being identified as a variable in one gate. + * + * Static analyzer usually prints input and output variables as variables in one gate. In tests these variables + * are not dangerous and usually we can filter them by fixing the witness which adds a gate. Then these variables will + * be in 2 gates, and static analyzer won't print them. + * + * @param element The bigfield element to fix */ - void fix_bigfield_element(const fq_ct& element) { for (int i = 0; i < 4; i++) { @@ -46,14 +48,15 @@ void fix_bigfield_element(const fq_ct& element) } /** - * @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 + * @brief Test graph description for bigfield constructors. + * * @details Tests construction of: * - Constant value * - Witness from u512 * - Small field witness * - Mixed construction with lower limb addition + * + * The result is one connected component with one variable in one gate. */ TEST(boomerang_bigfield, test_graph_description_bigfield_constructors) { @@ -72,9 +75,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_constructors) } /** - * @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 + * @brief Test graph description for bigfield addition operations. + * + * @details Tests various addition combinations with fix_bigfield_element. + * + * The result is one connected component with no variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_bigfield_addition) { @@ -101,9 +106,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_addition) } /** - * @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 + * @brief Test graph description for bigfield subtraction operations. + * + * @details Tests all possible subtraction combinations between mixed, constant, and variable values. + * + * The result is one connected component with no variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_bigfield_substraction) { @@ -134,9 +141,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_substraction) } /** - * @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 + * @brief Test graph description for bigfield multiplication operations. + * + * @details Tests all possible multiplication combinations. + * + * The result is one connected component with no variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_bigfield_multiplication) { @@ -160,11 +169,14 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_multiplication) } /** - * @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) + * @brief Test graph description for bigfield division operations. + * + * @details Tests division operations with circuit checking. Each division operator creates + * one inverse variable for polynomial gate check (a * a_inv - 1 = 0). + * + * The result is one connected component with three variables in one gate. */ + TEST(boomerang_bigfield, test_graph_description_bigfield_division) { Builder builder; @@ -194,11 +206,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_division) } /** - * @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 - * @details Each division operator creates one inverse variable for polynomial gate check (a * a_inv - 1 = 0) - * except for division constant / constant, so size of the variables_in_one_gate = 2. + * @brief Test graph description for mixed bigfield operations. + * + * @details Tests combinations of addition, subtraction, multiplication and division operations. + * + * The result is one connected component with two variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_bigfield_mix_operations) { @@ -247,9 +259,11 @@ TEST(boomerang_bigfield, test_graph_description_bigfield_mix_operations) } /** - * @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 + * @brief Test graph description for high/low bits constructor and operations. + * + * @details Tests bit-sliced construction and repeated additions. + * + * The result is one connected component with no variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits_and_operations) { @@ -273,20 +287,20 @@ TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits_and_op } /** - * @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 + * @brief Test graph description for multiple multiplication operations. + * + * @details Tests independent multiplication operations. + * + * The result is num_repetitions connected components with no variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_mul_function) { auto builder = Builder(); 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 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); @@ -297,9 +311,11 @@ TEST(boomerang_bigfield, test_graph_description_mul_function) } /** - * @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 + * @brief Test graph description for square operations. + * + * @details Tests repeated squaring operations on random inputs. + * + * The result is num_repetitions connected components with no variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_sqr_function) { @@ -308,7 +324,7 @@ TEST(boomerang_bigfield, test_graph_description_sqr_function) 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); + fix_bigfield_element(c); auto graph = Graph(builder); auto connected_components = graph.find_connected_components(); EXPECT_EQ(connected_components.size(), 1); @@ -317,23 +333,22 @@ TEST(boomerang_bigfield, test_graph_description_sqr_function) } /** - * @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 + * @brief Test graph description for multiply-add operations. + * + * @details Tests multiply-add operations with three inputs. + * + * The result is num_repetitions connected components with no variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_madd_function) { auto builder = Builder(); 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)))); + 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)))); fq_ct d = a.madd(b, { c }); fix_bigfield_element(d); auto graph = Graph(builder); @@ -344,10 +359,12 @@ TEST(boomerang_bigfield, test_graph_description_madd_function) } /** - * @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 + * @brief Test graph description for multiple multiply-add operations. + * + * @details Tests batch multiply-add operations with multiple inputs. Uses arrays of size + * number_of_madds=16 for left multiply, right multiply and add values. + * + * The result is connected components with no variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_mult_madd_function) { @@ -366,10 +383,8 @@ TEST(boomerang_bigfield, test_graph_description_mult_madd_function) 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])))); + 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])))); } @@ -382,9 +397,11 @@ TEST(boomerang_bigfield, test_graph_description_mult_madd_function) } /** - * @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 + * @brief Test graph description for high/low bits constructor. + * + * @details Tests basic multiplication with bit-sliced construction. + * + * The result is connected components with no variables in one gate. */ TEST(boomerang_bigfield, test_graph_description_constructor_high_low_bits) {