Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecdsa.test.cpp
Go to the documentation of this file.
2#include "../../primitives/bigfield/bigfield.hpp"
3#include "../../primitives/biggroup/biggroup.hpp"
4#include "../../primitives/curves/secp256k1.hpp"
5#include "../../primitives/curves/secp256r1.hpp"
8#include "ecdsa.hpp"
10
11#include <gtest/gtest.h>
12
13#include <algorithm>
14
15using namespace bb;
16using namespace bb::crypto;
17
18template <class Curve> class EcdsaTests : public ::testing::Test {
19 public:
20 using Builder = Curve::Builder;
21 using CurveType =
23
24 // Native Types
25 using FrNative = Curve::fr;
26 using FqNative = Curve::fq;
27 using G1Native = Curve::g1;
28
29 // Stdlib types
30 using Fr = Curve::bigfr_ct;
31 using Fq = Curve::fq_ct;
32 using G1 = Curve::g1_bigfr_ct;
33 using bool_t = Curve::bool_ct;
34
35 // Reproducible signature
36 static constexpr FrNative private_key =
37 FrNative("0xd67abee717b3fc725adf59e2cc8cd916435c348b277dd814a34e3ceb279436c2");
38
52
54 bool random_signature)
55 {
57
58 account.private_key = random_signature ? FrNative::random_element() : private_key;
59 account.public_key = G1Native::one * account.private_key;
60
61 ecdsa_signature signature =
62 ecdsa_construct_signature<Sha256Hasher, FqNative, FrNative, G1Native>(message_string, account);
63
64 if (random_signature) {
65 // Logging in case of random signature
66 info("The private key used generate this signature is: ", private_key);
67 }
68
69 return { account, signature };
70 }
71
72 std::string tampering(std::string message_string,
74 ecdsa_signature& signature,
76 {
77 std::string failure_msg;
78
79 switch (mode) {
81 // Invalidate the circuit by passing a public key with x >= q
82 // Do nothing here, tampering happens in circuit
83 failure_msg = "ECDSA input validation: coordinate(s) of the public key bigger than the base field modulus. "
84 "(x coordinate): hi limb.";
85 break;
86 }
88 // Invalidate the circuit by passing a public key with y >= q
89 // Do nothing here, tampering happens in circuit
90 failure_msg = "ECDSA input validation: coordinate(s) of the public key bigger than the base field modulus. "
91 "(y coordinate): hi limb.";
92 break;
93 }
95 // Invalidate the signature by changing r.
96 FrNative r = FrNative::serialize_from_buffer(&signature.r[0]);
97 r += FrNative::one();
98
99 FrNative::serialize_to_buffer(r, &signature.r[0]);
100 break;
101 }
103 // Invalidate the signature by changing s.
104 FrNative s = FrNative::serialize_from_buffer(&signature.s[0]);
105 s += FrNative::one();
106
107 FrNative::serialize_to_buffer(s, &signature.s[0]);
108 break;
109 }
111 // Invalidate the signature by changing s to -s.
112 FrNative s = FrNative::serialize_from_buffer(&signature.s[0]);
113 s = -s;
114
115 FrNative::serialize_to_buffer(s, &signature.s[0]);
116 failure_msg =
117 "ECDSA input validation: the s component of the signature is bigger than (Fr::modulus + 1)/2.: "
118 "hi limb."; // The second part of the message is added by the range constraint
119 break;
120 }
122 // Invalidate signature by setting r to 0
123 signature.r = std::array<uint8_t, 32>{};
124
125 failure_msg = "ECDSA input validation: the r component of the signature is zero.";
126 break;
127 }
129 // Invalidate signature by setting s to 0
130 signature.s = std::array<uint8_t, 32>{};
131
132 failure_msg = "ECDSA input validation: the s component of the signature is zero.";
133 break;
134 }
136 // Invalidate the signature by making making u1 * G + u2 * P return the point at infinity
137
138 // Compute H(m)
139 std::vector<uint8_t> buffer;
140 std::ranges::copy(message_string, std::back_inserter(buffer));
142
143 // Override the public key: new public key is (-hash) * r^{-1} * G
144 FrNative fr_hash = FrNative::serialize_from_buffer(&hash[0]);
145 FrNative r = FrNative::serialize_from_buffer(&signature.r[0]);
146 FrNative r_inverse = r.invert();
147 FrNative modified_private_key = r_inverse * (-fr_hash);
148 account.public_key = G1Native::one * modified_private_key;
149
150 // Verify that the result is the point at infinity
151 auto P = G1Native::one * fr_hash + account.public_key * r;
152 BB_ASSERT_EQ(P.is_point_at_infinity(), true);
153
154 failure_msg = "ECDSA validation: the result of the batch multiplication is the point at infinity.";
155 break;
156 }
158 // Invalidate the circuit by passing a public key which is not on the curve
159 account.public_key.x = account.public_key.y;
160 BB_ASSERT_EQ(account.public_key.on_curve(), false);
161
162 failure_msg = "ECDSA input validation: the public key is not a point on the elliptic curve.";
163 break;
164 }
166 // Invalidate the circuit by passing a public key which is not on the curve
167 account.public_key.self_set_infinity();
168 BB_ASSERT_EQ(account.public_key.is_point_at_infinity(), true);
169
170 failure_msg = "ECDSA input validation: the public key is the point at infinity.";
171 break;
172 }
174 break;
175 }
176
177 // Natively verify that the tampering was successfull
178 bool is_signature_valid = ecdsa_verify_signature<Sha256Hasher, FqNative, FrNative, G1Native>(
179 message_string, account.public_key, signature);
181 // If either s >= (n+1)/2 or the result of the scalar multiplication is the point at infinity, then the
182 // verification function raises an error, we treat it as an invalid signature
183 is_signature_valid = false;
184 }
186 // In these tampering modes nothing has changed and the tampering happens in circuit, so we override the
187 // result and set it to false
188 is_signature_valid = false;
189 }
190
191 bool expected = mode == TamperingMode::None;
192 BB_ASSERT_EQ(is_signature_valid,
193 expected,
194 "Signature verification returned a different result from the expected one. If the signature was "
195 "randomly generated, there is a (very) small chance this is not a bug.");
196
197 return failure_msg;
198 }
199
203 const ecdsa_signature& signature,
204 const TamperingMode mode)
205 {
206 // We construct the point via its x,y-coordinates to avoid the on curve check of G1::from_witness. In this way
207 // we test the on curve check of the ecdsa verification function
208 Fq x = Fq::from_witness(&builder, account.public_key.x);
209 Fq y = Fq::from_witness(&builder, account.public_key.y);
211 // To test the case in which one of the two coordinates is above the modulus of the base field, we need to
212 // override the limbs of the coordinates
213 uint256_t max_uint = (static_cast<uint256_t>(1) << 256) - 1;
214 for (size_t idx = 0; idx < 4; idx++) {
216 ? x.binary_basis_limbs[idx].element.get_witness_index()
217 : y.binary_basis_limbs[idx].element.get_witness_index(),
218 bb::fr(max_uint.slice(64 * idx, 64 * (idx + 1))));
219 }
220 }
221 bool_t is_infinity(
222 stdlib::witness_t<Builder>(&builder, account.public_key.is_point_at_infinity() ? fr::one() : fr::zero()),
223 false);
224 G1 pub_key(x, y, is_infinity, /*assert_on_curve=*/false);
225 pub_key.set_free_witness_tag();
226 BB_ASSERT_EQ(pub_key.is_point_at_infinity().get_value(), account.public_key.is_point_at_infinity());
227
228 std::vector<uint8_t> rr(signature.r.begin(), signature.r.end());
229 std::vector<uint8_t> ss(signature.s.begin(), signature.s.end());
230
233
234 return { pub_key, sig };
235 }
236
238 const stdlib::byte_array<Builder>& hashed_message,
240 const ecdsa_signature& signature,
241 const bool signature_verification_result,
242 const bool circuit_checker_result,
243 const std::string failure_msg,
244 const TamperingMode mode)
245
246 {
247 auto [public_key, sig] = create_stdlib_ecdsa_data(builder, account, signature, mode);
248
249 // Verify signature
250 stdlib::bool_t<Builder> signature_result =
251 stdlib::ecdsa_verify_signature<Builder, Curve, Fq, Fr, G1>(hashed_message, public_key, sig);
252
253 // Enforce verification returns the expected result
254 signature_result.assert_equal(stdlib::bool_t<Builder>(signature_verification_result));
255
256 // Check native values
257 EXPECT_EQ(signature_result.get_value(), signature_verification_result);
258
259 // Log data
260 size_t finalized_num_gates = builder.get_num_finalized_gates_inefficient();
261 info("num gates = ", finalized_num_gates);
262 benchmark_info(Builder::NAME_STRING, "ECDSA", "Signature Verification Test", "Gate Count", finalized_num_gates);
263
264 // Circuit checker
265 bool is_circuit_satisfied = CircuitChecker::check(builder);
266 EXPECT_EQ(is_circuit_satisfied, circuit_checker_result);
267
268 // Check the error
269 EXPECT_EQ(builder.err(), failure_msg);
270
271 return finalized_num_gates;
272 }
273
274 size_t test_verify_signature(bool random_signature, TamperingMode mode)
275 {
276 // Map tampering mode to signature verification result
277 bool signature_verification_result = (mode == TamperingMode::None) || (mode == TamperingMode::HighS);
278 // Map tampering mode to circuit checker result
279 bool circuit_checker_result =
281
282 std::string message_string = "Goblin";
283 std::vector<uint8_t> message_bytes(message_string.begin(), message_string.end());
284 std::array<uint8_t, 32> hashed_message_bytes_ = Sha256Hasher::hash(message_bytes);
285 std::vector<uint8_t> hashed_message_bytes;
286 hashed_message_bytes.reserve(32);
287 for (auto byte : hashed_message_bytes_) {
288 hashed_message_bytes.emplace_back(byte);
289 }
290
291 auto [account, signature] = generate_dummy_ecdsa_data(message_string, /*random_signature=*/random_signature);
292
293 // Tamper with the signature
294 std::string failure_msg = tampering(message_string, account, signature, mode);
295
296 // Create ECDSA verification circuit
298 stdlib::byte_array<Builder> hashed_message(&builder, hashed_message_bytes);
299
300 // ECDSA verification
302 hashed_message,
303 account,
304 signature,
305 signature_verification_result,
306 circuit_checker_result,
307 failure_msg,
308 mode);
309 }
310
317 {
318 for (auto test : tests) {
319 // Keypair
321 account.private_key = FrNative::one(); // Dummy value, unused
322 account.public_key = typename G1Native::affine_element(test.x, test.y);
323
324 // Signature
325 std::array<uint8_t, 32> r;
326 std::array<uint8_t, 32> s;
327 uint8_t v = 0; // Dummy value, unused
328 FrNative::serialize_to_buffer(test.r, &r[0]);
329 FrNative::serialize_to_buffer(test.s, &s[0]);
330
331 // Hashed message
332 std::array<uint8_t, 32> hashed_message_bytes_ = Sha256Hasher::hash(test.message);
333 std::vector<uint8_t> hashed_message_bytes;
334 hashed_message_bytes.reserve(32);
335 for (auto byte : hashed_message_bytes_) {
336 hashed_message_bytes.emplace_back(byte);
337 }
338
339 // Create ECDSA verification circuit
341 stdlib::byte_array<Builder> hashed_message(&builder, hashed_message_bytes);
342
343 // ECDSA verification
345 hashed_message,
346 account,
347 { r, s, v },
348 test.is_valid_signature,
349 test.is_circuit_satisfied,
350 test.failure_msg,
352 }
353 }
354};
355
356using Curves = testing::Types<stdlib::secp256k1<UltraCircuitBuilder>,
360
362
363TYPED_TEST(EcdsaTests, VerifyRandomSignature)
364{
365 TestFixture::test_verify_signature(/*random_signature=*/true, TestFixture::TamperingMode::None);
366}
367
368TYPED_TEST(EcdsaTests, VerifySignature)
369{
370 using Curve = TypeParam;
371
372 size_t finalized_num_gates =
373 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::None);
374 static constexpr size_t NUM_GATES_SECP256K1 = 41966;
375 static constexpr size_t NUM_GATES_SECP256R1 = IsMegaBuilder<typename Curve::Builder> ? 72025 : 72023;
376 BB_ASSERT_EQ(finalized_num_gates,
377 Curve::type == bb::CurveType::SECP256K1 ? NUM_GATES_SECP256K1 : NUM_GATES_SECP256R1,
378 "There has been a change in the number of gates for ECDSA verification");
379}
380
381TYPED_TEST(EcdsaTests, XCoordinateOverflow)
382{
384 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::XCoordinateOverflow);
385}
386
387TYPED_TEST(EcdsaTests, YCoordinateOverflow)
388{
390 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::YCoordinateOverflow);
391}
392
394{
395 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::InvalidR);
396}
397
399{
400 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::InvalidS);
401}
402
404{
405 // Disable asserts because native ecdsa verification raises an error if s >= (n+1)/2
407 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::HighS);
408}
409
411{
412 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::ZeroR);
413}
414
416{
417 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::ZeroS);
418}
419
420TYPED_TEST(EcdsaTests, InvalidPubKey)
421{
422 // Disable asserts because `validate_on_curve` raises an error in the `mult_madd` function:
423 // BB_ASSERT_EQ(remainder_1024.lo, uint512_t(0))
425 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::InvalidPubKey);
426}
427
428TYPED_TEST(EcdsaTests, InfinityPubKey)
429{
430 // Disable asserts to avoid errors trying to invert zero
432 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::InfinityPubKey);
433}
434
435TYPED_TEST(EcdsaTests, InfinityScalarMul)
436{
437 // Disable asserts because native ecdsa verification raises an error if the result of the scalar multiplication is
438 // the point at infinity
440 TestFixture::test_verify_signature(/*random_signature=*/false, TestFixture::TamperingMode::InfinityScalarMul);
441}
442
444{
445 if constexpr (TypeParam::type == bb::CurveType::SECP256K1) {
446 TestFixture::test_wycherproof(stdlib::secp256k1_tests);
447 } else {
448 TestFixture::test_wycherproof(stdlib::secp256r1_tests);
449 }
450}
451
452TEST(EcdsaTests, Secp256k1PointAtInfinityRegression)
453{
454 // Disable asserts because native ecdsa verification raises an error if the result of the scalar multiplication is
455 // the point at infinity
458
459 using FqNative = Curve::fq;
460 using FrNative = Curve::fr;
461 using G1Native = Curve::g1;
462
463 using Builder = Curve::Builder;
464 using FrStdlib = Curve::bigfr_ct;
465 using FqStdlib = Curve::fq_ct;
466 using G1Stdlib = Curve::g1_bigfr_ct;
467
468 // Attack parameters for P = 5*G
469 // These are crafted so that u1*G + u2*P = O (point at infinity)
470 const std::array<uint8_t, 32> pub_x_bytes = { 0x2f, 0x8b, 0xde, 0x4d, 0x1a, 0x07, 0x20, 0x93, 0x55, 0xb4, 0xa7,
471 0x25, 0x0a, 0x5c, 0x51, 0x28, 0xe8, 0x8b, 0x84, 0xbd, 0xdc, 0x61,
472 0x9a, 0xb7, 0xcb, 0xa8, 0xd5, 0x69, 0xb2, 0x40, 0xef, 0xe4 };
473 const std::array<uint8_t, 32> pub_y_bytes = { 0xd8, 0xac, 0x22, 0x26, 0x36, 0xe5, 0xe3, 0xd6, 0xd4, 0xdb, 0xa9,
474 0xdd, 0xa6, 0xc9, 0xc4, 0x26, 0xf7, 0x88, 0x27, 0x1b, 0xab, 0x0d,
475 0x68, 0x40, 0xdc, 0xa8, 0x7d, 0x3a, 0xa6, 0xac, 0x62, 0xd6 };
476 const std::array<uint8_t, 32> r_bytes = { 0xa8, 0x41, 0x94, 0xc3, 0x71, 0xc6, 0x7b, 0xa2, 0x59, 0x2f, 0x59,
477 0xc6, 0x20, 0xad, 0x30, 0x4c, 0xb7, 0x6d, 0x7a, 0x88, 0x25, 0x6b,
478 0xb5, 0x0d, 0xc4, 0x1c, 0x66, 0x57, 0x44, 0xbf, 0x78, 0x61 };
479 const std::array<uint8_t, 32> s_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
480 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64 };
482 const std::array<uint8_t, 32> z_bytes = { 0xb6, 0xb8, 0x18, 0x2e, 0xc7, 0x1f, 0x95, 0xd4, 0x42, 0x13, 0x3f,
483 0x21, 0x5c, 0x9e, 0x0e, 0x7b, 0x55, 0x98, 0x0e, 0xf2, 0x02, 0x07,
484 0xf7, 0xaa, 0x2a, 0xbb, 0x7a, 0x7e, 0xe9, 0x1b, 0xab, 0x1f };
485
486 FqNative pub_x = FqNative::serialize_from_buffer(pub_x_bytes.data());
487 FqNative pub_y = FqNative::serialize_from_buffer(pub_y_bytes.data());
488 typename G1Native::affine_element public_key_native(pub_x, pub_y);
489 ASSERT_TRUE(public_key_native.on_curve()) << "Public key must be on curve";
490
491 // Native verification
492 const std::string message_string(z_bytes.begin(), z_bytes.end());
493 ecdsa_signature sig;
494 sig.r = r_bytes;
495 sig.s = s_bytes;
496 sig.v = 27;
497 bool native_verification =
498 ecdsa_verify_signature<Sha256Hasher, FqNative, FrNative, G1Native>(message_string, public_key_native, sig);
499
500 bool stdlib_verification;
501 {
503
504 const G1Stdlib public_key_ct = G1Stdlib::from_witness(&builder, public_key_native);
505
506 const std::vector<uint8_t> r_vec(r_bytes.begin(), r_bytes.end());
507 const std::vector<uint8_t> s_vec(s_bytes.begin(), s_bytes.end());
510
511 const std::vector<uint8_t> z_vec(z_bytes.begin(), z_bytes.end());
512 const stdlib::byte_array<Builder> hashed_message_ct(&builder, z_vec);
513
514 const stdlib::bool_t<Builder> signature_result =
515 stdlib::ecdsa_verify_signature<Builder, Curve, FqStdlib, FrStdlib, G1Stdlib>(
516 hashed_message_ct, public_key_ct, sig_ct);
517
518 stdlib_verification = signature_result.get_value();
519
520 const bool circuit_valid = CircuitChecker::check(builder);
521
522 // Circuit should fail because the result of the scalar multiplication is the point at infinity
523 ASSERT_FALSE(circuit_valid);
524 EXPECT_EQ(builder.err(), "ECDSA validation: the result of the batch multiplication is the point at infinity.");
525 }
526
527 // Both native and stdlib should reject this invalid signature
528 EXPECT_FALSE(native_verification);
529 EXPECT_FALSE(stdlib_verification);
530 EXPECT_EQ(native_verification, stdlib_verification);
531}
532
533TEST(EcdsaTests, Secp256r1NativeStdlibDiscrepancyRegression)
534{
536
537 using FqNative = Curve::fq;
538 using FrNative = Curve::fr;
539 using G1Native = Curve::g1;
540
541 using Builder = Curve::Builder;
542 using FrStdlib = Curve::bigfr_ct;
543 using FqStdlib = Curve::fq_ct;
544 using G1Stdlib = Curve::g1_bigfr_ct;
545
546 const std::array<uint8_t, 32> pub_x_bytes = { 0x79, 0x9f, 0x2a, 0xba, 0xfa, 0x27, 0x16, 0x4b, 0x09, 0x50, 0xf2,
547 0xc8, 0x82, 0xf0, 0xd1, 0x67, 0xe1, 0xd2, 0x16, 0x74, 0x87, 0xd5,
548 0x2e, 0xa7, 0x23, 0x0b, 0x5d, 0x96, 0xc2, 0xa8, 0x74, 0x00 };
549 const std::array<uint8_t, 32> pub_y_bytes = { 0xda, 0xa5, 0x79, 0xf4, 0xf1, 0x61, 0xe9, 0xdc, 0xa1, 0xa1, 0x34,
550 0x35, 0x92, 0x16, 0xb9, 0x35, 0xea, 0xd0, 0x97, 0x2d, 0x76, 0x3f,
551 0xe3, 0x33, 0xc7, 0x12, 0xee, 0x8d, 0x18, 0x4b, 0xd8, 0x11 };
552 const std::array<uint8_t, 32> r_bytes = { 0xb1, 0x99, 0xa1, 0x62, 0x72, 0x66, 0x61, 0xba, 0x23, 0x3c, 0xd6,
553 0xc6, 0x6e, 0x99, 0x0b, 0x01, 0x2e, 0x1e, 0x76, 0x04, 0xb1, 0x1f,
554 0x76, 0x19, 0x3b, 0x2a, 0xf5, 0xca, 0x36, 0xc1, 0x01, 0x76 };
555 const std::array<uint8_t, 32> s_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 };
558 const std::array<uint8_t, 32> z_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 };
561
562 const FqNative pub_x = FqNative::serialize_from_buffer(pub_x_bytes.data());
563 const FqNative pub_y = FqNative::serialize_from_buffer(pub_y_bytes.data());
564 const typename G1Native::affine_element public_key_native(pub_x, pub_y);
565 ASSERT_TRUE(public_key_native.on_curve()) << "Public key must be on curve";
566
567 // Native verification
568 const std::string message_string(z_bytes.begin(), z_bytes.end());
569 ecdsa_signature sig;
570 sig.r = r_bytes;
571 sig.s = s_bytes;
572 sig.v = 27;
573 bool native_verification =
574 ecdsa_verify_signature<Sha256Hasher, FqNative, FrNative, G1Native>(message_string, public_key_native, sig);
575
576 // Stdlib verification
578 const G1Stdlib public_key_ct = G1Stdlib::from_witness(&builder, public_key_native);
579
580 const std::vector<uint8_t> r_vec(r_bytes.begin(), r_bytes.end());
581 const std::vector<uint8_t> s_vec(s_bytes.begin(), s_bytes.end());
584
585 const std::vector<uint8_t> z_vec(z_bytes.begin(), z_bytes.end());
586 const stdlib::byte_array<Builder> hashed_message_ct(&builder, z_vec);
587
588 const stdlib::bool_t<Builder> signature_result =
589 stdlib::ecdsa_verify_signature<Builder, Curve, FqStdlib, FrStdlib, G1Stdlib>(
590 hashed_message_ct, public_key_ct, sig_ct);
591
592 bool stdlib_verification = signature_result.get_value();
593
594 const bool circuit_valid = CircuitChecker::check(builder);
595 ASSERT_TRUE(circuit_valid);
596
597 EXPECT_EQ(native_verification, stdlib_verification);
598}
599
600TEST(EcdsaTests, Secp256r1NafOverflowRegression)
601{
603
604 using FqNative = Curve::fq;
605 using G1Native = Curve::g1;
606
607 using Builder = Curve::Builder;
608 using FrStdlib = Curve::bigfr_ct;
609 using FqStdlib = Curve::fq_ct;
610 using G1Stdlib = Curve::g1_bigfr_ct;
611
612 const std::array<uint8_t, 32> pub_x_bytes = { 0xbd, 0xae, 0xdd, 0xff, 0x80, 0x69, 0x8b, 0xd0, 0xb5, 0xdb, 0x79,
613 0x10, 0xe1, 0xc6, 0x56, 0x9d, 0xc3, 0x4e, 0x77, 0x3b, 0xda, 0x69,
614 0x5e, 0x61, 0x5c, 0x87, 0xf5, 0x4e, 0x6a, 0x70, 0x7e, 0xd6 };
615 const std::array<uint8_t, 32> pub_y_bytes = { 0xc1, 0xb3, 0x69, 0x9c, 0x7e, 0xea, 0x97, 0xbe, 0x5e, 0x52, 0x3d,
616 0x47, 0x5c, 0x5f, 0x72, 0x00, 0x97, 0x2c, 0x61, 0x23, 0xf2, 0xcd,
617 0x3d, 0x59, 0x33, 0x54, 0xe7, 0x4d, 0x35, 0xd1, 0x85, 0x11 };
618 const std::array<uint8_t, 32> r_bytes = { 0x4d, 0xc6, 0x6f, 0x06, 0x26, 0x12, 0x5d, 0x49, 0xb5, 0xa7, 0x7d,
619 0x36, 0xc3, 0xf9, 0x7e, 0x9b, 0xb8, 0x29, 0x48, 0xf2, 0xbd, 0xdc,
620 0xf8, 0x43, 0xe5, 0xee, 0x13, 0x3c, 0xc8, 0x96, 0xf1, 0xd8 };
621 const std::array<uint8_t, 32> s_bytes = { 0x52, 0x59, 0x33, 0x34, 0x92, 0xf6, 0x68, 0x42, 0x1a, 0xe0, 0x63,
622 0x3f, 0x2d, 0x16, 0x92, 0x4b, 0x9f, 0x3b, 0xe9, 0x36, 0xee, 0xd3,
623 0xf1, 0x96, 0x28, 0x6e, 0x0a, 0x57, 0x5d, 0xe2, 0x9f, 0xb7 };
624 const std::array<uint8_t, 32> z_bytes = { 0x93, 0xd5, 0x0c, 0x3d, 0xd6, 0xd6, 0xc3, 0xf7, 0xf7, 0x55, 0x0e,
625 0x69, 0x76, 0x40, 0x2b, 0x89, 0xaa, 0xf2, 0xd6, 0x8a, 0x7a, 0x94,
626 0x80, 0x44, 0x69, 0xaa, 0x69, 0x03, 0x15, 0xb8, 0x64, 0x31 };
627
628 const FqNative pub_x = FqNative::serialize_from_buffer(pub_x_bytes.data());
629 const FqNative pub_y = FqNative::serialize_from_buffer(pub_y_bytes.data());
630 const typename G1Native::affine_element public_key_native(pub_x, pub_y);
631 ASSERT_TRUE(public_key_native.on_curve()) << "Public key must be on curve";
632
634 const G1Stdlib public_key_ct = G1Stdlib::from_witness(&builder, public_key_native);
635
636 const std::vector<uint8_t> r_vec(r_bytes.begin(), r_bytes.end());
637 const std::vector<uint8_t> s_vec(s_bytes.begin(), s_bytes.end());
640
641 const std::vector<uint8_t> z_vec(z_bytes.begin(), z_bytes.end());
642 const stdlib::byte_array<Builder> hashed_message_ct(&builder, z_vec);
643
644 const stdlib::bool_t<Builder> signature_result =
645 stdlib::ecdsa_verify_signature<Builder, Curve, FqStdlib, FrStdlib, G1Stdlib>(
646 hashed_message_ct, public_key_ct, sig_ct);
647
648 // Verification should succeed for this valid signature
649 EXPECT_TRUE(signature_result.get_value());
650
651 const bool circuit_valid = CircuitChecker::check(builder);
652 ASSERT_TRUE(circuit_valid);
653}
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:33
size_t ecdsa_verification_circuit(Builder &builder, const stdlib::byte_array< Builder > &hashed_message, const ecdsa_key_pair< FrNative, G1Native > &account, const ecdsa_signature &signature, const bool signature_verification_result, const bool circuit_checker_result, const std::string failure_msg, const TamperingMode mode)
Curve::bigfr_ct Fr
Curve::g1_bigfr_ct G1
static constexpr FrNative private_key
Curve::fr FrNative
std::string tampering(std::string message_string, ecdsa_key_pair< FrNative, G1Native > &account, ecdsa_signature &signature, TamperingMode mode)
std::conditional_t< Curve::type==bb::CurveType::SECP256K1, bb::curve::SECP256K1, bb::curve::SECP256R1 > CurveType
std::pair< ecdsa_key_pair< FrNative, G1Native >, ecdsa_signature > generate_dummy_ecdsa_data(std::string message_string, bool random_signature)
size_t test_verify_signature(bool random_signature, TamperingMode mode)
Curve::fq FqNative
void test_wycherproof(std::vector< stdlib::WycherproofTest< CurveType > > tests)
Construct tests based on data fetched from the Wycherproof project.
Curve::fq_ct Fq
Curve::Builder Builder
Curve::bool_ct bool_t
std::pair< G1, stdlib::ecdsa_signature< Builder > > create_stdlib_ecdsa_data(Builder &builder, const ecdsa_key_pair< FrNative, G1Native > &account, const ecdsa_signature &signature, const TamperingMode mode)
Curve::g1 G1Native
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
constexpr uint256_t slice(uint64_t start, uint64_t end) const
Implements boolean logic in-circuit.
Definition bool.hpp:60
bool get_value() const
Definition bool.hpp:125
void assert_equal(const bool_t &rhs, std::string const &msg="bool_t::assert_equal") const
Implements copy constraint for bool_t elements.
Definition bool.cpp:433
Represents a dynamic array of bytes in-circuit.
#define info(...)
Definition log.hpp:93
void benchmark_info(Args...)
Info used to store circuit statistics during CI/CD with concrete structure. Writes straight to log.
Definition log.hpp:121
AluTraceBuilder builder
Definition alu.test.cpp:124
uint8_t buffer[RANDOM_BUFFER_SIZE]
Definition engine.cpp:44
void hash(State &state) noexcept
const std::vector< WycherproofSecp256k1 > secp256k1_tests
Test for Secp256k1 ECDSA signatures taken from the Wycherproof project.
const std::vector< WycherproofSecp256r1 > secp256r1_tests
Test for Secp256r1 ECDSA signatures taken from the Wycherproof project.
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
field< Bn254FrParams > fr
Definition fr.hpp:174
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
@ SECP256K1
Definition types.hpp:10
::testing::Types< curve::BN254, curve::Grumpkin > Curves
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static auto hash(const B &message)
Definition hashers.hpp:36
G1::affine_element public_key
Definition ecdsa.hpp:20
std::array< uint8_t, 32 > r
Definition ecdsa.hpp:26
std::array< uint8_t, 32 > s
Definition ecdsa.hpp:27
static constexpr field one()
static constexpr field zero()