From c1709b3d5fe615d980b2ebd9283fb841d9e6a85a Mon Sep 17 00:00:00 2001 From: maramihali Date: Thu, 29 Feb 2024 12:36:06 +0000 Subject: [PATCH] refactor: Remove VK computation Pg prover flow; improve benchmark to reflect possible optimization (#4639) Closes https://github.com/AztecProtocol/barretenberg/issues/833. Properly separate prover and verifier information in the implemented Protogalaxy protocol according to the paper. The prover now returns a folded `ProverInstance` and the verifier a folded `VerifierInstance`. Previously the structure of the `ProverInstance` contained also information only relevant for the `VerifierInstance` (i.e. the verification key). With this separation, the prover doesn't need to send the previous verifier accumulator through the transcript anymore. Furthermore, this PR refactors the ClientIVC to work with this change (enabling precomputation of verification keys) as well as the recursive folding and decider verifiers. The latter required creating a stdlib counterpart of `VeriferInstance` since the previous verifier accumulator (\phi*) is now received from the previous folding iteration. The PR also implements an optimization that is possible in the application client IVC scheme that was not previously reflected in our benchmarks. Namely, it is possible for the IVC provers first fold to be a function circuit-function circuit fold. This means that we can remove one kernel iteration (including the construction of the kernel's witnesses and the protgalaxy prover execution). Bechmarks follow. Note: looking at just the difference in commitment times, we have observed that the commitment cost was reduced by 4s. # Benchmarks ## Before ``` Benchmarking lock created at ~/BENCHMARK_IN_PROGRESS. ivc_bench 100% 16MB 65.3MB/s 00:00 2024-02-23T15:02:49+00:00 Running ./ivc_bench Run on (16 X 3000 MHz CPU s) CPU Caches: L1 Data 32 KiB (x8) L1 Instruction 32 KiB (x8) L2 Unified 1024 KiB (x8) L3 Unified 36608 KiB (x1) Load Average: 5.87, 2.74, 1.08 ---------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------- IvcBench/Full/6 39833 ms 37395 ms 1 Benchmarking lock deleted. ``` ## After ``` ivc_bench 100% 16MB 61.5MB/s 00:00 2024-02-23T15:00:54+00:00 Running ./ivc_bench Run on (16 X 3000 MHz CPU s) CPU Caches: L1 Data 32 KiB (x8) L1 Instruction 32 KiB (x8) L2 Unified 1024 KiB (x8) L3 Unified 36608 KiB (x1) Load Average: 0.17, 0.36, 0.17 ---------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------- IvcBench/Full/6 32817 ms 31790 ms 1 ``` --------- Co-authored-by: ludamad Co-authored-by: codygunton --- .../client_ivc_bench/client_ivc.bench.cpp | 42 ++- .../protogalaxy_bench/protogalaxy.bench.cpp | 2 +- .../protogalaxy_rounds.bench.cpp | 11 +- .../benchmark/ultra_bench/mock_proofs.hpp | 4 +- .../barretenberg/client_ivc/client_ivc.cpp | 80 ++++- .../barretenberg/client_ivc/client_ivc.hpp | 31 +- .../client_ivc/client_ivc.test.cpp | 89 +++-- .../client_ivc/mock_kernel_pinning.test.cpp | 26 +- .../cpp/src/barretenberg/goblin/goblin.hpp | 4 +- .../goblin/goblin_recursion.test.cpp | 7 +- .../src/barretenberg/goblin/mock_circuits.hpp | 55 ++- .../goblin/mock_circuits_pinning.test.cpp | 4 +- .../protogalaxy/decider_prover.cpp | 48 --- .../protogalaxy/decider_prover.hpp | 1 - .../protogalaxy/decider_verifier.cpp | 57 +-- .../protogalaxy/decider_verifier.hpp | 5 +- .../protogalaxy/protogalaxy_prover.cpp | 105 +----- .../protogalaxy/protogalaxy_prover.hpp | 31 +- .../protogalaxy/protogalaxy_verifier.cpp | 166 ++------- .../protogalaxy/protogalaxy_verifier.hpp | 12 +- .../verifier/decider_recursive_verifier.cpp | 58 +--- .../verifier/decider_recursive_verifier.hpp | 9 +- .../honk/verifier/goblin_verifier.test.cpp | 32 +- .../honk/verifier/merge_verifier.test.cpp | 4 +- .../protogalaxy_recursive_verifier.cpp | 179 ++-------- .../protogalaxy_recursive_verifier.hpp | 20 +- .../protogalaxy_recursive_verifier.test.cpp | 326 +++++++++--------- .../honk/verifier/recursive_instances.hpp | 43 +++ .../verifier/recursive_verifier_instance.hpp | 148 ++++++++ .../recursion/honk/verifier/verifier.test.cpp | 30 +- .../sumcheck/instance/instances.hpp | 8 +- .../sumcheck/instance/prover_instance.hpp | 13 +- .../sumcheck/instance/verifier_instance.hpp | 11 + .../ultra_honk/databus_composer.test.cpp | 4 +- .../ultra_honk/goblin_ultra_composer.test.cpp | 4 +- .../goblin_ultra_transcript.test.cpp | 10 +- .../ultra_honk/protogalaxy.test.cpp | 147 ++++---- .../ultra_honk/relation_correctness.test.cpp | 4 +- .../barretenberg/ultra_honk/sumcheck.test.cpp | 2 +- .../ultra_honk/ultra_composer.cpp | 28 +- .../ultra_honk/ultra_composer.hpp | 32 +- .../ultra_honk/ultra_composer.test.cpp | 10 +- .../ultra_honk/ultra_transcript.test.cpp | 10 +- 43 files changed, 930 insertions(+), 982 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp diff --git a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp index cbdfcb2c0c8..9840e596f89 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp @@ -19,6 +19,7 @@ namespace { class ClientIVCBench : public benchmark::Fixture { public: using Builder = GoblinUltraCircuitBuilder; + using VerifierFoldData = GoblinMockCircuits::VerifierFoldData; // Number of function circuits to accumulate(based on Zacs target numbers) static constexpr size_t NUM_ITERATIONS_MEDIUM_COMPLEXITY = 6; @@ -43,28 +44,43 @@ class ClientIVCBench : public benchmark::Fixture { { const size_t size_hint = 1 << 17; // Size hint for reserving wires/selector vector memory in builders // Initialize IVC with function circuit - Builder function_circuit{ size_hint, ivc.goblin.op_queue }; + Builder initial_function_circuit{ size_hint, ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(initial_function_circuit); + ivc.initialize(initial_function_circuit); + auto kernel_verifier_accumulator = std::make_shared(ivc.vks.first_func_vk); + + // Accumulate another function circuit + Builder function_circuit{ ivc.goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(function_circuit); - ivc.initialize(function_circuit); + auto function_fold_proof = ivc.accumulate(function_circuit); + VerifierFoldData function_fold_output = { function_fold_proof, ivc.vks.func_vk }; - // Accumulate kernel circuit (first kernel mocked as simple circuit since no folding proofs yet) + // Create and accumulate the first folding kernel which only verifies the accumulation of a function circuit Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(kernel_circuit); + kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, function_fold_output, {}, kernel_verifier_accumulator); auto kernel_fold_proof = ivc.accumulate(kernel_circuit); + VerifierFoldData kernel_fold_output = { kernel_fold_proof, ivc.vks.first_kernel_vk }; auto NUM_CIRCUITS = static_cast(state.range(0)); - NUM_CIRCUITS -= 1; // Subtract one to account for the "initialization" round above + // Subtract two to account for the "initialization" round above i.e. we have already folded two function + // circuits + NUM_CIRCUITS -= 2; for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - // Accumulate function circuit Builder function_circuit{ size_hint, ivc.goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(function_circuit); auto function_fold_proof = ivc.accumulate(function_circuit); + function_fold_output = { function_fold_proof, ivc.vks.func_vk }; - // Accumulate kernel circuit + // Create kernel circuit containing the recursive folding verification of a function circuit and a kernel + // circuit and accumulate it Builder kernel_circuit{ size_hint, 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); + kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, function_fold_output, kernel_fold_output, kernel_verifier_accumulator); + + kernel_fold_proof = ivc.accumulate(kernel_circuit); + kernel_fold_output = { kernel_fold_proof, ivc.vks.kernel_vk }; } } }; @@ -76,7 +92,7 @@ class ClientIVCBench : public benchmark::Fixture { BENCHMARK_DEFINE_F(ClientIVCBench, Full)(benchmark::State& state) { ClientIVC ivc; - + ivc.precompute_folding_verification_keys(); for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation @@ -94,7 +110,7 @@ BENCHMARK_DEFINE_F(ClientIVCBench, Full)(benchmark::State& state) BENCHMARK_DEFINE_F(ClientIVCBench, Accumulate)(benchmark::State& state) { ClientIVC ivc; - + ivc.precompute_folding_verification_keys(); // Perform a specified number of iterations of function/kernel accumulation for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); @@ -109,7 +125,6 @@ BENCHMARK_DEFINE_F(ClientIVCBench, Accumulate)(benchmark::State& state) BENCHMARK_DEFINE_F(ClientIVCBench, Decide)(benchmark::State& state) { ClientIVC ivc; - // Perform a specified number of iterations of function/kernel accumulation perform_ivc_accumulation_rounds(state, ivc); @@ -145,7 +160,7 @@ BENCHMARK_DEFINE_F(ClientIVCBench, ECCVM)(benchmark::State& state) BENCHMARK_DEFINE_F(ClientIVCBench, Translator)(benchmark::State& state) { ClientIVC ivc; - + ivc.precompute_folding_verification_keys(); BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation perform_ivc_accumulation_rounds(state, ivc); @@ -159,7 +174,6 @@ BENCHMARK_DEFINE_F(ClientIVCBench, Translator)(benchmark::State& state) #define ARGS \ Arg(ClientIVCBench::NUM_ITERATIONS_MEDIUM_COMPLEXITY) \ - ->Arg(1 << 0) \ ->Arg(1 << 1) \ ->Arg(1 << 2) \ ->Arg(1 << 3) \ diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp index 61c46dc2493..0b5c2403cc5 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp @@ -30,7 +30,7 @@ template void fold_one(State& state) noexcept static_assert(std::same_as); bb::mock_proofs::generate_basic_arithmetic_circuit(builder, log2_num_gates); } - return composer.create_instance(builder); + return composer.create_prover_instance(builder); }; std::shared_ptr instance_1 = construct_instance(); diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp index 626ab82bc1f..5efdccce9ce 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp @@ -13,7 +13,6 @@ void _bench_round(::benchmark::State& state, void (*F)(ProtoGalaxyProver_>&)) { using Flavor = typename Composer::Flavor; - using Instance = ProverInstance_; using Builder = typename Flavor::CircuitBuilder; bb::srs::init_crs_factory("../srs_db/ignition"); @@ -28,16 +27,16 @@ void _bench_round(::benchmark::State& state, static_assert(std::same_as); bb::mock_proofs::generate_basic_arithmetic_circuit(builder, log2_num_gates); } - return composer.create_instance(builder); + return composer.create_prover_instance(builder); }; - std::shared_ptr instance_1 = construct_instance(); - std::shared_ptr instance_2 = construct_instance(); + auto prover_instance_1 = construct_instance(); + auto prover_instance_2 = construct_instance(); - auto folding_prover = composer.create_folding_prover({ instance_1, instance_2 }); + auto folding_prover = composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); // prepare the prover state - folding_prover.state.accumulator = instance_1; + folding_prover.state.accumulator = prover_instance_1; folding_prover.state.deltas.resize(log2_num_gates); std::fill_n(folding_prover.state.deltas.begin(), log2_num_gates, 0); folding_prover.state.perturbator = Flavor::Polynomial::random(1 << log2_num_gates); diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp index 1c0a1ed43ba..29ff2fb135e 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp @@ -54,7 +54,7 @@ inline UltraProver get_prover(UltraComposer& composer, { UltraComposer::CircuitBuilder builder; test_circuit_function(builder, num_iterations); - std::shared_ptr instance = composer.create_instance(builder); + std::shared_ptr instance = composer.create_prover_instance(builder); return composer.create_prover(instance); } @@ -64,7 +64,7 @@ inline GoblinUltraProver get_prover(GoblinUltraComposer& composer, { GoblinUltraComposer::CircuitBuilder builder; test_circuit_function(builder, num_iterations); - std::shared_ptr instance = composer.create_instance(builder); + std::shared_ptr instance = composer.create_prover_instance(builder); return composer.create_prover(instance); } diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 92db4e2aaca..911c802ebf8 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -18,7 +18,7 @@ void ClientIVC::initialize(ClientCircuit& circuit) { goblin.merge(circuit); // Construct new merge proof Composer composer; - fold_output.accumulator = composer.create_instance(circuit); + prover_fold_output.accumulator = composer.create_prover_instance(circuit); } /** @@ -32,11 +32,10 @@ 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; + prover_instance = composer.create_prover_instance(circuit); + auto folding_prover = composer.create_folding_prover({ prover_fold_output.accumulator, prover_instance }); + prover_fold_output = folding_prover.fold_instances(); + return prover_fold_output.folding_data; } /** @@ -46,7 +45,7 @@ ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) */ ClientIVC::Proof ClientIVC::prove() { - return { fold_output.folding_data, decider_prove(), goblin.prove() }; + return { prover_fold_output.folding_data, decider_prove(), goblin.prove() }; } /** @@ -55,19 +54,19 @@ ClientIVC::Proof ClientIVC::prove() * @param proof * @return bool */ -bool ClientIVC::verify(Proof& proof) +bool ClientIVC::verify(Proof& proof, const std::vector& verifier_instances) { // 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); + auto folding_verifier = composer.create_folding_verifier({ verifier_instances[0], verifier_instances[1] }); + auto verifier_accumulator = folding_verifier.verify_folding_proof(proof.fold_proof); + + auto decider_verifier = composer.create_decider_verifier(verifier_accumulator); bool decision = decider_verifier.verify_proof(proof.decider_proof); - return goblin_verified && folding_verified && decision; + return goblin_verified && decision; } /** @@ -78,8 +77,61 @@ bool ClientIVC::verify(Proof& proof) HonkProof ClientIVC::decider_prove() const { Composer composer; - auto decider_prover = composer.create_decider_prover(fold_output.accumulator); + auto decider_prover = composer.create_decider_prover(prover_fold_output.accumulator); return decider_prover.construct_proof(); } +/** + * @brief Precompute the array of verification keys by simulating folding. There will be 4 different verification keys: + * initial function verification key (without recursive merge verifier), subsequent function verification key (with + * recursive merge verifier), initial kernel verification key (with recursive merge verifier appended, no previous + * kernel to fold), "full" kernel verification key( two recursive folding verifiers and merge verifier). + * + */ +void ClientIVC::precompute_folding_verification_keys() +{ + using VerifierInstance = VerifierInstance_; + + ClientCircuit initial_function_circuit{ goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(initial_function_circuit); + + // Initialise both the first prover and verifier accumulator from the inital function circuit + initialize(initial_function_circuit); + vks.first_func_vk = prover_fold_output.accumulator->verification_key; + auto initial_verifier_acc = std::make_shared(vks.first_func_vk); + + // Accumulate the next function circuit + ClientCircuit function_circuit{ goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + auto function_fold_proof = accumulate(function_circuit); + + // Create its verification key (we have called accumulate so it includes the recursive merge verifier) + vks.func_vk = prover_instance->verification_key; + + // Create the initial kernel iteration and precompute its verification key + ClientCircuit kernel_circuit{ goblin.op_queue }; + auto kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, { function_fold_proof, vks.func_vk }, {}, initial_verifier_acc); + auto kernel_fold_proof = accumulate(kernel_circuit); + vks.first_kernel_vk = prover_instance->verification_key; + + // Create another mock function circuit to run the full kernel + function_circuit = ClientCircuit{ goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + function_fold_proof = accumulate(function_circuit); + + // Create the full kernel circuit and compute verification key + kernel_circuit = GoblinUltraCircuitBuilder{ goblin.op_queue }; + kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, { function_fold_proof, vks.func_vk }, { kernel_fold_proof, vks.first_kernel_vk }, kernel_acc); + kernel_fold_proof = accumulate(kernel_circuit); + + vks.kernel_vk = prover_instance->verification_key; + + // Clean the ivc state + goblin.op_queue = std::make_shared(); + goblin.merge_proof_exists = false; + GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); +} + } // 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 cd3b82b4d6d..5c444ac9ec5 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -16,9 +16,13 @@ class ClientIVC { public: using Flavor = GoblinUltraFlavor; + using VerificationKey = Flavor::VerificationKey; using FF = Flavor::FF; using FoldProof = std::vector; - using Accumulator = std::shared_ptr>; + using ProverAccumulator = std::shared_ptr>; + using VerifierAccumulator = std::shared_ptr>; + using ProverInstance = ProverInstance_; + using VerifierInstance = VerifierInstance_; using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra // A full proof for the IVC scheme @@ -28,14 +32,27 @@ class ClientIVC { Goblin::Proof goblin_proof; }; + struct PrecomputedVerificationKeys { + std::shared_ptr first_func_vk; + std::shared_ptr func_vk; + std::shared_ptr first_kernel_vk; + std::shared_ptr kernel_vk; + }; + private: - using FoldingOutput = FoldingResult; - using Instance = ProverInstance_; + using ProverFoldOutput = FoldingResult; using Composer = GoblinUltraComposer; + // Note: We need to save the last instance that was folded in order to compute its verification key, this will not + // be needed in the real IVC as they are provided as inputs public: Goblin goblin; - FoldingOutput fold_output; + ProverFoldOutput prover_fold_output; + ProverAccumulator prover_accumulator; + PrecomputedVerificationKeys vks; + // Note: We need to save the last instance that was folded in order to compute its verification key, this will not + // be needed in the real IVC as they are provided as inputs + std::shared_ptr prover_instance; ClientIVC(); @@ -45,8 +62,12 @@ class ClientIVC { Proof prove(); - bool verify(Proof& proof); + bool verify(Proof& proof, const std::vector& verifier_instances); HonkProof decider_prove() const; + + void decider_prove_and_verify(const VerifierAccumulator&) const; + + void precompute_folding_verification_keys(); }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp index 2924188f87d..45e594f47a9 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp @@ -21,17 +21,22 @@ class ClientIVCTests : public ::testing::Test { using FF = typename Flavor::FF; using Builder = ClientIVC::ClientCircuit; using Composer = GoblinUltraComposer; - using Accumulator = ClientIVC::Accumulator; + using ProverAccumulator = ClientIVC::ProverAccumulator; + using VerifierAccumulator = ClientIVC::VerifierAccumulator; + using VerifierInstance = ClientIVC::VerifierInstance; using FoldProof = ClientIVC::FoldProof; - + using VerifierFoldData = GoblinMockCircuits::VerifierFoldData; using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; - using RecursiveVerifierInstances = ::bb::VerifierInstances_; + using RecursiveVerifierInstance = ::bb::stdlib::recursion::honk::RecursiveVerifierInstance_; + using RecursiveVerifierAccumulator = std::shared_ptr; + using RecursiveVerifierInstances = ::bb::stdlib::recursion::honk::RecursiveVerifierInstances_; using FoldingRecursiveVerifier = bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; /** * @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) + * @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 log2_num_gates = 15) @@ -43,41 +48,54 @@ class ClientIVCTests : public ::testing::Test { } /** - * @brief Construct mock kernel consisting of two recursive folding verifiers + * @brief Construct mock kernel consisting of two recursive folding verifiers to verify the folding of the previous + * function circuit and kernel circuit. * * @param builder - * @param fctn_fold_proof - * @param kernel_fold_proof + * @param func_accum contains the folding proof for the function circuit and the corresponsing function + * verifier instance + * @param kernel_accum contains the folding proof for the kernel circuit and the corresponding kernel verifier + * instance + * @returns the updated verifier accumulator */ - static void construct_mock_folding_kernel(Builder& builder, - FoldProof& fctn_fold_proof, - FoldProof& kernel_fold_proof) + static VerifierAccumulator construct_mock_folding_kernel(Builder& builder, + VerifierFoldData& func_accum, + VerifierFoldData& kernel_accum, + VerifierAccumulator& prev_kernel_accum) { - FoldingRecursiveVerifier verifier_1{ &builder }; - verifier_1.verify_folding_proof(fctn_fold_proof); - FoldingRecursiveVerifier verifier_2{ &builder }; - verifier_2.verify_folding_proof(kernel_fold_proof); + FoldingRecursiveVerifier verifier_1{ &builder, prev_kernel_accum, { func_accum.inst_vk } }; + auto fctn_verifier_accum = verifier_1.verify_folding_proof(func_accum.fold_proof); + auto native_acc = std::make_shared(fctn_verifier_accum->get_value()); + FoldingRecursiveVerifier verifier_2{ &builder, native_acc, { kernel_accum.inst_vk } }; + auto kernel_verifier_accum = verifier_2.verify_folding_proof(kernel_accum.fold_proof); + return std::make_shared(kernel_verifier_accum->get_value()); } /** * @brief Perform native fold verification and run decider prover/verifier * */ - static void EXPECT_FOLDING_AND_DECIDING_VERIFIED(const Accumulator& accumulator, const FoldProof& fold_proof) + static VerifierAccumulator update_accumulator_and_decide_native( + const ProverAccumulator& prover_accumulator, + const FoldProof& fold_proof, + const VerifierAccumulator& prev_verifier_accumulator, + const std::shared_ptr& verifier_inst_vk) { // 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); + auto new_verifier_inst = std::make_shared(verifier_inst_vk); + auto folding_verifier = composer.create_folding_verifier({ prev_verifier_accumulator, new_verifier_inst }); + auto verifier_accumulator = folding_verifier.verify_folding_proof(fold_proof); // 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(prover_accumulator); + auto decider_verifier = composer.create_decider_verifier(verifier_accumulator); auto decider_proof = decider_prover.construct_proof(); bool decision = decider_verifier.verify_proof(decider_proof); EXPECT_TRUE(decision); + + return verifier_accumulator; } }; @@ -88,33 +106,48 @@ class ClientIVCTests : public ::testing::Test { TEST_F(ClientIVCTests, Full) { ClientIVC ivc; - // Initialize IVC with function circuit Builder function_circuit = create_mock_circuit(ivc); ivc.initialize(function_circuit); + auto function_vk = ivc.prover_fold_output.accumulator->verification_key; + auto foo_verifier_instance = std::make_shared(function_vk); // 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.fold_output.accumulator, kernel_fold_proof); + // This will have a different verification key because we added the recursive merge verification to the circuit + auto function_vk_with_merge = ivc.prover_instance->verification_key; + auto kernel_vk = function_vk_with_merge; + auto intermediary_acc = update_accumulator_and_decide_native( + ivc.prover_fold_output.accumulator, kernel_fold_proof, foo_verifier_instance, kernel_vk); + VerifierFoldData kernel_fold_output = { kernel_fold_proof, function_vk_with_merge }; 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.fold_output.accumulator, function_fold_proof); + intermediary_acc = update_accumulator_and_decide_native( + ivc.prover_fold_output.accumulator, function_fold_proof, intermediary_acc, function_vk_with_merge); + + VerifierFoldData function_fold_output = { function_fold_proof, function_vk_with_merge }; // Accumulate kernel circuit Builder kernel_circuit{ ivc.goblin.op_queue }; - construct_mock_folding_kernel(kernel_circuit, function_fold_proof, kernel_fold_proof); + foo_verifier_instance = construct_mock_folding_kernel( + kernel_circuit, kernel_fold_output, function_fold_output, foo_verifier_instance); FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.fold_output.accumulator, kernel_fold_proof); + kernel_vk = ivc.prover_instance->verification_key; + + intermediary_acc = update_accumulator_and_decide_native( + ivc.prover_fold_output.accumulator, kernel_fold_proof, intermediary_acc, kernel_vk); + + VerifierFoldData kernel_fold_output = { kernel_fold_proof, kernel_vk }; } // Constuct four proofs: merge, eccvm, translator, decider auto proof = ivc.prove(); - + auto inst = std::make_shared(kernel_vk); // Verify all four proofs - EXPECT_TRUE(ivc.verify(proof)); -} \ No newline at end of file + EXPECT_TRUE(ivc.verify(proof, { foo_verifier_instance, inst })); +}; \ No newline at end of file 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 index 6ff29a1293e..773496dbfb2 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp @@ -19,24 +19,36 @@ class MockKernelTest : public ::testing::Test { TEST_F(MockKernelTest, PinFoldingKernelSizes) { ClientIVC ivc; - + ivc.precompute_folding_verification_keys(); // 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); + auto kernel_acc = std::make_shared(ivc.vks.first_func_vk); + kernel_acc->verification_key = ivc.vks.first_func_vk; GoblinUltraCircuitBuilder circuit_2{ ivc.goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(circuit_2); - auto fold_proof_1 = ivc.accumulate(circuit_2); + auto func_fold_proof = ivc.accumulate(circuit_2); + + // Construct kernel circuit + GoblinUltraCircuitBuilder kernel_circuit{ ivc.goblin.op_queue }; + kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, { func_fold_proof, ivc.vks.func_vk }, {}, kernel_acc); + + auto kernel_fold_proof = ivc.accumulate(kernel_circuit); + EXPECT_EQ(ivc.prover_instance->log_instance_size, 17); GoblinUltraCircuitBuilder circuit_3{ ivc.goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(circuit_3); - auto fold_proof_2 = ivc.accumulate(circuit_3); + func_fold_proof = 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); + kernel_circuit = GoblinUltraCircuitBuilder{ ivc.goblin.op_queue }; + kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, + { kernel_fold_proof, ivc.vks.first_kernel_vk }, + { func_fold_proof, ivc.vks.func_vk }, + kernel_acc); GoblinUltraComposer composer; - auto instance = composer.create_instance(kernel_circuit); + auto instance = composer.create_prover_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/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 0efd9b3183a..bb5772f7d31 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -104,7 +104,7 @@ class Goblin { // Construct a Honk proof for the main circuit GoblinUltraComposer composer; - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); auto prover = composer.create_prover(instance); auto ultra_proof = prover.construct_proof(); @@ -230,7 +230,7 @@ class Goblin { // Construct a Honk proof for the main circuit GoblinUltraComposer composer; - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); auto prover = composer.create_prover(instance); auto ultra_proof = prover.construct_proof(); diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp index dc0facdb60a..c731722d755 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp @@ -24,10 +24,11 @@ class GoblinRecursionTests : public ::testing::Test { static Goblin::AccumulationOutput construct_accumulator(GoblinUltraBuilder& builder) { GoblinUltraComposer composer; - auto instance = composer.create_instance(builder); - auto prover = composer.create_prover(instance); + auto prover_instance = composer.create_prover_instance(builder); + auto verifier_instance = composer.create_verifier_instance(prover_instance); + auto prover = composer.create_prover(prover_instance); auto ultra_proof = prover.construct_proof(); - return { ultra_proof, instance->verification_key }; + return { ultra_proof, verifier_instance->verification_key }; } }; diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index 04ac0636b20..884e5c27ab8 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -31,17 +31,30 @@ class GoblinMockCircuits { using RecursiveFlavor = bb::GoblinUltraRecursiveFlavor_; using RecursiveVerifier = bb::stdlib::recursion::honk::UltraRecursiveVerifier_; using KernelInput = Goblin::AccumulationOutput; + using VerifierInstance = bb::VerifierInstance_; + using RecursiveVerifierInstance = ::bb::stdlib::recursion::honk::RecursiveVerifierInstance_; + using RecursiveVerifierAccumulator = std::shared_ptr; + using VerificationKey = Flavor::VerificationKey; static constexpr size_t NUM_OP_QUEUE_COLUMNS = Flavor::NUM_WIRES; + /** + * @brief Information required by the verifier to verify a folding round besides the previous accumulator. + */ + struct VerifierFoldData { + std::vector fold_proof; // folding proof + std::shared_ptr + inst_vk; // Verification key of the instance to be folded (note: this would be a vector if k > 1 ) + }; + /** * @brief Populate a builder with a specified number of arithmetic gates; includes a PI * * @param builder * @param num_gates */ - static void construct_arithmetic_circuit(GoblinUltraBuilder& builder, size_t log2_num_gates = 0) + static void construct_arithmetic_circuit(GoblinUltraBuilder& builder, size_t log_num_gates = 0) { - size_t num_gates = 1 << log2_num_gates; + size_t num_gates = 1 << log_num_gates; // For good measure, include a gate with some public inputs { FF a = FF::random_element(); @@ -107,8 +120,9 @@ class GoblinMockCircuits { stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ITERATIONS); // min gates: ~41k stdlib::generate_merkle_membership_test_circuit(builder, NUM_ITERATIONS); // min gates: ~29k - // Note: its not clear whether goblin ops will be supported for function circuits initially but currently UGH - // can only be used if some op gates are included so for now we'll assume each function circuit has some. + // Note: its not clear whether goblin ops will be supported for function circuits initially but currently + // UGH can only be used if some op gates are included so for now we'll assume each function circuit has + // some. construct_goblin_ecc_op_circuit(builder); } @@ -213,30 +227,41 @@ class GoblinMockCircuits { * @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) + static std::shared_ptr construct_mock_folding_kernel( + GoblinUltraBuilder& builder, + const VerifierFoldData& func, + const VerifierFoldData& kernel, + std::shared_ptr& prev_kernel_accum) { BB_OP_COUNT_TIME(); using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; - using RecursiveVerifierInstances = ::bb::VerifierInstances_; + using RecursiveVerifierInstances = + bb::stdlib::recursion::honk::RecursiveVerifierInstances_; 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; + // 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 = 25; 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); + // Initial kernel iteration does not have a previous kernel to fold + if (kernel.fold_proof.empty()) { + FoldingRecursiveVerifier verifier_1{ &builder, prev_kernel_accum, { func.inst_vk } }; + auto fctn_verifier_accum = verifier_1.verify_folding_proof(func.fold_proof); + return std::make_shared(fctn_verifier_accum->get_value()); + } - FoldingRecursiveVerifier verifier_2{ &builder }; - verifier_2.verify_folding_proof(kernel_fold_proof); + FoldingRecursiveVerifier verifier_2{ &builder, prev_kernel_accum, { kernel.inst_vk } }; + auto kernel_verifier_accum = verifier_2.verify_folding_proof(kernel.fold_proof); + auto native_acc = std::make_shared(kernel_verifier_accum->get_value()); + FoldingRecursiveVerifier verifier_1{ &builder, native_acc, { func.inst_vk } }; + auto fctn_verifier_accum = verifier_1.verify_folding_proof(func.fold_proof); + return std::make_shared(fctn_verifier_accum->get_value()); } /** 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 2f52c964eab..db0fc69b80d 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp @@ -23,7 +23,7 @@ TEST_F(MockCircuits, PinFunctionSizes) GoblinUltraCircuitBuilder app_circuit{ goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(app_circuit, large); GoblinUltraComposer composer; - auto instance = composer.create_instance(app_circuit); + auto instance = composer.create_prover_instance(app_circuit); if (large) { EXPECT_EQ(instance->proving_key->log_circuit_size, 19); } else { @@ -47,7 +47,7 @@ TEST_F(MockCircuits, PinRecursionKernelSizes) GoblinUltraCircuitBuilder kernel_circuit{ goblin.op_queue }; GoblinMockCircuits::construct_mock_recursion_kernel_circuit(kernel_circuit, function_accum, kernel_accum); GoblinUltraComposer composer; - auto instance = composer.create_instance(kernel_circuit); + auto instance = composer.create_prover_instance(kernel_circuit); if (large) { EXPECT_EQ(instance->proving_key->log_circuit_size, 17); } else { diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp index 522b6e1d8e6..c808e5e6542 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp @@ -21,51 +21,6 @@ DeciderProver_::DeciderProver_(const std::shared_ptr& inst, , commitment_key(commitment_key) {} -/** - * @brief Add ϕ, \vec{β}, e to the transcript. These are produced in the last round of folding that was carried out - * before deciding. - */ -template void DeciderProver_::execute_preamble_round() -{ - const auto accumulator_size = static_cast(accumulator->instance_size); - const auto num_public_inputs = static_cast(accumulator->public_inputs.size()); - transcript->send_to_verifier("accumulator_size", accumulator_size); - transcript->send_to_verifier("public_input_size", num_public_inputs); - - for (size_t i = 0; i < accumulator->public_inputs.size(); ++i) { - auto public_input_i = accumulator->public_inputs[i]; - transcript->send_to_verifier("public_input_" + std::to_string(i), public_input_i); - } - - transcript->send_to_verifier("eta", accumulator->relation_parameters.eta); - transcript->send_to_verifier("beta", accumulator->relation_parameters.beta); - transcript->send_to_verifier("gamma", accumulator->relation_parameters.gamma); - transcript->send_to_verifier("public_input_delta", accumulator->relation_parameters.public_input_delta); - transcript->send_to_verifier("lookup_grand_product_delta", - accumulator->relation_parameters.lookup_grand_product_delta); - size_t alpha_idx = 0; - for (auto alpha : accumulator->alphas) { - transcript->send_to_verifier("alpha_" + std::to_string(alpha_idx), alpha); - } - - transcript->send_to_verifier("target_sum", accumulator->target_sum); - for (size_t idx = 0; idx < accumulator->gate_challenges.size(); idx++) { - transcript->send_to_verifier("gate_challenge_" + std::to_string(idx), accumulator->gate_challenges[idx]); - } - - auto comm_view = accumulator->witness_commitments.get_all(); - auto witness_labels = accumulator->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - transcript->send_to_verifier(witness_labels[idx], comm_view[idx]); - } - - auto vk_view = accumulator->verification_key->get_all(); - auto vk_labels = accumulator->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - transcript->send_to_verifier(vk_labels[idx], vk_view[idx]); - } -} - /** * @brief Run Sumcheck to establish that ∑_i pow(\vec{β*})f_i(ω) = e*. This results in u = (u_1,...,u_d) sumcheck round * challenges and all evaluations at u being calculated. @@ -105,9 +60,6 @@ template HonkProof& DeciderProver_::construct_pro { BB_OP_COUNT_TIME_NAME("Decider::construct_proof"); - // Add ϕ, \vec{β*}, e* to transcript - execute_preamble_round(); - // Run sumcheck subprotocol. execute_relation_check_rounds(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp index 43d0b602bcc..562a1700ba2 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp @@ -28,7 +28,6 @@ template class DeciderProver_ { const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); - BB_PROFILE void execute_preamble_round(); BB_PROFILE void execute_relation_check_rounds(); BB_PROFILE void execute_zeromorph_rounds(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index 18a2c949b69..e685f8930ec 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -8,8 +8,8 @@ namespace bb { template DeciderVerifier_::DeciderVerifier_(const std::shared_ptr& transcript, - const std::shared_ptr& verifier_key) - : key(verifier_key) + const std::shared_ptr& accumulator) + : accumulator(accumulator) , transcript(transcript) {} template @@ -25,65 +25,18 @@ DeciderVerifier_::DeciderVerifier_() */ template bool DeciderVerifier_::verify_proof(const HonkProof& proof) { - using FF = typename Flavor::FF; - using Commitment = typename Flavor::Commitment; using Curve = typename Flavor::Curve; using ZeroMorph = ZeroMorphVerifier_; - using Instance = VerifierInstance_; using VerifierCommitments = typename Flavor::VerifierCommitments; - static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; transcript = std::make_shared(proof); - auto inst = std::make_unique(); - inst->instance_size = transcript->template receive_from_prover("instance_size"); - inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); - inst->public_input_size = transcript->template receive_from_prover("public_input_size"); + VerifierCommitments commitments{ accumulator->verification_key, accumulator->witness_commitments }; - for (size_t i = 0; i < inst->public_input_size; ++i) { - auto public_input_i = transcript->template receive_from_prover("public_input_" + std::to_string(i)); - inst->public_inputs.emplace_back(public_input_i); - } - - auto eta = transcript->template receive_from_prover("eta"); - auto beta = transcript->template receive_from_prover("beta"); - auto gamma = transcript->template receive_from_prover("gamma"); - auto public_input_delta = transcript->template receive_from_prover("public_input_delta"); - auto lookup_grand_product_delta = transcript->template receive_from_prover("lookup_grand_product_delta"); - inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; - - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - - inst->alphas[idx] = transcript->template receive_from_prover("alpha" + std::to_string(idx)); - } - - inst->target_sum = transcript->template receive_from_prover("target_sum"); - - inst->gate_challenges = std::vector(inst->log_instance_size); - for (size_t idx = 0; idx < inst->log_instance_size; idx++) { - inst->gate_challenges[idx] = - transcript->template receive_from_prover("gate_challenge_" + std::to_string(idx)); - } - auto comm_view = inst->witness_commitments.get_all(); - auto witness_labels = inst->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - comm_view[idx] = transcript->template receive_from_prover(witness_labels[idx]); - } - - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = inst->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(vk_labels[idx]); - } - - VerifierCommitments commitments{ inst->verification_key, inst->witness_commitments }; - - auto sumcheck = SumcheckVerifier(inst->log_instance_size, transcript, inst->target_sum); + auto sumcheck = SumcheckVerifier(accumulator->log_instance_size, transcript, accumulator->target_sum); auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = - sumcheck.verify(inst->relation_parameters, inst->alphas, inst->gate_challenges); + sumcheck.verify(accumulator->relation_parameters, accumulator->alphas, accumulator->gate_challenges); // If Sumcheck did not verify, return false if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp index 70ca2033617..3969b89d96c 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp @@ -3,6 +3,7 @@ #include "barretenberg/flavor/ultra.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/srs/global_crs.hpp" +#include "barretenberg/sumcheck/instance/verifier_instance.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" namespace bb { @@ -12,16 +13,18 @@ template class DeciderVerifier_ { using VerificationKey = typename Flavor::VerificationKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using Transcript = typename Flavor::Transcript; + using VerifierInstance = VerifierInstance_; public: explicit DeciderVerifier_(); explicit DeciderVerifier_(const std::shared_ptr& transcript, - const std::shared_ptr& verifier_key = nullptr); + const std::shared_ptr& accumulator = nullptr); bool verify_proof(const HonkProof& proof); std::shared_ptr key; std::map commitments; + std::shared_ptr accumulator; std::shared_ptr pcs_verification_key; std::shared_ptr transcript; }; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index 378f6aee6fb..8d505a50959 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -92,56 +92,6 @@ void ProtoGalaxyProver_::finalise_and_send_instance(std::shared instance->alphas[idx] = transcript->template get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); } - auto vk_view = instance->verification_key->get_all(); - auto labels = instance->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < labels.size(); idx++) { - transcript->send_to_verifier(domain_separator + "_" + labels[idx], vk_view[idx]); - } -} - -template -void ProtoGalaxyProver_::send_accumulator(std::shared_ptr instance, - const std::string& domain_separator) -{ - const auto instance_size = static_cast(instance->instance_size); - const auto num_public_inputs = static_cast(instance->public_inputs.size()); - transcript->send_to_verifier(domain_separator + "_instance_size", instance_size); - transcript->send_to_verifier(domain_separator + "_public_input_size", num_public_inputs); - - for (size_t i = 0; i < instance->public_inputs.size(); ++i) { - auto public_input_i = instance->public_inputs[i]; - transcript->send_to_verifier(domain_separator + "_public_input_" + std::to_string(i), public_input_i); - } - - transcript->send_to_verifier(domain_separator + "_eta", instance->relation_parameters.eta); - transcript->send_to_verifier(domain_separator + "_beta", instance->relation_parameters.beta); - transcript->send_to_verifier(domain_separator + "_gamma", instance->relation_parameters.gamma); - transcript->send_to_verifier(domain_separator + "_public_input_delta", - instance->relation_parameters.public_input_delta); - transcript->send_to_verifier(domain_separator + "_lookup_grand_product_delta", - instance->relation_parameters.lookup_grand_product_delta); - - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - transcript->send_to_verifier(domain_separator + "_alpha_" + std::to_string(idx), instance->alphas[idx]); - } - - transcript->send_to_verifier(domain_separator + "_target_sum", instance->target_sum); - for (size_t idx = 0; idx < instance->gate_challenges.size(); idx++) { - transcript->send_to_verifier(domain_separator + "_gate_challenge_" + std::to_string(idx), - instance->gate_challenges[idx]); - } - - auto comm_view = instance->witness_commitments.get_all(); - auto witness_labels = instance->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - transcript->send_to_verifier(domain_separator + "_" + witness_labels[idx], comm_view[idx]); - } - - auto vk_view = instance->verification_key->get_all(); - auto vk_labels = instance->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - transcript->send_to_verifier(domain_separator + "_" + vk_labels[idx], vk_view[idx]); - } } template void ProtoGalaxyProver_::prepare_for_folding() @@ -149,11 +99,7 @@ template void ProtoGalaxyProver_::prepa auto idx = 0; auto instance = instances[0]; auto domain_separator = std::to_string(idx); - transcript->send_to_verifier(domain_separator + "is_accumulator", instance->is_accumulator); - if (instance->is_accumulator) { - send_accumulator(instance, domain_separator); - } else { - // This is the first round of folding and we need to generate some gate challenges. + if (!instance->is_accumulator) { finalise_and_send_instance(instance, domain_separator); instance->target_sum = 0; instance->gate_challenges = std::vector(instance->log_instance_size, 0); @@ -192,10 +138,6 @@ std::shared_ptr ProtoGalaxyProver_send_to_verifier("next_target_sum", next_target_sum); - for (size_t idx = 0; idx < instances.next_gate_challenges.size(); idx++) { - transcript->send_to_verifier("next_gate_challenge_" + std::to_string(idx), instances.next_gate_challenges[idx]); - } next_accumulator->target_sum = next_target_sum; next_accumulator->gate_challenges = instances.next_gate_challenges; @@ -216,20 +158,6 @@ std::shared_ptr ProtoGalaxyProver_prover_polynomials = std::move(acc_prover_polynomials); - // Fold the witness commtiments and send them to the verifier - auto witness_labels = next_accumulator->commitment_labels.get_witness(); - size_t comm_idx = 0; - for (auto& acc_comm : next_accumulator->witness_commitments.get_all()) { - acc_comm = Commitment::infinity(); - size_t inst_idx = 0; - for (auto& instance : instances) { - acc_comm = acc_comm + instance->witness_commitments.get_all()[comm_idx] * lagranges[inst_idx]; - inst_idx++; - } - transcript->send_to_verifier("next_" + witness_labels[comm_idx], acc_comm); - comm_idx++; - } - // Fold public data ϕ from all instances to produce ϕ* and add it to the transcript. As part of the folding // verification, the verifier will produce ϕ* as well and check it against what was sent by the prover. @@ -245,7 +173,6 @@ std::shared_ptr ProtoGalaxyProver_send_to_verifier("next_public_input_" + std::to_string(el_idx), el); el_idx++; } @@ -254,7 +181,6 @@ std::shared_ptr ProtoGalaxyProver_alphas; for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { folded_alphas[idx] = instances.alphas[idx].evaluate(challenge); - transcript->send_to_verifier("next_alpha_" + std::to_string(idx), folded_alphas[idx]); } // Evaluate each relation parameter univariate at challenge to obtain the folded relation parameters and send to @@ -267,32 +193,7 @@ std::shared_ptr ProtoGalaxyProver_send_to_verifier("next_eta", folded_relation_parameters.eta); - transcript->send_to_verifier("next_beta", folded_relation_parameters.beta); - transcript->send_to_verifier("next_gamma", folded_relation_parameters.gamma); - transcript->send_to_verifier("next_public_input_delta", folded_relation_parameters.public_input_delta); - transcript->send_to_verifier("next_lookup_grand_product_delta", - folded_relation_parameters.lookup_grand_product_delta); next_accumulator->relation_parameters = folded_relation_parameters; - - // Fold the verification key and send it to the verifier as this is part of ϕ as well - auto acc_vk = std::make_shared(instances[0]->prover_polynomials.get_polynomial_size(), - instances[0]->public_inputs.size()); - auto labels = next_accumulator->commitment_labels.get_precomputed(); - size_t vk_idx = 0; - for (auto& vk : acc_vk->get_all()) { - size_t inst = 0; - vk = Commitment::infinity(); - for (auto& instance : instances) { - vk = vk + (instance->verification_key->get_all()[vk_idx]) * lagranges[inst]; - inst++; - } - transcript->send_to_verifier("next_" + labels[vk_idx], vk); - vk_idx++; - } - next_accumulator->verification_key = acc_vk; return next_accumulator; } @@ -310,7 +211,9 @@ template void ProtoGalaxyProver_::pertu // compute perturbator only if this is not the first round and has an accumulator if (state.accumulator->is_accumulator) { state.perturbator = compute_perturbator(state.accumulator, state.deltas); - for (size_t idx = 0; idx <= state.accumulator->log_instance_size; idx++) { + // Prover doesn't send the constant coefficient of F because this is supposed to be equal to the target sum of + // the accumulator which the folding verifier has from the previous iteration. + for (size_t idx = 1; idx <= state.accumulator->log_instance_size; idx++) { transcript->send_to_verifier("perturbator_" + std::to_string(idx), state.perturbator[idx]); } } diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp index d5a142e7433..038c7a2e9da 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -41,6 +41,7 @@ template class ProtoGalaxyProver_ { using VerificationKey = typename Flavor::VerificationKey; using CommitmentKey = typename Flavor::CommitmentKey; using WitnessCommitments = typename Flavor::WitnessCommitments; + using CommitmentLabels = typename Flavor::CommitmentLabels; using Commitment = typename Flavor::Commitment; using BaseUnivariate = Univariate; @@ -80,14 +81,6 @@ template class ProtoGalaxyProver_ { */ void prepare_for_folding(); - /** - * @brief Send the public data of an accumulator, i.e. a relaxed instance, to the verifier (ϕ in the paper). - * - * @param domain_separator separates the same type of data coming from difference instances by instance - * index - */ - void send_accumulator(std::shared_ptr, const std::string& domain_separator); - /** * @brief For each instance produced by a circuit, prior to folding, we need to complete the computation of its * prover polynomials, commit to witnesses and generate the relation parameters as well as send the public data ϕ of @@ -465,9 +458,31 @@ template class ProtoGalaxyProver_ { FF& challenge, const FF& compressed_perturbator); + /** + * @brief Finalise the prover instances that will be folded: complete computation of all the witness polynomials and + * compute commitments. Send commitments to the verifier and retrieve challenges. + * + */ void preparation_round(); + + /** + * @brief Compute perturbator (F polynomial in paper). Send all but the constant coefficient to verifier. + * + */ void perturbator_round(); + + /** + * @brief Compute combiner (G polynomial in the paper) and then its quotient (K polynomial), whose coefficient will + * be sent to the verifier. + * + */ void combiner_quotient_round(); + + /** + * @brief Compute the next prover accumulator (ω* in the paper), encapsulated in a ProverInstance with folding + * parameters set. + * + */ void accumulator_update_round(); }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index bdcfa0500e9..b56f3da6344 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -2,65 +2,6 @@ #include "barretenberg/proof_system/library/grand_product_delta.hpp" namespace bb { -template -void ProtoGalaxyVerifier_::receive_accumulator(const std::shared_ptr& inst, - const std::string& domain_separator) -{ - // Get circuit parameters - inst->instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); - inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); - inst->public_input_size = - transcript->template receive_from_prover(domain_separator + "_public_input_size"); - - // Get folded public inputs - for (size_t i = 0; i < inst->public_input_size; ++i) { - auto public_input_i = - transcript->template receive_from_prover(domain_separator + "_public_input_" + std::to_string(i)); - inst->public_inputs.emplace_back(public_input_i); - } - - // Get folded relation parameters - auto eta = transcript->template receive_from_prover(domain_separator + "_eta"); - auto beta = transcript->template receive_from_prover(domain_separator + "_beta"); - auto gamma = transcript->template receive_from_prover(domain_separator + "_gamma"); - auto public_input_delta = transcript->template receive_from_prover(domain_separator + "_public_input_delta"); - auto lookup_grand_product_delta = - transcript->template receive_from_prover(domain_separator + "_lookup_grand_product_delta"); - inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; - - // Get the folded relation separator challenges \vec{α} - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - inst->alphas[idx] = - transcript->template receive_from_prover(domain_separator + "_alpha_" + std::to_string(idx)); - } - - inst->target_sum = transcript->template receive_from_prover(domain_separator + "_target_sum"); - - // Get the folded gate challenges, \vec{β} in the paper - inst->gate_challenges = std::vector(inst->log_instance_size); - for (size_t idx = 0; idx < inst->log_instance_size; idx++) { - inst->gate_challenges[idx] = - transcript->template receive_from_prover(domain_separator + "_gate_challenge_" + std::to_string(idx)); - } - - // Get the folded commitments to all witness polynomials - auto comm_view = inst->witness_commitments.get_all(); - auto witness_labels = inst->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - comm_view[idx] = - transcript->template receive_from_prover(domain_separator + "_" + witness_labels[idx]); - } - - // Get the folded commitments to selector polynomials - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = inst->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); - } -} - template void ProtoGalaxyVerifier_::receive_and_finalise_instance(const std::shared_ptr& inst, const std::string& domain_separator) @@ -135,14 +76,6 @@ void ProtoGalaxyVerifier_::receive_and_finalise_instance(cons for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { inst->alphas[idx] = transcript->template get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); } - - // Get the commitments to the selector polynomials for the given instance - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); - } } // TODO(https://github.com/AztecProtocol/barretenberg/issues/795): The rounds prior to actual verifying are common @@ -154,11 +87,7 @@ void ProtoGalaxyVerifier_::prepare_for_folding(const std::vec auto index = 0; auto inst = instances[0]; auto domain_separator = std::to_string(index); - inst->is_accumulator = transcript->template receive_from_prover(domain_separator + "is_accumulator"); - if (inst->is_accumulator) { - receive_accumulator(inst, domain_separator); - } else { - // This is the first round of folding and we need to generate some gate challenges. + if (!inst->is_accumulator) { receive_and_finalise_instance(inst, domain_separator); inst->target_sum = 0; inst->gate_challenges = std::vector(inst->log_instance_size, 0); @@ -173,7 +102,8 @@ void ProtoGalaxyVerifier_::prepare_for_folding(const std::vec } template -bool ProtoGalaxyVerifier_::verify_folding_proof(const std::vector& fold_data) +std::shared_ptr ProtoGalaxyVerifier_::verify_folding_proof( + const std::vector& fold_data) { prepare_for_folding(fold_data); @@ -183,16 +113,13 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(const std::ve std::vector perturbator_coeffs(accumulator->log_instance_size + 1, 0); if (accumulator->is_accumulator) { - for (size_t idx = 0; idx <= accumulator->log_instance_size; idx++) { + for (size_t idx = 1; idx <= accumulator->log_instance_size; idx++) { perturbator_coeffs[idx] = transcript->template receive_from_prover("perturbator_" + std::to_string(idx)); } } - if (perturbator_coeffs[0] != accumulator->target_sum) { - return false; - } - + perturbator_coeffs[0] = accumulator->target_sum; auto perturbator = Polynomial(perturbator_coeffs); FF perturbator_challenge = transcript->template get_challenge("perturbator_challenge"); auto perturbator_at_challenge = perturbator.evaluate(perturbator_challenge); @@ -211,60 +138,55 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(const std::ve auto vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)); auto lagranges = std::vector{ FF(1) - combiner_challenge, combiner_challenge }; - // Compute next folding parameters and verify against the ones received from the prover - auto expected_next_target_sum = + auto next_accumulator = std::make_shared(); + next_accumulator->instance_size = accumulator->instance_size; + next_accumulator->log_instance_size = accumulator->log_instance_size; + next_accumulator->is_accumulator = true; + // Compute next folding parameters + next_accumulator->target_sum = perturbator_at_challenge * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; - auto next_target_sum = transcript->template receive_from_prover("next_target_sum"); - bool verified = (expected_next_target_sum == next_target_sum); - auto expected_betas_star = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); - for (size_t idx = 0; idx < accumulator->log_instance_size; idx++) { - auto beta_star = transcript->template receive_from_prover("next_gate_challenge_" + std::to_string(idx)); - verified = verified & (expected_betas_star[idx] == beta_star); - } + next_accumulator->gate_challenges = + update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); - // Compute ϕ and verify against the data received from the prover - WitnessCommitments acc_witness_commitments; - auto witness_labels = commitment_labels.get_witness(); + // Compute ϕ + auto& acc_witness_commitments = next_accumulator->witness_commitments; size_t comm_idx = 0; - for (auto& expected_comm : acc_witness_commitments.get_all()) { - expected_comm = Commitment::infinity(); + for (auto& comm : acc_witness_commitments.get_all()) { + comm = Commitment::infinity(); size_t inst = 0; for (auto& instance : instances) { - expected_comm = expected_comm + instance->witness_commitments.get_all()[comm_idx] * lagranges[inst]; + comm = comm + instance->witness_commitments.get_all()[comm_idx] * lagranges[inst]; inst++; } - auto comm = transcript->template receive_from_prover("next_" + witness_labels[comm_idx]); - verified = verified & (comm == expected_comm); comm_idx++; } - std::vector folded_public_inputs(instances[0]->public_inputs.size(), 0); - size_t el_idx = 0; - for (auto& expected_el : folded_public_inputs) { + next_accumulator->public_input_size = instances[0]->public_input_size; + next_accumulator->public_inputs = std::vector(next_accumulator->public_input_size, 0); + size_t public_input_idx = 0; + for (auto& public_input : next_accumulator->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]; + if (instance->public_inputs.size() >= next_accumulator->public_input_size) { + public_input += instance->public_inputs[public_input_idx] * lagranges[inst]; inst++; - }; + } } - auto el = transcript->template receive_from_prover("next_public_input" + std::to_string(el_idx)); - verified = verified & (el == expected_el); - el_idx++; + public_input_idx++; } - for (size_t alpha_idx = 0; alpha_idx < NUM_SUBRELATIONS - 1; alpha_idx++) { - FF alpha(0); + size_t alpha_idx = 0; + for (auto& alpha : next_accumulator->alphas) { + alpha = FF(0); size_t instance_idx = 0; for (auto& instance : instances) { alpha += instance->alphas[alpha_idx] * lagranges[instance_idx]; instance_idx++; } - auto next_alpha = transcript->template receive_from_prover("next_alpha_" + std::to_string(alpha_idx)); - verified = verified & (alpha == next_alpha); + alpha_idx++; } - auto expected_parameters = bb::RelationParameters{}; + auto& expected_parameters = next_accumulator->relation_parameters; for (size_t inst_idx = 0; inst_idx < VerifierInstances::NUM; inst_idx++) { auto instance = instances[inst_idx]; expected_parameters.eta += instance->relation_parameters.eta * lagranges[inst_idx]; @@ -276,38 +198,20 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(const std::ve instance->relation_parameters.lookup_grand_product_delta * lagranges[inst_idx]; } - auto next_eta = transcript->template receive_from_prover("next_eta"); - verified = verified & (next_eta == expected_parameters.eta); - - auto next_beta = transcript->template receive_from_prover("next_beta"); - verified = verified & (next_beta == expected_parameters.beta); - - auto next_gamma = transcript->template receive_from_prover("next_gamma"); - verified = verified & (next_gamma == expected_parameters.gamma); - - auto next_public_input_delta = transcript->template receive_from_prover("next_public_input_delta"); - verified = verified & (next_public_input_delta == expected_parameters.public_input_delta); - - auto next_lookup_grand_product_delta = - transcript->template receive_from_prover("next_lookup_grand_product_delta"); - verified = verified & (next_lookup_grand_product_delta == expected_parameters.lookup_grand_product_delta); - - auto acc_vk = std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); - auto vk_labels = commitment_labels.get_precomputed(); + next_accumulator->verification_key = + std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); size_t vk_idx = 0; - for (auto& expected_vk : acc_vk->get_all()) { + for (auto& expected_vk : next_accumulator->verification_key->get_all()) { size_t inst = 0; expected_vk = Commitment::infinity(); for (auto& instance : instances) { expected_vk = expected_vk + instance->verification_key->get_all()[vk_idx] * lagranges[inst]; inst++; } - auto vk = transcript->template receive_from_prover("next_" + vk_labels[vk_idx]); - verified = verified & (vk == expected_vk); vk_idx++; } - return verified; + return next_accumulator; } template class ProtoGalaxyVerifier_>; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp index 5743a888a0f..9a39986fe4b 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp @@ -27,8 +27,8 @@ template class ProtoGalaxyVerifier_ { CommitmentLabels commitment_labels; - ProtoGalaxyVerifier_(VerifierInstances insts) - : instances(insts){}; + ProtoGalaxyVerifier_(const std::vector>& insts) + : instances(VerifierInstances(insts)){}; ~ProtoGalaxyVerifier_() = default; /** * @brief Given a new round challenge δ for each iteration of the full ProtoGalaxy protocol, compute the vector @@ -66,12 +66,6 @@ template class ProtoGalaxyVerifier_ { */ void prepare_for_folding(const std::vector&); - /** - * @brief Instantiatied the accumulator (i.e. the relaxed instance) from the transcript. - * - */ - void receive_accumulator(const std::shared_ptr&, const std::string&); - /** * @brief Process the public data ϕ for the Instances to be folded. * @@ -83,7 +77,7 @@ template class ProtoGalaxyVerifier_ { * accumulator, received from the prover is the same as that produced by the verifier. * */ - bool verify_folding_proof(const std::vector&); + std::shared_ptr verify_folding_proof(const std::vector&); }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp index 0ece406ee75..dffe20412d7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp @@ -1,16 +1,10 @@ #include "barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" -#include "barretenberg/sumcheck/instance/verifier_instance.hpp" #include "barretenberg/transcript/transcript.hpp" namespace bb::stdlib::recursion::honk { -template -DeciderRecursiveVerifier_::DeciderRecursiveVerifier_(Builder* builder) - : builder(builder) -{} - /** * @brief This function verifies an Ultra Honk proof for a given Flavor, produced for a relaxed instance (ϕ, \vec{β*}, * e*). @@ -24,60 +18,16 @@ std::array DeciderRecursiveVerifier_:: using ZeroMorph = ::bb::ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using Transcript = typename Flavor::Transcript; - using Instance = VerifierInstance_; - static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; StdlibProof stdlib_proof = bb::convert_proof_to_witness(builder, proof); transcript = std::make_shared(stdlib_proof); - auto inst = std::make_unique(); - - const auto instance_size = transcript->template receive_from_prover("instance_size"); - const auto public_input_size = transcript->template receive_from_prover("public_input_size"); - const auto log_instance_size = static_cast(numeric::get_msb(uint32_t(instance_size.get_value()))); - - for (size_t i = 0; i < uint32_t(public_input_size.get_value()); ++i) { - auto public_input_i = transcript->template receive_from_prover("public_input_" + std::to_string(i)); - inst->public_inputs.emplace_back(public_input_i); - } - - auto eta = transcript->template receive_from_prover("eta"); - auto beta = transcript->template receive_from_prover("beta"); - auto gamma = transcript->template receive_from_prover("gamma"); - auto public_input_delta = transcript->template receive_from_prover("public_input_delta"); - auto lookup_grand_product_delta = transcript->template receive_from_prover("lookup_grand_product_delta"); - inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; - - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - inst->alphas[idx] = transcript->template receive_from_prover("alpha" + std::to_string(idx)); - } - - inst->target_sum = transcript->template receive_from_prover("target_sum"); - - inst->gate_challenges = std::vector(log_instance_size); - for (size_t idx = 0; idx < log_instance_size; idx++) { - inst->gate_challenges[idx] = - transcript->template receive_from_prover("gate_challenge_" + std::to_string(idx)); - } - auto comm_view = inst->witness_commitments.get_all(); - auto witness_labels = inst->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - comm_view[idx] = transcript->template receive_from_prover(witness_labels[idx]); - } - - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = inst->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(vk_labels[idx]); - } - VerifierCommitments commitments{ inst->verification_key, inst->witness_commitments }; + VerifierCommitments commitments{ accumulator->verification_key, accumulator->witness_commitments }; - auto sumcheck = Sumcheck(log_instance_size, transcript, inst->target_sum); + auto sumcheck = Sumcheck(accumulator->log_instance_size, transcript, accumulator->target_sum); auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = - sumcheck.verify(inst->relation_parameters, inst->alphas, inst->gate_challenges); + sumcheck.verify(accumulator->relation_parameters, accumulator->alphas, accumulator->gate_challenges); // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the // unrolled protocol. @@ -91,6 +41,6 @@ std::array DeciderRecursiveVerifier_:: return pairing_points; } -template class DeciderRecursiveVerifier_>; +template class DeciderRecursiveVerifier_>; template class DeciderRecursiveVerifier_>; } // namespace bb::stdlib::recursion::honk diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp index 61f9a481420..829f47e99a5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp @@ -3,9 +3,11 @@ #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" namespace bb::stdlib::recursion::honk { template class DeciderRecursiveVerifier_ { + using NativeFlavor = typename Flavor::NativeFlavor; using FF = typename Flavor::FF; using Commitment = typename Flavor::Commitment; using GroupElement = typename Flavor::GroupElement; @@ -14,16 +16,21 @@ template class DeciderRecursiveVerifier_ { using Builder = typename Flavor::CircuitBuilder; using RelationSeparator = typename Flavor::RelationSeparator; using PairingPoints = std::array; + using Instance = RecursiveVerifierInstance_; + using NativeInstance = bb::VerifierInstance_; using Transcript = bb::BaseTranscript>; public: - explicit DeciderRecursiveVerifier_(Builder* builder); + explicit DeciderRecursiveVerifier_(Builder* builder, std::shared_ptr accumulator) + : builder(builder) + , accumulator(std::make_shared(builder, accumulator)){}; PairingPoints verify_proof(const HonkProof& proof); std::map commitments; std::shared_ptr pcs_verification_key; Builder* builder; + std::shared_ptr accumulator; std::shared_ptr transcript; }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index 9052d25c071..1a37b1fa092 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -148,21 +148,21 @@ template class GoblinRecursiveVerifierTest : public testi // Compute native verification key InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); auto prover = inner_composer.create_prover(instance); // A prerequisite for computing VK - + auto verification_key = instance->verification_key; // Instantiate the recursive verifier using the native verification key - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; // Spot check some values in the recursive VK to ensure it was constructed correctly - EXPECT_EQ(verifier.key->circuit_size, instance->verification_key->circuit_size); - EXPECT_EQ(verifier.key->log_circuit_size, instance->verification_key->log_circuit_size); - EXPECT_EQ(verifier.key->num_public_inputs, instance->verification_key->num_public_inputs); - EXPECT_EQ(verifier.key->q_m.get_value(), instance->verification_key->q_m); - EXPECT_EQ(verifier.key->q_r.get_value(), instance->verification_key->q_r); - EXPECT_EQ(verifier.key->sigma_1.get_value(), instance->verification_key->sigma_1); - EXPECT_EQ(verifier.key->id_3.get_value(), instance->verification_key->id_3); - EXPECT_EQ(verifier.key->lagrange_ecc_op.get_value(), instance->verification_key->lagrange_ecc_op); + EXPECT_EQ(verifier.key->circuit_size, verification_key->circuit_size); + EXPECT_EQ(verifier.key->log_circuit_size, verification_key->log_circuit_size); + EXPECT_EQ(verifier.key->num_public_inputs, verification_key->num_public_inputs); + EXPECT_EQ(verifier.key->q_m.get_value(), verification_key->q_m); + EXPECT_EQ(verifier.key->q_r.get_value(), verification_key->q_r); + EXPECT_EQ(verifier.key->sigma_1.get_value(), verification_key->sigma_1); + EXPECT_EQ(verifier.key->id_3.get_value(), verification_key->id_3); + EXPECT_EQ(verifier.key->lagrange_ecc_op.get_value(), verification_key->lagrange_ecc_op); } /** @@ -176,7 +176,7 @@ template class GoblinRecursiveVerifierTest : public testi // Generate a proof over the inner circuit InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); @@ -191,7 +191,7 @@ template class GoblinRecursiveVerifierTest : public testi // Check 1: Perform native verification then perform the pairing on the outputs of the recursive // verifier and check that the result agrees. - auto native_verifier = inner_composer.create_verifier(instance); + auto native_verifier = inner_composer.create_verifier(instance->verification_key); auto native_result = native_verifier.verify_proof(inner_proof); auto recursive_result = native_verifier.pcs_verification_key->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); @@ -208,9 +208,9 @@ template class GoblinRecursiveVerifierTest : public testi // Check 3: Construct and verify a proof of the recursive verifier circuit { auto composer = get_outer_composer(); - auto instance = composer.create_instance(outer_circuit); + auto instance = composer.create_prover_instance(outer_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -231,7 +231,7 @@ template class GoblinRecursiveVerifierTest : public testi // Generate a proof over the inner circuit InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp index bd227b91a67..cd603ed1c85 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp @@ -82,9 +82,9 @@ class RecursiveMergeVerifierTest : public testing::Test { // Check 3: Construct and verify a (goblin) ultra honk proof of the Merge recursive verifier circuit { GoblinUltraComposer composer; - auto instance = composer.create_instance(outer_circuit); + auto instance = composer.create_prover_instance(outer_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp index 6ac10f7cd30..8063c369db3 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp @@ -1,69 +1,9 @@ #include "protogalaxy_recursive_verifier.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/library/grand_product_delta.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp" namespace bb::stdlib::recursion::honk { -template -void ProtoGalaxyRecursiveVerifier_::receive_accumulator(const std::shared_ptr& inst, - const std::string& domain_separator) -{ - // Get circuit parameters - const auto instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); - const auto public_input_size = - transcript->template receive_from_prover(domain_separator + "_public_input_size"); - inst->instance_size = uint32_t(instance_size.get_value()); - inst->log_instance_size = uint32_t(numeric::get_msb(inst->instance_size)); - inst->public_input_size = uint32_t(public_input_size.get_value()); - - // Get folded public inputs - for (size_t i = 0; i < inst->public_input_size; ++i) { - auto public_input_i = - transcript->template receive_from_prover(domain_separator + "_public_input_" + std::to_string(i)); - inst->public_inputs.emplace_back(public_input_i); - } - - // Get folded relation parameters - auto eta = transcript->template receive_from_prover(domain_separator + "_eta"); - auto beta = transcript->template receive_from_prover(domain_separator + "_beta"); - auto gamma = transcript->template receive_from_prover(domain_separator + "_gamma"); - auto public_input_delta = transcript->template receive_from_prover(domain_separator + "_public_input_delta"); - auto lookup_grand_product_delta = - transcript->template receive_from_prover(domain_separator + "_lookup_grand_product_delta"); - inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; - - // Get the folded relation separator challenges \vec{α} - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - inst->alphas[idx] = - transcript->template receive_from_prover(domain_separator + "_alpha_" + std::to_string(idx)); - } - - inst->target_sum = transcript->template receive_from_prover(domain_separator + "_target_sum"); - - // Get the folded gate challenges, \vec{β} in the paper - inst->gate_challenges = std::vector(inst->log_instance_size); - for (size_t idx = 0; idx < inst->log_instance_size; idx++) { - inst->gate_challenges[idx] = - transcript->template receive_from_prover(domain_separator + "_gate_challenge_" + std::to_string(idx)); - } - - // Get the folded commitments to all witness polynomials - auto comm_view = inst->witness_commitments.get_all(); - auto witness_labels = inst->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - comm_view[idx] = - transcript->template receive_from_prover(domain_separator + "_" + witness_labels[idx]); - } - - // Get the folded commitments to selector polynomials - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = inst->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); - } -} - template void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_instance( const std::shared_ptr& inst, const std::string& domain_separator) @@ -141,14 +81,6 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { inst->alphas[idx] = transcript->template get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); } - - // Get the commitments to the selector polynomials for the given instance - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); - } } // TODO(https://github.com/AztecProtocol/barretenberg/issues/795): The rounds prior to actual verifying are common @@ -158,12 +90,8 @@ template void ProtoGalaxyRecursiveVerifier_template receive_from_prover(domain_separator + "is_accumulator"); - inst->is_accumulator = static_cast(is_accumulator.get_value()); - if (inst->is_accumulator) { - receive_accumulator(inst, domain_separator); - } else { - // This is the first round of folding and we need to generate some gate challenges. + + if (!inst->is_accumulator) { receive_and_finalise_instance(inst, domain_separator); inst->target_sum = 0; inst->gate_challenges = std::vector(inst->log_instance_size, 0); @@ -178,10 +106,10 @@ template void ProtoGalaxyRecursiveVerifier_ -void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(const HonkProof& proof) +std::shared_ptr ProtoGalaxyRecursiveVerifier_< + VerifierInstances>::verify_folding_proof(const HonkProof& proof) { using Transcript = typename Flavor::Transcript; - using ScalarNative = typename Flavor::Curve::ScalarFieldNative; StdlibProof stdlib_proof = bb::convert_proof_to_witness(builder, proof); transcript = std::make_shared(stdlib_proof); @@ -193,17 +121,13 @@ void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(cons std::vector perturbator_coeffs(accumulator->log_instance_size + 1, 0); if (accumulator->is_accumulator) { - for (size_t idx = 0; idx <= accumulator->log_instance_size; idx++) { + for (size_t idx = 1; idx <= accumulator->log_instance_size; idx++) { perturbator_coeffs[idx] = transcript->template receive_from_prover("perturbator_" + std::to_string(idx)); } } - // TODO(https://github.com/AztecProtocol/barretenberg/issues/833): As currently the stdlib transcript is not - // creating proper constraints linked to Fiat-Shamir we add an additonal gate to ensure assert_equal is correct. - // This comparison to 0 can be removed here and below once we have merged the transcript. - auto zero = FF::from_witness(builder, ScalarNative(0)); - zero.assert_equal(accumulator->target_sum - perturbator_coeffs[0], "F(0) != e"); + perturbator_coeffs[0] = accumulator->target_sum; FF perturbator_challenge = transcript->template get_challenge("perturbator_challenge"); @@ -222,24 +146,21 @@ void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(cons auto vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)); auto lagranges = std::vector{ FF(1) - combiner_challenge, combiner_challenge }; + auto next_accumulator = std::make_shared(builder); + next_accumulator->instance_size = accumulator->instance_size; + next_accumulator->log_instance_size = accumulator->log_instance_size; + next_accumulator->is_accumulator = true; + // Compute next folding parameters and verify against the ones received from the prover - auto expected_next_target_sum = + next_accumulator->target_sum = perturbator_at_challenge * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; - auto next_target_sum = transcript->template receive_from_prover("next_target_sum"); - zero.assert_equal(expected_next_target_sum - next_target_sum, "next target sum mismatch"); - - auto expected_betas_star = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); - for (size_t idx = 0; idx < accumulator->log_instance_size; idx++) { - auto beta_star = transcript->template receive_from_prover("next_gate_challenge_" + std::to_string(idx)); - zero.assert_equal(beta_star - expected_betas_star[idx], - " next gate challenge mismatch at: " + std::to_string(idx)); - } + next_accumulator->gate_challenges = + update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); // Compute ϕ and verify against the data received from the prover - WitnessCommitments acc_witness_commitments; - auto witness_labels = commitment_labels.get_witness(); + auto& acc_witness_commitments = next_accumulator->witness_commitments; size_t comm_idx = 0; - for (auto& expected_comm : acc_witness_commitments.get_all()) { + for (auto& comm : acc_witness_commitments.get_all()) { std::vector scalars; std::vector commitments; size_t inst = 0; @@ -248,41 +169,36 @@ void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(cons commitments.emplace_back(instance->witness_commitments.get_all()[comm_idx]); inst++; } - expected_comm = Commitment::batch_mul(commitments, scalars); - auto comm = transcript->template receive_from_prover("next_" + witness_labels[comm_idx]); - comm.x.assert_equal(expected_comm.x); - comm.y.assert_equal(expected_comm.y); + comm = Commitment::batch_mul(commitments, scalars); comm_idx++; } - std::vector folded_public_inputs(instances[0]->public_inputs.size(), 0); + next_accumulator->public_input_size = instances[0]->public_input_size; + next_accumulator->public_inputs = std::vector(next_accumulator->public_input_size, 0); size_t public_input_idx = 0; - for (auto& expected_public_input : folded_public_inputs) { + for (auto& public_input : next_accumulator->public_inputs) { size_t inst = 0; for (auto& instance : instances) { - expected_public_input += instance->public_inputs[public_input_idx] * lagranges[inst]; - inst++; + if (instance->public_inputs.size() >= next_accumulator->public_inputs.size()) { + public_input += instance->public_inputs[public_input_idx] * lagranges[inst]; + inst++; + }; } - auto next_public_input = - transcript->template receive_from_prover("next_public_input" + std::to_string(public_input_idx)); - zero.assert_equal(expected_public_input - next_public_input, - "folded public input mismatch at: " + std::to_string(public_input_idx)); public_input_idx++; } - for (size_t alpha_idx = 0; alpha_idx < NUM_SUBRELATIONS - 1; alpha_idx++) { - FF expected_alpha(0); + size_t alpha_idx = 0; + for (auto& alpha : next_accumulator->alphas) { + alpha = FF(0); size_t instance_idx = 0; for (auto& instance : instances) { - expected_alpha += instance->alphas[alpha_idx] * lagranges[instance_idx]; + alpha += instance->alphas[alpha_idx] * lagranges[instance_idx]; instance_idx++; } - auto next_alpha = transcript->template receive_from_prover("next_alpha_" + std::to_string(alpha_idx)); - zero.assert_equal(expected_alpha - next_alpha, - "folded relation separator mismatch at: " + std::to_string(alpha_idx)); + alpha_idx++; } - auto expected_parameters = bb::RelationParameters{}; + auto& expected_parameters = next_accumulator->relation_parameters; for (size_t inst_idx = 0; inst_idx < VerifierInstances::NUM; inst_idx++) { auto instance = instances[inst_idx]; expected_parameters.eta += instance->relation_parameters.eta * lagranges[inst_idx]; @@ -294,28 +210,10 @@ void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(cons instance->relation_parameters.lookup_grand_product_delta * lagranges[inst_idx]; } - auto next_eta = transcript->template receive_from_prover("next_eta"); - zero.assert_equal(expected_parameters.eta - next_eta, "relation parameter eta mismatch"); - - auto next_beta = transcript->template receive_from_prover("next_beta"); - zero.assert_equal(expected_parameters.beta - next_beta, "relation parameter beta mismatch"); - - auto next_gamma = transcript->template receive_from_prover("next_gamma"); - zero.assert_equal(expected_parameters.gamma - next_gamma, "relation parameter gamma mismatch"); - - auto next_public_input_delta = transcript->template receive_from_prover("next_public_input_delta"); - zero.assert_equal(expected_parameters.public_input_delta - next_public_input_delta, - "relation parameter public input delta mismatch"); - - auto next_lookup_grand_product_delta = - transcript->template receive_from_prover("next_lookup_grand_product_delta"); - zero.assert_equal(expected_parameters.lookup_grand_product_delta - next_lookup_grand_product_delta, - "relation parameter lookup grand product delta mismatch"); - - auto acc_vk = std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); - auto vk_labels = commitment_labels.get_precomputed(); + next_accumulator->verification_key = + std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); size_t vk_idx = 0; - for (auto& expected_vk : acc_vk->get_all()) { + for (auto& expected_vk : next_accumulator->verification_key->get_all()) { size_t inst = 0; std::vector scalars; std::vector commitments; @@ -325,14 +223,13 @@ void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(cons inst++; } expected_vk = Commitment::batch_mul(commitments, scalars); - auto vk = transcript->template receive_from_prover("next_" + vk_labels[vk_idx]); - vk.x.assert_equal(expected_vk.x); - vk.y.assert_equal(expected_vk.y); vk_idx++; } + return next_accumulator; } -template class ProtoGalaxyRecursiveVerifier_, 2>>; template class ProtoGalaxyRecursiveVerifier_< - VerifierInstances_, 2>>; + RecursiveVerifierInstances_, 2>>; +template class ProtoGalaxyRecursiveVerifier_< + RecursiveVerifierInstances_, 2>>; } // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp index 9bcc8a9c238..081b1361765 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp @@ -5,36 +5,42 @@ #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/protogalaxy/folding_result.hpp" #include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" -#include "barretenberg/sumcheck/instance/instances.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp" namespace bb::stdlib::recursion::honk { template class ProtoGalaxyRecursiveVerifier_ { public: using Flavor = typename VerifierInstances::Flavor; + using NativeFlavor = typename Flavor::NativeFlavor; using FF = typename Flavor::FF; using Commitment = typename Flavor::Commitment; using GroupElement = typename Flavor::GroupElement; using Instance = typename VerifierInstances::Instance; + using NativeInstance = bb::VerifierInstance_; using VerificationKey = typename Flavor::VerificationKey; + using NativeVerificationKey = typename Flavor::NativeVerificationKey; using WitnessCommitments = typename Flavor::WitnessCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; using Builder = typename Flavor::CircuitBuilder; using RelationSeparator = typename Flavor::RelationSeparator; using PairingPoints = std::array; + static constexpr size_t NUM = VerifierInstances::NUM; using Transcript = bb::BaseTranscript>; static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; - VerifierInstances instances; - CommitmentLabels commitment_labels; Builder* builder; std::shared_ptr transcript; + VerifierInstances instances; + + ProtoGalaxyRecursiveVerifier_(Builder* builder, + std::shared_ptr& accumulator, + const std::vector>& native_inst_vks) + : builder(builder) + , instances(VerifierInstances(builder, accumulator, native_inst_vks)){}; - explicit ProtoGalaxyRecursiveVerifier_(Builder* builder) - : instances(VerifierInstances()) - , builder(builder){}; /** * @brief Given a new round challenge δ for each iteration of the full ProtoGalaxy protocol, compute the vector * [δ, δ^2,..., δ^t] where t = logn and n is the size of the instance. @@ -92,7 +98,7 @@ template class ProtoGalaxyRecursiveVerifier_ { * by the prover, are expressed as constraints. */ - void verify_folding_proof(const HonkProof& proof); + std::shared_ptr verify_folding_proof(const HonkProof&); /** * @brief Evaluates the perturbator at a given scalar, in a sequential manner for the recursive setting. diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp index 0912edf91ce..6e2f1f5f3ce 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -10,41 +10,24 @@ namespace bb::stdlib::recursion::honk { template class ProtoGalaxyRecursiveTests : public testing::Test { public: - // Define types relevant for testing - using UltraComposer = ::bb::UltraComposer_; - using GoblinUltraComposer = ::bb::UltraComposer_; - - using InnerFlavor = typename RecursiveFlavor::NativeFlavor; - using InnerComposer = ::bb::UltraComposer_; - using Instance = ::bb::ProverInstance_; - using InnerBuilder = typename InnerComposer::CircuitBuilder; - using InnerCurve = bn254; - using Commitment = typename InnerFlavor::Commitment; - using FF = typename InnerFlavor::FF; - - // Types for veryfing a recursive verifier circuit - using OuterBuilder = GoblinUltraCircuitBuilder; - using OuterComposer = GoblinUltraComposer; - - using RecursiveVerifierInstances = ::bb::VerifierInstances_; + using NativeFlavor = typename RecursiveFlavor::NativeFlavor; + using Composer = ::bb::UltraComposer_; + using Builder = typename RecursiveFlavor::CircuitBuilder; + using ProverInstance = ::bb::ProverInstance_; + using VerifierInstance = ::bb::VerifierInstance_; + using RecursiveVerifierInstance = ::bb::stdlib::recursion::honk::RecursiveVerifierInstance_; + using Curve = bn254; + using Commitment = typename NativeFlavor::Commitment; + using FF = typename NativeFlavor::FF; + + using RecursiveVerifierInstances = ::bb::stdlib::recursion::honk::RecursiveVerifierInstances_; using FoldingRecursiveVerifier = ProtoGalaxyRecursiveVerifier_; using DeciderRecursiveVerifier = DeciderRecursiveVerifier_; - using DeciderVerifier = DeciderVerifier_; - using NativeVerifierInstances = VerifierInstances_; + using DeciderVerifier = DeciderVerifier_; + using NativeVerifierInstances = VerifierInstances_; using NativeFoldingVerifier = ProtoGalaxyVerifier_; static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } - - // Helper for getting composer for prover/verifier of recursive (outer) circuit - template static auto get_outer_composer() - { - if constexpr (IsGoblinBuilder) { - return GoblinUltraComposer(); - } else { - return UltraComposer(); - } - } - /** * @brief Create a non-trivial arbitrary inner circuit, the proof of which will be recursively verified * @@ -55,15 +38,15 @@ template class ProtoGalaxyRecursiveTests : public tes * TODO(https://github.com/AztecProtocol/barretenberg/issues/744): make testing utility with functionality shared * amongst test files */ - static void create_inner_circuit(InnerBuilder& builder, size_t log_num_gates = 10) + static void create_function_circuit(Builder& builder, size_t log_num_gates = 10) { - using fr_ct = typename InnerCurve::ScalarField; - using fq_ct = typename InnerCurve::BaseField; - using public_witness_ct = typename InnerCurve::public_witness_ct; - using witness_ct = typename InnerCurve::witness_ct; - using byte_array_ct = typename InnerCurve::byte_array_ct; - using fr = typename InnerCurve::ScalarFieldNative; - using point = typename InnerCurve::AffineElementNative; + using fr_ct = typename Curve::ScalarField; + using fq_ct = typename Curve::BaseField; + using public_witness_ct = typename Curve::public_witness_ct; + using witness_ct = typename Curve::witness_ct; + using byte_array_ct = typename Curve::byte_array_ct; + using fr = typename Curve::ScalarFieldNative; + using point = typename Curve::AffineElementNative; // Create 2^log_n many add gates based on input log num gates const size_t num_gates = 1 << log_num_gates; @@ -90,7 +73,7 @@ template class ProtoGalaxyRecursiveTests : public tes a = (a * b) + b + a; a = a.madd(b, c); } - pedersen_hash::hash({ a, b }); + pedersen_hash::hash({ a, b }); byte_array_ct to_hash(&builder, "nonsense test data"); blake3s(to_hash); @@ -103,7 +86,7 @@ template class ProtoGalaxyRecursiveTests : public tes big_a* big_b; - if constexpr (IsGoblinBuilder) { + if constexpr (IsGoblinBuilder) { auto p = point::one() * fr::random_element(); auto scalar = fr::random_element(); builder.queue_ecc_mul_accum(p, scalar); @@ -111,27 +94,35 @@ template class ProtoGalaxyRecursiveTests : public tes } }; - static std::shared_ptr fold_and_verify_native(const std::vector>& instances, - InnerComposer& composer) + static std::tuple, std::shared_ptr> fold_and_verify_native( + Composer& composer) { - auto folding_prover = composer.create_folding_prover(instances); - auto folding_verifier = composer.create_folding_verifier(); - - auto proof = folding_prover.fold_instances(); - auto next_accumulator = proof.accumulator; - auto res = folding_verifier.verify_folding_proof(proof.folding_data); - EXPECT_EQ(res, true); - return next_accumulator; + Builder builder1; + create_function_circuit(builder1); + Builder builder2; + builder2.add_public_variable(FF(1)); + create_function_circuit(builder2); + + auto prover_instance_1 = composer.create_prover_instance(builder1); + auto prover_instance_2 = composer.create_prover_instance(builder2); + auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); + auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + auto folding_prover = composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); + auto folding_verifier = composer.create_folding_verifier({ verifier_instance_1, verifier_instance_2 }); + + auto [prover_accumulator, folding_proof] = folding_prover.fold_instances(); + auto verifier_accumulator = folding_verifier.verify_folding_proof(folding_proof); + return { prover_accumulator, verifier_accumulator }; } /** *@brief Create inner circuit and call check_circuit on it */ - static void test_inner_circuit() + static void test_circuit() { - InnerBuilder builder; + Builder builder; - create_inner_circuit(builder); + create_function_circuit(builder); bool result = builder.check_circuit(); EXPECT_EQ(result, true); @@ -144,9 +135,9 @@ template class ProtoGalaxyRecursiveTests : public tes */ static void test_new_evaluate() { - OuterBuilder builder; - using fr_ct = bn254::ScalarField; - using fr = bn254::ScalarFieldNative; + Builder builder; + using fr_ct = typename bn254::ScalarField; + using fr = typename bn254::ScalarFieldNative; std::vector coeffs; std::vector coeffs_ct; @@ -165,39 +156,39 @@ template class ProtoGalaxyRecursiveTests : public tes }; /** - * @brief Tests a simple recursive fold that is valid works as expected. + * @brief Tests that a valid recursive fold works as expected. * */ static void test_recursive_folding() { // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; - - create_inner_circuit(builder1); - InnerBuilder builder2; + Builder builder1; + create_function_circuit(builder1); + Builder builder2; builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); - - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; + create_function_circuit(builder2); + Composer composer = Composer(); + auto prover_instance_1 = composer.create_prover_instance(builder1); + auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); + auto prover_instance_2 = composer.create_prover_instance(builder2); + auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); // Generate a folding proof - auto inner_folding_prover = inner_composer.create_folding_prover(instances); - auto inner_folding_proof = inner_folding_prover.fold_instances(); + auto folding_prover = composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); + auto folding_proof = folding_prover.fold_instances(); // Create a recursive folding verifier circuit for the folding proof of the two instances - OuterBuilder outer_folding_circuit; - FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; - verifier.verify_folding_proof(inner_folding_proof.folding_data); - info("Folding Recursive Verifier: num gates = ", outer_folding_circuit.num_gates); - - // Perform native folding verification and ensure it returns the same result (either true or false) as calling - // check_circuit on the recursive folding verifier - auto native_folding_verifier = inner_composer.create_folding_verifier(); - auto native_folding_result = native_folding_verifier.verify_folding_proof(inner_folding_proof.folding_data); - EXPECT_EQ(native_folding_result, !outer_folding_circuit.failed()); + Builder folding_circuit; + auto verifier = + FoldingRecursiveVerifier(&folding_circuit, verifier_instance_1, { verifier_instance_2->verification_key }); + verifier.verify_folding_proof(folding_proof.folding_data); + info("Folding Recursive Verifier: num gates = ", folding_circuit.num_gates); + EXPECT_EQ(folding_circuit.failed(), false) << folding_circuit.err(); + + // Perform native folding verification and ensure it returns the same result (either true or false) as + // calling check_circuit on the recursive folding verifier + auto native_folding_verifier = composer.create_folding_verifier({ verifier_instance_1, verifier_instance_2 }); + native_folding_verifier.verify_folding_proof(folding_proof.folding_data); // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the // manifestsproduced by each agree. @@ -209,13 +200,12 @@ template class ProtoGalaxyRecursiveTests : public tes } // Check for a failure flag in the recursive verifier circuit - EXPECT_EQ(outer_folding_circuit.failed(), false) << outer_folding_circuit.err(); { - auto composer = OuterComposer(); - auto instance = composer.create_instance(outer_folding_circuit); + auto composer = Composer(); + auto instance = composer.create_prover_instance(folding_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -233,44 +223,61 @@ template class ProtoGalaxyRecursiveTests : public tes static void test_full_protogalaxy_recursive() { // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; - - create_inner_circuit(builder1); - InnerBuilder builder2; + Builder builder1; + create_function_circuit(builder1); + Builder builder2; builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; + create_function_circuit(builder2); - auto accumulator = fold_and_verify_native(instances, inner_composer); + Composer composer = Composer(); + auto prover_instance_1 = composer.create_prover_instance(builder1); + auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); + auto prover_instance_2 = composer.create_prover_instance(builder2); + auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + // Generate a folding proof + auto folding_prover = composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); + auto folding_proof = folding_prover.fold_instances(); - // Create another circuit to do a second round of folding - InnerBuilder builder3; - create_inner_circuit(builder3); - auto instance3 = inner_composer.create_instance(builder3); - instances = std::vector>{ accumulator, instance3 }; + // Create a recursive folding verifier circuit for the folding proof of the two instances + Builder folding_circuit; + auto verifier = + FoldingRecursiveVerifier(&folding_circuit, verifier_instance_1, { verifier_instance_2->verification_key }); + auto recursive_verifier_accumulator = verifier.verify_folding_proof(folding_proof.folding_data); + auto native_verifier_acc = std::make_shared(recursive_verifier_accumulator->get_value()); + info("Folding Recursive Verifier: num gates = ", folding_circuit.num_gates); - accumulator = fold_and_verify_native(instances, inner_composer); + // Check for a failure flag in the recursive verifier circuit + EXPECT_EQ(folding_circuit.failed(), false) << folding_circuit.err(); - // Create a decider proof for the relaxed instance obtained through folding - auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); - auto inner_decider_proof = inner_decider_prover.construct_proof(); + // Perform native folding verification and ensure it returns the same result (either true or false) as + // calling check_circuit on the recursive folding verifier + auto native_folding_verifier = composer.create_folding_verifier({ verifier_instance_1, verifier_instance_2 }); + auto verifier_accumulator = native_folding_verifier.verify_folding_proof(folding_proof.folding_data); - // Create a decider verifier circuit for recursively verifying the decider proof - OuterBuilder outer_decider_circuit; - DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; - auto pairing_points = decider_verifier.verify_proof(inner_decider_proof); - info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); + // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the + // manifestsproduced by each agree. + auto recursive_folding_manifest = verifier.transcript->get_manifest(); + auto native_folding_manifest = native_folding_verifier.transcript->get_manifest(); + + for (size_t i = 0; i < recursive_folding_manifest.size(); ++i) { + EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]); + } + + auto decider_prover = composer.create_decider_prover(folding_proof.accumulator); + auto decider_proof = decider_prover.construct_proof(); + + Builder decider_circuit; + DeciderRecursiveVerifier decider_verifier{ &decider_circuit, native_verifier_acc }; + auto pairing_points = decider_verifier.verify_proof(decider_proof); + info("Decider Recursive Verifier: num gates = ", decider_circuit.num_gates); // Check for a failure flag in the recursive verifier circuit - EXPECT_EQ(outer_decider_circuit.failed(), false) << outer_decider_circuit.err(); + EXPECT_EQ(decider_circuit.failed(), false) << decider_circuit.err(); // Perform native verification then perform the pairing on the outputs of the recursive // decider verifier and check that the result agrees. - DeciderVerifier native_decider_verifier = inner_composer.create_decider_verifier(accumulator); - auto native_result = native_decider_verifier.verify_proof(inner_decider_proof); + DeciderVerifier native_decider_verifier = composer.create_decider_verifier(verifier_accumulator); + auto native_result = native_decider_verifier.verify_proof(decider_proof); auto recursive_result = native_decider_verifier.pcs_verification_key->pairing_check( pairing_points[0].get_value(), pairing_points[1].get_value()); EXPECT_EQ(native_result, recursive_result); @@ -285,10 +292,10 @@ template class ProtoGalaxyRecursiveTests : public tes // Construct and verify a proof of the recursive decider verifier circuit { - auto composer = OuterComposer(); - auto instance = composer.create_instance(outer_decider_circuit); + auto composer = Composer(); + auto instance = composer.create_prover_instance(decider_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -298,83 +305,64 @@ template class ProtoGalaxyRecursiveTests : public tes static void test_tampered_decider_proof() { - // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; - - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); - - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; - - auto accumulator = fold_and_verify_native(instances, inner_composer); + // Natively fold two circuits + auto composer = Composer(); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify_native(composer); // Tamper with the accumulator by changing the target sum - accumulator->target_sum = FF::random_element(); + verifier_accumulator->target_sum = FF::random_element(); // Create a decider proof for the relaxed instance obtained through folding - auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); - auto inner_decider_proof = inner_decider_prover.construct_proof(); + auto decider_prover = composer.create_decider_prover(prover_accumulator); + auto decider_proof = decider_prover.construct_proof(); // Create a decider verifier circuit for recursively verifying the decider proof - OuterBuilder outer_decider_circuit; - DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; - decider_verifier.verify_proof(inner_decider_proof); - info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); + Builder decider_circuit; + DeciderRecursiveVerifier decider_verifier{ &decider_circuit, verifier_accumulator }; + decider_verifier.verify_proof(decider_proof); + info("Decider Recursive Verifier: num gates = ", decider_circuit.num_gates); // We expect the decider circuit check to fail due to the bad proof - EXPECT_FALSE(outer_decider_circuit.check_circuit()); + EXPECT_FALSE(decider_circuit.check_circuit()); }; static void test_tampered_accumulator() { - // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; - - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); - - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; - - auto accumulator = fold_and_verify_native(instances, inner_composer); + // Fold two circuits natively + auto composer = Composer(); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify_native(composer); // Create another circuit to do a second round of folding - InnerBuilder builder3; - create_inner_circuit(builder3); - auto instance3 = inner_composer.create_instance(builder3); - - // Tamper with the accumulator - instances = std::vector>{ accumulator, instance3 }; - accumulator->prover_polynomials.w_l[1] = FF::random_element(); - - // Generate a folding proof - auto inner_folding_prover = inner_composer.create_folding_prover(instances); - auto inner_folding_proof = inner_folding_prover.fold_instances(); - - // Create a recursive folding verifier circuit for the folding proof of the two instances - OuterBuilder outer_folding_circuit; - FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; - verifier.verify_folding_proof(inner_folding_proof.folding_data); - EXPECT_EQ(outer_folding_circuit.check_circuit(), false); + Builder builder; + create_function_circuit(builder); + auto prover_inst = composer.create_prover_instance(builder); + auto verifier_inst = composer.create_verifier_instance(prover_inst); + + prover_accumulator->prover_polynomials.w_l[1] = FF::random_element(); + + // Generate a folding proof with the incorrect polynomials which would result in the prover having the wrong + // target sum + auto folding_prover = composer.create_folding_prover({ prover_accumulator, prover_inst }); + auto folding_proof = folding_prover.fold_instances(); + + // Create a recursive folding verifier circuit for the folding proof of the two instances with the untampered + // commitments + Builder folding_circuit; + FoldingRecursiveVerifier verifier{ &folding_circuit, + verifier_accumulator, + { verifier_inst->verification_key } }; + auto recursive_verifier_acc = verifier.verify_folding_proof(folding_proof.folding_data); + // Validate that the target sum between prover and verifier is now different + EXPECT_FALSE(folding_proof.accumulator->target_sum == recursive_verifier_acc->target_sum.get_value()); }; }; -using FlavorTypes = testing::Types, - UltraRecursiveFlavor_>; +using FlavorTypes = testing::Types>; TYPED_TEST_SUITE(ProtoGalaxyRecursiveTests, FlavorTypes); TYPED_TEST(ProtoGalaxyRecursiveTests, InnerCircuit) { - TestFixture::test_inner_circuit(); + TestFixture::test_circuit(); } TYPED_TEST(ProtoGalaxyRecursiveTests, NewEvaluate) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp new file mode 100644 index 00000000000..9e8151aad2e --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp @@ -0,0 +1,43 @@ +#pragma once +#include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/relations/relation_parameters.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp" + +namespace bb::stdlib::recursion::honk { +template struct RecursiveVerifierInstances_ { + using Flavor = Flavor_; + using Builder = typename Flavor::CircuitBuilder; + using VerificationKey = typename Flavor::VerificationKey; + using NativeVerificationKey = typename Flavor::NativeVerificationKey; + using Instance = RecursiveVerifierInstance_; + using NativeInstance = bb::VerifierInstance_; + using ArrayType = std::array, NUM_>; + + public: + static constexpr size_t NUM = NUM_; + static constexpr size_t BATCHED_EXTENDED_LENGTH = (Flavor::MAX_TOTAL_RELATION_LENGTH - 1 + NUM - 1) * (NUM - 1) + 1; + ArrayType _data; + std::shared_ptr const& operator[](size_t idx) const { return _data[idx]; } + typename ArrayType::iterator begin() { return _data.begin(); }; + typename ArrayType::iterator end() { return _data.end(); }; + Builder* builder; + + RecursiveVerifierInstances_(Builder* builder, + const std::shared_ptr& accumulator, + const std::vector>& vks) + : builder(builder) + { + ASSERT(vks.size() == NUM - 1); + if (accumulator->is_accumulator) { + _data[0] = std::make_shared(builder, accumulator); + } else { + _data[0] = std::make_shared(builder, accumulator->verification_key); + } + size_t idx = 1; + for (auto& vk : vks) { + _data[idx] = std::make_shared(builder, vk); + idx++; + } + } +}; +} // namespace bb::stdlib::recursion::honk diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp new file mode 100644 index 00000000000..d61ee8734fc --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp @@ -0,0 +1,148 @@ +#pragma once +#include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/relations/relation_parameters.hpp" +#include "barretenberg/sumcheck/instance/verifier_instance.hpp" + +namespace bb::stdlib::recursion::honk { + +/** + * @brief The stdlib counterpart of VerifierInstance, used in recursive folding verification. + */ +template class RecursiveVerifierInstance_ { + public: + using FF = typename Flavor::FF; + using NativeFF = typename Flavor::Curve::ScalarFieldNative; + using Commitment = typename Flavor::Commitment; + using VerificationKey = typename Flavor::VerificationKey; + using NativeVerificationKey = typename Flavor::NativeVerificationKey; + using WitnessCommitments = typename Flavor::WitnessCommitments; + using CommitmentLabels = typename Flavor::CommitmentLabels; + using RelationSeparator = typename Flavor::RelationSeparator; + using Builder = typename Flavor::CircuitBuilder; + using NativeFlavor = typename Flavor::NativeFlavor; + using VerifierInstance = bb::VerifierInstance_; + + Builder* builder; + + std::shared_ptr verification_key; + std::vector public_inputs; + size_t pub_inputs_offset = 0; + size_t public_input_size; + size_t instance_size; + size_t log_instance_size; + RelationParameters relation_parameters; + RelationSeparator alphas; + bool is_accumulator = false; + + // The folding parameters (\vec{β}, e) which are set for accumulators (i.e. relaxed instances). + std::vector gate_challenges; + FF target_sum; + + WitnessCommitments witness_commitments; + CommitmentLabels commitment_labels; + + RecursiveVerifierInstance_(Builder* builder) + : builder(builder){}; + RecursiveVerifierInstance_(Builder* builder, std::shared_ptr vk) + : builder(builder) + , verification_key(std::make_shared(builder, vk)) + {} + + RecursiveVerifierInstance_(Builder* builder, const std::shared_ptr& instance) + : pub_inputs_offset((instance->pub_inputs_offset)) + , public_input_size((instance->public_input_size)) + , instance_size((instance->instance_size)) + , log_instance_size((instance->log_instance_size)) + , is_accumulator(bool(instance->is_accumulator)) + { + + size_t public_input_idx = 0; + public_inputs = std::vector(public_input_size); + for (auto& public_input : instance->public_inputs) { + public_inputs[public_input_idx] = FF::from_witness(builder, public_input); + public_input_idx++; + } + verification_key = std::make_shared(instance_size, public_input_size); + auto other_vks = instance->verification_key->get_all(); + size_t vk_idx = 0; + for (auto& vk : verification_key->get_all()) { + vk = Commitment::from_witness(builder, other_vks[vk_idx]); + vk_idx++; + } + for (size_t alpha_idx = 0; alpha_idx < alphas.size(); alpha_idx++) { + alphas[alpha_idx] = FF::from_witness(builder, instance->alphas[alpha_idx]); + } + + auto other_comms = instance->witness_commitments.get_all(); + size_t comm_idx = 0; + for (auto& comm : witness_commitments.get_all()) { + comm = Commitment::from_witness(builder, other_comms[comm_idx]); + comm_idx++; + } + target_sum = FF::from_witness(builder, instance->target_sum); + + size_t challenge_idx = 0; + gate_challenges = std::vector(instance->gate_challenges.size()); + for (auto& challenge : gate_challenges) { + challenge = FF::from_witness(builder, instance->gate_challenges[challenge_idx]); + challenge_idx++; + } + relation_parameters.eta = FF::from_witness(builder, instance->relation_parameters.eta); + relation_parameters.beta = FF::from_witness(builder, instance->relation_parameters.beta); + relation_parameters.gamma = FF::from_witness(builder, instance->relation_parameters.gamma); + relation_parameters.public_input_delta = + FF::from_witness(builder, instance->relation_parameters.public_input_delta); + relation_parameters.lookup_grand_product_delta = + FF::from_witness(builder, instance->relation_parameters.lookup_grand_product_delta); + } + + /** + * @brief Return the underlying native VerifierInstance. + * + * @details In the context of client IVC, we will have several iterations of recursive folding verification. The + * RecursiveVerifierInstance is tied to the builder in whose context it was created so in order to preserve the + * accumulator values between several iterations we need to retrieve the native VerifierInstance values. + */ + VerifierInstance get_value() + { + VerifierInstance inst; + inst.pub_inputs_offset = pub_inputs_offset; + inst.public_input_size = public_input_size; + inst.log_instance_size = log_instance_size; + inst.instance_size = instance_size; + inst.is_accumulator = is_accumulator; + + inst.public_inputs = std::vector(public_input_size); + for (auto [public_input, inst_public_input] : zip_view(public_inputs, inst.public_inputs)) { + inst_public_input = public_input.get_value(); + } + + inst.verification_key = std::make_shared(instance_size, public_input_size); + for (auto [vk, inst_vk] : zip_view(verification_key->get_all(), inst.verification_key->get_all())) { + inst_vk = vk.get_value(); + } + + for (auto [alpha, inst_alpha] : zip_view(alphas, inst.alphas)) { + inst_alpha = alpha.get_value(); + } + + for (auto [comm, inst_comm] : zip_view(witness_commitments.get_all(), inst.witness_commitments.get_all())) { + inst_comm = comm.get_value(); + } + inst.target_sum = target_sum.get_value(); + + inst.gate_challenges = std::vector(gate_challenges.size()); + for (auto [challenge, inst_challenge] : zip_view(gate_challenges, inst.gate_challenges)) { + inst_challenge = challenge.get_value(); + } + + inst.relation_parameters.eta = relation_parameters.eta.get_value(); + inst.relation_parameters.beta = relation_parameters.beta.get_value(); + inst.relation_parameters.gamma = relation_parameters.gamma.get_value(); + inst.relation_parameters.public_input_delta = relation_parameters.public_input_delta.get_value(); + inst.relation_parameters.lookup_grand_product_delta = + relation_parameters.lookup_grand_product_delta.get_value(); + return inst; + } +}; +} // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp index 7203a67a2c2..384405d1272 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp @@ -132,20 +132,20 @@ template class RecursiveVerifierTest : public testing::Te // Compute native verification key InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); auto prover = inner_composer.create_prover(instance); // A prerequisite for computing VK - + auto verification_key = instance->verification_key; // Instantiate the recursive verifier using the native verification key - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; // Spot check some values in the recursive VK to ensure it was constructed correctly - EXPECT_EQ(verifier.key->circuit_size, instance->verification_key->circuit_size); - EXPECT_EQ(verifier.key->log_circuit_size, instance->verification_key->log_circuit_size); - EXPECT_EQ(verifier.key->num_public_inputs, instance->verification_key->num_public_inputs); - EXPECT_EQ(verifier.key->q_m.get_value(), instance->verification_key->q_m); - EXPECT_EQ(verifier.key->q_r.get_value(), instance->verification_key->q_r); - EXPECT_EQ(verifier.key->sigma_1.get_value(), instance->verification_key->sigma_1); - EXPECT_EQ(verifier.key->id_3.get_value(), instance->verification_key->id_3); + EXPECT_EQ(verifier.key->circuit_size, verification_key->circuit_size); + EXPECT_EQ(verifier.key->log_circuit_size, verification_key->log_circuit_size); + EXPECT_EQ(verifier.key->num_public_inputs, verification_key->num_public_inputs); + EXPECT_EQ(verifier.key->q_m.get_value(), verification_key->q_m); + EXPECT_EQ(verifier.key->q_r.get_value(), verification_key->q_r); + EXPECT_EQ(verifier.key->sigma_1.get_value(), verification_key->sigma_1); + EXPECT_EQ(verifier.key->id_3.get_value(), verification_key->id_3); } /** @@ -160,7 +160,7 @@ template class RecursiveVerifierTest : public testing::Te // Generate a proof over the inner circuit InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); @@ -175,7 +175,7 @@ template class RecursiveVerifierTest : public testing::Te // Check 1: Perform native verification then perform the pairing on the outputs of the recursive // verifier and check that the result agrees. - auto native_verifier = inner_composer.create_verifier(instance); + auto native_verifier = inner_composer.create_verifier(instance->verification_key); auto native_result = native_verifier.verify_proof(inner_proof); auto recursive_result = native_verifier.pcs_verification_key->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); @@ -192,9 +192,9 @@ template class RecursiveVerifierTest : public testing::Te // Check 3: Construct and verify a proof of the recursive verifier circuit { auto composer = get_outer_composer(); - auto instance = composer.create_instance(outer_circuit); + auto instance = composer.create_prover_instance(outer_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -216,7 +216,7 @@ template class RecursiveVerifierTest : public testing::Te // Generate a proof over the inner circuit InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp index a84f89db403..e2c168406c3 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp @@ -97,10 +97,14 @@ template struct VerifierInstances_ { std::shared_ptr const& operator[](size_t idx) const { return _data[idx]; } typename ArrayType::iterator begin() { return _data.begin(); }; typename ArrayType::iterator end() { return _data.end(); }; + VerifierInstances_() = default; - VerifierInstances_() + VerifierInstances_(const std::vector>& data) { - std::generate(_data.begin(), _data.end(), []() { return std::make_unique(); }); + ASSERT(data.size() == NUM); + for (size_t idx = 0; idx < data.size(); idx++) { + _data[idx] = std::move(data[idx]); + } }; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index c6d9d94d1e4..0781f4d11ac 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -9,15 +9,14 @@ namespace bb { /** - * @brief An Instance is normally constructed from a finalized circuit and it's role is to compute all the polynomials - * involved in creating a proof and, if requested, the verification key. - * In case of folded Instance, this will be created from the FoldingResult, the aggregated work from the folding prover - * and verifier. More specifically, a folded instance will be constructed from the complete set of folded polynomials - * and folded public inputs and its FoldingParams are expected to be non-zero + * @brief A ProverInstance is normally constructed from a finalized circuit and it contains all the information + * required by an Ultra Goblin Honk prover to create a proof. A ProverInstance is also the result of running the + * Protogalaxy prover, in which case it becomes a relaxed counterpart with the folding parameters (target sum and gate + * challenges set to non-zero values). * + * @details This is the equivalent of ω in the paper. */ -// TODO(https://github.com/AztecProtocol/barretenberg/issues/725): create an Instances class that manages several -// Instance and passes them to ProtoGalaxy prover and verifier so that Instance objects don't need to mantain an index + template class ProverInstance_ { using Circuit = typename Flavor::CircuitBuilder; using ProvingKey = typename Flavor::ProvingKey; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp index 9ba56880f84..0910ccb614d 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp @@ -3,6 +3,13 @@ #include "barretenberg/relations/relation_parameters.hpp" namespace bb { +/** + * @brief The VerifierInstance encapsulates all the necessary information for a Goblin Ultra Honk Verifier to verify a + * proof (sumcheck + Zeromorph). In the context of folding, this is returned by the Protogalaxy verifier with non-zero + * target sum and gate challenges. + * + * @details This is ϕ in the paper. + */ template class VerifierInstance_ { public: using FF = typename Flavor::FF; @@ -27,5 +34,9 @@ template class VerifierInstance_ { WitnessCommitments witness_commitments; CommitmentLabels commitment_labels; + VerifierInstance_() = default; + VerifierInstance_(std::shared_ptr vk) + : verification_key(std::move(vk)) + {} }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp index bbec6530151..6af08ef87f7 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp @@ -84,10 +84,10 @@ TEST_F(DataBusComposerTests, CallDataRead) auto composer = GoblinUltraComposer(); // Construct and verify Honk proof - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); // For debugging, use "instance_inspector::print_databus_info(instance)" auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); EXPECT_TRUE(verified); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp index ddc3cd4bd72..8e8ed2876fb 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp @@ -62,9 +62,9 @@ class GoblinUltraHonkComposerTests : public ::testing::Test { */ bool construct_and_verify_honk_proof(auto& composer, auto& builder) { - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp index 5e97fd5bfaf..12ae627a62f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp @@ -145,7 +145,7 @@ TEST_F(GoblinUltraTranscriptTests, ProverManifestConsistency) // Automatically generate a transcript manifest by constructing a proof auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); @@ -172,12 +172,12 @@ TEST_F(GoblinUltraTranscriptTests, VerifierManifestConsistency) // Automatically generate a transcript manifest in the prover by constructing a proof auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -223,10 +223,10 @@ TEST_F(GoblinUltraTranscriptTests, StructureTest) // Automatically generate a transcript manifest by constructing a proof auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp index 42f5757c1e3..3c4370edd94 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp @@ -14,9 +14,11 @@ template class ProtoGalaxyTests : public testing::Test { public: using Composer = UltraComposer_; using VerificationKey = typename Flavor::VerificationKey; - using Instance = ProverInstance_; - using Instances = ProverInstances_; - using ProtoGalaxyProver = ProtoGalaxyProver_; + using ProverInstance = ProverInstance_; + using ProverInstances = ProverInstances_; + using VerifierInstance = VerifierInstance_; + using VerifierInstances = VerifierInstances_; + using ProtoGalaxyProver = ProtoGalaxyProver_; using FF = typename Flavor::FF; using Affine = typename Flavor::Commitment; using Projective = typename Flavor::GroupElement; @@ -59,21 +61,20 @@ template class ProtoGalaxyTests : public testing::Test { return full_polynomials; } - static std::shared_ptr fold_and_verify(const std::vector>& instances, - Composer& composer, - bool expected_result) + static std::tuple, std::shared_ptr> fold_and_verify( + const std::vector>& prover_instances, + const std::vector>& verifier_instances, + Composer& composer) { - auto folding_prover = composer.create_folding_prover(instances); - auto folding_verifier = composer.create_folding_verifier(); - - auto proof = folding_prover.fold_instances(); - auto next_accumulator = proof.accumulator; - auto res = folding_verifier.verify_folding_proof(proof.folding_data); - EXPECT_EQ(res, expected_result); - return next_accumulator; + auto folding_prover = composer.create_folding_prover(prover_instances); + auto folding_verifier = composer.create_folding_verifier(verifier_instances); + + auto [prover_accumulator, folding_proof] = folding_prover.fold_instances(); + auto verifier_accumulator = folding_verifier.verify_folding_proof(folding_proof); + return { prover_accumulator, verifier_accumulator }; } - static void check_accumulator_target_sum_manual(std::shared_ptr& accumulator, bool expected_result) + static void check_accumulator_target_sum_manual(std::shared_ptr& accumulator, bool expected_result) { auto instance_size = accumulator->instance_size; auto expected_honk_evals = ProtoGalaxyProver::compute_full_honk_evaluations( @@ -90,10 +91,13 @@ template class ProtoGalaxyTests : public testing::Test { EXPECT_EQ(accumulator->target_sum == expected_target_sum, expected_result); } - static void decide_and_verify(std::shared_ptr& accumulator, Composer& composer, bool expected_result) + static void decide_and_verify(std::shared_ptr& prover_accumulator, + std::shared_ptr& verifier_accumulator, + Composer& composer, + bool expected_result) { - auto decider_prover = composer.create_decider_prover(accumulator); - auto decider_verifier = composer.create_decider_verifier(accumulator); + auto decider_prover = composer.create_decider_prover(prover_accumulator); + auto decider_verifier = composer.create_decider_verifier(verifier_accumulator); auto decider_proof = decider_prover.construct_proof(); auto verified = decider_verifier.verify_proof(decider_proof); EXPECT_EQ(verified, expected_result); @@ -111,7 +115,7 @@ template class ProtoGalaxyTests : public testing::Test { construct_circuit(builder); auto composer = Composer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); instance->initialize_prover_polynomials(); auto eta = FF::random_element(); @@ -191,7 +195,7 @@ template class ProtoGalaxyTests : public testing::Test { target_sum += full_honk_evals[i] * pow_beta[i]; } - auto accumulator = std::make_shared(); + auto accumulator = std::make_shared(); accumulator->prover_polynomials = std::move(full_polynomials); accumulator->gate_challenges = betas; accumulator->target_sum = target_sum; @@ -245,19 +249,16 @@ template class ProtoGalaxyTests : public testing::Test { */ static void test_combine_relation_parameters() { - using Instances = ProverInstances_; - using Instance = typename Instances::Instance; - Builder builder1; - auto instance1 = std::make_shared(builder1); + auto instance1 = std::make_shared(builder1); instance1->relation_parameters.eta = 1; Builder builder2; builder2.add_variable(3); - auto instance2 = std::make_shared(builder2); + auto instance2 = std::make_shared(builder2); instance2->relation_parameters.eta = 3; - Instances instances{ { instance1, instance2 } }; + ProverInstances instances{ { instance1, instance2 } }; ProtoGalaxyProver::combine_relation_parameters(instances); bb::Univariate expected_eta{ { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 } }; @@ -270,19 +271,16 @@ template class ProtoGalaxyTests : public testing::Test { */ static void test_combine_alpha() { - using Instances = ProverInstances_; - using Instance = typename Instances::Instance; - Builder builder1; - auto instance1 = std::make_shared(builder1); + auto instance1 = std::make_shared(builder1); instance1->alphas.fill(2); Builder builder2; builder2.add_variable(3); - auto instance2 = std::make_shared(builder2); + auto instance2 = std::make_shared(builder2); instance2->alphas.fill(4); - Instances instances{ { instance1, instance2 } }; + ProverInstances instances{ { instance1, instance2 } }; ProtoGalaxyProver::combine_alpha(instances); bb::Univariate expected_alpha{ { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26 } }; @@ -301,26 +299,29 @@ template class ProtoGalaxyTests : public testing::Test { auto builder_1 = typename Flavor::CircuitBuilder(); construct_circuit(builder_1); - auto instance_1 = composer.create_instance(builder_1); + auto prover_instance_1 = composer.create_prover_instance(builder_1); + auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); auto builder_2 = typename Flavor::CircuitBuilder(); construct_circuit(builder_2); + auto prover_instance_2 = composer.create_prover_instance(builder_2); + auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify( + { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, composer); - auto instance_2 = composer.create_instance(builder_2); - - auto instances = std::vector>{ instance_1, instance_2 }; - auto first_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(first_accumulator, true); + check_accumulator_target_sum_manual(prover_accumulator, true); auto builder_3 = typename Flavor::CircuitBuilder(); construct_circuit(builder_3); - auto instance_3 = composer.create_instance(builder_3); + auto prover_instance_3 = composer.create_prover_instance(builder_3); + auto verifier_instance_3 = composer.create_verifier_instance(prover_instance_3); + + auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify( + { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, composer); - instances = std::vector>{ first_accumulator, instance_3 }; - auto second_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(second_accumulator, true); + check_accumulator_target_sum_manual(prover_accumulator_2, true); - decide_and_verify(second_accumulator, composer, true); + decide_and_verify(prover_accumulator_2, verifier_accumulator_2, composer, true); } /** @@ -330,67 +331,67 @@ template class ProtoGalaxyTests : public testing::Test { static void test_tampered_commitment() { auto composer = Composer(); - auto builder_1 = typename Flavor::CircuitBuilder(); construct_circuit(builder_1); - auto instance_1 = composer.create_instance(builder_1); + auto prover_instance_1 = composer.create_prover_instance(builder_1); + auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); auto builder_2 = typename Flavor::CircuitBuilder(); construct_circuit(builder_2); + auto prover_instance_2 = composer.create_prover_instance(builder_2); + auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify( + { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, composer); + check_accumulator_target_sum_manual(prover_accumulator, true); - auto instance_2 = composer.create_instance(builder_2); - - auto instances = std::vector>{ instance_1, instance_2 }; - auto first_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(first_accumulator, true); - + verifier_accumulator->witness_commitments.w_l = Projective(Affine::random_element()); auto builder_3 = typename Flavor::CircuitBuilder(); construct_circuit(builder_3); - auto instance_3 = composer.create_instance(builder_3); + auto prover_instance_3 = composer.create_prover_instance(builder_3); + auto verifier_instance_3 = composer.create_verifier_instance(prover_instance_3); - // tampering with the commitment should cause the decider to fail - first_accumulator->witness_commitments.w_l = Projective(Affine::random_element()); - instances = std::vector>{ first_accumulator, instance_3 }; + auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify( + { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, composer); - auto second_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(prover_accumulator_2, true); - decide_and_verify(second_accumulator, composer, false); + decide_and_verify(prover_accumulator_2, verifier_accumulator_2, composer, false); } /** - * @brief Ensure tampering an accumulator and then calling fold again causes both the folding verification and - * decider verification to fail. + * @brief Ensure tampering an accumulator and then calling fold again causes the target sums in the prover and + * verifier accumulators to be different and decider verification to fail. * */ static void test_tampered_accumulator_polynomial() { auto composer = Composer(); - auto builder_1 = typename Flavor::CircuitBuilder(); construct_circuit(builder_1); - auto instance_1 = composer.create_instance(builder_1); + auto prover_instance_1 = composer.create_prover_instance(builder_1); + auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); auto builder_2 = typename Flavor::CircuitBuilder(); construct_circuit(builder_2); - - auto instance_2 = composer.create_instance(builder_2); - - auto instances = std::vector>{ instance_1, instance_2 }; - auto first_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(first_accumulator, true); + auto prover_instance_2 = composer.create_prover_instance(builder_2); + auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify( + { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, composer); + check_accumulator_target_sum_manual(prover_accumulator, true); auto builder_3 = typename Flavor::CircuitBuilder(); construct_circuit(builder_3); - auto instance_3 = composer.create_instance(builder_3); + auto prover_instance_3 = composer.create_prover_instance(builder_3); + auto verifier_instance_3 = composer.create_verifier_instance(prover_instance_3); - // tampering with accumulator's polynomial should cause both folding and deciding to fail - instances = std::vector>{ first_accumulator, instance_3 }; - first_accumulator->prover_polynomials.w_l[1] = FF::random_element(); - auto second_accumulator = fold_and_verify(instances, composer, false); + prover_accumulator->prover_polynomials.w_l[1] = FF::random_element(); + auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify( + { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, composer); - decide_and_verify(second_accumulator, composer, false); + EXPECT_EQ(prover_accumulator_2->target_sum == verifier_accumulator_2->target_sum, false); + decide_and_verify(prover_accumulator_2, verifier_accumulator_2, composer, false); } }; } // namespace diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp index 2b5ec50f37e..a52bbbe240b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp @@ -268,7 +268,7 @@ TEST_F(RelationCorrectnessTests, UltraRelationCorrectness) // Create a prover (it will compute proving key and witness) auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto proving_key = instance->proving_key; auto circuit_size = proving_key->circuit_size; @@ -321,7 +321,7 @@ TEST_F(RelationCorrectnessTests, GoblinUltraRelationCorrectness) // Create a prover (it will compute proving key and witness) auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto proving_key = instance->proving_key; auto circuit_size = proving_key->circuit_size; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp index 1ec8602c4fb..34515508931 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp @@ -149,7 +149,7 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) // Create a prover (it will compute proving key and witness) auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); // Generate eta, beta and gamma FF eta = FF::random_element(); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp index 334f60bf8c6..e8da52f540b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp @@ -7,13 +7,21 @@ namespace bb { template -std::shared_ptr> UltraComposer_::create_instance(CircuitBuilder& circuit) +std::shared_ptr> UltraComposer_::create_prover_instance(CircuitBuilder& circuit) { - return std::make_shared(circuit); + return std::make_shared(circuit); } template -UltraProver_ UltraComposer_::create_prover(const std::shared_ptr& instance, +std::shared_ptr> UltraComposer_::create_verifier_instance( + std::shared_ptr>& prover_instance) +{ + auto instance = std::make_shared(prover_instance->verification_key); + return instance; +} + +template +UltraProver_ UltraComposer_::create_prover(const std::shared_ptr& instance, const std::shared_ptr& transcript) { UltraProver_ output_state(instance, transcript); @@ -22,10 +30,9 @@ UltraProver_ UltraComposer_::create_prover(const std::shared_ptr } template -UltraVerifier_ UltraComposer_::create_verifier(const std::shared_ptr& instance, +UltraVerifier_ UltraComposer_::create_verifier(const std::shared_ptr& verification_key, const std::shared_ptr& transcript) { - auto& verification_key = instance->verification_key; UltraVerifier_ output_state(transcript, verification_key); auto pcs_verification_key = std::make_unique(verification_key->circuit_size, crs_factory_); output_state.pcs_verification_key = std::move(pcs_verification_key); @@ -34,7 +41,7 @@ UltraVerifier_ UltraComposer_::create_verifier(const std::shared } template -DeciderProver_ UltraComposer_::create_decider_prover(const std::shared_ptr& accumulator, +DeciderProver_ UltraComposer_::create_decider_prover(const std::shared_ptr& accumulator, const std::shared_ptr& transcript) { commitment_key = compute_commitment_key(accumulator->instance_size); @@ -45,7 +52,7 @@ DeciderProver_ UltraComposer_::create_decider_prover(const std:: template DeciderProver_ UltraComposer_::create_decider_prover( - const std::shared_ptr& accumulator, + const std::shared_ptr& accumulator, const std::shared_ptr& commitment_key, const std::shared_ptr& transcript) { @@ -55,11 +62,10 @@ DeciderProver_ UltraComposer_::create_decider_prover( } template -DeciderVerifier_ UltraComposer_::create_decider_verifier(const std::shared_ptr& accumulator, - const std::shared_ptr& transcript) +DeciderVerifier_ UltraComposer_::create_decider_verifier( + const std::shared_ptr& accumulator, const std::shared_ptr& transcript) { - auto& verification_key = accumulator->verification_key; - DeciderVerifier_ output_state(transcript, verification_key); + DeciderVerifier_ output_state(transcript, accumulator); auto pcs_verification_key = std::make_unique(accumulator->instance_size, crs_factory_); output_state.pcs_verification_key = std::move(pcs_verification_key); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp index dfa23c93349..0805d0e35f6 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp @@ -21,7 +21,7 @@ template class UltraComposer_ { using CommitmentKey = typename Flavor::CommitmentKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using ProverInstance = ProverInstance_; - using Instance = ProverInstance; + using VerifierInstance = VerifierInstance_; using FF = typename Flavor::FF; using Transcript = typename Flavor::Transcript; using CRSFactory = srs::factories::CrsFactory; @@ -58,41 +58,49 @@ template class UltraComposer_ { return commitment_key; }; - std::shared_ptr create_instance(CircuitBuilder& circuit); + std::shared_ptr create_prover_instance(CircuitBuilder&); - UltraProver_ create_prover(const std::shared_ptr&, + /** + * @brief Create a verifier instance object. + * + * @details Currently use prover instance + */ + std::shared_ptr create_verifier_instance(std::shared_ptr&); + + UltraProver_ create_prover(const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); UltraVerifier_ create_verifier( - const std::shared_ptr&, + const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); DeciderProver_ create_decider_prover( - const std::shared_ptr&, + const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); DeciderProver_ create_decider_prover( - const std::shared_ptr&, + const std::shared_ptr&, const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); DeciderVerifier_ create_decider_verifier( - const std::shared_ptr&, + const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); UltraVerifier_ create_verifier(CircuitBuilder& circuit); UltraVerifier_ create_ultra_with_keccak_verifier(CircuitBuilder& circuit); - ProtoGalaxyProver_ create_folding_prover(const std::vector>& instances) + ProtoGalaxyProver_ create_folding_prover( + const std::vector>& instances) { ProtoGalaxyProver_ output_state(instances); return output_state; }; - ProtoGalaxyVerifier_ create_folding_verifier() - { - auto insts = VerifierInstances(); - ProtoGalaxyVerifier_ output_state(insts); + ProtoGalaxyVerifier_ create_folding_verifier( + const std::vector>& instances) + { + ProtoGalaxyVerifier_ output_state(instances); return output_state; }; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp index 7acc891f7f9..c8f0a1667ca 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp @@ -33,9 +33,9 @@ std::vector add_variables(auto& circuit_builder, std::vector v void prove_and_verify(auto& circuit_builder, auto& composer, bool expected_result) { - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); EXPECT_EQ(verified, expected_result); @@ -67,7 +67,7 @@ TEST_F(UltraHonkComposerTests, ANonZeroPolynomialIsAGoodPolynomial) auto circuit_builder = UltraCircuitBuilder(); auto composer = UltraComposer(); - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); auto proving_key = instance->proving_key; @@ -198,9 +198,9 @@ TEST_F(UltraHonkComposerTests, create_gates_from_plookup_accumulators) } } auto composer = UltraComposer(); - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); auto proof = prover.construct_proof(); bool result = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index fd6ccf7c148..bb05c2588ba 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -131,7 +131,7 @@ TEST_F(UltraTranscriptTests, ProverManifestConsistency) // Automatically generate a transcript manifest by constructing a proof auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); @@ -158,12 +158,12 @@ TEST_F(UltraTranscriptTests, VerifierManifestConsistency) // Automatically generate a transcript manifest in the prover by constructing a proof auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -209,10 +209,10 @@ TEST_F(UltraTranscriptTests, StructureTest) // Automatically generate a transcript manifest by constructing a proof auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(instance->verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid