From e54fd059f93da53b8bae681d125d1caee4c5259f Mon Sep 17 00:00:00 2001 From: Innokentii Sennovskii Date: Wed, 25 Oct 2023 01:45:21 +0100 Subject: [PATCH] feat: Added correctness tests for several small relations in Goblin Translator (Goblin Translator part 8) (#2963) Added correctness tests for several Goblin Translator Relations: 1. GenPermSort relation (used for range constraints) 2. Opcode Constraint relation (used to constrain opcode constraint to 6 specific values) 3. Accumulator transfer (used to ensure correct initialisation, copying and final value of the accumulator) --- .../honk/flavor/goblin_translator.hpp | 2 +- .../sumcheck/relation_correctness.test.cpp | 186 ++++++++++++++++++ 2 files changed, 187 insertions(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_translator.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_translator.hpp index d7d3b6d19e2e..bd03cc7236c5 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_translator.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_translator.hpp @@ -311,9 +311,9 @@ template class GoblinTranslator_ { // define the tuple of Relations that comprise the Sumcheck relation using Relations = std::tuple, GoblinTranslatorGenPermSortRelation, - GoblinTranslatorDecompositionRelation, GoblinTranslatorOpcodeConstraintRelation, GoblinTranslatorAccumulatorTransferRelation, + GoblinTranslatorDecompositionRelation, GoblinTranslatorNonNativeFieldRelation>; static constexpr size_t MAX_RELATION_LENGTH = get_max_relation_length(); diff --git a/barretenberg/cpp/src/barretenberg/honk/sumcheck/relation_correctness.test.cpp b/barretenberg/cpp/src/barretenberg/honk/sumcheck/relation_correctness.test.cpp index e19db649b948..8155bb1fc56f 100644 --- a/barretenberg/cpp/src/barretenberg/honk/sumcheck/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/sumcheck/relation_correctness.test.cpp @@ -450,4 +450,190 @@ TEST_F(RelationCorrectnessTests, GoblinTranslatorPermutationRelationCorrectness) check_relation>(circuit_size, prover_polynomials, params); } +TEST_F(RelationCorrectnessTests, GoblinTranslatorGenPermSortRelationCorrectness) +{ + using Flavor = flavor::GoblinTranslatorBasic; + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + using Polynomial = barretenberg::Polynomial; + auto& engine = numeric::random::get_debug_engine(); + + const auto circuit_size = Flavor::FULL_CIRCUIT_SIZE; + const auto sort_step = Flavor::SORT_STEP; + const auto max_value = (1 << Flavor::MICRO_LIMB_BITS) - 1; + + // No relation parameters are used in this relation + proof_system::RelationParameters params; + + ProverPolynomials prover_polynomials; + std::vector polynomial_container; + + // Allocate polynomials + for (size_t i = 0; i < prover_polynomials.size(); i++) { + Polynomial temporary_polynomial(circuit_size); + polynomial_container.push_back(temporary_polynomial); + prover_polynomials[i] = polynomial_container[i]; + } + + // Construct lagrange polynomials that are needed for Goblin Translator's GenPermSort Relation + prover_polynomials.lagrange_first[0] = 1; + prover_polynomials.lagrange_last[circuit_size - 1] = 1; + + // Create a vector and fill with necessary steps for the GenPermSort relation + auto sorted_elements_count = (max_value / sort_step) + 1; + std::vector vector_for_sorting(circuit_size); + for (size_t i = 0; i < sorted_elements_count - 1; i++) { + vector_for_sorting[i] = i * sort_step; + } + vector_for_sorting[sorted_elements_count - 1] = max_value; + + // Add random values to fill the leftover space + for (size_t i = sorted_elements_count; i < circuit_size; i++) { + vector_for_sorting[i] = engine.get_random_uint16() & ((1 << Flavor::MICRO_LIMB_BITS) - 1); + } + + // Get ordered polynomials + auto polynomial_pointers = std::vector{ &prover_polynomials.ordered_range_constraints_0, + &prover_polynomials.ordered_range_constraints_1, + &prover_polynomials.ordered_range_constraints_2, + &prover_polynomials.ordered_range_constraints_3, + &prover_polynomials.ordered_range_constraints_4 }; + + // Sort the vector + std::sort(vector_for_sorting.begin(), vector_for_sorting.end()); + + // Copy values, transforming them into Finite Field elements + std::transform(vector_for_sorting.cbegin(), + vector_for_sorting.cend(), + prover_polynomials.ordered_range_constraints_0.begin(), + [](uint64_t in) { return FF(in); }); + + // Copy the same polynomial into the 4 other ordered polynomials (they are not the same in an actual proof, but we + // only need to check the correctness of the relation and it acts independently on each polynomial) + parallel_for(4, [&](size_t i) { + std::copy(prover_polynomials.ordered_range_constraints_0.begin(), + prover_polynomials.ordered_range_constraints_0.end(), + polynomial_pointers[i + 1]->begin()); + }); + + // Get shifted polynomials + prover_polynomials.ordered_range_constraints_0_shift = + polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_0].shifted(); + prover_polynomials.ordered_range_constraints_1_shift = + polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_1].shifted(); + prover_polynomials.ordered_range_constraints_2_shift = + polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_2].shifted(); + prover_polynomials.ordered_range_constraints_3_shift = + polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_3].shifted(); + prover_polynomials.ordered_range_constraints_4_shift = + polynomial_container[Flavor::ORDERED_RANGE_CONSTRAINTS_4].shifted(); + + using Relations = typename Flavor::Relations; + + // Check that GenPermSort relation is satisfied across each row of the prover polynomials + check_relation>(circuit_size, prover_polynomials, params); +} + +/** + * @brief Test the correctness of GoblinTranslator's extra relations (GoblinTranslatorOpcodeConstraintRelation and + * GoblinTranslatorAccumulatorTransferRelation) + * + */ +TEST_F(RelationCorrectnessTests, GoblinTranslatorExtraRelationsCorrectness) +{ + using Flavor = flavor::GoblinTranslatorBasic; + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + using ProverPolynomialIds = typename Flavor::ProverPolynomialIds; + using Polynomial = barretenberg::Polynomial; + + auto& engine = numeric::random::get_debug_engine(); + + auto circuit_size = Flavor::FULL_CIRCUIT_SIZE; + auto mini_circuit_size = Flavor::MINI_CIRCUIT_SIZE; + + // We only use accumulated_result from relation parameters in this relation + proof_system::RelationParameters params; + params.accumulated_result = { + FF::random_element(), FF::random_element(), FF::random_element(), FF::random_element() + }; + + // Create storage for polynomials + ProverPolynomials prover_polynomials; + // We use polynomial ids to make shifting the polynomials easier + ProverPolynomialIds prover_polynomial_ids; + std::vector polynomial_container; + std::vector polynomial_ids; + for (size_t i = 0; i < prover_polynomials.size(); i++) { + Polynomial temporary_polynomial(circuit_size); + // Allocate polynomials + polynomial_container.push_back(temporary_polynomial); + // Push sequential ids to polynomial ids + polynomial_ids.push_back(i); + prover_polynomial_ids[i] = polynomial_ids[i]; + } + // Get ids of shifted polynomials and put them in a set + auto shifted_ids = prover_polynomial_ids.get_shifted(); + std::unordered_set shifted_id_set; + for (auto& id : shifted_ids) { + shifted_id_set.emplace(id); + } + // Assign spans to non-shifted prover polynomials + for (size_t i = 0; i < prover_polynomials.size(); i++) { + if (!shifted_id_set.contains(i)) { + prover_polynomials[i] = polynomial_container[i]; + } + } + + // Assign shifted spans to shifted prover polynomials using ids + for (size_t i = 0; i < shifted_ids.size(); i++) { + auto shifted_id = shifted_ids[i]; + auto to_be_shifted_id = prover_polynomial_ids.get_to_be_shifted()[i]; + prover_polynomials[shifted_id] = polynomial_container[to_be_shifted_id].shifted(); + } + + // Fill in lagrange even polynomial + for (size_t i = 2; i < mini_circuit_size; i += 2) { + prover_polynomials.lagrange_even_in_minicircuit[i] = 1; + } + constexpr size_t NUMBER_OF_POSSIBLE_OPCODES = 6; + constexpr std::array possible_opcode_values = { 0, 1, 2, 3, 4, 8 }; + + // Assign random opcode values + for (size_t i = 1; i < mini_circuit_size - 1; i += 2) { + prover_polynomials.op[i] = + possible_opcode_values[static_cast(engine.get_random_uint8() % NUMBER_OF_POSSIBLE_OPCODES)]; + } + + // Initialize used lagrange polynomials + prover_polynomials.lagrange_second[1] = 1; + prover_polynomials.lagrange_second_to_last_in_minicircuit[mini_circuit_size - 2] = 1; + + // Put random values in accumulator binary limbs (values should be preserved across even->next odd shift) + for (size_t i = 2; i < mini_circuit_size - 2; i += 2) { + prover_polynomials.accumulators_binary_limbs_0[i] = FF ::random_element(); + prover_polynomials.accumulators_binary_limbs_1[i] = FF ::random_element(); + prover_polynomials.accumulators_binary_limbs_2[i] = FF ::random_element(); + prover_polynomials.accumulators_binary_limbs_3[i] = FF ::random_element(); + prover_polynomials.accumulators_binary_limbs_0[i + 1] = prover_polynomials.accumulators_binary_limbs_0[i]; + prover_polynomials.accumulators_binary_limbs_1[i + 1] = prover_polynomials.accumulators_binary_limbs_1[i]; + prover_polynomials.accumulators_binary_limbs_2[i + 1] = prover_polynomials.accumulators_binary_limbs_2[i]; + prover_polynomials.accumulators_binary_limbs_3[i + 1] = prover_polynomials.accumulators_binary_limbs_3[i]; + } + + // The values of accumulator binary limbs at index 1 should equal the accumulated result from relation parameters + prover_polynomials.accumulators_binary_limbs_0[1] = params.accumulated_result[0]; + prover_polynomials.accumulators_binary_limbs_1[1] = params.accumulated_result[1]; + prover_polynomials.accumulators_binary_limbs_2[1] = params.accumulated_result[2]; + prover_polynomials.accumulators_binary_limbs_3[1] = params.accumulated_result[3]; + + using Relations = typename Flavor::Relations; + + // Check that Opcode Constraint relation is satisfied across each row of the prover polynomials + check_relation>(circuit_size, prover_polynomials, params); + + // Check that Accumulator Transfer relation is satisfied across each row of the prover polynomials + check_relation>(circuit_size, prover_polynomials, params); +} + } // namespace test_honk_relations