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");
54 bool random_signature)
62 ecdsa_construct_signature<Sha256Hasher, FqNative, FrNative, G1Native>(message_string, account);
64 if (random_signature) {
69 return { account, signature };
77 std::string failure_msg;
83 failure_msg =
"ECDSA input validation: coordinate(s) of the public key bigger than the base field modulus. "
84 "(x coordinate): hi limb.";
90 failure_msg =
"ECDSA input validation: coordinate(s) of the public key bigger than the base field modulus. "
91 "(y coordinate): hi limb.";
96 FrNative r = FrNative::serialize_from_buffer(&signature.
r[0]);
99 FrNative::serialize_to_buffer(r, &signature.
r[0]);
104 FrNative s = FrNative::serialize_from_buffer(&signature.
s[0]);
105 s += FrNative::one();
107 FrNative::serialize_to_buffer(s, &signature.
s[0]);
112 FrNative s = FrNative::serialize_from_buffer(&signature.
s[0]);
115 FrNative::serialize_to_buffer(s, &signature.
s[0]);
117 "ECDSA input validation: the s component of the signature is bigger than (Fr::modulus + 1)/2.: "
123 signature.
r = std::array<uint8_t, 32>{};
125 failure_msg =
"ECDSA input validation: the r component of the signature is zero.";
130 signature.
s = std::array<uint8_t, 32>{};
132 failure_msg =
"ECDSA input validation: the s component of the signature is zero.";
139 std::vector<uint8_t>
buffer;
144 FrNative fr_hash = FrNative::serialize_from_buffer(&
hash[0]);
145 FrNative r = FrNative::serialize_from_buffer(&signature.
r[0]);
147 FrNative modified_private_key = r_inverse * (-fr_hash);
148 account.
public_key = G1Native::one * modified_private_key;
151 auto P = G1Native::one * fr_hash + account.
public_key * r;
154 failure_msg =
"ECDSA validation: the result of the batch multiplication is the point at infinity.";
162 failure_msg =
"ECDSA input validation: the public key is not a point on the elliptic curve.";
170 failure_msg =
"ECDSA input validation: the public key is the point at infinity.";
178 bool is_signature_valid = ecdsa_verify_signature<Sha256Hasher, FqNative, FrNative, G1Native>(
179 message_string, account.
public_key, signature);
183 is_signature_valid =
false;
188 is_signature_valid =
false;
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.");
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(),
224 G1 pub_key(x, y, is_infinity,
false);
225 pub_key.set_free_witness_tag();
228 std::vector<uint8_t> rr(signature.
r.begin(), signature.
r.end());
229 std::vector<uint8_t> ss(signature.
s.begin(), signature.
s.end());
234 return { pub_key, sig };
241 const bool signature_verification_result,
242 const bool circuit_checker_result,
243 const std::string failure_msg,
251 stdlib::ecdsa_verify_signature<Builder, Curve, Fq, Fr, G1>(hashed_message, public_key, sig);
257 EXPECT_EQ(signature_result.
get_value(), signature_verification_result);
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);
266 EXPECT_EQ(is_circuit_satisfied, circuit_checker_result);
269 EXPECT_EQ(
builder.err(), failure_msg);
271 return finalized_num_gates;
279 bool circuit_checker_result =
282 std::string message_string =
"Goblin";
283 std::vector<uint8_t> message_bytes(message_string.begin(), message_string.end());
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);
294 std::string failure_msg =
tampering(message_string, account, signature,
mode);
305 signature_verification_result,
306 circuit_checker_result,
318 for (
auto test : tests) {
322 account.
public_key =
typename G1Native::affine_element(test.x, test.y);
325 std::array<uint8_t, 32> r;
326 std::array<uint8_t, 32> s;
328 FrNative::serialize_to_buffer(test.r, &r[0]);
329 FrNative::serialize_to_buffer(test.s, &s[0]);
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);
348 test.is_valid_signature,
349 test.is_circuit_satisfied,
356using Curves = testing::Types<stdlib::secp256k1<UltraCircuitBuilder>,
365 TestFixture::test_verify_signature(
true, TestFixture::TamperingMode::None);
370 using Curve = TypeParam;
372 size_t finalized_num_gates =
373 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::None);
374 static constexpr size_t NUM_GATES_SECP256K1 = 41965;
378 "There has been a change in the number of gates for ECDSA verification");
384 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::XCoordinateOverflow);
390 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::YCoordinateOverflow);
395 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InvalidR);
400 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InvalidS);
407 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::HighS);
412 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::ZeroR);
417 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::ZeroS);
425 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InvalidPubKey);
432 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InfinityPubKey);
440 TestFixture::test_verify_signature(
false, TestFixture::TamperingMode::InfinityScalarMul);
#define BB_ASSERT_EQ(actual, expected,...)
#define BB_DISABLE_ASSERTS()
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)
static constexpr FrNative private_key
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)
void test_wycherproof(std::vector< stdlib::WycherproofTest< CurveType > > tests)
Construct tests based on data fetched from the Wycherproof project.
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)
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.
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)
field< Bn254FrParams > fr
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()