/********************************************************************** * Copyright (c) 2016 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_MAIN #define SECP256K1_MODULE_WHITELIST_MAIN #include "include/secp256k1_whitelist.h" #include "modules/whitelist/whitelist_impl.h" #define MAX_KEYS SECP256K1_WHITELIST_MAX_N_KEYS /* shorter alias */ int secp256k1_whitelist_sign(const secp256k1_context* ctx, secp256k1_whitelist_signature *sig, const secp256k1_pubkey *online_pubkeys, const secp256k1_pubkey *offline_pubkeys, const size_t n_keys, const secp256k1_pubkey *sub_pubkey, const unsigned char *online_seckey, const unsigned char *summed_seckey, const size_t index) { secp256k1_gej pubs[MAX_KEYS]; secp256k1_scalar s[MAX_KEYS]; secp256k1_scalar sec, non; unsigned char msg32[32]; int ret; /* Sanity checks */ VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); ARG_CHECK(sig != NULL); ARG_CHECK(online_pubkeys != NULL); ARG_CHECK(offline_pubkeys != NULL); ARG_CHECK(n_keys <= MAX_KEYS); ARG_CHECK(sub_pubkey != NULL); ARG_CHECK(online_seckey != NULL); ARG_CHECK(summed_seckey != NULL); ARG_CHECK(index < n_keys); /* Compute pubkeys: online_pubkey + tweaked(offline_pubkey + address), and message */ ret = secp256k1_whitelist_compute_keys_and_message(ctx, msg32, pubs, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey); /* Compute signing key: online_seckey + tweaked(summed_seckey) */ if (ret) { ret = secp256k1_whitelist_compute_tweaked_privkey(ctx, &sec, online_seckey, summed_seckey); } /* Compute nonce and random s-values */ if (ret) { unsigned char seckey32[32]; unsigned int count = 0; int overflow = 0; secp256k1_scalar_get_b32(seckey32, &sec); while (1) { size_t i; unsigned char nonce32[32]; int done; ret = secp256k1_nonce_function_default(nonce32, msg32, seckey32, NULL, NULL, count); if (!ret) { break; } secp256k1_scalar_set_b32(&non, nonce32, &overflow); memset(nonce32, 0, 32); if (overflow || secp256k1_scalar_is_zero(&non)) { count++; continue; } done = 1; for (i = 0; i < n_keys; i++) { msg32[0] ^= i + 1; msg32[1] ^= (i + 1) / 0x100; ret = secp256k1_nonce_function_default(&sig->data[32 * (i + 1)], msg32, seckey32, NULL, NULL, count); if (!ret) { break; } secp256k1_scalar_set_b32(&s[i], &sig->data[32 * (i + 1)], &overflow); msg32[0] ^= i + 1; msg32[1] ^= (i + 1) / 0x100; if (overflow || secp256k1_scalar_is_zero(&s[i])) { count++; done = 0; break; } } if (done) { break; } } memset(seckey32, 0, 32); } /* Actually sign */ if (ret) { sig->n_keys = n_keys; ret = secp256k1_borromean_sign(&ctx->ecmult_gen_ctx, &sig->data[0], s, pubs, &non, &sec, &n_keys, &index, 1, msg32, 32); /* Signing will change s[index], so update in the sig structure */ secp256k1_scalar_get_b32(&sig->data[32 * (index + 1)], &s[index]); } secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); return ret; } int secp256k1_whitelist_verify(const secp256k1_context* ctx, const secp256k1_whitelist_signature *sig, const secp256k1_pubkey *online_pubkeys, const secp256k1_pubkey *offline_pubkeys, const size_t n_keys, const secp256k1_pubkey *sub_pubkey) { secp256k1_scalar s[MAX_KEYS]; secp256k1_gej pubs[MAX_KEYS]; unsigned char msg32[32]; size_t i; VERIFY_CHECK(ctx != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(online_pubkeys != NULL); ARG_CHECK(offline_pubkeys != NULL); ARG_CHECK(sub_pubkey != NULL); if (sig->n_keys > MAX_KEYS || sig->n_keys != n_keys) { return 0; } for (i = 0; i < sig->n_keys; i++) { int overflow = 0; secp256k1_scalar_set_b32(&s[i], &sig->data[32 * (i + 1)], &overflow); if (overflow || secp256k1_scalar_is_zero(&s[i])) { return 0; } } /* Compute pubkeys: online_pubkey + tweaked(offline_pubkey + address), and message */ if (!secp256k1_whitelist_compute_keys_and_message(ctx, msg32, pubs, online_pubkeys, offline_pubkeys, sig->n_keys, sub_pubkey)) { return 0; } /* Do verification */ return secp256k1_borromean_verify(NULL, &sig->data[0], s, pubs, &sig->n_keys, 1, msg32, 32); } size_t secp256k1_whitelist_signature_n_keys(const secp256k1_whitelist_signature *sig) { return sig->n_keys; } int secp256k1_whitelist_signature_parse(const secp256k1_context* ctx, secp256k1_whitelist_signature *sig, const unsigned char *input, size_t input_len) { VERIFY_CHECK(ctx != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(input != NULL); if (input_len == 0) { return 0; } sig->n_keys = input[0]; if (sig->n_keys > MAX_KEYS || input_len != 1 + 32 * (sig->n_keys + 1)) { return 0; } memcpy(&sig->data[0], &input[1], 32 * (sig->n_keys + 1)); return 1; } int secp256k1_whitelist_signature_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *output_len, const secp256k1_whitelist_signature *sig) { VERIFY_CHECK(ctx != NULL); ARG_CHECK(output != NULL); ARG_CHECK(output_len != NULL); ARG_CHECK(sig != NULL); if (*output_len < 1 + 32 * (sig->n_keys + 1)) { return 0; } output[0] = sig->n_keys; memcpy(&output[1], &sig->data[0], 32 * (sig->n_keys + 1)); *output_len = 1 + 32 * (sig->n_keys + 1); return 1; } #endif