Skip to content

Commit

Permalink
Improve signing API documentation & specification
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa committed Feb 14, 2015
1 parent 7b2fc1c commit 8030d7c
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 9 deletions.
13 changes: 8 additions & 5 deletions include/secp256k1.h
Expand Up @@ -106,14 +106,16 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;

/** Create an ECDSA signature.
* Returns: 1: signature created
* 0: the nonce generation function failed
* 0: the nonce generation function failed, the private key was invalid, or there is not
* enough space in the signature (as indicated by siglen).
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In/Out: siglen: pointer to an int with the length of sig, which will be updated
* to contain the actual signature length (<=72).
* to contain the actual signature length (<=72). If 0 is returned, this will be
* set to zero.
* Requires starting using SECP256K1_START_SIGN.
*
* The sig always has an s value in the lower half of the range (From 0x1
Expand Down Expand Up @@ -153,12 +155,13 @@ int secp256k1_ecdsa_sign(

/** Create a compact ECDSA signature (64 byte + recovery id).
* Returns: 1: signature created
* 0: the nonce generation function failed
* 0: the nonce generation function failed, or the secret key was invalid.
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
* Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL)
* In case 0 is returned, the returned signature length will be zero.
* recid: pointer to an int, which will be updated to contain the recovery id (can be NULL)
* Requires starting using SECP256K1_START_SIGN.
*/
Expand Down
18 changes: 16 additions & 2 deletions src/secp256k1.c
Expand Up @@ -87,7 +87,11 @@ int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, i
noncefp = secp256k1_nonce_function_default;
}

secp256k1_scalar_set_b32(&sec, seckey, NULL);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
if (overflow || secp256k1_scalar_is_zero(&sec)) {
*signaturelen = 0;
return 0;
}
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
unsigned char nonce32[32];
Expand All @@ -107,6 +111,9 @@ int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, i
if (ret) {
ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
}
if (!ret) {
*signaturelen = 0;
}
secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non);
secp256k1_scalar_clear(&sec);
Expand All @@ -127,7 +134,11 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig6
noncefp = secp256k1_nonce_function_default;
}

secp256k1_scalar_set_b32(&sec, seckey, NULL);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
if (overflow || secp256k1_scalar_is_zero(&sec)) {
memset(sig64, 0, 64);
return 0;
}
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
unsigned char nonce32[32];
Expand All @@ -148,6 +159,9 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig6
secp256k1_scalar_get_b32(sig64, &sig.r);
secp256k1_scalar_get_b32(sig64 + 32, &sig.s);
}
if (!ret) {
memset(sig64, 0, 64);
}
secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non);
secp256k1_scalar_clear(&sec);
Expand Down
34 changes: 32 additions & 2 deletions src/tests.c
Expand Up @@ -1229,6 +1229,11 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char
return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data);
}

int is_empty_compact_signature(const unsigned char *sig64) {
static const unsigned char res[64] = {0};
return memcmp(sig64, res, 64) == 0;
}

void test_ecdsa_end_to_end(void) {
unsigned char privkey[32];
unsigned char message[32];
Expand Down Expand Up @@ -1300,6 +1305,7 @@ void test_ecdsa_end_to_end(void) {

/* Sign. */
CHECK(secp256k1_ecdsa_sign(message, signature, &signaturelen, privkey, NULL, NULL) == 1);
CHECK(signaturelen > 0);
/* Verify. */
CHECK(secp256k1_ecdsa_verify(message, signature, signaturelen, pubkey, pubkeylen) == 1);
/* Destroy signature and verify again. */
Expand All @@ -1308,6 +1314,7 @@ void test_ecdsa_end_to_end(void) {

/* Compact sign. */
CHECK(secp256k1_ecdsa_sign_compact(message, csignature, privkey, NULL, NULL, &recid) == 1);
CHECK(!is_empty_compact_signature(csignature));
/* Recover. */
CHECK(secp256k1_ecdsa_recover_compact(message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1);
CHECK(recpubkeylen == pubkeylen);
Expand Down Expand Up @@ -1588,13 +1595,18 @@ void test_ecdsa_edge_cases(void) {
unsigned char sig[72];
int siglen = 72;
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0);
CHECK(siglen == 0);
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0);
CHECK(siglen == 0);
msg[31] = 0xaa;
siglen = 72;
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1);
CHECK(siglen > 0);
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1);
CHECK(siglen > 0);
siglen = 10;
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1);
CHECK(siglen == 0);
}

/* Nonce function corner cases. */
Expand All @@ -1608,36 +1620,54 @@ void test_ecdsa_edge_cases(void) {
int siglen = 72;
int siglen2 = 72;
int recid2;
memset(key, 0, 32);
memset(msg, 0, 32);
key[31] = 1;
msg[31] = 1;
/* High key results in signature failure. */
memset(key, 0xFF, 32);
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, NULL) == 0);
CHECK(siglen == 0);
/* Zero key results in signature failure. */
memset(key, 0, 32);
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, NULL) == 0);
CHECK(siglen == 0);
/* Nonce function failure results in signature failure. */
key[31] = 1;
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_fail, NULL) == 0);
CHECK(siglen == 0);
CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_fail, NULL, &recid) == 0);
CHECK(is_empty_compact_signature(sig));
/* The retry loop successfully makes its way to the first good value. */
siglen = 72;
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_retry, NULL) == 1);
CHECK(siglen > 0);
CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, nonce_function_rfc6979, NULL) == 1);
CHECK(siglen > 0);
CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0));
CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_retry, NULL, &recid) == 1);
CHECK(!is_empty_compact_signature(sig));
CHECK(secp256k1_ecdsa_sign_compact(msg, sig2, key, nonce_function_rfc6979, NULL, &recid2) == 1);
CHECK(!is_empty_compact_signature(sig2));
CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0));
/* The default nonce function is determinstic. */
siglen = 72;
siglen2 = 72;
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, NULL) == 1);
CHECK(siglen > 0);
CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, NULL) == 1);
CHECK(siglen2 > 0);
CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0));
CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, NULL, NULL, &recid) == 1);
CHECK(!is_empty_compact_signature(sig));
CHECK(secp256k1_ecdsa_sign_compact(msg, sig2, key, NULL, NULL, &recid2) == 1);
CHECK(!is_empty_compact_signature(sig));
CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0));
/* The default nonce function changes output with different messages. */
for(i = 0; i < 256; i++) {
int j;
siglen2 = 72;
msg[0] = i;
CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, NULL) == 1);
CHECK(!is_empty_compact_signature(sig));
CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2));
for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r));
Expand Down

0 comments on commit 8030d7c

Please sign in to comment.