Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Separate ECDSA recovery tests
  • Loading branch information
sipa committed Aug 27, 2015
1 parent 439d34a commit d49abbd
Showing 1 changed file with 163 additions and 134 deletions.
297 changes: 163 additions & 134 deletions src/tests.c
Expand Up @@ -1844,15 +1844,12 @@ void test_ecdsa_end_to_end(void) {
unsigned char message[32];
unsigned char privkey2[32];
secp256k1_ecdsa_signature_t signature[5];
secp256k1_ecdsa_recoverable_signature_t rsignature[5];
unsigned char sig[74];
int siglen = 74;
unsigned char pubkeyc[65];
int pubkeyclen = 65;
secp256k1_pubkey_t pubkey;
secp256k1_pubkey_t recpubkey;
unsigned char seckey[300];
int recid = 0;
int seckeylen = 300;

/* Generate a random key and message. */
Expand Down Expand Up @@ -1944,6 +1941,31 @@ void test_ecdsa_end_to_end(void) {
sig[secp256k1_rand32() % siglen] += 1 + (secp256k1_rand32() % 255);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 ||
secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 0);
}

void test_ecdsa_recovery_end_to_end(void) {
unsigned char extra[32] = {0x00};
unsigned char privkey[32];
unsigned char message[32];
secp256k1_ecdsa_signature_t signature[5];
secp256k1_ecdsa_recoverable_signature_t rsignature[5];
unsigned char sig[74];
secp256k1_pubkey_t pubkey;
secp256k1_pubkey_t recpubkey;
int recid = 0;

/* Generate a random key and message. */
{
secp256k1_scalar_t msg, key;
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
secp256k1_scalar_get_b32(privkey, &key);
secp256k1_scalar_get_b32(message, &msg);
}

/* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);

/* Serialize/parse compact and verify/recover. */
extra[0] = 0;
Expand Down Expand Up @@ -2053,11 +2075,148 @@ void run_ecdsa_end_to_end(void) {
int i;
for (i = 0; i < 64*count; i++) {
test_ecdsa_end_to_end();
test_ecdsa_recovery_end_to_end();
}
}

/* Tests several edge cases. */
void test_ecdsa_edge_cases(void) {
int t;
secp256k1_ecdsa_signature_t sig;

/* Test the case where ECDSA recomputes a point that is infinity. */
{
secp256k1_gej_t keyj;
secp256k1_ge_t key;
secp256k1_scalar_t msg;
secp256k1_scalar_t sr, ss;
secp256k1_scalar_set_int(&ss, 1);
secp256k1_scalar_negate(&ss, &ss);
secp256k1_scalar_inverse(&ss, &ss);
secp256k1_scalar_set_int(&sr, 1);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr);
secp256k1_ge_set_gej(&key, &keyj);
msg = ss;
CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
}

/*Signature where s would be zero.*/
{
unsigned char signature[72];
int siglen;
const unsigned char nonce[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
};
static const unsigned char nonce2[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
};
const unsigned char key[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
};
unsigned char msg[32] = {
0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53,
0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7,
0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62,
0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9,
};
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce) == 0);
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 0);
msg[31] = 0xaa;
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 1);
siglen = 72;
CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1);
siglen = 10;
CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0);
}

/* Nonce function corner cases. */
for (t = 0; t < 2; t++) {
static const unsigned char zero[32] = {0x00};
int i;
unsigned char key[32];
unsigned char msg[32];
secp256k1_ecdsa_signature_t sig2;
secp256k1_scalar_t sr[512], ss;
const unsigned char *extra;
extra = t == 0 ? NULL : zero;
memset(msg, 0, 32);
msg[31] = 1;
/* High key results in signature failure. */
memset(key, 0xFF, 32);
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0);
CHECK(is_empty_signature(&sig));
/* Zero key results in signature failure. */
memset(key, 0, 32);
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0);
CHECK(is_empty_signature(&sig));
/* Nonce function failure results in signature failure. */
key[31] = 1;
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_fail, extra) == 0);
CHECK(is_empty_signature(&sig));
/* The retry loop successfully makes its way to the first good value. */
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_retry, extra) == 1);
CHECK(!is_empty_signature(&sig));
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, nonce_function_rfc6979, extra) == 1);
CHECK(!is_empty_signature(&sig2));
CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
/* The default nonce function is determinstic. */
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
CHECK(!is_empty_signature(&sig2));
CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
/* The default nonce function changes output with different messages. */
for(i = 0; i < 256; i++) {
int j;
msg[0] = i;
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
CHECK(!is_empty_signature(&sig2));
secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
}
}
msg[0] = 0;
msg[31] = 2;
/* The default nonce function changes output with different keys. */
for(i = 256; i < 512; i++) {
int j;
key[0] = i - 256;
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
CHECK(!is_empty_signature(&sig2));
secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
}
}
key[0] = 0;
}

