From 24bbaca06b1a3b6c913afcdd0a7c3ae76f5ad14d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 9 Oct 2023 19:04:18 +0000 Subject: [PATCH 1/7] ZM integrated into native honk, tests passing --- .../honk/pcs/zeromorph/zeromorph.hpp | 35 +++- .../honk/proof_system/ultra_prover.cpp | 155 +++++++----------- .../honk/proof_system/ultra_prover.hpp | 23 +-- .../honk/proof_system/ultra_verifier.cpp | 90 +++++----- 4 files changed, 149 insertions(+), 154 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp index d9dda108c65..23badad5c49 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp @@ -7,6 +7,24 @@ */ namespace proof_system::honk::pcs::zeromorph { +/** + * @brief Compute powers of a given challenge + * + * @tparam Fr + * @param challenge + * @param num_powers + * @return std::vector + */ +template inline std::vector powers_of_challenge(const Fr challenge, const size_t num_powers) +{ + std::vector challenge_powers = { Fr(1), challenge }; + challenge_powers.reserve(num_powers); + for (size_t j = 2; j < num_powers; j++) { + challenge_powers.emplace_back(challenge_powers[j - 1] * challenge); + } + return challenge_powers; +}; + /** * @brief Prover for ZeroMorph multilinear PCS * @@ -19,7 +37,7 @@ template class ZeroMorphProver_ { // TODO(#742): Set this N_max to be the number of G1 elements in the mocked zeromorph SRS once it's in place. (Then, // eventually, set it based on the real SRS). - static const size_t N_max = 1 << 10; + static const size_t N_max = 1 << 22; public: /** @@ -266,6 +284,21 @@ template class ZeroMorphVerifier_ { using Commitment = typename Curve::AffineElement; public: + /** + * @brief Compute commitment C_{v,x} = v * x * \Phi_n(x) * [1]_1 + * + * @param v_evaluation + * @param x_challenge + * @param N + * @return Commitment + */ + static Commitment compute_C_v_x(Fr v_evaluation, Fr x_challenge, size_t N) + { + // Phi_n(x) = (x^N - 1) / (x - 1) + auto phi_n_x = (x_challenge.pow(N) - 1) / (x_challenge - 1); + return Commitment::one() * v_evaluation * x_challenge * phi_n_x; + } + /** * @brief Compute commitment to partially evaluated batched lifted degree quotient identity * @details Compute commitment C_{\zeta_x} = [\zeta_x]_1 using homomorphicity: diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 887bb096a2a..2afe5464848 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -1,9 +1,6 @@ #include "ultra_prover.hpp" -#include "barretenberg/honk/pcs/claim.hpp" #include "barretenberg/honk/sumcheck/sumcheck.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" -#include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/transcript/transcript_wrappers.hpp" namespace proof_system::honk { @@ -115,95 +112,83 @@ template void UltraProver_::execute_relation_check_ * - Compute d+1 Fold polynomials and their evaluations. * * */ -template void UltraProver_::execute_univariatization_round() +template void UltraProver_::execute_zeromorph_rounds() { const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + const size_t circuit_size = instance->proving_key->circuit_size; // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ FF rho = transcript.get_challenge("rho"); - std::vector rhos = pcs::gemini::powers_of_rho(rho, NUM_POLYNOMIALS); - - // Batch the unshifted polynomials and the to-be-shifted polynomials using ρ - Polynomial batched_poly_unshifted(instance->proving_key->circuit_size); // batched unshifted polynomials - size_t poly_idx = 0; // TODO(https://github.com/AztecProtocol/barretenberg/issues/391) zip - for (auto& unshifted_poly : instance->prover_polynomials.get_unshifted()) { - batched_poly_unshifted.add_scaled(unshifted_poly, rhos[poly_idx]); + std::vector rhos = pcs::zeromorph::powers_of_challenge(rho, NUM_POLYNOMIALS); + + // Extract challenge u and claimed multilinear evaluations from Sumcheck output + std::span u_challenge = sumcheck_output.challenge; + std::span claimed_evaluations = sumcheck_output.claimed_evaluations; + size_t log_N = u_challenge.size(); + + // Compute batching of f_i and g_i polynomials: sum_{i=0}^{m-1}\alpha^i*f_i and + // sum_{i=0}^{l-1}\alpha^{m+i}*h_i, and also batched evaluation v = sum_{i=0}^{m-1}\alpha^i*f_i(u) + + // sum_{i=0}^{l-1}\alpha^{m+i}*h_i(u). + auto batched_evaluation = FF(0); + Polynomial f_batched(circuit_size); // batched unshifted polynomials + size_t poly_idx = 0; // TODO(#391) zip + for (auto& f_polynomial : instance->prover_polynomials.get_unshifted()) { + f_batched.add_scaled(f_polynomial, rhos[poly_idx]); + batched_evaluation += rhos[poly_idx] * claimed_evaluations[poly_idx]; ++poly_idx; } - Polynomial batched_poly_to_be_shifted(instance->proving_key->circuit_size); // batched to-be-shifted polynomials - for (auto& to_be_shifted_poly : instance->prover_polynomials.get_to_be_shifted()) { - batched_poly_to_be_shifted.add_scaled(to_be_shifted_poly, rhos[poly_idx]); + Polynomial g_batched(circuit_size); // batched to-be-shifted polynomials + for (auto& g_polynomial : instance->prover_polynomials.get_to_be_shifted()) { + g_batched.add_scaled(g_polynomial, rhos[poly_idx]); + batched_evaluation += rhos[poly_idx] * claimed_evaluations[poly_idx]; ++poly_idx; }; - // Compute d-1 polynomials Fold^(i), i = 1, ..., d-1. - gemini_polynomials = Gemini::compute_gemini_polynomials( - sumcheck_output.challenge, std::move(batched_poly_unshifted), std::move(batched_poly_to_be_shifted)); + // The new f is f_batched + g_batched.shifted() = f_batched + h_batched + auto f_polynomial = f_batched; + f_polynomial += g_batched.shifted(); - // Compute and add to trasnscript the commitments [Fold^(i)], i = 1, ..., d-1 - for (size_t l = 0; l < instance->proving_key->log_circuit_size - 1; ++l) { - queue.add_commitment(gemini_polynomials[l + 2], "Gemini:FOLD_" + std::to_string(l + 1)); - } -} + // Compute the multilinear quotients q_k = q_k(X_0, ..., X_{k-1}) + auto quotients = ZeroMorph::compute_multilinear_quotients(f_polynomial, u_challenge); -/** - * - Do Fiat-Shamir to get "r" challenge - * - Compute remaining two partially evaluated Fold polynomials Fold_{r}^(0) and Fold_{-r}^(0). - * - Compute and aggregate opening pairs (challenge, evaluation) for each of d Fold polynomials. - * - Add d-many Fold evaluations a_i, i = 0, ..., d-1 to the transcript, excluding eval of Fold_{r}^(0) - * */ -template void UltraProver_::execute_pcs_evaluation_round() -{ - const FF r_challenge = transcript.get_challenge("Gemini:r"); - univariate_openings = Gemini::compute_fold_polynomial_evaluations( - sumcheck_output.challenge, std::move(gemini_polynomials), r_challenge); - - for (size_t l = 0; l < instance->proving_key->log_circuit_size; ++l) { - std::string label = "Gemini:a_" + std::to_string(l); - const auto& evaluation = univariate_openings.opening_pairs[l + 1].evaluation; - transcript.send_to_verifier(label, evaluation); + // Compute and send commitments C_{q_k} = [q_k], k = 0,...,d-1 + std::vector q_k_commitments; + q_k_commitments.reserve(log_N); + for (size_t idx = 0; idx < log_N; ++idx) { + q_k_commitments[idx] = pcs_commitment_key->commit(quotients[idx]); + std::string label = "ZM:C_q_" + std::to_string(idx); + transcript.send_to_verifier(label, q_k_commitments[idx]); } -} -/** - * - Do Fiat-Shamir to get "nu" challenge. - * - Compute commitment [Q]_1 - * */ -template void UltraProver_::execute_shplonk_batched_quotient_round() -{ - nu_challenge = transcript.get_challenge("Shplonk:nu"); + // Get challenge y + auto y_challenge = transcript.get_challenge("ZM:y"); - batched_quotient_Q = Shplonk::compute_batched_quotient( - univariate_openings.opening_pairs, univariate_openings.witnesses, nu_challenge); + // Compute the batched, lifted-degree quotient \hat{q} + auto batched_quotient = ZeroMorph::compute_batched_lifted_degree_quotient(quotients, y_challenge, circuit_size); - // commit to Q(X) and add [Q] to the transcript - queue.add_commitment(batched_quotient_Q, "Shplonk:Q"); -} + // Compute and send the commitment C_q = [\hat{q}] + auto q_commitment = pcs_commitment_key->commit(batched_quotient); + transcript.send_to_verifier("ZM:C_q", q_commitment); -/** - * - Do Fiat-Shamir to get "z" challenge. - * - Compute polynomial Q(X) - Q_z(X) - * */ -template void UltraProver_::execute_shplonk_partial_evaluation_round() -{ - const FF z_challenge = transcript.get_challenge("Shplonk:z"); + // Get challenges x and z + auto [x_challenge, z_challenge] = transcript.get_challenges("ZM:x", "ZM:z"); - shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient(univariate_openings.opening_pairs, - univariate_openings.witnesses, - std::move(batched_quotient_Q), - nu_challenge, - z_challenge); -} -/** - * - Compute final PCS opening proof: - * - For KZG, this is the quotient commitmecnt [W]_1 - * - For IPA, the vectors L and R - * */ -template void UltraProver_::execute_final_pcs_round() -{ - PCS::compute_opening_proof(pcs_commitment_key, shplonk_output.opening_pair, shplonk_output.witness, transcript); - // queue.add_commitment(quotient_W, "KZG:W"); + // Compute degree check polynomial \zeta partially evaluated at x + auto zeta_x = ZeroMorph::compute_partially_evaluated_degree_check_polynomial( + batched_quotient, quotients, y_challenge, x_challenge); + + // Compute ZeroMorph identity polynomial Z partially evaluated at x + auto Z_x = ZeroMorph::compute_partially_evaluated_zeromorph_identity_polynomial( + f_batched, g_batched, quotients, batched_evaluation, u_challenge, x_challenge); + + // Compute batched degree and ZM-identity quotient polynomial pi + auto pi_polynomial = + ZeroMorph::compute_batched_evaluation_and_degree_check_quotient(zeta_x, Z_x, x_challenge, z_challenge); + + // Compute and send proof commitment pi + auto pi_commitment = pcs_commitment_key->commit(pi_polynomial); + transcript.send_to_verifier("ZM:PI", pi_commitment); } template plonk::proof& UltraProver_::export_proof() @@ -234,27 +219,9 @@ template plonk::proof& UltraProver_::construct_proo // Run sumcheck subprotocol. execute_relation_check_rounds(); - // Fiat-Shamir: rho - // Compute Fold polynomials and their commitments. - execute_univariatization_round(); - queue.process_queue(); - - // Fiat-Shamir: r - // Compute Fold evaluations - execute_pcs_evaluation_round(); - - // Fiat-Shamir: nu - // Compute Shplonk batched quotient commitment Q - execute_shplonk_batched_quotient_round(); - queue.process_queue(); - - // Fiat-Shamir: z - // Compute partial evaluation Q_z - execute_shplonk_partial_evaluation_round(); - - // Fiat-Shamir: z - // Compute PCS opening proof (either KZG quotient commitment or IPA opening proof) - execute_final_pcs_round(); + // Fiat-Shamir: rho, y, x, z + // Execute Zeromorph multilinear PCS + execute_zeromorph_rounds(); return export_proof(); } diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp index 43388fa380a..19a70210890 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -3,8 +3,7 @@ #include "barretenberg/honk/flavor/ultra.hpp" #include "barretenberg/honk/flavor/ultra_grumpkin.hpp" #include "barretenberg/honk/instance/prover_instance.hpp" -#include "barretenberg/honk/pcs/gemini/gemini.hpp" -#include "barretenberg/honk/pcs/shplonk/shplonk.hpp" +#include "barretenberg/honk/pcs/zeromorph/zeromorph.hpp" #include "barretenberg/honk/proof_system/work_queue.hpp" #include "barretenberg/honk/sumcheck/sumcheck_output.hpp" #include "barretenberg/honk/transcript/transcript.hpp" @@ -16,7 +15,6 @@ namespace proof_system::honk { template class UltraProver_ { using FF = typename Flavor::FF; using Commitment = typename Flavor::Commitment; - using PCS = typename Flavor::PCS; using CommitmentKey = typename Flavor::CommitmentKey; using ProvingKey = typename Flavor::ProvingKey; using Polynomial = typename Flavor::Polynomial; @@ -24,7 +22,6 @@ template class UltraProver_ { using CommitmentLabels = typename Flavor::CommitmentLabels; using Curve = typename Flavor::Curve; using Instance = ProverInstance_; - using OpenPair = pcs::OpeningPair; public: explicit UltraProver_(std::shared_ptr); @@ -33,12 +30,7 @@ template class UltraProver_ { void execute_sorted_list_accumulator_round(); void execute_grand_product_computation_round(); void execute_relation_check_rounds(); - void execute_univariatization_round(); - void execute_pcs_evaluation_round(); - void execute_op_queue_transcript_aggregation_round(); - void execute_shplonk_batched_quotient_round(); - void execute_shplonk_partial_evaluation_round(); - void execute_final_pcs_round(); + void execute_zeromorph_rounds(); plonk::proof& export_proof(); plonk::proof& construct_proof(); @@ -50,12 +42,6 @@ template class UltraProver_ { CommitmentLabels commitment_labels; - // Container for d + 1 Fold polynomials produced by Gemini - std::vector gemini_polynomials; - - Polynomial batched_quotient_Q; // batched quotient poly computed by Shplonk - FF nu_challenge; // needed in both Shplonk rounds - Polynomial quotient_W; work_queue queue; @@ -63,12 +49,9 @@ template class UltraProver_ { std::shared_ptr instance; sumcheck::SumcheckOutput sumcheck_output; - pcs::gemini::ProverOutput univariate_openings; - pcs::shplonk::ProverOutput shplonk_output; std::shared_ptr pcs_commitment_key; - using Gemini = pcs::gemini::GeminiProver_; - using Shplonk = pcs::shplonk::ShplonkProver_; + using ZeroMorph = pcs::zeromorph::ZeroMorphProver_; private: plonk::proof proof; diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index 2b98a316108..c4f175f6483 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -1,7 +1,5 @@ #include "./ultra_verifier.hpp" -#include "barretenberg/honk/pcs/claim.hpp" -#include "barretenberg/honk/pcs/gemini/gemini.hpp" -#include "barretenberg/honk/pcs/shplonk/shplonk.hpp" +#include "barretenberg/honk/pcs/zeromorph/zeromorph.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" @@ -36,12 +34,9 @@ template UltraVerifier_& UltraVerifier_::opera template bool UltraVerifier_::verify_proof(const plonk::proof& proof) { using FF = typename Flavor::FF; - using GroupElement = typename Flavor::GroupElement; using Commitment = typename Flavor::Commitment; - using PCS = typename Flavor::PCS; using Curve = typename Flavor::Curve; - using Gemini = pcs::gemini::GeminiVerifier_; - using Shplonk = pcs::shplonk::ShplonkVerifier_; + using ZeroMorph = pcs::zeromorph::ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; @@ -56,6 +51,7 @@ template bool UltraVerifier_::verify_proof(const plonk const auto circuit_size = transcript.template receive_from_prover("circuit_size"); const auto public_input_size = transcript.template receive_from_prover("public_input_size"); const auto pub_inputs_offset = transcript.template receive_from_prover("pub_inputs_offset"); + const size_t log_circuit_size = numeric::get_msb(circuit_size); if (circuit_size != key->circuit_size) { return false; @@ -114,7 +110,7 @@ template bool UltraVerifier_::verify_proof(const plonk // Execute Sumcheck Verifier auto sumcheck = SumcheckVerifier(circuit_size); - auto [multivariate_challenge, purported_evaluations, sumcheck_verified] = + auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(relation_parameters, transcript); // If Sumcheck did not verify, return false @@ -122,53 +118,69 @@ template bool UltraVerifier_::verify_proof(const plonk return false; } - // Execute Gemini/Shplonk verification: - - // Construct inputs for Gemini verifier: - // - Multivariate opening point u = (u_0, ..., u_{d-1}) - // - batched unshifted and to-be-shifted polynomial commitments - auto batched_commitment_unshifted = GroupElement::zero(); - auto batched_commitment_to_be_shifted = GroupElement::zero(); + // Execute ZeroMorph rounds // Compute powers of batching challenge rho FF rho = transcript.get_challenge("rho"); - std::vector rhos = pcs::gemini::powers_of_rho(rho, Flavor::NUM_ALL_ENTITIES); + std::vector rhos = pcs::zeromorph::powers_of_challenge(rho, Flavor::NUM_ALL_ENTITIES); - // Compute batched multivariate evaluation - FF batched_evaluation = FF::zero(); + // Construct batched evaluation v = sum_{i=0}^{m-1}\alpha^i*v_i + sum_{i=0}^{l-1}\alpha^{m+i}*w_i + FF batched_evaluation = FF(0); size_t evaluation_idx = 0; - for (auto& value : purported_evaluations.get_unshifted_then_shifted()) { + for (auto& value : claimed_evaluations.get_unshifted_then_shifted()) { batched_evaluation += value * rhos[evaluation_idx]; ++evaluation_idx; } - // Construct batched commitment for NON-shifted polynomials - size_t commitment_idx = 0; - for (auto& commitment : commitments.get_unshifted()) { - batched_commitment_unshifted += commitment * rhos[commitment_idx]; - ++commitment_idx; + // Receive commitments [q_k] + std::vector C_q_k; + C_q_k.reserve(log_circuit_size); + for (size_t i = 0; i < log_circuit_size; ++i) { + C_q_k.emplace_back(transcript.template receive_from_prover("ZM:C_q_" + std::to_string(i))); } - // Construct batched commitment for to-be-shifted polynomials + // Challenge y + auto y_challenge = transcript.get_challenge("ZM:y"); + + // Receive commitment C_{q} + auto C_q = transcript.template receive_from_prover("ZM:C_q"); + + // Challenges x, z + auto [x_challenge, z_challenge] = transcript.get_challenges("ZM:x", "ZM:z"); + + // Compute commitment C_{v,x} = v * x * \Phi_n(x) * [1]_1 + auto C_v_x = ZeroMorph::compute_C_v_x(batched_evaluation, x_challenge, circuit_size); + + // Compute commitment C_{\zeta_x} + auto C_zeta_x = ZeroMorph::compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); + + std::vector f_commitments; + std::vector g_commitments; + for (auto& commitment : commitments.get_unshifted()) { + f_commitments.emplace_back(commitment); + } for (auto& commitment : commitments.get_to_be_shifted()) { - batched_commitment_to_be_shifted += commitment * rhos[commitment_idx]; - ++commitment_idx; + g_commitments.emplace_back(commitment); } - // Produce a Gemini claim consisting of: - // - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1 - // - d+1 evaluations a_0_pos, and a_l, l = 0:d-1 - auto univariate_opening_claims = Gemini::reduce_verification(multivariate_challenge, - batched_evaluation, - batched_commitment_unshifted, - batched_commitment_to_be_shifted, - transcript); + // Compute commitment C_{Z_x} + Commitment C_Z_x = + ZeroMorph::compute_C_Z_x(C_v_x, f_commitments, g_commitments, C_q_k, rho, x_challenge, multivariate_challenge); + + // Compute commitment C_{\zeta,Z} + auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; - // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) - auto shplonk_claim = Shplonk::reduce_verification(pcs_verification_key, univariate_opening_claims, transcript); + // Receive proof commitment \pi + auto C_pi = transcript.template receive_from_prover("ZM:PI"); - // Verify the Shplonk claim with KZG or IPA - auto verified = PCS::verify(pcs_verification_key, shplonk_claim, transcript); + // Construct inputs and perform pairing check to verify claimed evaluation + // Note: The pairing check (without the degree check component X^{N_max-N-1}) can be expressed naturally as + // e(C_{\zeta,Z}, [1]_2) = e(pi, [X - x]_2). This can be rearranged (e.g. see the plonk paper) as + // e(C_{\zeta,Z} - x*pi, [1]_2) * e(-pi, [X]_2) = 1, or + // e(P_0, [1]_2) * e(P_1, [X]_2) = 1 + auto P0 = C_zeta_Z + C_pi * x_challenge; + auto P1 = -C_pi; + auto verified = pcs_verification_key->pairing_check(P0, P1); return sumcheck_verified.value() && verified; } From fcf87d420f48ee6e97aa91aca8ce36bb20bebe8d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 9 Oct 2023 20:49:47 +0000 Subject: [PATCH 2/7] refactor verifier methods in prep for recursion --- .../honk/pcs/zeromorph/zeromorph.hpp | 77 ++++++++++++------- .../honk/pcs/zeromorph/zeromorph.test.cpp | 5 +- .../honk/proof_system/ultra_verifier.cpp | 7 +- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp index 23badad5c49..0832ff73397 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp @@ -284,21 +284,6 @@ template class ZeroMorphVerifier_ { using Commitment = typename Curve::AffineElement; public: - /** - * @brief Compute commitment C_{v,x} = v * x * \Phi_n(x) * [1]_1 - * - * @param v_evaluation - * @param x_challenge - * @param N - * @return Commitment - */ - static Commitment compute_C_v_x(Fr v_evaluation, Fr x_challenge, size_t N) - { - // Phi_n(x) = (x^N - 1) / (x - 1) - auto phi_n_x = (x_challenge.pow(N) - 1) / (x_challenge - 1); - return Commitment::one() * v_evaluation * x_challenge * phi_n_x; - } - /** * @brief Compute commitment to partially evaluated batched lifted degree quotient identity * @details Compute commitment C_{\zeta_x} = [\zeta_x]_1 using homomorphicity: @@ -316,7 +301,12 @@ template class ZeroMorphVerifier_ { size_t log_N = C_q_k.size(); size_t N = 1 << log_N; - auto result = C_q; + std::vector scalars; + std::vector commitments; + + scalars.emplace_back(Fr(1)); + commitments.emplace_back(C_q); + for (size_t k = 0; k < log_N; ++k) { auto deg_k = static_cast((1 << k) - 1); // Compute scalar y^k * x^{N - deg_k - 1} @@ -324,53 +314,66 @@ template class ZeroMorphVerifier_ { scalar *= x_challenge.pow(N - deg_k - 1); scalar *= Fr(-1); - result = result + C_q_k[k] * scalar; + scalars.emplace_back(scalar); + commitments.emplace_back(C_q_k[k]); + } + + if constexpr (Curve::is_stdlib_type) { + return Commitment::one(); + } else { + return batch_mul_native(commitments, scalars); } - return result; } /** * @brief Compute commitment to partially evaluated ZeroMorph identity Z * @details Compute commitment C_{Z_x} = [Z_x]_1 using homomorphicity: * - * C_{Z_x} = x * \sum_{i=0}^{m-1}\alpha^i*[f_i] + \sum_{i=0}^{l-1}\alpha^{m+i}*[g_i] - C_v_x + * C_{Z_x} = x * \sum_{i=0}^{m-1}\alpha^i*[f_i] + \sum_{i=0}^{l-1}\alpha^{m+i}*[g_i] - v * x * \Phi_n(x) * [1]_1 * - x * \sum_k (x^{2^k}\Phi_{n-k-1}(x^{2^{k-1}}) - u_k\Phi_{n-k}(x^{2^k})) * [q_k] * - * @param C_v_x v * x * \Phi_n(x) * [1]_1 * @param f_commitments Commitments to unshifted polynomials [f_i] * @param g_commitments Commitments to to-be-shifted polynomials [g_i] * @param C_q_k Commitments to q_k * @param alpha + * @param batched_evaluation \sum_{i=0}^{m-1} f_i(u) + \sum_{i=0}^{l-1} h_i(u) * @param x_challenge * @param u_challenge multilinear challenge * @return Commitment */ - static Commitment compute_C_Z_x(Commitment C_v_x, - std::vector& f_commitments, + static Commitment compute_C_Z_x(std::vector& f_commitments, std::vector& g_commitments, std::vector& C_q_k, Fr alpha, + Fr batched_evaluation, Fr x_challenge, std::vector u_challenge) { size_t log_N = C_q_k.size(); size_t N = 1 << log_N; + std::vector scalars; + std::vector commitments; + + // Phi_n(x) = (x^N - 1) / (x - 1) auto phi_numerator = x_challenge.pow(N) - 1; // x^N - 1 - // auto phi_n_x = phi_numerator / (x_challenge - 1); + auto phi_n_x = phi_numerator / (x_challenge - 1); + + // Add contribution -C_{v,x} = -v * x * \Phi_n(x) * [1]_1 + scalars.emplace_back(Fr(-1) * batched_evaluation * x_challenge * phi_n_x); + commitments.emplace_back(Commitment::one()); - Commitment result = -C_v_x; // initialize with -C_{v,x} auto alpha_pow = Fr(1); // Add contribution x * \sum_{i=0}^{m-1} [f_i] for (auto& commitment : f_commitments) { - auto scalar = x_challenge * alpha_pow; - result = result + (commitment * scalar); + scalars.emplace_back(x_challenge * alpha_pow); + commitments.emplace_back(commitment); alpha_pow *= alpha; } // Add contribution \sum_{i=0}^{l-1} [g_i] for (auto& commitment : g_commitments) { - auto scalar = alpha_pow; - result = result + (commitment * scalar); + scalars.emplace_back(alpha_pow); + commitments.emplace_back(commitment); alpha_pow *= alpha; } @@ -390,8 +393,24 @@ template class ZeroMorphVerifier_ { scalar *= x_challenge; scalar *= Fr(-1); - result = result + C_q_k[k] * scalar; + scalars.emplace_back(scalar); + commitments.emplace_back(C_q_k[k]); } + + if constexpr (Curve::is_stdlib_type) { + return Commitment::one(); + } else { + return batch_mul_native(commitments, scalars); + } + } + + static Commitment batch_mul_native(std::vector points, std::vector scalars) + { + auto result = points[0] * scalars[0]; + for (size_t idx = 1; idx < scalars.size(); ++idx) { + result = result + points[idx] * scalars[idx]; + } + return result; } }; diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp index 8424491ba91..79ccd73b390 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp @@ -183,15 +183,12 @@ template class ZeroMorphTest : public CommitmentTest { // Challenges x, z auto [x_challenge, z_challenge] = verifier_transcript.get_challenges("ZM:x", "ZM:z"); - // Compute commitment C_{v,x} = v * x * \Phi_n(x) * [1]_1 - auto C_v_x = Commitment::one() * v_evaluation * x_challenge * this->Phi(x_challenge, log_N); - // Compute commitment C_{\zeta_x} auto C_zeta_x = ZeroMorphVerifier::compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); // Compute commitment C_{Z_x} Commitment C_Z_x = ZeroMorphVerifier::compute_C_Z_x( - C_v_x, f_commitments, g_commitments, C_q_k, alpha, x_challenge, u_challenge); + f_commitments, g_commitments, C_q_k, alpha, v_evaluation, x_challenge, u_challenge); // Compute commitment C_{\zeta,Z} auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index c4f175f6483..f9d893e7bcc 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -148,9 +148,6 @@ template bool UltraVerifier_::verify_proof(const plonk // Challenges x, z auto [x_challenge, z_challenge] = transcript.get_challenges("ZM:x", "ZM:z"); - // Compute commitment C_{v,x} = v * x * \Phi_n(x) * [1]_1 - auto C_v_x = ZeroMorph::compute_C_v_x(batched_evaluation, x_challenge, circuit_size); - // Compute commitment C_{\zeta_x} auto C_zeta_x = ZeroMorph::compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); @@ -164,8 +161,8 @@ template bool UltraVerifier_::verify_proof(const plonk } // Compute commitment C_{Z_x} - Commitment C_Z_x = - ZeroMorph::compute_C_Z_x(C_v_x, f_commitments, g_commitments, C_q_k, rho, x_challenge, multivariate_challenge); + Commitment C_Z_x = ZeroMorph::compute_C_Z_x( + f_commitments, g_commitments, C_q_k, rho, batched_evaluation, x_challenge, multivariate_challenge); // Compute commitment C_{\zeta,Z} auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; From 7d379c3f83c3ceecdc8c4282b33bd9983f4dd07a Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 9 Oct 2023 22:03:53 +0000 Subject: [PATCH 3/7] recursive verifier tests passing with ZM --- .../honk/pcs/zeromorph/zeromorph.hpp | 23 +++- .../recursion/honk/transcript/transcript.hpp | 2 +- .../verifier/ultra_recursive_verifier.cpp | 119 +++++++----------- 3 files changed, 61 insertions(+), 83 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp index 0832ff73397..7b7596cf34b 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp @@ -282,6 +282,7 @@ template class ZeroMorphProver_ { template class ZeroMorphVerifier_ { using Fr = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; + using GroupElement = typename Curve::Element; public: /** @@ -304,7 +305,12 @@ template class ZeroMorphVerifier_ { std::vector scalars; std::vector commitments; - scalars.emplace_back(Fr(1)); + if constexpr (Curve::is_stdlib_type) { + auto builder = x_challenge.get_context(); + scalars.emplace_back(Fr(builder, 1)); + } else { + scalars.emplace_back(Fr(1)); + } commitments.emplace_back(C_q); for (size_t k = 0; k < log_N; ++k) { @@ -319,7 +325,7 @@ template class ZeroMorphVerifier_ { } if constexpr (Curve::is_stdlib_type) { - return Commitment::one(); + return GroupElement::batch_mul(commitments, scalars); } else { return batch_mul_native(commitments, scalars); } @@ -359,9 +365,14 @@ template class ZeroMorphVerifier_ { auto phi_numerator = x_challenge.pow(N) - 1; // x^N - 1 auto phi_n_x = phi_numerator / (x_challenge - 1); - // Add contribution -C_{v,x} = -v * x * \Phi_n(x) * [1]_1 - scalars.emplace_back(Fr(-1) * batched_evaluation * x_challenge * phi_n_x); - commitments.emplace_back(Commitment::one()); + if constexpr (Curve::is_stdlib_type) { + auto builder = x_challenge.get_context(); + scalars.emplace_back(Fr(builder, -1) * batched_evaluation * x_challenge * phi_n_x); + commitments.emplace_back(Commitment::one(builder)); + } else { + scalars.emplace_back(Fr(-1) * batched_evaluation * x_challenge * phi_n_x); + commitments.emplace_back(Commitment::one()); + } auto alpha_pow = Fr(1); // Add contribution x * \sum_{i=0}^{m-1} [f_i] @@ -398,7 +409,7 @@ template class ZeroMorphVerifier_ { } if constexpr (Curve::is_stdlib_type) { - return Commitment::one(); + return GroupElement::batch_mul(commitments, scalars); } else { return batch_mul_native(commitments, scalars); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp index f02354207cb..3b25af820c1 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp @@ -60,7 +60,7 @@ template class Transcript { */ std::array challenges; for (size_t i = 0; i < num_challenges; ++i) { - challenges[i] = native_challenges[i]; + challenges[i] = field_ct::from_witness(builder, native_challenges[i]); } return challenges; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp index ac66bc3cf77..a7bc5573ab7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp @@ -1,6 +1,5 @@ #include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" -#include "barretenberg/honk/pcs/gemini/gemini.hpp" -#include "barretenberg/honk/pcs/shplonk/shplonk.hpp" +#include "barretenberg/honk/pcs/zeromorph/zeromorph.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/grand_product_delta.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" @@ -24,9 +23,7 @@ std::array UltraRecursiveVerifier_::ve { using Sumcheck = ::proof_system::honk::sumcheck::SumcheckVerifier; using Curve = typename Flavor::Curve; - using Gemini = ::proof_system::honk::pcs::gemini::GeminiVerifier_; - using Shplonk = ::proof_system::honk::pcs::shplonk::ShplonkVerifier_; - using KZG = ::proof_system::honk::pcs::kzg::KZG; // note: This can only be KZG + using ZeroMorph = ::proof_system::honk::pcs::zeromorph::ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; using RelationParams = ::proof_system::RelationParameters; @@ -44,6 +41,7 @@ std::array UltraRecursiveVerifier_::ve const auto circuit_size = transcript.template receive_from_prover("circuit_size"); const auto public_input_size = transcript.template receive_from_prover("public_input_size"); const auto pub_inputs_offset = transcript.template receive_from_prover("pub_inputs_offset"); + const auto log_circuit_size = numeric::get_msb32(static_cast(circuit_size.get_value())); // For debugging purposes only ASSERT(static_cast(circuit_size.get_value()) == key->circuit_size); @@ -100,7 +98,7 @@ std::array UltraRecursiveVerifier_::ve // Execute Sumcheck Verifier and extract multivariate opening point u = (u_0, ..., u_{d-1}) and purported // multivariate evaluations at u auto sumcheck = Sumcheck(key->circuit_size); - auto [multivariate_challenge, purported_evaluations, verified] = sumcheck.verify(relation_parameters, transcript); + auto [multivariate_challenge, claimed_evaluations, verified] = sumcheck.verify(relation_parameters, transcript); info("Sumcheck: num gates = ", builder->get_num_gates() - prev_num_gates, @@ -111,94 +109,63 @@ std::array UltraRecursiveVerifier_::ve // Compute powers of batching challenge rho FF rho = transcript.get_challenge("rho"); - std::vector rhos = ::proof_system::honk::pcs::gemini::powers_of_rho(rho, Flavor::NUM_ALL_ENTITIES); + std::vector rhos = ::proof_system::honk::pcs::zeromorph::powers_of_challenge(rho, Flavor::NUM_ALL_ENTITIES); - // Compute batched multivariate evaluation + // Construct batched evaluation v = sum_{i=0}^{m-1}\alpha^i*v_i + sum_{i=0}^{l-1}\alpha^{m+i}*w_i FF batched_evaluation = FF(0); size_t evaluation_idx = 0; - for (auto& value : purported_evaluations.get_unshifted_then_shifted()) { + for (auto& value : claimed_evaluations.get_unshifted_then_shifted()) { batched_evaluation += value * rhos[evaluation_idx]; ++evaluation_idx; } - info("Batched eval: num gates = ", - builder->get_num_gates() - prev_num_gates, - ", (total = ", - builder->get_num_gates(), - ")"); - prev_num_gates = builder->get_num_gates(); - - // Compute batched commitments needed for input to Gemini. - // Note: For efficiency in emulating the construction of the batched commitments, we want to perform a batch mul - // rather than naively accumulate the points one by one. To do this, we collect the points and scalars required for - // each MSM then perform the two batch muls. - const size_t NUM_UNSHIFTED = commitments.get_unshifted().size(); - const size_t NUM_TO_BE_SHIFTED = commitments.get_to_be_shifted().size(); - std::vector scalars_unshifted; - std::vector scalars_to_be_shifted; - size_t idx = 0; - for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { - scalars_unshifted.emplace_back(rhos[idx++]); + // Receive commitments [q_k] + std::vector C_q_k; + C_q_k.reserve(log_circuit_size); + for (size_t i = 0; i < log_circuit_size; ++i) { + C_q_k.emplace_back(transcript.template receive_from_prover("ZM:C_q_" + std::to_string(i))); } - for (size_t i = 0; i < NUM_TO_BE_SHIFTED; ++i) { - scalars_to_be_shifted.emplace_back(rhos[idx++]); - } - // TODO(luke): The powers_of_rho fctn does not set the context of rhos[0] = FF(1) so we do it explicitly here. Can - // we do something silly like set it to rho.pow(0) in the fctn to make it work both native and stdlib? - scalars_unshifted[0] = FF(builder, 1); - // Batch the commitments to the unshifted and to-be-shifted polynomials using powers of rho - auto batched_commitment_unshifted = GroupElement::batch_mul(commitments.get_unshifted(), scalars_unshifted); + // Challenge y + auto y_challenge = transcript.get_challenge("ZM:y"); - info("Batch mul (unshifted): num gates = ", - builder->get_num_gates() - prev_num_gates, - ", (total = ", - builder->get_num_gates(), - ")"); - prev_num_gates = builder->get_num_gates(); + // Receive commitment C_{q} + auto C_q = transcript.template receive_from_prover("ZM:C_q"); - auto batched_commitment_to_be_shifted = - GroupElement::batch_mul(commitments.get_to_be_shifted(), scalars_to_be_shifted); - - info("Batch mul (to-be-shited): num gates = ", - builder->get_num_gates() - prev_num_gates, - ", (total = ", - builder->get_num_gates(), - ")"); - prev_num_gates = builder->get_num_gates(); + // Challenges x, z + auto [x_challenge, z_challenge] = transcript.get_challenges("ZM:x", "ZM:z"); - // Produce a Gemini claim consisting of: - // - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1 - // - d+1 evaluations a_0_pos, and a_l, l = 0:d-1 - auto univariate_opening_claims = Gemini::reduce_verification(multivariate_challenge, - batched_evaluation, - batched_commitment_unshifted, - batched_commitment_to_be_shifted, - transcript); + // Compute commitment C_{\zeta_x} + auto C_zeta_x = ZeroMorph::compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); - info("Gemini: num gates = ", - builder->get_num_gates() - prev_num_gates, - ", (total = ", - builder->get_num_gates(), - ")"); - prev_num_gates = builder->get_num_gates(); + std::vector f_commitments; + std::vector g_commitments; + for (auto& commitment : commitments.get_unshifted()) { + f_commitments.emplace_back(commitment); + } + for (auto& commitment : commitments.get_to_be_shifted()) { + g_commitments.emplace_back(commitment); + } - // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) - auto shplonk_claim = Shplonk::reduce_verification(pcs_verification_key, univariate_opening_claims, transcript); + // Compute commitment C_{Z_x} + Commitment C_Z_x = ZeroMorph::compute_C_Z_x( + f_commitments, g_commitments, C_q_k, rho, batched_evaluation, x_challenge, multivariate_challenge); - info("Shplonk: num gates = ", - builder->get_num_gates() - prev_num_gates, - ", (total = ", - builder->get_num_gates(), - ")"); - prev_num_gates = builder->get_num_gates(); + // Compute commitment C_{\zeta,Z} + auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; - // Constuct the inputs to the final KZG pairing check - auto pairing_points = KZG::compute_pairing_points(shplonk_claim, transcript); + // Receive proof commitment \pi + auto C_pi = transcript.template receive_from_prover("ZM:PI"); - info("KZG: num gates = ", builder->get_num_gates() - prev_num_gates, ", (total = ", builder->get_num_gates(), ")"); + // Construct inputs and perform pairing check to verify claimed evaluation + // Note: The pairing check (without the degree check component X^{N_max-N-1}) can be expressed naturally as + // e(C_{\zeta,Z}, [1]_2) = e(pi, [X - x]_2). This can be rearranged (e.g. see the plonk paper) as + // e(C_{\zeta,Z} - x*pi, [1]_2) * e(-pi, [X]_2) = 1, or + // e(P_0, [1]_2) * e(P_1, [X]_2) = 1 + auto P0 = C_zeta_Z + C_pi * x_challenge; + auto P1 = -C_pi; - return pairing_points; + return { P0, P1 }; } template class UltraRecursiveVerifier_>; From 23935772b88af1dda1b526d652d9f7fafcdf0d6e Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 9 Oct 2023 22:20:52 +0000 Subject: [PATCH 4/7] update transcript test for ZM --- .../composer/goblin_ultra_composer.test.cpp | 20 +++++++++---------- .../honk/transcript/transcript.test.cpp | 17 +++++----------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp index ee13dff5b1e..dfde27a0e16 100644 --- a/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp @@ -201,16 +201,16 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsHonkAndMerge) EXPECT_TRUE(merge_verified); } - // Compute the commitments to the aggregate op queue directly and check that they match those that were computed - // iteratively during transcript aggregation by the provers and stored in the op queue. - size_t aggregate_op_queue_size = op_queue->current_ultra_ops_size; - auto crs_factory = std::make_shared>("../srs_db/ignition"); - auto commitment_key = std::make_shared(aggregate_op_queue_size, crs_factory); - size_t idx = 0; - for (auto& result : op_queue->ultra_ops_commitments) { - auto expected = commitment_key->commit(op_queue->ultra_ops[idx++]); - EXPECT_EQ(result, expected); - } + // // Compute the commitments to the aggregate op queue directly and check that they match those that were computed + // // iteratively during transcript aggregation by the provers and stored in the op queue. + // size_t aggregate_op_queue_size = op_queue->current_ultra_ops_size; + // auto crs_factory = std::make_shared>("../srs_db/ignition"); + // auto commitment_key = std::make_shared(aggregate_op_queue_size, crs_factory); + // size_t idx = 0; + // for (auto& result : op_queue->ultra_ops_commitments) { + // auto expected = commitment_key->commit(op_queue->ultra_ops[idx++]); + // EXPECT_EQ(result, expected); + // } } } // namespace test_ultra_honk_composer diff --git a/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.test.cpp index df3ca8526dd..bf563f2fe5c 100644 --- a/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.test.cpp @@ -72,23 +72,16 @@ class UltraTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "Sumcheck:evaluations", size_evals); manifest_expected.add_challenge(round, "rho"); - round++; - for (size_t i = 1; i < log_n; ++i) { - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, size_G); - } - manifest_expected.add_challenge(round, "Gemini:r"); - round++; for (size_t i = 0; i < log_n; ++i) { std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Gemini:a_" + idx, size_FF); + manifest_expected.add_entry(round, "ZM:C_q_" + idx, size_G); } - manifest_expected.add_challenge(round, "Shplonk:nu"); + manifest_expected.add_challenge(round, "ZM:y"); round++; - manifest_expected.add_entry(round, "Shplonk:Q", size_G); - manifest_expected.add_challenge(round, "Shplonk:z"); + manifest_expected.add_entry(round, "ZM:C_q", size_G); + manifest_expected.add_challenge(round, "ZM:x", "ZM:z"); round++; // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors @@ -108,7 +101,7 @@ class UltraTranscriptTests : public ::testing::Test { round++; manifest_expected.add_entry(round, "IPA:a_0", size_FF); } else { - manifest_expected.add_entry(round, "KZG:W", size_G); + manifest_expected.add_entry(round, "ZM:PI", size_G); } manifest_expected.add_challenge(round); // no challenge From 6ba5fadd13233d3a4191d22ba57a3ecc895a36ed Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 10 Oct 2023 20:06:28 +0000 Subject: [PATCH 5/7] cleanup --- .../composer/goblin_ultra_composer.test.cpp | 24 +++++++++---------- .../honk/pcs/zeromorph/zeromorph.hpp | 2 +- .../honk/proof_system/ultra_prover.cpp | 13 +++++----- .../honk/proof_system/ultra_verifier.cpp | 3 ++- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp index dfde27a0e16..584fb41d7a2 100644 --- a/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp @@ -136,7 +136,7 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsMergeOnly) auto composer = GoblinUltraComposer(); - // Construct and verify Goblin ECC op queue Merge its proof + // Construct and verify Goblin ECC op queue Merge proof auto merge_verified = construct_and_verify_merge_proof(composer, op_queue); EXPECT_TRUE(merge_verified); } @@ -196,21 +196,21 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsHonkAndMerge) auto honk_verified = construct_and_verify_honk_proof(composer, builder); EXPECT_TRUE(honk_verified); - // Construct and verify Goblin ECC op queue Merge its proof + // Construct and verify Goblin ECC op queue Merge proof auto merge_verified = construct_and_verify_merge_proof(composer, op_queue); EXPECT_TRUE(merge_verified); } - // // Compute the commitments to the aggregate op queue directly and check that they match those that were computed - // // iteratively during transcript aggregation by the provers and stored in the op queue. - // size_t aggregate_op_queue_size = op_queue->current_ultra_ops_size; - // auto crs_factory = std::make_shared>("../srs_db/ignition"); - // auto commitment_key = std::make_shared(aggregate_op_queue_size, crs_factory); - // size_t idx = 0; - // for (auto& result : op_queue->ultra_ops_commitments) { - // auto expected = commitment_key->commit(op_queue->ultra_ops[idx++]); - // EXPECT_EQ(result, expected); - // } + // Compute the commitments to the aggregate op queue directly and check that they match those that were computed + // iteratively during transcript aggregation by the provers and stored in the op queue. + size_t aggregate_op_queue_size = op_queue->current_ultra_ops_size; + auto crs_factory = std::make_shared>("../srs_db/ignition"); + auto commitment_key = std::make_shared(aggregate_op_queue_size, crs_factory); + size_t idx = 0; + for (auto& result : op_queue->ultra_ops_commitments) { + auto expected = commitment_key->commit(op_queue->ultra_ops[idx++]); + EXPECT_EQ(result, expected); + } } } // namespace test_ultra_honk_composer diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp index 7b7596cf34b..4fb95d0b1ed 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp @@ -342,7 +342,7 @@ template class ZeroMorphVerifier_ { * @param g_commitments Commitments to to-be-shifted polynomials [g_i] * @param C_q_k Commitments to q_k * @param alpha - * @param batched_evaluation \sum_{i=0}^{m-1} f_i(u) + \sum_{i=0}^{l-1} h_i(u) + * @param batched_evaluation \sum_{i=0}^{m-1} \alpha^i*f_i(u) + \sum_{i=0}^{l-1} \alpha^{m+i}*h_i(u) * @param x_challenge * @param u_challenge multilinear challenge * @return Commitment diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 2afe5464848..e090401c42c 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -108,8 +108,8 @@ template void UltraProver_::execute_relation_check_ } /** - * - Get rho challenge - * - Compute d+1 Fold polynomials and their evaluations. + * @brief Execute the ZeroMorph protocol to prove the multilinear evaluations produced by Sumcheck + * @details See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the unrolled protocol. * * */ template void UltraProver_::execute_zeromorph_rounds() @@ -124,7 +124,7 @@ template void UltraProver_::execute_zeromorph_round // Extract challenge u and claimed multilinear evaluations from Sumcheck output std::span u_challenge = sumcheck_output.challenge; std::span claimed_evaluations = sumcheck_output.claimed_evaluations; - size_t log_N = u_challenge.size(); + size_t log_circuit_size = u_challenge.size(); // Compute batching of f_i and g_i polynomials: sum_{i=0}^{m-1}\alpha^i*f_i and // sum_{i=0}^{l-1}\alpha^{m+i}*h_i, and also batched evaluation v = sum_{i=0}^{m-1}\alpha^i*f_i(u) + @@ -145,7 +145,8 @@ template void UltraProver_::execute_zeromorph_round ++poly_idx; }; - // The new f is f_batched + g_batched.shifted() = f_batched + h_batched + // Compute the full batched polynomial f = f_batched + g_batched.shifted() = f_batched + h_batched. This is the + // polynomial for which we compute the quotients q_k auto f_polynomial = f_batched; f_polynomial += g_batched.shifted(); @@ -154,8 +155,8 @@ template void UltraProver_::execute_zeromorph_round // Compute and send commitments C_{q_k} = [q_k], k = 0,...,d-1 std::vector q_k_commitments; - q_k_commitments.reserve(log_N); - for (size_t idx = 0; idx < log_N; ++idx) { + q_k_commitments.reserve(log_circuit_size); + for (size_t idx = 0; idx < log_circuit_size; ++idx) { q_k_commitments[idx] = pcs_commitment_key->commit(quotients[idx]); std::string label = "ZM:C_q_" + std::to_string(idx); transcript.send_to_verifier(label, q_k_commitments[idx]); diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index f9d893e7bcc..e6b28ef7197 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -120,8 +120,9 @@ template bool UltraVerifier_::verify_proof(const plonk // Execute ZeroMorph rounds - // Compute powers of batching challenge rho FF rho = transcript.get_challenge("rho"); + + // Compute powers of batching challenge rho std::vector rhos = pcs::zeromorph::powers_of_challenge(rho, Flavor::NUM_ALL_ENTITIES); // Construct batched evaluation v = sum_{i=0}^{m-1}\alpha^i*v_i + sum_{i=0}^{l-1}\alpha^{m+i}*w_i From 6667c150ce4b00f81d4f688b1d395422a176e757 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 10 Oct 2023 23:35:20 +0000 Subject: [PATCH 6/7] define prove and verify functions for ZM --- .../honk/pcs/zeromorph/zeromorph.hpp | 303 ++++++++++++++---- .../honk/proof_system/ultra_prover.cpp | 82 +---- .../honk/proof_system/ultra_verifier.cpp | 65 +--- .../verifier/ultra_recursive_verifier.cpp | 62 +--- 4 files changed, 255 insertions(+), 257 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp index 4fb95d0b1ed..e1651117a08 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp @@ -1,23 +1,19 @@ #pragma once #include "barretenberg/polynomials/polynomial.hpp" -/** - * @brief - * - */ namespace proof_system::honk::pcs::zeromorph { /** * @brief Compute powers of a given challenge * - * @tparam Fr + * @tparam FF * @param challenge * @param num_powers - * @return std::vector + * @return std::vector */ -template inline std::vector powers_of_challenge(const Fr challenge, const size_t num_powers) +template inline std::vector powers_of_challenge(const FF challenge, const size_t num_powers) { - std::vector challenge_powers = { Fr(1), challenge }; + std::vector challenge_powers = { FF(1), challenge }; challenge_powers.reserve(num_powers); for (size_t j = 2; j < num_powers; j++) { challenge_powers.emplace_back(challenge_powers[j - 1] * challenge); @@ -31,12 +27,12 @@ template inline std::vector powers_of_challenge(const Fr challeng * @tparam Curve */ template class ZeroMorphProver_ { - using Fr = typename Curve::ScalarField; + using FF = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; - using Polynomial = barretenberg::Polynomial; + using Polynomial = barretenberg::Polynomial; // TODO(#742): Set this N_max to be the number of G1 elements in the mocked zeromorph SRS once it's in place. (Then, - // eventually, set it based on the real SRS). + // eventually, set it based on the real SRS). For now we set it to be large but more or less arbitrary. static const size_t N_max = 1 << 22; public: @@ -51,7 +47,7 @@ template class ZeroMorphProver_ { * * q_k(X_0, ..., X_{k-1}) = f(X_0,...,X_{k-1}, u'') - f(X_0,...,X_{k-1}, u') * - * @note In practice, 2^d is equal to the circuit size + * @note In practice, 2^d is equal to the circuit size N * * TODO(#739): This method has been designed for clarity at the expense of efficiency. Implement the more efficient * algorithm detailed in the latest versions of the ZeroMorph paper. @@ -59,24 +55,24 @@ template class ZeroMorphProver_ { * @param u_challenge Multivariate challenge u = (u_0, ..., u_{d-1}) * @return std::vector The quotients q_k */ - static std::vector compute_multilinear_quotients(Polynomial polynomial, std::span u_challenge) + static std::vector compute_multilinear_quotients(Polynomial polynomial, std::span u_challenge) { - size_t log_poly_size = numeric::get_msb(polynomial.size()); + size_t log_N = numeric::get_msb(polynomial.size()); // The size of the multilinear challenge must equal the log of the polynomial size - ASSERT(log_poly_size == u_challenge.size()); + ASSERT(log_N == u_challenge.size()); - // Define the vector of quotients q_k, k = 0, ..., log_n-1 + // Define the vector of quotients q_k, k = 0, ..., log_N-1 std::vector quotients; - for (size_t k = 0; k < log_poly_size; ++k) { + for (size_t k = 0; k < log_N; ++k) { size_t size = 1 << k; quotients.emplace_back(Polynomial(size)); // degree 2^k - 1 } // Compute the q_k in reverse order, i.e. q_{n-1}, ..., q_0 - for (size_t k = 0; k < log_poly_size; ++k) { + for (size_t k = 0; k < log_N; ++k) { // Define partial evaluation point u' = (u_k, ..., u_{n-1}) auto evaluation_point_size = static_cast(k + 1); - std::vector u_partial(u_challenge.end() - evaluation_point_size, u_challenge.end()); + std::vector u_partial(u_challenge.end() - evaluation_point_size, u_challenge.end()); // Compute f' = f(X_0,...,X_{k-1}, u') auto f_1 = polynomial.partial_evaluate_mle(u_partial); @@ -91,7 +87,7 @@ template class ZeroMorphProver_ { auto q_k = f_2; q_k -= f_1; - quotients[log_poly_size - k - 1] = q_k; + quotients[log_N - k - 1] = q_k; } return quotients; @@ -106,11 +102,11 @@ template class ZeroMorphProver_ { * accumulate them into \hat{q} at the appropriate offset. * * @param quotients Polynomials q_k, interpreted as univariates; deg(q_k) = 2^k - 1 - * @param N + * @param N circuit size * @return Polynomial */ static Polynomial compute_batched_lifted_degree_quotient(std::vector& quotients, - Fr y_challenge, + FF y_challenge, size_t N) { // Batched lifted degree quotient polynomial @@ -118,7 +114,7 @@ template class ZeroMorphProver_ { // Compute \hat{q} = \sum_k y^k * X^{N - d_k - 1} * q_k size_t k = 0; - auto scalar = Fr(1); // y^k + auto scalar = FF(1); // y^k for (auto& quotient : quotients) { // Rather than explicitly computing the shifts of q_k by N - d_k - 1 (i.e. multiplying q_k by X^{N - d_k - // 1}) then accumulating them, we simply accumulate y^k*q_k into \hat{q} at the index offset N - d_k - 1 @@ -148,8 +144,8 @@ template class ZeroMorphProver_ { */ static Polynomial compute_partially_evaluated_degree_check_polynomial(Polynomial& batched_quotient, std::vector& quotients, - Fr y_challenge, - Fr x_challenge) + FF y_challenge, + FF x_challenge) { size_t N = batched_quotient.size(); size_t log_N = quotients.size(); @@ -157,7 +153,7 @@ template class ZeroMorphProver_ { // Initialize partially evaluated degree check polynomial \zeta_x to \hat{q} auto result = batched_quotient; - auto y_power = Fr(1); // y^k + auto y_power = FF(1); // y^k for (size_t k = 0; k < log_N; ++k) { // Accumulate y^k * x^{N - d_k - 1} * q_k into \hat{q} auto deg_k = static_cast((1 << k) - 1); @@ -189,17 +185,16 @@ template class ZeroMorphProver_ { static Polynomial compute_partially_evaluated_zeromorph_identity_polynomial(Polynomial& f_batched, Polynomial& g_batched, std::vector& quotients, - Fr v_evaluation, - std::span u_challenge, - Fr x_challenge) + FF v_evaluation, + std::span u_challenge, + FF x_challenge) { size_t N = f_batched.size(); size_t log_N = quotients.size(); // Initialize Z_x with x * \sum_{i=0}^{m-1} f_i + \sum_{i=0}^{l-1} g_i - auto result = Polynomial(N); + auto result = g_batched; result.add_scaled(f_batched, x_challenge); - result += g_batched; // Compute Z_x -= v * x * \Phi_n(x) auto phi_numerator = x_challenge.pow(N) - 1; // x^N - 1 @@ -221,7 +216,7 @@ template class ZeroMorphProver_ { auto scalar = x_power * phi_term_1 - u_challenge[k] * phi_term_2; scalar *= x_challenge; - scalar *= Fr(-1); + scalar *= FF(-1); result.add_scaled(quotients[k], scalar); } @@ -244,8 +239,8 @@ template class ZeroMorphProver_ { */ static Polynomial compute_batched_evaluation_and_degree_check_quotient(Polynomial& zeta_x, Polynomial& Z_x, - Fr x_challenge, - Fr z_challenge) + FF x_challenge, + FF z_challenge) { // We cannot commit to polynomials with size > N_max size_t N = zeta_x.size(); @@ -272,6 +267,103 @@ template class ZeroMorphProver_ { return batched_shifted_quotient; } + + /** + * @brief Prove a set of multilinear evaluation claims for unshifted polynomials f_i and to-be-shifted polynomials + * g_i + * + * @param f_polynomials Unshifted polynomials + * @param g_polynomials To-be-shifted polynomials (of which the shifts h_i were evaluated by sumcheck) + * @param evaluations Set of evaluations v_i = f_i(u), w_i = h_i(u) = g_i_shifted(u) + * @param multilinear_challenge Multilinear challenge point u + * @param commitment_key + * @param transcript + */ + static void prove(const auto& f_polynomials, + const auto& g_polynomials, + auto& evaluations, + auto& multilinear_challenge, + auto& commitment_key, + auto& transcript) + { + // Generate batching challenge \rho and powers 1,...,\rho^{m-1} + FF rho = transcript.get_challenge("rho"); + std::vector rhos = powers_of_challenge(rho, evaluations.size()); + + // Extract multilinear challenge u and claimed multilinear evaluations from Sumcheck output + std::span u_challenge = multilinear_challenge; + std::span claimed_evaluations = evaluations; + size_t log_N = u_challenge.size(); + size_t N = 1 << log_N; + + // Compute batching of unshifted polynomials f_i and to-be-shifted polynomials g_i: + // f_batched = sum_{i=0}^{m-1}\alpha^i*f_i and g_batched = sum_{i=0}^{l-1}\alpha^{m+i}*g_i, + // and also batched evaluation + // v = sum_{i=0}^{m-1}\alpha^i*f_i(u) + sum_{i=0}^{l-1}\alpha^{m+i}*h_i(u). + // Note: g_batched is formed from the to-be-shifted polynomials, but the batched evaluation incorporates the + // evaluations produced by sumcheck of h_i = g_i_shifted. + auto batched_evaluation = FF(0); + Polynomial f_batched(N); // batched unshifted polynomials + size_t poly_idx = 0; // TODO(#391) zip + for (auto& f_poly : f_polynomials) { + f_batched.add_scaled(f_poly, rhos[poly_idx]); + batched_evaluation += rhos[poly_idx] * claimed_evaluations[poly_idx]; + ++poly_idx; + } + + Polynomial g_batched(N); // batched to-be-shifted polynomials + for (auto& g_poly : g_polynomials) { + g_batched.add_scaled(g_poly, rhos[poly_idx]); + batched_evaluation += rhos[poly_idx] * claimed_evaluations[poly_idx]; + ++poly_idx; + }; + + // Compute the full batched polynomial f = f_batched + g_batched.shifted() = f_batched + h_batched. This is the + // polynomial for which we compute the quotients q_k and prove f(u) = v_batched. + auto f_polynomial = f_batched; + f_polynomial += g_batched.shifted(); + + // Compute the multilinear quotients q_k = q_k(X_0, ..., X_{k-1}) + auto quotients = compute_multilinear_quotients(f_polynomial, u_challenge); + + // Compute and send commitments C_{q_k} = [q_k], k = 0,...,d-1 + std::vector q_k_commitments; + q_k_commitments.reserve(log_N); + for (size_t idx = 0; idx < log_N; ++idx) { + q_k_commitments[idx] = commitment_key->commit(quotients[idx]); + std::string label = "ZM:C_q_" + std::to_string(idx); + transcript.send_to_verifier(label, q_k_commitments[idx]); + } + + // Get challenge y + auto y_challenge = transcript.get_challenge("ZM:y"); + + // Compute the batched, lifted-degree quotient \hat{q} + auto batched_quotient = compute_batched_lifted_degree_quotient(quotients, y_challenge, N); + + // Compute and send the commitment C_q = [\hat{q}] + auto q_commitment = commitment_key->commit(batched_quotient); + transcript.send_to_verifier("ZM:C_q", q_commitment); + + // Get challenges x and z + auto [x_challenge, z_challenge] = transcript.get_challenges("ZM:x", "ZM:z"); + + // Compute degree check polynomial \zeta partially evaluated at x + auto zeta_x = + compute_partially_evaluated_degree_check_polynomial(batched_quotient, quotients, y_challenge, x_challenge); + + // Compute ZeroMorph identity polynomial Z partially evaluated at x + auto Z_x = compute_partially_evaluated_zeromorph_identity_polynomial( + f_batched, g_batched, quotients, batched_evaluation, u_challenge, x_challenge); + + // Compute batched degree-check and ZM-identity quotient polynomial pi + auto pi_polynomial = + compute_batched_evaluation_and_degree_check_quotient(zeta_x, Z_x, x_challenge, z_challenge); + + // Compute and send proof commitment pi + auto pi_commitment = commitment_key->commit(pi_polynomial); + transcript.send_to_verifier("ZM:PI", pi_commitment); + } }; /** @@ -280,7 +372,7 @@ template class ZeroMorphProver_ { * @tparam Curve */ template class ZeroMorphVerifier_ { - using Fr = typename Curve::ScalarField; + using FF = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; using GroupElement = typename Curve::Element; @@ -297,33 +389,37 @@ template class ZeroMorphVerifier_ { * @param x_challenge * @return Commitment */ - static Commitment compute_C_zeta_x(Commitment C_q, std::vector& C_q_k, Fr y_challenge, Fr x_challenge) + static Commitment compute_C_zeta_x(Commitment C_q, std::vector& C_q_k, FF y_challenge, FF x_challenge) { size_t log_N = C_q_k.size(); size_t N = 1 << log_N; - std::vector scalars; + // Instantiate containers for input to batch mul + std::vector scalars; std::vector commitments; + // Contribution from C_q if constexpr (Curve::is_stdlib_type) { auto builder = x_challenge.get_context(); - scalars.emplace_back(Fr(builder, 1)); + scalars.emplace_back(FF(builder, 1)); } else { - scalars.emplace_back(Fr(1)); + scalars.emplace_back(FF(1)); } commitments.emplace_back(C_q); + // Contribution from C_q_k, k = 0,...,log_N for (size_t k = 0; k < log_N; ++k) { auto deg_k = static_cast((1 << k) - 1); // Compute scalar y^k * x^{N - deg_k - 1} auto scalar = y_challenge.pow(k); scalar *= x_challenge.pow(N - deg_k - 1); - scalar *= Fr(-1); + scalar *= FF(-1); scalars.emplace_back(scalar); commitments.emplace_back(C_q_k[k]); } + // Compute batch mul to get the result if constexpr (Curve::is_stdlib_type) { return GroupElement::batch_mul(commitments, scalars); } else { @@ -350,62 +446,66 @@ template class ZeroMorphVerifier_ { static Commitment compute_C_Z_x(std::vector& f_commitments, std::vector& g_commitments, std::vector& C_q_k, - Fr alpha, - Fr batched_evaluation, - Fr x_challenge, - std::vector u_challenge) + FF alpha, + FF batched_evaluation, + FF x_challenge, + std::vector u_challenge) { size_t log_N = C_q_k.size(); size_t N = 1 << log_N; - std::vector scalars; + std::vector scalars; std::vector commitments; // Phi_n(x) = (x^N - 1) / (x - 1) auto phi_numerator = x_challenge.pow(N) - 1; // x^N - 1 auto phi_n_x = phi_numerator / (x_challenge - 1); + // Add contribution: -v * x * \Phi_n(x) * [1]_1 if constexpr (Curve::is_stdlib_type) { auto builder = x_challenge.get_context(); - scalars.emplace_back(Fr(builder, -1) * batched_evaluation * x_challenge * phi_n_x); + scalars.emplace_back(FF(builder, -1) * batched_evaluation * x_challenge * phi_n_x); commitments.emplace_back(Commitment::one(builder)); } else { - scalars.emplace_back(Fr(-1) * batched_evaluation * x_challenge * phi_n_x); + scalars.emplace_back(FF(-1) * batched_evaluation * x_challenge * phi_n_x); commitments.emplace_back(Commitment::one()); } - auto alpha_pow = Fr(1); - // Add contribution x * \sum_{i=0}^{m-1} [f_i] + // Add contribution: x * \sum_{i=0}^{m-1} \alpha^i*[f_i] + auto alpha_pow = FF(1); for (auto& commitment : f_commitments) { scalars.emplace_back(x_challenge * alpha_pow); commitments.emplace_back(commitment); alpha_pow *= alpha; } - // Add contribution \sum_{i=0}^{l-1} [g_i] + + // Add contribution: \sum_{i=0}^{l-1} \alpha^{m+i}*[g_i] for (auto& commitment : g_commitments) { scalars.emplace_back(alpha_pow); commitments.emplace_back(commitment); alpha_pow *= alpha; } - // Add contribution from q_k commitments + // Add contributions: scalar * [q_k], k = 0,...,log_N, where + // scalar = -x * (x^{2^k} * \Phi_{n-k-1}(x^{2^{k+1}}) - u_k * \Phi_{n-k}(x^{2^k})) + auto x_pow_2k = x_challenge; // x^{2^k} + auto x_pow_2kp1 = x_challenge * x_challenge; // x^{2^{k + 1}} for (size_t k = 0; k < log_N; ++k) { - // Compute scalar x^{2^k} * \Phi_{n-k-1}(x^{2^{k+1}}) - u_k * \Phi_{n-k}(x^{2^k}) - auto x_pow_2k = x_challenge.pow(1 << k); // x^{2^k} - // \Phi_{n-k-1}(x^{2^{k + 1}}) - auto phi_term_1 = phi_numerator / (x_challenge.pow(1 << (k + 1)) - 1); - - // \Phi_{n-k}(x^{2^k}) - auto phi_term_2 = phi_numerator / (x_challenge.pow(1 << k) - 1); + auto phi_term_1 = phi_numerator / (x_pow_2kp1 - 1); // \Phi_{n-k-1}(x^{2^{k + 1}}) + auto phi_term_2 = phi_numerator / (x_pow_2k - 1); // \Phi_{n-k}(x^{2^k}) auto scalar = x_pow_2k * phi_term_1; scalar -= u_challenge[k] * phi_term_2; scalar *= x_challenge; - scalar *= Fr(-1); + scalar *= FF(-1); scalars.emplace_back(scalar); commitments.emplace_back(C_q_k[k]); + + // Update powers of challenge x + x_pow_2k = x_pow_2kp1; + x_pow_2kp1 *= x_pow_2kp1; } if constexpr (Curve::is_stdlib_type) { @@ -415,15 +515,96 @@ template class ZeroMorphVerifier_ { } } - static Commitment batch_mul_native(std::vector points, std::vector scalars) + /** + * @brief Utility for native batch multiplication of group elements + * + */ + static Commitment batch_mul_native(std::vector points, std::vector scalars) { auto result = points[0] * scalars[0]; for (size_t idx = 1; idx < scalars.size(); ++idx) { result = result + points[idx] * scalars[idx]; } - return result; } + + /** + * @brief Verify a set of multilinear evaluation claims for unshifted polynomials f_i and to-be-shifted polynomials + * g_i + * + * @param commitments Commitments to polynomials f_i and g_i (unshifted and to-be-shifted) + * @param claimed_evaluations Claimed evaluations v_i = f_i(u) and w_i = h_i(u) = g_i_shifted(u) + * @param multivariate_challenge Challenge point u + * @param transcript + * @return std::array Inputs to the final pairing check + */ + static std::array verify(auto& commitments, + auto& claimed_evaluations, + auto& multivariate_challenge, + auto& transcript) + { + size_t log_N = multivariate_challenge.size(); + FF rho = transcript.get_challenge("rho"); + + // Compute powers of batching challenge rho + std::vector rhos = pcs::zeromorph::powers_of_challenge(rho, claimed_evaluations.size()); + + // Construct batched evaluation v = sum_{i=0}^{m-1}\alpha^i*f_i(u) + sum_{i=0}^{l-1}\alpha^{m+i}*h_i(u) + FF batched_evaluation = FF(0); + size_t evaluation_idx = 0; + for (auto& value : claimed_evaluations.get_unshifted_then_shifted()) { + batched_evaluation += value * rhos[evaluation_idx]; + ++evaluation_idx; + } + + // Receive commitments [q_k] + std::vector C_q_k; + C_q_k.reserve(log_N); + for (size_t i = 0; i < log_N; ++i) { + C_q_k.emplace_back(transcript.template receive_from_prover("ZM:C_q_" + std::to_string(i))); + } + + // Challenge y + auto y_challenge = transcript.get_challenge("ZM:y"); + + // Receive commitment C_{q} + auto C_q = transcript.template receive_from_prover("ZM:C_q"); + + // Challenges x, z + auto [x_challenge, z_challenge] = transcript.get_challenges("ZM:x", "ZM:z"); + + // Compute commitment C_{\zeta_x} + auto C_zeta_x = compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); + + std::vector f_commitments; + std::vector g_commitments; + for (auto& commitment : commitments.get_unshifted()) { + f_commitments.emplace_back(commitment); + } + for (auto& commitment : commitments.get_to_be_shifted()) { + g_commitments.emplace_back(commitment); + } + + // Compute commitment C_{Z_x} + Commitment C_Z_x = compute_C_Z_x( + f_commitments, g_commitments, C_q_k, rho, batched_evaluation, x_challenge, multivariate_challenge); + + // Compute commitment C_{\zeta,Z} + auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; + + // Receive proof commitment \pi + auto C_pi = transcript.template receive_from_prover("ZM:PI"); + + // Construct inputs and perform pairing check to verify claimed evaluation + // Note: The pairing check (without the degree check component X^{N_max-N-1}) can be expressed naturally as + // e(C_{\zeta,Z}, [1]_2) = e(pi, [X - x]_2). This can be rearranged (e.g. see the plonk paper) as + // e(C_{\zeta,Z} - x*pi, [1]_2) * e(-pi, [X]_2) = 1, or + // e(P_0, [1]_2) * e(P_1, [X]_2) = 1 + auto P0 = C_zeta_Z + C_pi * x_challenge; + auto P1 = -C_pi; + + return { P0, P1 }; + } }; } // namespace proof_system::honk::pcs::zeromorph \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index e090401c42c..e5cb11ee069 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -114,82 +114,12 @@ template void UltraProver_::execute_relation_check_ * */ template void UltraProver_::execute_zeromorph_rounds() { - const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - const size_t circuit_size = instance->proving_key->circuit_size; - - // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ - FF rho = transcript.get_challenge("rho"); - std::vector rhos = pcs::zeromorph::powers_of_challenge(rho, NUM_POLYNOMIALS); - - // Extract challenge u and claimed multilinear evaluations from Sumcheck output - std::span u_challenge = sumcheck_output.challenge; - std::span claimed_evaluations = sumcheck_output.claimed_evaluations; - size_t log_circuit_size = u_challenge.size(); - - // Compute batching of f_i and g_i polynomials: sum_{i=0}^{m-1}\alpha^i*f_i and - // sum_{i=0}^{l-1}\alpha^{m+i}*h_i, and also batched evaluation v = sum_{i=0}^{m-1}\alpha^i*f_i(u) + - // sum_{i=0}^{l-1}\alpha^{m+i}*h_i(u). - auto batched_evaluation = FF(0); - Polynomial f_batched(circuit_size); // batched unshifted polynomials - size_t poly_idx = 0; // TODO(#391) zip - for (auto& f_polynomial : instance->prover_polynomials.get_unshifted()) { - f_batched.add_scaled(f_polynomial, rhos[poly_idx]); - batched_evaluation += rhos[poly_idx] * claimed_evaluations[poly_idx]; - ++poly_idx; - } - - Polynomial g_batched(circuit_size); // batched to-be-shifted polynomials - for (auto& g_polynomial : instance->prover_polynomials.get_to_be_shifted()) { - g_batched.add_scaled(g_polynomial, rhos[poly_idx]); - batched_evaluation += rhos[poly_idx] * claimed_evaluations[poly_idx]; - ++poly_idx; - }; - - // Compute the full batched polynomial f = f_batched + g_batched.shifted() = f_batched + h_batched. This is the - // polynomial for which we compute the quotients q_k - auto f_polynomial = f_batched; - f_polynomial += g_batched.shifted(); - - // Compute the multilinear quotients q_k = q_k(X_0, ..., X_{k-1}) - auto quotients = ZeroMorph::compute_multilinear_quotients(f_polynomial, u_challenge); - - // Compute and send commitments C_{q_k} = [q_k], k = 0,...,d-1 - std::vector q_k_commitments; - q_k_commitments.reserve(log_circuit_size); - for (size_t idx = 0; idx < log_circuit_size; ++idx) { - q_k_commitments[idx] = pcs_commitment_key->commit(quotients[idx]); - std::string label = "ZM:C_q_" + std::to_string(idx); - transcript.send_to_verifier(label, q_k_commitments[idx]); - } - - // Get challenge y - auto y_challenge = transcript.get_challenge("ZM:y"); - - // Compute the batched, lifted-degree quotient \hat{q} - auto batched_quotient = ZeroMorph::compute_batched_lifted_degree_quotient(quotients, y_challenge, circuit_size); - - // Compute and send the commitment C_q = [\hat{q}] - auto q_commitment = pcs_commitment_key->commit(batched_quotient); - transcript.send_to_verifier("ZM:C_q", q_commitment); - - // Get challenges x and z - auto [x_challenge, z_challenge] = transcript.get_challenges("ZM:x", "ZM:z"); - - // Compute degree check polynomial \zeta partially evaluated at x - auto zeta_x = ZeroMorph::compute_partially_evaluated_degree_check_polynomial( - batched_quotient, quotients, y_challenge, x_challenge); - - // Compute ZeroMorph identity polynomial Z partially evaluated at x - auto Z_x = ZeroMorph::compute_partially_evaluated_zeromorph_identity_polynomial( - f_batched, g_batched, quotients, batched_evaluation, u_challenge, x_challenge); - - // Compute batched degree and ZM-identity quotient polynomial pi - auto pi_polynomial = - ZeroMorph::compute_batched_evaluation_and_degree_check_quotient(zeta_x, Z_x, x_challenge, z_challenge); - - // Compute and send proof commitment pi - auto pi_commitment = pcs_commitment_key->commit(pi_polynomial); - transcript.send_to_verifier("ZM:PI", pi_commitment); + ZeroMorph::prove(instance->prover_polynomials.get_unshifted(), + instance->prover_polynomials.get_to_be_shifted(), + sumcheck_output.claimed_evaluations, + sumcheck_output.challenge, + pcs_commitment_key, + transcript); } template plonk::proof& UltraProver_::export_proof() diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index e6b28ef7197..0a29e7b08d9 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -51,7 +51,6 @@ template bool UltraVerifier_::verify_proof(const plonk const auto circuit_size = transcript.template receive_from_prover("circuit_size"); const auto public_input_size = transcript.template receive_from_prover("public_input_size"); const auto pub_inputs_offset = transcript.template receive_from_prover("pub_inputs_offset"); - const size_t log_circuit_size = numeric::get_msb(circuit_size); if (circuit_size != key->circuit_size) { return false; @@ -118,67 +117,11 @@ template bool UltraVerifier_::verify_proof(const plonk return false; } - // Execute ZeroMorph rounds + // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the + // unrolled protocol. + auto pairing_points = ZeroMorph::verify(commitments, claimed_evaluations, multivariate_challenge, transcript); - FF rho = transcript.get_challenge("rho"); - - // Compute powers of batching challenge rho - std::vector rhos = pcs::zeromorph::powers_of_challenge(rho, Flavor::NUM_ALL_ENTITIES); - - // Construct batched evaluation v = sum_{i=0}^{m-1}\alpha^i*v_i + sum_{i=0}^{l-1}\alpha^{m+i}*w_i - FF batched_evaluation = FF(0); - size_t evaluation_idx = 0; - for (auto& value : claimed_evaluations.get_unshifted_then_shifted()) { - batched_evaluation += value * rhos[evaluation_idx]; - ++evaluation_idx; - } - - // Receive commitments [q_k] - std::vector C_q_k; - C_q_k.reserve(log_circuit_size); - for (size_t i = 0; i < log_circuit_size; ++i) { - C_q_k.emplace_back(transcript.template receive_from_prover("ZM:C_q_" + std::to_string(i))); - } - - // Challenge y - auto y_challenge = transcript.get_challenge("ZM:y"); - - // Receive commitment C_{q} - auto C_q = transcript.template receive_from_prover("ZM:C_q"); - - // Challenges x, z - auto [x_challenge, z_challenge] = transcript.get_challenges("ZM:x", "ZM:z"); - - // Compute commitment C_{\zeta_x} - auto C_zeta_x = ZeroMorph::compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); - - std::vector f_commitments; - std::vector g_commitments; - for (auto& commitment : commitments.get_unshifted()) { - f_commitments.emplace_back(commitment); - } - for (auto& commitment : commitments.get_to_be_shifted()) { - g_commitments.emplace_back(commitment); - } - - // Compute commitment C_{Z_x} - Commitment C_Z_x = ZeroMorph::compute_C_Z_x( - f_commitments, g_commitments, C_q_k, rho, batched_evaluation, x_challenge, multivariate_challenge); - - // Compute commitment C_{\zeta,Z} - auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; - - // Receive proof commitment \pi - auto C_pi = transcript.template receive_from_prover("ZM:PI"); - - // Construct inputs and perform pairing check to verify claimed evaluation - // Note: The pairing check (without the degree check component X^{N_max-N-1}) can be expressed naturally as - // e(C_{\zeta,Z}, [1]_2) = e(pi, [X - x]_2). This can be rearranged (e.g. see the plonk paper) as - // e(C_{\zeta,Z} - x*pi, [1]_2) * e(-pi, [X]_2) = 1, or - // e(P_0, [1]_2) * e(P_1, [X]_2) = 1 - auto P0 = C_zeta_Z + C_pi * x_challenge; - auto P1 = -C_pi; - auto verified = pcs_verification_key->pairing_check(P0, P1); + auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); return sumcheck_verified.value() && verified; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp index a7bc5573ab7..068a62ca1c8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp @@ -41,7 +41,6 @@ std::array UltraRecursiveVerifier_::ve const auto circuit_size = transcript.template receive_from_prover("circuit_size"); const auto public_input_size = transcript.template receive_from_prover("public_input_size"); const auto pub_inputs_offset = transcript.template receive_from_prover("pub_inputs_offset"); - const auto log_circuit_size = numeric::get_msb32(static_cast(circuit_size.get_value())); // For debugging purposes only ASSERT(static_cast(circuit_size.get_value()) == key->circuit_size); @@ -107,65 +106,10 @@ std::array UltraRecursiveVerifier_::ve ")"); prev_num_gates = builder->get_num_gates(); - // Compute powers of batching challenge rho - FF rho = transcript.get_challenge("rho"); - std::vector rhos = ::proof_system::honk::pcs::zeromorph::powers_of_challenge(rho, Flavor::NUM_ALL_ENTITIES); + // Execute ZeroMorph multilinear PCS evaluation verifier + auto pairing_points = ZeroMorph::verify(commitments, claimed_evaluations, multivariate_challenge, transcript); - // Construct batched evaluation v = sum_{i=0}^{m-1}\alpha^i*v_i + sum_{i=0}^{l-1}\alpha^{m+i}*w_i - FF batched_evaluation = FF(0); - size_t evaluation_idx = 0; - for (auto& value : claimed_evaluations.get_unshifted_then_shifted()) { - batched_evaluation += value * rhos[evaluation_idx]; - ++evaluation_idx; - } - - // Receive commitments [q_k] - std::vector C_q_k; - C_q_k.reserve(log_circuit_size); - for (size_t i = 0; i < log_circuit_size; ++i) { - C_q_k.emplace_back(transcript.template receive_from_prover("ZM:C_q_" + std::to_string(i))); - } - - // Challenge y - auto y_challenge = transcript.get_challenge("ZM:y"); - - // Receive commitment C_{q} - auto C_q = transcript.template receive_from_prover("ZM:C_q"); - - // Challenges x, z - auto [x_challenge, z_challenge] = transcript.get_challenges("ZM:x", "ZM:z"); - - // Compute commitment C_{\zeta_x} - auto C_zeta_x = ZeroMorph::compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); - - std::vector f_commitments; - std::vector g_commitments; - for (auto& commitment : commitments.get_unshifted()) { - f_commitments.emplace_back(commitment); - } - for (auto& commitment : commitments.get_to_be_shifted()) { - g_commitments.emplace_back(commitment); - } - - // Compute commitment C_{Z_x} - Commitment C_Z_x = ZeroMorph::compute_C_Z_x( - f_commitments, g_commitments, C_q_k, rho, batched_evaluation, x_challenge, multivariate_challenge); - - // Compute commitment C_{\zeta,Z} - auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; - - // Receive proof commitment \pi - auto C_pi = transcript.template receive_from_prover("ZM:PI"); - - // Construct inputs and perform pairing check to verify claimed evaluation - // Note: The pairing check (without the degree check component X^{N_max-N-1}) can be expressed naturally as - // e(C_{\zeta,Z}, [1]_2) = e(pi, [X - x]_2). This can be rearranged (e.g. see the plonk paper) as - // e(C_{\zeta,Z} - x*pi, [1]_2) * e(-pi, [X]_2) = 1, or - // e(P_0, [1]_2) * e(P_1, [X]_2) = 1 - auto P0 = C_zeta_Z + C_pi * x_challenge; - auto P1 = -C_pi; - - return { P0, P1 }; + return pairing_points; } template class UltraRecursiveVerifier_>; From b2dc1a1e79f0e92e8e84a2e6f7306da32f7dd393 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 11 Oct 2023 21:10:48 +0000 Subject: [PATCH 7/7] cleanup related to maras review --- .../honk/pcs/zeromorph/zeromorph.hpp | 59 +++++++++---------- .../honk/pcs/zeromorph/zeromorph.test.cpp | 46 +++++++-------- 2 files changed, 50 insertions(+), 55 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp index e1651117a08..ed3beccf79e 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.hpp @@ -174,7 +174,7 @@ template class ZeroMorphProver_ { * Z_x = x * f_batched + g_batched - v * x * \Phi_n(x) * - x * \sum_k (x^{2^k}\Phi_{n-k-1}(x^{2^{k-1}}) - u_k\Phi_{n-k}(x^{2^k})) * q_k * - * where f_batched = \sum_{i=0}^{m-1}\alpha^i*f_i, g_batched = \sum_{i=0}^{l-1}\alpha^{m+i}*g_i + * where f_batched = \sum_{i=0}^{m-1}\rho^i*f_i, g_batched = \sum_{i=0}^{l-1}\rho^{m+i}*g_i * * @param input_polynomial * @param quotients @@ -297,9 +297,9 @@ template class ZeroMorphProver_ { size_t N = 1 << log_N; // Compute batching of unshifted polynomials f_i and to-be-shifted polynomials g_i: - // f_batched = sum_{i=0}^{m-1}\alpha^i*f_i and g_batched = sum_{i=0}^{l-1}\alpha^{m+i}*g_i, + // f_batched = sum_{i=0}^{m-1}\rho^i*f_i and g_batched = sum_{i=0}^{l-1}\rho^{m+i}*g_i, // and also batched evaluation - // v = sum_{i=0}^{m-1}\alpha^i*f_i(u) + sum_{i=0}^{l-1}\alpha^{m+i}*h_i(u). + // v = sum_{i=0}^{m-1}\rho^i*f_i(u) + sum_{i=0}^{l-1}\rho^{m+i}*h_i(u). // Note: g_batched is formed from the to-be-shifted polynomials, but the batched evaluation incorporates the // evaluations produced by sumcheck of h_i = g_i_shifted. auto batched_evaluation = FF(0); @@ -374,7 +374,6 @@ template class ZeroMorphProver_ { template class ZeroMorphVerifier_ { using FF = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; - using GroupElement = typename Curve::Element; public: /** @@ -421,7 +420,7 @@ template class ZeroMorphVerifier_ { // Compute batch mul to get the result if constexpr (Curve::is_stdlib_type) { - return GroupElement::batch_mul(commitments, scalars); + return Commitment::batch_mul(commitments, scalars); } else { return batch_mul_native(commitments, scalars); } @@ -431,22 +430,22 @@ template class ZeroMorphVerifier_ { * @brief Compute commitment to partially evaluated ZeroMorph identity Z * @details Compute commitment C_{Z_x} = [Z_x]_1 using homomorphicity: * - * C_{Z_x} = x * \sum_{i=0}^{m-1}\alpha^i*[f_i] + \sum_{i=0}^{l-1}\alpha^{m+i}*[g_i] - v * x * \Phi_n(x) * [1]_1 + * C_{Z_x} = x * \sum_{i=0}^{m-1}\rho^i*[f_i] + \sum_{i=0}^{l-1}\rho^{m+i}*[g_i] - v * x * \Phi_n(x) * [1]_1 * - x * \sum_k (x^{2^k}\Phi_{n-k-1}(x^{2^{k-1}}) - u_k\Phi_{n-k}(x^{2^k})) * [q_k] * * @param f_commitments Commitments to unshifted polynomials [f_i] * @param g_commitments Commitments to to-be-shifted polynomials [g_i] * @param C_q_k Commitments to q_k - * @param alpha - * @param batched_evaluation \sum_{i=0}^{m-1} \alpha^i*f_i(u) + \sum_{i=0}^{l-1} \alpha^{m+i}*h_i(u) + * @param rho + * @param batched_evaluation \sum_{i=0}^{m-1} \rho^i*f_i(u) + \sum_{i=0}^{l-1} \rho^{m+i}*h_i(u) * @param x_challenge * @param u_challenge multilinear challenge * @return Commitment */ - static Commitment compute_C_Z_x(std::vector& f_commitments, - std::vector& g_commitments, + static Commitment compute_C_Z_x(std::vector f_commitments, + std::vector g_commitments, std::vector& C_q_k, - FF alpha, + FF rho, FF batched_evaluation, FF x_challenge, std::vector u_challenge) @@ -471,19 +470,19 @@ template class ZeroMorphVerifier_ { commitments.emplace_back(Commitment::one()); } - // Add contribution: x * \sum_{i=0}^{m-1} \alpha^i*[f_i] - auto alpha_pow = FF(1); + // Add contribution: x * \sum_{i=0}^{m-1} \rho^i*[f_i] + auto rho_pow = FF(1); for (auto& commitment : f_commitments) { - scalars.emplace_back(x_challenge * alpha_pow); + scalars.emplace_back(x_challenge * rho_pow); commitments.emplace_back(commitment); - alpha_pow *= alpha; + rho_pow *= rho; } - // Add contribution: \sum_{i=0}^{l-1} \alpha^{m+i}*[g_i] + // Add contribution: \sum_{i=0}^{l-1} \rho^{m+i}*[g_i] for (auto& commitment : g_commitments) { - scalars.emplace_back(alpha_pow); + scalars.emplace_back(rho_pow); commitments.emplace_back(commitment); - alpha_pow *= alpha; + rho_pow *= rho; } // Add contributions: scalar * [q_k], k = 0,...,log_N, where @@ -509,7 +508,7 @@ template class ZeroMorphVerifier_ { } if constexpr (Curve::is_stdlib_type) { - return GroupElement::batch_mul(commitments, scalars); + return Commitment::batch_mul(commitments, scalars); } else { return batch_mul_native(commitments, scalars); } @@ -517,7 +516,7 @@ template class ZeroMorphVerifier_ { /** * @brief Utility for native batch multiplication of group elements - * + * @note This is used only for native verification and is not optimized for efficiency */ static Commitment batch_mul_native(std::vector points, std::vector scalars) { @@ -549,7 +548,7 @@ template class ZeroMorphVerifier_ { // Compute powers of batching challenge rho std::vector rhos = pcs::zeromorph::powers_of_challenge(rho, claimed_evaluations.size()); - // Construct batched evaluation v = sum_{i=0}^{m-1}\alpha^i*f_i(u) + sum_{i=0}^{l-1}\alpha^{m+i}*h_i(u) + // Construct batched evaluation v = sum_{i=0}^{m-1}\rho^i*f_i(u) + sum_{i=0}^{l-1}\rho^{m+i}*h_i(u) FF batched_evaluation = FF(0); size_t evaluation_idx = 0; for (auto& value : claimed_evaluations.get_unshifted_then_shifted()) { @@ -576,18 +575,14 @@ template class ZeroMorphVerifier_ { // Compute commitment C_{\zeta_x} auto C_zeta_x = compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); - std::vector f_commitments; - std::vector g_commitments; - for (auto& commitment : commitments.get_unshifted()) { - f_commitments.emplace_back(commitment); - } - for (auto& commitment : commitments.get_to_be_shifted()) { - g_commitments.emplace_back(commitment); - } - // Compute commitment C_{Z_x} - Commitment C_Z_x = compute_C_Z_x( - f_commitments, g_commitments, C_q_k, rho, batched_evaluation, x_challenge, multivariate_challenge); + Commitment C_Z_x = compute_C_Z_x(commitments.get_unshifted(), + commitments.get_to_be_shifted(), + C_q_k, + rho, + batched_evaluation, + x_challenge, + multivariate_challenge); // Compute commitment C_{\zeta,Z} auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp index 79ccd73b390..2dd12c429f9 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp @@ -81,24 +81,24 @@ template class ZeroMorphTest : public CommitmentTest { // Execute Prover protocol { - auto alpha = prover_transcript.get_challenge("ZM:alpha"); + auto rho = prover_transcript.get_challenge("ZM:rho"); - // Compute batching of f_i and g_i polynomials: sum_{i=0}^{m-1}\alpha^i*f_i and - // sum_{i=0}^{l-1}\alpha^{m+i}*h_i, and also batched evaluation v = sum_{i=0}^{m-1}\alpha^i*v_i + - // sum_{i=0}^{l-1}\alpha^{m+i}*w_i. + // Compute batching of f_i and g_i polynomials: sum_{i=0}^{m-1}\rho^i*f_i and + // sum_{i=0}^{l-1}\rho^{m+i}*h_i, and also batched evaluation v = sum_{i=0}^{m-1}\rho^i*v_i + + // sum_{i=0}^{l-1}\rho^{m+i}*w_i. auto f_batched = Polynomial(N); auto g_batched = Polynomial(N); auto v_evaluation = Fr(0); - auto alpha_pow = Fr(1); + auto rho_pow = Fr(1); for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { - f_batched.add_scaled(f_polynomials[i], alpha_pow); - v_evaluation += alpha_pow * v_evaluations[i]; - alpha_pow *= alpha; + f_batched.add_scaled(f_polynomials[i], rho_pow); + v_evaluation += rho_pow * v_evaluations[i]; + rho_pow *= rho; } for (size_t i = 0; i < NUM_SHIFTED; ++i) { - g_batched.add_scaled(g_polynomials[i], alpha_pow); - v_evaluation += alpha_pow * w_evaluations[i]; - alpha_pow *= alpha; + g_batched.add_scaled(g_polynomials[i], rho_pow); + v_evaluation += rho_pow * w_evaluations[i]; + rho_pow *= rho; } // The new f is f_batched + g_batched.shifted() = f_batched + h_batched @@ -151,19 +151,19 @@ template class ZeroMorphTest : public CommitmentTest { // Execute Verifier protocol { - // Challenge alpha - auto alpha = verifier_transcript.get_challenge("ZM:alpha"); + // Challenge rho + auto rho = verifier_transcript.get_challenge("ZM:rho"); - // Construct batched evaluation v = sum_{i=0}^{m-1}\alpha^i*v_i + sum_{i=0}^{l-1}\alpha^{m+i}*w_i + // Construct batched evaluation v = sum_{i=0}^{m-1}\rho^i*v_i + sum_{i=0}^{l-1}\rho^{m+i}*w_i auto v_evaluation = Fr(0); - auto alpha_pow = Fr(1); + auto rho_pow = Fr(1); for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { - v_evaluation += alpha_pow * v_evaluations[i]; - alpha_pow *= alpha; + v_evaluation += rho_pow * v_evaluations[i]; + rho_pow *= rho; } for (size_t i = 0; i < NUM_SHIFTED; ++i) { - v_evaluation += alpha_pow * w_evaluations[i]; - alpha_pow *= alpha; + v_evaluation += rho_pow * w_evaluations[i]; + rho_pow *= rho; } // Receive commitments [q_k] @@ -188,7 +188,7 @@ template class ZeroMorphTest : public CommitmentTest { // Compute commitment C_{Z_x} Commitment C_Z_x = ZeroMorphVerifier::compute_C_Z_x( - f_commitments, g_commitments, C_q_k, alpha, v_evaluation, x_challenge, u_challenge); + f_commitments, g_commitments, C_q_k, rho, v_evaluation, x_challenge, u_challenge); // Compute commitment C_{\zeta,Z} auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; @@ -415,13 +415,13 @@ TYPED_TEST(ZeroMorphTest, PartiallyEvaluatedQuotientZ) Fr v_evaluation = multilinear_f.evaluate_mle(u_challenge); Fr w_evaluation = multilinear_g.evaluate_mle(u_challenge, /* shift = */ true); - auto alpha = Fr::random_element(); + auto rho = Fr::random_element(); // compute batched polynomial and evaluation auto f_batched = multilinear_f; auto g_batched = multilinear_g; - g_batched *= alpha; - auto v_batched = v_evaluation + alpha * w_evaluation; + g_batched *= rho; + auto v_batched = v_evaluation + rho * w_evaluation; // Define some mock q_k with deg(q_k) = 2^k - 1 auto q_0 = this->random_polynomial(1 << 0);