diff --git a/barretenberg/cpp/src/barretenberg/api/api_chonk.cpp b/barretenberg/cpp/src/barretenberg/api/api_chonk.cpp index c7ef0746710b..20347f652292 100644 --- a/barretenberg/cpp/src/barretenberg/api/api_chonk.cpp +++ b/barretenberg/cpp/src/barretenberg/api/api_chonk.cpp @@ -115,6 +115,36 @@ bool ChonkAPI::verify([[maybe_unused]] const Flags& flags, return response.valid; } +bool ChonkAPI::batch_verify([[maybe_unused]] const Flags& flags, const std::filesystem::path& proofs_dir) +{ + BB_BENCH_NAME("ChonkAPI::batch_verify"); + + std::vector proofs; + std::vector> vks; + + for (size_t i = 0;; ++i) { + auto proof_file = proofs_dir / ("proof_" + std::to_string(i)); + auto vk_file = proofs_dir / ("vk_" + std::to_string(i)); + + if (!std::filesystem::exists(proof_file) || !std::filesystem::exists(vk_file)) { + break; + } + + auto proof_fields = many_from_buffer(read_file(proof_file)); + proofs.push_back(ChonkProof::from_field_elements(proof_fields)); + vks.push_back(read_vk_file(vk_file)); + } + + if (proofs.empty()) { + throw_or_abort("batch_verify: no proof_0/vk_0 pairs found in " + proofs_dir.string()); + } + + info("ChonkAPI::batch_verify - found ", proofs.size(), " proof/vk pairs in ", proofs_dir.string()); + + auto response = bbapi::ChonkBatchVerify{ .proofs = std::move(proofs), .vks = std::move(vks) }.execute(); + return response.valid; +} + // WORKTODO(bbapi) remove this bool ChonkAPI::prove_and_verify(const std::filesystem::path& input_path) { diff --git a/barretenberg/cpp/src/barretenberg/api/api_chonk.hpp b/barretenberg/cpp/src/barretenberg/api/api_chonk.hpp index 877896c38969..f14e03810253 100644 --- a/barretenberg/cpp/src/barretenberg/api/api_chonk.hpp +++ b/barretenberg/cpp/src/barretenberg/api/api_chonk.hpp @@ -81,6 +81,14 @@ class ChonkAPI : public API { const std::filesystem::path& bytecode_path, const std::filesystem::path& output_path) override; + /** + * @brief Batch-verify multiple Chonk proofs from a directory of proof_N/vk_N pairs. + * + * @param proofs_dir Directory containing proof_0/vk_0, proof_1/vk_1, ... + * @return true if all proofs verify + */ + bool batch_verify(const Flags& flags, const std::filesystem::path& proofs_dir); + /** * @brief Validate that precomputed VKs in ivc-inputs.msgpack match computed VKs. * diff --git a/barretenberg/cpp/src/barretenberg/bb/cli.cpp b/barretenberg/cpp/src/barretenberg/bb/cli.cpp index 4474232d6cf5..f3bd856c9fcd 100644 --- a/barretenberg/cpp/src/barretenberg/bb/cli.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/cli.cpp @@ -519,6 +519,20 @@ int parse_and_run_cli_command(int argc, char* argv[]) remove_zk_option(verify); add_ipa_accumulation_flag(verify); + /*************************************************************************************************************** + * Subcommand: batch_verify + ***************************************************************************************************************/ + std::filesystem::path batch_verify_proofs_dir{ "./proofs" }; + CLI::App* batch_verify = + app.add_subcommand("batch_verify", "Batch-verify multiple Chonk proofs with a single IPA SRS MSM."); + + add_help_extended_flag(batch_verify); + add_scheme_option(batch_verify); + batch_verify->add_option("--proofs_dir", batch_verify_proofs_dir, "Directory containing proof_N/vk_N pairs."); + add_verbose_flag(batch_verify); + add_debug_flag(batch_verify); + add_crs_path_option(batch_verify); + /*************************************************************************************************************** * Subcommand: write_solidity_verifier ***************************************************************************************************************/ @@ -954,6 +968,11 @@ int parse_and_run_cli_command(int argc, char* argv[]) } return api.check_precomputed_vks(flags, ivc_inputs_path) ? 0 : 1; } + if (batch_verify->parsed()) { + const bool verified = api.batch_verify(flags, batch_verify_proofs_dir); + vinfo("batch verified: ", verified); + return verified ? 0 : 1; + } return execute_non_prove_command(api); } else if (flags.scheme == "ultra_honk") { UltraHonkAPI api; diff --git a/barretenberg/cpp/src/barretenberg/bbapi/bbapi.test.cpp b/barretenberg/cpp/src/barretenberg/bbapi/bbapi.test.cpp index 4ccd0199f02b..9c096e7c10a2 100644 --- a/barretenberg/cpp/src/barretenberg/bbapi/bbapi.test.cpp +++ b/barretenberg/cpp/src/barretenberg/bbapi/bbapi.test.cpp @@ -22,7 +22,8 @@ using Commands = ::testing::Types; + bbapi::ChonkCheckPrecomputedVk, + bbapi::ChonkBatchVerify>; // Typed test suites template class BBApiMsgpack : public ::testing::Test {}; diff --git a/barretenberg/cpp/src/barretenberg/bbapi/bbapi_chonk.cpp b/barretenberg/cpp/src/barretenberg/bbapi/bbapi_chonk.cpp index 0fb97f41e8cb..7be5bd4be250 100644 --- a/barretenberg/cpp/src/barretenberg/bbapi/bbapi_chonk.cpp +++ b/barretenberg/cpp/src/barretenberg/bbapi/bbapi_chonk.cpp @@ -1,4 +1,5 @@ #include "barretenberg/bbapi/bbapi_chonk.hpp" +#include "barretenberg/chonk/chonk_batch_verifier.hpp" #include "barretenberg/chonk/chonk_verifier.hpp" #include "barretenberg/chonk/mock_circuit_producer.hpp" #include "barretenberg/chonk/proof_compression.hpp" @@ -157,6 +158,43 @@ ChonkVerify::Response ChonkVerify::execute(const BBApiRequest& /*request*/) && return { .valid = verified }; } +ChonkBatchVerify::Response ChonkBatchVerify::execute(const BBApiRequest& /*request*/) && +{ + BB_BENCH_NAME(MSGPACK_SCHEMA_NAME); + + if (proofs.size() != vks.size()) { + throw_or_abort("ChonkBatchVerify: proofs.size() (" + std::to_string(proofs.size()) + ") != vks.size() (" + + std::to_string(vks.size()) + ")"); + } + if (proofs.empty()) { + throw_or_abort("ChonkBatchVerify: no proofs provided"); + } + + using VerificationKey = Chonk::MegaVerificationKey; + + std::vector inputs; + inputs.reserve(proofs.size()); + + for (size_t i = 0; i < proofs.size(); ++i) { + validate_vk_size(vks[i]); + auto hiding_kernel_vk = std::make_shared(from_buffer(vks[i])); + + const size_t expected_proof_size = + static_cast(hiding_kernel_vk->num_public_inputs) + ChonkProof::PROOF_LENGTH_WITHOUT_PUB_INPUTS; + if (proofs[i].size() != expected_proof_size) { + throw_or_abort("ChonkBatchVerify: proof[" + std::to_string(i) + "] has wrong size: expected " + + std::to_string(expected_proof_size) + ", got " + std::to_string(proofs[i].size())); + } + + auto vk_and_hash = std::make_shared(hiding_kernel_vk); + inputs.push_back({ .proof = std::move(proofs[i]), .vk_and_hash = std::move(vk_and_hash) }); + } + + const bool verified = ChonkBatchVerifier::verify(inputs); + + return { .valid = verified }; +} + static std::shared_ptr get_acir_program_prover_instance(acir_format::AcirProgram& program) { Chonk::ClientCircuit builder = acir_format::create_circuit(program); diff --git a/barretenberg/cpp/src/barretenberg/bbapi/bbapi_chonk.hpp b/barretenberg/cpp/src/barretenberg/bbapi/bbapi_chonk.hpp index d156a5a0c6c3..293a3282685a 100644 --- a/barretenberg/cpp/src/barretenberg/bbapi/bbapi_chonk.hpp +++ b/barretenberg/cpp/src/barretenberg/bbapi/bbapi_chonk.hpp @@ -239,6 +239,27 @@ struct ChonkStats { bool operator==(const ChonkStats&) const = default; }; +/** + * @struct ChonkBatchVerify + * @brief Batch-verify multiple Chonk proofs with a single IPA SRS MSM + */ +struct ChonkBatchVerify { + static constexpr const char MSGPACK_SCHEMA_NAME[] = "ChonkBatchVerify"; + + struct Response { + static constexpr const char MSGPACK_SCHEMA_NAME[] = "ChonkBatchVerifyResponse"; + bool valid; + MSGPACK_FIELDS(valid); + bool operator==(const Response&) const = default; + }; + + std::vector proofs; + std::vector> vks; + Response execute(const BBApiRequest& request = {}) &&; + MSGPACK_FIELDS(proofs, vks); + bool operator==(const ChonkBatchVerify&) const = default; +}; + /** * @struct ChonkCompressProof * @brief Compress a Chonk proof to a compact byte representation diff --git a/barretenberg/cpp/src/barretenberg/bbapi/bbapi_execute.hpp b/barretenberg/cpp/src/barretenberg/bbapi/bbapi_execute.hpp index ab16da99a508..7c2db20e993d 100644 --- a/barretenberg/cpp/src/barretenberg/bbapi/bbapi_execute.hpp +++ b/barretenberg/cpp/src/barretenberg/bbapi/bbapi_execute.hpp @@ -23,6 +23,7 @@ using Command = NamedUnion #include +#include "barretenberg/chonk/chonk_batch_verifier.hpp" #include "barretenberg/chonk/chonk_verifier.hpp" #include "barretenberg/chonk/proof_compression.hpp" #include "barretenberg/chonk/test_bench_shared.hpp" @@ -40,6 +41,7 @@ BENCHMARK_DEFINE_F(ChonkBench, VerificationOnly)(benchmark::State& state) auto [proof, vk_and_hash] = accumulate_and_prove_with_precomputed_vks(NUM_APP_CIRCUITS, precomputed_vks); for (auto _ : state) { + GOOGLE_BB_BENCH_REPORTER(state); ChonkNativeVerifier verifier(vk_and_hash); benchmark::DoNotOptimize(verifier.verify(proof)); } @@ -90,12 +92,53 @@ BENCHMARK_DEFINE_F(ChonkBench, ProofDecompress)(benchmark::State& state) } } +/** + * @brief Benchmark N individual Chonk verifications (sequential). Baseline for batch comparison. + */ +BENCHMARK_DEFINE_F(ChonkBench, VerifyIndividual)(benchmark::State& state) +{ + const size_t num_proofs = static_cast(state.range(0)); + auto precomputed_vks = precompute_vks(1); + + // Generate a single proof and reuse it N times + auto [proof, vk_and_hash] = accumulate_and_prove_with_precomputed_vks(1, precomputed_vks); + + for (auto _ : state) { + for (size_t i = 0; i < num_proofs; i++) { + ChonkNativeVerifier verifier(vk_and_hash); + benchmark::DoNotOptimize(verifier.verify(proof)); + } + } +} + +/** + * @brief Benchmark batch verification of N Chonk proofs (single SRS MSM). + */ +BENCHMARK_DEFINE_F(ChonkBench, BatchVerify)(benchmark::State& state) +{ + const size_t num_proofs = static_cast(state.range(0)); + auto precomputed_vks = precompute_vks(1); + + // Generate a single proof and reuse it N times + auto [proof, vk_and_hash] = accumulate_and_prove_with_precomputed_vks(1, precomputed_vks); + std::vector inputs(num_proofs); + for (size_t i = 0; i < num_proofs; i++) { + inputs[i] = { proof, vk_and_hash }; + } + + for (auto _ : state) { + benchmark::DoNotOptimize(ChonkBatchVerifier::verify(inputs)); + } +} + #define ARGS Arg(ChonkBench::NUM_ITERATIONS_MEDIUM_COMPLEXITY)->Arg(2) BENCHMARK_REGISTER_F(ChonkBench, Full)->Unit(benchmark::kMillisecond)->ARGS; BENCHMARK_REGISTER_F(ChonkBench, VerificationOnly)->Unit(benchmark::kMillisecond); BENCHMARK_REGISTER_F(ChonkBench, ProofCompress)->Unit(benchmark::kMillisecond); BENCHMARK_REGISTER_F(ChonkBench, ProofDecompress)->Unit(benchmark::kMillisecond); +BENCHMARK_REGISTER_F(ChonkBench, VerifyIndividual)->Unit(benchmark::kMillisecond)->Arg(1)->Arg(2)->Arg(4)->Arg(8); +BENCHMARK_REGISTER_F(ChonkBench, BatchVerify)->Unit(benchmark::kMillisecond)->Arg(1)->Arg(2)->Arg(4)->Arg(8); } // namespace diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp index 67242d17cf0a..8701df7313c1 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp @@ -66,6 +66,83 @@ void ipa_verify(State& state) noexcept BB_ASSERT(result); } } + +// Batch verification benchmarks: compare N individual verifications vs one batch verification. +// Uses default IPA poly_length (ECCVM size = 2^17) to match real Chonk usage. + +// Pre-generated single proof for batch benchmarks (reused N times to avoid expensive setup) +OpeningClaim batch_claim; +HonkProof batch_proof_data_single; + +static void DoBatchSetup(const benchmark::State&) +{ + srs::init_file_crs_factory(srs::bb_crs_path()); + static constexpr size_t BENCH_POLY_LENGTH = IPA::poly_length; + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + + ck = CommitmentKey(BENCH_POLY_LENGTH); + vk = VerifierCommitmentKey(BENCH_POLY_LENGTH, srs::get_grumpkin_crs_factory()); + + numeric::RNG& engine = numeric::get_debug_randomness(); + Polynomial poly(BENCH_POLY_LENGTH); + for (size_t j = 0; j < BENCH_POLY_LENGTH; j++) { + poly.at(j) = Fr::random_element(&engine); + } + auto x = Fr::random_element(&engine); + auto eval = poly.evaluate(x); + batch_claim = { { x, eval }, ck.commit(poly) }; + + auto pt = std::make_shared(); + IPA::compute_opening_proof(ck, { poly, { x, eval } }, pt); + batch_proof_data_single = pt->export_proof(); +} + +/** + * @brief Verify N IPA proofs individually (sequential). Baseline for comparison. + */ +void ipa_verify_individual(State& state) noexcept +{ + const size_t num_proofs = static_cast(state.range(0)); + for (auto _ : state) { + state.PauseTiming(); + // Create fresh verifier transcripts from the same proof data + std::vector> transcripts(num_proofs); + for (size_t i = 0; i < num_proofs; i++) { + transcripts[i] = std::make_shared(batch_proof_data_single); + } + state.ResumeTiming(); + + for (size_t i = 0; i < num_proofs; i++) { + auto result = IPA::reduce_verify(vk, batch_claim, transcripts[i]); + BB_ASSERT(result); + } + } +} + +/** + * @brief Verify N IPA proofs with batched SRS MSM. + */ +void ipa_batch_verify(State& state) noexcept +{ + const size_t num_proofs = static_cast(state.range(0)); + for (auto _ : state) { + state.PauseTiming(); + std::vector> claims(num_proofs, batch_claim); + std::vector> transcripts(num_proofs); + for (size_t i = 0; i < num_proofs; i++) { + transcripts[i] = std::make_shared(batch_proof_data_single); + } + state.ResumeTiming(); + + auto result = IPA::batch_reduce_verify(vk, claims, transcripts); + BB_ASSERT(result); + } +} + } // namespace BENCHMARK(ipa_open) ->Unit(kMillisecond) @@ -75,4 +152,6 @@ BENCHMARK(ipa_verify) ->Unit(kMillisecond) ->DenseRange(MIN_POLYNOMIAL_DEGREE_LOG2, MAX_POLYNOMIAL_DEGREE_LOG2) ->Setup(DoSetup); +BENCHMARK(ipa_verify_individual)->Unit(kMillisecond)->Arg(1)->Arg(2)->Arg(4)->Arg(8)->Setup(DoBatchSetup); +BENCHMARK(ipa_batch_verify)->Unit(kMillisecond)->Arg(1)->Arg(2)->Arg(4)->Arg(8)->Setup(DoBatchSetup); BENCHMARK_MAIN(); diff --git a/barretenberg/cpp/src/barretenberg/chonk/chonk_batch_verifier.cpp b/barretenberg/cpp/src/barretenberg/chonk/chonk_batch_verifier.cpp new file mode 100644 index 000000000000..6b39bb70a90c --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/chonk/chonk_batch_verifier.cpp @@ -0,0 +1,38 @@ +#include "chonk_batch_verifier.hpp" +#include "barretenberg/commitment_schemes/ipa/ipa.hpp" +#include "barretenberg/commitment_schemes/verification_key.hpp" +#include "barretenberg/eccvm/eccvm_flavor.hpp" + +namespace bb { + +bool ChonkBatchVerifier::verify(std::span inputs) +{ + const size_t num_proofs = inputs.size(); + if (num_proofs == 0) { + return true; + } + + // Phase 1: Run all non-IPA verification for each proof, collecting IPA claims + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1651): Consider batching and/or multithreading the + // non-IPA portion of verification as well. Becomes significant for moderate batch sizes. + std::vector> ipa_claims; + std::vector> ipa_transcripts; + ipa_claims.reserve(num_proofs); + ipa_transcripts.reserve(num_proofs); + + for (const auto& input : inputs) { + ChonkNativeVerifier verifier(input.vk_and_hash); + auto result = verifier.reduce_to_ipa_claim(input.proof); + if (!result.all_checks_passed) { + return false; + } + ipa_claims.push_back(result.ipa_claim); + ipa_transcripts.push_back(std::make_shared(result.ipa_proof)); + } + + // Phase 2: Batch IPA verification with single SRS MSM + auto ipa_vk = VerifierCommitmentKey{ ECCVMFlavor::ECCVM_FIXED_SIZE }; + return IPA::batch_reduce_verify(ipa_vk, ipa_claims, ipa_transcripts); +} + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/chonk/chonk_batch_verifier.hpp b/barretenberg/cpp/src/barretenberg/chonk/chonk_batch_verifier.hpp new file mode 100644 index 000000000000..bc11ea979ae5 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/chonk/chonk_batch_verifier.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "barretenberg/chonk/chonk_proof.hpp" +#include "barretenberg/chonk/chonk_verifier.hpp" + +namespace bb { + +/** + * @brief Batch verifier for multiple Chonk IVC proofs. + * @details Runs all non-IPA verification (MegaZK, databus, Goblin) for each proof independently, + * then batches the resulting IPA opening claims into a single IPA verification via random linear combination. + * This replaces N separate large SRS MSMs with one, giving ~Nx speedup on the IPA bottleneck. + */ +class ChonkBatchVerifier { + public: + struct Input { + ChonkProof proof; + std::shared_ptr vk_and_hash; + }; + + /** + * @brief Verify multiple Chonk proofs with batched IPA verification. + * @details For each proof, performs all non-IPA verification (MegaZK, databus, Goblin). + * If all pass, collects IPA claims and batch-verifies them with a single SRS MSM. + * Returns true only if ALL proofs verify. On failure, does not identify which proof failed. + * + * @param inputs Span of (proof, vk_and_hash) pairs to verify + * @return true if all proofs verify + */ + static bool verify(std::span inputs); +}; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/chonk/chonk_batch_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/chonk/chonk_batch_verifier.test.cpp new file mode 100644 index 000000000000..3f950f602035 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/chonk/chonk_batch_verifier.test.cpp @@ -0,0 +1,93 @@ +#include "barretenberg/chonk/chonk_batch_verifier.hpp" +#include "barretenberg/chonk/chonk.hpp" +#include "barretenberg/chonk/mock_circuit_producer.hpp" +#include "barretenberg/common/test.hpp" + +using namespace bb; + +static constexpr size_t SMALL_LOG_2_NUM_GATES = 5; + +class ChonkBatchVerifierTests : public ::testing::Test { + protected: + static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } + + using CircuitProducer = PrivateFunctionExecutionMockCircuitProducer; + + static std::pair> generate_chonk_proof( + size_t num_app_circuits = 1) + { + CircuitProducer circuit_producer(num_app_circuits); + const size_t num_circuits = circuit_producer.total_num_circuits; + Chonk ivc{ num_circuits }; + + TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES }; + for (size_t j = 0; j < num_circuits; ++j) { + circuit_producer.construct_and_accumulate_next_circuit(ivc, settings); + } + return { ivc.prove(), ivc.get_hiding_kernel_vk_and_hash() }; + } +}; + +TEST_F(ChonkBatchVerifierTests, BatchVerifyTwoValidProofs) +{ + auto [proof1, vk1] = generate_chonk_proof(); + auto [proof2, vk2] = generate_chonk_proof(); + + std::vector inputs = { + { std::move(proof1), vk1 }, + { std::move(proof2), vk2 }, + }; + EXPECT_TRUE(ChonkBatchVerifier::verify(inputs)); +} + +TEST_F(ChonkBatchVerifierTests, BatchVerifySingleProof) +{ + auto [proof, vk] = generate_chonk_proof(); + + std::vector inputs = { + { std::move(proof), vk }, + }; + EXPECT_TRUE(ChonkBatchVerifier::verify(inputs)); +} + +/** + * @brief Tamper with only the IPA proof, keeping all other proof components valid. + * @details Targets the batch IPA verification path (Phase 2 of ChonkBatchVerifier). + */ +TEST_F(ChonkBatchVerifierTests, BatchVerifyTamperedIPAProof) +{ + BB_DISABLE_ASSERTS(); + + auto [proof1, vk1] = generate_chonk_proof(); + auto [proof2, vk2] = generate_chonk_proof(); + + // Corrupt a field element in the IPA proof portion of the goblin proof + ASSERT_FALSE(proof2.goblin_proof.ipa_proof.empty()); + proof2.goblin_proof.ipa_proof[0] = proof2.goblin_proof.ipa_proof[0] + bb::fr(1); + + std::vector inputs = { + { std::move(proof1), vk1 }, + { std::move(proof2), vk2 }, + }; + EXPECT_FALSE(ChonkBatchVerifier::verify(inputs)); +} + +/** + * @brief Swap goblin proofs between two valid Chonk proofs to test non-IPA verification failures. + */ +TEST_F(ChonkBatchVerifierTests, BatchVerifySwappedGoblinProofs) +{ + BB_DISABLE_ASSERTS(); + + auto [proof1, vk1] = generate_chonk_proof(); + auto [proof2, vk2] = generate_chonk_proof(); + + // Swap goblin proofs: each mega_proof is now paired with the wrong goblin proof + std::swap(proof1.goblin_proof, proof2.goblin_proof); + + std::vector inputs = { + { std::move(proof1), vk1 }, + { std::move(proof2), vk2 }, + }; + EXPECT_FALSE(ChonkBatchVerifier::verify(inputs)); +} diff --git a/barretenberg/cpp/src/barretenberg/chonk/chonk_verifier.cpp b/barretenberg/cpp/src/barretenberg/chonk/chonk_verifier.cpp index 7f5d8caf2f4b..aaee550ecfe0 100644 --- a/barretenberg/cpp/src/barretenberg/chonk/chonk_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/chonk/chonk_verifier.cpp @@ -7,20 +7,22 @@ #include "chonk_verifier.hpp" #include "barretenberg/commitment_schemes/ipa/ipa.hpp" #include "barretenberg/commitment_schemes/verification_key.hpp" +#include "barretenberg/common/bb_bench.hpp" namespace bb { /** - * @brief Verifies a Chonk IVC proof (Native specialization). + * @brief Run all Chonk verification except IPA, returning the IPA data for deferred verification. */ -template <> ChonkVerifier::Output ChonkVerifier::verify(const Proof& proof) +template <> ChonkVerifier::IPAReductionResult ChonkVerifier::reduce_to_ipa_claim(const Proof& proof) { + BB_BENCH_NAME("ChonkVerifier::reduce_to_ipa_claim"); // Step 1: Verify the Hiding kernel proof (includes pairing check) HidingKernelVerifier verifier{ vk_and_hash, transcript }; auto verifier_output = verifier.verify_proof(proof.mega_proof); if (!verifier_output.result) { info("ChonkVerifier: verification failed at MegaZK verification step"); - return false; + return { {}, {}, false }; } // Extract public inputs and kernel data @@ -34,7 +36,7 @@ template <> ChonkVerifier::Output ChonkVerifier::verify(const Proo vinfo("ChonkVerifier: databus consistency verified: ", databus_consistency_verified); if (!databus_consistency_verified) { info("Chonk Verifier: verification failed at databus consistency check"); - return false; + return { {}, {}, false }; } // Step 3: Goblin verification (merge, eccvm, translator) @@ -45,13 +47,27 @@ template <> ChonkVerifier::Output ChonkVerifier::verify(const Proo if (!goblin_output.all_checks_passed) { info("ChonkVerifier: chonk verification failed at Goblin checks (merge/eccvm/translator reduction + pairing)"); + return { {}, {}, false }; + } + + return { std::move(goblin_output.ipa_claim), std::move(goblin_output.ipa_proof), true }; +} + +/** + * @brief Verifies a Chonk IVC proof (Native specialization). + */ +template <> ChonkVerifier::Output ChonkVerifier::verify(const Proof& proof) +{ + BB_BENCH_NAME("ChonkVerifier::verify"); + auto result = reduce_to_ipa_claim(proof); + if (!result.all_checks_passed) { return false; } // Step 4: Verify IPA opening - auto ipa_transcript = std::make_shared(goblin_output.ipa_proof); + auto ipa_transcript = std::make_shared(result.ipa_proof); auto ipa_vk = VerifierCommitmentKey{ ECCVMFlavor::ECCVM_FIXED_SIZE }; - bool ipa_verified = IPA::reduce_verify(ipa_vk, goblin_output.ipa_claim, ipa_transcript); + bool ipa_verified = IPA::reduce_verify(ipa_vk, result.ipa_claim, ipa_transcript); vinfo("ChonkVerifier: Goblin IPA verified: ", ipa_verified); if (!ipa_verified) { info("ChonkVerifier: Chonk verification failed at IPA check"); @@ -113,6 +129,15 @@ template <> ChonkVerifier::Output ChonkVerifier::verify(const Proof& .all_checks_passed = mega_reduction_succeeded && goblin_output.all_checks_passed }; } +/** + * @brief Stub for recursive mode (not meaningful — reduce_to_ipa_claim is only used in native batch verification). + */ +template <> +ChonkVerifier::IPAReductionResult ChonkVerifier::reduce_to_ipa_claim([[maybe_unused]] const Proof& proof) +{ + throw_or_abort("reduce_to_ipa_claim is only available for native (non-recursive) ChonkVerifier"); +} + // Template instantiations template class ChonkVerifier; // Native verifier template class ChonkVerifier; // Recursive verifier diff --git a/barretenberg/cpp/src/barretenberg/chonk/chonk_verifier.hpp b/barretenberg/cpp/src/barretenberg/chonk/chonk_verifier.hpp index c9b86a2c1a80..9b1a2824ee00 100644 --- a/barretenberg/cpp/src/barretenberg/chonk/chonk_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/chonk/chonk_verifier.hpp @@ -104,6 +104,28 @@ template class ChonkVerifier { */ [[nodiscard("IPA claim and pairing points must be accumulated")]] Output verify(const Proof& proof); + /** + * @brief Result of reducing Chonk verification to an IPA opening claim (native mode only). + * @details Contains the IPA claim and proof from non-IPA verification (MegaZK, databus, Goblin), + * allowing batch IPA verification across multiple Chonk proofs. + */ + struct IPAReductionResult { + OpeningClaim ipa_claim; + ::bb::HonkProof ipa_proof; + bool all_checks_passed; + }; + + /** + * @brief Run Chonk verification up to but not including IPA, returning the IPA claim for deferred verification. + * @details Verifies the MegaZK proof, databus consistency, and Goblin proof (merge/eccvm/translator), + * then returns the IPA opening claim and proof without performing the final IPA MSM. + * This enables batch IPA verification across multiple Chonk proofs. + * + * @param proof The Chonk proof to partially verify + * @return IPAReductionResult containing the IPA claim/proof and whether all non-IPA checks passed + */ + IPAReductionResult reduce_to_ipa_claim(const Proof& proof); + private: // VK and hash of the hiding kernel std::shared_ptr vk_and_hash; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp index 500ba9ff4356..6709a3c3aaa5 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp @@ -8,6 +8,7 @@ #include "barretenberg/commitment_schemes/claim.hpp" #include "barretenberg/commitment_schemes/verification_key.hpp" #include "barretenberg/common/assert.hpp" +#include "barretenberg/common/bb_bench.hpp" #include "barretenberg/common/container.hpp" #include "barretenberg/common/thread.hpp" #include "barretenberg/common/throw_or_abort.hpp" @@ -325,44 +326,55 @@ template class IPA } /** - * @brief Natively verify the correctness of a Proof + * @brief Per-proof data extracted from an IPA transcript. + * @details Contains all values derived from transcript processing (steps 2–7, 9 of the IPA verification + * protocol) that are needed for either single-proof or batch IPA verification. + * Does not include the MSM (step 8). + */ + struct TranscriptData { + GroupElement C_zero; ///< \f$C_0 = C' + \sum_{j=0}^{k-1}(u_j^{-1}L_j + u_jR_j)\f$ + Fr b_zero; ///< \f$b_0 = g(\beta) = \prod_{i=0}^{k-1}(1+u_{i}^{-1}x^{2^{i}})\f$ + Polynomial s_vec; ///< \f$\vec{s}=(1,u_{0}^{-1},u_{1}^{-1},u_{0}^{-1}u_{1}^{-1},..., + ///< \prod_{i=0}^{k-1}u_{i}^{-1})\f$ + Fr gen_challenge; ///< Generator challenge \f$u\f$ where \f$U = u \cdot G\f$ + Commitment G_zero_from_prover; ///< \f$G_0\f$ received from prover (not recomputed) + Fr a_zero; ///< \f$a_0\f$ received from prover + }; + + /** + * @brief Process a single IPA proof's transcript, extracting all per-proof verification data. * - * @tparam Transcript Allows to specify a transcript class. Useful for testing - * @param vk Verification_key containing srs - * @param opening_claim Contains the commitment C and opening pair \f$(\beta, f(\beta))\f$ + * @param opening_claim Contains the commitment \f$C\f$ and opening pair \f$(\beta, f(\beta))\f$ * @param transcript Transcript with elements from the prover and generated challenges * - * @return true/false depending on if the proof verifies + * @return TranscriptData containing \f$C_0, b_0, \vec{s}, u, G_0, a_0\f$ * - * @details The procedure runs as follows: + * @details Performs steps 2–7 and 9 of the IPA verification protocol (see reduce_verify_internal_native): * - *1. Receive commitment, challenge, and claimed evaluation from the prover *2. Receive the generator challenge \f$u\f$, abort if it's zero, otherwise compute \f$U=u\cdot G\f$ - *3. Compute \f$C'=C+f(\beta)\cdot U\f$. (Recall that \f$f(\beta)\f$ is the claimed evaluation.) - *4. Receive \f$L_j, R_j\f$ and compute challenges \f$u_j\f$ for \f$j \in {k-1,..,0}\f$, abort immediately on - receiving a \f$u_j=0\f$ + *3. Compute \f$C'=C+f(\beta)\cdot U\f$. (Recall that \f$f(\beta)\f$ is the claimed evaluation.) + *4. Receive \f$L_j, R_j\f$ and compute challenges \f$u_j\f$ for \f$j \in {k-1,..,0}\f$, abort on \f$u_j=0\f$ *5. Compute \f$C_0 = C' + \sum_{j=0}^{k-1}(u_j^{-1}L_j + u_jR_j)\f$ *6. Compute \f$b_0=g(\beta)=\prod_{i=0}^{k-1}(1+u_{i}^{-1}x^{2^{i}})\f$ *7. Compute vector \f$\vec{s}=(1,u_{0}^{-1},u_{1}^{-1},u_{0}^{-1}u_{1}^{-1},...,\prod_{i=0}^{k-1}u_{i}^{-1})\f$ - *8. Compute \f$G_s=\langle \vec{s},\vec{G}\rangle\f$ - *9. Receive \f$\vec{a}_{0}\f$ of length 1 - *10. Compute \f$C_{right}=a_{0}G_{s}+a_{0}b_{0}U\f$ - *11. Check that \f$C_{right} = C_0\f$. If they match, return true. Otherwise return false. + * + * Additionally receives \f$G_0\f$ and \f$a_0\f$ from the prover transcript (step 9). + * Does NOT compute \f$G_s=\langle \vec{s},\vec{G}\rangle\f$ (step 8, the MSM) + * or perform the final verification check (steps 10–11). + * + * @pre add_claim_to_hash_buffer must have been called on the transcript (step 1). */ - static bool reduce_verify_internal_native(const VK& vk, const OpeningClaim& opening_claim, auto& transcript) + template + static TranscriptData read_transcript_data(const OpeningClaim& opening_claim, + const std::shared_ptr& transcript) requires(!Curve::is_stdlib_type) { - // Step 1 - // Done by `add_claim_to_hash_buffer`. - // Step 2. // Receive generator challenge u and compute auxiliary generator const Fr generator_challenge = transcript->template get_challenge("IPA:generator_challenge"); - if (generator_challenge.is_zero()) { throw_or_abort("The generator challenge can't be zero"); } - const Commitment aux_generator = Commitment::one() * generator_challenge; // Step 3. @@ -371,13 +383,11 @@ template class IPA const auto pippenger_size = 2 * log_poly_length; std::vector round_challenges(log_poly_length); - // the group elements that will participate in our MSM. - std::vector msm_elements(pippenger_size); // L_{k-1}, R_{k-1}, L_{k-2}, ..., L_0, R_0. - // the scalars that will participate in our MSM. - std::vector msm_scalars(pippenger_size); // w_{k-1}^{-1}, w_{k-1}, ..., w_{0}^{-1}, w_{0}. + std::vector msm_elements(pippenger_size); + std::vector msm_scalars(pippenger_size); // Step 4. - // Receive all L_i and R_i and populate msm_elements. + // Receive all L_j, R_j and compute round challenges u_j for (size_t i = 0; i < log_poly_length; i++) { std::string index = std::to_string(log_poly_length - i - 1); const auto element_L = transcript->template receive_from_prover("IPA:L_" + index); @@ -405,7 +415,7 @@ template class IPA { 0, { &msm_scalars[0], /*size*/ pippenger_size } }, { &msm_elements[0], /*size*/ pippenger_size }); GroupElement C_zero = C_prime + LR_sums; - // Step 6. + // Step 6. // Compute b_zero succinctly const Fr b_zero = evaluate_challenge_poly(round_challenges_inv, opening_claim.opening_pair.challenge); @@ -414,29 +424,69 @@ template class IPA Polynomial s_vec( construct_poly_from_u_challenges_inv(std::span(round_challenges_inv).subspan(0, log_poly_length))); + // Receive G_0 and a_0 from prover (advances transcript; G_0 not recomputed here) + Commitment G_zero_from_prover = transcript->template receive_from_prover("IPA:G_0"); + Fr a_zero = transcript->template receive_from_prover("IPA:a_0"); + + return { C_zero, b_zero, std::move(s_vec), generator_challenge, G_zero_from_prover, a_zero }; + } + + /** + * @brief Natively verify the correctness of a Proof + * + * @tparam Transcript Allows to specify a transcript class. Useful for testing + * @param vk Verification_key containing srs + * @param opening_claim Contains the commitment C and opening pair \f$(\beta, f(\beta))\f$ + * @param transcript Transcript with elements from the prover and generated challenges + * + * @return true/false depending on if the proof verifies + * + * @details The procedure runs as follows: + * + *1. Receive commitment, challenge, and claimed evaluation from the prover + *2. Receive the generator challenge \f$u\f$, abort if it's zero, otherwise compute \f$U=u\cdot G\f$ + *3. Compute \f$C'=C+f(\beta)\cdot U\f$. (Recall that \f$f(\beta)\f$ is the claimed evaluation.) + *4. Receive \f$L_j, R_j\f$ and compute challenges \f$u_j\f$ for \f$j \in {k-1,..,0}\f$, abort immediately on + receiving a \f$u_j=0\f$ + *5. Compute \f$C_0 = C' + \sum_{j=0}^{k-1}(u_j^{-1}L_j + u_jR_j)\f$ + *6. Compute \f$b_0=g(\beta)=\prod_{i=0}^{k-1}(1+u_{i}^{-1}x^{2^{i}})\f$ + *7. Compute vector \f$\vec{s}=(1,u_{0}^{-1},u_{1}^{-1},u_{0}^{-1}u_{1}^{-1},...,\prod_{i=0}^{k-1}u_{i}^{-1})\f$ + *8. Compute \f$G_s=\langle \vec{s},\vec{G}\rangle\f$ + *9. Receive \f$\vec{a}_{0}\f$ of length 1 + *10. Compute \f$C_{right}=a_{0}G_{s}+a_{0}b_{0}U\f$ + *11. Check that \f$C_{right} = C_0\f$. If they match, return true. Otherwise return false. + */ + static bool reduce_verify_internal_native(const VK& vk, const OpeningClaim& opening_claim, auto& transcript) + requires(!Curve::is_stdlib_type) + { + BB_BENCH_NAME("IPA::reduce_verify"); + + // Steps 2–7, 9: Process transcript and extract per-proof data (step 1 done by add_claim_to_hash_buffer) + auto data = read_transcript_data(opening_claim, transcript); + + // Step 8. + // Compute G_s = via SRS MSM and verify against prover's G_0 std::span srs_elements = vk.get_monomial_points(); if (poly_length > srs_elements.size()) { throw_or_abort("potential bug: Not enough SRS points for IPA!"); } - - // Step 8. - // Compute G_zero - Commitment G_zero = - scalar_multiplication::pippenger_unsafe(s_vec, { &srs_elements[0], /*size*/ poly_length }); - Commitment G_zero_sent = transcript->template receive_from_prover("IPA:G_0"); - BB_ASSERT_EQ(G_zero, G_zero_sent, "G_0 should be equal to G_0 sent in transcript. IPA verification fails."); - - // Step 9. - // Receive a_zero from the prover - auto a_zero = transcript->template receive_from_prover("IPA:a_0"); + Commitment G_zero; + { + BB_BENCH_NAME("IPA::srs_msm"); + G_zero = + scalar_multiplication::pippenger_unsafe(data.s_vec, { &srs_elements[0], /*size*/ poly_length }); + } + BB_ASSERT_EQ( + G_zero, data.G_zero_from_prover, "G_0 should be equal to G_0 sent in transcript. IPA verification fails."); // Step 10. - // Compute C_right. Implicitly, this is an IPA statement for the length 1 vectors and together with - // the URS G_0. - GroupElement right_hand_side = G_zero * a_zero + aux_generator * a_zero * b_zero; + // Compute C_right = a_0 * G_s + a_0 * b_0 * U + Commitment aux_generator = Commitment::one() * data.gen_challenge; + GroupElement right_hand_side = G_zero * data.a_zero + aux_generator * data.a_zero * data.b_zero; + // Step 11. - // Check if C_right == C_zero - return (C_zero.normalize() == right_hand_side.normalize()); + // Check if C_right == C_0 + return (data.C_zero.normalize() == right_hand_side.normalize()); } /** @@ -594,6 +644,91 @@ template class IPA return reduce_verify_internal_native(vk, opening_claim, transcript); } + /** + * @brief Batch verify multiple IPA proofs with a single large SRS MSM. + * + * @details For N proofs, IPA verification's dominant cost is the SRS MSM (pippenger over poly_length points). + * By combining N proofs via random linear combination with challenge \f$\alpha\f$, we replace N separate MSMs with + * one. + * + * The batch check verifies: + * \f$\sum \alpha^i C_{0,i} = \langle \sum \alpha^i a_{0,i} \vec{s}_i, \vec{G} \rangle + * + (\sum \alpha^i a_{0,i} b_{0,i} u_i) \cdot G\f$ + * + * where \f$G\f$ = Commitment::one() and \f$U_i = u_i \cdot G\f$. + * + * @param vk Verification key containing SRS + * @param opening_claims The opening claims for each proof + * @param transcripts The transcripts containing each proof's data + * @return true if all proofs verify + */ + template + static bool batch_reduce_verify(const VK& vk, + const std::vector>& opening_claims, + const std::vector>& transcripts) + requires(!Curve::is_stdlib_type) + { + const size_t num_claims = opening_claims.size(); + BB_ASSERT(num_claims == transcripts.size()); + BB_ASSERT(num_claims > 0); + + // Phase 1: Per-proof transcript processing (sequential, each proof is cheap) + std::vector C_zeros(num_claims); + std::vector a_zeros(num_claims); + std::vector b_zeros(num_claims); + std::vector gen_challenges(num_claims); + std::vector> s_vecs(num_claims); + + for (size_t i = 0; i < num_claims; i++) { + add_claim_to_hash_buffer(opening_claims[i], transcripts[i]); + auto data = read_transcript_data(opening_claims[i], transcripts[i]); + C_zeros[i] = std::move(data.C_zero); + b_zeros[i] = data.b_zero; + s_vecs[i] = std::move(data.s_vec); + gen_challenges[i] = data.gen_challenge; + a_zeros[i] = data.a_zero; + } + + // Phase 2: Batched computation using random challenge alpha + Fr alpha = Fr::random_element(); + std::vector alpha_pows(num_claims); + alpha_pows[0] = Fr::one(); + for (size_t i = 1; i < num_claims; i++) { + alpha_pows[i] = alpha_pows[i - 1] * alpha; + } + + // Combined s_vec: combined_s[j] = \sum \alpha^i * a_zero_i * s_vec_i[j] + Polynomial combined_s(poly_length); + for (size_t i = 0; i < num_claims; i++) { + Fr scalar = alpha_pows[i] * a_zeros[i]; + combined_s.add_scaled(s_vecs[i], scalar); + } + + // Single MSM over combined scalars + std::span srs_elements = vk.get_monomial_points(); + if (poly_length > srs_elements.size()) { + throw_or_abort("potential bug: Not enough SRS points for IPA!"); + } + Commitment G_batch = + scalar_multiplication::pippenger_unsafe(combined_s, { &srs_elements[0], /*size*/ poly_length }); + + // Combined LHS: C_batch = \sum \alpha^i * C_zero_i + GroupElement C_batch = C_zeros[0]; + for (size_t i = 1; i < num_claims; i++) { + C_batch = C_batch + C_zeros[i] * alpha_pows[i]; + } + + // Combined scalar for U terms: bU_scalar = \sum \alpha^i * a_zero_i * b_zero_i * gen_challenge_i + Fr bU_scalar = Fr::zero(); + for (size_t i = 0; i < num_claims; i++) { + bU_scalar += alpha_pows[i] * a_zeros[i] * b_zeros[i] * gen_challenges[i]; + } + + // Check: C_batch == G_batch + bU_scalar * G + GroupElement right_hand_side = G_batch + Commitment::one() * bU_scalar; + return (C_batch.normalize() == right_hand_side.normalize()); + } + /** * @brief Recursively _partially_ verify the correctness of an IPA proof. * diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp index 9785be0b6792..72febbb8fd9b 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp @@ -39,6 +39,22 @@ class IPATest : public CommitmentTest { vk = create_verifier_commitment_key(); } + struct ProofData { + OpeningClaim claim; + NativeTranscript::Proof proof_data; + }; + + static ProofData generate_proof(const Polynomial& poly, const Fr& x) + { + Commitment commitment = ck.commit(poly); + auto eval = poly.evaluate(x); + auto prover_transcript = std::make_shared(); + PCS::compute_opening_proof(ck, { poly, { x, eval } }, prover_transcript); + return { { { x, eval }, commitment }, prover_transcript->export_proof() }; + } + + static ProofData generate_random_proof() { return generate_proof(Polynomial::random(n), Fr::random_element()); } + struct ResultOfProveVerify { bool result; std::shared_ptr prover_transcript; @@ -49,17 +65,14 @@ class IPATest : public CommitmentTest { { Commitment commitment = ck.commit(poly); auto eval = poly.evaluate(x); - const OpeningPair opening_pair = { x, eval }; - const OpeningClaim opening_claim{ opening_pair, commitment }; - // initialize empty prover transcript auto prover_transcript = std::make_shared(); - PCS::compute_opening_proof(ck, { poly, opening_pair }, prover_transcript); + PCS::compute_opening_proof(ck, { poly, { x, eval } }, prover_transcript); // initialize verifier transcript from proof data auto verifier_transcript = std::make_shared(prover_transcript->export_proof()); // the native reduce_verify does a _complete_ IPA proof and returns whether or not the checks pass. - bool result = PCS::reduce_verify(vk, opening_claim, verifier_transcript); + bool result = PCS::reduce_verify(vk, { { x, eval }, commitment }, verifier_transcript); return { result, prover_transcript, verifier_transcript }; } }; @@ -360,5 +373,63 @@ TEST_F(IPATest, ShpleminiIPAShiftsRemoval) auto result = PCS::reduce_verify_batch_opening_claim(batch_opening_claim, vk, verifier_transcript); EXPECT_EQ(result, true); } + +// Batch IPA verification tests + +TEST_F(IPATest, BatchVerifyTwoValidProofs) +{ + auto [claim1, proof1] = generate_random_proof(); + auto [claim2, proof2] = generate_random_proof(); + + std::vector> claims = { claim1, claim2 }; + std::vector> transcripts = { std::make_shared(proof1), + std::make_shared(proof2) }; + + EXPECT_TRUE(PCS::batch_reduce_verify(vk, claims, transcripts)); +} + +TEST_F(IPATest, BatchVerifySingleProof) +{ + // Degenerate case: batch verify with N=1 should match reduce_verify + auto [claim, proof_data] = generate_random_proof(); + + EXPECT_TRUE(PCS::reduce_verify(vk, claim, std::make_shared(proof_data))); + EXPECT_TRUE(PCS::batch_reduce_verify(vk, { claim }, { std::make_shared(proof_data) })); +} + +TEST_F(IPATest, BatchVerifyTamperedProof) +{ + auto [claim1, proof1] = generate_random_proof(); + auto [claim2, proof2] = generate_random_proof(); + + // Tamper with the second claim's evaluation + claim2.opening_pair.evaluation += Fr::one(); + + std::vector> claims = { claim1, claim2 }; + std::vector> transcripts = { std::make_shared(proof1), + std::make_shared(proof2) }; + + EXPECT_FALSE(PCS::batch_reduce_verify(vk, claims, transcripts)); +} + +TEST_F(IPATest, BatchVerifyRejectsClaimTranscriptMismatch) +{ + // Batch verification must bind each claim to its own transcript. Two individually valid proofs + // should pass when correctly paired but fail when the transcripts are swapped, since each + // transcript's round messages (L_j, R_j) are coupled to its claim's commitment in C_zero. + auto [claim1, proof1] = generate_random_proof(); + auto [claim2, proof2] = generate_random_proof(); + + std::vector> claims = { claim1, claim2 }; + + // Correct pairing: passes + EXPECT_TRUE(PCS::batch_reduce_verify( + vk, claims, { std::make_shared(proof1), std::make_shared(proof2) })); + + // Swapped pairing: fails + EXPECT_FALSE(PCS::batch_reduce_verify( + vk, claims, { std::make_shared(proof2), std::make_shared(proof1) })); +} + typename IPATest::CK IPATest::ck; typename IPATest::VK IPATest::vk; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/pairing_points.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/pairing_points.hpp index 9f2e99a904f4..86570970b692 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/pairing_points.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/pairing_points.hpp @@ -8,6 +8,7 @@ #include "barretenberg/commitment_schemes/verification_key.hpp" #include "barretenberg/common/assert.hpp" +#include "barretenberg/common/bb_bench.hpp" namespace bb { @@ -75,6 +76,7 @@ template class PairingPoints { */ bool check() const { + BB_BENCH_NAME("PairingPoints::check"); VerifierCK vck{}; // TODO(https://github.com/AztecProtocol/barretenberg/issues/1423): Rename to verifier_pcs_key or vckey or // something. Issue exists in many places besides just here. diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 1294cd410902..bda23ae721d0 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -6,6 +6,7 @@ #include "./eccvm_verifier.hpp" #include "barretenberg/commitment_schemes/shplonk/shplemini.hpp" +#include "barretenberg/common/bb_bench.hpp" #include "barretenberg/stdlib/eccvm_verifier/eccvm_recursive_flavor.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" #include "barretenberg/transcript/origin_tag.hpp" @@ -19,6 +20,7 @@ namespace bb { template typename ECCVMVerifier_::ReductionResult ECCVMVerifier_::reduce_to_ipa_opening() { + BB_BENCH_NAME("ECCVMVerifier::reduce"); using Curve = typename Flavor::Curve; using Shplemini = ShpleminiVerifier_; using Shplonk = ShplonkVerifier_; diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_verifier.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_verifier.cpp index 111f928fb6ec..9386174b39b8 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_verifier.cpp @@ -5,6 +5,7 @@ // ===================== #include "goblin_verifier.hpp" +#include "barretenberg/common/bb_bench.hpp" #include "barretenberg/common/log.hpp" namespace bb { @@ -17,6 +18,7 @@ namespace bb { template typename GoblinVerifier_::ReductionResult GoblinVerifier_::reduce_to_pairing_check_and_ipa_opening() { + BB_BENCH_NAME("GoblinVerifier::reduce"); // Step 1: Verify the merge proof MergeVerifier merge_verifier{ merge_settings, transcript }; auto merge_result = merge_verifier.reduce_to_pairing_check(proof.merge_proof, merge_commitments); diff --git a/barretenberg/cpp/src/barretenberg/goblin/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/goblin/merge_verifier.cpp index 326f276f4293..dcdea114037a 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/merge_verifier.cpp @@ -6,6 +6,7 @@ #include "merge_verifier.hpp" #include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" +#include "barretenberg/common/bb_bench.hpp" #include "barretenberg/common/log.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/proof/proof.hpp" @@ -114,6 +115,7 @@ template typename MergeVerifier_::ReductionResult MergeVerifier_::reduce_to_pairing_check( const Proof& proof, const InputCommitments& input_commitments) { + BB_BENCH_NAME("MergeVerifier::reduce"); transcript->load_proof(proof); // Receive shift size from prover diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp index 7aa36240939d..ab9ffba56527 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp @@ -6,6 +6,7 @@ #include "./translator_verifier.hpp" #include "barretenberg/commitment_schemes/shplonk/shplemini.hpp" +#include "barretenberg/common/bb_bench.hpp" #include "barretenberg/relations/translator_vm/translator_decomposition_relation_impl.hpp" #include "barretenberg/relations/translator_vm/translator_delta_range_constraint_relation_impl.hpp" #include "barretenberg/relations/translator_vm/translator_extra_relations_impl.hpp" @@ -133,6 +134,7 @@ template void TranslatorVerifier_::put_translation_dat template typename TranslatorVerifier_::ReductionResult TranslatorVerifier_::reduce_to_pairing_check() { + BB_BENCH_NAME("TranslatorVerifier::reduce"); using PCS = typename Flavor::PCS; using Shplemini = ShpleminiVerifier_; using ClaimBatcher = ClaimBatcher_; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index 0720061a8f4c..7ac039993752 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -8,6 +8,7 @@ #include "barretenberg/commitment_schemes/ipa/ipa.hpp" #include "barretenberg/commitment_schemes/pairing_points.hpp" #include "barretenberg/commitment_schemes/shplonk/shplemini.hpp" +#include "barretenberg/common/bb_bench.hpp" #include "barretenberg/flavor/mega_avm_recursive_flavor.hpp" #include "barretenberg/flavor/mega_zk_recursive_flavor.hpp" #include "barretenberg/flavor/ultra_zk_recursive_flavor.hpp" @@ -231,6 +232,7 @@ template typename UltraVerifier_::Output UltraVerifier_::verify_proof( const typename UltraVerifier_::Proof& proof) { + BB_BENCH_NAME("UltraVerifier::verify_proof"); // Step 1: Split proof if needed Proof honk_proof; Proof ipa_proof;