diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index deee8860d9a..5ff14f552aa 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -380,36 +380,35 @@ class GoblinUltraFlavor { calldata_read_counts = "CALLDATA_READ_COUNTS"; lookup_inverses = "LOOKUP_INVERSES"; - // The ones beginning with "__" are only used for debugging - q_c = "__Q_C"; - q_l = "__Q_L"; - q_r = "__Q_R"; - q_o = "__Q_O"; - q_4 = "__Q_4"; - q_m = "__Q_M"; - q_arith = "__Q_ARITH"; - q_sort = "__Q_SORT"; - q_elliptic = "__Q_ELLIPTIC"; - q_aux = "__Q_AUX"; - q_lookup = "__Q_LOOKUP"; - q_busread = "__Q_BUSREAD"; - q_poseidon2_external = "__Q_POSEIDON2_EXTERNAL"; - q_poseidon2_internal = "__Q_POSEIDON2_INTERNAL"; - sigma_1 = "__SIGMA_1"; - sigma_2 = "__SIGMA_2"; - sigma_3 = "__SIGMA_3"; - sigma_4 = "__SIGMA_4"; - id_1 = "__ID_1"; - id_2 = "__ID_2"; - id_3 = "__ID_3"; - id_4 = "__ID_4"; - table_1 = "__TABLE_1"; - table_2 = "__TABLE_2"; - table_3 = "__TABLE_3"; - table_4 = "__TABLE_4"; - lagrange_first = "__LAGRANGE_FIRST"; - lagrange_last = "__LAGRANGE_LAST"; - lagrange_ecc_op = "__Q_ECC_OP_QUEUE"; + q_c = "Q_C"; + q_l = "Q_L"; + q_r = "Q_R"; + q_o = "Q_O"; + q_4 = "Q_4"; + q_m = "Q_M"; + q_arith = "Q_ARITH"; + q_sort = "Q_SORT"; + q_elliptic = "Q_ELLIPTIC"; + q_aux = "Q_AUX"; + q_lookup = "Q_LOOKUP"; + q_busread = "Q_BUSREAD"; + q_poseidon2_external = "Q_POSEIDON2_EXTERNAL"; + q_poseidon2_internal = "Q_POSEIDON2_INTERNAL"; + sigma_1 = "SIGMA_1"; + sigma_2 = "SIGMA_2"; + sigma_3 = "SIGMA_3"; + sigma_4 = "SIGMA_4"; + id_1 = "ID_1"; + id_2 = "ID_2"; + id_3 = "ID_3"; + id_4 = "ID_4"; + table_1 = "TABLE_1"; + table_2 = "TABLE_2"; + table_3 = "TABLE_3"; + table_4 = "TABLE_4"; + lagrange_first = "LAGRANGE_FIRST"; + lagrange_last = "LAGRANGE_LAST"; + lagrange_ecc_op = "Q_ECC_OP_QUEUE"; }; }; @@ -458,15 +457,16 @@ class GoblinUltraFlavor { this->w_l = commitments.w_l; this->w_r = commitments.w_r; this->w_o = commitments.w_o; - this->sorted_accum = commitments.sorted_accum; this->w_4 = commitments.w_4; + this->sorted_accum = commitments.sorted_accum; this->z_perm = commitments.z_perm; this->z_lookup = commitments.z_lookup; this->ecc_op_wire_1 = commitments.ecc_op_wire_1; this->ecc_op_wire_2 = commitments.ecc_op_wire_2; this->ecc_op_wire_3 = commitments.ecc_op_wire_3; + this->ecc_op_wire_4 = commitments.ecc_op_wire_4; this->calldata = commitments.calldata; - this->calldata = commitments.calldata_read_counts; + this->calldata_read_counts = commitments.calldata_read_counts; this->lookup_inverses = commitments.lookup_inverses; } } diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index 559b3a9a270..16cfefff849 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -46,7 +46,8 @@ template class GoblinUltraRecursiveFlavor_ { using FF = typename Curve::ScalarField; using Commitment = typename Curve::Element; using CommitmentHandle = typename Curve::Element; - using NativeVerificationKey = GoblinUltraFlavor::VerificationKey; + using NativeFlavor = GoblinUltraFlavor; + using NativeVerificationKey = NativeFlavor::VerificationKey; // Note(luke): Eventually this may not be needed at all using VerifierCommitmentKey = bb::VerifierCommitmentKey; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index 9666b1e8648..0c8aede2d37 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -54,7 +54,8 @@ template class UltraRecursiveFlavor_ { using Commitment = typename Curve::Element; using CommitmentHandle = typename Curve::Element; using FF = typename Curve::ScalarField; - using NativeVerificationKey = UltraFlavor::VerificationKey; + using NativeFlavor = UltraFlavor; + using NativeVerificationKey = NativeFlavor::VerificationKey; // Note(luke): Eventually this may not be needed at all using VerifierCommitmentKey = bb::VerifierCommitmentKey; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index f5273d654a4..c0efde0a3d8 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -34,6 +34,27 @@ void ProtoGalaxyProver_::finalise_and_send_instance(std::shared transcript->send_to_verifier(domain_separator + "_" + wire_labels[idx], wire_comms[idx]); } + if constexpr (IsGoblinFlavor) { + // Commit to Goblin ECC op wires + witness_commitments.ecc_op_wire_1 = commitment_key->commit(instance->proving_key->ecc_op_wire_1); + witness_commitments.ecc_op_wire_2 = commitment_key->commit(instance->proving_key->ecc_op_wire_2); + witness_commitments.ecc_op_wire_3 = commitment_key->commit(instance->proving_key->ecc_op_wire_3); + witness_commitments.ecc_op_wire_4 = commitment_key->commit(instance->proving_key->ecc_op_wire_4); + + auto op_wire_comms = instance->witness_commitments.get_ecc_op_wires(); + auto labels = commitment_labels.get_ecc_op_wires(); + for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + transcript->send_to_verifier(domain_separator + "_" + labels[idx], op_wire_comms[idx]); + } + // Commit to DataBus columns + witness_commitments.calldata = commitment_key->commit(instance->proving_key->calldata); + witness_commitments.calldata_read_counts = commitment_key->commit(instance->proving_key->calldata_read_counts); + transcript->send_to_verifier(domain_separator + "_" + commitment_labels.calldata, + instance->witness_commitments.calldata); + transcript->send_to_verifier(domain_separator + "_" + commitment_labels.calldata_read_counts, + instance->witness_commitments.calldata_read_counts); + } + auto eta = transcript->get_challenge(domain_separator + "_eta"); instance->compute_sorted_accumulator_polynomials(eta); @@ -47,6 +68,16 @@ void ProtoGalaxyProver_::finalise_and_send_instance(std::shared transcript->send_to_verifier(domain_separator + "_" + commitment_labels.w_4, witness_commitments.w_4); auto [beta, gamma] = transcript->get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); + + if constexpr (IsGoblinFlavor) { + // Compute and commit to the logderivative inverse used in DataBus + instance->compute_logderivative_inverse(beta, gamma); + instance->witness_commitments.lookup_inverses = + commitment_key->commit(instance->prover_polynomials.lookup_inverses); + transcript->send_to_verifier(domain_separator + "_" + commitment_labels.lookup_inverses, + instance->witness_commitments.lookup_inverses); + } + instance->compute_grand_product_polynomials(beta, gamma); witness_commitments.z_perm = commitment_key->commit(instance->prover_polynomials.z_perm); @@ -303,7 +334,6 @@ FoldingResult ProtoGalaxyProver_proof_data; res.accumulator = next_accumulator; - return res; } diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp index 46d4305a30a..026c83a618c 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -127,16 +127,23 @@ template class ProtoGalaxyProver_ { std::shared_ptr get_accumulator() { return instances[0]; } /** - * @brief Compute the values of the full Honk relation at each row in the execution trace, f_i(ω) in the - * ProtoGalaxy paper, given the evaluations of all the prover polynomials and α (the parameter that helps establish - * each subrelation is independently valid in Honk - from the Plonk paper, DO NOT confuse with α in ProtoGalaxy), + * @brief Compute the values of the full Honk relation at each row in the execution trace, representing f_i(ω) in + * the ProtoGalaxy paper, given the evaluations of all the prover polynomials and \vec{α} (the batching challenges + * that help establishing each subrelation is independently valid in Honk - from the Plonk paper, DO NOT confuse + * with α in ProtoGalaxy). + * + * @details When folding GoblinUltra instances, one of the relations is linearly dependent. We define such relations + * as acting on the entire execution trace and hence requiring to be accumulated separately as we iterate over each + * row. At the end of the function, the linearly dependent contribution is accumulated at index 0 representing the + * sum f_0(ω) + α_j*g(ω) where f_0 represents the full honk evaluation at row 0, g(ω) is the linearly dependent + * subrelation and α_j is its corresponding batching challenge. */ static std::vector compute_full_honk_evaluations(const ProverPolynomials& instance_polynomials, const RelationSeparator& alpha, const RelationParameters& relation_parameters) { auto instance_size = instance_polynomials.get_polynomial_size(); - + FF linearly_dependent_contribution = FF(0); std::vector full_honk_evaluations(instance_size); for (size_t row = 0; row < instance_size; row++) { auto row_evaluations = instance_polynomials.get_row(row); @@ -150,17 +157,22 @@ template class ProtoGalaxyProver_ { auto output = FF(0); auto running_challenge = FF(1); - Utils::scale_and_batch_elements(relation_evaluations, alpha, running_challenge, output); + + // Sum relation evaluations, batched by their corresponding relation separator challenge, to get the value + // of the full honk relation at a specific row + Utils::scale_and_batch_elements( + relation_evaluations, alpha, running_challenge, output, linearly_dependent_contribution); full_honk_evaluations[row] = output; } + full_honk_evaluations[0] += linearly_dependent_contribution; return full_honk_evaluations; } /** - * @brief Recursively compute the parent nodes of each level in there, starting from the leaves. Note that at each - * level, the resulting parent nodes will be polynomials of degree (level + 1) because we multiply by an additional - * factor of X. + * @brief Recursively compute the parent nodes of each level in the tree, starting from the leaves. Note that at + * each level, the resulting parent nodes will be polynomials of degree (level+1) because we multiply by an + * additional factor of X. */ static std::vector construct_coefficients_tree(const std::vector& betas, const std::vector& deltas, @@ -307,7 +319,8 @@ template class ProtoGalaxyProver_ { FF pow_challenge = pow_betas[idx]; // Accumulate the i-th row's univariate contribution. Note that the relation parameters passed to this - // function have already been folded + // function have already been folded. Moreover, linear-dependent relations that act over the entire + // execution trace rather than on rows, will not be multiplied by the pow challenge. accumulate_relation_univariates( thread_univariate_accumulators[thread_idx], extended_univariates[thread_idx], @@ -323,6 +336,7 @@ template class ProtoGalaxyProver_ { // Batch the univariate contributions from each sub-relation to obtain the round univariate return batch_over_relations(univariate_accumulators, instances.alphas); } + static ExtendedUnivariateWithRandomization batch_over_relations(TupleOfTuplesOfUnivariates& univariate_accumulators, const CombinedRelationSeparator& alpha) { @@ -331,7 +345,7 @@ template class ProtoGalaxyProver_ { auto result = std::get<0>(std::get<0>(univariate_accumulators)) .template extend_to(); size_t idx = 0; - auto scale_and_sum = [&](auto& element) { + auto scale_and_sum = [&](auto& element) { auto extended = element.template extend_to(); extended *= alpha[idx]; result += extended; @@ -416,7 +430,8 @@ template class ProtoGalaxyProver_ { } /** - * @brief Compute the next accumulator (ϕ*, ω*\vec{\beta*}, e*), send the public data ϕ* and the folding parameters + * @brief Compute the next accumulator (ϕ*, ω*, \vec{\beta*}, e*), send the public data ϕ* and the folding + * parameters * (\vec{\beta*}, e*) to the verifier and return the complete accumulator * * @details At this stage, we assume that the instances have the same size and the same number of public parameter.s diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index 02923df5972..bee65a68010 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -87,6 +87,22 @@ void ProtoGalaxyVerifier_::receive_and_finalise_instance(cons witness_commitments.w_r = transcript->template receive_from_prover(domain_separator + "_" + labels.w_r); witness_commitments.w_o = transcript->template receive_from_prover(domain_separator + "_" + labels.w_o); + if constexpr (IsGoblinFlavor) { + // Get commitments to the ECC wire polynomials and databus polynomials + witness_commitments.ecc_op_wire_1 = + transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_1); + witness_commitments.ecc_op_wire_2 = + transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_2); + witness_commitments.ecc_op_wire_3 = + transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_3); + witness_commitments.ecc_op_wire_4 = + transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_4); + witness_commitments.calldata = + transcript->template receive_from_prover(domain_separator + "_" + labels.calldata); + witness_commitments.calldata_read_counts = + transcript->template receive_from_prover(domain_separator + "_" + labels.calldata_read_counts); + } + // Get challenge for sorted list batching and wire four memory records commitment auto eta = transcript->get_challenge(domain_separator + "_eta"); witness_commitments.sorted_accum = @@ -95,6 +111,13 @@ void ProtoGalaxyVerifier_::receive_and_finalise_instance(cons // Get permutation challenges and commitment to permutation and lookup grand products auto [beta, gamma] = transcript->get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); + + if constexpr (IsGoblinFlavor) { + // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial + witness_commitments.lookup_inverses = transcript->template receive_from_prover( + domain_separator + "_" + commitment_labels.lookup_inverses); + } + witness_commitments.z_perm = transcript->template receive_from_prover(domain_separator + "_" + labels.z_perm); witness_commitments.z_lookup = diff --git a/barretenberg/cpp/src/barretenberg/relations/utils.hpp b/barretenberg/cpp/src/barretenberg/relations/utils.hpp index 331967359f3..9818249f3ad 100644 --- a/barretenberg/cpp/src/barretenberg/relations/utils.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/utils.hpp @@ -184,7 +184,7 @@ template class RelationUtils { }; /** - * @brief Scale elements, which in sumcheck represent evaluations of subrelations, by different challenges then sum + * @brief Scale elements, representing evaluations of subrelations, by separate challenges then sum them * @param challenges Array of NUM_SUBRELATIONS - 1 challenges (because the first subrelation does not need to be * scaled) * @param result Batched result @@ -208,7 +208,49 @@ template class RelationUtils { } /** - * @brief Scale elements by consecutive powers of the challenge then sum + * @brief Scales elements, representing evaluations of polynomials in subrelations, by separate challenges and then + * sum them together. This function has identical functionality with the one above with the caveat that one such + * evaluation is part of a linearly dependent subrelation and hence needs to be accumulated separately. + * + * @details Such functionality is needed when computing the evaluation of the full relation at a specific row in + * the execution trace because a linearly dependent subrelation does not act on a specific row but rather on the + * entire execution trace. + * + * @param tuple + * @param challenges + * @param current_scalar + * @param result + * @param linearly_dependent_contribution + */ + static void scale_and_batch_elements(auto& tuple, + const RelationSeparator& challenges, + FF current_scalar, + FF& result, + FF& linearly_dependent_contribution) + requires bb::IsFoldingFlavor + { + size_t idx = 0; + std::array tmp{ current_scalar }; + + std::copy(challenges.begin(), challenges.end(), tmp.begin() + 1); + + auto scale_by_challenge_and_accumulate = + [&](Element& element) { + using Relation = typename std::tuple_element_t; + const bool is_subrelation_linearly_independent = + bb::subrelation_is_linearly_independent(); + if (is_subrelation_linearly_independent) { + result += element * tmp[idx]; + } else { + linearly_dependent_contribution += element * tmp[idx]; + } + idx++; + }; + apply_to_tuple_of_arrays_elements(scale_by_challenge_and_accumulate, tuple); + } + + /** + * @brief Scale elements by consecutive powers of a given challenge then sum the result * @param result Batched result */ static void scale_and_batch_elements(auto& tuple, const RelationSeparator& challenge, FF current_scalar, FF& result) @@ -240,5 +282,33 @@ template class RelationUtils { apply_to_tuple_of_arrays(operation, tuple); } } + + /** + * @brief Recursive template function to apply a specific operation on each element of several arrays in a tuple + * + * @details We need this method in addition to the apply_to_tuple_of_arrays when we aim to perform different + * operations depending on the array element. More explicitly, in our codebase this method is used when the elements + * of array are values of subrelations and we want to accumulate some of these values separately (the linearly + * dependent contribution when we compute the evaluation of full rel_U(G)H at particular row.) + */ + template + static void apply_to_tuple_of_arrays_elements(Operation&& operation, std::tuple& tuple) + { + using Relation = typename std::tuple_element_t; + const auto subrelation_length = Relation::SUBRELATION_PARTIAL_LENGTHS.size(); + auto& element = std::get(tuple); + + // Invoke the operation with outer_idx (array index) and inner_idx (element index) as template arguments + operation.template operator()(element[inner_idx]); + + if constexpr (inner_idx + 1 < subrelation_length) { + // Recursively call for the next element within the same array + apply_to_tuple_of_arrays_elements(std::forward(operation), + tuple); + } else if constexpr (outer_idx + 1 < sizeof...(Ts)) { + // Move to the next array in the tuple + apply_to_tuple_of_arrays_elements(std::forward(operation), tuple); + } + } }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp index 48f6d655c5a..e0fed9ac6a2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp @@ -94,6 +94,21 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst witness_commitments.w_r = transcript->template receive_from_prover(domain_separator + "_" + labels.w_r); witness_commitments.w_o = transcript->template receive_from_prover(domain_separator + "_" + labels.w_o); + if constexpr (IsGoblinFlavor) { + witness_commitments.ecc_op_wire_1 = + transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_1); + witness_commitments.ecc_op_wire_2 = + transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_2); + witness_commitments.ecc_op_wire_3 = + transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_3); + witness_commitments.ecc_op_wire_4 = + transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_4); + witness_commitments.calldata = + transcript->template receive_from_prover(domain_separator + "_" + labels.calldata); + witness_commitments.calldata_read_counts = + transcript->template receive_from_prover(domain_separator + "_" + labels.calldata_read_counts); + } + // Get challenge for sorted list batching and wire four memory records commitment auto eta = transcript->get_challenge(domain_separator + "_eta"); witness_commitments.sorted_accum = @@ -102,6 +117,13 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst // Get permutation challenges and commitment to permutation and lookup grand products auto [beta, gamma] = transcript->get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); + + // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial + if constexpr (IsGoblinFlavor) { + witness_commitments.lookup_inverses = transcript->template receive_from_prover( + domain_separator + "_" + commitment_labels.lookup_inverses); + } + witness_commitments.z_perm = transcript->template receive_from_prover(domain_separator + "_" + labels.z_perm); witness_commitments.z_lookup = diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp index 34cfdfb303f..0912edf91ce 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -8,31 +8,33 @@ #include "barretenberg/ultra_honk/ultra_composer.hpp" namespace bb::stdlib::recursion::honk { -class ProtogalaxyRecursiveTest : public testing::Test { +template class ProtoGalaxyRecursiveTests : public testing::Test { public: // Define types relevant for testing using UltraComposer = ::bb::UltraComposer_; using GoblinUltraComposer = ::bb::UltraComposer_; - using InnerFlavor = UltraFlavor; - using InnerComposer = UltraComposer; + using InnerFlavor = typename RecursiveFlavor::NativeFlavor; + using InnerComposer = ::bb::UltraComposer_; using Instance = ::bb::ProverInstance_; using InnerBuilder = typename InnerComposer::CircuitBuilder; using InnerCurve = bn254; - using Commitment = InnerFlavor::Commitment; - using FF = InnerFlavor::FF; + using Commitment = typename InnerFlavor::Commitment; + using FF = typename InnerFlavor::FF; - // Types for recursive verifier circuit - // cannot do on Goblin + // Types for veryfing a recursive verifier circuit using OuterBuilder = GoblinUltraCircuitBuilder; - using RecursiveFlavor = ::bb::UltraRecursiveFlavor_; - using RecursiveVerifierInstances = VerifierInstances_; + using OuterComposer = GoblinUltraComposer; + + using RecursiveVerifierInstances = ::bb::VerifierInstances_; using FoldingRecursiveVerifier = ProtoGalaxyRecursiveVerifier_; using DeciderRecursiveVerifier = DeciderRecursiveVerifier_; using DeciderVerifier = DeciderVerifier_; using NativeVerifierInstances = VerifierInstances_; using NativeFoldingVerifier = ProtoGalaxyVerifier_; + static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } + // Helper for getting composer for prover/verifier of recursive (outer) circuit template static auto get_outer_composer() { @@ -55,12 +57,13 @@ class ProtogalaxyRecursiveTest : public testing::Test { */ static void create_inner_circuit(InnerBuilder& builder, size_t log_num_gates = 10) { - using fr_ct = InnerCurve::ScalarField; - using fq_ct = InnerCurve::BaseField; - using public_witness_ct = InnerCurve::public_witness_ct; - using witness_ct = InnerCurve::witness_ct; - using byte_array_ct = InnerCurve::byte_array_ct; + using fr_ct = typename InnerCurve::ScalarField; + using fq_ct = typename InnerCurve::BaseField; + using public_witness_ct = typename InnerCurve::public_witness_ct; + using witness_ct = typename InnerCurve::witness_ct; + using byte_array_ct = typename InnerCurve::byte_array_ct; using fr = typename InnerCurve::ScalarFieldNative; + using point = typename InnerCurve::AffineElementNative; // Create 2^log_n many add gates based on input log num gates const size_t num_gates = 1 << log_num_gates; @@ -99,14 +102,87 @@ class ProtogalaxyRecursiveTest : public testing::Test { fq_ct big_b(fr_ct(witness_ct(&builder, bigfield_data_b.to_montgomery_form())), fr_ct(witness_ct(&builder, 0))); big_a* big_b; + + if constexpr (IsGoblinBuilder) { + auto p = point::one() * fr::random_element(); + auto scalar = fr::random_element(); + builder.queue_ecc_mul_accum(p, scalar); + builder.queue_ecc_eq(); + } }; - public: - static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } + static std::shared_ptr fold_and_verify_native(const std::vector>& instances, + InnerComposer& composer) + { + auto folding_prover = composer.create_folding_prover(instances); + auto folding_verifier = composer.create_folding_verifier(); + + auto proof = folding_prover.fold_instances(); + auto next_accumulator = proof.accumulator; + auto res = folding_verifier.verify_folding_proof(proof.folding_data); + EXPECT_EQ(res, true); + return next_accumulator; + } + + /** + *@brief Create inner circuit and call check_circuit on it + */ + static void test_inner_circuit() + { + InnerBuilder builder; + + create_inner_circuit(builder); + + bool result = builder.check_circuit(); + EXPECT_EQ(result, true); + }; + + /** + * @brief Ensure that evaluating the perturbator in the recursive folding verifier returns the same result as + * evaluating in Polynomial class. + * + */ + static void test_new_evaluate() + { + OuterBuilder builder; + using fr_ct = bn254::ScalarField; + using fr = bn254::ScalarFieldNative; + + std::vector coeffs; + std::vector coeffs_ct; + for (size_t idx = 0; idx < 8; idx++) { + auto el = fr::random_element(); + coeffs.emplace_back(el); + coeffs_ct.emplace_back(fr_ct(&builder, el)); + } + Polynomial poly(coeffs); + fr point = fr::random_element(); + fr_ct point_ct(fr_ct(&builder, point)); + auto res1 = poly.evaluate(point); - static std::shared_ptr fold_and_verify(const std::vector>& instances, - InnerComposer& inner_composer) + auto res2 = FoldingRecursiveVerifier::evaluate_perturbator(coeffs_ct, point_ct); + EXPECT_EQ(res1, res2.get_value()); + }; + + /** + * @brief Tests a simple recursive fold that is valid works as expected. + * + */ + static void test_recursive_folding() { + // Create two arbitrary circuits for the first round of folding + InnerBuilder builder1; + + create_inner_circuit(builder1); + InnerBuilder builder2; + builder2.add_public_variable(FF(1)); + create_inner_circuit(builder2); + + InnerComposer inner_composer = InnerComposer(); + auto instance1 = inner_composer.create_instance(builder1); + auto instance2 = inner_composer.create_instance(builder2); + auto instances = std::vector>{ instance1, instance2 }; + // Generate a folding proof auto inner_folding_prover = inner_composer.create_folding_prover(instances); auto inner_folding_proof = inner_folding_prover.fold_instances(); @@ -115,16 +191,16 @@ class ProtogalaxyRecursiveTest : public testing::Test { OuterBuilder outer_folding_circuit; FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; verifier.verify_folding_proof(inner_folding_proof.folding_data); - info("Recursive Verifier with Ultra instances: num gates = ", outer_folding_circuit.num_gates); + info("Folding Recursive Verifier: num gates = ", outer_folding_circuit.num_gates); // Perform native folding verification and ensure it returns the same result (either true or false) as calling // check_circuit on the recursive folding verifier auto native_folding_verifier = inner_composer.create_folding_verifier(); auto native_folding_result = native_folding_verifier.verify_folding_proof(inner_folding_proof.folding_data); - EXPECT_EQ(native_folding_result, outer_folding_circuit.check_circuit()); + EXPECT_EQ(native_folding_result, !outer_folding_circuit.failed()); - // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring - // the manifests produced by each agree. + // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the + // manifestsproduced by each agree. auto recursive_folding_manifest = verifier.transcript->get_manifest(); auto native_folding_manifest = native_folding_verifier.transcript->get_manifest(); @@ -135,214 +211,196 @@ class ProtogalaxyRecursiveTest : public testing::Test { // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(outer_folding_circuit.failed(), false) << outer_folding_circuit.err(); - return inner_folding_proof.accumulator; - } -}; -/** - * @brief Create inner circuit and call check_circuit on it - * - */ -TEST_F(ProtogalaxyRecursiveTest, InnerCircuit) -{ - InnerBuilder builder; + { + auto composer = OuterComposer(); + auto instance = composer.create_instance(outer_folding_circuit); + auto prover = composer.create_prover(instance); + auto verifier = composer.create_verifier(instance); + auto proof = prover.construct_proof(); + bool verified = verifier.verify_proof(proof); - create_inner_circuit(builder); + ASSERT(verified); + } + }; - bool result = builder.check_circuit(); - EXPECT_EQ(result, true); -} + /** + * @brief Perform two rounds of folding valid circuits and then recursive verify the final decider proof, + * make sure the verifer circuits pass check_circuit(). Ensure that the algorithm of the recursive and native + * verifiers are identical by checking the manifests + */ + // TODO(https://github.com/AztecProtocol/barretenberg/issues/844): Fold the recursive folding verifier in tests once + // we can fold instances of different sizes. + static void test_full_protogalaxy_recursive() + { + // Create two arbitrary circuits for the first round of folding + InnerBuilder builder1; + + create_inner_circuit(builder1); + InnerBuilder builder2; + builder2.add_public_variable(FF(1)); + create_inner_circuit(builder2); + + InnerComposer inner_composer = InnerComposer(); + auto instance1 = inner_composer.create_instance(builder1); + auto instance2 = inner_composer.create_instance(builder2); + auto instances = std::vector>{ instance1, instance2 }; + + auto accumulator = fold_and_verify_native(instances, inner_composer); + + // Create another circuit to do a second round of folding + InnerBuilder builder3; + create_inner_circuit(builder3); + auto instance3 = inner_composer.create_instance(builder3); + instances = std::vector>{ accumulator, instance3 }; + + accumulator = fold_and_verify_native(instances, inner_composer); + + // Create a decider proof for the relaxed instance obtained through folding + auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); + auto inner_decider_proof = inner_decider_prover.construct_proof(); + + // Create a decider verifier circuit for recursively verifying the decider proof + OuterBuilder outer_decider_circuit; + DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; + auto pairing_points = decider_verifier.verify_proof(inner_decider_proof); + info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); + // Check for a failure flag in the recursive verifier circuit + EXPECT_EQ(outer_decider_circuit.failed(), false) << outer_decider_circuit.err(); + + // Perform native verification then perform the pairing on the outputs of the recursive + // decider verifier and check that the result agrees. + DeciderVerifier native_decider_verifier = inner_composer.create_decider_verifier(accumulator); + auto native_result = native_decider_verifier.verify_proof(inner_decider_proof); + auto recursive_result = native_decider_verifier.pcs_verification_key->pairing_check( + pairing_points[0].get_value(), pairing_points[1].get_value()); + EXPECT_EQ(native_result, recursive_result); + + // Ensure that the underlying native and recursive decider verification algorithms agree by ensuring + // the manifests produced are the same. + auto recursive_decider_manifest = decider_verifier.transcript->get_manifest(); + auto native_decider_manifest = native_decider_verifier.transcript->get_manifest(); + for (size_t i = 0; i < recursive_decider_manifest.size(); ++i) { + EXPECT_EQ(recursive_decider_manifest[i], native_decider_manifest[i]); + } -/** - * @brief Ensure that evaluating the perturbator in the recursive folding verifier returns the same result as - * evaluating in Polynomial class. - * - */ -TEST_F(ProtogalaxyRecursiveTest, NewEvaluate) -{ - OuterBuilder builder; - using fr_ct = bn254::ScalarField; - using fr = bn254::ScalarFieldNative; - - std::vector coeffs; - std::vector coeffs_ct; - for (size_t idx = 0; idx < 8; idx++) { - auto el = fr::random_element(); - coeffs.emplace_back(el); - coeffs_ct.emplace_back(fr_ct(&builder, el)); - } - Polynomial poly(coeffs); - fr point = fr::random_element(); - fr_ct point_ct(fr_ct(&builder, point)); - auto res1 = poly.evaluate(point); + // Construct and verify a proof of the recursive decider verifier circuit + { + auto composer = OuterComposer(); + auto instance = composer.create_instance(outer_decider_circuit); + auto prover = composer.create_prover(instance); + auto verifier = composer.create_verifier(instance); + auto proof = prover.construct_proof(); + bool verified = verifier.verify_proof(proof); - auto res2 = FoldingRecursiveVerifier::evaluate_perturbator(coeffs_ct, point_ct); - EXPECT_EQ(res1, res2.get_value()); -} + ASSERT(verified); + } + }; -/** - * @brief Tests a simple recursive fold that is valid works as expected. - * - */ -TEST_F(ProtogalaxyRecursiveTest, RecursiveFoldingTest) -{ - // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; + static void test_tampered_decider_proof() + { + // Create two arbitrary circuits for the first round of folding + InnerBuilder builder1; - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); + create_inner_circuit(builder1); + InnerBuilder builder2; + builder2.add_public_variable(FF(1)); + create_inner_circuit(builder2); - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; + InnerComposer inner_composer = InnerComposer(); + auto instance1 = inner_composer.create_instance(builder1); + auto instance2 = inner_composer.create_instance(builder2); + auto instances = std::vector>{ instance1, instance2 }; - fold_and_verify(instances, inner_composer); -} + auto accumulator = fold_and_verify_native(instances, inner_composer); -/** - * @brief Recursively verify two rounds of folding valid circuits and then recursive verify the final decider proof, - * make sure the verifer circuits pass check_circuit(). Ensure that the algorithm of the recursive and native verifiers - * are identical by checking the manifests + // Tamper with the accumulator by changing the target sum + accumulator->target_sum = FF::random_element(); - */ -TEST_F(ProtogalaxyRecursiveTest, FullProtogalaxyRecursiveTest) -{ + // Create a decider proof for the relaxed instance obtained through folding + auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); + auto inner_decider_proof = inner_decider_prover.construct_proof(); - // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; - - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); - - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; - - auto accumulator = fold_and_verify(instances, inner_composer); - - // Create another circuit to do a second round of folding - InnerBuilder builder3; - create_inner_circuit(builder3); - auto instance3 = inner_composer.create_instance(builder3); - instances = std::vector>{ accumulator, instance3 }; - - accumulator = fold_and_verify(instances, inner_composer); - - // Create a decider proof for the relaxed instance obtained through folding - auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); - auto inner_decider_proof = inner_decider_prover.construct_proof(); - - // Create a decider verifier circuit for recursively verifying the decider proof - OuterBuilder outer_decider_circuit; - DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; - auto pairing_points = decider_verifier.verify_proof(inner_decider_proof); - info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); - // Check for a failure flag in the recursive verifier circuit - EXPECT_EQ(outer_decider_circuit.failed(), false) << outer_decider_circuit.err(); - - // Perform native verification then perform the pairing on the outputs of the recursive - // decider verifier and check that the result agrees. - DeciderVerifier native_decider_verifier = inner_composer.create_decider_verifier(accumulator); - auto native_result = native_decider_verifier.verify_proof(inner_decider_proof); - auto recursive_result = native_decider_verifier.pcs_verification_key->pairing_check(pairing_points[0].get_value(), - pairing_points[1].get_value()); - EXPECT_EQ(native_result, recursive_result); - - // Ensure that the underlying native and recursive decider verification algorithms agree by ensuring - // the manifests produced are the same. - auto recursive_decider_manifest = decider_verifier.transcript->get_manifest(); - auto native_decider_manifest = native_decider_verifier.transcript->get_manifest(); - for (size_t i = 0; i < recursive_decider_manifest.size(); ++i) { - EXPECT_EQ(recursive_decider_manifest[i], native_decider_manifest[i]); - } + // Create a decider verifier circuit for recursively verifying the decider proof + OuterBuilder outer_decider_circuit; + DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; + decider_verifier.verify_proof(inner_decider_proof); + info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); + + // We expect the decider circuit check to fail due to the bad proof + EXPECT_FALSE(outer_decider_circuit.check_circuit()); + }; - // Construct and verify a proof of the recursive decider verifier circuit + static void test_tampered_accumulator() { - auto composer = get_outer_composer(); - auto instance = composer.create_instance(outer_decider_circuit); - auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); - auto proof = prover.construct_proof(); - bool verified = verifier.verify_proof(proof); - - ASSERT(verified); - } -} + // Create two arbitrary circuits for the first round of folding + InnerBuilder builder1; -TEST_F(ProtogalaxyRecursiveTest, TamperedDeciderProof) -{ - // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; + create_inner_circuit(builder1); + InnerBuilder builder2; + builder2.add_public_variable(FF(1)); + create_inner_circuit(builder2); + + InnerComposer inner_composer = InnerComposer(); + auto instance1 = inner_composer.create_instance(builder1); + auto instance2 = inner_composer.create_instance(builder2); + auto instances = std::vector>{ instance1, instance2 }; + + auto accumulator = fold_and_verify_native(instances, inner_composer); + + // Create another circuit to do a second round of folding + InnerBuilder builder3; + create_inner_circuit(builder3); + auto instance3 = inner_composer.create_instance(builder3); + + // Tamper with the accumulator + instances = std::vector>{ accumulator, instance3 }; + accumulator->prover_polynomials.w_l[1] = FF::random_element(); - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); + // Generate a folding proof + auto inner_folding_prover = inner_composer.create_folding_prover(instances); + auto inner_folding_proof = inner_folding_prover.fold_instances(); + + // Create a recursive folding verifier circuit for the folding proof of the two instances + OuterBuilder outer_folding_circuit; + FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; + verifier.verify_folding_proof(inner_folding_proof.folding_data); + EXPECT_EQ(outer_folding_circuit.check_circuit(), false); + }; +}; - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; +using FlavorTypes = testing::Types, + UltraRecursiveFlavor_>; +TYPED_TEST_SUITE(ProtoGalaxyRecursiveTests, FlavorTypes); - auto accumulator = fold_and_verify(instances, inner_composer); +TYPED_TEST(ProtoGalaxyRecursiveTests, InnerCircuit) +{ + TestFixture::test_inner_circuit(); +} + +TYPED_TEST(ProtoGalaxyRecursiveTests, NewEvaluate) +{ + TestFixture::test_new_evaluate(); +} - // Tamper with the accumulator by changing the target sum - accumulator->target_sum = FF::random_element(); +TYPED_TEST(ProtoGalaxyRecursiveTests, RecursiveFoldingTest) +{ + TestFixture::test_recursive_folding(); +} - // Create a decider proof for the relaxed instance obtained through folding - auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); - auto inner_decider_proof = inner_decider_prover.construct_proof(); +TYPED_TEST(ProtoGalaxyRecursiveTests, FullProtogalaxyRecursiveTest) +{ - // Create a decider verifier circuit for recursively verifying the decider proof - OuterBuilder outer_decider_circuit; - DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; - decider_verifier.verify_proof(inner_decider_proof); - info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); + TestFixture::test_full_protogalaxy_recursive(); +} - // We expect the decider circuit check to fail due to the bad proof - EXPECT_FALSE(outer_decider_circuit.check_circuit()); +TYPED_TEST(ProtoGalaxyRecursiveTests, TamperedDeciderProof) +{ + TestFixture::test_tampered_decider_proof(); } -TEST_F(ProtogalaxyRecursiveTest, TamperedAccumulator) +TYPED_TEST(ProtoGalaxyRecursiveTests, TamperedAccumulator) { - // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; - - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); - - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; - - auto accumulator = fold_and_verify(instances, inner_composer); - - // Create another circuit to do a second round of folding - InnerBuilder builder3; - create_inner_circuit(builder3); - auto instance3 = inner_composer.create_instance(builder3); - - // Tamper with the accumulator - instances = std::vector>{ accumulator, instance3 }; - accumulator->prover_polynomials.w_l[1] = FF::random_element(); - - // Generate a folding proof - auto inner_folding_prover = inner_composer.create_folding_prover(instances); - auto inner_folding_proof = inner_folding_prover.fold_instances(); - - // Create a recursive folding verifier circuit for the folding proof of the two instances - OuterBuilder outer_folding_circuit; - FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; - verifier.verify_folding_proof(inner_folding_proof.folding_data); - EXPECT_EQ(outer_folding_circuit.check_circuit(), false); + TestFixture::test_tampered_accumulator(); } } // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp index 651c05fa19c..f0237d439f1 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp @@ -1,3 +1,4 @@ +#include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/polynomials/pow.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" #include "barretenberg/ultra_honk/ultra_composer.hpp" @@ -6,340 +7,438 @@ using namespace bb; namespace { -using Flavor = UltraFlavor; -using VerificationKey = Flavor::VerificationKey; -using Instance = ProverInstance_; -using Instances = ProverInstances_; -using ProtoGalaxyProver = ProtoGalaxyProver_; -using FF = Flavor::FF; -using Affine = Flavor::Commitment; -using Projective = Flavor::GroupElement; -using Builder = Flavor::CircuitBuilder; -using ProverPolynomials = Flavor::ProverPolynomials; -using WitnessCommitments = typename Flavor::WitnessCommitments; -using CommitmentKey = Flavor::CommitmentKey; - -const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; auto& engine = numeric::get_debug_randomness(); -// TODO(https://github.com/AztecProtocol/barretenberg/issues/744): make testing utility with functionality shared -// amongst test files in the proof system -Polynomial get_random_polynomial(size_t size) -{ - auto poly = bb::Polynomial(size); - for (auto& coeff : poly) { - coeff = FF::random_element(); - } - return poly; -} - -ProverPolynomials construct_ultra_full_polynomials(auto& input_polynomials) -{ - ProverPolynomials full_polynomials; - for (auto [prover_poly, input_poly] : zip_view(full_polynomials.get_all(), input_polynomials)) { - prover_poly = input_poly.share(); - } - return full_polynomials; -} - -std::shared_ptr fold_and_verify(const std::vector>& instances, - UltraComposer& composer, - bool expected_result) -{ - auto folding_prover = composer.create_folding_prover(instances); - auto folding_verifier = composer.create_folding_verifier(); - - auto proof = folding_prover.fold_instances(); - auto next_accumulator = proof.accumulator; - auto res = folding_verifier.verify_folding_proof(proof.folding_data); - EXPECT_EQ(res, expected_result); - return next_accumulator; -} - -void check_accumulator_target_sum_manual(std::shared_ptr& accumulator, bool expected_result) -{ - auto instance_size = accumulator->instance_size; - auto expected_honk_evals = ProtoGalaxyProver::compute_full_honk_evaluations( - accumulator->prover_polynomials, accumulator->alphas, accumulator->relation_parameters); - // Construct pow(\vec{betas*}) as in the paper - auto expected_pows = PowPolynomial(accumulator->gate_challenges); - expected_pows.compute_values(); - - // Compute the corresponding target sum and create a dummy accumulator - auto expected_target_sum = FF(0); - for (size_t i = 0; i < instance_size; i++) { - expected_target_sum += expected_honk_evals[i] * expected_pows[i]; - } - - EXPECT_EQ(accumulator->target_sum == expected_target_sum, expected_result); -} -void decide_and_verify(std::shared_ptr& accumulator, UltraComposer& composer, bool expected_result) -{ - auto decider_prover = composer.create_decider_prover(accumulator); - auto decider_verifier = composer.create_decider_verifier(accumulator); - auto decision = decider_prover.construct_proof(); - auto verified = decider_verifier.verify_proof(decision); - EXPECT_EQ(verified, expected_result); -} -class ProtoGalaxyTests : public ::testing::Test { +template class ProtoGalaxyTests : public testing::Test { public: + using Composer = UltraComposer_; + using VerificationKey = typename Flavor::VerificationKey; + using Instance = ProverInstance_; + using Instances = ProverInstances_; + using ProtoGalaxyProver = ProtoGalaxyProver_; + using FF = typename Flavor::FF; + using Affine = typename Flavor::Commitment; + using Projective = typename Flavor::GroupElement; + using Builder = typename Flavor::CircuitBuilder; + using Polynomial = typename Flavor::Polynomial; + using ProverPolynomials = typename Flavor::ProverPolynomials; + using RelationParameters = bb::RelationParameters; + using WitnessCommitments = typename Flavor::WitnessCommitments; + using CommitmentKey = typename Flavor::CommitmentKey; + using PowPolynomial = bb::PowPolynomial; + static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } -}; -} // namespace -TEST_F(ProtoGalaxyTests, FullHonkEvaluationsValidCircuit) -{ - auto builder = Builder(); - FF a = FF::one(); - uint32_t a_idx = builder.add_public_variable(a); - FF b = FF::one(); - FF c = a + b; - uint32_t b_idx = builder.add_variable(b); - uint32_t c_idx = builder.add_variable(c); - builder.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); - builder.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); - - auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); - instance->initialize_prover_polynomials(); - - auto eta = FF::random_element(); - auto beta = FF::random_element(); - auto gamma = FF::random_element(); - instance->compute_sorted_accumulator_polynomials(eta); - instance->compute_grand_product_polynomials(beta, gamma); - - for (auto& alpha : instance->alphas) { - alpha = FF::random_element(); + static void construct_circuit(Builder& builder) + { + if constexpr (IsGoblinFlavor) { + GoblinMockCircuits::construct_arithmetic_circuit(builder); + GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); + + } else { + FF a = FF::random_element(); + FF b = FF::random_element(); + FF c = FF::random_element(); + FF d = a + b + c; + uint32_t a_idx = builder.add_public_variable(a); + uint32_t b_idx = builder.add_variable(b); + uint32_t c_idx = builder.add_variable(c); + uint32_t d_idx = builder.add_variable(d); + + builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) }); + } } - auto full_honk_evals = ProtoGalaxyProver::compute_full_honk_evaluations( - instance->prover_polynomials, instance->alphas, instance->relation_parameters); - // Evaluations should be 0 for valid circuit - for (const auto& eval : full_honk_evals) { - EXPECT_EQ(eval, FF(0)); + static ProverPolynomials construct_full_prover_polynomials(auto& input_polynomials) + { + ProverPolynomials full_polynomials; + for (auto [prover_poly, input_poly] : zip_view(full_polynomials.get_all(), input_polynomials)) { + prover_poly = input_poly.share(); + } + return full_polynomials; } -} -TEST_F(ProtoGalaxyTests, PerturbatorCoefficients) -{ - std::vector betas = { FF(5), FF(8), FF(11) }; - std::vector deltas = { FF(2), FF(4), FF(8) }; - std::vector full_honk_evaluations = { FF(1), FF(1), FF(1), FF(1), FF(1), FF(1), FF(1), FF(1) }; - auto perturbator = ProtoGalaxyProver::construct_perturbator_coefficients(betas, deltas, full_honk_evaluations); - std::vector expected_values = { FF(648), FF(936), FF(432), FF(64) }; - EXPECT_EQ(perturbator.size(), 4); // log(instance_size) + 1 - for (size_t i = 0; i < perturbator.size(); i++) { - EXPECT_EQ(perturbator[i], expected_values[i]); - } -} -TEST_F(ProtoGalaxyTests, PerturbatorPolynomial) -{ - using RelationSeparator = Flavor::RelationSeparator; - const size_t log_instance_size(3); - const size_t instance_size(1 << log_instance_size); - - std::array, NUM_POLYNOMIALS> random_polynomials; - for (auto& poly : random_polynomials) { - poly = get_random_polynomial(instance_size); + static std::shared_ptr fold_and_verify(const std::vector>& instances, + Composer& composer, + bool expected_result) + { + auto folding_prover = composer.create_folding_prover(instances); + auto folding_verifier = composer.create_folding_verifier(); + + auto proof = folding_prover.fold_instances(); + auto next_accumulator = proof.accumulator; + auto res = folding_verifier.verify_folding_proof(proof.folding_data); + EXPECT_EQ(res, expected_result); + return next_accumulator; } - auto full_polynomials = construct_ultra_full_polynomials(random_polynomials); - auto relation_parameters = RelationParameters::get_random(); - RelationSeparator alphas; - for (auto& alpha : alphas) { - alpha = FF::random_element(); + + static void check_accumulator_target_sum_manual(std::shared_ptr& accumulator, bool expected_result) + { + auto instance_size = accumulator->instance_size; + auto expected_honk_evals = ProtoGalaxyProver::compute_full_honk_evaluations( + accumulator->prover_polynomials, accumulator->alphas, accumulator->relation_parameters); + // Construct pow(\vec{betas*}) as in the paper + auto expected_pows = PowPolynomial(accumulator->gate_challenges); + expected_pows.compute_values(); + + // Compute the corresponding target sum and create a dummy accumulator + auto expected_target_sum = FF(0); + for (size_t i = 0; i < instance_size; i++) { + expected_target_sum += expected_honk_evals[i] * expected_pows[i]; + } + EXPECT_EQ(accumulator->target_sum == expected_target_sum, expected_result); } - auto full_honk_evals = - ProtoGalaxyProver::compute_full_honk_evaluations(full_polynomials, alphas, relation_parameters); - std::vector betas(log_instance_size); - for (size_t idx = 0; idx < log_instance_size; idx++) { - betas[idx] = FF::random_element(); + static void decide_and_verify(std::shared_ptr& accumulator, Composer& composer, bool expected_result) + { + auto decider_prover = composer.create_decider_prover(accumulator); + auto decider_verifier = composer.create_decider_verifier(accumulator); + auto decider_proof = decider_prover.construct_proof(); + auto verified = decider_verifier.verify_proof(decider_proof); + EXPECT_EQ(verified, expected_result); } - // Construct pow(\vec{betas}) as in the paper - auto pow_beta = bb::PowPolynomial(betas); - pow_beta.compute_values(); + /** + * @brief For a valid circuit, ensures that computing the value of the full UH/UGH relation at each row in its + * execution trace (with the contribution of the linearly dependent one added tot he first row, in case of Goblin) + * will be 0. + * + */ + static void test_full_honk_evaluations_valid_circuit() + { + auto builder = typename Flavor::CircuitBuilder(); + construct_circuit(builder); + + auto composer = Composer(); + auto instance = composer.create_instance(builder); + instance->initialize_prover_polynomials(); + + auto eta = FF::random_element(); + auto beta = FF::random_element(); + auto gamma = FF::random_element(); + instance->compute_sorted_accumulator_polynomials(eta); + if constexpr (IsGoblinFlavor) { + instance->compute_logderivative_inverse(beta, gamma); + } + instance->compute_grand_product_polynomials(beta, gamma); + + for (auto& alpha : instance->alphas) { + alpha = FF::random_element(); + } + auto full_honk_evals = ProtoGalaxyProver::compute_full_honk_evaluations( + instance->prover_polynomials, instance->alphas, instance->relation_parameters); + + // Evaluations should be 0 for valid circuit + for (const auto& eval : full_honk_evals) { + EXPECT_EQ(eval, FF(0)); + } + } - // Compute the corresponding target sum and create a dummy accumulator - auto target_sum = FF(0); - for (size_t i = 0; i < instance_size; i++) { - target_sum += full_honk_evals[i] * pow_beta[i]; + /** + * @brief Check the coefficients of the perturbator computed from dummy \vec{β}, \vec{δ} and f_i(ω) will be the same + * as if computed manually. + * + */ + static void test_pertubator_coefficients() + { + std::vector betas = { FF(5), FF(8), FF(11) }; + std::vector deltas = { FF(2), FF(4), FF(8) }; + std::vector full_honk_evaluations = { FF(1), FF(1), FF(1), FF(1), FF(1), FF(1), FF(1), FF(1) }; + auto perturbator = ProtoGalaxyProver::construct_perturbator_coefficients(betas, deltas, full_honk_evaluations); + std::vector expected_values = { FF(648), FF(936), FF(432), FF(64) }; + EXPECT_EQ(perturbator.size(), 4); // log(instance_size) + 1 + for (size_t i = 0; i < perturbator.size(); i++) { + EXPECT_EQ(perturbator[i], expected_values[i]); + } } - auto accumulator = std::make_shared(); - accumulator->prover_polynomials = std::move(full_polynomials); - accumulator->gate_challenges = betas; - accumulator->target_sum = target_sum; - accumulator->relation_parameters = relation_parameters; - accumulator->alphas = alphas; + /** + * @brief Create a dummy accumulator and ensure coefficient 0 of the computed perturbator is the same as the + * accumulator's target sum. + * + */ + static void test_pertubator_polynomial() + { + using RelationSeparator = typename Flavor::RelationSeparator; + const size_t log_instance_size(3); + const size_t instance_size(1 << log_instance_size); + std::array, Flavor::NUM_ALL_ENTITIES> random_polynomials; + for (auto& poly : random_polynomials) { + poly = bb::Polynomial::random(instance_size); + } + auto full_polynomials = construct_full_prover_polynomials(random_polynomials); + auto relation_parameters = bb::RelationParameters::get_random(); + RelationSeparator alphas; + for (auto& alpha : alphas) { + alpha = FF::random_element(); + } + + auto full_honk_evals = + ProtoGalaxyProver::compute_full_honk_evaluations(full_polynomials, alphas, relation_parameters); + std::vector betas(log_instance_size); + for (size_t idx = 0; idx < log_instance_size; idx++) { + betas[idx] = FF::random_element(); + } + + // Construct pow(\vec{betas}) as in the paper + auto pow_beta = bb::PowPolynomial(betas); + pow_beta.compute_values(); + + // Compute the corresponding target sum and create a dummy accumulator + auto target_sum = FF(0); + for (size_t i = 0; i < instance_size; i++) { + target_sum += full_honk_evals[i] * pow_beta[i]; + } + + auto accumulator = std::make_shared(); + accumulator->prover_polynomials = std::move(full_polynomials); + accumulator->gate_challenges = betas; + accumulator->target_sum = target_sum; + accumulator->relation_parameters = relation_parameters; + accumulator->alphas = alphas; + + auto deltas = ProtoGalaxyProver::compute_round_challenge_pows(log_instance_size, FF::random_element()); + auto perturbator = ProtoGalaxyProver::compute_perturbator(accumulator, deltas); + + // Ensure the constant coefficient of the perturbator is equal to the target sum as indicated by the paper + EXPECT_EQ(perturbator[0], target_sum); + } - auto deltas = ProtoGalaxyProver::compute_round_challenge_pows(log_instance_size, FF::random_element()); - auto perturbator = ProtoGalaxyProver::compute_perturbator(accumulator, deltas); + /** + * @brief Manually compute the expected evaluations of the combiner quotient, given evaluations of the combiner and + * check them against the evaluations returned by the function. + * + */ + static void test_combiner_quotient() + { + auto compressed_perturbator = FF(2); // F(\alpha) in the paper + auto combiner = + bb::Univariate(std::array{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }); + auto combiner_quotient = ProtoGalaxyProver::compute_combiner_quotient(compressed_perturbator, combiner); + + // K(i) = (G(i) - ( L_0(i) * F(\alpha)) / Z(i), i = {2,.., 13} for ProverInstances::NUM = 2 + // K(i) = (G(i) - (1 - i) * F(\alpha)) / i * (i - 1) + auto expected_evals = bb::Univariate(std::array{ + (FF(22) - (FF(1) - FF(2)) * compressed_perturbator) / (FF(2) * FF(2 - 1)), + (FF(23) - (FF(1) - FF(3)) * compressed_perturbator) / (FF(3) * FF(3 - 1)), + (FF(24) - (FF(1) - FF(4)) * compressed_perturbator) / (FF(4) * FF(4 - 1)), + (FF(25) - (FF(1) - FF(5)) * compressed_perturbator) / (FF(5) * FF(5 - 1)), + (FF(26) - (FF(1) - FF(6)) * compressed_perturbator) / (FF(6) * FF(6 - 1)), + (FF(27) - (FF(1) - FF(7)) * compressed_perturbator) / (FF(7) * FF(7 - 1)), + (FF(28) - (FF(1) - FF(8)) * compressed_perturbator) / (FF(8) * FF(8 - 1)), + (FF(29) - (FF(1) - FF(9)) * compressed_perturbator) / (FF(9) * FF(9 - 1)), + (FF(30) - (FF(1) - FF(10)) * compressed_perturbator) / (FF(10) * FF(10 - 1)), + (FF(31) - (FF(1) - FF(11)) * compressed_perturbator) / (FF(11) * FF(11 - 1)), + (FF(32) - (FF(1) - FF(12)) * compressed_perturbator) / (FF(12) * FF(12 - 1)), + }); + + for (size_t idx = 2; idx < 7; idx++) { + EXPECT_EQ(combiner_quotient.value_at(idx), expected_evals.value_at(idx)); + } + } - // Ensure the constant coefficient of the perturbator is equal to the target sum as indicated by the paper - EXPECT_EQ(perturbator[0], target_sum); -} + /** + * @brief For two dummy instances with their relation parameter η set, check that combining them in a univariate, + * barycentrially extended to the desired number of evaluations, is performed correctly. + * + */ + static void test_combine_relation_parameters() + { + using Instances = ProverInstances_; + using Instance = typename Instances::Instance; + + Builder builder1; + auto instance1 = std::make_shared(builder1); + instance1->relation_parameters.eta = 1; + + Builder builder2; + builder2.add_variable(3); + auto instance2 = std::make_shared(builder2); + instance2->relation_parameters.eta = 3; + + Instances instances{ { instance1, instance2 } }; + ProtoGalaxyProver::combine_relation_parameters(instances); + + bb::Univariate expected_eta{ { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 } }; + EXPECT_EQ(instances.relation_parameters.eta, expected_eta); + } -TEST_F(ProtoGalaxyTests, CombinerQuotient) -{ - auto compressed_perturbator = FF(2); // F(\alpha) in the paper - auto combiner = Univariate(std::array{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }); - auto combiner_quotient = ProtoGalaxyProver::compute_combiner_quotient(compressed_perturbator, combiner); - - // K(i) = (G(i) - ( L_0(i) * F(\alpha)) / Z(i), i = {2,.., 13} for ProverInstances::NUM = 2 - // K(i) = (G(i) - (1 - i) * F(\alpha)) / i * (i - 1) - auto expected_evals = Univariate(std::array{ - (FF(22) - (FF(1) - FF(2)) * compressed_perturbator) / (FF(2) * FF(2 - 1)), - (FF(23) - (FF(1) - FF(3)) * compressed_perturbator) / (FF(3) * FF(3 - 1)), - (FF(24) - (FF(1) - FF(4)) * compressed_perturbator) / (FF(4) * FF(4 - 1)), - (FF(25) - (FF(1) - FF(5)) * compressed_perturbator) / (FF(5) * FF(5 - 1)), - (FF(26) - (FF(1) - FF(6)) * compressed_perturbator) / (FF(6) * FF(6 - 1)), - (FF(27) - (FF(1) - FF(7)) * compressed_perturbator) / (FF(7) * FF(7 - 1)), - (FF(28) - (FF(1) - FF(8)) * compressed_perturbator) / (FF(8) * FF(8 - 1)), - (FF(29) - (FF(1) - FF(9)) * compressed_perturbator) / (FF(9) * FF(9 - 1)), - (FF(30) - (FF(1) - FF(10)) * compressed_perturbator) / (FF(10) * FF(10 - 1)), - (FF(31) - (FF(1) - FF(11)) * compressed_perturbator) / (FF(11) * FF(11 - 1)), - (FF(32) - (FF(1) - FF(12)) * compressed_perturbator) / (FF(12) * FF(12 - 1)), - }); - - for (size_t idx = 2; idx < 7; idx++) { - EXPECT_EQ(combiner_quotient.value_at(idx), expected_evals.value_at(idx)); + /** + * @brief Given two dummy instances with the batching challenges alphas set (one for each subrelation) ensure + * combining them in a univariate of desired length works as expected. + */ + static void test_combine_alpha() + { + using Instances = ProverInstances_; + using Instance = typename Instances::Instance; + + Builder builder1; + auto instance1 = std::make_shared(builder1); + instance1->alphas.fill(2); + + Builder builder2; + builder2.add_variable(3); + auto instance2 = std::make_shared(builder2); + instance2->alphas.fill(4); + + Instances instances{ { instance1, instance2 } }; + ProtoGalaxyProver::combine_alpha(instances); + + bb::Univariate expected_alpha{ { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26 } }; + for (const auto& alpha : instances.alphas) { + EXPECT_EQ(alpha, expected_alpha); + } } -} -TEST_F(ProtoGalaxyTests, CombineRelationParameters) -{ - using Instances = ProverInstances_; - using Instance = typename Instances::Instance; + /** + * @brief Testing two valid rounds of folding followed by the decider. + * + */ + static void test_full_protogalaxy() + { + auto composer = Composer(); + auto builder_1 = typename Flavor::CircuitBuilder(); + construct_circuit(builder_1); - Builder builder1; - auto instance1 = std::make_shared(builder1); - instance1->relation_parameters.eta = 1; + auto instance_1 = composer.create_instance(builder_1); - Builder builder2; - builder2.add_variable(3); - auto instance2 = std::make_shared(builder2); - instance2->relation_parameters.eta = 3; + auto builder_2 = typename Flavor::CircuitBuilder(); + construct_circuit(builder_2); - Instances instances{ { instance1, instance2 } }; - ProtoGalaxyProver::combine_relation_parameters(instances); + auto instance_2 = composer.create_instance(builder_2); - Univariate expected_eta{ { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 } }; - EXPECT_EQ(instances.relation_parameters.eta, expected_eta); -} + auto instances = std::vector>{ instance_1, instance_2 }; + auto first_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(first_accumulator, true); -TEST_F(ProtoGalaxyTests, CombineAlpha) -{ - using Instances = ProverInstances_; - using Instance = typename Instances::Instance; + auto builder_3 = typename Flavor::CircuitBuilder(); + construct_circuit(builder_3); + auto instance_3 = composer.create_instance(builder_3); - Builder builder1; - auto instance1 = std::make_shared(builder1); - instance1->alphas.fill(2); + instances = std::vector>{ first_accumulator, instance_3 }; + auto second_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(second_accumulator, true); - Builder builder2; - builder2.add_variable(3); - auto instance2 = std::make_shared(builder2); - instance2->alphas.fill(4); + decide_and_verify(first_accumulator, composer, true); + } - Instances instances{ { instance1, instance2 } }; - ProtoGalaxyProver::combine_alpha(instances); + /** + * @brief Ensure tampering a commitment and then calling the decider causes the decider verification to fail. + * + */ + static void test_tampered_commitment() + { + auto composer = Composer(); - Univariate expected_alpha{ { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26 } }; - for (const auto& alpha : instances.alphas) { - EXPECT_EQ(alpha, expected_alpha); - } -} + auto builder_1 = typename Flavor::CircuitBuilder(); + construct_circuit(builder_1); -// Check both manually and using the protocol two rounds of folding -TEST_F(ProtoGalaxyTests, FullProtogalaxyTest) -{ - auto composer = UltraComposer(); + auto instance_1 = composer.create_instance(builder_1); - auto builder_1 = typename Flavor::CircuitBuilder(); - builder_1.add_public_variable(FF(1)); + auto builder_2 = typename Flavor::CircuitBuilder(); + construct_circuit(builder_2); - auto instance_1 = composer.create_instance(builder_1); + auto instance_2 = composer.create_instance(builder_2); - auto builder_2 = typename Flavor::CircuitBuilder(); - builder_2.add_public_variable(FF(1)); + auto instances = std::vector>{ instance_1, instance_2 }; + auto first_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(first_accumulator, true); - auto instance_2 = composer.create_instance(builder_2); + auto builder_3 = typename Flavor::CircuitBuilder(); + construct_circuit(builder_3); + auto instance_3 = composer.create_instance(builder_3); - auto instances = std::vector>{ instance_1, instance_2 }; - auto first_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(first_accumulator, true); + // tampering with the commitment should cause the decider to fail + first_accumulator->witness_commitments.w_l = Projective(Affine::random_element()); + instances = std::vector>{ first_accumulator, instance_3 }; - auto builder_3 = typename Flavor::CircuitBuilder(); - builder_3.add_public_variable(FF(1)); - auto instance_3 = composer.create_instance(builder_3); + auto second_accumulator = fold_and_verify(instances, composer, true); - instances = std::vector>{ first_accumulator, instance_3 }; - auto second_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(second_accumulator, true); + decide_and_verify(second_accumulator, composer, false); + } - decide_and_verify(second_accumulator, composer, true); -} + /** + * @brief Ensure tampering an accumulator and then calling fold again causes both the folding verification and + * decider verification to fail. + * + */ + static void test_tampered_accumulator_polynomial() + { + auto composer = Composer(); -TEST_F(ProtoGalaxyTests, TamperedCommitment) -{ - auto composer = UltraComposer(); + auto builder_1 = typename Flavor::CircuitBuilder(); + construct_circuit(builder_1); - auto builder_1 = typename Flavor::CircuitBuilder(); - builder_1.add_public_variable(FF(1)); + auto instance_1 = composer.create_instance(builder_1); - auto instance_1 = composer.create_instance(builder_1); + auto builder_2 = typename Flavor::CircuitBuilder(); + construct_circuit(builder_2); - auto builder_2 = typename Flavor::CircuitBuilder(); - builder_2.add_public_variable(FF(1)); + auto instance_2 = composer.create_instance(builder_2); - auto instance_2 = composer.create_instance(builder_2); + auto instances = std::vector>{ instance_1, instance_2 }; + auto first_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(first_accumulator, true); - auto instances = std::vector>{ instance_1, instance_2 }; - auto first_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(first_accumulator, true); + auto builder_3 = typename Flavor::CircuitBuilder(); + construct_circuit(builder_3); + auto instance_3 = composer.create_instance(builder_3); - auto builder_3 = typename Flavor::CircuitBuilder(); - builder_3.add_public_variable(FF(1)); - auto instance_3 = composer.create_instance(builder_3); + // tampering with accumulator's polynomial should cause both folding and deciding to fail + instances = std::vector>{ first_accumulator, instance_3 }; + first_accumulator->prover_polynomials.w_l[1] = FF::random_element(); + auto second_accumulator = fold_and_verify(instances, composer, false); - // tampering with the commitment should cause the decider to fail - first_accumulator->witness_commitments.w_l = Projective(Affine::random_element()); - instances = std::vector>{ first_accumulator, instance_3 }; + decide_and_verify(second_accumulator, composer, false); + } +}; +} // namespace - auto second_accumulator = fold_and_verify(instances, composer, true); +using FlavorTypes = testing::Types; +TYPED_TEST_SUITE(ProtoGalaxyTests, FlavorTypes); - decide_and_verify(second_accumulator, composer, false); +TYPED_TEST(ProtoGalaxyTests, PerturbatorCoefficients) +{ + TestFixture::test_pertubator_coefficients(); } -TEST_F(ProtoGalaxyTests, TamperedAccumulatorPolynomial) +TYPED_TEST(ProtoGalaxyTests, FullHonkEvaluationsValidCircuit) { - auto composer = UltraComposer(); - - auto builder_1 = typename Flavor::CircuitBuilder(); - builder_1.add_public_variable(FF(1)); + TestFixture::test_full_honk_evaluations_valid_circuit(); +} - auto instance_1 = composer.create_instance(builder_1); +TYPED_TEST(ProtoGalaxyTests, PerturbatorPolynomial) +{ + TestFixture::test_pertubator_polynomial(); +} - auto builder_2 = typename Flavor::CircuitBuilder(); - builder_2.add_public_variable(FF(1)); +TYPED_TEST(ProtoGalaxyTests, CombinerQuotient) +{ + TestFixture::test_combiner_quotient(); +} - auto instance_2 = composer.create_instance(builder_2); +TYPED_TEST(ProtoGalaxyTests, CombineRelationParameters) +{ + TestFixture::test_combine_relation_parameters(); +} - auto instances = std::vector>{ instance_1, instance_2 }; - auto first_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(first_accumulator, true); +TYPED_TEST(ProtoGalaxyTests, CombineAlpha) +{ + TestFixture::test_combine_alpha(); +} - auto builder_3 = typename Flavor::CircuitBuilder(); - builder_3.add_public_variable(FF(1)); - auto instance_3 = composer.create_instance(builder_3); +TYPED_TEST(ProtoGalaxyTests, FullProtogalaxyTest) +{ + TestFixture::test_full_protogalaxy(); +} - // tampering with accumulator's polynomial should cause both folding and deciding to fail - instances = std::vector>{ first_accumulator, instance_3 }; - first_accumulator->prover_polynomials.w_l[1] = FF::random_element(); - auto second_accumulator = fold_and_verify(instances, composer, false); +TYPED_TEST(ProtoGalaxyTests, TamperedCommitment) +{ + TestFixture::test_tampered_commitment(); +} - decide_and_verify(second_accumulator, composer, false); +TYPED_TEST(ProtoGalaxyTests, TamperedAccumulatorPolynomial) +{ + TestFixture::test_tampered_accumulator_polynomial(); } \ No newline at end of file