2#include "../../primitives/bigfield/bigfield.hpp"
3#include "../../primitives/biggroup/biggroup.hpp"
4#include "../../primitives/curves/secp256k1.hpp"
5#include "../../primitives/curves/secp256r1.hpp"
11#include <gtest/gtest.h>
18template <
class Curve>
class EcdsaTests :
public ::testing::Test {
30 using Fr = Curve::bigfr_ct;
31 using Fq = Curve::fq_ct;
32 using G1 = Curve::g1_bigfr_ct;
37 FrNative(
"0xd67abee717b3fc725adf59e2cc8cd916435c348b277dd814a34e3ceb279436c2");
53 bool random_signature)
61 ecdsa_construct_signature<Sha256Hasher, FqNative, FrNative, G1Native>(message_string, account);
63 if (random_signature) {
68 return { account, signature };
82 FrNative k = FrNative::random_element();
83 typename G1Native::affine_element R = G1Native::one * k;
84 FqNative::serialize_to_buffer(R.x, &signature.
r[0]);
86 FrNative r = FrNative::serialize_from_buffer(&signature.
r[0]);
89 bool is_s_low = (
static_cast<uint256_t>(s) < (FrNative::modulus + 1) / 2);
90 s = is_s_low ? s : -s;
91 FrNative::serialize_to_buffer(s, &signature.
s[0]);
96 bool recovery_bit = y_parity ^ is_s_low;
97 constexpr uint8_t
offset = 27;
100 offset +
static_cast<int>(recovery_bit) + (
static_cast<uint8_t
>(2) *
static_cast<int>(!is_r_finite));
102 signature.
v =
static_cast<uint8_t
>(
value);
106 typename G1Native::affine_element Q = G1Native::one * ((fr_hash * s_inverse) + (r * s_inverse *
private_key));
109 "Signature with out of bounds message failed verification");
119 std::string failure_msg;
124 FrNative r = FrNative::serialize_from_buffer(&signature.
r[0]);
125 r += FrNative::one();
127 FrNative::serialize_to_buffer(r, &signature.
r[0]);
132 FrNative s = FrNative::serialize_from_buffer(&signature.
s[0]);
133 s += FrNative::one();
135 FrNative::serialize_to_buffer(s, &signature.
s[0]);
140 FrNative s = FrNative::serialize_from_buffer(&signature.
s[0]);
143 FrNative::serialize_to_buffer(s, &signature.
s[0]);
144 failure_msg =
"ECDSA input validation: the s component of the signature is bigger than Fr::modulus - s.: "
153 failure_msg =
"ECDSA input validation: the hash of the message is bigger than the order of the elliptic "
159 signature.
r = std::array<uint8_t, 32>{};
161 failure_msg =
"ECDSA input validation: the r component of the signature is zero.";
166 signature.
s = std::array<uint8_t, 32>{};
168 failure_msg =
"ECDSA input validation: the s component of the signature is zero.";
175 std::vector<uint8_t>
buffer;
180 FrNative fr_hash = FrNative::serialize_from_buffer(&
hash[0]);
181 FrNative r = FrNative::serialize_from_buffer(&signature.
r[0]);
183 FrNative modified_private_key = r_inverse * (-fr_hash);
184 account.
public_key = G1Native::one * modified_private_key;
187 auto P = G1Native::one * fr_hash + account.
public_key * r;
190 failure_msg =
"ECDSA validation: the result of the batch multiplication is the point at infinity.";
198 failure_msg =
"ECDSA input validation: the public key is not a point on the elliptic curve.";
206 failure_msg =
"ECDSA input validation: the public key is the point at infinity.";
214 bool is_signature_valid = ecdsa_verify_signature<Sha256Hasher, FqNative, FrNative, G1Native>(
215 message_string, account.
public_key, signature);
219 is_signature_valid =
false;
225 "Signature verification returned a different result from the expected one. If the signature was "
226 "randomly generated, there is a (very) small chance this is not a bug.");
241 G1 pub_key(x, y, is_infinity);
242 pub_key.set_free_witness_tag();
245 std::vector<uint8_t> rr(signature.
r.begin(), signature.
r.end());
246 std::vector<uint8_t> ss(signature.
s.begin(), signature.
s.end());
251 return { pub_key, sig };
258 const bool signature_verification_result,
259 const bool circuit_checker_result,
260 const std::string failure_msg)
267 stdlib::ecdsa_verify_signature<Builder, Curve, Fq, Fr, G1>(hashed_message, public_key, sig);
273 EXPECT_EQ(signature_result.
get_value(), signature_verification_result);
279 "Signature Verification Test",
281 builder.get_estimated_num_finalized_gates());
285 EXPECT_EQ(is_circuit_satisfied, circuit_checker_result);
288 EXPECT_EQ(
builder.err(), failure_msg);
292 std::vector<uint8_t>& message_bytes,
305 std::array<uint8_t, 32> hashed_message_witness;
309 FqNative::serialize_to_buffer(fr_hash, &hashed_message_witness[0]);
312 &
builder, std::vector<uint8_t>(hashed_message_witness.begin(), hashed_message_witness.end()));
317 return hashed_message;
323 bool signature_verification_result =
326 bool circuit_checker_result =
329 std::string message_string =
"Goblin";
330 std::vector<uint8_t> message_bytes(message_string.begin(), message_string.end());
335 std::string failure_msg =
tampering(message_string, account, signature, mode);
348 signature_verification_result,
349 circuit_checker_result,
360 for (
auto test : tests) {
364 account.
public_key =
typename G1Native::affine_element(test.x, test.y);
367 std::array<uint8_t, 32> r;
368 std::array<uint8_t, 32> s;
370 FrNative::serialize_to_buffer(test.r, &r[0]);
371 FrNative::serialize_to_buffer(test.s, &s[0]);
385 test.is_valid_signature,
386 test.is_circuit_satisfied,
392using Curves = testing::Types<stdlib::secp256k1<UltraCircuitBuilder>,
401 TestFixture::test_verify_signature(
true, TestFixture::TamperingMode::None);
406 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::None);
411 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InvalidR);
416 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InvalidS);
423 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::HighS);
428 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::ZeroR);
433 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::ZeroS);
441 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InvalidPubKey);
448 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InfinityPubKey);
453 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::OutOfBoundsHash);
461 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InfinityScalarMul);
#define BB_ASSERT_EQ(actual, expected,...)
#define BB_ASSERT_LTE(left, right,...)
#define BB_DISABLE_ASSERTS()
static constexpr FrNative private_key
void test_verify_signature(bool random_signature, TamperingMode mode)
void 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)
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)
std::pair< G1, stdlib::ecdsa_signature< Builder > > create_stdlib_ecdsa_data(Builder &builder, const ecdsa_key_pair< FrNative, G1Native > &account, const ecdsa_signature &signature)
stdlib::byte_array< Builder > construct_hashed_message(Builder &builder, std::vector< uint8_t > &message_bytes, TamperingMode mode)
void test_wycherproof(std::vector< stdlib::WycherproofTest< CurveType > > tests)
Construct tests based on data fetched from the Wycherproof project.
ecdsa_signature generate_signature_out_of_bounds_hash()
Generate valid signature for the message Fr(1)
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
constexpr bool get_bit(uint64_t bit_index) const
static byte_array< Builder > hash(const byte_array_ct &input)
Implements boolean logic in-circuit.
void assert_equal(const bool_t &rhs, std::string const &msg="bool_t::assert_equal") const
Implements copy constraint for bool_t elements.
Represents a dynamic array of bytes in-circuit.
void benchmark_info(Args...)
Info used to store circuit statistics during CI/CD with concrete structure. Writes straight to log.
uint8_t buffer[RANDOM_BUFFER_SIZE]
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.
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
::testing::Types< curve::BN254, curve::Grumpkin > Curves
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
static auto hash(const B &message)
G1::affine_element public_key
std::array< uint8_t, 32 > r
std::array< uint8_t, 32 > s
static constexpr field one()
static constexpr field zero()