You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
6.1 KiB
173 lines
6.1 KiB
/**********************************************************************
|
|
* 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
|
|
|