66#include " barretenberg/dsl/acir_format/witness_constant.hpp"
77#include " barretenberg/stdlib/primitives/curves/secp256k1.hpp"
88#include " barretenberg/stdlib/primitives/curves/secp256r1.hpp"
9+ #include " barretenberg/ultra_honk/ultra_prover.hpp"
10+ #include " barretenberg/ultra_honk/ultra_verifier.hpp"
911
1012#include < algorithm>
1113#include < gtest/gtest.h>
14+ #include < memory>
1215#include < vector>
1316
1417using namespace bb ;
@@ -31,7 +34,7 @@ template <class Curve> class EcdsaTestingFunctions {
3134 ZeroR, // Set R=0 (tests ECDSA validation)
3235 ZeroS, // Set S=0 (tests ECDSA validation)
3336 HighS, // Set S=high (tests malleability protection)
34- P, // Invalidate public key
37+ P, // Make public key fail the curve equation
3538 Result // Invalid signature with claimed valid result
3639 };
3740
@@ -43,7 +46,8 @@ template <class Curve> class EcdsaTestingFunctions {
4346
4447 static std::vector<std::string> get_labels ()
4548 {
46- return { " None" , " Hash is not a byte array" , " Zero R" , " Zero S" , " High S" , " Public key" , " Result" };
49+ return { " None" , " Hash is not a byte array" , " Zero R" , " Zero S" ,
50+ " High S" , " Public key not on curve" , " Result" };
4751 }
4852 };
4953
@@ -53,6 +57,20 @@ template <class Curve> class EcdsaTestingFunctions {
5357
5458 static ProgramMetadata generate_metadata () { return ProgramMetadata{}; }
5559
60+ static std::pair<AcirConstraint, WitnessVector> generate_invalid_verification_result_constraints (
61+ const InvalidWitness::Target& invalid_witness_target)
62+ {
63+ AcirConstraint ecdsa_constraint;
64+ WitnessVector witness_values;
65+ generate_constraints (ecdsa_constraint, witness_values);
66+
67+ auto [invalid_constraint, invalid_witness_values] =
68+ invalidate_witness (ecdsa_constraint, witness_values, invalid_witness_target);
69+
70+ invalid_witness_values[invalid_constraint.result ] = bb::fr (0 );
71+ return { invalid_constraint, invalid_witness_values };
72+ }
73+
5674 static std::pair<AcirConstraint, WitnessVector> invalidate_witness (
5775 AcirConstraint ecdsa_constraints,
5876 WitnessVector witness_values,
@@ -94,7 +112,7 @@ template <class Curve> class EcdsaTestingFunctions {
94112 };
95113 break ;
96114 case InvalidWitness::Target::P:
97- // Invalidate public key
115+ // Invalidate public key so signature verification returns false.
98116 witness_values[ecdsa_constraints.pub_x_indices [0 ]] += bb::fr (1 );
99117 break ;
100118 case InvalidWitness::Target::Result:
@@ -169,6 +187,24 @@ template <class Curve> class EcdsaTestingFunctions {
169187 }
170188};
171189
190+ template <typename Flavor> bool construct_and_verify_honk_proof (typename Flavor::CircuitBuilder& builder)
191+ {
192+ using Prover = UltraProver_<Flavor>;
193+ using Verifier = UltraVerifier_<Flavor, DefaultIO>;
194+ using ProverInstance = ProverInstance_<Flavor>;
195+ using VerificationKey = typename Flavor::VerificationKey;
196+
197+ auto prover_instance = std::make_shared<ProverInstance>(builder);
198+ auto verification_key = std::make_shared<VerificationKey>(prover_instance->get_precomputed ());
199+ auto vk_and_hash = std::make_shared<typename Flavor::VKAndHash>(verification_key);
200+
201+ Prover prover (prover_instance, verification_key);
202+ auto proof = prover.construct_proof ();
203+
204+ Verifier verifier (vk_and_hash);
205+ return verifier.verify_proof (proof).result ;
206+ }
207+
172208template <class Curve >
173209class EcdsaConstraintsTest : public ::testing::Test, public TestClassWithPredicate<EcdsaTestingFunctions<Curve>> {
174210 protected:
@@ -220,3 +256,34 @@ TYPED_TEST(EcdsaConstraintsTest, InvalidWitnesses)
220256 BB_DISABLE_ASSERTS ();
221257 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses ();
222258}
259+
260+ TYPED_TEST (EcdsaConstraintsTest, InvalidVerificationInputsReturnFalseAndProve)
261+ {
262+ BB_DISABLE_ASSERTS ();
263+ using Builder = typename TypeParam::Builder;
264+ using Flavor = std::conditional_t <std::is_same_v<Builder, UltraCircuitBuilder>, UltraFlavor, MegaFlavor>;
265+ using InvalidWitnessTarget = typename TestFixture::InvalidWitnessTarget;
266+
267+ const std::vector<InvalidWitnessTarget> invalid_targets = {
268+ InvalidWitnessTarget::ZeroR,
269+ InvalidWitnessTarget::ZeroS,
270+ InvalidWitnessTarget::P,
271+ };
272+ const std::vector<std::string> target_labels = { " zero r" , " zero s" , " public key not on curve" };
273+
274+ for (auto [invalid_target, target_label] : zip_view (invalid_targets, target_labels)) {
275+ SCOPED_TRACE (target_label);
276+
277+ auto [constraint, witness_values] =
278+ TestFixture::Base::generate_invalid_verification_result_constraints (invalid_target);
279+ ASSERT_EQ (witness_values[constraint.result ], bb::fr (0 ));
280+
281+ AcirFormat constraint_system = constraint_to_acir_format (constraint);
282+ AcirProgram program{ constraint_system, witness_values };
283+ auto builder = create_circuit<Builder>(program, TestFixture::Base::generate_metadata ());
284+
285+ EXPECT_TRUE (CircuitChecker::check (builder));
286+ EXPECT_FALSE (builder.failed ()) << builder.err ();
287+ EXPECT_TRUE (construct_and_verify_honk_proof<Flavor>(builder));
288+ }
289+ }
0 commit comments