From f6347fe4f8d5f1fb33d6126b31e944100859d3d7 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 25 Sep 2023 20:10:04 +0000 Subject: [PATCH] add failure tests for the honk recursive verifiers --- .../honk/verifier/goblin_verifier.test.cpp | 36 ++++++++++++++++++ .../recursion/honk/verifier/verifier.test.cpp | 37 +++++++++++++++++++ 2 files changed, 73 insertions(+) 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 a74ea38d1f89..814968794f56 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 @@ -196,6 +196,37 @@ template class GoblinRecursiveVerifierTest : public testi EXPECT_EQ(recursive_manifest[i], native_manifest[i]); } } + + /** + * @brief Construct a verifier circuit for a proof whose data has been tampered with. Expect failure + * TODO(#656): For now we gat a "bad" proof by arbitrarily tampering with bits in a valid proof. It would be + * much nicer to explicitly change meaningful components, e.g. such that one of the multilinear evaluations is + * wrong. This is difficult now but should be straightforward if the proof is a struct. + */ + static void test_recursive_verification_fails() + { + // Create an arbitrary inner circuit + auto inner_circuit = create_inner_circuit(); + + // Generate a proof over the inner circuit + InnerComposer inner_composer; + auto instance = inner_composer.create_instance(inner_circuit); + auto inner_prover = inner_composer.create_prover(instance); + auto inner_proof = inner_prover.construct_proof(); + const auto native_verification_key = instance->compute_verification_key(); + + // Arbitrarily tamper with the proof to be verified + inner_proof.proof_data[10] = 25; + + // Create a recursive verification circuit for the proof of the inner circuit + OuterBuilder outer_circuit; + auto verification_key = std::make_shared(&outer_circuit, native_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 + EXPECT_FALSE(outer_circuit.check_circuit()); + } }; // Run the recursive verifier tests with conventional Ultra builder and Goblin builder @@ -218,4 +249,9 @@ HEAVY_TYPED_TEST(GoblinRecursiveVerifierTest, SingleRecursiveVerification) TestFixture::test_recursive_verification(); }; +HEAVY_TYPED_TEST(GoblinRecursiveVerifierTest, SingleRecursiveVerificationFailure) +{ + TestFixture::test_recursive_verification_fails(); +}; + } // namespace proof_system::plonk::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 557194b433c1..da17d1e687ed 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 @@ -180,6 +180,38 @@ template class RecursiveVerifierTest : public testing::Te EXPECT_EQ(recursive_manifest[i], native_manifest[i]); } } + + /** + * @brief Construct a verifier circuit for a proof whose data has been tampered with. Expect failure + * TODO(#656): For now we gat a "bad" proof by arbitrarily tampering with bits in a valid proof. It would be + * much nicer to explicitly change meaningful components, e.g. such that one of the multilinear evaluations is + * wrong. This is difficult now but should be straightforward if the proof is a struct. + */ + static void test_recursive_verification_fails() + { + // Create an arbitrary inner circuit + InnerBuilder inner_circuit; + create_inner_circuit(inner_circuit); + + // Generate a proof over the inner circuit + InnerComposer inner_composer; + auto instance = inner_composer.create_instance(inner_circuit); + auto inner_prover = inner_composer.create_prover(instance); + auto inner_proof = inner_prover.construct_proof(); + const auto native_verification_key = instance->compute_verification_key(); + + // Arbitrarily tamper with the proof to be verified + inner_proof.proof_data[10] = 25; + + // Create a recursive verification circuit for the proof of the inner circuit + OuterBuilder outer_circuit; + auto verification_key = std::make_shared(&outer_circuit, native_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 + EXPECT_FALSE(outer_circuit.check_circuit()); + } }; // Run the recursive verifier tests with conventional Ultra builder and Goblin builder @@ -202,4 +234,9 @@ HEAVY_TYPED_TEST(RecursiveVerifierTest, SingleRecursiveVerification) TestFixture::test_recursive_verification(); }; +HEAVY_TYPED_TEST(RecursiveVerifierTest, SingleRecursiveVerificationFailure) +{ + TestFixture::test_recursive_verification_fails(); +}; + } // namespace proof_system::plonk::stdlib::recursion::honk \ No newline at end of file