From 38a73270323d5b7041b8597289c5219bf09ff4e9 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 2 Feb 2024 03:46:07 +0000 Subject: [PATCH 01/23] gob recusion test with goblin.merge --- .../goblin/full_goblin_recursion.test.cpp | 54 +++++++++++++++++++ .../cpp/src/barretenberg/goblin/goblin.hpp | 24 +++++++++ .../src/barretenberg/goblin/mock_circuits.hpp | 15 ++++++ 3 files changed, 93 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp index 04968199532..bb4a356f574 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp @@ -25,6 +25,16 @@ class GoblinRecursionTests : public ::testing::Test { using FF = Curve::ScalarField; using GoblinUltraBuilder = GoblinUltraCircuitBuilder; using KernelInput = Goblin::AccumulationOutput; + + static Goblin::AccumulationOutput construct_accumulator(GoblinUltraBuilder& builder) + { + GoblinUltraComposer composer; + auto instance = composer.create_instance(builder); + auto prover = composer.create_prover(instance); + info("function proof"); + auto ultra_proof = prover.construct_proof(); + return { ultra_proof, instance->verification_key }; + } }; /** * @brief A full Goblin test that mimicks the basic aztec client architecture @@ -59,4 +69,48 @@ TEST_F(GoblinRecursionTests, Pseudo) EXPECT_TRUE(ultra_verified && verified); } +/** + * @brief A full Goblin test that mimicks the basic aztec client architecture + * @details + */ +TEST_F(GoblinRecursionTests, Vanilla) +{ + Goblin goblin; + + Goblin::AccumulationOutput kernel_accum; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): + GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + + size_t NUM_CIRCUITS = 2; + for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + + // Construct and accumulate a mock function circuit + GoblinUltraCircuitBuilder function_circuit{ goblin.op_queue }; + GoblinMockCircuits::construct_arithmetic_circuit(function_circuit, 1 << 8); + GoblinMockCircuits::construct_goblin_ecc_op_circuit(function_circuit); + info("function merge"); + goblin.merge(function_circuit); + auto function_accum = construct_accumulator(function_circuit); + + // Construct and accumulate the mock kernel circuit (no kernel accum in first round) + GoblinUltraCircuitBuilder kernel_circuit{ goblin.op_queue }; + GoblinMockCircuits::construct_mock_kernel_small(kernel_circuit, function_accum, kernel_accum); + info("kernel accum"); + goblin.merge(kernel_circuit); + kernel_accum = construct_accumulator(kernel_circuit); + } + + info("goblin prove"); + Goblin::Proof proof = goblin.prove(); + // Verify the final ultra proof + GoblinUltraVerifier ultra_verifier{ kernel_accum.verification_key }; + info("ultra verify"); + bool ultra_verified = ultra_verifier.verify_proof(kernel_accum.proof); + // Verify the goblin proof (eccvm, translator, merge) + info("goblin verify"); + bool verified = goblin.verify(proof); + EXPECT_TRUE(ultra_verified && verified); +} + // TODO(https://github.com/AztecProtocol/barretenberg/issues/787) Expand these tests. diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 4913695c918..7077d0e9e27 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -119,6 +119,30 @@ class Goblin { return { ultra_proof, instance->verification_key }; }; + /** + * @brief Construct a GUH proof and a merge proof for the present circuit. + * @details If there is a previous merge proof, recursively verify it. + * + * @param circuit_builder + */ + void merge(GoblinUltraCircuitBuilder& circuit_builder) + { + // 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 and store the merge proof to be recursively verified on the next call to accumulate + GoblinUltraComposer composer; + auto merge_prover = composer.create_merge_prover(op_queue); + merge_proof = merge_prover.construct_proof(); + + if (!merge_proof_exists) { + merge_proof_exists = true; + } + }; + /** * @brief Construct an ECCVM proof and the translation polynomial evaluations * diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index db98486ddbb..75a1df13800 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -197,5 +197,20 @@ class GoblinMockCircuits { verifier2.verify_proof(prev_kernel_accum.proof); } } + + static void construct_mock_kernel_small(GoblinUltraBuilder& builder, + const KernelInput& function_accum, + const KernelInput& prev_kernel_accum) + { + // Execute recursive aggregation of function proof + RecursiveVerifier verifier1{ &builder, function_accum.verification_key }; + verifier1.verify_proof(function_accum.proof); + + // Execute recursive aggregation of previous kernel proof if one exists + if (!prev_kernel_accum.proof.empty()) { + RecursiveVerifier verifier2{ &builder, prev_kernel_accum.verification_key }; + verifier2.verify_proof(prev_kernel_accum.proof); + } + } }; } // namespace bb From d5c3dbec30c991abe869e7e4f899d69d97666d8d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 2 Feb 2024 16:43:09 +0000 Subject: [PATCH 02/23] new folding test suite --- .../goblin/goblin_folding.test.cpp | 106 ++++++++++++++++++ ...ion.test.cpp => goblin_recursion.test.cpp} | 5 - 2 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp rename barretenberg/cpp/src/barretenberg/goblin/{full_goblin_recursion.test.cpp => goblin_recursion.test.cpp} (92%) diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp new file mode 100644 index 00000000000..a5d17b8ff4f --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp @@ -0,0 +1,106 @@ +#include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/goblin/mock_circuits.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/ultra_composer.hpp" + +#include +using namespace bb; +using namespace bb::honk; + +class GoblinFoldingTests : public ::testing::Test { + protected: + static void SetUpTestSuite() + { + srs::init_crs_factory("../srs_db/ignition"); + srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); + } + + using Curve = curve::BN254; + using FF = Curve::ScalarField; + using GoblinUltraBuilder = GoblinUltraCircuitBuilder; + using KernelInput = Goblin::AccumulationOutput; + using GUHFlavor = flavor::GoblinUltra; + using Instance = ProverInstance_; + using FoldingOutput = FoldingResult; + + static GoblinUltraBuilder create_function_circuit(auto& op_queue) + { + GoblinUltraCircuitBuilder function_circuit{ op_queue }; + GoblinMockCircuits::construct_arithmetic_circuit(function_circuit, 1 << 8); + GoblinMockCircuits::construct_goblin_ecc_op_circuit(function_circuit); + return function_circuit; + } + + static FoldingOutput construct_folding_accumulator(GoblinUltraBuilder& builder, + const std::shared_ptr& accumulator) + { + GoblinUltraComposer composer; + auto instance = composer.create_instance(builder); + std::vector> instances{ accumulator, instance }; + auto folding_prover = composer.create_folding_prover(instances); + return folding_prover.fold_instances(); + } +}; + +/** + * @brief A full Goblin test that mimicks the basic aztec client architecture + * @details + */ +TEST_F(GoblinFoldingTests, Folding) +{ + Goblin goblin; + + Goblin::AccumulationOutput kernel_accum; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): + GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + + // Perform "Round 0" + auto function_circuit = create_function_circuit(goblin.op_queue); + auto kernel_circuit = create_function_circuit(goblin.op_queue); + + GoblinUltraComposer composer; + auto fctn_instance = composer.create_instance(function_circuit); + auto kernel_instance = composer.create_instance(kernel_circuit); + std::vector> instances{ fctn_instance, kernel_instance }; + auto folding_prover = composer.create_folding_prover(instances); + auto folding_output = folding_prover.fold_instances(); + auto fold_proof = folding_output.folding_data; + std::shared_ptr accum_instance{ folding_output.accumulator }; + auto folding_verifier = composer.create_folding_verifier(); + auto folding_verified = folding_verifier.verify_folding_proof(fold_proof); + EXPECT_TRUE(folding_verified); + + // size_t NUM_CIRCUITS = 2; + // for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + + // // Construct and accumulate a mock function circuit + // auto function_circuit = create_function_circuit(goblin.op_queue); + // info("function merge"); + // goblin.merge(function_circuit); + // // WORKTODO + // auto function_accum = construct_folding_accumulator(function_circuit); + + // // Construct and accumulate the mock kernel circuit (no kernel accum in first round) + // GoblinUltraCircuitBuilder kernel_circuit{ goblin.op_queue }; + // // WORKTODO + // // GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, function_accum, kernel_accum); + // info("kernel accum"); + // goblin.merge(kernel_circuit); + // // WORKTODO + // // kernel_accum = construct_folding_accumulator(kernel_circuit); + // } + + // // WORKTODO: do we need to execute the decider prover here? Should this happen instead of the last folding accum? + + // info("goblin prove"); + // Goblin::Proof proof = goblin.prove(); + // // WORKTODO: Execute the decider verifier + // // Verify the goblin proof (eccvm, translator, merge) + // info("goblin verify"); + // bool verified = goblin.verify(proof); + // EXPECT_TRUE(verified); + // // WORKTODO: check decider result as well + // // EXPECT_TRUE(ultra_verified && verified); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp similarity index 92% rename from barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp rename to barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp index bb4a356f574..68c3643972c 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp @@ -1,12 +1,7 @@ -#include "barretenberg/eccvm/eccvm_composer.hpp" #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" -#include "barretenberg/goblin/translation_evaluations.hpp" -#include "barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" -#include "barretenberg/translator_vm/goblin_translator_composer.hpp" #include "barretenberg/ultra_honk/ultra_composer.hpp" #include From bb728f702521c363ba828a83e792f891e443ccbf Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 2 Feb 2024 21:16:47 +0000 Subject: [PATCH 03/23] WiP; cant fold recursive folding verifier circuit --- .../cpp/src/barretenberg/goblin/goblin.hpp | 11 +- .../goblin/goblin_folding.test.cpp | 210 +++++++++++++----- .../ultra_honk/protogalaxy.test.cpp | 1 + 3 files changed, 163 insertions(+), 59 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 309c91eb467..8c56a915cb9 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -120,9 +120,11 @@ class Goblin { return { ultra_proof, instance->verification_key }; }; - /** - * @brief Construct a GUH proof and a merge proof for the present circuit. - * @details If there is a previous merge proof, recursively verify it. + /** WORKTODO + * @brief Similar to "accumulate" but only does merge-related stuff, no proving + * @details When this method is used, the "prover" functionality of the IVC scheme must be performed explicitly, but + * this method has to be called first so that the recursive merge verifier can be "appended" to the circuit being + * accumulated * * @param circuit_builder */ @@ -135,8 +137,7 @@ class Goblin { } // Construct and store the merge proof to be recursively verified on the next call to accumulate - GoblinUltraComposer composer; - 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/goblin/goblin_folding.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp index a5d17b8ff4f..de9fd933ee4 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp @@ -2,11 +2,11 @@ #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" #include "barretenberg/ultra_honk/ultra_composer.hpp" #include using namespace bb; -using namespace bb::honk; class GoblinFoldingTests : public ::testing::Test { protected: @@ -18,81 +18,132 @@ class GoblinFoldingTests : public ::testing::Test { using Curve = curve::BN254; using FF = Curve::ScalarField; - using GoblinUltraBuilder = GoblinUltraCircuitBuilder; + using Builder = GoblinUltraCircuitBuilder; + using Composer = GoblinUltraComposer; using KernelInput = Goblin::AccumulationOutput; - using GUHFlavor = flavor::GoblinUltra; - using Instance = ProverInstance_; - using FoldingOutput = FoldingResult; + using Instance = ProverInstance_; + using FoldingOutput = FoldingResult; + using FoldProof = HonkProof; - static GoblinUltraBuilder create_function_circuit(auto& op_queue) + using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; + using RecursiveVerifierInstances = ::bb::VerifierInstances_; + using FoldingRecursiveVerifier = + bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + + // Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2) + static void create_mock_function_circuit(Builder& builder, size_t num_gates = 1 << 15) { - GoblinUltraCircuitBuilder function_circuit{ op_queue }; - GoblinMockCircuits::construct_arithmetic_circuit(function_circuit, 1 << 8); - GoblinMockCircuits::construct_goblin_ecc_op_circuit(function_circuit); - return function_circuit; + GoblinMockCircuits::construct_arithmetic_circuit(builder, num_gates); + GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); } - static FoldingOutput construct_folding_accumulator(GoblinUltraBuilder& builder, - const std::shared_ptr& accumulator) + static HonkProof construct_fold_proof_and_update_accumulator(std::shared_ptr& accumulator, + Builder& circuit_to_fold) { - GoblinUltraComposer composer; - auto instance = composer.create_instance(builder); + Composer composer; + auto instance = composer.create_instance(circuit_to_fold); std::vector> instances{ accumulator, instance }; auto folding_prover = composer.create_folding_prover(instances); - return folding_prover.fold_instances(); + auto output = folding_prover.fold_instances(); + accumulator = output.accumulator; + auto fold_proof = output.folding_data; + return fold_proof; + } + + static bool decide_and_verify(std::shared_ptr& accumulator) + { + Composer composer; + auto decider_prover = composer.create_decider_prover(accumulator); + auto decider_verifier = composer.create_decider_verifier(accumulator); + auto decider_proof = decider_prover.construct_proof(); + auto verified = decider_verifier.verify_proof(decider_proof); + return verified; + } + + static void construct_mock_folding_kernel(Builder& builder, + FoldProof& fctn_fold_proof, + FoldProof& kernel_fold_proof) + { + FoldingRecursiveVerifier verifier_1{ &builder }; + verifier_1.verify_folding_proof(fctn_fold_proof); + + FoldingRecursiveVerifier verifier_2{ &builder }; + verifier_2.verify_folding_proof(kernel_fold_proof); + + Composer composer; + auto instance = composer.create_instance(builder); + info("kernel size = ", instance->proving_key->circuit_size); + info("kernel num ecc op gates = ", instance->proving_key->num_ecc_op_gates); + } + + // DEBUG only: perform native fold verification and run decider prover/verifier + static void verify_fold_and_decide(FoldProof& fold_proof, std::shared_ptr& accumulator) + { + // Verify fold proof + Composer composer; + auto folding_verifier = composer.create_folding_verifier(); + bool folding_verified = folding_verifier.verify_folding_proof(fold_proof); + EXPECT_TRUE(folding_verified); + + // Run decider + auto decider_prover = composer.create_decider_prover(accumulator); + auto decider_verifier = composer.create_decider_verifier(accumulator); + auto decider_proof = decider_prover.construct_proof(); + bool decision = decider_verifier.verify_proof(decider_proof); + EXPECT_TRUE(decision); } }; /** - * @brief A full Goblin test that mimicks the basic aztec client architecture + * @brief A full Goblin test using PG that mimicks the basic aztec client architecture * @details */ -TEST_F(GoblinFoldingTests, Folding) +TEST_F(GoblinFoldingTests, Full) { Goblin goblin; - Goblin::AccumulationOutput kernel_accum; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); // Perform "Round 0" - auto function_circuit = create_function_circuit(goblin.op_queue); - auto kernel_circuit = create_function_circuit(goblin.op_queue); + Builder function_circuit{ goblin.op_queue }; + create_mock_function_circuit(function_circuit); + Composer composer; // This is annoying + auto accum_instance = composer.create_instance(function_circuit); + info("function circuit num_gates = ", accum_instance->proving_key->circuit_size); - GoblinUltraComposer composer; - auto fctn_instance = composer.create_instance(function_circuit); - auto kernel_instance = composer.create_instance(kernel_circuit); - std::vector> instances{ fctn_instance, kernel_instance }; - auto folding_prover = composer.create_folding_prover(instances); - auto folding_output = folding_prover.fold_instances(); - auto fold_proof = folding_output.folding_data; - std::shared_ptr accum_instance{ folding_output.accumulator }; - auto folding_verifier = composer.create_folding_verifier(); - auto folding_verified = folding_verifier.verify_folding_proof(fold_proof); - EXPECT_TRUE(folding_verified); - - // size_t NUM_CIRCUITS = 2; - // for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - - // // Construct and accumulate a mock function circuit - // auto function_circuit = create_function_circuit(goblin.op_queue); - // info("function merge"); - // goblin.merge(function_circuit); - // // WORKTODO - // auto function_accum = construct_folding_accumulator(function_circuit); - - // // Construct and accumulate the mock kernel circuit (no kernel accum in first round) - // GoblinUltraCircuitBuilder kernel_circuit{ goblin.op_queue }; - // // WORKTODO - // // GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, function_accum, kernel_accum); - // info("kernel accum"); - // goblin.merge(kernel_circuit); - // // WORKTODO - // // kernel_accum = construct_folding_accumulator(kernel_circuit); - // } - - // // WORKTODO: do we need to execute the decider prover here? Should this happen instead of the last folding accum? + Builder kernel_circuit{ goblin.op_queue }; + create_mock_function_circuit(kernel_circuit); + auto kernel_fold_proof = construct_fold_proof_and_update_accumulator(accum_instance, kernel_circuit); + + // DEBUG only + verify_fold_and_decide(kernel_fold_proof, accum_instance); + + // "Round i" + size_t NUM_CIRCUITS = 1; + for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + + // Construct and accumulate a mock function circuit + Builder function_circuit{ goblin.op_queue }; + create_mock_function_circuit(function_circuit); + goblin.merge(function_circuit); // must be called prior to folding + auto fctn_fold_proof = construct_fold_proof_and_update_accumulator(accum_instance, function_circuit); + + // DEBUG only + verify_fold_and_decide(fctn_fold_proof, accum_instance); + + // Construct and accumulate the mock kernel circuit (no kernel accum in first round) + Builder kernel_circuit{ goblin.op_queue }; + construct_mock_folding_kernel(kernel_circuit, fctn_fold_proof, kernel_fold_proof); + goblin.merge(kernel_circuit); // must be called prior to folding + // WORKTODO: Getting an issue in the fold prover here; making standalone test to debug + // auto kernel_fold_proof = construct_fold_proof_and_update_accumulator(accum_instance, kernel_circuit); + + // // DEBUG only + // verify_fold_and_decide(kernel_fold_proof, accum_instance); + } + + // // WORKTODO: execute the decider prover here? // info("goblin prove"); // Goblin::Proof proof = goblin.prove(); @@ -103,4 +154,55 @@ TEST_F(GoblinFoldingTests, Folding) // EXPECT_TRUE(verified); // // WORKTODO: check decider result as well // // EXPECT_TRUE(ultra_verified && verified); +} + +/** + * @brief Check that we can fold a recursive folding verifier circuit + * @details This has not been checked elsewhere and seems to be the failure point of the full test above + */ +TEST_F(GoblinFoldingTests, FoldRecursiveFoldingVerifier) +{ + Goblin goblin; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): + GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + + // Construct two arbirary circuits (sized to match size of single recursive verifier = 2^15) + Builder circuit1{ goblin.op_queue }; + Builder circuit2{ goblin.op_queue }; + create_mock_function_circuit(circuit1, 1 << 14); // 2^14 here results in 2^15 + create_mock_function_circuit(circuit2, 1 << 14); // 2^14 here results in 2^15 + Composer composer; + auto instance1 = composer.create_instance(circuit1); + auto instance2 = composer.create_instance(circuit2); + std::vector> instances{ instance1, instance2 }; + info("function circuit num_gates = ", instance1->proving_key->circuit_size); + + // Fold the first two arbitrary circuits + auto folding_prover = composer.create_folding_prover(instances); + auto output = folding_prover.fold_instances(); + auto accumulator = output.accumulator; + auto fold_proof = output.folding_data; + + // DEBUG only: check the folding all the way through decider + verify_fold_and_decide(fold_proof, accumulator); + + // Construct a recursive folding verifier circuit + Builder rec_verifier_circuit{ goblin.op_queue }; + FoldingRecursiveVerifier verifier{ &rec_verifier_circuit }; + verifier.verify_folding_proof(fold_proof); + // WORKTODO: DEBUG: try adding a public input via the mock function circuit; Without this we don't get through fold + // proving; with it we get through but decider fails + create_mock_function_circuit(rec_verifier_circuit, 2); + + // Check size of recursive verifier circuit + Composer composer2; + auto ver_instance = composer.create_instance(rec_verifier_circuit); + info("rec verifier size = ", ver_instance->proving_key->circuit_size); + + // Fold recursive verifier circuit into the accumulator instance + auto verifier_fold_proof = construct_fold_proof_and_update_accumulator(accumulator, rec_verifier_circuit); + + // DEBUG only + verify_fold_and_decide(verifier_fold_proof, accumulator); } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp index f0237d439f1..ba42986617e 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp @@ -320,6 +320,7 @@ template class ProtoGalaxyTests : public testing::Test { auto second_accumulator = fold_and_verify(instances, composer, true); check_accumulator_target_sum_manual(second_accumulator, true); + // WORKTODO: looks like a bug/typo? should probably check second_accumulator decide_and_verify(first_accumulator, composer, true); } From 81a5a93e283795c4c97f9c4b5a9192a392131160 Mon Sep 17 00:00:00 2001 From: codygunton Date: Mon, 5 Feb 2024 18:11:56 +0000 Subject: [PATCH 04/23] Don't destroy shared_ptr; hack around different PI sizes. --- barretenberg/barretenberg.code-workspace | 3 +- .../goblin/goblin_folding.test.cpp | 101 +++++------------- .../protogalaxy/protogalaxy_prover.cpp | 6 +- .../protogalaxy/protogalaxy_verifier.cpp | 6 +- 4 files changed, 35 insertions(+), 81 deletions(-) diff --git a/barretenberg/barretenberg.code-workspace b/barretenberg/barretenberg.code-workspace index 24c8a186612..362ddc1783c 100644 --- a/barretenberg/barretenberg.code-workspace +++ b/barretenberg/barretenberg.code-workspace @@ -152,8 +152,7 @@ }, "cmake.configureArgs": [ "--preset clang16", - "-G Ninja", - "-g" + "-G Ninja" ], "cmake.useCMakePresets": "auto", "editor.inlayHints.enabled": "offUnlessPressed", diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp index de9fd933ee4..13984a580e1 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp @@ -37,17 +37,15 @@ class GoblinFoldingTests : public ::testing::Test { GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); } - static HonkProof construct_fold_proof_and_update_accumulator(std::shared_ptr& accumulator, - Builder& circuit_to_fold) + static FoldingOutput construct_fold_proof_and_update_accumulator(std::shared_ptr& accumulator, + Builder& circuit_to_fold) { Composer composer; auto instance = composer.create_instance(circuit_to_fold); std::vector> instances{ accumulator, instance }; auto folding_prover = composer.create_folding_prover(instances); - auto output = folding_prover.fold_instances(); - accumulator = output.accumulator; - auto fold_proof = output.folding_data; - return fold_proof; + FoldingOutput output = folding_prover.fold_instances(); + return output; } static bool decide_and_verify(std::shared_ptr& accumulator) @@ -71,23 +69,23 @@ class GoblinFoldingTests : public ::testing::Test { verifier_2.verify_folding_proof(kernel_fold_proof); Composer composer; - auto instance = composer.create_instance(builder); - info("kernel size = ", instance->proving_key->circuit_size); - info("kernel num ecc op gates = ", instance->proving_key->num_ecc_op_gates); + // auto instance = composer.create_instance(builder); + // info("kernel size = ", instance->proving_key->circuit_size); + // info("kernel num ecc op gates = ", instance->proving_key->num_ecc_op_gates); } // DEBUG only: perform native fold verification and run decider prover/verifier - static void verify_fold_and_decide(FoldProof& fold_proof, std::shared_ptr& accumulator) + static void verify_fold_and_decide(FoldingOutput& folding_output) { // Verify fold proof Composer composer; auto folding_verifier = composer.create_folding_verifier(); - bool folding_verified = folding_verifier.verify_folding_proof(fold_proof); + bool folding_verified = folding_verifier.verify_folding_proof(folding_output.folding_data); EXPECT_TRUE(folding_verified); // Run decider - auto decider_prover = composer.create_decider_prover(accumulator); - auto decider_verifier = composer.create_decider_verifier(accumulator); + auto decider_prover = composer.create_decider_prover(folding_output.accumulator); + auto decider_verifier = composer.create_decider_verifier(folding_output.accumulator); auto decider_proof = decider_prover.construct_proof(); bool decision = decider_verifier.verify_proof(decider_proof); EXPECT_TRUE(decision); @@ -109,38 +107,42 @@ TEST_F(GoblinFoldingTests, Full) Builder function_circuit{ goblin.op_queue }; create_mock_function_circuit(function_circuit); Composer composer; // This is annoying - auto accum_instance = composer.create_instance(function_circuit); - info("function circuit num_gates = ", accum_instance->proving_key->circuit_size); + FoldingOutput function_folding_output; + function_folding_output.accumulator = composer.create_instance(function_circuit); + info("function circuit num_gates = ", function_folding_output.accumulator->proving_key->circuit_size); Builder kernel_circuit{ goblin.op_queue }; create_mock_function_circuit(kernel_circuit); - auto kernel_fold_proof = construct_fold_proof_and_update_accumulator(accum_instance, kernel_circuit); + FoldingOutput kernel_folding_output = + construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); // DEBUG only - verify_fold_and_decide(kernel_fold_proof, accum_instance); + verify_fold_and_decide(kernel_folding_output); // "Round i" size_t NUM_CIRCUITS = 1; for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - // Construct and accumulate a mock function circuit Builder function_circuit{ goblin.op_queue }; create_mock_function_circuit(function_circuit); goblin.merge(function_circuit); // must be called prior to folding - auto fctn_fold_proof = construct_fold_proof_and_update_accumulator(accum_instance, function_circuit); + function_folding_output = + construct_fold_proof_and_update_accumulator(kernel_folding_output.accumulator, function_circuit); // DEBUG only - verify_fold_and_decide(fctn_fold_proof, accum_instance); + verify_fold_and_decide(function_folding_output); // Construct and accumulate the mock kernel circuit (no kernel accum in first round) Builder kernel_circuit{ goblin.op_queue }; - construct_mock_folding_kernel(kernel_circuit, fctn_fold_proof, kernel_fold_proof); + construct_mock_folding_kernel( + kernel_circuit, function_folding_output.folding_data, kernel_folding_output.folding_data); goblin.merge(kernel_circuit); // must be called prior to folding // WORKTODO: Getting an issue in the fold prover here; making standalone test to debug - // auto kernel_fold_proof = construct_fold_proof_and_update_accumulator(accum_instance, kernel_circuit); + kernel_folding_output = + construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); - // // DEBUG only - // verify_fold_and_decide(kernel_fold_proof, accum_instance); + // DEBUG only + verify_fold_and_decide(kernel_folding_output); } // // WORKTODO: execute the decider prover here? @@ -154,55 +156,4 @@ TEST_F(GoblinFoldingTests, Full) // EXPECT_TRUE(verified); // // WORKTODO: check decider result as well // // EXPECT_TRUE(ultra_verified && verified); -} - -/** - * @brief Check that we can fold a recursive folding verifier circuit - * @details This has not been checked elsewhere and seems to be the failure point of the full test above - */ -TEST_F(GoblinFoldingTests, FoldRecursiveFoldingVerifier) -{ - Goblin goblin; - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): - GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); - - // Construct two arbirary circuits (sized to match size of single recursive verifier = 2^15) - Builder circuit1{ goblin.op_queue }; - Builder circuit2{ goblin.op_queue }; - create_mock_function_circuit(circuit1, 1 << 14); // 2^14 here results in 2^15 - create_mock_function_circuit(circuit2, 1 << 14); // 2^14 here results in 2^15 - Composer composer; - auto instance1 = composer.create_instance(circuit1); - auto instance2 = composer.create_instance(circuit2); - std::vector> instances{ instance1, instance2 }; - info("function circuit num_gates = ", instance1->proving_key->circuit_size); - - // Fold the first two arbitrary circuits - auto folding_prover = composer.create_folding_prover(instances); - auto output = folding_prover.fold_instances(); - auto accumulator = output.accumulator; - auto fold_proof = output.folding_data; - - // DEBUG only: check the folding all the way through decider - verify_fold_and_decide(fold_proof, accumulator); - - // Construct a recursive folding verifier circuit - Builder rec_verifier_circuit{ goblin.op_queue }; - FoldingRecursiveVerifier verifier{ &rec_verifier_circuit }; - verifier.verify_folding_proof(fold_proof); - // WORKTODO: DEBUG: try adding a public input via the mock function circuit; Without this we don't get through fold - // proving; with it we get through but decider fails - create_mock_function_circuit(rec_verifier_circuit, 2); - - // Check size of recursive verifier circuit - Composer composer2; - auto ver_instance = composer.create_instance(rec_verifier_circuit); - info("rec verifier size = ", ver_instance->proving_key->circuit_size); - - // Fold recursive verifier circuit into the accumulator instance - auto verifier_fold_proof = construct_fold_proof_and_update_accumulator(accumulator, rec_verifier_circuit); - - // DEBUG only - verify_fold_and_decide(verifier_fold_proof, accumulator); } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index c0efde0a3d8..e14e3ec0b06 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -246,8 +246,10 @@ std::shared_ptr ProtoGalaxyProver_public_inputs) { size_t inst = 0; for (auto& instance : instances) { - el += instance->public_inputs[el_idx] * lagranges[inst]; - inst++; + if (instance->public_inputs.size() >= next_accumulator->public_inputs.size()) { + el += instance->public_inputs[el_idx] * lagranges[inst]; + inst++; + }; } transcript->send_to_verifier("next_public_input_" + std::to_string(el_idx), el); el_idx++; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index bee65a68010..b9b363bc493 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -247,8 +247,10 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(const std::ve for (auto& expected_el : folded_public_inputs) { size_t inst = 0; for (auto& instance : instances) { - expected_el += instance->public_inputs[el_idx] * lagranges[inst]; - inst++; + if (instance->public_inputs.size() >= folded_public_inputs.size()) { + expected_el += instance->public_inputs[el_idx] * lagranges[inst]; + inst++; + }; } auto el = transcript->template receive_from_prover("next_public_input" + std::to_string(el_idx)); verified = verified & (el == expected_el); From 668cacab22e1acb915fa0a31ca5da945f9129b4e Mon Sep 17 00:00:00 2001 From: codygunton Date: Mon, 5 Feb 2024 21:20:39 +0000 Subject: [PATCH 05/23] Cleanup (Ultra already decided yeah?) --- .../goblin/goblin_folding.test.cpp | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp index 13984a580e1..eefa620786a 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp @@ -67,11 +67,6 @@ class GoblinFoldingTests : public ::testing::Test { FoldingRecursiveVerifier verifier_2{ &builder }; verifier_2.verify_folding_proof(kernel_fold_proof); - - Composer composer; - // auto instance = composer.create_instance(builder); - // info("kernel size = ", instance->proving_key->circuit_size); - // info("kernel num ecc op gates = ", instance->proving_key->num_ecc_op_gates); } // DEBUG only: perform native fold verification and run decider prover/verifier @@ -106,7 +101,9 @@ TEST_F(GoblinFoldingTests, Full) // Perform "Round 0" Builder function_circuit{ goblin.op_queue }; create_mock_function_circuit(function_circuit); - Composer composer; // This is annoying + Composer composer; + + // initialize accumulator FoldingOutput function_folding_output; function_folding_output.accumulator = composer.create_instance(function_circuit); info("function circuit num_gates = ", function_folding_output.accumulator->proving_key->circuit_size); @@ -115,6 +112,7 @@ TEST_F(GoblinFoldingTests, Full) create_mock_function_circuit(kernel_circuit); FoldingOutput kernel_folding_output = construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); + info("kernel circuit num_gates = ", kernel_folding_output.accumulator->proving_key->circuit_size); // DEBUG only verify_fold_and_decide(kernel_folding_output); @@ -145,15 +143,9 @@ TEST_F(GoblinFoldingTests, Full) verify_fold_and_decide(kernel_folding_output); } - // // WORKTODO: execute the decider prover here? - - // info("goblin prove"); - // Goblin::Proof proof = goblin.prove(); - // // WORKTODO: Execute the decider verifier - // // Verify the goblin proof (eccvm, translator, merge) - // info("goblin verify"); - // bool verified = goblin.verify(proof); - // EXPECT_TRUE(verified); - // // WORKTODO: check decider result as well - // // EXPECT_TRUE(ultra_verified && verified); + // WORKTODO: execute the decider prover here? + + Goblin::Proof proof = goblin.prove(); + bool goblin_verified = goblin.verify(proof); + EXPECT_TRUE(goblin_verified); } \ No newline at end of file From 2be164da19a9a00e275e7db40ae95052998b1004 Mon Sep 17 00:00:00 2001 From: codygunton Date: Mon, 5 Feb 2024 21:35:35 +0000 Subject: [PATCH 06/23] Touch up example --- .../goblin/goblin_folding.test.cpp | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp index eefa620786a..d3cb9b76f16 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp @@ -70,7 +70,7 @@ class GoblinFoldingTests : public ::testing::Test { } // DEBUG only: perform native fold verification and run decider prover/verifier - static void verify_fold_and_decide(FoldingOutput& folding_output) + static void EXEPCT_FOLDING_AND_DECIDING_VERIFIED(FoldingOutput& folding_output) { // Verify fold proof Composer composer; @@ -98,24 +98,22 @@ TEST_F(GoblinFoldingTests, Full) // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); - // Perform "Round 0" + // "Round 0" + // Initialize accumulator with function instance Builder function_circuit{ goblin.op_queue }; create_mock_function_circuit(function_circuit); - Composer composer; - - // initialize accumulator FoldingOutput function_folding_output; + Composer composer; function_folding_output.accumulator = composer.create_instance(function_circuit); info("function circuit num_gates = ", function_folding_output.accumulator->proving_key->circuit_size); + // Fold kernel circuit into function instance Builder kernel_circuit{ goblin.op_queue }; create_mock_function_circuit(kernel_circuit); FoldingOutput kernel_folding_output = construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); info("kernel circuit num_gates = ", kernel_folding_output.accumulator->proving_key->circuit_size); - - // DEBUG only - verify_fold_and_decide(kernel_folding_output); + EXEPCT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); // "Round i" size_t NUM_CIRCUITS = 1; @@ -126,25 +124,19 @@ TEST_F(GoblinFoldingTests, Full) goblin.merge(function_circuit); // must be called prior to folding function_folding_output = construct_fold_proof_and_update_accumulator(kernel_folding_output.accumulator, function_circuit); + EXEPCT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); - // DEBUG only - verify_fold_and_decide(function_folding_output); - - // Construct and accumulate the mock kernel circuit (no kernel accum in first round) + // Construct and accumulate the mock kernel circuit Builder kernel_circuit{ goblin.op_queue }; construct_mock_folding_kernel( kernel_circuit, function_folding_output.folding_data, kernel_folding_output.folding_data); goblin.merge(kernel_circuit); // must be called prior to folding - // WORKTODO: Getting an issue in the fold prover here; making standalone test to debug kernel_folding_output = construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); - - // DEBUG only - verify_fold_and_decide(kernel_folding_output); + EXEPCT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); } - // WORKTODO: execute the decider prover here? - + // Verify the goblin proof (eccvm, translator, merge) Goblin::Proof proof = goblin.prove(); bool goblin_verified = goblin.verify(proof); EXPECT_TRUE(goblin_verified); From ec5cf1f8763e2ba2762b0ee6caa7c3323d49ab30 Mon Sep 17 00:00:00 2001 From: codygunton Date: Mon, 5 Feb 2024 21:57:34 +0000 Subject: [PATCH 07/23] Fix size printing --- .../src/barretenberg/goblin/goblin_folding.test.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp index d3cb9b76f16..d96b48cba77 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp @@ -70,7 +70,7 @@ class GoblinFoldingTests : public ::testing::Test { } // DEBUG only: perform native fold verification and run decider prover/verifier - static void EXEPCT_FOLDING_AND_DECIDING_VERIFIED(FoldingOutput& folding_output) + static void EXEPECT_FOLDING_AND_DECIDING_VERIFIED(FoldingOutput& folding_output) { // Verify fold proof Composer composer; @@ -112,8 +112,8 @@ TEST_F(GoblinFoldingTests, Full) create_mock_function_circuit(kernel_circuit); FoldingOutput kernel_folding_output = construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); - info("kernel circuit num_gates = ", kernel_folding_output.accumulator->proving_key->circuit_size); - EXEPCT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); + info("kernel circuit num_gates = ", kernel_folding_output.accumulator->instance_size); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); // "Round i" size_t NUM_CIRCUITS = 1; @@ -124,7 +124,7 @@ TEST_F(GoblinFoldingTests, Full) goblin.merge(function_circuit); // must be called prior to folding function_folding_output = construct_fold_proof_and_update_accumulator(kernel_folding_output.accumulator, function_circuit); - EXEPCT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); // Construct and accumulate the mock kernel circuit Builder kernel_circuit{ goblin.op_queue }; @@ -133,7 +133,7 @@ TEST_F(GoblinFoldingTests, Full) goblin.merge(kernel_circuit); // must be called prior to folding kernel_folding_output = construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); - EXEPCT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); } // Verify the goblin proof (eccvm, translator, merge) From 0b9e153d1a0121306bf78c5d0eab28866765894c Mon Sep 17 00:00:00 2001 From: codygunton Date: Mon, 5 Feb 2024 22:23:22 +0000 Subject: [PATCH 08/23] Move to new Bb module --- barretenberg/cpp/scripts/bb-tests.sh | 1 + barretenberg/cpp/src/CMakeLists.txt | 1 + .../barretenberg/client_ivc/CMakeLists.txt | 1 + .../barretenberg/client_ivc/client_ivc.cpp | 1 + .../barretenberg/client_ivc/client_ivc.hpp | 301 ++++++++++++++++++ .../client_ivc/ivc_folding.test.cpp | 143 +++++++++ .../goblin/goblin_folding.test.cpp | 55 ---- 7 files changed, 448 insertions(+), 55 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/client_ivc/CMakeLists.txt create mode 100644 barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp create mode 100644 barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp create mode 100644 barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp diff --git a/barretenberg/cpp/scripts/bb-tests.sh b/barretenberg/cpp/scripts/bb-tests.sh index a4ba5b39417..0c0d27ed922 100755 --- a/barretenberg/cpp/scripts/bb-tests.sh +++ b/barretenberg/cpp/scripts/bb-tests.sh @@ -11,6 +11,7 @@ IMAGE_URI=$(calculate_image_uri $REPOSITORY) retry docker pull $IMAGE_URI TESTS=( + client_ivc_tests commitment_schemes_tests crypto_aes128_tests crypto_blake2s_tests diff --git a/barretenberg/cpp/src/CMakeLists.txt b/barretenberg/cpp/src/CMakeLists.txt index 0ca963d4f87..f3e5c0eb5cc 100644 --- a/barretenberg/cpp/src/CMakeLists.txt +++ b/barretenberg/cpp/src/CMakeLists.txt @@ -49,6 +49,7 @@ else() endif() add_subdirectory(barretenberg/bb) +add_subdirectory(barretenberg/client_ivc) add_subdirectory(barretenberg/commitment_schemes) add_subdirectory(barretenberg/common) add_subdirectory(barretenberg/crypto) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/client_ivc/CMakeLists.txt new file mode 100644 index 00000000000..e4f75e5e984 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/CMakeLists.txt @@ -0,0 +1 @@ +barretenberg_module(client_ivc goblin) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp new file mode 100644 index 00000000000..a21aaa2ca06 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -0,0 +1 @@ +// NB: This file is here so that goblin_objects will be created \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp new file mode 100644 index 00000000000..c3b9a5d282b --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -0,0 +1,301 @@ +#pragma once + +#include "barretenberg/eccvm/eccvm_composer.hpp" +#include "barretenberg/flavor/goblin_ultra.hpp" +#include "barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_translator_circuit_builder.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#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 { + +class ClientIVC { + using GoblinUltraCircuitBuilder = bb::GoblinUltraCircuitBuilder; + + using Commitment = GoblinUltraFlavor::Commitment; + using FF = GoblinUltraFlavor::FF; + + public: + using Builder = GoblinUltraCircuitBuilder; + using Fr = bb::fr; + using Transcript = bb::BaseTranscript; + + using GoblinUltraComposer = bb::UltraComposer_; + using GoblinUltraVerifier = bb::UltraVerifier_; + using OpQueue = bb::ECCOpQueue; + using ECCVMFlavor = bb::ECCVMFlavor; + using ECCVMBuilder = bb::ECCVMCircuitBuilder; + using ECCVMComposer = bb::ECCVMComposer; + using ECCVMProver = bb::ECCVMProver_; + using TranslatorBuilder = bb::GoblinTranslatorCircuitBuilder; + using TranslatorComposer = bb::GoblinTranslatorComposer; + using RecursiveMergeVerifier = bb::stdlib::recursion::goblin::MergeRecursiveVerifier_; + using MergeProver = bb::MergeProver; + using MergeVerifier = bb::MergeVerifier; + /** + * @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; + std::vector to_buffer() + { + // ACIRHACK: so much copying and duplication added here and elsewhere + std::vector translation_evaluations_buf; // = translation_evaluations.to_buffer(); + size_t proof_size = + merge_proof.size() + eccvm_proof.size() + translator_proof.size() + translation_evaluations_buf.size(); + + std::vector result(proof_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_buf); + return result; + } + }; + + std::shared_ptr op_queue = std::make_shared(); + + HonkProof merge_proof; + Proof goblin_proof; + + // on the first call to accumulate there is no merge proof to verify + bool merge_proof_exists{ false }; + + private: + // TODO(https://github.com/AztecProtocol/barretenberg/issues/798) unique_ptr use is a hack + std::unique_ptr eccvm_builder; + std::unique_ptr translator_builder; + std::unique_ptr eccvm_composer; + std::unique_ptr eccvm_prover; + std::unique_ptr translator_composer; + + AccumulationOutput accumulator; // Used only for ACIR methods for now + + public: + /** + * @brief Construct a GUH proof and a merge proof for the present circuit. + * @details If there is a previous merge proof, recursively verify it. + * + * @param circuit_builder + */ + AccumulationOutput accumulate(GoblinUltraCircuitBuilder& circuit_builder) + { + // 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 + GoblinUltraComposer composer; + auto instance = composer.create_instance(circuit_builder); + auto prover = composer.create_prover(instance); + auto ultra_proof = prover.construct_proof(); + + // 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, instance->verification_key }; + }; + + /** WORKTODO + * @brief Similar to "accumulate" but only does merge-related stuff, no proving + * @details When this method is used, the "prover" functionality of the IVC scheme must be performed explicitly, but + * this method has to be called first so that the recursive merge verifier can be "appended" to the circuit being + * accumulated + * + * @param circuit_builder + */ + void merge(GoblinUltraCircuitBuilder& circuit_builder) + { + // 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 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; + } + }; + + /** + * @brief Construct an ECCVM proof and the translation polynomial evaluations + * + */ + void prove_eccvm() + { + eccvm_builder = std::make_unique(op_queue); + eccvm_composer = std::make_unique(); + eccvm_prover = std::make_unique(eccvm_composer->create_prover(*eccvm_builder)); + goblin_proof.eccvm_proof = eccvm_prover->construct_proof(); + goblin_proof.translation_evaluations = eccvm_prover->translation_evaluations; + }; + + /** + * @brief Construct a translator proof + * + */ + void prove_translator() + { + translator_builder = std::make_unique( + eccvm_prover->translation_batching_challenge_v, eccvm_prover->evaluation_challenge_x, op_queue); + translator_composer = std::make_unique(); + auto translator_prover = translator_composer->create_prover(*translator_builder, eccvm_prover->transcript); + goblin_proof.translator_proof = translator_prover.construct_proof(); + }; + + /** + * @brief Constuct a full Goblin proof (ECCVM, Translator, merge) + * @details The merge proof is assumed to already have been constucted in the last accumulate step. It is simply + * moved into the final proof here. + * + * @return Proof + */ + Proof prove() + { + goblin_proof.merge_proof = std::move(merge_proof); + prove_eccvm(); + prove_translator(); + return goblin_proof; + }; + + /** + * @brief Verify a full Goblin proof (ECCVM, Translator, merge) + * + * @param proof + * @return true + * @return false + */ + bool verify(const Proof& proof) + { + MergeVerifier merge_verifier; + bool merge_verified = merge_verifier.verify_proof(proof.merge_proof); + + auto eccvm_verifier = eccvm_composer->create_verifier(*eccvm_builder); + bool eccvm_verified = eccvm_verifier.verify_proof(proof.eccvm_proof); + + auto translator_verifier = translator_composer->create_verifier(*translator_builder, 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 + // correctly + bool translation_verified = translator_verifier.verify_translation(proof.translation_evaluations); + + 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 GUH proof for the given circuit. (No merge proof for now) + * + * @param circuit_builder + * @return std::vector + */ + std::vector accumulate_for_acir(GoblinUltraCircuitBuilder& 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 + GoblinUltraComposer composer; + auto instance = composer.create_instance(circuit_builder); + auto prover = composer.create_prover(instance); + auto ultra_proof = prover.construct_proof(); + + accumulator = { ultra_proof, instance->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 GUH proof + * + * @param proof_buf + * @return true + * @return false + */ + bool verify_accumulator_for_acir(const std::vector& proof_buf) const + { + GoblinUltraVerifier 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); + + auto eccvm_verifier = eccvm_composer->create_verifier(*eccvm_builder); + bool eccvm_verified = eccvm_verifier.verify_proof(goblin_proof.eccvm_proof); + + auto translator_verifier = translator_composer->create_verifier(*translator_builder, 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/client_ivc/ivc_folding.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp new file mode 100644 index 00000000000..4fe48b69b9d --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp @@ -0,0 +1,143 @@ +#include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" +#include "barretenberg/ultra_honk/ultra_composer.hpp" + +#include +using namespace bb; + +class ClientIVCTests : public ::testing::Test { + protected: + static void SetUpTestSuite() + { + srs::init_crs_factory("../srs_db/ignition"); + srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); + } + + using Curve = curve::BN254; + using FF = Curve::ScalarField; + using Builder = GoblinUltraCircuitBuilder; + using Composer = GoblinUltraComposer; + using KernelInput = Goblin::AccumulationOutput; + using Instance = ProverInstance_; + using FoldingOutput = FoldingResult; + using FoldProof = HonkProof; + + using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; + using RecursiveVerifierInstances = ::bb::VerifierInstances_; + using FoldingRecursiveVerifier = + bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + + // Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2) + static void create_mock_function_circuit(Builder& builder, size_t num_gates = 1 << 15) + { + GoblinMockCircuits::construct_arithmetic_circuit(builder, num_gates); + GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); + } + + static FoldingOutput construct_fold_proof_and_update_accumulator(std::shared_ptr& accumulator, + Builder& circuit_to_fold) + { + Composer composer; + auto instance = composer.create_instance(circuit_to_fold); + std::vector> instances{ accumulator, instance }; + auto folding_prover = composer.create_folding_prover(instances); + FoldingOutput output = folding_prover.fold_instances(); + return output; + } + + static bool decide_and_verify(std::shared_ptr& accumulator) + { + Composer composer; + auto decider_prover = composer.create_decider_prover(accumulator); + auto decider_verifier = composer.create_decider_verifier(accumulator); + auto decider_proof = decider_prover.construct_proof(); + auto verified = decider_verifier.verify_proof(decider_proof); + return verified; + } + + static void construct_mock_folding_kernel(Builder& builder, + FoldProof& fctn_fold_proof, + FoldProof& kernel_fold_proof) + { + FoldingRecursiveVerifier verifier_1{ &builder }; + verifier_1.verify_folding_proof(fctn_fold_proof); + + FoldingRecursiveVerifier verifier_2{ &builder }; + verifier_2.verify_folding_proof(kernel_fold_proof); + } + + // DEBUG only: perform native fold verification and run decider prover/verifier + static void EXEPECT_FOLDING_AND_DECIDING_VERIFIED(FoldingOutput& folding_output) + { + // Verify fold proof + Composer composer; + auto folding_verifier = composer.create_folding_verifier(); + bool folding_verified = folding_verifier.verify_folding_proof(folding_output.folding_data); + EXPECT_TRUE(folding_verified); + + // Run decider + auto decider_prover = composer.create_decider_prover(folding_output.accumulator); + auto decider_verifier = composer.create_decider_verifier(folding_output.accumulator); + auto decider_proof = decider_prover.construct_proof(); + bool decision = decider_verifier.verify_proof(decider_proof); + EXPECT_TRUE(decision); + } +}; + +/** + * @brief A full Goblin test using PG that mimicks the basic aztec client architecture + * @details + */ +TEST_F(GoblinFoldingTests, Full) +{ + Goblin goblin; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): + GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + + // "Round 0" + // Initialize accumulator with function instance + Builder function_circuit{ goblin.op_queue }; + create_mock_function_circuit(function_circuit); + FoldingOutput function_folding_output; + Composer composer; + function_folding_output.accumulator = composer.create_instance(function_circuit); + info("function circuit num_gates = ", function_folding_output.accumulator->proving_key->circuit_size); + + // Fold kernel circuit into function instance + Builder kernel_circuit{ goblin.op_queue }; + create_mock_function_circuit(kernel_circuit); + FoldingOutput kernel_folding_output = + construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); + info("kernel circuit num_gates = ", kernel_folding_output.accumulator->instance_size); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); + + // "Round i" + size_t NUM_CIRCUITS = 1; + for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + // Construct and accumulate a mock function circuit + Builder function_circuit{ goblin.op_queue }; + create_mock_function_circuit(function_circuit); + goblin.merge(function_circuit); // must be called prior to folding + function_folding_output = + construct_fold_proof_and_update_accumulator(kernel_folding_output.accumulator, function_circuit); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); + + // Construct and accumulate the mock kernel circuit + Builder kernel_circuit{ goblin.op_queue }; + construct_mock_folding_kernel( + kernel_circuit, function_folding_output.folding_data, kernel_folding_output.folding_data); + goblin.merge(kernel_circuit); // must be called prior to folding + kernel_folding_output = + construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); + } + + // Verify the goblin proof (eccvm, translator, merge) + Goblin::Proof proof = goblin.prove(); + bool goblin_verified = goblin.verify(proof); + EXPECT_TRUE(goblin_verified); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp index d96b48cba77..2f167940706 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp @@ -86,58 +86,3 @@ class GoblinFoldingTests : public ::testing::Test { EXPECT_TRUE(decision); } }; - -/** - * @brief A full Goblin test using PG that mimicks the basic aztec client architecture - * @details - */ -TEST_F(GoblinFoldingTests, Full) -{ - Goblin goblin; - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): - GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); - - // "Round 0" - // Initialize accumulator with function instance - Builder function_circuit{ goblin.op_queue }; - create_mock_function_circuit(function_circuit); - FoldingOutput function_folding_output; - Composer composer; - function_folding_output.accumulator = composer.create_instance(function_circuit); - info("function circuit num_gates = ", function_folding_output.accumulator->proving_key->circuit_size); - - // Fold kernel circuit into function instance - Builder kernel_circuit{ goblin.op_queue }; - create_mock_function_circuit(kernel_circuit); - FoldingOutput kernel_folding_output = - construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); - info("kernel circuit num_gates = ", kernel_folding_output.accumulator->instance_size); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); - - // "Round i" - size_t NUM_CIRCUITS = 1; - for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - // Construct and accumulate a mock function circuit - Builder function_circuit{ goblin.op_queue }; - create_mock_function_circuit(function_circuit); - goblin.merge(function_circuit); // must be called prior to folding - function_folding_output = - construct_fold_proof_and_update_accumulator(kernel_folding_output.accumulator, function_circuit); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); - - // Construct and accumulate the mock kernel circuit - Builder kernel_circuit{ goblin.op_queue }; - construct_mock_folding_kernel( - kernel_circuit, function_folding_output.folding_data, kernel_folding_output.folding_data); - goblin.merge(kernel_circuit); // must be called prior to folding - kernel_folding_output = - construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); - } - - // Verify the goblin proof (eccvm, translator, merge) - Goblin::Proof proof = goblin.prove(); - bool goblin_verified = goblin.verify(proof); - EXPECT_TRUE(goblin_verified); -} \ No newline at end of file From 7e1d64c74f6854d17d9609c093259174f1b9be14 Mon Sep 17 00:00:00 2001 From: codygunton Date: Mon, 5 Feb 2024 22:24:07 +0000 Subject: [PATCH 09/23] Use correct suite name --- .../cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp index 4fe48b69b9d..a9f331e863f 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp @@ -91,7 +91,7 @@ class ClientIVCTests : public ::testing::Test { * @brief A full Goblin test using PG that mimicks the basic aztec client architecture * @details */ -TEST_F(GoblinFoldingTests, Full) +TEST_F(ClientIVCTests, Full) { Goblin goblin; From a67f8a21ca6b65b391b7dd93022d7e595b36a77b Mon Sep 17 00:00:00 2001 From: codygunton Date: Mon, 5 Feb 2024 23:38:32 +0000 Subject: [PATCH 10/23] Pseudocode --- .../client_ivc/ivc_folding.test.cpp | 101 ++++++++---------- 1 file changed, 46 insertions(+), 55 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp index a9f331e863f..d2d68e3536d 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp @@ -1,3 +1,4 @@ +#include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" @@ -16,35 +17,39 @@ class ClientIVCTests : public ::testing::Test { srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); } - using Curve = curve::BN254; - using FF = Curve::ScalarField; + using Flavor = GoblinUltraFlavor; + using Curve = typename Flavor::Curve; + using FF = typename Flavor::FF; using Builder = GoblinUltraCircuitBuilder; using Composer = GoblinUltraComposer; - using KernelInput = Goblin::AccumulationOutput; using Instance = ProverInstance_; - using FoldingOutput = FoldingResult; - using FoldProof = HonkProof; + using AccumulationProof = HonkProof; + using AccumulatorWithProof = FoldingResult; using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; using RecursiveVerifierInstances = ::bb::VerifierInstances_; using FoldingRecursiveVerifier = bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + using ClientCircuit = typename ClientIVC::Circuit; + // Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2) - static void create_mock_function_circuit(Builder& builder, size_t num_gates = 1 << 15) + static Builder create_mock_circuit(ClientIVC& ivc, size_t num_gates = 1 << 15) { - GoblinMockCircuits::construct_arithmetic_circuit(builder, num_gates); - GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); + ClientCircuit circuit; // WORKTODO: write constructor + GoblinMockCircuits::construct_arithmetic_circuit(circuit, num_gates); + GoblinMockCircuits::construct_goblin_ecc_op_circuit(circuit); + return circuit; } - static FoldingOutput construct_fold_proof_and_update_accumulator(std::shared_ptr& accumulator, - Builder& circuit_to_fold) + // WORKTODO: this moves in + static AccumulatorWithProof fold(std::shared_ptr& accumulator, Builder& circuit_to_fold) { Composer composer; auto instance = composer.create_instance(circuit_to_fold); std::vector> instances{ accumulator, instance }; auto folding_prover = composer.create_folding_prover(instances); - FoldingOutput output = folding_prover.fold_instances(); + AccumulatorWithProof output = folding_prover.fold_instances(); return output; } @@ -59,8 +64,8 @@ class ClientIVCTests : public ::testing::Test { } static void construct_mock_folding_kernel(Builder& builder, - FoldProof& fctn_fold_proof, - FoldProof& kernel_fold_proof) + AccumulationProof& fctn_fold_proof, + AccumulationProof& kernel_fold_proof) { FoldingRecursiveVerifier verifier_1{ &builder }; verifier_1.verify_folding_proof(fctn_fold_proof); @@ -70,7 +75,7 @@ class ClientIVCTests : public ::testing::Test { } // DEBUG only: perform native fold verification and run decider prover/verifier - static void EXEPECT_FOLDING_AND_DECIDING_VERIFIED(FoldingOutput& folding_output) + static void EXEPECT_FOLDING_AND_DECIDING_VERIFIED(AccumulatorWithProof& folding_output) { // Verify fold proof Composer composer; @@ -93,51 +98,37 @@ class ClientIVCTests : public ::testing::Test { */ TEST_F(ClientIVCTests, Full) { - Goblin goblin; - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): - GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); - - // "Round 0" - // Initialize accumulator with function instance - Builder function_circuit{ goblin.op_queue }; - create_mock_function_circuit(function_circuit); - FoldingOutput function_folding_output; - Composer composer; - function_folding_output.accumulator = composer.create_instance(function_circuit); - info("function circuit num_gates = ", function_folding_output.accumulator->proving_key->circuit_size); - - // Fold kernel circuit into function instance - Builder kernel_circuit{ goblin.op_queue }; - create_mock_function_circuit(kernel_circuit); - FoldingOutput kernel_folding_output = - construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); - info("kernel circuit num_gates = ", kernel_folding_output.accumulator->instance_size); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); - - // "Round i" - size_t NUM_CIRCUITS = 1; - for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + // WORKTODO move these up + const auto EXPECT_ACCUMULATION_VERIFIED = [](AccumulatorWithProof& folding_output) { + EXPECT_TRUE(ivc.verify_accumulation(folding_output)); + }; + + const auto EXPECT_ACCUMULATOR_VERIFIED = [](AccumulatorWithProof& folding_output) { + EXPECT_TRUE(ivc.verify_accumulator(folding_output)); + }; + + ClientIVC ivc; // mock opqueue happens inside + Builder function_circuit = create_mock_circuit(ivc); + ivc.initialize(function_circuit); + + Builder kernel_circuit = create_mock_circuit(ivc); + AccumulatorWithProof kernel_acc_with_proof = ivc.accumulate(kernel_circuit); // handles merge base case + EXPECT_ACCUMULATION_VERIFIED(kernel_acc_with_proof); + + size_t NUM_KERNEL_ITERATIONS_MINUS_1 = 1; + for (size_t circuit_idx = 0; circuit_idx < NUM_KERNEL_ITERATIONS_MINUS_1; ++circuit_idx) { // Construct and accumulate a mock function circuit - Builder function_circuit{ goblin.op_queue }; - create_mock_function_circuit(function_circuit); - goblin.merge(function_circuit); // must be called prior to folding - function_folding_output = - construct_fold_proof_and_update_accumulator(kernel_folding_output.accumulator, function_circuit); + Builder function_circuit = create_mock_circuit(ivc); + function_folding_output = ivc.accumulate(function_circuit); EXEPECT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); // Construct and accumulate the mock kernel circuit - Builder kernel_circuit{ goblin.op_queue }; - construct_mock_folding_kernel( - kernel_circuit, function_folding_output.folding_data, kernel_folding_output.folding_data); - goblin.merge(kernel_circuit); // must be called prior to folding - kernel_folding_output = - construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); + // WORKNOTE: this is the reason to track two + Builder kernel_circuit = + construct_mock_folding_kernel(function_folding_output.folding_data, kernel_acc_with_proof.folding_data); + kernel_acc_with_proof = ivc.accumulate(kernel_circuit); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_acc_with_proof); } - // Verify the goblin proof (eccvm, translator, merge) - Goblin::Proof proof = goblin.prove(); - bool goblin_verified = goblin.verify(proof); - EXPECT_TRUE(goblin_verified); + EXPECT_ACCUMULATOR_VERIFIED(kernel_accumulation_output); } \ No newline at end of file From 68f3e89eb925377d814cf65a55254f22c1cf9089 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 6 Feb 2024 17:29:20 +0000 Subject: [PATCH 11/23] functionality in place; cleanup needed --- .../barretenberg/client_ivc/client_ivc.hpp | 303 ++---------------- .../client_ivc/ivc_folding.test.cpp | 188 ++++++++--- 2 files changed, 168 insertions(+), 323 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index c3b9a5d282b..44e1521649b 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -2,6 +2,8 @@ #include "barretenberg/eccvm/eccvm_composer.hpp" #include "barretenberg/flavor/goblin_ultra.hpp" +#include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_translator_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" @@ -15,287 +17,46 @@ namespace bb { class ClientIVC { - using GoblinUltraCircuitBuilder = bb::GoblinUltraCircuitBuilder; - - using Commitment = GoblinUltraFlavor::Commitment; - using FF = GoblinUltraFlavor::FF; + using Flavor = GoblinUltraFlavor; + using FF = Flavor::FF; + using FoldingOutput = FoldingResult; + using FoldProof = std::vector; + using Accumulator = std::shared_ptr>; + using Instance = ProverInstance_; + using Composer = GoblinUltraComposer; public: - using Builder = GoblinUltraCircuitBuilder; - using Fr = bb::fr; - using Transcript = bb::BaseTranscript; - - using GoblinUltraComposer = bb::UltraComposer_; - using GoblinUltraVerifier = bb::UltraVerifier_; - using OpQueue = bb::ECCOpQueue; - using ECCVMFlavor = bb::ECCVMFlavor; - using ECCVMBuilder = bb::ECCVMCircuitBuilder; - using ECCVMComposer = bb::ECCVMComposer; - using ECCVMProver = bb::ECCVMProver_; - using TranslatorBuilder = bb::GoblinTranslatorCircuitBuilder; - using TranslatorComposer = bb::GoblinTranslatorComposer; - using RecursiveMergeVerifier = bb::stdlib::recursion::goblin::MergeRecursiveVerifier_; - using MergeProver = bb::MergeProver; - using MergeVerifier = bb::MergeVerifier; - /** - * @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; - std::vector to_buffer() - { - // ACIRHACK: so much copying and duplication added here and elsewhere - std::vector translation_evaluations_buf; // = translation_evaluations.to_buffer(); - size_t proof_size = - merge_proof.size() + eccvm_proof.size() + translator_proof.size() + translation_evaluations_buf.size(); - - std::vector result(proof_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_buf); - return result; - } - }; - - std::shared_ptr op_queue = std::make_shared(); - - HonkProof merge_proof; - Proof goblin_proof; + using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra + Goblin goblin; + Accumulator accumulator; - // on the first call to accumulate there is no merge proof to verify - bool merge_proof_exists{ false }; + ClientIVC() + { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): + GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + } private: - // TODO(https://github.com/AztecProtocol/barretenberg/issues/798) unique_ptr use is a hack - std::unique_ptr eccvm_builder; - std::unique_ptr translator_builder; - std::unique_ptr eccvm_composer; - std::unique_ptr eccvm_prover; - std::unique_ptr translator_composer; - - AccumulationOutput accumulator; // Used only for ACIR methods for now - public: - /** - * @brief Construct a GUH proof and a merge proof for the present circuit. - * @details If there is a previous merge proof, recursively verify it. - * - * @param circuit_builder - */ - AccumulationOutput accumulate(GoblinUltraCircuitBuilder& circuit_builder) - { - // 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 - GoblinUltraComposer composer; - auto instance = composer.create_instance(circuit_builder); - auto prover = composer.create_prover(instance); - auto ultra_proof = prover.construct_proof(); - - // 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, instance->verification_key }; - }; - - /** WORKTODO - * @brief Similar to "accumulate" but only does merge-related stuff, no proving - * @details When this method is used, the "prover" functionality of the IVC scheme must be performed explicitly, but - * this method has to be called first so that the recursive merge verifier can be "appended" to the circuit being - * accumulated - * - * @param circuit_builder - */ - void merge(GoblinUltraCircuitBuilder& circuit_builder) - { - // 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 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; - } - }; - - /** - * @brief Construct an ECCVM proof and the translation polynomial evaluations - * - */ - void prove_eccvm() - { - eccvm_builder = std::make_unique(op_queue); - eccvm_composer = std::make_unique(); - eccvm_prover = std::make_unique(eccvm_composer->create_prover(*eccvm_builder)); - goblin_proof.eccvm_proof = eccvm_prover->construct_proof(); - goblin_proof.translation_evaluations = eccvm_prover->translation_evaluations; - }; - - /** - * @brief Construct a translator proof - * - */ - void prove_translator() + void initialize(ClientCircuit& circuit) { - translator_builder = std::make_unique( - eccvm_prover->translation_batching_challenge_v, eccvm_prover->evaluation_challenge_x, op_queue); - translator_composer = std::make_unique(); - auto translator_prover = translator_composer->create_prover(*translator_builder, eccvm_prover->transcript); - goblin_proof.translator_proof = translator_prover.construct_proof(); - }; - - /** - * @brief Constuct a full Goblin proof (ECCVM, Translator, merge) - * @details The merge proof is assumed to already have been constucted in the last accumulate step. It is simply - * moved into the final proof here. - * - * @return Proof - */ - Proof prove() - { - goblin_proof.merge_proof = std::move(merge_proof); - prove_eccvm(); - prove_translator(); - return goblin_proof; - }; - - /** - * @brief Verify a full Goblin proof (ECCVM, Translator, merge) - * - * @param proof - * @return true - * @return false - */ - bool verify(const Proof& proof) - { - MergeVerifier merge_verifier; - bool merge_verified = merge_verifier.verify_proof(proof.merge_proof); - - auto eccvm_verifier = eccvm_composer->create_verifier(*eccvm_builder); - bool eccvm_verified = eccvm_verifier.verify_proof(proof.eccvm_proof); - - auto translator_verifier = translator_composer->create_verifier(*translator_builder, 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 - // correctly - bool translation_verified = translator_verifier.verify_translation(proof.translation_evaluations); - - 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 GUH proof for the given circuit. (No merge proof for now) - * - * @param circuit_builder - * @return std::vector - */ - std::vector accumulate_for_acir(GoblinUltraCircuitBuilder& 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 - GoblinUltraComposer composer; - auto instance = composer.create_instance(circuit_builder); - auto prover = composer.create_prover(instance); - auto ultra_proof = prover.construct_proof(); - - accumulator = { ultra_proof, instance->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 GUH proof - * - * @param proof_buf - * @return true - * @return false - */ - bool verify_accumulator_for_acir(const std::vector& proof_buf) const - { - GoblinUltraVerifier verifier{ accumulator.verification_key }; - HonkProof proof{ proof_buf }; - bool verified = verifier.verify_proof(proof); - - return verified; + merge(circuit); + Composer composer; + accumulator = composer.create_instance(circuit); } - /** - * @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 + FoldProof accumulate(ClientCircuit& circuit) { - // 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); - - auto eccvm_verifier = eccvm_composer->create_verifier(*eccvm_builder); - bool eccvm_verified = eccvm_verifier.verify_proof(goblin_proof.eccvm_proof); - - auto translator_verifier = translator_composer->create_verifier(*translator_builder, 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); + merge(circuit); + Composer composer; + auto instance = composer.create_instance(circuit); + std::vector> instances{ accumulator, instance }; + auto folding_prover = composer.create_folding_prover(instances); + FoldingOutput output = folding_prover.fold_instances(); + accumulator = output.accumulator; + return output.folding_data; + } - return /* merge_verified && */ eccvm_verified && translation_accumulator_construction_verified && - translation_verified; - }; + void merge(ClientCircuit& circuit_builder) { goblin.merge(circuit_builder); } }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp index d2d68e3536d..a60bf3cf29c 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp @@ -20,52 +20,40 @@ class ClientIVCTests : public ::testing::Test { using Flavor = GoblinUltraFlavor; using Curve = typename Flavor::Curve; using FF = typename Flavor::FF; - using Builder = GoblinUltraCircuitBuilder; + using Builder = ClientIVC::ClientCircuit; using Composer = GoblinUltraComposer; using Instance = ProverInstance_; - using AccumulationProof = HonkProof; - using AccumulatorWithProof = FoldingResult; using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; using RecursiveVerifierInstances = ::bb::VerifierInstances_; using FoldingRecursiveVerifier = bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; - using ClientCircuit = typename ClientIVC::Circuit; + // WORKTODO: temporary stuff to be eventiually handled internally by ivc + + using FoldingOutput = FoldingResult; + using Accumulator = std::shared_ptr>; + using FoldProof = std::vector; // Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2) static Builder create_mock_circuit(ClientIVC& ivc, size_t num_gates = 1 << 15) { - ClientCircuit circuit; // WORKTODO: write constructor + Builder circuit{ ivc.goblin.op_queue }; // WORKTODO: write constructor GoblinMockCircuits::construct_arithmetic_circuit(circuit, num_gates); GoblinMockCircuits::construct_goblin_ecc_op_circuit(circuit); return circuit; } - // WORKTODO: this moves in - static AccumulatorWithProof fold(std::shared_ptr& accumulator, Builder& circuit_to_fold) - { - Composer composer; - auto instance = composer.create_instance(circuit_to_fold); - std::vector> instances{ accumulator, instance }; - auto folding_prover = composer.create_folding_prover(instances); - AccumulatorWithProof output = folding_prover.fold_instances(); - return output; - } - - static bool decide_and_verify(std::shared_ptr& accumulator) + // Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2) + static void create_mock_function_circuit(Builder& builder, size_t num_gates = 1 << 15) { - Composer composer; - auto decider_prover = composer.create_decider_prover(accumulator); - auto decider_verifier = composer.create_decider_verifier(accumulator); - auto decider_proof = decider_prover.construct_proof(); - auto verified = decider_verifier.verify_proof(decider_proof); - return verified; + GoblinMockCircuits::construct_arithmetic_circuit(builder, num_gates); + GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); } static void construct_mock_folding_kernel(Builder& builder, - AccumulationProof& fctn_fold_proof, - AccumulationProof& kernel_fold_proof) + FoldProof& fctn_fold_proof, + FoldProof& kernel_fold_proof) { FoldingRecursiveVerifier verifier_1{ &builder }; verifier_1.verify_folding_proof(fctn_fold_proof); @@ -75,60 +63,156 @@ class ClientIVCTests : public ::testing::Test { } // DEBUG only: perform native fold verification and run decider prover/verifier - static void EXEPECT_FOLDING_AND_DECIDING_VERIFIED(AccumulatorWithProof& folding_output) + static void EXEPECT_FOLDING_AND_DECIDING_VERIFIED(const Accumulator& accumulator, const FoldProof& fold_proof) { // Verify fold proof Composer composer; auto folding_verifier = composer.create_folding_verifier(); - bool folding_verified = folding_verifier.verify_folding_proof(folding_output.folding_data); + bool folding_verified = folding_verifier.verify_folding_proof(fold_proof); EXPECT_TRUE(folding_verified); // Run decider - auto decider_prover = composer.create_decider_prover(folding_output.accumulator); - auto decider_verifier = composer.create_decider_verifier(folding_output.accumulator); + auto decider_prover = composer.create_decider_prover(accumulator); + auto decider_verifier = composer.create_decider_verifier(accumulator); auto decider_proof = decider_prover.construct_proof(); bool decision = decider_verifier.verify_proof(decider_proof); EXPECT_TRUE(decision); } }; +// /** +// * @brief A full Goblin test using PG that mimicks the basic aztec client architecture +// * @details +// */ +// TEST_F(ClientIVCTests, Full) +// { +// // WORKTODO move these up +// const auto EXPECT_ACCUMULATION_VERIFIED = [](AccumulatorWithProof& folding_output) { +// EXPECT_TRUE(ivc.verify_accumulation(folding_output)); +// }; + +// const auto EXPECT_ACCUMULATOR_VERIFIED = [](AccumulatorWithProof& folding_output) { +// EXPECT_TRUE(ivc.verify_accumulator(folding_output)); +// }; + +// ClientIVC ivc; // mock opqueue happens inside +// Builder function_circuit = create_mock_circuit(ivc); +// ivc.initialize(function_circuit); + +// Builder kernel_circuit = create_mock_circuit(ivc); +// AccumulatorWithProof kernel_acc_with_proof = ivc.accumulate(kernel_circuit); // handles merge base case +// EXPECT_ACCUMULATION_VERIFIED(kernel_acc_with_proof); + +// size_t NUM_KERNEL_ITERATIONS_MINUS_1 = 1; +// for (size_t circuit_idx = 0; circuit_idx < NUM_KERNEL_ITERATIONS_MINUS_1; ++circuit_idx) { +// // Construct and accumulate a mock function circuit +// Builder function_circuit = create_mock_circuit(ivc); +// function_folding_output = ivc.accumulate(function_circuit); +// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); + +// // Construct and accumulate the mock kernel circuit +// // WORKNOTE: this is the reason to track two +// Builder kernel_circuit = +// construct_mock_folding_kernel(function_folding_output.folding_data, kernel_acc_with_proof.folding_data); +// kernel_acc_with_proof = ivc.accumulate(kernel_circuit); +// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_acc_with_proof); +// } + +// EXPECT_ACCUMULATOR_VERIFIED(kernel_accumulation_output); +// } + /** * @brief A full Goblin test using PG that mimicks the basic aztec client architecture * @details */ -TEST_F(ClientIVCTests, Full) +TEST_F(ClientIVCTests, Working) { - // WORKTODO move these up - const auto EXPECT_ACCUMULATION_VERIFIED = [](AccumulatorWithProof& folding_output) { - EXPECT_TRUE(ivc.verify_accumulation(folding_output)); - }; - - const auto EXPECT_ACCUMULATOR_VERIFIED = [](AccumulatorWithProof& folding_output) { - EXPECT_TRUE(ivc.verify_accumulator(folding_output)); - }; + ClientIVC ivc; - ClientIVC ivc; // mock opqueue happens inside + // "Round 0" + // Initialize accumulator with function instance Builder function_circuit = create_mock_circuit(ivc); ivc.initialize(function_circuit); + info("function circuit num_gates = ", ivc.accumulator->proving_key->circuit_size); + // Fold kernel circuit into function instance Builder kernel_circuit = create_mock_circuit(ivc); - AccumulatorWithProof kernel_acc_with_proof = ivc.accumulate(kernel_circuit); // handles merge base case - EXPECT_ACCUMULATION_VERIFIED(kernel_acc_with_proof); + FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); + info("kernel circuit num_gates = ", ivc.accumulator->instance_size); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, kernel_fold_proof); - size_t NUM_KERNEL_ITERATIONS_MINUS_1 = 1; - for (size_t circuit_idx = 0; circuit_idx < NUM_KERNEL_ITERATIONS_MINUS_1; ++circuit_idx) { + // "Round i" + size_t NUM_CIRCUITS = 1; + for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { // Construct and accumulate a mock function circuit Builder function_circuit = create_mock_circuit(ivc); - function_folding_output = ivc.accumulate(function_circuit); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); + FoldProof function_fold_proof = ivc.accumulate(function_circuit); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, function_fold_proof); // Construct and accumulate the mock kernel circuit - // WORKNOTE: this is the reason to track two - Builder kernel_circuit = - construct_mock_folding_kernel(function_folding_output.folding_data, kernel_acc_with_proof.folding_data); - kernel_acc_with_proof = ivc.accumulate(kernel_circuit); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_acc_with_proof); + Builder kernel_circuit{ ivc.goblin.op_queue }; + construct_mock_folding_kernel(kernel_circuit, function_fold_proof, kernel_fold_proof); + FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); + EXEPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, kernel_fold_proof); } - EXPECT_ACCUMULATOR_VERIFIED(kernel_accumulation_output); -} \ No newline at end of file + // Verify the goblin proof (eccvm, translator, merge) + Goblin::Proof proof = ivc.goblin.prove(); + bool goblin_verified = ivc.goblin.verify(proof); + EXPECT_TRUE(goblin_verified); +} + +// /** +// * @brief A full Goblin test using PG that mimicks the basic aztec client architecture +// * @details +// */ +// TEST_F(ClientIVCTests, WorkingOriginl) +// { +// Goblin goblin; + +// // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): +// GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + +// // "Round 0" +// // Initialize accumulator with function instance +// Builder function_circuit{ goblin.op_queue }; +// create_mock_function_circuit(function_circuit); +// FoldingOutput function_folding_output; +// Composer composer; +// function_folding_output.accumulator = composer.create_instance(function_circuit); +// info("function circuit num_gates = ", function_folding_output.accumulator->proving_key->circuit_size); + +// // Fold kernel circuit into function instance +// Builder kernel_circuit{ goblin.op_queue }; +// create_mock_function_circuit(kernel_circuit); +// FoldingOutput kernel_folding_output = +// construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); +// info("kernel circuit num_gates = ", kernel_folding_output.accumulator->instance_size); +// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); + +// // "Round i" +// size_t NUM_CIRCUITS = 1; +// for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { +// // Construct and accumulate a mock function circuit +// Builder function_circuit{ goblin.op_queue }; +// create_mock_function_circuit(function_circuit); +// goblin.merge(function_circuit); // must be called prior to folding +// function_folding_output = +// construct_fold_proof_and_update_accumulator(kernel_folding_output.accumulator, function_circuit); +// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); + +// // Construct and accumulate the mock kernel circuit +// Builder kernel_circuit{ goblin.op_queue }; +// construct_mock_folding_kernel( +// kernel_circuit, function_folding_output.folding_data, kernel_folding_output.folding_data); +// goblin.merge(kernel_circuit); // must be called prior to folding +// kernel_folding_output = +// construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); +// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); +// } + +// // Verify the goblin proof (eccvm, translator, merge) +// Goblin::Proof proof = goblin.prove(); +// bool goblin_verified = goblin.verify(proof); +// EXPECT_TRUE(goblin_verified); +// } \ No newline at end of file From 0690ac8c64c05951c3868952ae1f3fa0e6a03f0b Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 6 Feb 2024 20:50:43 +0000 Subject: [PATCH 12/23] ivc prove and verify methods --- .../barretenberg/client_ivc/client_ivc.hpp | 42 ++++- .../client_ivc/ivc_folding.test.cpp | 170 ++++-------------- 2 files changed, 73 insertions(+), 139 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index 44e1521649b..ee8396c3948 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -17,16 +17,25 @@ namespace bb { class ClientIVC { + + struct Proof { + Goblin::Proof goblin_proof; + HonkProof decider_proof; + }; + + public: using Flavor = GoblinUltraFlavor; using FF = Flavor::FF; - using FoldingOutput = FoldingResult; using FoldProof = std::vector; using Accumulator = std::shared_ptr>; + using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra + + private: + using FoldingOutput = FoldingResult; using Instance = ProverInstance_; using Composer = GoblinUltraComposer; public: - using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra Goblin goblin; Accumulator accumulator; @@ -40,14 +49,14 @@ class ClientIVC { public: void initialize(ClientCircuit& circuit) { - merge(circuit); + goblin.merge(circuit); Composer composer; accumulator = composer.create_instance(circuit); } FoldProof accumulate(ClientCircuit& circuit) { - merge(circuit); + goblin.merge(circuit); Composer composer; auto instance = composer.create_instance(circuit); std::vector> instances{ accumulator, instance }; @@ -57,6 +66,29 @@ class ClientIVC { return output.folding_data; } - void merge(ClientCircuit& circuit_builder) { goblin.merge(circuit_builder); } + Proof prove() + { + // Construct Goblin proof (merge, eccvm, translator) + auto goblin_proof = goblin.prove(); + + // Construct decider proof for final accumulator + Composer composer; + auto decider_prover = composer.create_decider_prover(accumulator); + auto decider_proof = decider_prover.construct_proof(); + return { goblin_proof, decider_proof }; + } + + bool verify(Proof& proof) + { + // Goblin verification (merge, eccvm, translator) + bool goblin_verified = goblin.verify(proof.goblin_proof); + + // Decider verification + Composer composer; + // NOTE: Use of member accumulator here will go away with removal of vkey from ProverInstance + auto decider_verifier = composer.create_decider_verifier(accumulator); + bool decision = decider_verifier.verify_proof(proof.decider_proof); + return decision && goblin_verified; + } }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp index a60bf3cf29c..9ccd4e98feb 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp @@ -17,40 +17,38 @@ class ClientIVCTests : public ::testing::Test { srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); } - using Flavor = GoblinUltraFlavor; - using Curve = typename Flavor::Curve; + using Flavor = ClientIVC::Flavor; using FF = typename Flavor::FF; using Builder = ClientIVC::ClientCircuit; using Composer = GoblinUltraComposer; - using Instance = ProverInstance_; + using Accumulator = ClientIVC::Accumulator; + using FoldProof = ClientIVC::FoldProof; using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; using RecursiveVerifierInstances = ::bb::VerifierInstances_; using FoldingRecursiveVerifier = bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; - // WORKTODO: temporary stuff to be eventiually handled internally by ivc - - using FoldingOutput = FoldingResult; - using Accumulator = std::shared_ptr>; - using FoldProof = std::vector; - - // Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2) + /** + * @brief Construct mock circuit with arithmetic gates and goblin ops + * @details Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2) + * + */ static Builder create_mock_circuit(ClientIVC& ivc, size_t num_gates = 1 << 15) { - Builder circuit{ ivc.goblin.op_queue }; // WORKTODO: write constructor + Builder circuit{ ivc.goblin.op_queue }; GoblinMockCircuits::construct_arithmetic_circuit(circuit, num_gates); GoblinMockCircuits::construct_goblin_ecc_op_circuit(circuit); return circuit; } - // Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2) - static void create_mock_function_circuit(Builder& builder, size_t num_gates = 1 << 15) - { - GoblinMockCircuits::construct_arithmetic_circuit(builder, num_gates); - GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); - } - + /** + * @brief Construct mock kernel consisting of two recursive folding verifiers + * + * @param builder + * @param fctn_fold_proof + * @param kernel_fold_proof + */ static void construct_mock_folding_kernel(Builder& builder, FoldProof& fctn_fold_proof, FoldProof& kernel_fold_proof) @@ -62,8 +60,11 @@ class ClientIVCTests : public ::testing::Test { verifier_2.verify_folding_proof(kernel_fold_proof); } - // DEBUG only: perform native fold verification and run decider prover/verifier - static void EXEPECT_FOLDING_AND_DECIDING_VERIFIED(const Accumulator& accumulator, const FoldProof& fold_proof) + /** + * @brief Perform native fold verification and run decider prover/verifier + * + */ + static void EXPECT_FOLDING_AND_DECIDING_VERIFIED(const Accumulator& accumulator, const FoldProof& fold_proof) { // Verify fold proof Composer composer; @@ -80,139 +81,40 @@ class ClientIVCTests : public ::testing::Test { } }; -// /** -// * @brief A full Goblin test using PG that mimicks the basic aztec client architecture -// * @details -// */ -// TEST_F(ClientIVCTests, Full) -// { -// // WORKTODO move these up -// const auto EXPECT_ACCUMULATION_VERIFIED = [](AccumulatorWithProof& folding_output) { -// EXPECT_TRUE(ivc.verify_accumulation(folding_output)); -// }; - -// const auto EXPECT_ACCUMULATOR_VERIFIED = [](AccumulatorWithProof& folding_output) { -// EXPECT_TRUE(ivc.verify_accumulator(folding_output)); -// }; - -// ClientIVC ivc; // mock opqueue happens inside -// Builder function_circuit = create_mock_circuit(ivc); -// ivc.initialize(function_circuit); - -// Builder kernel_circuit = create_mock_circuit(ivc); -// AccumulatorWithProof kernel_acc_with_proof = ivc.accumulate(kernel_circuit); // handles merge base case -// EXPECT_ACCUMULATION_VERIFIED(kernel_acc_with_proof); - -// size_t NUM_KERNEL_ITERATIONS_MINUS_1 = 1; -// for (size_t circuit_idx = 0; circuit_idx < NUM_KERNEL_ITERATIONS_MINUS_1; ++circuit_idx) { -// // Construct and accumulate a mock function circuit -// Builder function_circuit = create_mock_circuit(ivc); -// function_folding_output = ivc.accumulate(function_circuit); -// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); - -// // Construct and accumulate the mock kernel circuit -// // WORKNOTE: this is the reason to track two -// Builder kernel_circuit = -// construct_mock_folding_kernel(function_folding_output.folding_data, kernel_acc_with_proof.folding_data); -// kernel_acc_with_proof = ivc.accumulate(kernel_circuit); -// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_acc_with_proof); -// } - -// EXPECT_ACCUMULATOR_VERIFIED(kernel_accumulation_output); -// } - /** * @brief A full Goblin test using PG that mimicks the basic aztec client architecture - * @details + * */ -TEST_F(ClientIVCTests, Working) +TEST_F(ClientIVCTests, Full) { ClientIVC ivc; - // "Round 0" - // Initialize accumulator with function instance + // Initialize IVC with function circuit Builder function_circuit = create_mock_circuit(ivc); ivc.initialize(function_circuit); - info("function circuit num_gates = ", ivc.accumulator->proving_key->circuit_size); - // Fold kernel circuit into function instance + // Accumulate kernel circuit (first kernel mocked as simple circuit since no folding proofs yet) Builder kernel_circuit = create_mock_circuit(ivc); FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - info("kernel circuit num_gates = ", ivc.accumulator->instance_size); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, kernel_fold_proof); + EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, kernel_fold_proof); - // "Round i" size_t NUM_CIRCUITS = 1; for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - // Construct and accumulate a mock function circuit + // Accumulate function circuit Builder function_circuit = create_mock_circuit(ivc); FoldProof function_fold_proof = ivc.accumulate(function_circuit); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, function_fold_proof); + EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, function_fold_proof); - // Construct and accumulate the mock kernel circuit + // Accumulate kernel circuit Builder kernel_circuit{ ivc.goblin.op_queue }; construct_mock_folding_kernel(kernel_circuit, function_fold_proof, kernel_fold_proof); FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - EXEPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, kernel_fold_proof); + EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, kernel_fold_proof); } - // Verify the goblin proof (eccvm, translator, merge) - Goblin::Proof proof = ivc.goblin.prove(); - bool goblin_verified = ivc.goblin.verify(proof); - EXPECT_TRUE(goblin_verified); -} - -// /** -// * @brief A full Goblin test using PG that mimicks the basic aztec client architecture -// * @details -// */ -// TEST_F(ClientIVCTests, WorkingOriginl) -// { -// Goblin goblin; - -// // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): -// GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); - -// // "Round 0" -// // Initialize accumulator with function instance -// Builder function_circuit{ goblin.op_queue }; -// create_mock_function_circuit(function_circuit); -// FoldingOutput function_folding_output; -// Composer composer; -// function_folding_output.accumulator = composer.create_instance(function_circuit); -// info("function circuit num_gates = ", function_folding_output.accumulator->proving_key->circuit_size); - -// // Fold kernel circuit into function instance -// Builder kernel_circuit{ goblin.op_queue }; -// create_mock_function_circuit(kernel_circuit); -// FoldingOutput kernel_folding_output = -// construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); -// info("kernel circuit num_gates = ", kernel_folding_output.accumulator->instance_size); -// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); - -// // "Round i" -// size_t NUM_CIRCUITS = 1; -// for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { -// // Construct and accumulate a mock function circuit -// Builder function_circuit{ goblin.op_queue }; -// create_mock_function_circuit(function_circuit); -// goblin.merge(function_circuit); // must be called prior to folding -// function_folding_output = -// construct_fold_proof_and_update_accumulator(kernel_folding_output.accumulator, function_circuit); -// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(function_folding_output); - -// // Construct and accumulate the mock kernel circuit -// Builder kernel_circuit{ goblin.op_queue }; -// construct_mock_folding_kernel( -// kernel_circuit, function_folding_output.folding_data, kernel_folding_output.folding_data); -// goblin.merge(kernel_circuit); // must be called prior to folding -// kernel_folding_output = -// construct_fold_proof_and_update_accumulator(function_folding_output.accumulator, kernel_circuit); -// EXEPECT_FOLDING_AND_DECIDING_VERIFIED(kernel_folding_output); -// } - -// // Verify the goblin proof (eccvm, translator, merge) -// Goblin::Proof proof = goblin.prove(); -// bool goblin_verified = goblin.verify(proof); -// EXPECT_TRUE(goblin_verified); -// } \ No newline at end of file + // Constuct four proofs: merge, eccvm, translator, decider + auto proof = ivc.prove(); + + // Verify all four proofs + EXPECT_TRUE(ivc.verify(proof)); +} \ No newline at end of file From a69d34c93c6d371812dd551129194357846abc6e Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 7 Feb 2024 15:07:37 +0000 Subject: [PATCH 13/23] Cleanup and commenting --- .../barretenberg/client_ivc/client_ivc.cpp | 2 +- .../barretenberg/client_ivc/client_ivc.hpp | 49 +++++++---- .../cpp/src/barretenberg/goblin/goblin.hpp | 4 +- .../goblin/goblin_folding.test.cpp | 88 ------------------- .../goblin/goblin_recursion.test.cpp | 36 -------- .../ultra_honk/protogalaxy.test.cpp | 3 +- 6 files changed, 38 insertions(+), 144 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index a21aaa2ca06..4391a62c1d0 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -1 +1 @@ -// NB: This file is here so that goblin_objects will be created \ No newline at end of file +// NB: This file is here so that client_ivc_objects will be created \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index ee8396c3948..b9ac394fabc 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -1,23 +1,20 @@ #pragma once -#include "barretenberg/eccvm/eccvm_composer.hpp" -#include "barretenberg/flavor/goblin_ultra.hpp" #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" -#include "barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp" -#include "barretenberg/proof_system/circuit_builder/goblin_translator_circuit_builder.hpp" -#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" -#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 { +/** + * @brief The IVC interface to be used by the aztec client for private function exectuion + * @details Combines Protogalaxy with Goblin to accumulate one circuit instance at a time with efficient EC group + * operations + * + */ class ClientIVC { + // A full proof for the IVC scheme struct Proof { Goblin::Proof goblin_proof; HonkProof decider_proof; @@ -45,18 +42,29 @@ class ClientIVC { GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); } - private: - public: + /** + * @brief Initialize the IVC with a first circuit + * @details Initializes the accumulator and performs the initial goblin merge + * + * @param circuit + */ void initialize(ClientCircuit& circuit) { - goblin.merge(circuit); + goblin.merge(circuit); // Construct new merge proof Composer composer; accumulator = composer.create_instance(circuit); } + /** + * @brief Accumulate a circuit into the IVC scheme + * @details Performs goblin merge, generates circuit instance, folds into accumulator and constructs a folding proof + * + * @param circuit Circuit to be accumulated/folded + * @return FoldProof + */ FoldProof accumulate(ClientCircuit& circuit) { - goblin.merge(circuit); + goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof Composer composer; auto instance = composer.create_instance(circuit); std::vector> instances{ accumulator, instance }; @@ -66,18 +74,29 @@ class ClientIVC { return output.folding_data; } + /** + * @brief Construct a proof for the IVC, which, if verified, fully establishes its correctness + * + * @return Proof + */ Proof prove() { // Construct Goblin proof (merge, eccvm, translator) auto goblin_proof = goblin.prove(); - // Construct decider proof for final accumulator + // Construct decider proof for the final accumulator Composer composer; auto decider_prover = composer.create_decider_prover(accumulator); auto decider_proof = decider_prover.construct_proof(); return { goblin_proof, decider_proof }; } + /** + * @brief Verify a full proof of the IVC + * + * @param proof + * @return bool + */ bool verify(Proof& proof) { // Goblin verification (merge, eccvm, translator) diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 8c56a915cb9..9f108389eda 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -120,8 +120,8 @@ class Goblin { return { ultra_proof, instance->verification_key }; }; - /** WORKTODO - * @brief Similar to "accumulate" but only does merge-related stuff, no proving + /** + * @brief Add a recursive merge verifier to input circuit and construct a merge proof for the updated op queue * @details When this method is used, the "prover" functionality of the IVC scheme must be performed explicitly, but * this method has to be called first so that the recursive merge verifier can be "appended" to the circuit being * accumulated diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp deleted file mode 100644 index 2f167940706..00000000000 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_folding.test.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "barretenberg/goblin/goblin.hpp" -#include "barretenberg/goblin/mock_circuits.hpp" -#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" -#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" - -#include -using namespace bb; - -class GoblinFoldingTests : public ::testing::Test { - protected: - static void SetUpTestSuite() - { - srs::init_crs_factory("../srs_db/ignition"); - srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); - } - - using Curve = curve::BN254; - using FF = Curve::ScalarField; - using Builder = GoblinUltraCircuitBuilder; - using Composer = GoblinUltraComposer; - using KernelInput = Goblin::AccumulationOutput; - using Instance = ProverInstance_; - using FoldingOutput = FoldingResult; - using FoldProof = HonkProof; - - using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; - using RecursiveVerifierInstances = ::bb::VerifierInstances_; - using FoldingRecursiveVerifier = - bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; - - // Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2) - static void create_mock_function_circuit(Builder& builder, size_t num_gates = 1 << 15) - { - GoblinMockCircuits::construct_arithmetic_circuit(builder, num_gates); - GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); - } - - static FoldingOutput construct_fold_proof_and_update_accumulator(std::shared_ptr& accumulator, - Builder& circuit_to_fold) - { - Composer composer; - auto instance = composer.create_instance(circuit_to_fold); - std::vector> instances{ accumulator, instance }; - auto folding_prover = composer.create_folding_prover(instances); - FoldingOutput output = folding_prover.fold_instances(); - return output; - } - - static bool decide_and_verify(std::shared_ptr& accumulator) - { - Composer composer; - auto decider_prover = composer.create_decider_prover(accumulator); - auto decider_verifier = composer.create_decider_verifier(accumulator); - auto decider_proof = decider_prover.construct_proof(); - auto verified = decider_verifier.verify_proof(decider_proof); - return verified; - } - - static void construct_mock_folding_kernel(Builder& builder, - FoldProof& fctn_fold_proof, - FoldProof& kernel_fold_proof) - { - FoldingRecursiveVerifier verifier_1{ &builder }; - verifier_1.verify_folding_proof(fctn_fold_proof); - - FoldingRecursiveVerifier verifier_2{ &builder }; - verifier_2.verify_folding_proof(kernel_fold_proof); - } - - // DEBUG only: perform native fold verification and run decider prover/verifier - static void EXEPECT_FOLDING_AND_DECIDING_VERIFIED(FoldingOutput& folding_output) - { - // Verify fold proof - Composer composer; - auto folding_verifier = composer.create_folding_verifier(); - bool folding_verified = folding_verifier.verify_folding_proof(folding_output.folding_data); - EXPECT_TRUE(folding_verified); - - // Run decider - auto decider_prover = composer.create_decider_prover(folding_output.accumulator); - auto decider_verifier = composer.create_decider_verifier(folding_output.accumulator); - auto decider_proof = decider_prover.construct_proof(); - bool decision = decider_verifier.verify_proof(decider_proof); - EXPECT_TRUE(decision); - } -}; diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp index daecb8297d8..dc0facdb60a 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp @@ -26,44 +26,11 @@ class GoblinRecursionTests : public ::testing::Test { GoblinUltraComposer composer; auto instance = composer.create_instance(builder); auto prover = composer.create_prover(instance); - info("function proof"); auto ultra_proof = prover.construct_proof(); return { ultra_proof, instance->verification_key }; } }; -/** * @brief A full Goblin test that mimicks the basic aztec client architecture - * - */ -TEST_F(GoblinRecursionTests, Pseudo) -{ - Goblin goblin; - - // Construct an initial circuit; its proof will be recursively verified by the first kernel - GoblinUltraBuilder initial_circuit{ goblin.op_queue }; - GoblinMockCircuits::construct_simple_initial_circuit(initial_circuit); - KernelInput kernel_input = goblin.accumulate(initial_circuit); - - // Construct a series of simple Goblin circuits; generate and verify their proofs - size_t NUM_CIRCUITS = 2; - for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - // Construct a circuit with logic resembling that of the "kernel circuit" - GoblinUltraBuilder circuit_builder{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_kernel_circuit(circuit_builder, kernel_input, kernel_input); - - // Construct proof of the current kernel circuit to be recursively verified by the next one - kernel_input = goblin.accumulate(circuit_builder); - } - - Goblin::Proof proof = goblin.prove(); - // Verify the final ultra proof - GoblinUltraVerifier ultra_verifier{ kernel_input.verification_key }; - bool ultra_verified = ultra_verifier.verify_proof(kernel_input.proof); - // Verify the goblin proof (eccvm, translator, merge) - bool verified = goblin.verify(proof); - EXPECT_TRUE(ultra_verified && verified); -} - /** * @brief A full Goblin test that mimicks the basic aztec client architecture * @details @@ -96,14 +63,11 @@ TEST_F(GoblinRecursionTests, Vanilla) kernel_accum = construct_accumulator(kernel_circuit); } - info("goblin prove"); Goblin::Proof proof = goblin.prove(); // Verify the final ultra proof GoblinUltraVerifier ultra_verifier{ kernel_accum.verification_key }; - info("ultra verify"); bool ultra_verified = ultra_verifier.verify_proof(kernel_accum.proof); // Verify the goblin proof (eccvm, translator, merge) - info("goblin verify"); bool verified = goblin.verify(proof); EXPECT_TRUE(ultra_verified && verified); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp index ba42986617e..42f5757c1e3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp @@ -320,8 +320,7 @@ template class ProtoGalaxyTests : public testing::Test { auto second_accumulator = fold_and_verify(instances, composer, true); check_accumulator_target_sum_manual(second_accumulator, true); - // WORKTODO: looks like a bug/typo? should probably check second_accumulator - decide_and_verify(first_accumulator, composer, true); + decide_and_verify(second_accumulator, composer, true); } /** From 416097a5bd38939b12f89337ecb9c67cfe43944a Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 7 Feb 2024 18:10:53 +0000 Subject: [PATCH 14/23] verify final fold proof + typo --- .../barretenberg/client_ivc/client_ivc.hpp | 36 ++++++++++--------- .../client_ivc/ivc_folding.test.cpp | 6 ++-- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index b9ac394fabc..f3b372fa3a3 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -7,19 +7,13 @@ namespace bb { /** - * @brief The IVC interface to be used by the aztec client for private function exectuion + * @brief The IVC interface to be used by the aztec client for private function execution * @details Combines Protogalaxy with Goblin to accumulate one circuit instance at a time with efficient EC group * operations * */ class ClientIVC { - // A full proof for the IVC scheme - struct Proof { - Goblin::Proof goblin_proof; - HonkProof decider_proof; - }; - public: using Flavor = GoblinUltraFlavor; using FF = Flavor::FF; @@ -27,6 +21,13 @@ class ClientIVC { using Accumulator = std::shared_ptr>; using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra + // A full proof for the IVC scheme + struct Proof { + Goblin::Proof goblin_proof; + FoldProof fold_proof; // final fold proof + HonkProof decider_proof; + }; + private: using FoldingOutput = FoldingResult; using Instance = ProverInstance_; @@ -34,7 +35,7 @@ class ClientIVC { public: Goblin goblin; - Accumulator accumulator; + FoldingOutput fold_output; ClientIVC() { @@ -52,7 +53,7 @@ class ClientIVC { { goblin.merge(circuit); // Construct new merge proof Composer composer; - accumulator = composer.create_instance(circuit); + fold_output.accumulator = composer.create_instance(circuit); } /** @@ -67,11 +68,10 @@ class ClientIVC { goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof Composer composer; auto instance = composer.create_instance(circuit); - std::vector> instances{ accumulator, instance }; + std::vector> instances{ fold_output.accumulator, instance }; auto folding_prover = composer.create_folding_prover(instances); - FoldingOutput output = folding_prover.fold_instances(); - accumulator = output.accumulator; - return output.folding_data; + fold_output = folding_prover.fold_instances(); + return fold_output.folding_data; } /** @@ -86,9 +86,9 @@ class ClientIVC { // Construct decider proof for the final accumulator Composer composer; - auto decider_prover = composer.create_decider_prover(accumulator); + auto decider_prover = composer.create_decider_prover(fold_output.accumulator); auto decider_proof = decider_prover.construct_proof(); - return { goblin_proof, decider_proof }; + return { goblin_proof, fold_output.folding_data, decider_proof }; } /** @@ -104,10 +104,12 @@ class ClientIVC { // Decider verification Composer composer; + auto folding_verifier = composer.create_folding_verifier(); + bool folding_verified = folding_verifier.verify_folding_proof(proof.fold_proof); // NOTE: Use of member accumulator here will go away with removal of vkey from ProverInstance - auto decider_verifier = composer.create_decider_verifier(accumulator); + auto decider_verifier = composer.create_decider_verifier(fold_output.accumulator); bool decision = decider_verifier.verify_proof(proof.decider_proof); - return decision && goblin_verified; + return goblin_verified && folding_verified && decision; } }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp index 9ccd4e98feb..52aed2f2987 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp @@ -96,20 +96,20 @@ TEST_F(ClientIVCTests, Full) // Accumulate kernel circuit (first kernel mocked as simple circuit since no folding proofs yet) Builder kernel_circuit = create_mock_circuit(ivc); FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, kernel_fold_proof); + EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.fold_output.accumulator, kernel_fold_proof); size_t NUM_CIRCUITS = 1; for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { // Accumulate function circuit Builder function_circuit = create_mock_circuit(ivc); FoldProof function_fold_proof = ivc.accumulate(function_circuit); - EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, function_fold_proof); + EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.fold_output.accumulator, function_fold_proof); // Accumulate kernel circuit Builder kernel_circuit{ ivc.goblin.op_queue }; construct_mock_folding_kernel(kernel_circuit, function_fold_proof, kernel_fold_proof); FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.accumulator, kernel_fold_proof); + EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.fold_output.accumulator, kernel_fold_proof); } // Constuct four proofs: merge, eccvm, translator, decider From f61b19178fb6a2c9c592ee111f31ebb19ed519c3 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 7 Feb 2024 18:49:46 +0000 Subject: [PATCH 15/23] chaotic WiP --- .../benchmark/goblin_bench/goblin.bench.cpp | 2 +- .../benchmark/ivc_bench/CMakeLists.txt | 1 + .../benchmark/ivc_bench/ivc.bench.cpp | 154 ++++++++++++++++++ .../goblin/full_goblin_recursion.test.cpp | 2 +- .../src/barretenberg/goblin/mock_circuits.hpp | 46 +++++- .../goblin/mock_circuits_pinning.test.cpp | 2 +- 6 files changed, 200 insertions(+), 7 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt create mode 100644 barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp 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 44e68a5065c..8667c739dec 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp @@ -49,7 +49,7 @@ class GoblinBench : public benchmark::Fixture { // Construct and accumulate the mock kernel circuit // Note: in first round, kernel_accum is empty since there is no previous kernel to recursively verify GoblinUltraCircuitBuilder circuit_builder{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_kernel_circuit(circuit_builder, function_accum, kernel_accum); + GoblinMockCircuits::construct_mock_recursion_kernel_circuit(circuit_builder, function_accum, kernel_accum); kernel_accum = goblin.accumulate(circuit_builder); } } diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt new file mode 100644 index 00000000000..97c85e335ab --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt @@ -0,0 +1 @@ +barretenberg_module(ivc_bench ultra_honk eccvm stdlib_recursion stdlib_sha256 stdlib_merkle_tree stdlib_primitives) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp new file mode 100644 index 00000000000..3866d433830 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp @@ -0,0 +1,154 @@ + +#include + +#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/common/op_count_google_bench.hpp" +#include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/ultra_honk/ultra_composer.hpp" + +using namespace benchmark; +using namespace bb; + +namespace { + +/** + * @brief Benchmark suite for the aztec client PG-Goblin IVC scheme + * + */ +class IvcBench : public benchmark::Fixture { + public: + // Goblin::AccumulationOutput kernel_accum; + using Builder = GoblinUltraCircuitBuilder; + + // Number of function circuits to accumulate(based on Zacs target numbers) + static constexpr size_t NUM_ITERATIONS_MEDIUM_COMPLEXITY = 6; + + void SetUp([[maybe_unused]] const ::benchmark::State& state) override + { + bb::srs::init_crs_factory("../srs_db/ignition"); + bb::srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); + } + + /** + * @brief Perform a specified number of function circuit accumulation rounds + * @details Each round "accumulates" a mock function circuit and a mock kernel circuit. Each round thus consists of + * the generation of two circuits, two UGH proofs and two Merge proofs. To match the sizes called out in the spec + * (https://github.com/AztecProtocol/aztec-packages/blob/master/yellow-paper/docs/cryptography/performance-targets.md) + * we set the size of the function circuit to be 2^17 except for the first one which is 2^19. + * + * @param state + */ + void perform_ivc_accumulation_rounds(State& state, ClientIVC& ivc) + { + auto NUM_CIRCUITS = static_cast(state.range(0)); + for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + + // Accumulate function circuit + Builder function_circuit{ goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + auto function_fold_proof = ivc.accumulate(function_circuit); + + // Accumulate kernel circuit + Builder kernel_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, function_fold_proof, kernel_fold_proof); + auto kernel_fold_proof = ivc.accumulate(kernel_circuit); + } + } +}; + +/** + * @brief Benchmark the full PG-Goblin IVC protocol + * + */ +BENCHMARK_DEFINE_F(IvcBench, GoblinFull)(benchmark::State& state) +{ + ClientIVC ivc; + + for (auto _ : state) { + BB_REPORT_OP_COUNT_IN_BENCH(state); + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(state, goblin); + + // Construct proofs for ECCVM and Translator + goblin.prove(); + } +} + +// /** +// * @brief Benchmark only the accumulation rounds +// * +// */ +// BENCHMARK_DEFINE_F(IvcBench, GoblinAccumulate)(benchmark::State& state) +// { +// Goblin goblin; + +// // TODO(https://github.com/AztecProtocol/barretenberg/issues/723) +// GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + +// // Perform a specified number of iterations of function/kernel accumulation +// for (auto _ : state) { +// perform_goblin_accumulation_rounds(state, goblin); +// } +// } + +// /** +// * @brief Benchmark only the ECCVM component +// * +// */ +// BENCHMARK_DEFINE_F(IvcBench, GoblinECCVMProve)(benchmark::State& state) +// { +// Goblin goblin; + +// // TODO(https://github.com/AztecProtocol/barretenberg/issues/723) +// GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + +// // Perform a specified number of iterations of function/kernel accumulation +// perform_goblin_accumulation_rounds(state, goblin); + +// // Prove ECCVM only +// for (auto _ : state) { +// goblin.prove_eccvm(); +// } +// } + +// /** +// * @brief Benchmark only the Translator component +// * +// */ +// BENCHMARK_DEFINE_F(IvcBench, GoblinTranslatorProve)(benchmark::State& state) +// { +// Goblin goblin; + +// // TODO(https://github.com/AztecProtocol/barretenberg/issues/723) +// GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + +// // Perform a specified number of iterations of function/kernel accumulation +// perform_goblin_accumulation_rounds(state, goblin); + +// // Prove ECCVM (unmeasured) and Translator (measured) +// goblin.prove_eccvm(); +// for (auto _ : state) { +// goblin.prove_translator(); +// } +// } + +#define ARGS \ + Arg(IvcBench::NUM_ITERATIONS_MEDIUM_COMPLEXITY) \ + ->Arg(1 << 0) \ + ->Arg(1 << 1) \ + ->Arg(1 << 2) \ + ->Arg(1 << 3) \ + ->Arg(1 << 4) \ + ->Arg(1 << 5) \ + ->Arg(1 << 6) + +BENCHMARK_REGISTER_F(IvcBench, GoblinFull)->Unit(benchmark::kMillisecond)->ARGS; +// BENCHMARK_REGISTER_F(IvcBench, GoblinAccumulate)->Unit(benchmark::kMillisecond)->ARGS; +// BENCHMARK_REGISTER_F(IvcBench, GoblinECCVMProve)->Unit(benchmark::kMillisecond)->ARGS; +// BENCHMARK_REGISTER_F(IvcBench, GoblinTranslatorProve)->Unit(benchmark::kMillisecond)->ARGS; + +} // namespace + +BENCHMARK_MAIN(); diff --git a/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp index dcc1323d781..0212d234948 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp @@ -44,7 +44,7 @@ TEST_F(GoblinRecursionTests, Pseudo) for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { // Construct a circuit with logic resembling that of the "kernel circuit" GoblinUltraBuilder circuit_builder{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_kernel_circuit(circuit_builder, kernel_input, kernel_input); + GoblinMockCircuits::construct_mock_recursion_kernel_circuit(circuit_builder, kernel_input, kernel_input); // Construct proof of the current kernel circuit to be recursively verified by the next one kernel_input = goblin.accumulate(circuit_builder); diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index 576fc798ae0..f10c91310d8 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -13,6 +13,7 @@ #include "barretenberg/stdlib/merkle_tree/merkle_tree.hpp" #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" #include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" #include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" namespace bb { @@ -31,6 +32,11 @@ class GoblinMockCircuits { using KernelInput = Goblin::AccumulationOutput; static constexpr size_t NUM_OP_QUEUE_COLUMNS = Flavor::NUM_WIRES; + using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; + using RecursiveVerifierInstances = ::bb::VerifierInstances_; + using FoldingRecursiveVerifier = + bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + /** * @brief Populate a builder with a specified number of arithmetic gates; includes a PI * @@ -164,7 +170,7 @@ class GoblinMockCircuits { } /** - * @brief Construct a mock kernel circuit + * @brief Construct a mock kernel circuit based on vanilla recursion * @details This circuit contains (1) some arbitrary operations representing general kernel logic, (2) recursive * verification of a function circuit proof, and optionally (3) recursive verification of a previous kernel circuit * proof. The arbitrary kernel logic is structured to bring the final dyadic circuit size of the kernel to 2^17. @@ -174,9 +180,9 @@ class GoblinMockCircuits { * @param function_accum {proof, vkey} for function circuit to be recursively verified * @param prev_kernel_accum {proof, vkey} for previous kernel circuit to be recursively verified */ - static void construct_mock_kernel_circuit(GoblinUltraBuilder& builder, - const KernelInput& function_accum, - const KernelInput& prev_kernel_accum) + static void construct_mock_recursion_kernel_circuit(GoblinUltraBuilder& builder, + const KernelInput& function_accum, + const KernelInput& prev_kernel_accum) { // Add operations representing general kernel logic e.g. state updates. Note: these are structured to make the // kernel "full" within the dyadic size 2^17 (130914 gates) @@ -197,5 +203,37 @@ class GoblinMockCircuits { verifier2.verify_proof(prev_kernel_accum.proof); } } + + /** + * @brief Construct a mock kernel circuit based on folding + * @details This circuit contains (1) some arbitrary operations representing general kernel logic, (2) recursive + * folding verification of a function circuit folding proof, and optionally (3) recursive folding verification of a + * previous kernel circuit folding proof. The arbitrary kernel logic is structured to bring the final dyadic circuit + * size of the kernel to 2^17. + * + * TODO(https://github.com/AztecProtocol/barretenberg/issues/801): Pairing point aggregation not implemented + * @param builder + * @param function_accum {proof, vkey} for function circuit to be recursively verified + * @param prev_kernel_accum {proof, vkey} for previous kernel circuit to be recursively verified + */ + static void construct_mock_folding_kernel_circuit(GoblinUltraBuilder& builder, + const FoldProof& function_fold_proof, + const FoldProof& kernel_fold_proof) + { + // Add operations representing general kernel logic e.g. state updates. Note: these are structured to make the + // kernel "full" within the dyadic size 2^17 (130914 gates) + const size_t NUM_MERKLE_CHECKS = 45; + const size_t NUM_ECDSA_VERIFICATIONS = 1; + const size_t NUM_SHA_HASHES = 1; + stdlib::generate_merkle_membership_test_circuit(builder, NUM_MERKLE_CHECKS); + stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ECDSA_VERIFICATIONS); + stdlib::generate_sha256_test_circuit(builder, NUM_SHA_HASHES); + + FoldingRecursiveVerifier verifier_1{ &builder }; + verifier_1.verify_folding_proof(function_fold_proof); + + FoldingRecursiveVerifier verifier_2{ &builder }; + verifier_2.verify_folding_proof(kernel_fold_proof); + } }; } // namespace bb 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 6d642bf5bc8..1508ccd6e8f 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp @@ -45,7 +45,7 @@ TEST_F(MockCircuits, PinKernelSizes) GoblinMockCircuits::construct_mock_function_circuit(app_circuit, large); auto function_accum = goblin.accumulate(app_circuit); GoblinUltraCircuitBuilder kernel_circuit{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_kernel_circuit(kernel_circuit, function_accum, kernel_accum); + GoblinMockCircuits::construct_mock_recursion_kernel_circuit(kernel_circuit, function_accum, kernel_accum); GoblinUltraComposer composer; auto instance = composer.create_instance(kernel_circuit); if (large) { From 54db43d3df42e4d5e6ea218224fe1ab1cec95aaf Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 7 Feb 2024 19:20:21 +0000 Subject: [PATCH 16/23] updates based on review --- .../barretenberg/client_ivc/client_ivc.cpp | 80 ++++++++++++++++++- .../barretenberg/client_ivc/client_ivc.hpp | 75 ++--------------- ...c_folding.test.cpp => client_ivc.test.cpp} | 0 .../src/barretenberg/goblin/mock_circuits.hpp | 6 +- .../protogalaxy/protogalaxy_prover.cpp | 1 + .../protogalaxy/protogalaxy_verifier.cpp | 1 + 6 files changed, 91 insertions(+), 72 deletions(-) rename barretenberg/cpp/src/barretenberg/client_ivc/{ivc_folding.test.cpp => client_ivc.test.cpp} (100%) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 4391a62c1d0..3affe72d550 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -1 +1,79 @@ -// NB: This file is here so that client_ivc_objects will be created \ No newline at end of file +#include "barretenberg/client_ivc/client_ivc.hpp" + +namespace bb { + +ClientIVC::ClientIVC() +{ + // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): + GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); +} + +/** + * @brief Initialize the IVC with a first circuit + * @details Initializes the accumulator and performs the initial goblin merge + * + * @param circuit + */ +void ClientIVC::initialize(ClientCircuit& circuit) +{ + goblin.merge(circuit); // Construct new merge proof + Composer composer; + fold_output.accumulator = composer.create_instance(circuit); +} + +/** + * @brief Accumulate a circuit into the IVC scheme + * @details Performs goblin merge, generates circuit instance, folds into accumulator and constructs a folding proof + * + * @param circuit Circuit to be accumulated/folded + * @return FoldProof + */ +ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) +{ + goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof + Composer composer; + auto instance = composer.create_instance(circuit); + std::vector> instances{ fold_output.accumulator, instance }; + auto folding_prover = composer.create_folding_prover(instances); + fold_output = folding_prover.fold_instances(); + return fold_output.folding_data; +} + +/** + * @brief Construct a proof for the IVC, which, if verified, fully establishes its correctness + * + * @return Proof + */ +ClientIVC::Proof ClientIVC::prove() +{ + // Construct Goblin proof (merge, eccvm, translator) + auto goblin_proof = goblin.prove(); + + // Construct decider proof for the final accumulator + Composer composer; + auto decider_prover = composer.create_decider_prover(fold_output.accumulator); + auto decider_proof = decider_prover.construct_proof(); + return { goblin_proof, fold_output.folding_data, decider_proof }; +} + +/** + * @brief Verify a full proof of the IVC + * + * @param proof + * @return bool + */ +bool ClientIVC::verify(Proof& proof) +{ + // Goblin verification (merge, eccvm, translator) + bool goblin_verified = goblin.verify(proof.goblin_proof); + + // Decider verification + Composer composer; + auto folding_verifier = composer.create_folding_verifier(); + bool folding_verified = folding_verifier.verify_folding_proof(proof.fold_proof); + // NOTE: Use of member accumulator here will go away with removal of vkey from ProverInstance + auto decider_verifier = composer.create_decider_verifier(fold_output.accumulator); + bool decision = decider_verifier.verify_proof(proof.decider_proof); + return goblin_verified && folding_verified && decision; +} +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index f3b372fa3a3..6f065bd452f 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -37,79 +37,14 @@ class ClientIVC { Goblin goblin; FoldingOutput fold_output; - ClientIVC() - { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): - GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); - } + ClientIVC(); - /** - * @brief Initialize the IVC with a first circuit - * @details Initializes the accumulator and performs the initial goblin merge - * - * @param circuit - */ - void initialize(ClientCircuit& circuit) - { - goblin.merge(circuit); // Construct new merge proof - Composer composer; - fold_output.accumulator = composer.create_instance(circuit); - } + void initialize(ClientCircuit& circuit); - /** - * @brief Accumulate a circuit into the IVC scheme - * @details Performs goblin merge, generates circuit instance, folds into accumulator and constructs a folding proof - * - * @param circuit Circuit to be accumulated/folded - * @return FoldProof - */ - FoldProof accumulate(ClientCircuit& circuit) - { - goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof - Composer composer; - auto instance = composer.create_instance(circuit); - std::vector> instances{ fold_output.accumulator, instance }; - auto folding_prover = composer.create_folding_prover(instances); - fold_output = folding_prover.fold_instances(); - return fold_output.folding_data; - } + FoldProof accumulate(ClientCircuit& circuit); - /** - * @brief Construct a proof for the IVC, which, if verified, fully establishes its correctness - * - * @return Proof - */ - Proof prove() - { - // Construct Goblin proof (merge, eccvm, translator) - auto goblin_proof = goblin.prove(); + Proof prove(); - // Construct decider proof for the final accumulator - Composer composer; - auto decider_prover = composer.create_decider_prover(fold_output.accumulator); - auto decider_proof = decider_prover.construct_proof(); - return { goblin_proof, fold_output.folding_data, decider_proof }; - } - - /** - * @brief Verify a full proof of the IVC - * - * @param proof - * @return bool - */ - bool verify(Proof& proof) - { - // Goblin verification (merge, eccvm, translator) - bool goblin_verified = goblin.verify(proof.goblin_proof); - - // Decider verification - Composer composer; - auto folding_verifier = composer.create_folding_verifier(); - bool folding_verified = folding_verifier.verify_folding_proof(proof.fold_proof); - // NOTE: Use of member accumulator here will go away with removal of vkey from ProverInstance - auto decider_verifier = composer.create_decider_verifier(fold_output.accumulator); - bool decision = decider_verifier.verify_proof(proof.decider_proof); - return goblin_verified && folding_verified && decision; - } + bool verify(Proof& proof); }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/client_ivc/ivc_folding.test.cpp rename to barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index 01d5d1fe01c..d2a75f243f7 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -164,7 +164,7 @@ class GoblinMockCircuits { } /** - * @brief Construct a mock kernel circuit + * @brief Construct a size 2^17 mock kernel circuit for benchmarking * @details This circuit contains (1) some arbitrary operations representing general kernel logic, (2) recursive * verification of a function circuit proof, and optionally (3) recursive verification of a previous kernel circuit * proof. The arbitrary kernel logic is structured to bring the final dyadic circuit size of the kernel to 2^17. @@ -198,6 +198,10 @@ class GoblinMockCircuits { } } + /** + * @brief A minimal version of the mock kernel (recursive verifiers only) for faster testing + * + */ static void construct_mock_kernel_small(GoblinUltraBuilder& builder, const KernelInput& function_accum, const KernelInput& prev_kernel_accum) diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index e14e3ec0b06..48bbcd86e8b 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -246,6 +246,7 @@ std::shared_ptr ProtoGalaxyProver_public_inputs) { size_t inst = 0; for (auto& instance : instances) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/830) if (instance->public_inputs.size() >= next_accumulator->public_inputs.size()) { el += instance->public_inputs[el_idx] * lagranges[inst]; inst++; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index b9b363bc493..3aeeda75779 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -247,6 +247,7 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(const std::ve for (auto& expected_el : folded_public_inputs) { size_t inst = 0; for (auto& instance : instances) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/830) if (instance->public_inputs.size() >= folded_public_inputs.size()) { expected_el += instance->public_inputs[el_idx] * lagranges[inst]; inst++; From af684eee4f781756437edace583b405f88c2e54f Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 7 Feb 2024 19:50:53 +0000 Subject: [PATCH 17/23] ivc bench is building --- .../src/barretenberg/benchmark/CMakeLists.txt | 11 ++++++----- .../benchmark/ivc_bench/CMakeLists.txt | 2 +- .../benchmark/ivc_bench/ivc.bench.cpp | 19 +++++++++++++++---- .../src/barretenberg/goblin/mock_circuits.hpp | 6 +++--- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt index 285f2bb5937..03b7e657a6d 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt @@ -1,10 +1,11 @@ +add_subdirectory(basics_bench) add_subdirectory(decrypt_bench) add_subdirectory(ipa_bench) +add_subdirectory(ivc_bench) +add_subdirectory(goblin_bench) add_subdirectory(pippenger_bench) add_subdirectory(plonk_bench) -add_subdirectory(ultra_bench) -add_subdirectory(goblin_bench) -add_subdirectory(basics_bench) +add_subdirectory(protogalaxy_bench) add_subdirectory(relations_bench) -add_subdirectory(widgets_bench) -add_subdirectory(protogalaxy_bench) \ No newline at end of file +add_subdirectory(ultra_bench) +add_subdirectory(widgets_bench) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt index 97c85e335ab..3f0c9245850 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(ivc_bench ultra_honk eccvm stdlib_recursion stdlib_sha256 stdlib_merkle_tree stdlib_primitives) +barretenberg_module(ivc_bench client_ivc stdlib_recursion stdlib_sha256 stdlib_merkle_tree stdlib_primitives) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp index 3866d433830..f7731bc3c4a 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp @@ -2,6 +2,7 @@ #include #include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/common/op_count_google_bench.hpp" #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" @@ -40,13 +41,23 @@ class IvcBench : public benchmark::Fixture { * * @param state */ - void perform_ivc_accumulation_rounds(State& state, ClientIVC& ivc) + static void perform_ivc_accumulation_rounds(State& state, ClientIVC& ivc) { + // Initialize IVC with function circuit + Builder function_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + ivc.initialize(function_circuit); + + // Accumulate kernel circuit (first kernel mocked as simple circuit since no folding proofs yet) + Builder kernel_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(kernel_circuit); + auto kernel_fold_proof = ivc.accumulate(kernel_circuit); + auto NUM_CIRCUITS = static_cast(state.range(0)); for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { // Accumulate function circuit - Builder function_circuit{ goblin.op_queue }; + Builder function_circuit{ ivc.goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(function_circuit); auto function_fold_proof = ivc.accumulate(function_circuit); @@ -69,10 +80,10 @@ BENCHMARK_DEFINE_F(IvcBench, GoblinFull)(benchmark::State& state) for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, goblin); + perform_ivc_accumulation_rounds(state, ivc); // Construct proofs for ECCVM and Translator - goblin.prove(); + ivc.prove(); } } diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index ea342309011..21190023f8f 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -216,9 +216,9 @@ class GoblinMockCircuits { * @param function_accum {proof, vkey} for function circuit to be recursively verified * @param prev_kernel_accum {proof, vkey} for previous kernel circuit to be recursively verified */ - static void construct_mock_folding_kernel_circuit(GoblinUltraBuilder& builder, - const FoldProof& function_fold_proof, - const FoldProof& kernel_fold_proof) + static void construct_mock_folding_kernel(GoblinUltraBuilder& builder, + const std::vector& function_fold_proof, + const std::vector& kernel_fold_proof) { // Add operations representing general kernel logic e.g. state updates. Note: these are structured to make the // kernel "full" within the dyadic size 2^17 (130914 gates) From aa614d6e764564fa3b24affd4501dde820cc6743 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 7 Feb 2024 21:34:05 +0000 Subject: [PATCH 18/23] basic full ivc bench in place --- .../benchmark/ivc_bench/ivc.bench.cpp | 11 +++++---- .../barretenberg/client_ivc/client_ivc.cpp | 23 ++++++++++++------- .../barretenberg/client_ivc/client_ivc.hpp | 5 +++- .../src/barretenberg/goblin/mock_circuits.hpp | 2 +- .../sumcheck/instance/prover_instance.cpp | 2 +- 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp index f7731bc3c4a..a34a88d92ae 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp @@ -35,9 +35,11 @@ class IvcBench : public benchmark::Fixture { /** * @brief Perform a specified number of function circuit accumulation rounds * @details Each round "accumulates" a mock function circuit and a mock kernel circuit. Each round thus consists of - * the generation of two circuits, two UGH proofs and two Merge proofs. To match the sizes called out in the spec + * the generation of two circuits, two folding proofs and two Merge proofs. To match the sizes called out in the + * spec * (https://github.com/AztecProtocol/aztec-packages/blob/master/yellow-paper/docs/cryptography/performance-targets.md) - * we set the size of the function circuit to be 2^17 except for the first one which is 2^19. + * we set the size of the function circuit to be 2^17. The first one should be 2^19 but we can't currently support + * folding circuits of unequal size. * * @param state */ @@ -54,6 +56,7 @@ class IvcBench : public benchmark::Fixture { auto kernel_fold_proof = ivc.accumulate(kernel_circuit); auto NUM_CIRCUITS = static_cast(state.range(0)); + NUM_CIRCUITS -= 1; // Subtract one to account for the "initialization" round above for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { // Accumulate function circuit @@ -73,7 +76,7 @@ class IvcBench : public benchmark::Fixture { * @brief Benchmark the full PG-Goblin IVC protocol * */ -BENCHMARK_DEFINE_F(IvcBench, GoblinFull)(benchmark::State& state) +BENCHMARK_DEFINE_F(IvcBench, Full)(benchmark::State& state) { ClientIVC ivc; @@ -82,7 +85,7 @@ BENCHMARK_DEFINE_F(IvcBench, GoblinFull)(benchmark::State& state) // Perform a specified number of iterations of function/kernel accumulation perform_ivc_accumulation_rounds(state, ivc); - // Construct proofs for ECCVM and Translator + // Construct IVC scheme proof (fold, decider, merge, eccvm, translator) ivc.prove(); } } diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 3affe72d550..99958f08e8a 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -33,6 +33,7 @@ ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof Composer composer; auto instance = composer.create_instance(circuit); + info("accumulate: instance->instance_size", instance->proving_key->circuit_size); std::vector> instances{ fold_output.accumulator, instance }; auto folding_prover = composer.create_folding_prover(instances); fold_output = folding_prover.fold_instances(); @@ -46,14 +47,7 @@ ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) */ ClientIVC::Proof ClientIVC::prove() { - // Construct Goblin proof (merge, eccvm, translator) - auto goblin_proof = goblin.prove(); - - // Construct decider proof for the final accumulator - Composer composer; - auto decider_prover = composer.create_decider_prover(fold_output.accumulator); - auto decider_proof = decider_prover.construct_proof(); - return { goblin_proof, fold_output.folding_data, decider_proof }; + return { fold_output.folding_data, decider_prove(), goblin.prove() }; } /** @@ -76,4 +70,17 @@ bool ClientIVC::verify(Proof& proof) bool decision = decider_verifier.verify_proof(proof.decider_proof); return goblin_verified && folding_verified && decision; } + +/** + * @brief Internal method for constructing a decider proof + * + * @return HonkProof + */ +HonkProof ClientIVC::decider_prove() const +{ + Composer composer; + auto decider_prover = composer.create_decider_prover(fold_output.accumulator); + return decider_prover.construct_proof(); +} + } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index 6f065bd452f..749a6ccec0a 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -23,9 +23,9 @@ class ClientIVC { // A full proof for the IVC scheme struct Proof { - Goblin::Proof goblin_proof; FoldProof fold_proof; // final fold proof HonkProof decider_proof; + Goblin::Proof goblin_proof; }; private: @@ -46,5 +46,8 @@ class ClientIVC { Proof prove(); bool verify(Proof& proof); + + private: + HonkProof decider_prove() const; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index 21190023f8f..e8214bb1b57 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -222,7 +222,7 @@ class GoblinMockCircuits { { // Add operations representing general kernel logic e.g. state updates. Note: these are structured to make the // kernel "full" within the dyadic size 2^17 (130914 gates) - const size_t NUM_MERKLE_CHECKS = 45; + const size_t NUM_MERKLE_CHECKS = 20; const size_t NUM_ECDSA_VERIFICATIONS = 1; const size_t NUM_SHA_HASHES = 1; stdlib::generate_merkle_membership_test_circuit(builder, NUM_MERKLE_CHECKS); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 5479420510d..7c789d613b0 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -37,7 +37,7 @@ template void ProverInstance_::compute_circuit_size_param // The number of gates is max(lookup gates + tables, rows already populated in trace) + 1, where the +1 is due to // addition of a "zero row" at top of the execution trace to ensure wires and other polys are shiftable. total_num_gates = std::max(minimum_circuit_size_due_to_lookups, num_rows_populated_in_execution_trace); - + info("total_num_gates", total_num_gates); // Next power of 2 dyadic_circuit_size = circuit.get_circuit_subgroup_size(total_num_gates); } From 292543bd782441ef6f08b1d3b616af69d8b6f324 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 8 Feb 2024 16:25:42 +0000 Subject: [PATCH 19/23] more benches plus pinning test --- .../benchmark/ivc_bench/ivc.bench.cpp | 134 ++++++++++-------- .../barretenberg/client_ivc/client_ivc.hpp | 1 - .../src/barretenberg/goblin/CMakeLists.txt | 2 +- .../goblin/mock_circuits_pinning.test.cpp | 28 +++- 4 files changed, 101 insertions(+), 64 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp index a34a88d92ae..9ae6fce9869 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp @@ -90,63 +90,74 @@ BENCHMARK_DEFINE_F(IvcBench, Full)(benchmark::State& state) } } -// /** -// * @brief Benchmark only the accumulation rounds -// * -// */ -// BENCHMARK_DEFINE_F(IvcBench, GoblinAccumulate)(benchmark::State& state) -// { -// Goblin goblin; - -// // TODO(https://github.com/AztecProtocol/barretenberg/issues/723) -// GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); - -// // Perform a specified number of iterations of function/kernel accumulation -// for (auto _ : state) { -// perform_goblin_accumulation_rounds(state, goblin); -// } -// } - -// /** -// * @brief Benchmark only the ECCVM component -// * -// */ -// BENCHMARK_DEFINE_F(IvcBench, GoblinECCVMProve)(benchmark::State& state) -// { -// Goblin goblin; - -// // TODO(https://github.com/AztecProtocol/barretenberg/issues/723) -// GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); - -// // Perform a specified number of iterations of function/kernel accumulation -// perform_goblin_accumulation_rounds(state, goblin); - -// // Prove ECCVM only -// for (auto _ : state) { -// goblin.prove_eccvm(); -// } -// } - -// /** -// * @brief Benchmark only the Translator component -// * -// */ -// BENCHMARK_DEFINE_F(IvcBench, GoblinTranslatorProve)(benchmark::State& state) -// { -// Goblin goblin; - -// // TODO(https://github.com/AztecProtocol/barretenberg/issues/723) -// GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); - -// // Perform a specified number of iterations of function/kernel accumulation -// perform_goblin_accumulation_rounds(state, goblin); - -// // Prove ECCVM (unmeasured) and Translator (measured) -// goblin.prove_eccvm(); -// for (auto _ : state) { -// goblin.prove_translator(); -// } -// } +/** + * @brief Benchmark only the accumulation rounds + * + */ +BENCHMARK_DEFINE_F(IvcBench, Accumulate)(benchmark::State& state) +{ + ClientIVC ivc; + + // Perform a specified number of iterations of function/kernel accumulation + for (auto _ : state) { + perform_ivc_accumulation_rounds(state, ivc); + } +} + +/** + * @brief Benchmark only the Decider component + * + */ +BENCHMARK_DEFINE_F(IvcBench, Decide)(benchmark::State& state) +{ + ClientIVC ivc; + + BB_REPORT_OP_COUNT_IN_BENCH(state); + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(state, ivc); + + // Construct eccvm proof, measure only translator proof construction + for (auto _ : state) { + ivc.decider_prove(); + } +} + +/** + * @brief Benchmark only the ECCVM component + * + */ +BENCHMARK_DEFINE_F(IvcBench, ECCVM)(benchmark::State& state) +{ + ClientIVC ivc; + + BB_REPORT_OP_COUNT_IN_BENCH(state); + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(state, ivc); + + // Construct and measure eccvm only + for (auto _ : state) { + ivc.goblin.prove_eccvm(); + } +} + +/** + * @brief Benchmark only the Translator component + * + */ +BENCHMARK_DEFINE_F(IvcBench, Translator)(benchmark::State& state) +{ + ClientIVC ivc; + + BB_REPORT_OP_COUNT_IN_BENCH(state); + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(state, ivc); + + // Construct eccvm proof, measure only translator proof construction + ivc.goblin.prove_eccvm(); + for (auto _ : state) { + ivc.goblin.prove_translator(); + } +} #define ARGS \ Arg(IvcBench::NUM_ITERATIONS_MEDIUM_COMPLEXITY) \ @@ -158,10 +169,11 @@ BENCHMARK_DEFINE_F(IvcBench, Full)(benchmark::State& state) ->Arg(1 << 5) \ ->Arg(1 << 6) -BENCHMARK_REGISTER_F(IvcBench, GoblinFull)->Unit(benchmark::kMillisecond)->ARGS; -// BENCHMARK_REGISTER_F(IvcBench, GoblinAccumulate)->Unit(benchmark::kMillisecond)->ARGS; -// BENCHMARK_REGISTER_F(IvcBench, GoblinECCVMProve)->Unit(benchmark::kMillisecond)->ARGS; -// BENCHMARK_REGISTER_F(IvcBench, GoblinTranslatorProve)->Unit(benchmark::kMillisecond)->ARGS; +BENCHMARK_REGISTER_F(IvcBench, Full)->Unit(benchmark::kMillisecond)->ARGS; +BENCHMARK_REGISTER_F(IvcBench, Accumulate)->Unit(benchmark::kMillisecond)->ARGS; +BENCHMARK_REGISTER_F(IvcBench, Decide)->Unit(benchmark::kMillisecond)->ARGS; +BENCHMARK_REGISTER_F(IvcBench, ECCVM)->Unit(benchmark::kMillisecond)->ARGS; +BENCHMARK_REGISTER_F(IvcBench, Translator)->Unit(benchmark::kMillisecond)->ARGS; } // namespace diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index 749a6ccec0a..cd3b82b4d6d 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -47,7 +47,6 @@ class ClientIVC { bool verify(Proof& proof); - private: HonkProof decider_prove() const; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt index ee4b04affe8..386f068b491 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(goblin stdlib_recursion ultra_honk eccvm translator_vm stdlib_sha256 stdlib_merkle_tree stdlib_primitives) \ No newline at end of file +barretenberg_module(goblin stdlib_recursion ultra_honk eccvm translator_vm stdlib_sha256 stdlib_merkle_tree stdlib_primitives client_ivc) \ No newline at end of file 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 1508ccd6e8f..a439cbe10d7 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp @@ -1,3 +1,4 @@ +#include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" @@ -34,7 +35,7 @@ TEST_F(MockCircuits, PinFunctionSizes) run_test(false); } -TEST_F(MockCircuits, PinKernelSizes) +TEST_F(MockCircuits, PinRecursionKernelSizes) { const auto run_test = [](bool large) { { @@ -57,4 +58,29 @@ TEST_F(MockCircuits, PinKernelSizes) }; run_test(true); run_test(false); +} + +TEST_F(MockCircuits, PinFoldingKernelSizes) +{ + ClientIVC ivc; + + // Accumulate three circuits to generate two folding proofs for input to folding kernel + GoblinUltraCircuitBuilder circuit_1{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_1); + ivc.initialize(circuit_1); + + GoblinUltraCircuitBuilder circuit_2{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_2); + auto fold_proof_1 = ivc.accumulate(circuit_2); + + GoblinUltraCircuitBuilder circuit_3{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_3); + auto fold_proof_2 = ivc.accumulate(circuit_3); + + // Construct kernel circuit + GoblinUltraCircuitBuilder kernel_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, fold_proof_1, fold_proof_2); + GoblinUltraComposer composer; + auto instance = composer.create_instance(kernel_circuit); + EXPECT_EQ(instance->proving_key->log_circuit_size, 17); } \ No newline at end of file From 42b3a04e193c244408091e27d31925d7dc39d22d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 8 Feb 2024 16:28:56 +0000 Subject: [PATCH 20/23] kill prints --- barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp | 1 - .../cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 99958f08e8a..92db4e2aaca 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -33,7 +33,6 @@ ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof Composer composer; auto instance = composer.create_instance(circuit); - info("accumulate: instance->instance_size", instance->proving_key->circuit_size); std::vector> instances{ fold_output.accumulator, instance }; auto folding_prover = composer.create_folding_prover(instances); fold_output = folding_prover.fold_instances(); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 7c789d613b0..956fcda30f7 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -37,7 +37,6 @@ template void ProverInstance_::compute_circuit_size_param // The number of gates is max(lookup gates + tables, rows already populated in trace) + 1, where the +1 is due to // addition of a "zero row" at top of the execution trace to ensure wires and other polys are shiftable. total_num_gates = std::max(minimum_circuit_size_due_to_lookups, num_rows_populated_in_execution_trace); - info("total_num_gates", total_num_gates); // Next power of 2 dyadic_circuit_size = circuit.get_circuit_subgroup_size(total_num_gates); } From 0e404bc6425a013276fe8843b0044421c0401ae4 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 8 Feb 2024 16:37:37 +0000 Subject: [PATCH 21/23] cleanup --- .../benchmark/ivc_bench/ivc.bench.cpp | 4 +--- .../cpp/src/barretenberg/goblin/mock_circuits.hpp | 15 +++++++-------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp index 9ae6fce9869..95eeb7d5b94 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp @@ -20,7 +20,6 @@ namespace { */ class IvcBench : public benchmark::Fixture { public: - // Goblin::AccumulationOutput kernel_accum; using Builder = GoblinUltraCircuitBuilder; // Number of function circuits to accumulate(based on Zacs target numbers) @@ -41,7 +40,6 @@ class IvcBench : public benchmark::Fixture { * we set the size of the function circuit to be 2^17. The first one should be 2^19 but we can't currently support * folding circuits of unequal size. * - * @param state */ static void perform_ivc_accumulation_rounds(State& state, ClientIVC& ivc) { @@ -73,7 +71,7 @@ class IvcBench : public benchmark::Fixture { }; /** - * @brief Benchmark the full PG-Goblin IVC protocol + * @brief Benchmark the prover work for the full PG-Goblin IVC protocol * */ BENCHMARK_DEFINE_F(IvcBench, Full)(benchmark::State& state) diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index e8214bb1b57..1ada9716fc5 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -32,11 +32,6 @@ class GoblinMockCircuits { using KernelInput = Goblin::AccumulationOutput; static constexpr size_t NUM_OP_QUEUE_COLUMNS = Flavor::NUM_WIRES; - using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; - using RecursiveVerifierInstances = ::bb::VerifierInstances_; - using FoldingRecursiveVerifier = - bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; - /** * @brief Populate a builder with a specified number of arithmetic gates; includes a PI * @@ -211,15 +206,19 @@ class GoblinMockCircuits { * previous kernel circuit folding proof. The arbitrary kernel logic is structured to bring the final dyadic circuit * size of the kernel to 2^17. * - * TODO(https://github.com/AztecProtocol/barretenberg/issues/801): Pairing point aggregation not implemented * @param builder - * @param function_accum {proof, vkey} for function circuit to be recursively verified - * @param prev_kernel_accum {proof, vkey} for previous kernel circuit to be recursively verified + * @param function_fold_proof + * @param kernel_fold_proof */ static void construct_mock_folding_kernel(GoblinUltraBuilder& builder, const std::vector& function_fold_proof, const std::vector& kernel_fold_proof) { + using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; + using RecursiveVerifierInstances = ::bb::VerifierInstances_; + using FoldingRecursiveVerifier = + bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + // Add operations representing general kernel logic e.g. state updates. Note: these are structured to make the // kernel "full" within the dyadic size 2^17 (130914 gates) const size_t NUM_MERKLE_CHECKS = 20; From 93a247047a95f50b2faf54da4b809c571f6b0d77 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 8 Feb 2024 16:42:09 +0000 Subject: [PATCH 22/23] more cleanup --- barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt | 2 +- barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp | 6 +++--- .../src/barretenberg/sumcheck/instance/prover_instance.cpp | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt index 03b7e657a6d..ae6fa95da27 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt @@ -1,8 +1,8 @@ add_subdirectory(basics_bench) add_subdirectory(decrypt_bench) +add_subdirectory(goblin_bench) add_subdirectory(ipa_bench) add_subdirectory(ivc_bench) -add_subdirectory(goblin_bench) add_subdirectory(pippenger_bench) add_subdirectory(plonk_bench) add_subdirectory(protogalaxy_bench) diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index 1ada9716fc5..12fde5fb31b 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -202,9 +202,9 @@ class GoblinMockCircuits { /** * @brief Construct a mock kernel circuit based on folding * @details This circuit contains (1) some arbitrary operations representing general kernel logic, (2) recursive - * folding verification of a function circuit folding proof, and optionally (3) recursive folding verification of a - * previous kernel circuit folding proof. The arbitrary kernel logic is structured to bring the final dyadic circuit - * size of the kernel to 2^17. + * folding verification of a function circuit folding proof, and (3) recursive folding verification of a previous + * kernel circuit folding proof. The arbitrary kernel logic is structured to bring the final dyadic circuit size of + * the kernel to 2^17. * * @param builder * @param function_fold_proof diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 956fcda30f7..5479420510d 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -37,6 +37,7 @@ template void ProverInstance_::compute_circuit_size_param // The number of gates is max(lookup gates + tables, rows already populated in trace) + 1, where the +1 is due to // addition of a "zero row" at top of the execution trace to ensure wires and other polys are shiftable. total_num_gates = std::max(minimum_circuit_size_due_to_lookups, num_rows_populated_in_execution_trace); + // Next power of 2 dyadic_circuit_size = circuit.get_circuit_subgroup_size(total_num_gates); } From 91fbbfb71d0031be523377d198e1adcc636ce840 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 8 Feb 2024 17:20:09 +0000 Subject: [PATCH 23/23] move folding kernel pinning to ivc --- .../client_ivc/mock_kernel_pinning.test.cpp | 42 +++++++++++++++++++ .../src/barretenberg/goblin/CMakeLists.txt | 2 +- .../goblin/mock_circuits_pinning.test.cpp | 26 ------------ 3 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp new file mode 100644 index 00000000000..6ff29a1293e --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp @@ -0,0 +1,42 @@ +#include "barretenberg/client_ivc/client_ivc.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include + +using namespace bb; + +/** + * @brief For benchmarking, we want to be sure that our mocking functions create circuits of a known size. We control + * this, to the degree that matters for proof construction time, using these "pinning tests" that fix values. + * + */ +class MockKernelTest : public ::testing::Test { + protected: + static void SetUpTestSuite() { srs::init_crs_factory("../srs_db/ignition"); } +}; + +TEST_F(MockKernelTest, PinFoldingKernelSizes) +{ + ClientIVC ivc; + + // Accumulate three circuits to generate two folding proofs for input to folding kernel + GoblinUltraCircuitBuilder circuit_1{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_1); + ivc.initialize(circuit_1); + + GoblinUltraCircuitBuilder circuit_2{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_2); + auto fold_proof_1 = ivc.accumulate(circuit_2); + + GoblinUltraCircuitBuilder circuit_3{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_3); + auto fold_proof_2 = ivc.accumulate(circuit_3); + + // Construct kernel circuit + GoblinUltraCircuitBuilder kernel_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, fold_proof_1, fold_proof_2); + GoblinUltraComposer composer; + auto instance = composer.create_instance(kernel_circuit); + EXPECT_EQ(instance->proving_key->log_circuit_size, 17); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt index 386f068b491..ee4b04affe8 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(goblin stdlib_recursion ultra_honk eccvm translator_vm stdlib_sha256 stdlib_merkle_tree stdlib_primitives client_ivc) \ No newline at end of file +barretenberg_module(goblin stdlib_recursion ultra_honk eccvm translator_vm stdlib_sha256 stdlib_merkle_tree stdlib_primitives) \ No newline at end of file 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 a439cbe10d7..2f52c964eab 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp @@ -1,4 +1,3 @@ -#include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" @@ -58,29 +57,4 @@ TEST_F(MockCircuits, PinRecursionKernelSizes) }; run_test(true); run_test(false); -} - -TEST_F(MockCircuits, PinFoldingKernelSizes) -{ - ClientIVC ivc; - - // Accumulate three circuits to generate two folding proofs for input to folding kernel - GoblinUltraCircuitBuilder circuit_1{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_1); - ivc.initialize(circuit_1); - - GoblinUltraCircuitBuilder circuit_2{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_2); - auto fold_proof_1 = ivc.accumulate(circuit_2); - - GoblinUltraCircuitBuilder circuit_3{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_3); - auto fold_proof_2 = ivc.accumulate(circuit_3); - - // Construct kernel circuit - GoblinUltraCircuitBuilder kernel_circuit{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, fold_proof_1, fold_proof_2); - GoblinUltraComposer composer; - auto instance = composer.create_instance(kernel_circuit); - EXPECT_EQ(instance->proving_key->log_circuit_size, 17); } \ No newline at end of file