Skip to content

Commit

Permalink
schnorrsig: add opaque config object for sign_custom
Browse files Browse the repository at this point in the history
This allows adding customization options in the future without
breaking the API
  • Loading branch information
jonasnick committed Nov 2, 2020
1 parent d12ca15 commit 14565fb
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 13 deletions.
56 changes: 50 additions & 6 deletions include/secp256k1_schnorrsig.h
Expand Up @@ -60,6 +60,10 @@ typedef int (*secp256k1_nonce_function_hardened)(
*/
SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;

/** Opaque data structure that holds additional arguments for schnorrsig signing.
*/
typedef struct secp256k1_schnorrsig_config_struct secp256k1_schnorrsig_config;

/** Create a Schnorr signature.
*
* Does _not_ strictly follow BIP-340 because it does not verify the resulting
Expand All @@ -86,28 +90,68 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
unsigned char *aux_rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);

/** Create a schnorrsig config (in dynamically allocated memory).
*
* This function uses malloc to allocate memory. It is guaranteed that malloc is
* called at most once for every call of this function.
*
* The allocated memory must be freed with secp256k1_schnorrsig_config_destroy.
*
* Returns: a newly created schnorrsig config
* Args: ctx: an existing context object (cannot be NULL)
*/
SECP256K1_API secp256k1_schnorrsig_config* secp256k1_schnorrsig_config_create(
const secp256k1_context* ctx
) SECP256K1_ARG_NONNULL(1);

/** Destroy a schnorrsig config (created in dynamically allocated memory).
*
* The config pointer may not be used afterwards.
* Args: ctx: a secp256k1 context object
* In: config: the config to destroy
*/
SECP256K1_API void secp256k1_schnorrsig_config_destroy(
const secp256k1_context* ctx,
secp256k1_schnorrsig_config *config
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);

/** Set nonce function pointer and nonce data of a config object
*
* Returns: 1 if the arguments are valid. 0 otherwise
* Args: ctx: a secp256k1 context object
* In: config: the config to set the noncefp and ndata for
* noncefp: the nonce function pointer to set
* ndata: the nonce data to set
*/
SECP256K1_API int secp256k1_schnorrsig_config_set_nonce(
const secp256k1_context* ctx,
secp256k1_schnorrsig_config *config,
secp256k1_nonce_function_hardened noncefp,
void *ndata
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);

/** Create a Schnorr signature with a more flexible API.
*
* Same arguments as secp256k1_schnorrsig_sign except that it misses aux_rand32
* and instead allows allows providing a different nonce derivation function
* with its own data argument.
* Same arguments as secp256k1_schnorrsig_sign except that it accepts a pointer
* to a config object that allows customizing signing by passing additional
* arguments.
*
* In: noncefp: pointer to a nonce generation function. If NULL,
* secp256k1_nonce_function_bip340 is used
* ndata: pointer to arbitrary data used by the nonce generation function
* (can be NULL). If it is non-NULL and
* secp256k1_nonce_function_bip340 is used, then ndata must be a
* pointer to 32-byte auxiliary randomness as per BIP-340.
* config: pointer to a config object.
*/
SECP256K1_API int secp256k1_schnorrsig_sign_custom(
const secp256k1_context* ctx,
unsigned char *sig64,
const unsigned char *msg,
size_t msg_len,
const secp256k1_keypair *keypair,
secp256k1_nonce_function_hardened noncefp,
void *ndata
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
secp256k1_schnorrsig_config *config
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);


/** Verify a Schnorr signature.
Expand Down
48 changes: 42 additions & 6 deletions src/modules/schnorrsig/main_impl.h
Expand Up @@ -124,12 +124,7 @@ static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned c
secp256k1_scalar_set_b32(e, buf, NULL);
}


int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msg_len, const secp256k1_keypair *keypair, unsigned char *aux_rand32) {
return secp256k1_schnorrsig_sign_custom(ctx, sig64, msg, msg_len, keypair, NULL, aux_rand32);
}

int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msg_len, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) {
int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msg_len, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) {
secp256k1_scalar sk;
secp256k1_scalar e;
secp256k1_scalar k;
Expand Down Expand Up @@ -192,6 +187,47 @@ int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char
return ret;
}


int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msg_len, const secp256k1_keypair *keypair, unsigned char *aux_rand32) {
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg, msg_len, keypair, secp256k1_nonce_function_bip340, aux_rand32);
}

struct secp256k1_schnorrsig_config_struct {
secp256k1_nonce_function_hardened noncefp;
void *ndata;
};

secp256k1_schnorrsig_config* secp256k1_schnorrsig_config_create(const secp256k1_context* ctx) {
secp256k1_schnorrsig_config *config;
config = (secp256k1_schnorrsig_config*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_schnorrsig_config));
config->noncefp = NULL;
config->ndata = NULL;
return config;
}

void secp256k1_schnorrsig_config_destroy(const secp256k1_context* ctx, secp256k1_schnorrsig_config *config) {
VERIFY_CHECK(ctx != NULL);

if (config != NULL) {
free(config);
}
}

int secp256k1_schnorrsig_config_set_nonce(const secp256k1_context* ctx, secp256k1_schnorrsig_config *config, secp256k1_nonce_function_hardened noncefp, void *ndata) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(config != NULL);

config->noncefp = noncefp;
config->ndata = ndata;
return 1;
}

int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msg_len, const secp256k1_keypair *keypair, secp256k1_schnorrsig_config *config) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(config != NULL);
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg, msg_len, keypair, config->noncefp, config->ndata);
}

int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg, size_t msg_len, const secp256k1_xonly_pubkey *pubkey) {
secp256k1_scalar s;
secp256k1_scalar e;
Expand Down
6 changes: 5 additions & 1 deletion src/modules/schnorrsig/tests_exhaustive_impl.h
Expand Up @@ -137,8 +137,10 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons
}

static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) {
secp256k1_schnorrsig_config *config = secp256k1_schnorrsig_config_create(ctx);
int d, k;
uint64_t iter = 0;

/* Loop over keys. */
for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) {
int actual_d = d;
Expand All @@ -151,6 +153,7 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign
unsigned char sig64[64];
int actual_k = k;
if (skip_section(&iter)) continue;
VERIFY_CHECK(secp256k1_schnorrsig_config_set_nonce(ctx, config, secp256k1_hardened_nonce_function_smallint, &k));
if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k;
/* Generate random messages until all challenges have been tried. */
while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
Expand All @@ -163,7 +166,7 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign
unsigned char expected_s_bytes[32];
secp256k1_scalar_get_b32(expected_s_bytes, &expected_s);
/* Invoke the real function to construct a signature. */
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], secp256k1_hardened_nonce_function_smallint, &k));
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], config));
/* The first 32 bytes must match the xonly pubkey for the specified k. */
CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0);
/* The last 32 bytes must match the expected s value. */
Expand All @@ -175,6 +178,7 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign
}
}
}
secp256k1_schnorrsig_config_destroy(ctx, config);
}

static void test_exhaustive_schnorrsig(const secp256k1_context *ctx) {
Expand Down

0 comments on commit 14565fb

Please sign in to comment.