[Pkg-bitcoin-commits] [libsecp256k1] 10/27: recovery: add tests to cover API misusage

Jonas Smedegaard dr at jones.dk
Tue Jan 10 21:47:16 UTC 2017


This is an automated email from the git hooks/post-receive script.

js pushed a commit to branch master
in repository libsecp256k1.

commit b59516399211f6e3d2511d2b3a15491e99fdaba0
Author: Andrew Poelstra <apoelstra at wpsoftware.net>
Date:   Sat Nov 26 19:52:37 2016 +0000

    recovery: add tests to cover API misusage
---
 src/modules/recovery/main_impl.h  |   2 +-
 src/modules/recovery/tests_impl.h | 143 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+), 1 deletion(-)

diff --git a/src/modules/recovery/main_impl.h b/src/modules/recovery/main_impl.h
index 86f2f0c..c6fbe23 100755
--- a/src/modules/recovery/main_impl.h
+++ b/src/modules/recovery/main_impl.h
@@ -179,7 +179,7 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk
     ARG_CHECK(pubkey != NULL);
 
     secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
-    ARG_CHECK(recid >= 0 && recid < 4);
+    VERIFY_CHECK(recid >= 0 && recid < 4);  /* should have been caught in parse_compact */
     secp256k1_scalar_set_b32(&m, msg32, NULL);
     if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
         secp256k1_pubkey_save(pubkey, &q);
diff --git a/src/modules/recovery/tests_impl.h b/src/modules/recovery/tests_impl.h
index 8932d5f..765c7dd 100644
--- a/src/modules/recovery/tests_impl.h
+++ b/src/modules/recovery/tests_impl.h
@@ -7,6 +7,146 @@
 #ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
 #define _SECP256K1_MODULE_RECOVERY_TESTS_
 
+static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
+    (void) msg32;
+    (void) key32;
+    (void) algo16;
+    (void) data;
+
+    /* On the first run, return 0 to force a second run */
+    if (counter == 0) {
+        memset(nonce32, 0, 32);
+        return 1;
+    }
+    /* On the second run, return an overflow to force a third run */
+    if (counter == 1) {
+        memset(nonce32, 0xff, 32);
+        return 1;
+    }
+    /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
+    memset(nonce32, 1, 32);
+    return secp256k1_rand_bits(1);
+}
+
+void test_ecdsa_recovery_api(void) {
+    /* Setup contexts that just count errors */
+    secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+    secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+    secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
+    secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+    secp256k1_pubkey pubkey;
+    secp256k1_pubkey recpubkey;
+    secp256k1_ecdsa_signature normal_sig;
+    secp256k1_ecdsa_recoverable_signature recsig;
+    unsigned char privkey[32] = { 1 };
+    unsigned char message[32] = { 2 };
+    int32_t ecount = 0;
+    int recid = 0;
+    unsigned char sig[74];
+    unsigned char zero_privkey[32] = { 0 };
+    unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+    secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
+    secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
+    secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
+    secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
+    secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
+    secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
+    secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
+    secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
+
+    /* Construct and verify corresponding public key. */
+    CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
+    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+
+    /* Check bad contexts and NULLs for signing */
+    ecount = 0;
+    CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0);
+    CHECK(ecount == 1);
+    CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);
+    CHECK(ecount == 1);
+    CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);
+    CHECK(ecount == 3);
+    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);
+    CHECK(ecount == 4);
+    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);
+    CHECK(ecount == 5);
+    /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
+    secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);
+    CHECK(ecount == 5);
+    /* These will all fail, but not in ARG_CHECK way */
+    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);
+    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);
+    /* This one will succeed. */
+    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+    CHECK(ecount == 5);
+
+    /* Check signing with a goofy nonce function */
+
+    /* Check bad contexts and NULLs for recovery */
+    ecount = 0;
+    CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0);
+    CHECK(ecount == 1);
+    CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0);
+    CHECK(ecount == 3);
+    CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0);
+    CHECK(ecount == 4);
+    CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);
+    CHECK(ecount == 5);
+
+    /* Check NULLs for conversion */
+    CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);
+    ecount = 0;
+    CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);
+    CHECK(ecount == 1);
+    CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);
+
+    /* Check NULLs for de/serialization */
+    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+    ecount = 0;
+    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);
+    CHECK(ecount == 1);
+    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);
+    CHECK(ecount == 2);
+    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);
+    CHECK(ecount == 3);
+    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);
+
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);
+    CHECK(ecount == 4);
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);
+    CHECK(ecount == 5);
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);
+    CHECK(ecount == 6);
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);
+    CHECK(ecount == 7);
+    /* overflow in signature will fail but not affect ecount */
+    memcpy(sig, over_privkey, 32);
+    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);
+    CHECK(ecount == 7);
+
+    /* cleanup */
+    secp256k1_context_destroy(none);
+    secp256k1_context_destroy(sign);
+    secp256k1_context_destroy(vrfy);
+    secp256k1_context_destroy(both);
+}
+
 void test_ecdsa_recovery_end_to_end(void) {
     unsigned char extra[32] = {0x00};
     unsigned char privkey[32];
@@ -241,6 +381,9 @@ void test_ecdsa_recovery_edge_cases(void) {
 
 void run_recovery_tests(void) {
     int i;
+    for (i = 0; i < count; i++) {
+        test_ecdsa_recovery_api();
+    }
     for (i = 0; i < 64*count; i++) {
         test_ecdsa_recovery_end_to_end();
     }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-bitcoin/libsecp256k1.git



More information about the Pkg-bitcoin-commits mailing list