diff --git a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp index 3b2dc618be3..5ad7944451a 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp @@ -13,7 +13,7 @@ namespace { class GoblinBench : public benchmark::Fixture { public: - Goblin::AccumulationOutput kernel_accum; + GoblinAccumulationOutput kernel_accum; // Number of function circuits to accumulate(based on Zacs target numbers) static constexpr size_t NUM_ITERATIONS_MEDIUM_COMPLEXITY = 6; @@ -34,7 +34,7 @@ class GoblinBench : public benchmark::Fixture { * * @param state */ - void perform_goblin_accumulation_rounds(State& state, Goblin& goblin) + void perform_goblin_accumulation_rounds(State& state, GoblinProver& goblin) { auto NUM_CIRCUITS = static_cast(state.range(0)); for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { @@ -63,7 +63,7 @@ class GoblinBench : public benchmark::Fixture { */ BENCHMARK_DEFINE_F(GoblinBench, GoblinFull)(benchmark::State& state) { - Goblin goblin; + GoblinProver goblin; for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); @@ -81,7 +81,7 @@ BENCHMARK_DEFINE_F(GoblinBench, GoblinFull)(benchmark::State& state) */ BENCHMARK_DEFINE_F(GoblinBench, GoblinAccumulate)(benchmark::State& state) { - Goblin goblin; + GoblinProver goblin; // Perform a specified number of iterations of function/kernel accumulation for (auto _ : state) { @@ -95,7 +95,7 @@ BENCHMARK_DEFINE_F(GoblinBench, GoblinAccumulate)(benchmark::State& state) */ BENCHMARK_DEFINE_F(GoblinBench, GoblinECCVMProve)(benchmark::State& state) { - Goblin goblin; + GoblinProver goblin; // Perform a specified number of iterations of function/kernel accumulation perform_goblin_accumulation_rounds(state, goblin); @@ -112,7 +112,7 @@ BENCHMARK_DEFINE_F(GoblinBench, GoblinECCVMProve)(benchmark::State& state) */ BENCHMARK_DEFINE_F(GoblinBench, TranslatorProve)(benchmark::State& state) { - Goblin goblin; + GoblinProver goblin; // Perform a specified number of iterations of function/kernel accumulation perform_goblin_accumulation_rounds(state, goblin); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 53e0eaaa194..b7140e671fc 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -65,7 +65,10 @@ ClientIVC::Proof ClientIVC::prove() bool ClientIVC::verify(Proof& proof, const std::vector>& verifier_instances) { // Goblin verification (merge, eccvm, translator) - bool goblin_verified = goblin.verify(proof.goblin_proof); + auto eccvm_vkey = std::make_shared(goblin.get_eccvm_proving_key()); + auto translator_vkey = std::make_shared(goblin.get_translator_proving_key()); + GoblinVerifier goblin_verifier{ eccvm_vkey, translator_vkey }; + bool goblin_verified = goblin_verifier.verify(proof.goblin_proof); // Decider verification ClientIVC::FoldingVerifier folding_verifier({ verifier_instances[0], verifier_instances[1] }); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index deea3d3c86e..38268e6da7c 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -32,6 +32,8 @@ class ClientIVC { using FoldingProver = ProtoGalaxyProver_; using VerifierInstances = VerifierInstances_; using FoldingVerifier = ProtoGalaxyVerifier_; + using ECCVMVerificationKey = bb::ECCVMFlavor::VerificationKey; + using TranslatorVerificationKey = bb::TranslatorFlavor::VerificationKey; using GURecursiveFlavor = MegaRecursiveFlavor_; using RecursiveVerifierInstances = bb::stdlib::recursion::honk::RecursiveVerifierInstances_; @@ -42,7 +44,7 @@ class ClientIVC { struct Proof { FoldProof folding_proof; // final fold proof HonkProof decider_proof; - Goblin::Proof goblin_proof; + GoblinProof goblin_proof; std::vector to_buffer() const { @@ -66,7 +68,7 @@ class ClientIVC { // be needed in the real IVC as they are provided as inputs public: - Goblin goblin; + GoblinProver goblin; ProverFoldOutput fold_output; std::shared_ptr prover_accumulator; std::shared_ptr verifier_accumulator; diff --git a/barretenberg/cpp/src/barretenberg/dsl/types.hpp b/barretenberg/cpp/src/barretenberg/dsl/types.hpp index f398ee16840..fb48a69622d 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/types.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/types.hpp @@ -27,7 +27,7 @@ namespace acir_format { using Builder = bb::UltraCircuitBuilder; -using GoblinBuilder = bb::Goblin::Builder; +using GoblinBuilder = bb::GoblinProver::Builder; using Composer = plonk::UltraComposer; using Prover = diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 9642799f01a..f0d3462b6ad 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -5,6 +5,7 @@ #include "barretenberg/eccvm/eccvm_trace_checker.hpp" #include "barretenberg/eccvm/eccvm_verifier.hpp" #include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/goblin/types.hpp" #include "barretenberg/plonk_honk_shared/instance_inspector.hpp" #include "barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.hpp" #include "barretenberg/stdlib_circuit_builders/mega_circuit_builder.hpp" @@ -19,7 +20,7 @@ namespace bb { -class Goblin { +class GoblinProver { using MegaCircuitBuilder = bb::MegaCircuitBuilder; using Commitment = MegaFlavor::Commitment; using FF = MegaFlavor::FF; @@ -33,57 +34,30 @@ class Goblin { using ECCVMFlavor = bb::ECCVMFlavor; using ECCVMBuilder = bb::ECCVMCircuitBuilder; using ECCVMProver = bb::ECCVMProver; + using ECCVMProvingKey = ECCVMFlavor::ProvingKey; using TranslationEvaluations = ECCVMProver::TranslationEvaluations; using TranslatorBuilder = bb::TranslatorCircuitBuilder; using TranslatorProver = bb::TranslatorProver; + using TranslatorProvingKey = bb::TranslatorFlavor::ProvingKey; using RecursiveMergeVerifier = bb::stdlib::recursion::goblin::MergeRecursiveVerifier_; using MergeProver = bb::MergeProver_; - using MergeVerifier = bb::MergeVerifier_; using VerificationKey = MegaFlavor::VerificationKey; /** * @brief Output of goblin::accumulate; an Ultra proof and the corresponding verification key * */ - struct AccumulationOutput { - HonkProof proof; - std::shared_ptr verification_key; - }; - - struct Proof { - HonkProof merge_proof; - HonkProof eccvm_proof; - HonkProof translator_proof; - TranslationEvaluations translation_evaluations; - - size_t size() const - { - return merge_proof.size() + eccvm_proof.size() + translator_proof.size() + TranslationEvaluations::size(); - }; - - std::vector to_buffer() const - { - // ACIRHACK: so much copying and duplication added here and elsewhere - std::vector result; - result.reserve(size()); - const auto insert = [&result](const std::vector& buf) { - result.insert(result.end(), buf.begin(), buf.end()); - }; - insert(merge_proof); - insert(eccvm_proof); - insert(translator_proof); - insert(translation_evaluations.to_buffer()); - return result; - } - }; std::shared_ptr op_queue = std::make_shared(); HonkProof merge_proof; - Proof goblin_proof; + GoblinProof goblin_proof; // on the first call to accumulate there is no merge proof to verify bool merge_proof_exists{ false }; + std::shared_ptr get_eccvm_proving_key() const { return eccvm_prover->key; } + std::shared_ptr get_translator_proving_key() const { return translator_prover->key; } + private: // TODO(https://github.com/AztecProtocol/barretenberg/issues/798) unique_ptr use is a hack std::unique_ptr eccvm_builder; @@ -91,10 +65,10 @@ class Goblin { std::unique_ptr translator_prover; std::unique_ptr eccvm_prover; - AccumulationOutput accumulator; // Used only for ACIR methods for now + GoblinAccumulationOutput accumulator; // Used only for ACIR methods for now public: - Goblin() + GoblinProver() { // Mocks the interaction of a first circuit with the op queue due to the inability to currently handle zero // commitments (https://github.com/AztecProtocol/barretenberg/issues/871) which would otherwise appear in the // first round of the merge protocol. To be removed once the issue has been resolved. @@ -106,7 +80,7 @@ class Goblin { * * @param circuit_builder */ - AccumulationOutput accumulate(MegaCircuitBuilder& circuit_builder) + GoblinAccumulationOutput accumulate(MegaCircuitBuilder& circuit_builder) { // Complete the circuit logic by recursively verifying previous merge proof if it exists if (merge_proof_exists) { @@ -197,13 +171,31 @@ class Goblin { * * @return Proof */ - Proof prove() + GoblinProof prove() { goblin_proof.merge_proof = std::move(merge_proof); prove_eccvm(); prove_translator(); return goblin_proof; }; +}; + +class GoblinVerifier { + public: + using ECCVMVerificationKey = ECCVMFlavor::VerificationKey; + using TranslatorVerificationKey = bb::TranslatorFlavor::VerificationKey; + using MergeVerifier = bb::MergeVerifier_; + + private: + std::shared_ptr eccvm_verification_key; + std::shared_ptr translator_verification_key; + + public: + GoblinVerifier(std::shared_ptr eccvm_verification_key, + std::shared_ptr translator_verification_key) + : eccvm_verification_key(eccvm_verification_key) + , translator_verification_key(translator_verification_key) + {} /** * @brief Verify a full Goblin proof (ECCVM, Translator, merge) @@ -212,15 +204,15 @@ class Goblin { * @return true * @return false */ - bool verify(const Proof& proof) + bool verify(const GoblinProof& proof) { MergeVerifier merge_verifier; bool merge_verified = merge_verifier.verify_proof(proof.merge_proof); - ECCVMVerifier eccvm_verifier(eccvm_prover->key); + ECCVMVerifier eccvm_verifier(eccvm_verification_key); bool eccvm_verified = eccvm_verifier.verify_proof(proof.eccvm_proof); - TranslatorVerifier translator_verifier(translator_prover->key, eccvm_verifier.transcript); + TranslatorVerifier translator_verifier(translator_verification_key, eccvm_verifier.transcript); bool accumulator_construction_verified = translator_verifier.verify_proof(proof.translator_proof); // TODO(https://github.com/AztecProtocol/barretenberg/issues/799): Ensure translation_evaluations are passed @@ -229,94 +221,5 @@ class Goblin { return merge_verified && eccvm_verified && accumulator_construction_verified && translation_verified; }; - - // The methods below this point are to be used only for ACIR. They exist while the interface is in flux. Eventually - // there will be agreement and no acir-specific methods should be needed. - - /** - * @brief Construct a MegaHonk proof for the given circuit. (No merge proof for now) - * - * @param circuit_builder - * @return std::vector - */ - std::vector accumulate_for_acir(MegaCircuitBuilder& circuit_builder) - { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): no merge prover for now - // // Complete the circuit logic by recursively verifying previous merge proof if it exists - // if (merge_proof_exists) { - // RecursiveMergeVerifier merge_verifier{ &circuit_builder }; - // [[maybe_unused]] auto pairing_points = merge_verifier.verify_proof(merge_proof); - // } - - // Construct a Honk proof for the main circuit - auto instance = std::make_shared(circuit_builder); - MegaProver prover(instance); - auto ultra_proof = prover.construct_proof(); - auto verification_key = std::make_shared(instance->proving_key); - - accumulator = { ultra_proof, verification_key }; - - // 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 - // MergeProver merge_prover{ op_queue }; - // merge_proof = merge_prover.construct_proof(); - - // if (!merge_proof_exists) { - // merge_proof_exists = true; - // } - - return ultra_proof; - }; - - /** - * @brief Verify a MegaHonk proof - * - * @param proof_buf - * @return true - * @return false - */ - bool verify_accumulator_for_acir(const std::vector& proof_buf) const - { - MegaVerifier verifier{ accumulator.verification_key }; - HonkProof proof{ proof_buf }; - bool verified = verifier.verify_proof(proof); - - return verified; - } - - /** - * @brief Construct a Goblin proof - * - * @return Proof - */ - Proof prove_for_acir() { return prove(); }; - - /** - * @brief Verify a Goblin proof (excluding the merge proof for now) - * - * @return true - * @return false - */ - bool verify_for_acir() const - { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): No merge proof for now - // MergeVerifier merge_verifier; - // bool merge_verified = merge_verifier.verify_proof(goblin_proof.merge_proof); - - ECCVMVerifier eccvm_verifier(eccvm_prover->key); - bool eccvm_verified = eccvm_verifier.verify_proof(goblin_proof.eccvm_proof); - - TranslatorVerifier translator_verifier(translator_prover->key, eccvm_verifier.transcript); - - bool translation_accumulator_construction_verified = - translator_verifier.verify_proof(goblin_proof.translator_proof); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/799): Ensure translation_evaluations are passed - // correctly - bool translation_verified = translator_verifier.verify_translation(goblin_proof.translation_evaluations); - - return /* merge_verified && */ eccvm_verified && translation_accumulator_construction_verified && - translation_verified; - }; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.test.cpp new file mode 100644 index 00000000000..fa5b91590c4 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.test.cpp @@ -0,0 +1,60 @@ +#include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/stdlib_circuit_builders/mega_circuit_builder.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" + +#include + +using namespace bb; + +class GoblinTests : public ::testing::Test { + protected: + static void SetUpTestSuite() + { + srs::init_crs_factory("../srs_db/ignition"); + srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); + } + + using Builder = MegaCircuitBuilder; + using ECCVMVerificationKey = bb::ECCVMFlavor::VerificationKey; + using TranslatorVerificationKey = bb::TranslatorFlavor::VerificationKey; + + static Builder construct_mock_circuit(std::shared_ptr op_queue) + { + Builder circuit{ op_queue }; + MockCircuits::construct_arithmetic_circuit(circuit, /*target_log2_dyadic_size=*/8); + MockCircuits::construct_goblin_ecc_op_circuit(circuit); + return circuit; + } +}; + +/** + * @brief A simple test demonstrating goblin proof construction / verification based on operations from a collection of + * circuits + * + */ +TEST_F(GoblinTests, MultipleCircuits) +{ + GoblinProver goblin; + + // Construct and accumulate multiple circuits + size_t NUM_CIRCUITS = 3; + for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { + auto circuit = construct_mock_circuit(goblin.op_queue); + goblin.merge(circuit); // appends a recurisve merge verifier if a merge proof exists + } + + // Construct a goblin proof which consists of a merge proof and ECCVM/Translator proofs + GoblinProof proof = goblin.prove(); + + // Verify the goblin proof (eccvm, translator, merge); (Construct ECCVM/Translator verification keys from their + // respective proving keys) + auto eccvm_vkey = std::make_shared(goblin.get_eccvm_proving_key()); + auto translator_vkey = std::make_shared(goblin.get_translator_proving_key()); + GoblinVerifier goblin_verifier{ eccvm_vkey, translator_vkey }; + bool verified = goblin_verifier.verify(proof); + + EXPECT_TRUE(verified); +} + +// TODO(https://github.com/AztecProtocol/barretenberg/issues/787) Expand these tests. diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp index 078093d6662..760575a687c 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp @@ -17,11 +17,13 @@ class GoblinRecursionTests : public ::testing::Test { using Curve = curve::BN254; using FF = Curve::ScalarField; - using KernelInput = Goblin::AccumulationOutput; + using KernelInput = GoblinAccumulationOutput; using ProverInstance = ProverInstance_; using VerifierInstance = VerifierInstance_; + using ECCVMVerificationKey = bb::ECCVMFlavor::VerificationKey; + using TranslatorVerificationKey = bb::TranslatorFlavor::VerificationKey; - static Goblin::AccumulationOutput construct_accumulator(MegaCircuitBuilder& builder) + static GoblinAccumulationOutput construct_accumulator(MegaCircuitBuilder& builder) { auto prover_instance = std::make_shared(builder); auto verification_key = std::make_shared(prover_instance->proving_key); @@ -38,9 +40,9 @@ class GoblinRecursionTests : public ::testing::Test { */ TEST_F(GoblinRecursionTests, Vanilla) { - Goblin goblin; + GoblinProver goblin; - Goblin::AccumulationOutput kernel_accum; + GoblinAccumulationOutput kernel_accum; size_t NUM_CIRCUITS = 2; for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { @@ -62,12 +64,15 @@ TEST_F(GoblinRecursionTests, Vanilla) kernel_accum = construct_accumulator(kernel_circuit); } - Goblin::Proof proof = goblin.prove(); + GoblinProof proof = goblin.prove(); // Verify the final ultra proof MegaVerifier ultra_verifier{ kernel_accum.verification_key }; bool ultra_verified = ultra_verifier.verify_proof(kernel_accum.proof); // Verify the goblin proof (eccvm, translator, merge) - bool verified = goblin.verify(proof); + auto eccvm_vkey = std::make_shared(goblin.get_eccvm_proving_key()); + auto translator_vkey = std::make_shared(goblin.get_translator_proving_key()); + GoblinVerifier goblin_verifier{ eccvm_vkey, translator_vkey }; + bool verified = goblin_verifier.verify(proof); EXPECT_TRUE(ultra_verified && verified); } diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp index 40c42b10c3e..a31ee0cc09b 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp @@ -20,7 +20,7 @@ class MegaMockCircuitsPinning : public ::testing::Test { TEST_F(MegaMockCircuitsPinning, FunctionSizes) { const auto run_test = [](bool large) { - Goblin goblin; + GoblinProver goblin; MegaCircuitBuilder app_circuit{ goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(app_circuit, large); auto instance = std::make_shared(app_circuit); @@ -38,8 +38,8 @@ TEST_F(MegaMockCircuitsPinning, RecursionKernelSizes) { const auto run_test = [](bool large) { { - Goblin goblin; - Goblin::AccumulationOutput kernel_accum; + GoblinProver goblin; + GoblinAccumulationOutput kernel_accum; MegaCircuitBuilder app_circuit{ goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(app_circuit, large); auto function_accum = goblin.accumulate(app_circuit); diff --git a/barretenberg/cpp/src/barretenberg/goblin/types.hpp b/barretenberg/cpp/src/barretenberg/goblin/types.hpp new file mode 100644 index 00000000000..e15dff889a8 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/goblin/types.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "barretenberg/eccvm/eccvm_prover.hpp" +#include "barretenberg/honk/proof_system/types/proof.hpp" +#include "barretenberg/stdlib_circuit_builders/mega_flavor.hpp" + +namespace bb { +struct GoblinAccumulationOutput { + HonkProof proof; + std::shared_ptr verification_key; +}; + +struct GoblinProof { + using TranslationEvaluations = bb::ECCVMProver::TranslationEvaluations; + using FF = MegaFlavor::FF; + + HonkProof merge_proof; + HonkProof eccvm_proof; + HonkProof translator_proof; + ECCVMProver::TranslationEvaluations translation_evaluations; + + size_t size() const + { + return merge_proof.size() + eccvm_proof.size() + translator_proof.size() + TranslationEvaluations::size(); + }; + + std::vector to_buffer() const + { + // ACIRHACK: so much copying and duplication added here and elsewhere + std::vector result; + result.reserve(size()); + const auto insert = [&result](const std::vector& buf) { + result.insert(result.end(), buf.begin(), buf.end()); + }; + insert(merge_proof); + insert(eccvm_proof); + insert(translator_proof); + insert(translation_evaluations.to_buffer()); + return result; + } +}; +} // namespace bb