/* Privkey export where pubkey is the point at infinity. */
{
unsigned char privkey[300];
unsigned char seckey[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
};
int outlen = 300;
CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 0));
CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 1));
}
}

/* Tests several edge cases. */
void test_ecdsa_recovery_edge_cases(void) {
const unsigned char msg32[32] = {
'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
Expand All @@ -2077,7 +2236,6 @@ void test_ecdsa_edge_cases(void) {
0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
};
secp256k1_pubkey_t pubkey;
int t;
/* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
const unsigned char sigb64[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Expand Down Expand Up @@ -2196,22 +2354,6 @@ void test_ecdsa_edge_cases(void) {
}
}

/* Test the case where ECDSA recomputes a point that is infinity. */
{
secp256k1_gej_t keyj;
secp256k1_ge_t key;
secp256k1_scalar_t msg;
secp256k1_scalar_t sr, ss;
secp256k1_scalar_set_int(&ss, 1);
secp256k1_scalar_negate(&ss, &ss);
secp256k1_scalar_inverse(&ss, &ss);
secp256k1_scalar_set_int(&sr, 1);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr);
secp256k1_ge_set_gej(&key, &keyj);
msg = ss;
CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
}

/* Test r/s equal to zero */
{
/* (1,1) encoded in DER. */
Expand Down Expand Up @@ -2246,124 +2388,11 @@ void test_ecdsa_edge_cases(void) {
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 0);
}

/*Signature where s would be zero.*/
{
unsigned char signature[72];
int siglen;
const unsigned char nonce[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
};
static const unsigned char nonce2[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
};
const unsigned char key[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
};
unsigned char msg[32] = {
0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53,
0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7,
0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62,
0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9,
};
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce) == 0);
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 0);
msg[31] = 0xaa;
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 1);
siglen = 72;
CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1);
siglen = 10;
CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0);
}

/* Nonce function corner cases. */
for (t = 0; t < 2; t++) {
static const unsigned char zero[32] = {0x00};
int i;
unsigned char key[32];
unsigned char msg[32];
secp256k1_ecdsa_signature_t sig2;
secp256k1_scalar_t sr[512], ss;
const unsigned char *extra;
extra = t == 0 ? NULL : zero;
memset(msg, 0, 32);
msg[31] = 1;
/* High key results in signature failure. */
memset(key, 0xFF, 32);
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0);
CHECK(is_empty_signature(&sig));
/* Zero key results in signature failure. */
memset(key, 0, 32);
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0);
CHECK(is_empty_signature(&sig));
/* Nonce function failure results in signature failure. */
key[31] = 1;
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_fail, extra) == 0);
CHECK(is_empty_signature(&sig));
/* The retry loop successfully makes its way to the first good value. */
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_retry, extra) == 1);
CHECK(!is_empty_signature(&sig));
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, nonce_function_rfc6979, extra) == 1);
CHECK(!is_empty_signature(&sig2));
CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
/* The default nonce function is determinstic. */
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
CHECK(!is_empty_signature(&sig2));
CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
/* The default nonce function changes output with different messages. */
for(i = 0; i < 256; i++) {
int j;
msg[0] = i;
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
CHECK(!is_empty_signature(&sig2));
secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
}
}
msg[0] = 0;
msg[31] = 2;
/* The default nonce function changes output with different keys. */
for(i = 256; i < 512; i++) {
int j;
key[0] = i - 256;
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
CHECK(!is_empty_signature(&sig2));
secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);
for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
}
}
key[0] = 0;
}

/* Privkey export where pubkey is the point at infinity. */
{
unsigned char privkey[300];
unsigned char seckey[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
};
int outlen = 300;
CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 0));
CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 1));
}
}

void run_ecdsa_edge_cases(void) {
test_ecdsa_edge_cases();
test_ecdsa_recovery_edge_cases();
}

#ifdef ENABLE_OPENSSL_TESTS
Expand Down

0 comments on commit d49abbd

Please sign in to comment.