175 lines
6.3 KiB
C
175 lines
6.3 KiB
C
/**********************************************************************
|
|
* 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_nonce_function noncefp, const void *noncedata) {
|
|
secp256k1_gej pubs[MAX_KEYS];
|
|
secp256k1_scalar s[MAX_KEYS];
|
|
secp256k1_scalar sec, non;
|
|
unsigned char msg32[32];
|
|
int ret;
|
|
|
|
if (noncefp == NULL) {
|
|
noncefp = secp256k1_nonce_function_default;
|
|
}
|
|
|
|
/* Sanity checks */
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
|
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 = noncefp(nonce32, msg32, seckey32, NULL, (void*)noncedata, 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 = noncefp(&sig->data[32 * (i + 1)], msg32, seckey32, NULL, (void*)noncedata, 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_ctx, &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(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
|
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(&ctx->ecmult_ctx, 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
|