diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 4f5cc1942cd..3b028be637e 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -8,6 +8,8 @@ #include "barretenberg/proof_system/instance_inspector.hpp" #include "barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp" #include "barretenberg/translator_vm/goblin_translator_composer.hpp" +#include "barretenberg/ultra_honk/merge_prover.hpp" +#include "barretenberg/ultra_honk/merge_verifier.hpp" #include "barretenberg/ultra_honk/ultra_composer.hpp" namespace bb { @@ -33,7 +35,8 @@ class Goblin { using TranslatorBuilder = bb::GoblinTranslatorCircuitBuilder; using TranslatorComposer = bb::GoblinTranslatorComposer; using RecursiveMergeVerifier = bb::stdlib::recursion::goblin::MergeRecursiveVerifier_; - using MergeVerifier = bb::MergeVerifier_; + using MergeProver = bb::MergeProver; + using MergeVerifier = bb::MergeVerifier; /** * @brief Output of goblin::accumulate; an Ultra proof and the corresponding verification key * @@ -107,7 +110,7 @@ class Goblin { auto ultra_proof = prover.construct_proof(); // Construct and store the merge proof to be recursively verified on the next call to accumulate - auto merge_prover = composer.create_merge_prover(op_queue); + MergeProver merge_prover{ op_queue }; merge_proof = merge_prover.construct_proof(); if (!merge_proof_exists) { @@ -211,7 +214,7 @@ class Goblin { // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): no merge prover for now since we're not // mocking the first set of ecc ops // // Construct and store the merge proof to be recursively verified on the next call to accumulate - // auto merge_prover = composer.create_merge_prover(op_queue); + // MergeProver merge_prover{ op_queue }; // merge_proof = merge_prover.construct_proof(); // if (!merge_proof_exists) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp index 04c0fd54e41..af5b40ecfc3 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp @@ -48,7 +48,7 @@ class RecursiveMergeVerifierTest : public testing::Test { // Generate a proof over the inner circuit InnerComposer inner_composer; - auto merge_prover = inner_composer.create_merge_prover(op_queue); + MergeProver merge_prover{ op_queue }; auto merge_proof = merge_prover.construct_proof(); // Create a recursive merge verification circuit for the merge proof @@ -61,7 +61,7 @@ class RecursiveMergeVerifierTest : public testing::Test { // Check 1: Perform native merge verification then perform the pairing on the outputs of the recursive merge // verifier and check that the result agrees. - auto native_verifier = inner_composer.create_merge_verifier(); + MergeVerifier native_verifier; bool verified_native = native_verifier.verify_proof(merge_proof); VerifierCommitmentKey pcs_verification_key(0, srs::get_crs_factory()); auto verified_recursive = diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp index b9e5fc5c669..6c948a15e2f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp @@ -5,6 +5,8 @@ #include "barretenberg/common/log.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/ultra_honk/merge_prover.hpp" +#include "barretenberg/ultra_honk/merge_verifier.hpp" #include "barretenberg/ultra_honk/ultra_composer.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" @@ -71,10 +73,10 @@ class GoblinUltraHonkComposerTests : public ::testing::Test { * @brief Construct and verify a Goblin ECC op queue merge proof * */ - bool construct_and_verify_merge_proof(auto& composer, auto& op_queue) + bool construct_and_verify_merge_proof(auto& op_queue) { - auto merge_prover = composer.create_merge_prover(op_queue); - auto merge_verifier = composer.create_merge_verifier(); + MergeProver merge_prover{ op_queue }; + MergeVerifier merge_verifier; auto merge_proof = merge_prover.construct_proof(); bool verified = merge_verifier.verify_proof(merge_proof); @@ -108,7 +110,7 @@ TEST_F(GoblinUltraHonkComposerTests, SingleCircuit) EXPECT_TRUE(honk_verified); // Construct and verify Goblin ECC op queue Merge proof - auto merge_verified = construct_and_verify_merge_proof(composer, op_queue); + auto merge_verified = construct_and_verify_merge_proof(op_queue); EXPECT_TRUE(merge_verified); } @@ -135,7 +137,7 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsMergeOnly) auto composer = GoblinUltraComposer(); // Construct and verify Goblin ECC op queue Merge proof - auto merge_verified = construct_and_verify_merge_proof(composer, op_queue); + auto merge_verified = construct_and_verify_merge_proof(op_queue); EXPECT_TRUE(merge_verified); } } @@ -195,7 +197,7 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsHonkAndMerge) EXPECT_TRUE(honk_verified); // Construct and verify Goblin ECC op queue Merge proof - auto merge_verified = construct_and_verify_merge_proof(composer, op_queue); + auto merge_verified = construct_and_verify_merge_proof(op_queue); EXPECT_TRUE(merge_verified); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp index 328a7ead912..8d39901d419 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp @@ -3,17 +3,18 @@ namespace bb { /** - * Create MergeProver_ + * @brief Create MergeProver + * @details We require an SRS at least as large as the current op queue size in order to commit to the shifted + * per-circuit contribution t_i^{shift} * */ -template -MergeProver_::MergeProver_(const std::shared_ptr& commitment_key, - const std::shared_ptr& op_queue, - const std::shared_ptr& transcript) - : transcript(transcript) - , op_queue(op_queue) - , pcs_commitment_key(commitment_key) -{} +MergeProver::MergeProver(const std::shared_ptr& op_queue) + : op_queue(op_queue) + , pcs_commitment_key(std::make_shared(op_queue->ultra_ops[0].size())) +{ + // Update internal size data in the op queue that allows for extraction of e.g. previous aggregate transcript + op_queue->set_size_data(); +} /** * @brief Prove proper construction of the aggregate Goblin ECC op queue polynomials T_i^(j), j = 1,2,3,4. @@ -26,11 +27,12 @@ MergeProver_::MergeProver_(const std::shared_ptr& commitm * TODO(#746): Prove connection between t_i^{shift}, committed to herein, and t_i, used in the main protocol. See issue * for details (https://github.com/AztecProtocol/barretenberg/issues/746). * - * @tparam Flavor - * @return HonkProof& + * @return honk::proof */ -template HonkProof& MergeProver_::construct_proof() +HonkProof MergeProver::construct_proof() { + transcript = std::make_shared(); + size_t N = op_queue->get_current_size(); // Extract T_i, T_{i-1} @@ -40,14 +42,14 @@ template HonkProof& MergeProver_::construct_proof() ASSERT(T_prev[0].size() > 0); // Construct t_i^{shift} as T_i - T_{i-1} - std::array t_shift; - for (size_t i = 0; i < Flavor::NUM_WIRES; ++i) { + std::array t_shift; + for (size_t i = 0; i < NUM_WIRES; ++i) { t_shift[i] = Polynomial(T_current[i]); t_shift[i] -= T_prev[i]; } // Compute/get commitments [t_i^{shift}], [T_{i-1}], and [T_i] and add to transcript - std::array C_T_current; + std::array C_T_current; for (size_t idx = 0; idx < t_shift.size(); ++idx) { // Get previous transcript commitment [T_{i-1}] from op queue auto C_T_prev = op_queue->ultra_ops_commitments[idx]; @@ -72,20 +74,20 @@ template HonkProof& MergeProver_::construct_proof() // Add univariate opening claims for each polynomial. std::vector opening_claims; // Compute evaluation T_{i-1}(\kappa) - for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { auto polynomial = Polynomial(T_prev[idx]); auto evaluation = polynomial.evaluate(kappa); transcript->send_to_verifier("T_prev_eval_" + std::to_string(idx + 1), evaluation); opening_claims.emplace_back(OpeningClaim{ polynomial, { kappa, evaluation } }); } // Compute evaluation t_i^{shift}(\kappa) - for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { auto evaluation = t_shift[idx].evaluate(kappa); transcript->send_to_verifier("t_shift_eval_" + std::to_string(idx + 1), evaluation); opening_claims.emplace_back(OpeningClaim{ t_shift[idx], { kappa, evaluation } }); } // Compute evaluation T_i(\kappa) - for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { auto polynomial = Polynomial(T_current[idx]); auto evaluation = polynomial.evaluate(kappa); transcript->send_to_verifier("T_current_eval_" + std::to_string(idx + 1), evaluation); @@ -112,11 +114,7 @@ template HonkProof& MergeProver_::construct_proof() auto quotient_commitment = pcs_commitment_key->commit(quotient); transcript->send_to_verifier("KZG:W", quotient_commitment); - proof = transcript->proof_data; - return proof; + return transcript->proof_data; } -template class MergeProver_; -template class MergeProver_; - -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp index 5ba8c85769e..a615f9f816c 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp @@ -12,31 +12,28 @@ namespace bb { /** * @brief Prover class for the Goblin ECC op queue transcript merge protocol * - * @tparam Flavor */ -template class MergeProver_ { - using FF = typename Flavor::FF; - using Polynomial = typename Flavor::Polynomial; - using CommitmentKey = typename Flavor::CommitmentKey; - using Commitment = typename Flavor::Commitment; - using PCS = typename Flavor::PCS; - using Curve = typename Flavor::Curve; - using OpeningClaim = ProverOpeningClaim; - using OpeningPair = bb::OpeningPair; +class MergeProver { + using Curve = curve::BN254; + using FF = Curve::ScalarField; + using Polynomial = polynomial; + using CommitmentKey = bb::CommitmentKey; + using Commitment = Curve::AffineElement; + using PCS = bb::KZG; + using OpeningClaim = typename bb::ProverOpeningClaim; using Transcript = BaseTranscript; public: std::shared_ptr transcript; - std::shared_ptr op_queue; - std::shared_ptr pcs_commitment_key; - explicit MergeProver_(const std::shared_ptr&, - const std::shared_ptr&, - const std::shared_ptr& transcript = std::make_shared()); - BBERG_PROFILE HonkProof& construct_proof(); + explicit MergeProver(const std::shared_ptr&); + + BBERG_PROFILE HonkProof construct_proof(); private: - HonkProof proof; + std::shared_ptr op_queue; + std::shared_ptr pcs_commitment_key; + static constexpr size_t NUM_WIRES = GoblinUltraFlavor::NUM_WIRES; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index c00504c95a5..f8eb261b195 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -2,10 +2,8 @@ namespace bb { -template -MergeVerifier_::MergeVerifier_() - : transcript(std::make_shared()) - , pcs_verification_key(std::make_unique(0, bb::srs::get_crs_factory())){}; +MergeVerifier::MergeVerifier() + : pcs_verification_key(std::make_unique(0, bb::srs::get_crs_factory())){}; /** * @brief Verify proper construction of the aggregate Goblin ECC op queue polynomials T_i^(j), j = 1,2,3,4. @@ -15,18 +13,17 @@ MergeVerifier_::MergeVerifier_() * M_{i-1}), where the shift magnitude M_{i-1} is the length of T_{i-1}. This protocol verfies that the aggregate op * queue has been constructed correctly via a simple Schwartz-Zippel check. Evaluations are checked via batched KZG. * - * @tparam Flavor * @return HonkProof& */ -template bool MergeVerifier_::verify_proof(const HonkProof& proof) +bool MergeVerifier::verify_proof(const HonkProof& proof) { transcript = std::make_shared(proof); // Receive commitments [t_i^{shift}], [T_{i-1}], and [T_i] - std::array C_T_prev; - std::array C_t_shift; - std::array C_T_current; - for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + std::array C_T_prev; + std::array C_t_shift; + std::array C_T_current; + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { C_T_prev[idx] = transcript->template receive_from_prover("T_PREV_" + std::to_string(idx + 1)); C_t_shift[idx] = transcript->template receive_from_prover("t_SHIFT_" + std::to_string(idx + 1)); C_T_current[idx] = transcript->template receive_from_prover("T_CURRENT_" + std::to_string(idx + 1)); @@ -35,19 +32,19 @@ template bool MergeVerifier_::verify_proof(const HonkP FF kappa = transcript->get_challenge("kappa"); // Receive transcript poly evaluations and add corresponding univariate opening claims {(\kappa, p(\kappa), [p(X)]} - std::array T_prev_evals; - std::array t_shift_evals; - std::array T_current_evals; + std::array T_prev_evals; + std::array t_shift_evals; + std::array T_current_evals; std::vector opening_claims; - for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { T_prev_evals[idx] = transcript->template receive_from_prover("T_prev_eval_" + std::to_string(idx + 1)); opening_claims.emplace_back(OpeningClaim{ { kappa, T_prev_evals[idx] }, C_T_prev[idx] }); } - for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { t_shift_evals[idx] = transcript->template receive_from_prover("t_shift_eval_" + std::to_string(idx + 1)); opening_claims.emplace_back(OpeningClaim{ { kappa, t_shift_evals[idx] }, C_t_shift[idx] }); } - for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { T_current_evals[idx] = transcript->template receive_from_prover("T_current_eval_" + std::to_string(idx + 1)); opening_claims.emplace_back(OpeningClaim{ { kappa, T_current_evals[idx] }, C_T_current[idx] }); @@ -55,7 +52,7 @@ template bool MergeVerifier_::verify_proof(const HonkP // Check the identity T_i(\kappa) = T_{i-1}(\kappa) + t_i^{shift}(\kappa). If it fails, return false bool identity_checked = true; - for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + for (size_t idx = 0; idx < NUM_WIRES; ++idx) { identity_checked = identity_checked && (T_current_evals[idx] == T_prev_evals[idx] + t_shift_evals[idx]); } @@ -79,7 +76,4 @@ template bool MergeVerifier_::verify_proof(const HonkP return identity_checked && verified; } -template class MergeVerifier_; -template class MergeVerifier_; - -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index 8081c060450..efd95773b6f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -13,27 +13,25 @@ namespace bb { /** * @brief Verifier class for the Goblin ECC op queue transcript merge protocol * - * @tparam Flavor */ -template class MergeVerifier_ { - using FF = typename Flavor::FF; - using Polynomial = typename Flavor::Polynomial; - using CommitmentKey = typename Flavor::CommitmentKey; - using Commitment = typename Flavor::Commitment; - using PCS = typename Flavor::PCS; - using Curve = typename Flavor::Curve; - using OpeningClaim = typename bb::OpeningClaim; - using VerificationKey = typename Flavor::VerificationKey; - using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; - using Transcript = typename Flavor::Transcript; +class MergeVerifier { + using Curve = curve::BN254; + using FF = typename Curve::ScalarField; + using Commitment = typename Curve::AffineElement; + using PCS = bb::KZG; + using OpeningClaim = bb::OpeningClaim; + using VerifierCommitmentKey = bb::VerifierCommitmentKey; + using Transcript = BaseTranscript; public: std::shared_ptr transcript; - std::shared_ptr op_queue; - std::shared_ptr pcs_verification_key; - explicit MergeVerifier_(); + explicit MergeVerifier(); bool verify_proof(const HonkProof& proof); + + private: + std::shared_ptr pcs_verification_key; + static constexpr size_t NUM_WIRES = GoblinUltraFlavor::NUM_WIRES; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp index 57ae8c06f99..ea929b92033 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp @@ -7,8 +7,6 @@ #include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" #include "barretenberg/srs/global_crs.hpp" #include "barretenberg/sumcheck/instance/prover_instance.hpp" -#include "barretenberg/ultra_honk/merge_prover.hpp" -#include "barretenberg/ultra_honk/merge_verifier.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -83,33 +81,6 @@ template class UltraComposer_ { UltraVerifier_ create_ultra_with_keccak_verifier(CircuitBuilder& circuit); - /** - * @brief Create Prover for Goblin ECC op queue merge protocol - * - * @param op_queue - * @return MergeProver_ - * TODO(https://github.com/AztecProtocol/barretenberg/issues/804): Goblin should be responsible for constructing - * merge prover/verifier. - */ - MergeProver_ create_merge_prover( - const std::shared_ptr& op_queue, - const std::shared_ptr& transcript = std::make_shared()) - { - // Store the previous aggregate op queue size and update the current one - op_queue->set_size_data(); - // Merge requires a commitment key with size equal to that of the current op queue transcript T_i since the - // shift of the current contribution t_i will be of degree equal to deg(T_i) - auto commitment_key = compute_commitment_key(op_queue->get_current_size()); - return MergeProver_(commitment_key, op_queue, transcript); - } - - /** - * @brief Create Verifier for Goblin ECC op queue merge protocol - * - * @return MergeVerifier_ - */ - MergeVerifier_ create_merge_verifier() { return MergeVerifier_(); } - ProtoGalaxyProver_ create_folding_prover(const std::vector>& instances) { ProtoGalaxyProver_ output_state(instances, commitment_key);