diff --git a/barretenberg/cpp/src/barretenberg/api/api_chonk.cpp b/barretenberg/cpp/src/barretenberg/api/api_chonk.cpp index bb0d8080c168..9c290315fff1 100644 --- a/barretenberg/cpp/src/barretenberg/api/api_chonk.cpp +++ b/barretenberg/cpp/src/barretenberg/api/api_chonk.cpp @@ -123,7 +123,7 @@ bool ChonkAPI::verify([[maybe_unused]] const Flags& flags, auto proof_fields = many_from_buffer(read_file(proof_path)); auto proof = ChonkProof::from_field_elements(proof_fields); - auto vk_buffer = read_file(vk_path); + auto vk_buffer = read_vk_file(vk_path); auto response = bbapi::ChonkVerify{ .proof = std::move(proof), .vk = std::move(vk_buffer) }.execute(); return response.valid; diff --git a/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp b/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp index b7e335b6237c..0d7f08e947a6 100644 --- a/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp +++ b/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp @@ -101,7 +101,7 @@ bool UltraHonkAPI::verify(const Flags& flags, // Read input files auto public_inputs = many_from_buffer(read_file(public_inputs_path)); auto proof = many_from_buffer(read_file(proof_path)); - auto vk_bytes = read_file(vk_path); + auto vk_bytes = read_vk_file(vk_path); // Convert flags to ProofSystemSettings bbapi::ProofSystemSettings settings{ .ipa_accumulation = flags.ipa_accumulation, @@ -209,7 +209,7 @@ void UltraHonkAPI::write_solidity_verifier(const Flags& flags, { BB_BENCH_NAME("UltraHonkAPI::write_solidity_verifier"); // Read VK file - auto vk_bytes = read_file(vk_path); + auto vk_bytes = read_vk_file(vk_path); // Convert flags to ProofSystemSettings bbapi::ProofSystemSettings settings{ .ipa_accumulation = flags.ipa_accumulation, diff --git a/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.test.cpp b/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.test.cpp index b84d75c2efbc..93e9424154ba 100644 --- a/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.test.cpp @@ -233,3 +233,35 @@ TEST_F(ApiUltraHonkTest, GatesWithOpcodesSmokeTest) // Check that output contains per-opcode information EXPECT_TRUE(output.find("gates_per_opcode") != std::string::npos); } + +TEST_F(ApiUltraHonkTest, VerifyWithMissingVkGivesActionableError) +{ + auto [bytecode_path, witness_path] = create_test_circuit_files(test_dir); + + API::Flags flags; + flags.oracle_hash_type = "poseidon2"; + flags.write_vk = true; + + UltraHonkAPI api; + + // Generate proof with vk + auto proof_output_dir = test_dir / "proof"; + std::filesystem::create_directories(proof_output_dir); + api.prove(flags, bytecode_path, witness_path, "", proof_output_dir); + + // Try to verify with a non-existent vk path + auto nonexistent_vk_path = test_dir / "nonexistent_vk"; + try { + api.verify(flags, proof_output_dir / "public_inputs", proof_output_dir / "proof", nonexistent_vk_path); + FAIL() << "Expected an exception to be thrown"; + } catch (const std::runtime_error& e) { + std::string error_msg = e.what(); + // Check that the error message contains actionable guidance + EXPECT_TRUE(error_msg.find("--write_vk") != std::string::npos) + << "Error message should mention --write_vk flag. Got: " << error_msg; + EXPECT_TRUE(error_msg.find("bb write_vk") != std::string::npos) + << "Error message should mention bb write_vk command. Got: " << error_msg; + EXPECT_TRUE(error_msg.find("--vk_path") != std::string::npos) + << "Error message should mention --vk_path option. Got: " << error_msg; + } +} diff --git a/barretenberg/cpp/src/barretenberg/api/file_io.hpp b/barretenberg/cpp/src/barretenberg/api/file_io.hpp index c5436170d0ca..fe9cf30adf5f 100644 --- a/barretenberg/cpp/src/barretenberg/api/file_io.hpp +++ b/barretenberg/cpp/src/barretenberg/api/file_io.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -100,4 +101,23 @@ template inline std::string field_elements_to_json(const std::vect ss << "]"; return ss.str(); } + +/** + * @brief Read a verification key file with an actionable error message if not found. + * + * @param vk_path Path to the verification key file + * @return std::vector The verification key bytes + * @throws std::runtime_error with actionable message if vk file not found + */ +inline std::vector read_vk_file(const std::filesystem::path& vk_path) +{ + try { + return read_file(vk_path); + } catch (const std::runtime_error&) { + THROW std::runtime_error("Unable to open file: " + vk_path.string() + + "\nGenerate a vk during proving by running `bb prove` with an additional `--write_vk` " + "flag, or run `bb write_vk` to generate a standalone vk." + "\nIf you already have a vk file, specify its path with `--vk_path `."); + } +} } // namespace bb