From 7ae9a6b039f961fc43b3e527632b291f31714d43 Mon Sep 17 00:00:00 2001 From: akokoshn Date: Thu, 4 Jan 2024 11:34:36 +0200 Subject: [PATCH] Avoid slow std::set::find() in satifiability check --- .../blueprint/plonk/assignment_proxy.hpp | 5 +- .../blueprint/utils/satisfiability_check.hpp | 218 ++++++++++-------- 2 files changed, 123 insertions(+), 100 deletions(-) diff --git a/include/nil/blueprint/blueprint/plonk/assignment_proxy.hpp b/include/nil/blueprint/blueprint/plonk/assignment_proxy.hpp index f335cb17c..c23a1b28d 100644 --- a/include/nil/blueprint/blueprint/plonk/assignment_proxy.hpp +++ b/include/nil/blueprint/blueprint/plonk/assignment_proxy.hpp @@ -430,15 +430,16 @@ namespace nil { ArithmetizationParams>> &bp, const assignment_proxy> &assignments){ + const auto& used_gates = bp.get_used_gates(); const auto& used_lookup_gates = bp.get_used_lookup_gates(); const auto& used_copy_constraints = bp.get_used_copy_constraints(); - const auto& private_rows = assignments.get_used_selector_rows(); + const auto& selector_rows = assignments.get_used_selector_rows(); - return is_satisfied(bp, assignments, used_gates, used_lookup_gates, used_copy_constraints, private_rows); + return is_satisfied(bp, assignments, used_gates, used_lookup_gates, used_copy_constraints, selector_rows); } } // namespace blueprint } // namespace nil diff --git a/include/nil/blueprint/utils/satisfiability_check.hpp b/include/nil/blueprint/utils/satisfiability_check.hpp index bc6a2ef21..438b9268d 100644 --- a/include/nil/blueprint/utils/satisfiability_check.hpp +++ b/include/nil/blueprint/utils/satisfiability_check.hpp @@ -40,6 +40,36 @@ namespace nil { namespace blueprint { + template + bool is_satisfied( + const circuit> &bp, + const assignment> &assignments) { + std::set used_gates; + for (std::uint32_t i = 0; i < bp.gates().size(); i++) { + used_gates.insert(i); + } + + std::set used_lookup_gates; + for (std::uint32_t i = 0; i < bp.lookup_gates().size(); i++) { + used_lookup_gates.insert(i); + } + + std::set used_copy_constraints; + for (std::uint32_t i = 0; i < bp.copy_constraints().size(); i++) { + used_copy_constraints.insert(i); + } + + std::set selector_rows; + for (std::uint32_t i = 0; i < assignments.allocated_rows(); i++) { + selector_rows.insert(i); + } + + return is_satisfied(bp, assignments, used_gates, used_lookup_gates, used_copy_constraints, selector_rows); + } + template bool is_satisfied( @@ -47,10 +77,10 @@ namespace nil { ArithmetizationParams>> &bp, const assignment> &assignments, - const std::set &used_gates = std::set(), - const std::set &used_lookup_gates = std::set(), - const std::set &used_copy_constraints = std::set(), - const std::set &private_rows = std::set()){ + const std::set &used_gates, + const std::set &used_lookup_gates, + const std::set &used_copy_constraints, + const std::set &selector_rows){ const auto &gates = bp.gates(); @@ -58,120 +88,112 @@ namespace nil { const auto &lookup_gates = bp.lookup_gates(); - for (std::size_t i = 0; i < gates.size(); i++) { - if (used_gates.empty() || used_gates.find(i) != used_gates.end()) { - crypto3::zk::snark::plonk_column selector = - assignments.crypto3::zk::snark:: - template plonk_assignment_table::selector( - gates[i].selector_index); - - for (std::size_t selector_row = 0; selector_row < selector.size(); selector_row++) { - if (!selector[selector_row].is_zero() && - (private_rows.empty() || private_rows.find(selector_row) != private_rows.end())) { - for (std::size_t j = 0; j < gates[i].constraints.size(); j++) { - - typename BlueprintFieldType::value_type constraint_result = - gates[i].constraints[j].evaluate(selector_row, assignments); - - if (!constraint_result.is_zero()) { - std::cout << "Constraint " << j << " from gate " << i << " on row " << selector_row - << " is not satisfied." << std::endl; - std::cout << "Constraint result: " << constraint_result << std::endl; - std::cout << "Offending gate:" << std::endl; - for (const auto &constraint : gates[i].constraints) { - std::cout << constraint << std::endl; - } - return false; + for (const auto& i : used_gates) { + crypto3::zk::snark::plonk_column selector = + assignments.crypto3::zk::snark:: + template plonk_assignment_table::selector( + gates[i].selector_index); + + for (const auto& selector_row : selector_rows) { + if (selector_row < selector.size() && !selector[selector_row].is_zero()) { + for (std::size_t j = 0; j < gates[i].constraints.size(); j++) { + + typename BlueprintFieldType::value_type constraint_result = + gates[i].constraints[j].evaluate(selector_row, assignments); + + if (!constraint_result.is_zero()) { + std::cout << "Constraint " << j << " from gate " << i << " on row " << selector_row + << " is not satisfied." << std::endl; + std::cout << "Constraint result: " << constraint_result << std::endl; + std::cout << "Offending gate:" << std::endl; + for (const auto &constraint : gates[i].constraints) { + std::cout << constraint << std::endl; } + return false; } } } } } - for (std::size_t i = 0; i < lookup_gates.size(); i++) { - if (used_lookup_gates.empty() || used_lookup_gates.find(i) != used_lookup_gates.end()) { - crypto3::zk::snark::plonk_column selector = - assignments.crypto3::zk::snark:: - template plonk_assignment_table::selector( - lookup_gates[i].tag_index); - - for (std::size_t selector_row = 0; selector_row < selector.size(); selector_row++) { - if (!selector[selector_row].is_zero() && - (private_rows.empty() || private_rows.find(selector_row) != private_rows.end())) { - for (std::size_t j = 0; j < lookup_gates[i].constraints.size(); j++) { - std::vector input_values; - input_values.reserve(lookup_gates[i].constraints[j].lookup_input.size()); - for (std::size_t k = 0; k < lookup_gates[i].constraints[j].lookup_input.size(); k++) { - input_values.emplace_back(lookup_gates[i].constraints[j].lookup_input[k].evaluate( - selector_row, assignments)); - } - const auto table_name = - bp.get_reserved_indices_right().at(lookup_gates[i].constraints[j].table_id); - try { - std::string main_table_name = table_name.substr(0, table_name.find("/")); - std::string subtable_name = - table_name.substr(table_name.find("/") + 1, table_name.size() - 1); - const auto &table = bp.get_reserved_tables().at(main_table_name)->get_table(); - const auto &subtable = - bp.get_reserved_tables().at(main_table_name)->subtables.at(subtable_name); - - std::size_t columns_number = subtable.column_indices.size(); - - // Search the table for the input values - // We can cache it with sorting, or use KMP, but I need a simple solution first - bool found = false; - BOOST_ASSERT(columns_number == input_values.size()); - for (std::size_t k = 0; k < table[0].size(); k++) { - bool match = true; - for (std::size_t l = 0; l < columns_number; l++) { - if (table[subtable.column_indices[l]][k] != input_values[l]) { - match = false; - break; - } - } - if (match) { - found = true; + for (const auto& i : used_lookup_gates) { + crypto3::zk::snark::plonk_column selector = + assignments.crypto3::zk::snark:: + template plonk_assignment_table::selector( + lookup_gates[i].tag_index); + + for (const auto& selector_row : selector_rows) { + if (selector_row < selector.size() && !selector[selector_row].is_zero()) { + for (std::size_t j = 0; j < lookup_gates[i].constraints.size(); j++) { + std::vector input_values; + input_values.reserve(lookup_gates[i].constraints[j].lookup_input.size()); + for (std::size_t k = 0; k < lookup_gates[i].constraints[j].lookup_input.size(); k++) { + input_values.emplace_back(lookup_gates[i].constraints[j].lookup_input[k].evaluate( + selector_row, assignments)); + } + const auto table_name = + bp.get_reserved_indices_right().at(lookup_gates[i].constraints[j].table_id); + try { + std::string main_table_name = table_name.substr(0, table_name.find("/")); + std::string subtable_name = + table_name.substr(table_name.find("/") + 1, table_name.size() - 1); + const auto &table = bp.get_reserved_tables().at(main_table_name)->get_table(); + const auto &subtable = + bp.get_reserved_tables().at(main_table_name)->subtables.at(subtable_name); + + std::size_t columns_number = subtable.column_indices.size(); + + // Search the table for the input values + // We can cache it with sorting, or use KMP, but I need a simple solution first + bool found = false; + BOOST_ASSERT(columns_number == input_values.size()); + for (std::size_t k = 0; k < table[0].size(); k++) { + bool match = true; + for (std::size_t l = 0; l < columns_number; l++) { + if (table[subtable.column_indices[l]][k] != input_values[l]) { + match = false; break; } } - if (!found) { - std::cout << "Input values:"; - for (std::size_t k = 0; k < input_values.size(); k++) { - std::cout << input_values[k] << " "; - } - std::cout << std::endl; - std::cout << "Constraint " << j << " from lookup gate " << i << " from table " - << table_name << " on row " << selector_row << " is not satisfied." - << std::endl; - std::cout << "Offending Lookup Gate: " << std::endl; - for (const auto &constraint : lookup_gates[i].constraints) { - std::cout << "Table id: " << constraint.table_id << std::endl; - for (auto &lookup_input : constraint.lookup_input) { - std::cout << lookup_input << std::endl; - } + if (match) { + found = true; + break; + } + } + if (!found) { + std::cout << "Input values:"; + for (std::size_t k = 0; k < input_values.size(); k++) { + std::cout << input_values[k] << " "; + } + std::cout << std::endl; + std::cout << "Constraint " << j << " from lookup gate " << i << " from table " + << table_name << " on row " << selector_row << " is not satisfied." + << std::endl; + std::cout << "Offending Lookup Gate: " << std::endl; + for (const auto &constraint : lookup_gates[i].constraints) { + std::cout << "Table id: " << constraint.table_id << std::endl; + for (auto &lookup_input : constraint.lookup_input) { + std::cout << lookup_input << std::endl; } - return false; } - } catch (std::out_of_range &e) { - std::cout << "Lookup table " << table_name << " not found." << std::endl; return false; } + } catch (std::out_of_range &e) { + std::cout << "Lookup table " << table_name << " not found." << std::endl; + return false; } } } } } - for (std::size_t i = 0; i < copy_constraints.size(); i++) { - if (used_copy_constraints.empty() || used_copy_constraints.find(i) != used_copy_constraints.end()) { - if (var_value(assignments, copy_constraints[i].first) != - var_value(assignments, copy_constraints[i].second)) { - std::cout << "Copy constraint number " << i << " is not satisfied." - << " First variable: " << copy_constraints[i].first - << " second variable: " << copy_constraints[i].second << std::endl; - return false; - } + for (const auto& i : used_copy_constraints) { + if (var_value(assignments, copy_constraints[i].first) != + var_value(assignments, copy_constraints[i].second)) { + std::cout << "Copy constraint number " << i << " is not satisfied." + << " First variable: " << copy_constraints[i].first + << " second variable: " << copy_constraints[i].second << std::endl; + return false; } } return true;