/********************************************************************** * Copyright (c) 2014-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #ifndef SECP256K1_MODULE_SCHNORR_TESTS #define SECP256K1_MODULE_SCHNORR_TESTS void test_schnorr_end_to_end(void) { unsigned char privkey[32]; unsigned char message[32]; unsigned char schnorr_signature[64]; secp256k1_pubkey_t pubkey, recpubkey; /* Generate a random key and message. */ { secp256k1_scalar_t key; random_scalar_order_test(&key); secp256k1_scalar_get_b32(privkey, &key); secp256k1_rand256_test(message); } /* Construct and verify corresponding public key. */ CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); /* Schnorr sign. */ CHECK(secp256k1_schnorr_sign(ctx, message, schnorr_signature, privkey, NULL, NULL) == 1); CHECK(secp256k1_schnorr_verify(ctx, message, schnorr_signature, &pubkey) == 1); CHECK(secp256k1_schnorr_recover(ctx, message, schnorr_signature, &recpubkey) == 1); CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); /* Destroy signature and verify again. */ schnorr_signature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); CHECK(secp256k1_schnorr_verify(ctx, message, schnorr_signature, &pubkey) == 0); CHECK(secp256k1_schnorr_recover(ctx, message, schnorr_signature, &recpubkey) != 1 || memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); } /** Horribly broken hash function. Do not use for anything but tests. */ void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { int i; for (i = 0; i < 32; i++) { h32[i] = r32[i] ^ msg32[i]; } } void test_schnorr_sign_verify(void) { unsigned char msg32[32]; unsigned char sig64[3][64]; secp256k1_gej_t pubkeyj[3]; secp256k1_ge_t pubkey[3]; secp256k1_scalar_t nonce[3], key[3]; int i = 0; int k; secp256k1_rand256_test(msg32); for (k = 0; k < 3; k++) { random_scalar_order_test(&key[k]); do { random_scalar_order_test(&nonce[k]); if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) { break; } } while(1); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]); secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]); CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32)); for (i = 0; i < 4; i++) { int pos = secp256k1_rand32() % 64; int mod = 1 + (secp256k1_rand32() % 255); sig64[k][pos] ^= mod; CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0); sig64[k][pos] ^= mod; } } } void test_schnorr_threshold(void) { unsigned char msg[32]; unsigned char sec[5][32]; secp256k1_pubkey_t pub[5]; unsigned char nonce[5][32]; secp256k1_pubkey_t pubnonce[5]; unsigned char sig[5][64]; const unsigned char* sigs[5]; unsigned char allsig[64]; const secp256k1_pubkey_t* pubs[5]; secp256k1_pubkey_t allpub; int n, i; int damage; int ret = 0; damage = (secp256k1_rand32() % 2) ? (1 + (secp256k1_rand32() % 4)) : 0; secp256k1_rand256_test(msg); n = 2 + (secp256k1_rand32() % 4); for (i = 0; i < n; i++) { do { secp256k1_rand256_test(sec[i]); } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, msg, sec[i], NULL, NULL, &pubnonce[i], nonce[i])); pubs[i] = &pub[i]; } if (damage == 1) { nonce[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); } else if (damage == 2) { sec[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); } for (i = 0; i < n; i++) { secp256k1_pubkey_t allpubnonce; const secp256k1_pubkey_t *pubnonces[4]; int j; for (j = 0; j < i; j++) { pubnonces[j] = &pubnonce[j]; } for (j = i + 1; j < n; j++) { pubnonces[j - 1] = &pubnonce[j]; } CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, n - 1, pubnonces)); ret |= (secp256k1_schnorr_partial_sign(ctx, msg, sig[i], sec[i], nonce[i], &allpubnonce) != 1) * 1; sigs[i] = sig[i]; } if (damage == 3) { sig[secp256k1_rand32() % n][secp256k1_rand32() % 64] ^= 1 + (secp256k1_rand32() % 255); } ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, n, pubs) != 1) * 2; if ((ret & 1) == 0) { ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, n, sigs) != 1) * 4; } if (damage == 4) { allsig[secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); } if ((ret & 7) == 0) { ret |= (secp256k1_schnorr_verify(ctx, msg, allsig, &allpub) != 1) * 8; } CHECK((ret == 0) == (damage == 0)); } void test_schnorr_recovery(void) { unsigned char msg32[32]; unsigned char sig64[64]; secp256k1_ge_t Q; secp256k1_rand256_test(msg32); secp256k1_rand256_test(sig64); secp256k1_rand256_test(sig64 + 32); if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) { CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1); } } void run_schnorr_tests(void) { int i; for (i = 0; i < 32*count; i++) { test_schnorr_end_to_end(); } for (i = 0; i < 32 * count; i++) { test_schnorr_sign_verify(); } for (i = 0; i < 16 * count; i++) { test_schnorr_recovery(); } for (i = 0; i < 10 * count; i++) { test_schnorr_threshold(); } } #endif