diff --git a/cpp/src/barretenberg/honk/pcs/commitment_key.hpp b/cpp/src/barretenberg/honk/pcs/commitment_key.hpp index 81aec686f4..bd8138326f 100644 --- a/cpp/src/barretenberg/honk/pcs/commitment_key.hpp +++ b/cpp/src/barretenberg/honk/pcs/commitment_key.hpp @@ -198,8 +198,7 @@ namespace ipa { /** * @brief CommitmentKey object over a group 𝔾₁, using a structured reference string (SRS). - * The SRS is given as a list of 𝔾₁ points - * { [xʲ]₁ }ⱼ where 'x' is unknown. + * The SRS is given as a list of 𝔾₁ points { [xʲ]₁ }ⱼ where 'x' is unknown. * * @todo This class should take ownership of the SRS, and handle reading the file from disk. */ @@ -216,7 +215,7 @@ class CommitmentKey { CommitmentKey() = delete; /** - * @brief Construct a new Kate Commitment Key object from existing SRS + * @brief Construct a new IPA Commitment Key object from existing SRS * * @param n * @param path @@ -257,10 +256,10 @@ class VerificationKey { VerificationKey() = delete; /** - * @brief Construct a new Kate Commitment Key object from existing SRS - * - * - * @param verifier_srs verifier G2 point + * @brief Construct a new IPA Verification Key object from existing SRS. srs and pippenger_runtime_state are set + * public to be used in 'reduce_verify` method for MSM + * @param num_points + * @param path */ VerificationKey(const size_t num_points, std::string_view path) : pippenger_runtime_state(num_points) diff --git a/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp b/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp index b4add52fe5..92b87c9e91 100644 --- a/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp +++ b/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp @@ -32,44 +32,48 @@ template class InnerProductArgument { 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 * - * @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 ck Commitment key contains srs and pippenger_runtime_state for computing MSM + * @param opening_pair OpeningPair = {challenge_point, evaluation = polynomial(challenge_point)} * @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 + * @return a Proof, contains 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 Proof reduce_prove(std::shared_ptr ck, + const OpeningPair& opening_pair, + const Polynomial& polynomial, + const auto& transcript) { Proof proof; - auto& challenge_point = pub_input.challenge_point; + auto& challenge_point = opening_pair.query; 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 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 commitment = ck->commit(polynomial); + auto& evaluation = opening_pair.evaluation; + transcript->add_element("ipa_commitment", static_cast(commitment).to_buffer()); + transcript->add_element("ipa_challenge_point", static_cast(challenge_point).to_buffer()); + transcript->add_element("ipa_eval", static_cast(evaluation).to_buffer()); + transcript->apply_fiat_shamir("ipa_aux"); + + const Fr aux_challenge = Fr::serialize_from_buffer(transcript->get_challenge("ipa_aux").begin()); auto srs_elements = ck->srs.get_monomial_points(); + const auto aux_generator = srs_elements[poly_degree] * aux_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. + std::vector G_vec_local(poly_degree); for (size_t i = 0; i < poly_degree; i++) { G_vec_local[i] = srs_elements[i]; @@ -111,9 +115,13 @@ template class InnerProductArgument { L_elements[i] = affine_element(partial_L); R_elements[i] = affine_element(partial_R); - - // Generate the round challenge. TODO(#220)(Arijit): Use Fiat-Shamir - const Fr round_challenge = pub_input.round_challenges[i]; + // Using Fiat-Shamir + auto label = std::to_string(i); + transcript->add_element("L_" + label, static_cast(partial_L).to_buffer()); + transcript->add_element("R_" + label, static_cast(partial_R).to_buffer()); + transcript->apply_fiat_shamir("ipa_round_" + label); + const Fr round_challenge = + Fr::serialize_from_buffer(transcript->get_challenge("ipa_round_" + label).begin()); const Fr round_challenge_inv = round_challenge.invert(); // Update the vectors a_vec, b_vec and G_vec. @@ -156,34 +164,41 @@ template class InnerProductArgument { /** * @brief Verify the correctness of a Proof * - * @param vk Verification_key containing srs and pippenger_runtime_state to be used for MSM - * @param proof The proof containg L_vec, R_vec and a_zero - * @param pub_input Data required to verify the proof + * @param vk Verification_key contains the srs and pippenger_runtime_state to be used for MSM + * @param claim OpeningClaim contains the commitment, challenge, and the evaluation + * @param proof Proof contains L_vec, R_vec, and a_zero + * @param transcript Transcript contains the round challenges and the aux challenge * * @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 OpeningClaim& claim, + const Proof& proof, + const auto& transcript) { - // 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& commitment = claim.commitment; + auto& challenge_point = claim.opening_pair.query; + auto& evaluation = claim.opening_pair.evaluation; + const auto& log_poly_degree = static_cast(proof.L_vec.size()); + const auto& poly_degree = static_cast(static_cast(Fr(2).pow(log_poly_degree))); + + const Fr aux_challenge = Fr::serialize_from_buffer(transcript->get_challenge("ipa_aux").begin()); + auto srs_elements = vk->srs.get_monomial_points(); + const auto aux_generator = srs_elements[poly_degree] * aux_challenge; // Compute C_prime element 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 round_challenges(log_poly_degree); for (size_t i = 0; i < log_poly_degree; i++) { - round_challenges[i] = pub_input.round_challenges[i]; + auto label = std::to_string(i); + round_challenges[i] = Fr::serialize_from_buffer(transcript->get_challenge("ipa_round_" + label).begin()); } 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]; + round_challenges_inv[i] = round_challenges[i]; } Fr::batch_invert(&round_challenges_inv[0], log_poly_degree); std::vector L_vec(log_poly_degree); @@ -236,14 +251,9 @@ template class InnerProductArgument { } s_vec[i] = s_vec_scalar; } - auto srs_elements = vk->srs.get_monomial_points(); - // Copy the G_vector to local memory. - 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); + &s_vec[0], &srs_elements[0], poly_degree, vk->pippenger_runtime_state); element 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; diff --git a/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp b/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp index 39bd880312..f25bdc9264 100644 --- a/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp +++ b/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp @@ -6,6 +6,7 @@ #include "barretenberg/ecc/curves/bn254/fq12.hpp" #include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/honk/pcs/commitment_key.test.hpp" +#include "barretenberg/transcript/manifest.hpp" using namespace barretenberg; namespace honk::pcs::ipa { @@ -18,6 +19,41 @@ template class IpaCommitmentTest : public CommitmentTest using Polynomial = barretenberg::Polynomial; }; +// Creating mock manifest to test only the IPA PCS + +static transcript::Manifest create_mock_manifest(const size_t num_ipa_rounds) +{ + constexpr size_t g1_size = 64; + constexpr size_t fr_size = 32; + std::vector manifest_rounds; + + std::vector aux_generator_entries; + aux_generator_entries.emplace_back(transcript::Manifest::ManifestEntry( + { .name = "ipa_commitment", .num_bytes = g1_size, .derived_by_verifier = false })); + aux_generator_entries.emplace_back(transcript::Manifest::ManifestEntry( + { .name = "ipa_challenge_point", .num_bytes = fr_size, .derived_by_verifier = false })); + aux_generator_entries.emplace_back(transcript::Manifest::ManifestEntry( + { .name = "ipa_eval", .num_bytes = fr_size, .derived_by_verifier = false })); + manifest_rounds.emplace_back(transcript::Manifest::RoundManifest(aux_generator_entries, + /* challenge_name = */ "ipa_aux", + /* num_challenges_in */ 1)); + std::vector ipa_round_challenges_entries; + for (size_t i = 0; i < num_ipa_rounds; i++) { + auto label = std::to_string(i); + ipa_round_challenges_entries.emplace_back(transcript::Manifest::ManifestEntry( + { .name = "L_" + label, .num_bytes = g1_size, .derived_by_verifier = false })); + ipa_round_challenges_entries.emplace_back(transcript::Manifest::ManifestEntry( + { .name = "R_" + label, .num_bytes = g1_size, .derived_by_verifier = false })); + manifest_rounds.emplace_back(transcript::Manifest::RoundManifest(ipa_round_challenges_entries, + /* challenge_name = */ "ipa_round_" + label, + /* num_challenges_in */ 1)); + ipa_round_challenges_entries.clear(); + }; + + auto output = transcript::Manifest(manifest_rounds); + return output; +} + TYPED_TEST_SUITE(IpaCommitmentTest, IpaCommitmentSchemeParams); TYPED_TEST(IpaCommitmentTest, commit) @@ -36,26 +72,20 @@ 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; + const size_t log_n = static_cast(numeric::get_msb(n)); + using Transcript = transcript::StandardTranscript; + auto transcript = std::make_shared(create_mock_manifest(log_n)); auto poly = this->random_polynomial(n); - auto [x, eval] = this->random_eval(poly); + auto [challenge_point, 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 opening_pair = OpeningPair{ challenge_point, eval }; + auto opening_claim = OpeningClaim{ opening_pair, commitment }; + + auto proof = IPA::reduce_prove(this->ck(), opening_pair, poly, transcript); + auto result = IPA::reduce_verify(this->vk(), opening_claim, proof, transcript); EXPECT_TRUE(result); } } // namespace honk::pcs::ipa