diff --git a/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp b/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp index 5d4e53a8c1..54b571021a 100644 --- a/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp +++ b/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp @@ -126,24 +126,29 @@ TYPED_TEST(BilinearAccumulationTest, GeminiShplonkKzgWithShift) const Fr r_challenge = prover_transcript.get_challenge("Gemini:r"); - auto gemini_prover_output = + const auto [gemini_opening_pairs, gemini_witnesses] = Gemini::compute_fold_polynomial_evaluations(mle_opening_point, std::move(fold_polynomials), r_challenge); for (size_t l = 0; l < log_n; ++l) { std::string label = "Gemini:a_" + std::to_string(l); - const auto& evaluation = gemini_prover_output.opening_pairs[l + 1].evaluation; + const auto& evaluation = gemini_opening_pairs[l + 1].evaluation; prover_transcript.send_to_verifier(label, evaluation); } // Shplonk prover output: // - opening pair: (z_challenge, 0) // - witness: polynomial Q - Q_z - auto shplonk_prover_output = Shplonk::reduce_prove( - this->ck(), gemini_prover_output.opening_pairs, gemini_prover_output.witnesses, prover_transcript); + const Fr nu_challenge = prover_transcript.get_challenge("Shplonk:nu"); + auto batched_quotient_Q = Shplonk::compute_batched_quotient(gemini_opening_pairs, gemini_witnesses, nu_challenge); + prover_transcript.send_to_verifier("Shplonk:Q", this->ck()->commit(batched_quotient_Q)); + + const Fr z_challenge = prover_transcript.get_challenge("Shplonk:z"); + const auto [shplonk_opening_pair, shplonk_witness] = Shplonk::compute_partially_evaluated_batched_quotient( + gemini_opening_pairs, gemini_witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); // KZG prover: // - Adds commitment [W] to transcript - KZG::reduce_prove(this->ck(), shplonk_prover_output.opening_pair, shplonk_prover_output.witness, prover_transcript); + KZG::reduce_prove(this->ck(), shplonk_opening_pair, shplonk_witness, prover_transcript); // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation) diff --git a/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.test.cpp b/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.test.cpp index 072b665e8c..059c44fd98 100644 --- a/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.test.cpp +++ b/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.test.cpp @@ -45,8 +45,13 @@ TYPED_TEST(ShplonkTest, ShplonkSimple) std::vector polynomials = { poly1, poly2 }; // Execute the shplonk prover functionality - const auto [prover_opening_pair, shplonk_prover_witness] = - Shplonk::reduce_prove(this->ck(), opening_pairs, polynomials, prover_transcript); + const Fr nu_challenge = prover_transcript.get_challenge("Shplonk:nu"); + auto batched_quotient_Q = Shplonk::compute_batched_quotient(opening_pairs, polynomials, nu_challenge); + prover_transcript.send_to_verifier("Shplonk:Q", this->ck()->commit(batched_quotient_Q)); + + const Fr z_challenge = prover_transcript.get_challenge("Shplonk:z"); + const auto [prover_opening_pair, shplonk_prover_witness] = Shplonk::compute_partially_evaluated_batched_quotient( + opening_pairs, polynomials, std::move(batched_quotient_Q), nu_challenge, z_challenge); // An intermediate check to confirm the opening of the shplonk prover witness Q this->verify_opening_pair(prover_opening_pair, shplonk_prover_witness); diff --git a/cpp/src/barretenberg/honk/pcs/shplonk/shplonk_single.hpp b/cpp/src/barretenberg/honk/pcs/shplonk/shplonk_single.hpp index 099e73962a..36c3567185 100644 --- a/cpp/src/barretenberg/honk/pcs/shplonk/shplonk_single.hpp +++ b/cpp/src/barretenberg/honk/pcs/shplonk/shplonk_single.hpp @@ -22,24 +22,17 @@ template class SingleBatchOpeningScheme { public: /** - * @brief Batches several single-point 'OpeningClaim' into a single 'OpeningClaim' suitable for - * a univariate polynomial opening scheme. + * @brief Compute batched quotient polynomial Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ ) * - * @param ck CommitmentKey * @param opening_pairs list of opening pairs (xⱼ, vⱼ) for a witness polynomial fⱼ(X), s.t. fⱼ(xⱼ) = vⱼ. * @param witness_polynomials list of polynomials fⱼ(X). - * @param transcript - * @return Output{OpeningClaim, WitnessPolynomial, Proof} + * @param nu + * @return Polynomial Q(X) */ - static ProverOutput reduce_prove(std::shared_ptr ck, - std::span> opening_pairs, - std::span witness_polynomials, - ProverTranscript& transcript) + static Polynomial compute_batched_quotient(std::span> opening_pairs, + std::span witness_polynomials, + const Fr& nu) { - Fr nu = transcript.get_challenge("Shplonk:nu"); - - const size_t num_opening_pairs = opening_pairs.size(); - // Find n, the maximum size of all polynomials fⱼ(X) size_t max_poly_size{ 0 }; for (const auto& poly : witness_polynomials) { @@ -50,7 +43,7 @@ template class SingleBatchOpeningScheme { Polynomial tmp(max_poly_size); Fr current_nu = Fr::one(); - for (size_t j = 0; j < num_opening_pairs; ++j) { + for (size_t j = 0; j < opening_pairs.size(); ++j) { // (Cⱼ, xⱼ, vⱼ) const auto& [challenge, evaluation] = opening_pairs[j]; @@ -63,12 +56,28 @@ template class SingleBatchOpeningScheme { current_nu *= nu; } - // commit to Q(X) and add [Q] to the transcript - auto Q_commitment = ck->commit(Q); - transcript.send_to_verifier("Shplonk:Q", Q_commitment); + // Return batched quotient polynomial Q(X) + return Q; + }; - // generate random evaluation challenge zeta_challenge - const Fr z_challenge = transcript.get_challenge("Shplonk:z"); + /** + * @brief Compute partially evaluated batched quotient polynomial difference Q(X) - Q_z(X) + * + * @param opening_pairs list of opening pairs (xⱼ, vⱼ) for a witness polynomial fⱼ(X), s.t. fⱼ(xⱼ) = vⱼ. + * @param witness_polynomials list of polynomials fⱼ(X). + * @param batched_quotient_Q Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ ) + * @param nu_challenge + * @param z_challenge + * @return Output{OpeningPair, Polynomial} + */ + static ProverOutput compute_partially_evaluated_batched_quotient( + std::span> opening_pairs, + std::span witness_polynomials, + Polynomial&& batched_quotient_Q, + const Fr& nu_challenge, + const Fr& z_challenge) + { + const size_t num_opening_pairs = opening_pairs.size(); // {ẑⱼ(r)}ⱼ , where ẑⱼ(r) = 1/zⱼ(r) = 1/(r - xⱼ) std::vector inverse_vanishing_evals; @@ -80,10 +89,11 @@ template class SingleBatchOpeningScheme { // G(X) = Q(X) - Q_z(X) = Q(X) - ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ ), // s.t. G(r) = 0 - Polynomial& G = Q; + Polynomial G(std::move(batched_quotient_Q)); // G(X) = Q(X) // G₀ = ∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ) - current_nu = Fr::one(); + Fr current_nu = Fr::one(); + Polynomial tmp(G.size()); for (size_t j = 0; j < num_opening_pairs; ++j) { // (Cⱼ, xⱼ, vⱼ) const auto& [challenge, evaluation] = opening_pairs[j]; @@ -96,7 +106,7 @@ template class SingleBatchOpeningScheme { // G -= ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ ) G.add_scaled(tmp, -scaling_factor); - current_nu *= nu; + current_nu *= nu_challenge; } // Return opening pair (z, 0) and polynomial G(X) = Q(X) - Q_z(X) diff --git a/cpp/src/barretenberg/honk/proof_system/prover.cpp b/cpp/src/barretenberg/honk/proof_system/prover.cpp index 7dbd085f40..3c93e9964b 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/prover.cpp @@ -239,13 +239,28 @@ template void Prover::execute_pcs_evaluation_round /** * - Do Fiat-Shamir to get "nu" challenge. * - Compute commitment [Q]_1 + * */ +template void Prover::execute_shplonk_batched_quotient_round() +{ + nu_challenge = transcript.get_challenge("Shplonk:nu"); + + batched_quotient_Q = + Shplonk::compute_batched_quotient(gemini_output.opening_pairs, gemini_output.witnesses, nu_challenge); + + // commit to Q(X) and add [Q] to the transcript + auto Q_commitment = commitment_key->commit(batched_quotient_Q); + transcript.send_to_verifier("Shplonk:Q", Q_commitment); +} + +/** * - Do Fiat-Shamir to get "z" challenge. * - Compute polynomial Q(X) - Q_z(X) * */ -template void Prover::execute_shplonk_round() +template void Prover::execute_shplonk_partial_evaluation_round() { - shplonk_output = - Shplonk::reduce_prove(commitment_key, gemini_output.opening_pairs, gemini_output.witnesses, transcript); + const Fr z_challenge = transcript.get_challenge("Shplonk:z"); + shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient( + gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); } /** @@ -302,7 +317,8 @@ template plonk::proof& Prover::construct_proof() // Fiat-Shamir: nu // Compute Shplonk batched quotient commitment - execute_shplonk_round(); + execute_shplonk_batched_quotient_round(); + execute_shplonk_partial_evaluation_round(); // queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue // Fiat-Shamir: z diff --git a/cpp/src/barretenberg/honk/proof_system/prover.hpp b/cpp/src/barretenberg/honk/proof_system/prover.hpp index 43d2d27f38..cef92763f9 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/prover.hpp @@ -42,7 +42,8 @@ template class Prover { void execute_relation_check_rounds(); void execute_univariatization_round(); void execute_pcs_evaluation_round(); - void execute_shplonk_round(); + void execute_shplonk_batched_quotient_round(); + void execute_shplonk_partial_evaluation_round(); void execute_kzg_round(); void compute_wire_commitments(); @@ -71,6 +72,9 @@ template class Prover { // Container for d + 1 Fold polynomials produced by Gemini std::vector fold_polynomials; + Polynomial batched_quotient_Q; + Fr nu_challenge; + // Honk only needs a small portion of the functionality but may be fine to use existing work_queue // NOTE: this is not currently in use, but it may well be used in the future. // TODO(Adrian): Uncomment when we need this again.