From 91a3e05d8e4128130d751b374581c8525dab7a22 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 19 Apr 2023 21:00:15 +0000 Subject: [PATCH 1/2] updating IPA to use transcript --- .../barretenberg/honk/pcs/commitment_key.hpp | 1 + cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp | 136 +++++++++--------- .../barretenberg/honk/pcs/ipa/ipa.test.cpp | 27 ++-- 3 files changed, 77 insertions(+), 87 deletions(-) diff --git a/cpp/src/barretenberg/honk/pcs/commitment_key.hpp b/cpp/src/barretenberg/honk/pcs/commitment_key.hpp index ce29e5fe7d..5d4e32c80d 100644 --- a/cpp/src/barretenberg/honk/pcs/commitment_key.hpp +++ b/cpp/src/barretenberg/honk/pcs/commitment_key.hpp @@ -12,6 +12,7 @@ #include "barretenberg/ecc/curves/bn254/pairing.hpp" #include "barretenberg/numeric/bitop/pow.hpp" +#include #include #include diff --git a/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp b/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp index 6175d4da46..8f4eb2f6d8 100644 --- a/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp +++ b/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp @@ -1,6 +1,9 @@ #pragma once +#include #include +#include #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" +#include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" // Suggested by Zac: Future optimisations @@ -20,30 +23,13 @@ namespace proof_system::honk::pcs::ipa { template class InnerProductArgument { using Fr = typename Params::Fr; - using element = typename Params::Commitment; - using affine_element = typename Params::C; + using Commitment = typename Params::Commitment; + using CommitmentAffine = typename Params::C; using CK = typename Params::CK; using VK = typename Params::VK; using Polynomial = barretenberg::Polynomial; public: - struct Proof { - std::vector L_vec; - std::vector R_vec; - Fr a_zero; - }; - // To contain the public inputs for IPA proof - // For now we are including the aux_generator and round_challenges in public input. They will be computed by the - // prover and the verifier by Fiat-Shamir when the challengeGenerator is defined. - struct PubInput { - element commitment; - Fr challenge_point; - Fr evaluation; - size_t poly_degree; - element aux_generator; // To be removed - std::vector round_challenges; // To be removed - }; - /** * @brief Compute a proof for opening a single polynomial at a single evaluation point * @@ -54,23 +40,27 @@ template class InnerProductArgument { * @return a Proof, containing information required to verify whether the commitment is computed correctly and * the polynomial evaluation is correct in the given challenge point. */ - static Proof reduce_prove(std::shared_ptr ck, const PubInput& pub_input, const Polynomial& polynomial) + static void reduce_prove(std::shared_ptr ck, + const OpeningPair& opening_pair, + const Polynomial& polynomial, + ProverTranscript& transcript) { - Proof proof; - auto& challenge_point = pub_input.challenge_point; + Fr generator_challenge = transcript.get_challenge("generator_challenge"); + + auto& challenge_point = opening_pair.challenge; ASSERT(challenge_point != 0 && "The challenge point should not be zero"); - const size_t poly_degree = pub_input.poly_degree; + const size_t poly_degree = polynomial.size(); // To check poly_degree is greater than zero and a power of two // TODO(#220)(Arijit): To accomodate non power of two poly_degree ASSERT((poly_degree > 0) && (!(poly_degree & (poly_degree - 1))) && "The poly_degree should be positive and a power of two"); - auto& aux_generator = pub_input.aux_generator; + auto aux_generator = CommitmentAffine::one() * generator_challenge; auto a_vec = polynomial; // TODO(#220)(Arijit): to make it more efficient by directly using G_vector for the input points when i = 0 and // write the output points to G_vec_local. Then use G_vec_local for rounds where i>0, this can be done after we // use SRS instead of G_vector. auto srs_elements = ck->srs.get_monomial_points(); - std::vector G_vec_local(poly_degree); + std::vector G_vec_local(poly_degree); for (size_t i = 0; i < poly_degree; i++) { G_vec_local[i] = srs_elements[i]; } @@ -86,8 +76,8 @@ template class InnerProductArgument { } // Iterate for log_2(poly_degree) rounds to compute the round commitments. const size_t log_poly_degree = static_cast(numeric::get_msb(poly_degree)); - std::vector L_elements(log_poly_degree); - std::vector R_elements(log_poly_degree); + std::vector L_elements(log_poly_degree); + std::vector R_elements(log_poly_degree); size_t round_size = poly_degree; for (size_t i = 0; i < log_poly_degree; i++) { @@ -100,20 +90,24 @@ template class InnerProductArgument { inner_prod_R += a_vec[round_size + j] * b_vec[j]; } // L_i = < a_vec_lo, G_vec_hi > + inner_prod_L * aux_generator - element partial_L = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( + Commitment partial_L = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( &a_vec[0], &G_vec_local[round_size], round_size, ck->pippenger_runtime_state); partial_L += aux_generator * inner_prod_L; // R_i = < a_vec_hi, G_vec_lo > + inner_prod_R * aux_generator - element partial_R = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( + Commitment partial_R = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( &a_vec[round_size], &G_vec_local[0], round_size, ck->pippenger_runtime_state); partial_R += aux_generator * inner_prod_R; - L_elements[i] = affine_element(partial_L); - R_elements[i] = affine_element(partial_R); + L_elements[i] = CommitmentAffine(partial_L); + R_elements[i] = CommitmentAffine(partial_R); - // Generate the round challenge. TODO(#220)(Arijit): Use Fiat-Shamir - const Fr round_challenge = pub_input.round_challenges[i]; + std::string index = std::to_string(i); + transcript.send_to_verifier("IPA:L_" + index, CommitmentAffine(partial_L)); + transcript.send_to_verifier("IPA:R_" + index, CommitmentAffine(partial_R)); + + // Generate the round challenge. + const Fr round_challenge = transcript.get_challenge("IPA:round_challenge_" + index); const Fr round_challenge_inv = round_challenge.invert(); // Update the vectors a_vec, b_vec and G_vec. @@ -137,20 +131,14 @@ template class InnerProductArgument { across multiple points). */ - auto G_lo = element(G_vec_local[j]) * round_challenge_inv; - auto G_hi = element(G_vec_local[round_size + j]) * round_challenge; + auto G_lo = Commitment(G_vec_local[j]) * round_challenge_inv; + auto G_hi = Commitment(G_vec_local[round_size + j]) * round_challenge; auto temp = G_lo + G_hi; G_vec_local[j] = temp.normalize(); } } - proof.L_vec = std::vector(log_poly_degree); - proof.R_vec = std::vector(log_poly_degree); - for (size_t i = 0; i < log_poly_degree; i++) { - proof.L_vec[i] = L_elements[i]; - proof.R_vec[i] = R_elements[i]; - } - proof.a_zero = a_vec[0]; - return proof; + + transcript.send_to_verifier("IPA:a_0", a_vec[0]); } /** @@ -162,50 +150,52 @@ template class InnerProductArgument { * * @return true/false depending on if the proof verifies */ - static bool reduce_verify(std::shared_ptr vk, const Proof& proof, const PubInput& pub_input) + static bool reduce_verify(std::shared_ptr vk, + const OpeningPair& opening_pair, + size_t poly_degree, + VerifierTranscript& transcript) { + auto commitment = transcript.template receive_from_prover("IPA:C"); + + Fr generator_challenge = transcript.get_challenge("generator_challenge"); + auto aux_generator = CommitmentAffine::one() * generator_challenge; + // Local copies of public inputs - auto& a_zero = proof.a_zero; - auto& commitment = pub_input.commitment; - auto& challenge_point = pub_input.challenge_point; - auto& evaluation = pub_input.evaluation; - auto& poly_degree = pub_input.poly_degree; - auto& aux_generator = pub_input.aux_generator; + // auto& a_zero = proof.a_zero; + auto& challenge_point = opening_pair.challenge; + auto& evaluation = opening_pair.evaluation; + size_t log_poly_degree = numeric::get_msb(poly_degree); // Compute C_prime - element C_prime = commitment + (aux_generator * evaluation); + Commitment C_prime = commitment + (aux_generator * evaluation); // Compute the round challeneges and their inverses. - const size_t log_poly_degree = static_cast(numeric::get_msb(poly_degree)); + std::vector L_vec(log_poly_degree); + std::vector R_vec(log_poly_degree); std::vector round_challenges(log_poly_degree); - for (size_t i = 0; i < log_poly_degree; i++) { - round_challenges[i] = pub_input.round_challenges[i]; - } std::vector round_challenges_inv(log_poly_degree); for (size_t i = 0; i < log_poly_degree; i++) { - round_challenges_inv[i] = pub_input.round_challenges[i]; + std::string index = std::to_string(i); + L_vec[i] = transcript.template receive_from_prover("IPA:L_" + index); + R_vec[i] = transcript.template receive_from_prover("IPA:R_" + index); + round_challenges[i] = transcript.get_challenge("IPA:round_challenge_" + index); + round_challenges_inv[i] = round_challenges[i]; } Fr::batch_invert(&round_challenges_inv[0], log_poly_degree); - std::vector L_vec(log_poly_degree); - std::vector R_vec(log_poly_degree); - for (size_t i = 0; i < log_poly_degree; i++) { - L_vec[i] = proof.L_vec[i]; - R_vec[i] = proof.R_vec[i]; - } // Compute C_zero = C_prime + ∑_{j ∈ [k]} u_j^2L_j + ∑_{j ∈ [k]} u_j^{-2}R_j const size_t pippenger_size = 2 * log_poly_degree; - std::vector msm_elements(pippenger_size); + std::vector msm_elements(pippenger_size); std::vector msm_scalars(pippenger_size); for (size_t i = 0; i < log_poly_degree; i++) { - msm_elements[size_t(2) * i] = L_vec[i]; - msm_elements[size_t(2) * i + 1] = R_vec[i]; - msm_scalars[size_t(2) * i] = round_challenges[i] * round_challenges[i]; - msm_scalars[size_t(2) * i + 1] = round_challenges_inv[i] * round_challenges_inv[i]; + msm_elements[2 * i] = L_vec[i]; + msm_elements[2 * i + 1] = R_vec[i]; + msm_scalars[2 * i] = round_challenges[i] * round_challenges[i]; + msm_scalars[2 * i + 1] = round_challenges_inv[i] * round_challenges_inv[i]; } - element LR_sums = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( + Commitment LR_sums = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( &msm_scalars[0], &msm_elements[0], pippenger_size, vk->pippenger_runtime_state); - element C_zero = C_prime + LR_sums; + Commitment C_zero = C_prime + LR_sums; /** * Compute b_zero where b_zero can be computed using the polynomial: @@ -220,6 +210,7 @@ template class InnerProductArgument { b_zero *= round_challenges_inv[log_poly_degree - 1 - i] + (round_challenges[log_poly_degree - 1 - i] * challenge_point.pow(exponent)); } + // Compute G_zero // First construct s_vec std::vector s_vec(poly_degree); @@ -238,13 +229,16 @@ template class InnerProductArgument { } auto srs_elements = vk->srs.get_monomial_points(); // Copy the G_vector to local memory. - std::vector G_vec_local(poly_degree); + std::vector G_vec_local(poly_degree); for (size_t i = 0; i < poly_degree; i++) { G_vec_local[i] = srs_elements[i]; } auto G_zero = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( &s_vec[0], &G_vec_local[0], poly_degree, vk->pippenger_runtime_state); - element right_hand_side = G_zero * a_zero; + + auto a_zero = transcript.template receive_from_prover("IPA:a_0"); + + Commitment right_hand_side = G_zero * a_zero; Fr a_zero_b_zero = a_zero * b_zero; right_hand_side += aux_generator * a_zero_b_zero; return (C_zero.normalize() == right_hand_side.normalize()); diff --git a/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp b/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp index 513e931d47..d30eec5d26 100644 --- a/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp +++ b/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp @@ -36,26 +36,21 @@ TYPED_TEST(IpaCommitmentTest, commit) TYPED_TEST(IpaCommitmentTest, open) { using IPA = InnerProductArgument; - using PubInput = typename IPA::PubInput; // generate a random polynomial, degree needs to be a power of two size_t n = 128; auto poly = this->random_polynomial(n); auto [x, eval] = this->random_eval(poly); - barretenberg::g1::element commitment = this->commit(poly); - PubInput pub_input; - pub_input.commitment = commitment; - pub_input.challenge_point = x; - pub_input.evaluation = eval; - pub_input.poly_degree = n; - auto aux_scalar = fr::random_element(); - pub_input.aux_generator = barretenberg::g1::one * aux_scalar; - const size_t log_n = static_cast(numeric::get_msb(n)); - pub_input.round_challenges = std::vector(log_n); - for (size_t i = 0; i < log_n; i++) { - pub_input.round_challenges[i] = barretenberg::fr::random_element(); - } - auto proof = IPA::reduce_prove(this->ck(), pub_input, poly); - auto result = IPA::reduce_verify(this->vk(), proof, pub_input); + auto commitment = this->commit(poly); + const OpeningPair opening_pair{ x, eval }; + + auto prover_transcript = ProverTranscript::init_empty(); + prover_transcript.send_to_verifier("IPA:C", commitment); + + IPA::reduce_prove(this->ck(), opening_pair, poly, prover_transcript); + + auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + + auto result = IPA::reduce_verify(this->vk(), opening_pair, n, verifier_transcript); EXPECT_TRUE(result); } } // namespace proof_system::honk::pcs::ipa From 5586f5df3a1d9e48a3b89e05ebdccb68b34f9636 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 20 Apr 2023 17:41:01 +0000 Subject: [PATCH 2/2] cleanup and reorg --- cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp | 74 ++++++++----------- .../barretenberg/honk/pcs/ipa/ipa.test.cpp | 9 ++- 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp b/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp index 8f4eb2f6d8..a7eaf54f91 100644 --- a/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp +++ b/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp @@ -34,27 +34,25 @@ template class InnerProductArgument { * @brief Compute a proof for opening a single polynomial at a single evaluation point * * @param ck The commitment key containing srs and pippenger_runtime_state for computing MSM - * @param pub_input Data required to compute the opening proof. See spec for more details + * @param opening_pair (challenge, evaluation) * @param polynomial The witness polynomial whose opening proof needs to be computed - * - * @return a Proof, containing information required to verify whether the commitment is computed correctly and - * the polynomial evaluation is correct in the given challenge point. + * @param transcript Prover transcript */ static void reduce_prove(std::shared_ptr ck, const OpeningPair& opening_pair, const Polynomial& polynomial, ProverTranscript& transcript) { - Fr generator_challenge = transcript.get_challenge("generator_challenge"); + Fr generator_challenge = transcript.get_challenge("IPA:generator_challenge"); + auto aux_generator = CommitmentAffine::one() * generator_challenge; - auto& challenge_point = opening_pair.challenge; - ASSERT(challenge_point != 0 && "The challenge point should not be zero"); + ASSERT(opening_pair.challenge != 0 && "The challenge point should not be zero"); const size_t poly_degree = polynomial.size(); // To check poly_degree is greater than zero and a power of two // TODO(#220)(Arijit): To accomodate non power of two poly_degree ASSERT((poly_degree > 0) && (!(poly_degree & (poly_degree - 1))) && "The poly_degree should be positive and a power of two"); - auto aux_generator = CommitmentAffine::one() * generator_challenge; + auto a_vec = polynomial; // TODO(#220)(Arijit): to make it more efficient by directly using G_vector for the input points when i = 0 and // write the output points to G_vec_local. Then use G_vec_local for rounds where i>0, this can be done after we @@ -72,7 +70,7 @@ template class InnerProductArgument { Fr b_power = 1; for (size_t i = 0; i < poly_degree; i++) { b_vec[i] = b_power; - b_power *= challenge_point; + b_power *= opening_pair.challenge; } // Iterate for log_2(poly_degree) rounds to compute the round commitments. const size_t log_poly_degree = static_cast(numeric::get_msb(poly_degree)); @@ -90,21 +88,18 @@ template class InnerProductArgument { inner_prod_R += a_vec[round_size + j] * b_vec[j]; } // L_i = < a_vec_lo, G_vec_hi > + inner_prod_L * aux_generator - Commitment partial_L = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( + L_elements[i] = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( &a_vec[0], &G_vec_local[round_size], round_size, ck->pippenger_runtime_state); - partial_L += aux_generator * inner_prod_L; + L_elements[i] += aux_generator * inner_prod_L; // R_i = < a_vec_hi, G_vec_lo > + inner_prod_R * aux_generator - Commitment partial_R = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( + R_elements[i] = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( &a_vec[round_size], &G_vec_local[0], round_size, ck->pippenger_runtime_state); - partial_R += aux_generator * inner_prod_R; - - L_elements[i] = CommitmentAffine(partial_L); - R_elements[i] = CommitmentAffine(partial_R); + R_elements[i] += aux_generator * inner_prod_R; std::string index = std::to_string(i); - transcript.send_to_verifier("IPA:L_" + index, CommitmentAffine(partial_L)); - transcript.send_to_verifier("IPA:R_" + index, CommitmentAffine(partial_R)); + transcript.send_to_verifier("IPA:L_" + index, CommitmentAffine(L_elements[i])); + transcript.send_to_verifier("IPA:R_" + index, CommitmentAffine(R_elements[i])); // Generate the round challenge. const Fr round_challenge = transcript.get_challenge("IPA:round_challenge_" + index); @@ -157,41 +152,31 @@ template class InnerProductArgument { { auto commitment = transcript.template receive_from_prover("IPA:C"); - Fr generator_challenge = transcript.get_challenge("generator_challenge"); + Fr generator_challenge = transcript.get_challenge("IPA:generator_challenge"); auto aux_generator = CommitmentAffine::one() * generator_challenge; - // Local copies of public inputs - // auto& a_zero = proof.a_zero; - auto& challenge_point = opening_pair.challenge; - auto& evaluation = opening_pair.evaluation; size_t log_poly_degree = numeric::get_msb(poly_degree); // Compute C_prime - Commitment C_prime = commitment + (aux_generator * evaluation); + Commitment C_prime = commitment + (aux_generator * opening_pair.evaluation); - // Compute the round challeneges and their inverses. - std::vector L_vec(log_poly_degree); - std::vector R_vec(log_poly_degree); + // Compute C_zero = C_prime + ∑_{j ∈ [k]} u_j^2L_j + ∑_{j ∈ [k]} u_j^{-2}R_j + const size_t pippenger_size = 2 * log_poly_degree; std::vector round_challenges(log_poly_degree); std::vector round_challenges_inv(log_poly_degree); + std::vector msm_elements(pippenger_size); + std::vector msm_scalars(pippenger_size); for (size_t i = 0; i < log_poly_degree; i++) { std::string index = std::to_string(i); - L_vec[i] = transcript.template receive_from_prover("IPA:L_" + index); - R_vec[i] = transcript.template receive_from_prover("IPA:R_" + index); + auto element_L = transcript.template receive_from_prover("IPA:L_" + index); + auto element_R = transcript.template receive_from_prover("IPA:R_" + index); round_challenges[i] = transcript.get_challenge("IPA:round_challenge_" + index); - round_challenges_inv[i] = round_challenges[i]; - } - Fr::batch_invert(&round_challenges_inv[0], log_poly_degree); + round_challenges_inv[i] = round_challenges[i].invert(); - // Compute C_zero = C_prime + ∑_{j ∈ [k]} u_j^2L_j + ∑_{j ∈ [k]} u_j^{-2}R_j - const size_t pippenger_size = 2 * log_poly_degree; - std::vector msm_elements(pippenger_size); - std::vector msm_scalars(pippenger_size); - for (size_t i = 0; i < log_poly_degree; i++) { - msm_elements[2 * i] = L_vec[i]; - msm_elements[2 * i + 1] = R_vec[i]; - msm_scalars[2 * i] = round_challenges[i] * round_challenges[i]; - msm_scalars[2 * i + 1] = round_challenges_inv[i] * round_challenges_inv[i]; + msm_elements[2 * i] = element_L; + msm_elements[2 * i + 1] = element_R; + msm_scalars[2 * i] = round_challenges[i].sqr(); + msm_scalars[2 * i + 1] = round_challenges_inv[i].sqr(); } Commitment LR_sums = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points( &msm_scalars[0], &msm_elements[0], pippenger_size, vk->pippenger_runtime_state); @@ -208,7 +193,7 @@ template class InnerProductArgument { for (size_t i = 0; i < log_poly_degree; i++) { auto exponent = static_cast(Fr(2).pow(i)); b_zero *= round_challenges_inv[log_poly_degree - 1 - i] + - (round_challenges[log_poly_degree - 1 - i] * challenge_point.pow(exponent)); + (round_challenges[log_poly_degree - 1 - i] * opening_pair.challenge.pow(exponent)); } // Compute G_zero @@ -238,9 +223,8 @@ template class InnerProductArgument { auto a_zero = transcript.template receive_from_prover("IPA:a_0"); - Commitment right_hand_side = G_zero * a_zero; - Fr a_zero_b_zero = a_zero * b_zero; - right_hand_side += aux_generator * a_zero_b_zero; + Commitment right_hand_side = G_zero * a_zero + aux_generator * a_zero * b_zero; + return (C_zero.normalize() == right_hand_side.normalize()); } }; diff --git a/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp b/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp index d30eec5d26..17d74eb9e9 100644 --- a/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp +++ b/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp @@ -43,14 +43,19 @@ TYPED_TEST(IpaCommitmentTest, open) auto commitment = this->commit(poly); const OpeningPair opening_pair{ x, eval }; - auto prover_transcript = ProverTranscript::init_empty(); + // initialize empty prover transcript + ProverTranscript prover_transcript; + prover_transcript.send_to_verifier("IPA:C", commitment); IPA::reduce_prove(this->ck(), opening_pair, poly, prover_transcript); - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + // initialize verifier transcript from proof data + VerifierTranscript verifier_transcript{ prover_transcript.proof_data }; auto result = IPA::reduce_verify(this->vk(), opening_pair, n, verifier_transcript); EXPECT_TRUE(result); + + EXPECT_EQ(prover_transcript.get_manifest(), verifier_transcript.get_manifest()); } } // namespace proof_system::honk::pcs::ipa