/********************************************************************** * Copyright (c) 2014-2016 Pieter Wuille, Andrew Poelstra * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #ifndef SECP256K1_MODULE_WHITELIST_TESTS_H #define SECP256K1_MODULE_WHITELIST_TESTS_H #include "../../../include/secp256k1_whitelist.h" #include "../../unit_test.h" static void test_whitelist_end_to_end_internal(const unsigned char *summed_seckey, const unsigned char *online_seckey, const secp256k1_pubkey *online_pubkeys, const secp256k1_pubkey *offline_pubkeys, const secp256k1_pubkey *sub_pubkey, const size_t signer_i, const size_t n_keys) { unsigned char serialized[32 + 4 + 32 * SECP256K1_WHITELIST_MAX_N_KEYS] = {0}; size_t slen = sizeof(serialized); secp256k1_whitelist_signature sig; secp256k1_whitelist_signature sig1; CHECK(secp256k1_whitelist_sign(CTX, &sig, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey, online_seckey, summed_seckey, signer_i)); CHECK(secp256k1_whitelist_verify(CTX, &sig, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey) == 1); /* Check that exchanging keys causes a failure */ CHECK(secp256k1_whitelist_verify(CTX, &sig, offline_pubkeys, online_pubkeys, n_keys, sub_pubkey) != 1); /* Serialization round trip */ CHECK(secp256k1_whitelist_signature_serialize(CTX, serialized, &slen, &sig) == 1); CHECK(slen == 33 + 32 * n_keys); /* (Check various bad-length conditions) */ CHECK(secp256k1_whitelist_signature_parse(CTX, &sig1, serialized, slen + 32) == 0); CHECK(secp256k1_whitelist_signature_parse(CTX, &sig1, serialized, slen + 1) == 0); CHECK(secp256k1_whitelist_signature_parse(CTX, &sig1, serialized, slen - 1) == 0); CHECK(secp256k1_whitelist_signature_parse(CTX, &sig1, serialized, 0) == 0); /* A failed parse must leave a signature that fails validation for any * key set, as documented on secp256k1_whitelist_signature_parse. */ CHECK(secp256k1_whitelist_signature_n_keys(&sig1) > SECP256K1_WHITELIST_MAX_N_KEYS); CHECK(secp256k1_whitelist_verify(CTX, &sig1, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey) == 0); /* Re-parse to restore a valid state. */ CHECK(secp256k1_whitelist_signature_parse(CTX, &sig1, serialized, slen) == 1); CHECK(secp256k1_whitelist_verify(CTX, &sig1, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey) == 1); CHECK(secp256k1_whitelist_verify(CTX, &sig1, offline_pubkeys, online_pubkeys, n_keys, sub_pubkey) != 1); /* Test n_keys */ CHECK(secp256k1_whitelist_signature_n_keys(&sig) == n_keys); CHECK(secp256k1_whitelist_signature_n_keys(&sig1) == n_keys); /* Test bad number of keys in signature */ sig.n_keys = n_keys + 1; CHECK(secp256k1_whitelist_verify(CTX, &sig, offline_pubkeys, online_pubkeys, n_keys, sub_pubkey) != 1); sig.n_keys = n_keys; } static void test_whitelist_end_to_end(const size_t n_keys, int test_all_keys) { unsigned char **online_seckey = malloc(n_keys * sizeof(*online_seckey)); unsigned char **summed_seckey = malloc(n_keys * sizeof(*summed_seckey)); secp256k1_pubkey *online_pubkeys = malloc(n_keys * sizeof(*online_pubkeys)); secp256k1_pubkey *offline_pubkeys = malloc(n_keys * sizeof(*offline_pubkeys)); secp256k1_scalar ssub; unsigned char csub[32]; secp256k1_pubkey sub_pubkey; /* Generate random keys */ size_t i; /* Start with subkey */ testutil_random_scalar_order_test(&ssub); secp256k1_scalar_get_b32(csub, &ssub); CHECK(secp256k1_ec_seckey_verify(CTX, csub) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &sub_pubkey, csub) == 1); /* Then offline and online whitelist keys */ for (i = 0; i < n_keys; i++) { secp256k1_scalar son, soff; online_seckey[i] = malloc(32); summed_seckey[i] = malloc(32); /* Create two keys */ testutil_random_scalar_order_test(&son); secp256k1_scalar_get_b32(online_seckey[i], &son); CHECK(secp256k1_ec_seckey_verify(CTX, online_seckey[i]) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &online_pubkeys[i], online_seckey[i]) == 1); testutil_random_scalar_order_test(&soff); secp256k1_scalar_get_b32(summed_seckey[i], &soff); CHECK(secp256k1_ec_seckey_verify(CTX, summed_seckey[i]) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &offline_pubkeys[i], summed_seckey[i]) == 1); /* Make summed_seckey correspond to the sum of offline_pubkey and sub_pubkey */ secp256k1_scalar_add(&soff, &soff, &ssub); secp256k1_scalar_get_b32(summed_seckey[i], &soff); CHECK(secp256k1_ec_seckey_verify(CTX, summed_seckey[i]) == 1); } /* Sign/verify with each one */ if (test_all_keys) { for (i = 0; i < n_keys; i++) { test_whitelist_end_to_end_internal(summed_seckey[i], online_seckey[i], online_pubkeys, offline_pubkeys, &sub_pubkey, i, n_keys); } } else { uint32_t rand_idx = testrand_int(n_keys-1); test_whitelist_end_to_end_internal(summed_seckey[0], online_seckey[0], online_pubkeys, offline_pubkeys, &sub_pubkey, 0, n_keys); test_whitelist_end_to_end_internal(summed_seckey[rand_idx], online_seckey[rand_idx], online_pubkeys, offline_pubkeys, &sub_pubkey, rand_idx, n_keys); test_whitelist_end_to_end_internal(summed_seckey[n_keys-1], online_seckey[n_keys-1], online_pubkeys, offline_pubkeys, &sub_pubkey, n_keys-1, n_keys); } for (i = 0; i < n_keys; i++) { free(online_seckey[i]); free(summed_seckey[i]); } free(online_seckey); free(summed_seckey); free(online_pubkeys); free(offline_pubkeys); } static void test_whitelist_bad_parse(void) { secp256k1_whitelist_signature sig; const unsigned char serialized0[] = { 1+32*(0+1) }; const unsigned char serialized1[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; const unsigned char serialized2[] = { 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; /* Empty input */ CHECK(secp256k1_whitelist_signature_parse(CTX, &sig, serialized0, 0) == 0); /* Misses one byte of e0 */ CHECK(secp256k1_whitelist_signature_parse(CTX, &sig, serialized1, sizeof(serialized1)) == 0); /* Enough bytes for e0, but there is no s value */ CHECK(secp256k1_whitelist_signature_parse(CTX, &sig, serialized2, sizeof(serialized2)) == 0); } static void test_whitelist_bad_serialize(void) { unsigned char serialized[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; size_t serialized_len; secp256k1_whitelist_signature sig; CHECK(secp256k1_whitelist_signature_parse(CTX, &sig, serialized, sizeof(serialized)) == 1); serialized_len = sizeof(serialized) - 1; /* Output buffer is one byte too short */ CHECK(secp256k1_whitelist_signature_serialize(CTX, serialized, &serialized_len, &sig) == 0); } static void test_whitelist_end_to_end_all_internal(void) { test_whitelist_end_to_end(1, 1); test_whitelist_end_to_end(10, 1); test_whitelist_end_to_end(50, 1); test_whitelist_end_to_end(SECP256K1_WHITELIST_MAX_N_KEYS, 0); } /* --- Test registry --- */ REPEAT_TEST(test_whitelist_end_to_end_all) static const struct tf_test_entry tests_whitelist[] = { CASE1(test_whitelist_bad_parse), CASE1(test_whitelist_bad_serialize), CASE1(test_whitelist_end_to_end_all), }; #endif