diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp index 1e436faba75d..b475bfd8d2ad 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp @@ -3,6 +3,7 @@ #include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/client_ivc/test_bench_shared.hpp" #include "barretenberg/common/test.hpp" +#include "barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp" namespace bb::stdlib::recursion::honk { class ClientIVCRecursionTests : public testing::Test { @@ -11,9 +12,9 @@ class ClientIVCRecursionTests : public testing::Test { using ClientIVCVerifier = ClientIVCRecursiveVerifier; using FoldVerifierInput = ClientIVCVerifier::FoldVerifierInput; using Proof = ClientIVC::Proof; - using Flavor = UltraRollupRecursiveFlavor_; - using NativeFlavor = Flavor::NativeFlavor; - using UltraRecursiveVerifier = UltraRecursiveVerifier_; + using RollupFlavor = UltraRollupRecursiveFlavor_; + using NativeFlavor = RollupFlavor::NativeFlavor; + using UltraRecursiveVerifier = UltraRecursiveVerifier_; using MockCircuitProducer = PrivateFunctionExecutionMockCircuitProducer; using IVCVerificationKey = ClientIVC::VerificationKey; @@ -34,11 +35,11 @@ class ClientIVCRecursionTests : public testing::Test { * @brief Construct a genuine ClientIVC prover output based on accumulation of an arbitrary set of mock circuits * */ - static ClientIVCProverOutput construct_client_ivc_prover_output(ClientIVC& ivc) + static ClientIVCProverOutput construct_client_ivc_prover_output(ClientIVC& ivc, const size_t NUM_CIRCUITS = 2) { // Construct and accumulate a series of mocked private function execution circuits MockCircuitProducer circuit_producer; - size_t NUM_CIRCUITS = 2; + for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { auto circuit = circuit_producer.create_next_circuit(ivc); ivc.accumulate(circuit); @@ -120,6 +121,7 @@ TEST_F(ClientIVCRecursionTests, ClientTubeBase) // Construct and verify a proof for the ClientIVC Recursive Verifier circuit auto proving_key = std::make_shared>(*tube_builder); UltraProver_ tube_prover{ proving_key }; + // Prove the CIVCRecursiveVerifier circuit auto native_tube_proof = tube_prover.construct_proof(); // Natively verify the tube proof @@ -130,13 +132,13 @@ TEST_F(ClientIVCRecursionTests, ClientTubeBase) // Construct a base rollup circuit that recursively verifies the tube proof and forwards the IPA proof. Builder base_builder; - auto native_vk = std::make_shared(proving_key->proving_key); - auto vk = std::make_shared(&base_builder, native_vk); - auto tube_proof = bb::convert_native_proof_to_stdlib(&base_builder, native_tube_proof); - UltraRecursiveVerifier base_verifier{ &base_builder, vk }; - UltraRecursiveVerifierOutput output = base_verifier.verify_proof( - tube_proof, stdlib::recursion::init_default_aggregation_state(base_builder)); - info("UH Recursive Verifier: num prefinalized gates = ", base_builder.num_gates); + auto tube_vk = std::make_shared(proving_key->proving_key); + auto base_vk = std::make_shared(&base_builder, tube_vk); + auto base_tube_proof = bb::convert_native_proof_to_stdlib(&base_builder, native_tube_proof); + UltraRecursiveVerifier base_verifier{ &base_builder, base_vk }; + UltraRecursiveVerifierOutput output = base_verifier.verify_proof( + base_tube_proof, stdlib::recursion::init_default_aggregation_state(base_builder)); + info("Tube UH Recursive Verifier: num prefinalized gates = ", base_builder.num_gates); base_builder.add_pairing_point_accumulator(output.agg_obj.get_witness_indices()); base_builder.add_ipa_claim(output.ipa_opening_claim.get_witness_indices()); base_builder.ipa_proof = tube_prover.proving_key->proving_key.ipa_proof; @@ -150,4 +152,48 @@ TEST_F(ClientIVCRecursionTests, ClientTubeBase) ipa_verification_key, output.ipa_opening_claim.get_native_opening_claim(), ipa_transcript); } +// Ensure that the Client IVC Recursive Verifier Circuit does not depend on the Client IVC input +TEST_F(ClientIVCRecursionTests, TubeVKIndependentOfInputCircuits) +{ + + // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit + auto get_blocks = [](size_t inner_size) + -> std::tuple> { + ClientIVC ivc{ trace_settings }; + + auto [proof, ivc_vk] = construct_client_ivc_prover_output(ivc, inner_size); + + auto tube_builder = std::make_shared(); + ClientIVCVerifier verifier{ tube_builder, ivc_vk }; + + auto client_ivc_rec_verifier_output = verifier.verify(proof); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1069): fix this by taking it from the output + // instead of + // just using default. + tube_builder->add_pairing_point_accumulator( + stdlib::recursion::init_default_agg_obj_indices(*tube_builder)); + // The tube only calls an IPA recursive verifier once, so we can just add this IPA claim and proof + tube_builder->add_ipa_claim(client_ivc_rec_verifier_output.opening_claim.get_witness_indices()); + tube_builder->ipa_proof = + convert_stdlib_proof_to_native(client_ivc_rec_verifier_output.ipa_transcript->proof_data); + + info("ClientIVC Recursive Verifier: num prefinalized gates = ", tube_builder->num_gates); + + EXPECT_EQ(tube_builder->failed(), false) << tube_builder->err(); + + // Construct and verify a proof for the ClientIVC Recursive Verifier circuit + auto proving_key = std::make_shared>(*tube_builder); + + auto tube_vk = std::make_shared(proving_key->proving_key); + + return { tube_builder->blocks, tube_vk }; + }; + + auto [blocks_2, verification_key_2] = get_blocks(2); + auto [blocks_4, verification_key_4] = get_blocks(4); + + compare_ultra_blocks_and_verification_keys({ blocks_2, blocks_4 }, + { verification_key_2, verification_key_4 }); +} } // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp index d180fe037fa5..88dadca19764 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.test.cpp @@ -2,6 +2,7 @@ #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/eccvm/eccvm_prover.hpp" #include "barretenberg/eccvm/eccvm_verifier.hpp" +#include "barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -20,6 +21,8 @@ template class ECCVMRecursiveTests : public ::testing using InnerG1 = InnerFlavor::Commitment; using InnerFF = InnerFlavor::FF; using InnerBF = InnerFlavor::BF; + using InnerPK = InnerFlavor::ProvingKey; + using InnerVK = InnerFlavor::VerificationKey; using Transcript = InnerFlavor::Transcript; @@ -42,7 +45,7 @@ template class ECCVMRecursiveTests : public ::testing * @param engine * @return ECCVMCircuitBuilder */ - static InnerBuilder generate_circuit(numeric::RNG* engine = nullptr) + static InnerBuilder generate_circuit(numeric::RNG* engine = nullptr, const size_t num_iterations = 1) { using Curve = curve::BN254; using G1 = Curve::Element; @@ -54,21 +57,22 @@ template class ECCVMRecursiveTests : public ::testing G1 c = G1::random_element(engine); Fr x = Fr::random_element(engine); Fr y = Fr::random_element(engine); - - op_queue->add_accumulate(a); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->mul_accumulate(b, y); - op_queue->add_accumulate(a); - op_queue->mul_accumulate(b, x); - op_queue->eq_and_reset(); - op_queue->add_accumulate(c); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->eq_and_reset(); - op_queue->mul_accumulate(a, x); - op_queue->mul_accumulate(b, x); - op_queue->mul_accumulate(c, x); + for (size_t idx = 0; idx < num_iterations; idx++) { + op_queue->add_accumulate(a); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->mul_accumulate(b, y); + op_queue->add_accumulate(a); + op_queue->mul_accumulate(b, x); + op_queue->eq_and_reset(); + op_queue->add_accumulate(c); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->eq_and_reset(); + op_queue->mul_accumulate(a, x); + op_queue->mul_accumulate(b, x); + op_queue->mul_accumulate(c, x); + } InnerBuilder builder{ op_queue }; return builder; } @@ -140,6 +144,40 @@ template class ECCVMRecursiveTests : public ::testing // Check for a failure flag in the recursive verifier circuit EXPECT_FALSE(CircuitChecker::check(outer_circuit)); } + + static void test_independent_vk_hash() + { + + // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit + auto get_blocks = [](size_t inner_size) -> std::tuple> { + auto inner_circuit = generate_circuit(&engine, inner_size); + InnerProver inner_prover(inner_circuit); + info("test circuit size: ", inner_prover.key->circuit_size); + + ECCVMProof inner_proof = inner_prover.construct_proof(); + auto verification_key = std::make_shared(inner_prover.key); + + // Create a recursive verification circuit for the proof of the inner circuit + OuterBuilder outer_circuit; + + RecursiveVerifier verifier{ &outer_circuit, verification_key }; + + auto [opening_claim, ipa_transcript] = verifier.verify_proof(inner_proof); + + auto outer_proving_key = std::make_shared(outer_circuit); + auto outer_verification_key = + std::make_shared(outer_proving_key->proving_key); + + return { outer_circuit.blocks, outer_verification_key }; + }; + + auto [blocks_20, verification_key_20] = get_blocks(20); + auto [blocks_40, verification_key_40] = get_blocks(40); + + compare_ultra_blocks_and_verification_keys({ blocks_20, blocks_40 }, + { verification_key_20, verification_key_40 }); + }; }; using FlavorTypes = testing::Types>; @@ -154,4 +192,9 @@ TYPED_TEST(ECCVMRecursiveTests, SingleRecursiveVerificationFailure) { TestFixture::test_recursive_verification_failure(); }; + +TYPED_TEST(ECCVMRecursiveTests, IndependentVKHash) +{ + TestFixture::test_independent_vk_hash(); +}; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp index 5e854a677a1a..591a80722d02 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp @@ -7,6 +7,7 @@ #include "barretenberg/stdlib_circuit_builders/ultra_rollup_recursive_flavor.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" +#include "ultra_verification_keys_comparator.hpp" namespace bb::stdlib::recursion::honk { @@ -137,7 +138,7 @@ template class RecursiveVerifierTest : public testing /** * @brief Ensures that the recursive verifier circuit for two inner circuits of different size is the same as the - * proofs are currently constant. This is done by taking each trace block in part and checking all it's selector + * proofs are currently constant. This is done by taking each trace block in part and checking all its selector * values. * */ @@ -160,7 +161,6 @@ template class RecursiveVerifierTest : public testing // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; RecursiveVerifier verifier{ &outer_circuit, verification_key }; - HonkProof honk_proof; typename RecursiveVerifier::Output verifier_output = verifier.verify_proof( inner_proof, @@ -177,44 +177,11 @@ template class RecursiveVerifierTest : public testing return { outer_circuit.blocks, outer_verification_key }; }; - bool broke(false); - auto check_eq = [&broke](auto& p1, auto& p2) { - EXPECT_TRUE(p1.size() == p2.size()); - for (size_t idx = 0; idx < p1.size(); idx++) { - if (p1[idx] != p2[idx]) { - broke = true; - break; - } - } - }; - auto [blocks_10, verification_key_10] = get_blocks(10); auto [blocks_11, verification_key_11] = get_blocks(11); - size_t block_idx = 0; - for (auto [b_10, b_11] : zip_view(blocks_10.get(), blocks_11.get())) { - info("block index: ", block_idx); - EXPECT_TRUE(b_10.selectors.size() == 13); - EXPECT_TRUE(b_11.selectors.size() == 13); - for (auto [p_10, p_11] : zip_view(b_10.selectors, b_11.selectors)) { - check_eq(p_10, p_11); - } - block_idx++; - } - - typename OuterFlavor::CommitmentLabels labels; - for (auto [vk_10, vk_11, label] : - zip_view(verification_key_10->get_all(), verification_key_11->get_all(), labels.get_precomputed())) { - if (vk_10 != vk_11) { - broke = true; - info("Mismatch verification key label: ", label, " left: ", vk_10, " right: ", vk_11); - } - } - - EXPECT_TRUE(verification_key_10->circuit_size == verification_key_11->circuit_size); - EXPECT_TRUE(verification_key_10->num_public_inputs == verification_key_11->num_public_inputs); - - EXPECT_FALSE(broke); + compare_ultra_blocks_and_verification_keys({ blocks_10, blocks_11 }, + { verification_key_10, verification_key_11 }); } /** @@ -360,7 +327,8 @@ HEAVY_TYPED_TEST(RecursiveVerifierTest, IndependentVKHash) { if constexpr (IsAnyOf, - UltraRollupRecursiveFlavor_>) { + UltraRollupRecursiveFlavor_, + MegaZKRecursiveFlavor_>) { TestFixture::test_independent_vk_hash(); } else { GTEST_SKIP() << "Not built for this parameter"; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp new file mode 100644 index 000000000000..20b1ca212101 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp @@ -0,0 +1,57 @@ + + +#include "barretenberg/common/assert.hpp" +#include "barretenberg/common/log.hpp" +#include +#include +namespace bb { + +template +static void compare_ultra_blocks_and_verification_keys( + std::array blocks, + std::array, 2> verification_keys) +{ + + // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit + + bool broke(false); + auto check_eq = [&broke](auto& p1, auto& p2, size_t block_idx, size_t selector_idx) { + ASSERT(p1.size() == p2.size()); + for (size_t idx = 0; idx < p1.size(); idx++) { + if (p1[idx] != p2[idx]) { + info("Mismatch selector ", selector_idx, " in block ", block_idx, ", at ", idx); + broke = true; + break; + } + } + }; + + size_t block_idx = 0; + for (auto [block_0, block_1] : zip_view(blocks[0].get(), blocks[1].get())) { + ASSERT(block_0.selectors.size() == 13); + ASSERT(block_1.selectors.size() == 13); + size_t selector_idx = 0; + for (auto [p_10, p_11] : zip_view(block_0.selectors, block_1.selectors)) { + check_eq(p_10, p_11, block_idx, selector_idx); + selector_idx++; + } + block_idx++; + } + + typename OuterFlavor::CommitmentLabels labels; + for (auto [vk_0, vk_1, label] : + zip_view(verification_keys[0]->get_all(), verification_keys[1]->get_all(), labels.get_precomputed())) { + if (vk_0 != vk_1) { + broke = true; + info("Mismatch verification key label: ", label, " left: ", vk_0, " right: ", vk_1); + } + } + + ASSERT(verification_keys[0]->circuit_size == verification_keys[1]->circuit_size); + ASSERT(verification_keys[0]->num_public_inputs == verification_keys[1]->num_public_inputs); + ASSERT(verification_keys[0]->pub_inputs_offset == verification_keys[1]->pub_inputs_offset); + + ASSERT(!broke); +} + +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp index 9e7c0d5745d3..abe273f388c5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp @@ -1,10 +1,6 @@ #include "barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp" #include "barretenberg/common/log.hpp" -#include "barretenberg/numeric/uint256/uint256.hpp" -#include "barretenberg/relations/relation_parameters.hpp" -#include "barretenberg/sumcheck/sumcheck_round.hpp" -#include "barretenberg/translator_vm/translator_circuit_builder.hpp" -#include "barretenberg/translator_vm/translator_prover.hpp" +#include "barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp" #include "barretenberg/translator_vm/translator_verifier.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -44,7 +40,7 @@ template class TranslatorRecursiveTests : public ::te static void SetUpTestSuite() { bb::srs::init_crs_factory(bb::srs::get_ignition_crs_path()); } - static void test_recursive_verification() + static std::shared_ptr create_op_queue(const size_t num_ops) { auto P1 = InnerG1::random_element(); auto P2 = InnerG1::random_element(); @@ -54,10 +50,17 @@ template class TranslatorRecursiveTests : public ::te auto op_queue = std::make_shared(); op_queue->append_nonzero_ops(); - for (size_t i = 0; i < 500; i++) { + for (size_t i = 0; i < num_ops; i++) { op_queue->add_accumulate(P1); op_queue->mul_accumulate(P2, z); } + return op_queue; + } + + static void test_recursive_verification() + { + // Add the same operations to the ECC op queue; the native computation is performed under the hood. + auto op_queue = create_op_queue(500); auto prover_transcript = std::make_shared(); prover_transcript->send_to_verifier("init", InnerBF::random_element()); @@ -121,6 +124,60 @@ template class TranslatorRecursiveTests : public ::te ASSERT(verified); } } + + static void test_independent_vk_hash() + { + + // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit + auto get_blocks = [](size_t num_ops) -> std::tuple> { + auto op_queue = create_op_queue(num_ops); + + auto prover_transcript = std::make_shared(); + prover_transcript->send_to_verifier("init", InnerBF::random_element()); + + // normally this would be the eccvm proof + auto fake_inital_proof = prover_transcript->export_proof(); + InnerBF translation_batching_challenge = + prover_transcript->template get_challenge("Translation:batching_challenge"); + InnerBF translation_evaluation_challenge = InnerBF::random_element(); + + auto inner_circuit = + InnerBuilder(translation_batching_challenge, translation_evaluation_challenge, op_queue); + + // Generate a proof over the inner circuit + auto inner_proving_key = std::make_shared(inner_circuit); + InnerProver inner_prover(inner_proving_key, prover_transcript); + info("test circuit size: ", inner_proving_key->proving_key->circuit_size); + auto verification_key = + std::make_shared(inner_prover.key->proving_key); + auto inner_proof = inner_prover.construct_proof(); + + // Create a recursive verification circuit for the proof of the inner circuit + OuterBuilder outer_circuit; + + // Mock a previous verifier that would in reality be the ECCVM recursive verifier + StdlibProof stdlib_proof = + bb::convert_native_proof_to_stdlib(&outer_circuit, fake_inital_proof); + auto transcript = std::make_shared(stdlib_proof); + transcript->template receive_from_prover("init"); + + RecursiveVerifier verifier{ &outer_circuit, verification_key, transcript }; + verifier.verify_proof(inner_proof); + + auto outer_proving_key = std::make_shared(outer_circuit); + auto outer_verification_key = + std::make_shared(outer_proving_key->proving_key); + + return { outer_circuit.blocks, outer_verification_key }; + }; + + auto [blocks_256, verification_key_256] = get_blocks(256); + auto [blocks_512, verification_key_512] = get_blocks(512); + + compare_ultra_blocks_and_verification_keys({ blocks_256, blocks_512 }, + { verification_key_256, verification_key_512 }); + }; }; using FlavorTypes = testing::Types, @@ -133,4 +190,13 @@ TYPED_TEST(TranslatorRecursiveTests, SingleRecursiveVerification) { TestFixture::test_recursive_verification(); }; + +TYPED_TEST(TranslatorRecursiveTests, IndependentVKHash) +{ + if constexpr (std::is_same_v>) { + TestFixture::test_independent_vk_hash(); + } else { + GTEST_SKIP() << "Not built for this parameter"; + } +}; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 4a5444bb43c2..dd12305bc436 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -547,27 +547,27 @@ polynomials that are sent in clear. * * For \f$ i = 0,\ldots, d-1\f$: * - Extract Round Univariate's \f$\tilde{F}\f$ evaluations at \f$0,\ldots, D \f$ from the transcript using \ref - bb::BaseTranscript::receive_from_prover "receive_from_prover" method from \ref bb::BaseTranscript< TranscriptParams > - "Base Transcript Class". +bb::BaseTranscript::receive_from_prover "receive_from_prover" method from \ref bb::BaseTranscript< TranscriptParams > +"Base Transcript Class". * - \ref bb::SumcheckVerifierRound< Flavor >::check_sum "Check target sum": \f$\quad \sigma_{ i } \stackrel{?}{=} \tilde{S}^i(0) + \tilde{S}^i(1) \f$ - * - Compute the challenge \f$u_i\f$ from the transcript using \ref bb::BaseTranscript::get_challenge "get_challenge" - method. - * - \ref bb::SumcheckVerifierRound< Flavor >::compute_next_target_sum "Compute next target sum" :\f$ \quad \sigma_{i+1} - \gets \tilde{S}^i(u_i) \f$ +* - Compute the challenge \f$u_i\f$ from the transcript using \ref bb::BaseTranscript::get_challenge "get_challenge" +method. +* - \ref bb::SumcheckVerifierRound< Flavor >::compute_next_target_sum "Compute next target sum" :\f$ \quad \sigma_{i+1} +\gets \tilde{S}^i(u_i) \f$ * ### Verifier's Data before Final Step - * Entering the final round, the Verifier has already checked that \f$\quad \sigma_{ d-1 } = \tilde{S}^{d-2}(u_{d-2}) - \stackrel{?}{=} \tilde{S}^{d-1}(0) + \tilde{S}^{d-1}(1) \f$ and computed \f$\sigma_d = \tilde{S}^{d-1}(u_{d-1})\f$. +* Entering the final round, the Verifier has already checked that \f$\quad \sigma_{ d-1 } = \tilde{S}^{d-2}(u_{d-2}) +\stackrel{?}{=} \tilde{S}^{d-1}(0) + \tilde{S}^{d-1}(1) \f$ and computed \f$\sigma_d = \tilde{S}^{d-1}(u_{d-1})\f$. * ### Final Verification Step * - Extract \ref ClaimedEvaluations of prover polynomials \f$P_1,\ldots, P_N\f$ at the challenge point \f$ (u_0,\ldots,u_{d-1}) \f$ from the transcript and \ref bb::SumcheckVerifierRound< Flavor >::compute_full_relation_purported_value "compute evaluation:" \f{align}{\tilde{F}\left( P_1(u_0,\ldots, u_{d-1}), \ldots, P_N(u_0,\ldots, u_{d-1}) \right)\f} and store it at \f$ \texttt{full_honk_relation_purported_value} \f$. - * - Compare \f$ \sigma_d \f$ against the evaluation of \f$ \tilde{F} \f$ at \f$P_1(u_0,\ldots, u_{d-1}), \ldots, - P_N(u_0,\ldots, u_{d-1})\f$: - * \f{align}{\quad \sigma_{ d } \stackrel{?}{=} \tilde{F}\left(P_1(u_{0}, \ldots, u_{d-1}),\ldots, P_N(u_0,\ldots, - u_{d-1})\right)\f} +* - Compare \f$ \sigma_d \f$ against the evaluation of \f$ \tilde{F} \f$ at \f$P_1(u_0,\ldots, u_{d-1}), \ldots, +P_N(u_0,\ldots, u_{d-1})\f$: +* \f{align}{\quad \sigma_{ d } \stackrel{?}{=} \tilde{F}\left(P_1(u_{0}, \ldots, u_{d-1}),\ldots, P_N(u_0,\ldots, +u_{d-1})\right)\f} \snippet cpp/src/barretenberg/sumcheck/sumcheck.hpp Final Verification Step @@ -612,6 +612,8 @@ template class SumcheckVerifier { FF libra_challenge; FF libra_total_sum; + FF correcting_factor; + std::vector round_univariate_commitments = {}; std::vector> round_univariate_evaluations = {}; @@ -705,8 +707,15 @@ template class SumcheckVerifier { // For ZK Flavors: the evaluation of the Row Disabling Polynomial at the sumcheck challenge if constexpr (Flavor::HasZK) { libra_evaluation = transcript->template receive_from_prover("Libra:claimed_evaluation"); - FF correcting_factor = - RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); + if constexpr (!IsRecursiveFlavor) { + correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d); + } else { + typename Flavor::CircuitBuilder* builder = libra_evaluation.get_context(); + correcting_factor = + RowDisablingPolynomial::evaluate_at_challenge(multivariate_challenge, multivariate_d, builder); + } + full_honk_purported_value = full_honk_purported_value * correcting_factor + libra_evaluation * libra_challenge; }