diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp index e9ba9ed185eb..fb95a7fd7286 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp @@ -21,6 +21,7 @@ namespace { class IvcBench : 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,29 +44,45 @@ class IvcBench : public benchmark::Fixture { */ static void perform_ivc_accumulation_rounds(State& state, ClientIVC& ivc) { - // Initialize IVC with function circuit + // Initialize IVC with a function circuit + Builder initial_function_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(initial_function_circuit); + ivc.initialize(initial_function_circuit); + auto kernel_verifier_accumulator = std::make_shared(); + kernel_verifier_accumulator->verification_key = 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{ 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{ 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{ 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 }; } } }; @@ -77,7 +94,7 @@ class IvcBench : public benchmark::Fixture { BENCHMARK_DEFINE_F(IvcBench, 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 @@ -95,7 +112,7 @@ BENCHMARK_DEFINE_F(IvcBench, Full)(benchmark::State& state) BENCHMARK_DEFINE_F(IvcBench, 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); @@ -110,7 +127,6 @@ BENCHMARK_DEFINE_F(IvcBench, Accumulate)(benchmark::State& state) BENCHMARK_DEFINE_F(IvcBench, Decide)(benchmark::State& state) { ClientIVC ivc; - // Perform a specified number of iterations of function/kernel accumulation perform_ivc_accumulation_rounds(state, ivc); @@ -128,7 +144,6 @@ BENCHMARK_DEFINE_F(IvcBench, Decide)(benchmark::State& state) BENCHMARK_DEFINE_F(IvcBench, ECCVM)(benchmark::State& state) { ClientIVC ivc; - // Perform a specified number of iterations of function/kernel accumulation perform_ivc_accumulation_rounds(state, ivc); @@ -146,7 +161,7 @@ BENCHMARK_DEFINE_F(IvcBench, ECCVM)(benchmark::State& state) BENCHMARK_DEFINE_F(IvcBench, 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); @@ -160,7 +175,6 @@ BENCHMARK_DEFINE_F(IvcBench, Translator)(benchmark::State& state) #define ARGS \ Arg(IvcBench::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 61c46dc24938..0b5c2403cc5e 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 626ab82bc1fb..5efdccce9ceb 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 1c0a1ed43ba9..29ff2fb135e0 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 92db4e2aacab..0b524505d7e0 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,64 @@ 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_; + + Composer composer; + 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); + composer.compute_commitment_key(prover_fold_output.accumulator->instance_size); + vks.first_func_vk = composer.compute_verification_key(prover_fold_output.accumulator); + auto initial_verifier_acc = std::make_shared(); + initial_verifier_acc->verification_key = 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 = composer.compute_verification_key(prover_instance); + + // 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 = composer.compute_verification_key(prover_instance); + + // 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 = composer.compute_verification_key(prover_instance); + + // 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 cd3b82b4d6d3..5c444ac9ec57 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 2924188f87d3..873920aad420 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) @@ -49,35 +54,18 @@ class ClientIVCTests : public ::testing::Test { * @param fctn_fold_proof * @param kernel_fold_proof */ - static void construct_mock_folding_kernel(Builder& builder, - FoldProof& fctn_fold_proof, - FoldProof& kernel_fold_proof) - { - FoldingRecursiveVerifier verifier_1{ &builder }; - verifier_1.verify_folding_proof(fctn_fold_proof); - - FoldingRecursiveVerifier verifier_2{ &builder }; - verifier_2.verify_folding_proof(kernel_fold_proof); - } - - /** - * @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 construct_mock_folding_kernel(Builder& builder, + VerifierFoldData& func_accum, + VerifierFoldData& kernel_accum, + VerifierAccumulator& prev_kernel_accum) { - // Verify fold proof - Composer composer; - auto folding_verifier = composer.create_folding_verifier(); - bool folding_verified = folding_verifier.verify_folding_proof(fold_proof); - EXPECT_TRUE(folding_verified); - // Run decider - auto decider_prover = composer.create_decider_prover(accumulator); - auto decider_verifier = composer.create_decider_verifier(accumulator); - auto decider_proof = decider_prover.construct_proof(); - bool decision = decider_verifier.verify_proof(decider_proof); - EXPECT_TRUE(decision); + 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()); } }; @@ -88,33 +76,40 @@ class ClientIVCTests : public ::testing::Test { TEST_F(ClientIVCTests, Full) { ClientIVC ivc; - + Composer composer; // Initialize IVC with function circuit Builder function_circuit = create_mock_circuit(ivc); ivc.initialize(function_circuit); + composer.compute_commitment_key(ivc.prover_fold_output.accumulator->instance_size); + auto function_vk = composer.compute_verification_key(ivc.prover_fold_output.accumulator); + auto kernel_acc = std::make_shared(); + kernel_acc->verification_key = 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); - + auto function_vk_2 = composer.compute_verification_key(ivc.prover_instance); + auto kernel_vk = function_vk_2; + VerifierFoldData kernel_fold_output = { kernel_fold_proof, function_vk_2 }; 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); - + VerifierFoldData function_fold_output = { function_fold_proof, function_vk_2 }; // Accumulate kernel circuit Builder kernel_circuit{ ivc.goblin.op_queue }; - construct_mock_folding_kernel(kernel_circuit, function_fold_proof, kernel_fold_proof); + kernel_acc = + construct_mock_folding_kernel(kernel_circuit, kernel_fold_output, function_fold_output, kernel_acc); FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.fold_output.accumulator, kernel_fold_proof); + kernel_vk = composer.compute_verification_key(ivc.prover_instance); + 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(); + inst->verification_key = kernel_vk; // Verify all four proofs - EXPECT_TRUE(ivc.verify(proof)); -} \ No newline at end of file + EXPECT_TRUE(ivc.verify(proof, { kernel_acc, 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 6ff29a1293e2..d3b322558aee 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 initial_acc = std::make_shared(); + initial_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); - - GoblinUltraCircuitBuilder circuit_3{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_3); - auto fold_proof_2 = ivc.accumulate(circuit_3); + auto func_fold_proof = ivc.accumulate(circuit_2); // Construct kernel circuit GoblinUltraCircuitBuilder kernel_circuit{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, fold_proof_1, fold_proof_2); + auto kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, { func_fold_proof, ivc.vks.func_vk }, {}, initial_acc); + + auto kernel_fold_proof = ivc.accumulate(kernel_circuit); + EXPECT_EQ(ivc.prover_instance->log_instance_size, 17); + + GoblinUltraCircuitBuilder circuit_4{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_4); + func_fold_proof = ivc.accumulate(circuit_4); + + 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 1fde752ccecc..fdfed9ef41d7 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -104,7 +104,8 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto ultra_proof = prover.construct_proof(); @@ -116,7 +117,7 @@ class Goblin { merge_proof_exists = true; } - return { ultra_proof, instance->verification_key }; + return { ultra_proof, verification_key }; }; /** @@ -229,11 +230,12 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto ultra_proof = prover.construct_proof(); - accumulator = { ultra_proof, instance->verification_key }; + accumulator = { ultra_proof, verification_key }; // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): no merge prover for now since we're not // mocking the first set of ecc ops diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp index dc0facdb60af..c731722d755a 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 bc14c506539f..e6502fcc7294 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); } @@ -214,30 +228,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 2f52c964eab0..db0fc69b80d2 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 51d55e9766a5..ccac06c79282 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp @@ -20,51 +20,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. @@ -102,9 +57,6 @@ template HonkProof& DeciderProver_::export_proof( template HonkProof& DeciderProver_::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_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index 1c6601613fbb..173ed95e488a 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 70ca20336175..3969b89d96c1 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 c31ebba7e457..ec7d9dbaa912 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 4fd7689471e4..d84f5d5ae3c5 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 @@ -284,8 +277,25 @@ template class ProtoGalaxyProver_ { const FF& scaling_factor) { using Relation = std::tuple_element_t; - Relation::accumulate( - std::get(univariate_accumulators), extended_univariates, relation_parameters, scaling_factor); + + // Check if the relation has a skip function to speed up accumulation + if constexpr (!isSkippable) { + + // If not, accumulate normally + Relation::accumulate(std::get(univariate_accumulators), + extended_univariates, + relation_parameters, + scaling_factor); + } else { + + // If it has the skip function, only accumulate if it returns false + if (!Relation::skip(extended_univariates)) { + Relation::accumulate(std::get(univariate_accumulators), + extended_univariates, + relation_parameters, + scaling_factor); + } + } // Repeat for the next relation. if constexpr (relation_idx + 1 < Flavor::NUM_RELATIONS) { @@ -465,9 +475,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 bdcfa0500e93..b56f3da63446 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 5743a888a0f1..9a39986fe4b9 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/relations/auxiliary_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp index 0e97cb1ded28..e9a1be3b425b 100644 --- a/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp @@ -48,7 +48,18 @@ template class AuxiliaryRelationImpl { 6, // RAM consistency sub-relation 2 6 // RAM consistency sub-relation 3 }; - + /** + * @brief Determine if auxiliary relation can be ignored at current row + * + * @param in UnivariateViews of entities + * @return true if we can skip + * @return false if relation has to be accumulated + */ + template inline static bool skip(const AllEntities& in) + { + // If evaluations at 0 and 1 are both zero, then all evaluations are zero and relation will result in zero + return in.q_aux.evaluations[0].is_zero() && in.q_aux.evaluations[1].is_zero(); + } /** * @brief Expression for the generalized permutation sort gate. * @details The following explanation is reproduced from the Plonk analog 'plookup_auxiliary_widget': diff --git a/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp index eb79bb21efeb..90f3d0dde415 100644 --- a/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp @@ -23,6 +23,20 @@ template class DatabusLookupRelationImpl { LENGTH // log-derivative lookup argument subrelation }; + /** + * @brief Determine if DatabusLookup relation can be ignored at current row + * + * @param in UnivariateViews of entities + * @return true if we can skip + * @return false if relation has to be accumulated + */ + template inline static bool skip(const AllEntities& in) + { + // If evaluations at 0 and 1 for selectors determinining read and write are both zero, then all + // evaluations are zero and relation will result in zero + return in.q_busread.evaluations[0].is_zero() && in.q_busread.evaluations[1].is_zero() && + in.calldata_read_counts.evaluations[0].is_zero() && in.calldata_read_counts.evaluations[1].is_zero(); + } // The second subrelation is "linearly dependant" in the sense that it establishes the value of a sum across the // entire execution trace rather than a per-row identity. static constexpr std::array SUBRELATION_LINEARLY_INDEPENDENT = { true, false }; diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_op_queue_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_op_queue_relation.hpp index c958296832f7..6f4d1d80fa21 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_op_queue_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_op_queue_relation.hpp @@ -18,6 +18,18 @@ template class EccOpQueueRelationImpl { 3 // op-queue-wire vanishes sub-relation 4 }; + /** + * @brief Determine if EccOpQueue relation can be ignored at current row + * + * @param in UnivariateViews of entities + * @return true if we can skip + * @return false if relation has to be accumulated + */ + template inline static bool skip(const AllEntities& in) + { + // If evaluations at 0 and 1 are both zero, then all evaluations are zero and relation will result in zero + return in.lagrange_ecc_op.evaluations[0].is_zero() && in.lagrange_ecc_op.evaluations[1].is_zero(); + } /** * @brief Expression for the generalized permutation sort gate. * @details The relation is defined as C(in(X)...) = diff --git a/barretenberg/cpp/src/barretenberg/relations/elliptic_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/elliptic_relation.hpp index 646400b5fd1e..1065fbb8b34d 100644 --- a/barretenberg/cpp/src/barretenberg/relations/elliptic_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/elliptic_relation.hpp @@ -14,6 +14,18 @@ template class EllipticRelationImpl { 6, // y-coordinate sub-relation }; + /** + * @brief Determine if elliptic relation can be ignored at current row + * + * @param in UnivariateViews of entities + * @return true if we can skip + * @return false if relation has to be accumulated + */ + template inline static bool skip(const AllEntities& in) + { + // If evaluations at 0 and 1 are both zero, then all evaluations are zero and relation will result in zero + return in.q_elliptic.evaluations[0].is_zero() && in.q_elliptic.evaluations[1].is_zero(); + } // TODO(@zac-williamson #2609 find more generic way of doing this) static constexpr FF get_curve_b() { diff --git a/barretenberg/cpp/src/barretenberg/relations/poseidon2_external_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/poseidon2_external_relation.hpp index f19ac3e37f34..00dcd677f1d1 100644 --- a/barretenberg/cpp/src/barretenberg/relations/poseidon2_external_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/poseidon2_external_relation.hpp @@ -13,6 +13,18 @@ template class Poseidon2ExternalRelationImpl { 7, // external poseidon2 round sub-relation for fourth value }; + /** + * @brief Determine if poseidon external relation can be ignored at current row + * + * @param in UnivariateViews of entities + * @return true if we can skip + * @return false if relation has to be accumulated + */ + template inline static bool skip(const AllEntities& in) + { + // If evaluations at 0 and 1 are both zero, then all evaluations are zero and relation will result in zero + return in.q_poseidon2_external.evaluations[0].is_zero() && in.q_poseidon2_external.evaluations[1].is_zero(); + } /** * @brief Expression for the poseidon2 external round relation, based on E_i in Section 6 of * https://eprint.iacr.org/2023/323.pdf. diff --git a/barretenberg/cpp/src/barretenberg/relations/poseidon2_internal_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/poseidon2_internal_relation.hpp index c1db21caea79..2b1220959274 100644 --- a/barretenberg/cpp/src/barretenberg/relations/poseidon2_internal_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/poseidon2_internal_relation.hpp @@ -15,6 +15,18 @@ template class Poseidon2InternalRelationImpl { 7, // internal poseidon2 round sub-relation for fourth value }; + /** + * @brief Determine if poseidon internal relation can be ignored at current row + * + * @param in UnivariateViews of entities + * @return true if we can skip + * @return false if relation has to be accumulated + */ + template inline static bool skip(const AllEntities& in) + { + // If evaluations at 0 and 1 are both zero, then all evaluations are zero and relation will result in zero + return in.q_poseidon2_internal.evaluations[0].is_zero() && in.q_poseidon2_internal.evaluations[1].is_zero(); + } /** * @brief Expression for the poseidon2 internal round relation, based on I_i in Section 6 of * https://eprint.iacr.org/2023/323.pdf. diff --git a/barretenberg/cpp/src/barretenberg/relations/relation_types.hpp b/barretenberg/cpp/src/barretenberg/relations/relation_types.hpp index be4b87322548..7a5a7bc3fed4 100644 --- a/barretenberg/cpp/src/barretenberg/relations/relation_types.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/relation_types.hpp @@ -23,10 +23,10 @@ using GetParameterView = std::conditional_t, template concept HasSubrelationLinearlyIndependentMember = requires(T) { - { - std::get(T::SUBRELATION_LINEARLY_INDEPENDENT) - } -> std::convertible_to; - }; + { + std::get(T::SUBRELATION_LINEARLY_INDEPENDENT) + } -> std::convertible_to; +}; template concept HasParameterLengthAdjustmentsMember = requires { T::TOTAL_LENGTH_ADJUSTMENTS; }; @@ -111,6 +111,21 @@ consteval std::array compute_composed_subrelation_part * */ +/** + * @brief Check if the relation has a static skip method to determine if accumulation of its result can be optimised + * based on a single check + * + * @details The skip function should return true if relation can be skipped and false if it can't + * @tparam Relation The relation type + * @tparam AllEntities The type containing UnivariateViews with witness and selector values + */ +template +concept isSkippable = requires(const AllEntities& input) { + { + Relation::skip(input) + } -> std::same_as; +}; + /** * @brief A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the * contribution of a given relation to the corresponding accumulator. diff --git a/barretenberg/cpp/src/barretenberg/relations/ultra_arithmetic_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ultra_arithmetic_relation.hpp index 898e3a7d1444..6837b2d23aca 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ultra_arithmetic_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ultra_arithmetic_relation.hpp @@ -11,6 +11,10 @@ template class UltraArithmeticRelationImpl { 6, // primary arithmetic sub-relation 5 // secondary arithmetic sub-relation }; + template inline static bool skip(const AllEntities& in) + { + return in.q_arith.evaluations[0].is_zero() && in.q_arith.evaluations[1].is_zero(); + } /** * @brief Expression for the Ultra Arithmetic gate. 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 0ece406ee75f..dffe20412d71 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 61f9a4814206..829f47e99a5d 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 9052d25c0710..f74d18faccb4 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,22 @@ 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 verification_key = inner_composer.compute_verification_key(instance); auto prover = inner_composer.create_prover(instance); // A prerequisite for computing VK // 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,13 +177,14 @@ 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 verification_key = inner_composer.compute_verification_key(instance); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; auto pairing_points = verifier.verify_proof(inner_proof); info("Recursive Verifier Goblin: num gates = ", outer_circuit.num_gates); @@ -191,7 +193,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(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 +210,10 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -231,7 +234,8 @@ 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 verification_key = inner_composer.compute_verification_key(instance); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); @@ -243,7 +247,7 @@ template class GoblinRecursiveVerifierTest : public testi // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; verifier.verify_proof(inner_proof); // We expect the circuit check to fail due to the bad 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 8e6595a1b981..4b02a451818e 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,10 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(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 6ac10f7cd30d..8063c369db3a 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 9bcc8a9c2382..f413fb3b1519 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 0912edf91ce0..9e1f0835dadb 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 = 15) { - 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,40 @@ 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; - 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 }; - + Builder builder1; + create_function_circuit(builder1); + Builder builder2; + 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); + 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); + + // 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); - // 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()); + // Check for a failure flag in the recursive verifier circuit + EXPECT_EQ(folding_circuit.failed(), false) << folding_circuit.err(); // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the // manifestsproduced by each agree. @@ -208,14 +200,12 @@ template class ProtoGalaxyRecursiveTests : public tes EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]); } - // 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -228,67 +218,72 @@ template class ProtoGalaxyRecursiveTests : public tes * make sure the verifer circuits pass check_circuit(). Ensure that the algorithm of the recursive and native * verifiers are identical by checking the manifests */ - // TODO(https://github.com/AztecProtocol/barretenberg/issues/844): Fold the recursive folding verifier in tests once - // we can fold instances of different sizes. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/844): Fold the recursive folding verifier in + // tests once we can fold instances of different sizes. static void test_full_protogalaxy_recursive() { // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; + Builder builder1; + create_function_circuit(builder1); + Builder builder2; + 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 folding_prover = composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); + auto folding_proof = folding_prover.fold_instances(); - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); + // 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); - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; + // Check for a failure flag in the recursive verifier circuit + EXPECT_EQ(folding_circuit.failed(), false) << folding_circuit.err(); - auto accumulator = fold_and_verify_native(instances, inner_composer); + // 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 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 }; + // 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(); - accumulator = fold_and_verify_native(instances, inner_composer); + for (size_t i = 0; i < recursive_folding_manifest.size(); ++i) { + EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]); + } - // 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(folding_proof.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 }; - auto pairing_points = 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, 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); - // Ensure that the underlying native and recursive decider verification algorithms agree by ensuring - // the manifests produced are the same. - auto recursive_decider_manifest = decider_verifier.transcript->get_manifest(); - auto native_decider_manifest = native_decider_verifier.transcript->get_manifest(); - for (size_t i = 0; i < recursive_decider_manifest.size(); ++i) { - EXPECT_EQ(recursive_decider_manifest[i], native_decider_manifest[i]); - } - - // 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -299,82 +294,69 @@ 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); + 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); + + { + auto composer = Composer(); + auto instance = composer.create_prover_instance(decider_circuit); + auto verification_key = composer.compute_verification_key(instance); + auto prover = composer.create_prover(instance); + auto verifier = composer.create_verifier(verification_key); + auto proof = prover.construct_proof(); + bool verified = verifier.verify_proof(proof); - // We expect the decider circuit check to fail due to the bad proof - EXPECT_FALSE(outer_decider_circuit.check_circuit()); + EXPECT_FALSE(verified); + } }; 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); + 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); + Builder builder3; + create_function_circuit(builder3); + auto prover_inst = composer.create_prover_instance(builder3); + auto verifier_inst = composer.create_verifier_instance(prover_inst); - // Tamper with the accumulator - instances = std::vector>{ accumulator, instance3 }; - accumulator->prover_polynomials.w_l[1] = FF::random_element(); + prover_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(); + 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 - 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 folding_circuit; + FoldingRecursiveVerifier verifier{ &folding_circuit, + verifier_accumulator, + { verifier_inst->verification_key } }; + auto recursive_verifier_acc = verifier.verify_folding_proof(folding_proof.folding_data); + 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 000000000000..86aa1013ee9c --- /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, + std::shared_ptr accumulator, + 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 000000000000..f708c2274abc --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp @@ -0,0 +1,153 @@ +#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; + + size_t public_input_idx = 0; + inst.public_inputs = std::vector(public_input_size); + for (auto public_input : public_inputs) { + inst.public_inputs[public_input_idx] = public_input.get_value(); + public_input_idx++; + } + inst.verification_key = std::make_shared(instance_size, public_input_size); + size_t vk_idx = 0; + for (auto& vk : verification_key->get_all()) { + inst.verification_key->get_all()[vk_idx] = vk.get_value(); + vk_idx++; + } + for (size_t alpha_idx = 0; alpha_idx < alphas.size(); alpha_idx++) { + inst.alphas[alpha_idx] = alphas[alpha_idx].get_value(); + } + + size_t comm_idx = 0; + for (auto& comm : witness_commitments.get_all()) { + inst.witness_commitments.get_all()[comm_idx] = comm.get_value(); + comm_idx++; + } + inst.target_sum = target_sum.get_value(); + + size_t challenge_idx = 0; + inst.gate_challenges = std::vector(gate_challenges.size()); + for (auto& challenge : inst.gate_challenges) { + challenge = gate_challenges[challenge_idx].get_value(); + challenge_idx++; + } + 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 7203a67a2c26..cef987ae9da1 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,21 @@ 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 verification_key = inner_composer.compute_verification_key(instance); auto prover = inner_composer.create_prover(instance); // A prerequisite for computing VK // 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,13 +161,14 @@ 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 verification_key = inner_composer.compute_verification_key(instance); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; auto pairing_points = verifier.verify_proof(inner_proof); info("Recursive Verifier Ultra: num gates = ", outer_circuit.num_gates); @@ -175,7 +177,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(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 +194,10 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -216,7 +219,8 @@ 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 verification_key = inner_composer.compute_verification_key(instance); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); @@ -228,7 +232,7 @@ template class RecursiveVerifierTest : public testing::Te // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; verifier.verify_proof(inner_proof); // We expect the circuit check to fail due to the bad proof diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp index a84f89db403b..f4ee368b7f6f 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_(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 d2b8da8f28e0..9eadb6fd1210 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; @@ -34,7 +33,6 @@ template class ProverInstance_ { public: std::shared_ptr proving_key; - std::shared_ptr verification_key; ProverPolynomials prover_polynomials; WitnessCommitments witness_commitments; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp index 9ba56880f84c..01328e4dc6b2 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; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp index 8f308808749f..4e2cc85c4dc1 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp @@ -239,9 +239,22 @@ template class SumcheckProverRound { const FF& scaling_factor) { using Relation = std::tuple_element_t; - Relation::accumulate( - std::get(univariate_accumulators), extended_edges, relation_parameters, scaling_factor); + // Check if the relation has a skip function to speed up accumulation + if constexpr (!isSkippable) { + + // If not, accumulate normally + Relation::accumulate( + std::get(univariate_accumulators), extended_edges, relation_parameters, scaling_factor); + } else { + // If it has the skip function, only accumulate if it returns false + if (!Relation::skip(extended_edges)) { + Relation::accumulate(std::get(univariate_accumulators), + extended_edges, + relation_parameters, + scaling_factor); + } + } // Repeat for the next relation. if constexpr (relation_idx + 1 < NUM_RELATIONS) { accumulate_relation_univariates( 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 bbec6530151e..d8759ba07a0f 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,11 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(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 7252076bab7f..ef4938a58511 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,10 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(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 5e97fd5bfaf8..6190d640ac1b 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,13 @@ 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 verification_key = composer.compute_verification_key(instance); 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(verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -223,10 +224,11 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(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 42f5757c1e39..895aba6c4128 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; @@ -33,7 +35,7 @@ template class ProtoGalaxyTests : public testing::Test { static void construct_circuit(Builder& builder) { if constexpr (IsGoblinFlavor) { - GoblinMockCircuits::construct_arithmetic_circuit(builder); + GoblinMockCircuits::construct_arithmetic_circuit(builder, 200); GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); } else { @@ -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); @@ -101,8 +105,8 @@ template class ProtoGalaxyTests : public testing::Test { /** * @brief For a valid circuit, ensures that computing the value of the full UH/UGH relation at each row in its - * execution trace (with the contribution of the linearly dependent one added tot he first row, in case of Goblin) - * will be 0. + * execution trace (with the contribution of the linearly dependent one added tot he first row, in case of + * Goblin) will be 0. * */ static void test_full_honk_evaluations_valid_circuit() @@ -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(); @@ -136,8 +140,8 @@ template class ProtoGalaxyTests : public testing::Test { } /** - * @brief Check the coefficients of the perturbator computed from dummy \vec{β}, \vec{δ} and f_i(ω) will be the same - * as if computed manually. + * @brief Check the coefficients of the perturbator computed from dummy \vec{β}, \vec{δ} and f_i(ω) will be the + * same as if computed manually. * */ static void test_pertubator_coefficients() @@ -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; @@ -206,8 +210,8 @@ template class ProtoGalaxyTests : public testing::Test { } /** - * @brief Manually compute the expected evaluations of the combiner quotient, given evaluations of the combiner and - * check them against the evaluations returned by the function. + * @brief Manually compute the expected evaluations of the combiner quotient, given evaluations of the combiner + * and check them against the evaluations returned by the function. * */ static void test_combiner_quotient() @@ -239,25 +243,22 @@ template class ProtoGalaxyTests : public testing::Test { } /** - * @brief For two dummy instances with their relation parameter η set, check that combining them in a univariate, - * barycentrially extended to the desired number of evaluations, is performed correctly. + * @brief For two dummy instances with their relation parameter η set, check that combining them in a + * univariate, barycentrially extended to the desired number of evaluations, is performed correctly. * */ 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 2b5ec50f37e3..a52bbbe240be 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 1ec8602c4fb4..345155089313 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 ae42bd4366ae..1ed884e8830f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp @@ -12,12 +12,9 @@ namespace bb { * @return Pointer to the resulting verification key of the Instance. * */ template -void UltraComposer_::compute_verification_key(const std::shared_ptr>& instance) +std::shared_ptr UltraComposer_::compute_verification_key( + const std::shared_ptr>& instance) { - if (instance->verification_key) { - return; - } - auto& proving_key = instance->proving_key; auto verification_key = @@ -61,23 +58,31 @@ void UltraComposer_::compute_verification_key(const std::shared_ptrq_poseidon2_internal = commitment_key->commit(proving_key->q_poseidon2_internal); } - instance->verification_key = std::move(verification_key); + return verification_key; } template -std::shared_ptr> UltraComposer_::create_instance(CircuitBuilder& circuit) +std::shared_ptr> UltraComposer_::create_prover_instance(CircuitBuilder& circuit) { circuit.add_gates_to_ensure_all_polys_are_non_zero(); circuit.finalize_circuit(); - auto instance = std::make_shared(circuit); - commitment_key = compute_commitment_key(instance->proving_key->circuit_size); + auto instance = std::make_shared(circuit); + instance->instance_size = instance->proving_key->circuit_size; + commitment_key = compute_commitment_key(instance->instance_size); // hm + return instance; +} - compute_verification_key(instance); +template +std::shared_ptr> UltraComposer_::create_verifier_instance( + std::shared_ptr>& prover_instance) +{ + auto instance = std::make_shared(); + instance->verification_key = compute_verification_key(prover_instance); return instance; } template -UltraProver_ UltraComposer_::create_prover(const std::shared_ptr& instance, +UltraProver_ UltraComposer_::create_prover(const std::shared_ptr& instance, const std::shared_ptr& transcript) { UltraProver_ output_state(instance, commitment_key, transcript); @@ -86,10 +91,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); @@ -98,7 +102,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); @@ -109,7 +113,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) { @@ -119,11 +123,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 28a95f03145a..66ca19c1fb00 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, commitment_key); 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; }; @@ -102,7 +110,7 @@ template class UltraComposer_ { * * @param inst */ - void compute_verification_key(const std::shared_ptr&); + std::shared_ptr compute_verification_key(const std::shared_ptr&); }; // TODO(#532): this pattern is weird; is this not instantiating the templates? 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 205a67aad242..514b2b69783b 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,10 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); EXPECT_EQ(verified, expected_result); @@ -67,7 +68,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 +199,10 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(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 fd6ccf7c1483..1e5409c1e283 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,13 @@ 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 verification_key = composer.compute_verification_key(instance); 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(verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -209,10 +210,11 @@ 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 verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid