Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecdsa_constraints.test.cpp
Go to the documentation of this file.
2#include "acir_format.hpp"
9
10#include <algorithm>
11#include <gtest/gtest.h>
12#include <vector>
13
14using namespace bb;
15using namespace bb::crypto;
16using namespace acir_format;
17
18template <class Curve> class EcdsaTestingFunctions {
19 public:
20 using Builder = Curve::Builder;
21 using FrNative = Curve::ScalarFieldNative;
22 using FqNative = Curve::BaseFieldNative;
23 using G1Native = Curve::GroupNative;
25
27 public:
28 enum class Target : uint8_t {
29 None,
30 HashIsNotAByteArray, // Set one element of the hash > 255
31 ZeroR, // Set R=0 (tests ECDSA validation)
32 ZeroS, // Set S=0 (tests ECDSA validation)
33 HighS, // Set S=high (tests malleability protection)
34 P, // Invalidate public key
35 Result // Invalid signature with claimed valid result
36 };
37
43
44 static std::vector<std::string> get_labels()
45 {
46 return { "None", "Hash is not a byte array", "Zero R", "Zero S", "High S", "Public key", "Result" };
47 }
48 };
49
50 // Reproducible test
51 static constexpr FrNative private_key =
52 FrNative("0xd67abee717b3fc725adf59e2cc8cd916435c348b277dd814a34e3ceb279436c2");
53
55
57 AcirConstraint ecdsa_constraints,
58 WitnessVector witness_values,
59 const InvalidWitness::Target& invalid_witness_target)
60 {
61
62 // The ECDSA verification algorithm never makes the circuit fail, it just returns a boolean bearing witness to
63 // whether the verification succeeded or not. The only exception is HashIsNotAByteArray, in which case the
64 // byte_array constructors raises an error. To ensure that the failure mode caught by the test is specific to
65 // the particular case being tested, not just simple verification failure, we set the verification result to
66 // false for HashIsNotAByteArray and to true for every other case.
67 if (invalid_witness_target == InvalidWitness::Target::HashIsNotAByteArray) {
68 witness_values[ecdsa_constraints.result] = bb::fr(0);
69 }
70
71 switch (invalid_witness_target) {
73 // Set all bytes of hash to 256 (invalid as it doesn't fit in one byte)
74 for (size_t idx = 0; idx < 32; idx++) {
75 witness_values[ecdsa_constraints.hashed_message[idx]] = bb::fr(256);
76 };
77 break;
79 // Set r = 0 (invalid ECDSA signature component)
80 for (size_t idx = 0; idx < 32; idx++) {
81 witness_values[ecdsa_constraints.signature[idx]] = bb::fr(0);
82 };
83 break;
85 // Set s = 0 (tests ECDSA validation: s must be non-zero)
86 for (size_t idx = 32; idx < 64; idx++) {
87 witness_values[ecdsa_constraints.signature[idx]] = bb::fr(0);
88 };
89 break;
91 // Set s = high value (tests signature malleability protection)
92 for (size_t idx = 32; idx < 64; idx++) {
93 witness_values[ecdsa_constraints.signature[idx]] = bb::fr(255);
94 };
95 break;
97 // Invalidate public key
98 witness_values[ecdsa_constraints.pub_x_indices[0]] += bb::fr(1);
99 break;
101 // Test enforcement of verification result: tamper signature but claim it's valid
102 witness_values[ecdsa_constraints.signature[31]] = bb::fr(0);
103 break;
105 break;
106 }
107
108 return { ecdsa_constraints, witness_values };
109 }
110
114 static void generate_constraints(EcdsaConstraint& ecdsa_constraint, WitnessVector& witness_values)
115 {
116 std::string message_string = "Instructions unclear, ask again later.";
117
118 // Hash the message
119 std::vector<uint8_t> message_buffer(message_string.begin(), message_string.end());
120 std::array<uint8_t, 32> hashed_message = Sha256Hasher::hash(message_buffer);
121
122 // Generate ECDSA key pair
124 account.private_key = private_key;
125 account.public_key = G1Native::one * account.private_key;
126
127 // Generate signature
128 ecdsa_signature signature =
129 ecdsa_construct_signature<Sha256Hasher, FqNative, FrNative, G1Native>(message_string, account);
130
131 // Serialize public key coordinates into bytes
132 std::array<uint8_t, 32> buffer_x;
133 std::array<uint8_t, 32> buffer_y;
134 FqNative::serialize_to_buffer(account.public_key.x, &buffer_x[0]);
135 FqNative::serialize_to_buffer(account.public_key.y, &buffer_y[0]);
136
137 // Create witness indices and witnesses
138 std::array<uint32_t, 32> hashed_message_indices =
139 add_to_witness_and_track_indices<std::span<uint8_t>, 32>(witness_values, std::span(hashed_message));
140
141 std::array<uint32_t, 32> pub_x_indices =
142 add_to_witness_and_track_indices<std::span<uint8_t>, 32>(witness_values, std::span(buffer_x));
143
144 std::array<uint32_t, 32> pub_y_indices =
145 add_to_witness_and_track_indices<std::span<uint8_t>, 32>(witness_values, std::span(buffer_y));
146
147 std::array<uint32_t, 32> r_indices =
148 add_to_witness_and_track_indices<std::span<uint8_t>, 32>(witness_values, std::span(signature.r));
149
150 std::array<uint32_t, 32> s_indices =
151 add_to_witness_and_track_indices<std::span<uint8_t>, 32>(witness_values, std::span(signature.s));
152
153 uint32_t result_index = add_to_witness_and_track_indices(witness_values, bb::fr(1));
154
155 uint32_t predicate_index = add_to_witness_and_track_indices(witness_values, bb::fr(1));
156
157 // Restructure vectors into array
158 std::array<uint32_t, 64> signature_indices;
159 std::ranges::copy(r_indices, signature_indices.begin());
160 std::ranges::copy(s_indices, signature_indices.begin() + 32);
161
162 ecdsa_constraint = EcdsaConstraint{ .type = Curve::type,
163 .hashed_message = hashed_message_indices,
164 .signature = signature_indices,
165 .pub_x_indices = pub_x_indices,
166 .pub_y_indices = pub_y_indices,
167 .predicate = WitnessOrConstant<bb::fr>::from_index(predicate_index),
168 .result = result_index };
169 }
170};
171
172template <class Curve>
173class EcdsaConstraintsTest : public ::testing::Test, public TestClassWithPredicate<EcdsaTestingFunctions<Curve>> {
174 protected:
176};
177
178using CurveTypes = testing::Types<stdlib::secp256k1<UltraCircuitBuilder>,
182
184
185TYPED_TEST(EcdsaConstraintsTest, GenerateVKFromConstraints)
186{
187 using Flavor =
189 TestFixture::template test_vk_independence<Flavor>();
190}
191
193{
195 TestFixture::test_constant_true(TestFixture::InvalidWitnessTarget::Result);
196}
197
199{
201 TestFixture::test_witness_true(TestFixture::InvalidWitnessTarget::Result);
202}
203
205{
207 TestFixture::test_witness_false();
208}
209
211{
212 // This test is equal to WitnessFalse but also checks that each configuration would have failed if the
213 // predicate were witness true. It can be useful for debugging.
215 TestFixture::test_witness_false_slow();
216}
217
219{
221 [[maybe_unused]] std::vector<std::string> _ = TestFixture::test_invalid_witnesses();
222}
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:33
static constexpr FrNative private_key
static void generate_constraints(EcdsaConstraint &ecdsa_constraint, WitnessVector &witness_values)
Generate valid ECDSA constraint with witness predicate equal to true.
Curve::ScalarFieldNative FrNative
static ProgramMetadata generate_metadata()
static std::pair< AcirConstraint, WitnessVector > invalidate_witness(AcirConstraint ecdsa_constraints, WitnessVector witness_values, const InvalidWitness::Target &invalid_witness_target)
Curve::BaseFieldNative FqNative
Test class for ACIR constraints that contain a predicate.
std::vector< bb::fr > WitnessVector
std::vector< uint32_t > add_to_witness_and_track_indices(std::vector< bb::fr > &witness, const T &input)
Append values to a witness vector and track their indices.
Definition utils.hpp:90
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
field< Bn254FrParams > fr
Definition fr.hpp:155
::testing::Types< curve::BN254, curve::Grumpkin > CurveTypes
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static std::vector< std::string > get_labels()
std::array< uint32_t, 32 > pub_x_indices
std::array< uint32_t, 32 > hashed_message
std::array< uint32_t, 64 > signature
Metadata required to create a circuit.
static WitnessOrConstant from_index(uint32_t index)
static auto hash(const B &message)
Definition hashers.hpp:36
G1::affine_element public_key
Definition ecdsa.hpp:24
std::array< uint8_t, 32 > r
Definition ecdsa.hpp:31
std::array< uint8_t, 32 > s
Definition ecdsa.hpp:32