From eb0c7be80530101617a4ecf7e60d47dca65e14f4 Mon Sep 17 00:00:00 2001 From: Cody Gunton Date: Fri, 30 Aug 2024 15:54:10 -0400 Subject: [PATCH] feat: Clarify state in Protogalaxy 3 (#8181) Main goal: more explicit state by making round functions pure functions (with const inputs). - Exception: first round mutates instances. May handle in follow-on that changes handling of accumulator. - Also: get rid of several pieces of prover state (`gate_challenges`, `relation_parameters`, `optimised_relation_parameters`, `accumulators`, `result`) - FYI: will likely get rid of temporary refactoring helper classes `State` and `ProtogalaxyProverInternal` also. Also: - Rename `accumulator_update_round`, `preparation_round`, `compressed_perturbator`, `OptimisedFoo`, `CombinedFoo`. - Combiner test does not use prover class. - Use `const` in a bunch of places - Reduce amount of templating by explicitly naming instantiations of compute_combiner --- .../cpp/scripts/analyze_client_ivc_bench.py | 8 +- .../cpp/scripts/analyze_protogalaxy_bench.py | 8 +- .../protogalaxy/combiner.test.cpp | 50 +++---- .../protogalaxy/protogalaxy_prover.hpp | 56 ++++++-- .../protogalaxy/protogalaxy_prover_impl.hpp | 123 ++++-------------- .../protogalaxy_prover_internal.hpp | 23 ++-- 6 files changed, 118 insertions(+), 150 deletions(-) diff --git a/barretenberg/cpp/scripts/analyze_client_ivc_bench.py b/barretenberg/cpp/scripts/analyze_client_ivc_bench.py index 43efc74fed09..c2464204ea4d 100644 --- a/barretenberg/cpp/scripts/analyze_client_ivc_bench.py +++ b/barretenberg/cpp/scripts/analyze_client_ivc_bench.py @@ -66,10 +66,10 @@ print('\nBreakdown of ProtogalaxyProver::prove:') protogalaxy_round_labels = [ - "ProtogalaxyProver_::preparation_round(t)", - "ProtogalaxyProver_::perturbator_round(t)", - "ProtogalaxyProver_::combiner_quotient_round(t)", - "ProtogalaxyProver_::update_target_sum_and_fold(t)" + "ProtoGalaxyProver_::preparation_round(t)", + "ProtoGalaxyProver_::perturbator_round(t)", + "ProtoGalaxyProver_::combiner_quotient_round(t)", + "ProtoGalaxyProver_::update_target_sum_and_fold(t)" ] max_label_length = max(len(label) for label in protogalaxy_round_labels) for key in protogalaxy_round_labels: diff --git a/barretenberg/cpp/scripts/analyze_protogalaxy_bench.py b/barretenberg/cpp/scripts/analyze_protogalaxy_bench.py index b5686fc351a1..56be71fec2ed 100755 --- a/barretenberg/cpp/scripts/analyze_protogalaxy_bench.py +++ b/barretenberg/cpp/scripts/analyze_protogalaxy_bench.py @@ -47,10 +47,10 @@ print('\nBreakdown of ProtogalaxyProver::prove:') protogalaxy_round_labels = [ - "ProtogalaxyProver_::preparation_round(t)", - "ProtogalaxyProver_::perturbator_round(t)", - "ProtogalaxyProver_::combiner_quotient_round(t)", - "ProtogalaxyProver_::update_target_sum_and_fold(t)" + "ProtoGalaxyProver_::preparation_round(t)", + "ProtoGalaxyProver_::perturbator_round(t)", + "ProtoGalaxyProver_::combiner_quotient_round(t)", + "ProtoGalaxyProver_::update_target_sum_and_fold(t)" ] max_label_length = max(len(label) for label in protogalaxy_round_labels) for key in protogalaxy_round_labels: diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp index a9bcb68de764..cfa625bbc1b1 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp @@ -53,10 +53,10 @@ TEST(Protogalaxy, CombinerOn2Instances) ProverInstances instances{ instance_data }; Fun::UnivariateRelationSeparator alphas; alphas.fill(bb::Univariate(FF(0))); // focus on the arithmetic relation only - GateSeparatorPolynomial gate_separators({ 2 }, /*log_num_monomials=*/1); - Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters_no_skpping; - auto result_no_skipping = Fun::compute_combiner_no_optimistic_skipping( - instances, gate_separators, univariate_relation_parameters_no_skpping, alphas); + PowPolynomial pow_polynomial({ 2 }, /*log_num_monomials=*/1); + Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters; + auto result = Fun::compute_combiner_no_optimistic_skipping( + instances, pow_polynomial, univariate_relation_parameters, alphas); // The expected_result values are computed by running the python script combiner_example_gen.py auto expected_result = Univariate(std::array{ 9704UL, 13245288UL, @@ -133,13 +133,13 @@ TEST(Protogalaxy, CombinerOn2Instances) relation value: 0 0 0 0 0 0 0 0 0 6 18 36 60 90 */ - GateSeparatorPolynomial gate_separators({ 2 }, /*log_num_monomials=*/1); - Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters_no_skpping; - Fun::UnivariateRelationParameters univariate_relation_parameters; - auto result_no_skipping = Fun::compute_combiner_no_optimistic_skipping( - instances, gate_separators, univariate_relation_parameters_no_skpping, alphas); - auto result_with_skipping = - Fun::compute_combiner(instances, gate_separators, univariate_relation_parameters, alphas); + PowPolynomial pow_polynomial({ 2 }, /*log_num_monomials=*/1); + Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters; + Fun::UnivariateRelationParameters optimised_univariate_relation_parameters; + auto result = Fun::compute_combiner_no_optimistic_skipping( + instances, pow_polynomial, univariate_relation_parameters, alphas); + auto optimised_result = + Fun::compute_combiner(instances, pow_polynomial, optimised_univariate_relation_parameters, alphas); auto expected_result = Univariate(std::array{ 0, 0, 12, 36, 72, 120, 180, 252, 336, 432, 540, 660 }); @@ -193,7 +193,7 @@ TEST(Protogalaxy, CombinerOptimizationConsistency) ProverInstances instances{ instance_data }; Fun::UnivariateRelationSeparator alphas; alphas.fill(bb::Univariate(FF(0))); // focus on the arithmetic relation only - GateSeparatorPolynomial gate_separators({ 2 }, /*log_num_monomials=*/1); + PowPolynomial pow_polynomial({ 2 }, /*log_num_monomials=*/1); // Relation parameters are all zeroes RelationParameters relation_parameters; @@ -254,12 +254,12 @@ TEST(Protogalaxy, CombinerOptimizationConsistency) precomputed_result[idx] = std::get<0>(accumulator)[0]; } auto expected_result = Univariate(precomputed_result); - Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters_no_skpping; - Fun::UnivariateRelationParameters univariate_relation_parameters; - auto result_no_skipping = Fun::compute_combiner_no_optimistic_skipping( - instances, gate_separators, univariate_relation_parameters_no_skpping, alphas); - auto result_with_skipping = - Fun::compute_combiner(instances, gate_separators, univariate_relation_parameters, alphas); + Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters; + Fun::UnivariateRelationParameters optimised_univariate_relation_parameters; + auto result = Fun::compute_combiner_no_optimistic_skipping( + instances, pow_polynomial, univariate_relation_parameters, alphas); + auto optimised_result = + Fun::compute_combiner(instances, pow_polynomial, optimised_univariate_relation_parameters, alphas); EXPECT_EQ(result_no_skipping, expected_result); EXPECT_EQ(result_with_skipping, expected_result); @@ -325,13 +325,13 @@ TEST(Protogalaxy, CombinerOptimizationConsistency) relation value: 0 0 0 0 0 0 0 0 0 6 18 36 60 90 */ - GateSeparatorPolynomial gate_separators({ 2 }, /*log_num_monomials=*/1); - Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters_no_skpping; - Fun::UnivariateRelationParameters univariate_relation_parameters; - auto result_no_skipping = Fun::compute_combiner_no_optimistic_skipping( - instances, gate_separators, univariate_relation_parameters_no_skpping, alphas); - auto result_with_skipping = - Fun::compute_combiner(instances, gate_separators, univariate_relation_parameters, alphas); + PowPolynomial pow_polynomial({ 2 }, /*log_num_monomials=*/1); + Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters; + Fun::UnivariateRelationParameters optimised_univariate_relation_parameters; + auto result = Fun::compute_combiner_no_optimistic_skipping( + instances, pow_polynomial, univariate_relation_parameters, alphas); + auto optimised_result = + Fun::compute_combiner(instances, pow_polynomial, optimised_univariate_relation_parameters, alphas); auto expected_result = Univariate(std::array{ 0, 0, 12, 36, 72, 120, 180, 252, 336, 432, 540, 660 }); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp index 0f9b09079ffe..60d91f22ac24 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -11,9 +11,9 @@ template class ProtogalaxyProver_ { using FF = typename ProverInstances_::Flavor::FF; static constexpr size_t NUM_INSTANCES = ProverInstances_::NUM; using CombinerQuotient = Univariate; - using TupleOfTuplesOfUnivariatesNoOptimisticSkipping = - typename Flavor::template ProtogalaxyTupleOfTuplesOfUnivariatesNoOptimisticSkipping; using TupleOfTuplesOfUnivariates = typename Flavor::template ProtogalaxyTupleOfTuplesOfUnivariates; + using OptimisedTupleOfTuplesOfUnivariates = + typename Flavor::template OptimisedProtogalaxyTupleOfTuplesOfUnivariates; using UnivariateRelationParameters = bb::RelationParameters>; using UnivariateRelationSeparator = @@ -40,16 +40,12 @@ template class ProtogalaxyProver_ { std::shared_ptr commitment_key; State state; - ProtogalaxyProver_() = default; - ProtogalaxyProver_(const std::vector>& insts) + ProtoGalaxyProver_() = default; + ProtoGalaxyProver_(const std::vector>& insts) : instances(ProverInstances_(insts)) // TODO(https://github.com/AztecProtocol/barretenberg/issues/878) , commitment_key(instances[1]->proving_key.commitment_key){}; - // Returns the accumulator, which is the first element in ProverInstances. The accumulator is assumed to have the - // FoldingParameters set and be the result of a previous round of folding. - std::shared_ptr get_accumulator() { return instances[0]; } - /** * @brief For each instance produced by a circuit, prior to folding, we need to complete the computation of its * prover polynomials, commit to witnesses and generate the relation parameters as well as send the public data ϕ of @@ -106,5 +102,49 @@ template class ProtogalaxyProver_ { * accumulator was computed correctly. */ BB_PROFILE FoldingResult prove(); + + // Returns the accumulator, which is the first element in ProverInstances. The accumulator is assumed to have the + // FoldingParameters set and be the result of a previous round of folding. + std::shared_ptr get_accumulator() { return instances[0]; } + + /** + * @brief Create inputs to folding protocol (an Oink interaction). + * @details Finalise the prover instances that will be folded: complete computation of all the witness polynomials + * and compute commitments. Send commitments to the verifier and retrieve challenges. + */ + void run_oink_prover_on_each_instance(); + + /** + * @brief Steps 2 - 5 of the paper. + * @details Compute perturbator (F polynomial in paper). Send all but the constant coefficient to verifier. + * + * @param accumulator + * @return std::tuple, Polynomial> deltas, perturbator + */ + std::tuple, Polynomial> perturbator_round(const std::shared_ptr& accumulator); + + /** + * @brief Steps 6 - 11 of the paper. + * @details Compute combiner (G polynomial in the paper) and then its quotient (K polynomial), whose coefficient + * will be sent to the verifier. + */ + /*gate_challenges, alphas, optimised_relation_parameters, perturbator_evaluation, combiner_quotient */ + std::tuple, UnivariateRelationSeparator, UnivariateRelationParameters, FF, CombinerQuotient> + combiner_quotient_round(const std::vector& gate_challenges, + const std::vector& deltas, + const ProverInstances_& instances); + + /** + * @brief Steps 12 - 13 of the paper plus the prover folding work. + * @details Compute \f$ e^* \f$ plus, then update the prover accumulator by taking a Lagrange-linear combination of + * the current accumulator and the instances to be folded. In our mental model, we are doing a scalar multipliation + * of matrices whose columns are polynomials, as well as taking similar linear combinations of the relation + * parameters. + */ + FoldingResult update_target_sum_and_fold(const ProverInstances_& instances, + const CombinerQuotient& combiner_quotient, + const UnivariateRelationSeparator& alphas, + const UnivariateRelationParameters& univariate_relation_parameters, + const FF& perturbator_evaluation); }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp index 2c0c49d79caf..b4e1b04d46d1 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp @@ -16,110 +16,15 @@ void ProtogalaxyProver_::run_oink_prover_on_instance(std::share oink_prover.prove(); } -template void ProtogalaxyProver_::run_oink_prover_on_each_instance() -{ - BB_OP_COUNT_TIME_NAME("ProtogalaxyProver_::run_oink_prover_on_each_instance"); - auto idx = 0; - auto& instance = instances[0]; - auto domain_separator = std::to_string(idx); - - if (!instance->is_accumulator) { - run_oink_prover_on_instance(instance, domain_separator); - instance->target_sum = 0; - instance->gate_challenges = std::vector(instance->proving_key.log_circuit_size, 0); - } - - idx++; - - for (auto it = instances.begin() + 1; it != instances.end(); it++, idx++) { - auto instance = *it; - auto domain_separator = std::to_string(idx); - run_oink_prover_on_instance(instance, domain_separator); - } - - state.accumulator = instances[0]; -}; - template -std::tuple, Polynomial> -ProtogalaxyProver_::perturbator_round( - const std::shared_ptr& accumulator) -{ - BB_OP_COUNT_TIME_NAME("ProtogalaxyProver_::perturbator_round"); - - using Fun = ProtogalaxyProverInternal; - - const FF delta = transcript->template get_challenge("delta"); - const std::vector deltas = compute_round_challenge_pows(accumulator->proving_key.log_circuit_size, delta); - // An honest prover with valid initial instances computes that the perturbator is 0 in the first round - const Polynomial perturbator = accumulator->is_accumulator - ? Fun::compute_perturbator(accumulator, deltas) - : Polynomial(accumulator->proving_key.log_circuit_size + 1); - // Prover doesn't send the constant coefficient of F because this is supposed to be equal to the target sum of - // the accumulator which the folding verifier has from the previous iteration. - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1087): Verifier circuit for first IVC step is - // different - if (accumulator->is_accumulator) { - for (size_t idx = 1; idx <= accumulator->proving_key.log_circuit_size; idx++) { - transcript->send_to_verifier("perturbator_" + std::to_string(idx), perturbator[idx]); - } - } - - return std::make_tuple(deltas, perturbator); -}; - -template -std::tuple, - typename ProtogalaxyProver_::UnivariateRelationSeparator, - typename ProtogalaxyProver_::UnivariateRelationParameters, - typename ProverInstances::Flavor::FF, - typename ProtogalaxyProver_::CombinerQuotient> -ProtogalaxyProver_::combiner_quotient_round(const std::vector& gate_challenges, - const std::vector& deltas, - const ProverInstances& instances) -{ - BB_OP_COUNT_TIME_NAME("ProtogalaxyProver_::combiner_quotient_round"); - - using Fun = ProtogalaxyProverInternal; - - const FF perturbator_challenge = transcript->template get_challenge("perturbator_challenge"); - - const std::vector updated_gate_challenges = - update_gate_challenges(perturbator_challenge, gate_challenges, deltas); - const UnivariateRelationSeparator alphas = Fun::compute_and_extend_alphas(instances); - const GateSeparatorPolynomial gate_separators{ updated_gate_challenges, - instances[0]->proving_key.log_circuit_size }; - const UnivariateRelationParameters relation_parameters = - Fun::template compute_extended_relation_parameters(instances); - - TupleOfTuplesOfUnivariates accumulators; - auto combiner = Fun::compute_combiner(instances, gate_separators, relation_parameters, alphas, accumulators); - - const FF perturbator_evaluation = state.perturbator.evaluate(perturbator_challenge); - const CombinerQuotient combiner_quotient = Fun::compute_combiner_quotient(perturbator_evaluation, combiner); - - for (size_t idx = ProverInstances::NUM; idx < ProverInstances::BATCHED_EXTENDED_LENGTH; idx++) { - transcript->send_to_verifier("combiner_quotient_" + std::to_string(idx), combiner_quotient.value_at(idx)); - } - - return std::make_tuple( - updated_gate_challenges, alphas, relation_parameters, perturbator_evaluation, combiner_quotient); -} - -/** - * @brief Given the challenge \gamma, compute Z(\gamma) and {L_0(\gamma),L_1(\gamma)} - * TODO(https://github.com/AztecProtocol/barretenberg/issues/764): Generalize the vanishing polynomial formula - * and the computation of Lagrange basis for k instances - */ -template -FoldingResult ProtogalaxyProver_::update_target_sum_and_fold( +FoldingResult ProtoGalaxyProver_::update_target_sum_and_fold( const ProverInstances& instances, const CombinerQuotient& combiner_quotient, const UnivariateRelationSeparator& alphas, const UnivariateRelationParameters& univariate_relation_parameters, const FF& perturbator_evaluation) { - BB_OP_COUNT_TIME_NAME("ProtogalaxyProver_::update_target_sum_and_fold"); + BB_OP_COUNT_TIME_NAME("ProtoGalaxyProver_::update_target_sum_and_fold"); using Fun = ProtogalaxyProverInternal; const FF combiner_challenge = transcript->template get_challenge("combiner_quotient_challenge"); @@ -161,6 +66,30 @@ FoldingResult ProtogalaxyProver_ void ProtoGalaxyProver_::run_oink_prover_on_each_instance() +{ + BB_OP_COUNT_TIME_NAME("ProtoGalaxyProver_::run_oink_prover_on_each_instance"); + auto idx = 0; + auto& instance = instances[0]; + auto domain_separator = std::to_string(idx); + + if (!instance->is_accumulator) { + run_oink_prover_on_instance(instance, domain_separator); + instance->target_sum = 0; + instance->gate_challenges = std::vector(instance->proving_key.log_circuit_size, 0); + } + + idx++; + + for (auto it = instances.begin() + 1; it != instances.end(); it++, idx++) { + auto instance = *it; + auto domain_separator = std::to_string(idx); + run_oink_prover_on_instance(instance, domain_separator); + } + + state.accumulator = instances[0]; +}; + template std::tuple, Polynomial> ProtoGalaxyProver_::perturbator_round( diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_internal.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_internal.hpp index 8767b4e076b0..c6e7224ec02a 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_internal.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_internal.hpp @@ -316,7 +316,7 @@ template class ProtogalaxyProverInternal { constexpr size_t skip_count = skip_zero_computations ? ProverInstances::NUM - 1 : 0; extend_univariates(extended_univariates[thread_idx], instances, idx); - const FF pow_challenge = gate_separators[idx]; + const 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. Moreover, linear-dependent relations that act over the @@ -346,21 +346,21 @@ template class ProtogalaxyProverInternal { */ static ExtendedUnivariateWithRandomization compute_combiner_no_optimistic_skipping( const ProverInstances& instances, - const GateSeparatorPolynomial& gate_separators, + const PowPolynomial& pow_betas, const UnivariateRelationParametersNoOptimisticSkipping& relation_parameters, const UnivariateRelationSeparator& alphas) { - TupleOfTuplesOfUnivariatesNoOptimisticSkipping accumulators; - return compute_combiner(instances, gate_separators, relation_parameters, alphas, accumulators); + TupleOfTuplesOfUnivariates accumulators; + return compute_combiner(instances, pow_betas, relation_parameters, alphas, accumulators); } static ExtendedUnivariateWithRandomization compute_combiner(const ProverInstances& instances, - const GateSeparatorPolynomial& gate_separators, + const PowPolynomial& pow_betas, const UnivariateRelationParameters& relation_parameters, const UnivariateRelationSeparator& alphas) { - TupleOfTuplesOfUnivariates accumulators; - return compute_combiner(instances, gate_separators, relation_parameters, alphas, accumulators); + OptimisedTupleOfTuplesOfUnivariates accumulators; + return compute_combiner(instances, pow_betas, relation_parameters, alphas, accumulators); } /** @@ -379,8 +379,8 @@ template class ProtogalaxyProverInternal { } const auto deoptimise = [&](auto& element) { - auto& element_with_skipping = std::get(std::get(tup)); - element = element_with_skipping.convert(); + auto& optimised_element = std::get(std::get(tup)); + element = optimised_element.convert(); }; TupleOfTuplesOfUnivariatesNoOptimisticSkipping result; @@ -388,9 +388,8 @@ template class ProtogalaxyProverInternal { return result; } - static ExtendedUnivariateWithRandomization batch_over_relations( - TupleOfTuplesOfUnivariatesNoOptimisticSkipping& univariate_accumulators, - const UnivariateRelationSeparator& alpha) + static ExtendedUnivariateWithRandomization batch_over_relations(TupleOfTuplesOfUnivariates& univariate_accumulators, + const UnivariateRelationSeparator& alpha) { auto result = std::get<0>(std::get<0>(univariate_accumulators)) .template extend_to();