Skip to content

Commit 14565fb

Browse files
committed
schnorrsig: add opaque config object for sign_custom
This allows adding customization options in the future without breaking the API
1 parent d12ca15 commit 14565fb

File tree

3 files changed

+97
-13
lines changed

3 files changed

+97
-13
lines changed

include/secp256k1_schnorrsig.h

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ typedef int (*secp256k1_nonce_function_hardened)(
6060
*/
6161
SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
6262

63+
/** Opaque data structure that holds additional arguments for schnorrsig signing.
64+
*/
65+
typedef struct secp256k1_schnorrsig_config_struct secp256k1_schnorrsig_config;
66+
6367
/** Create a Schnorr signature.
6468
*
6569
* Does _not_ strictly follow BIP-340 because it does not verify the resulting
@@ -86,28 +90,68 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
8690
unsigned char *aux_rand32
8791
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
8892

93+
/** Create a schnorrsig config (in dynamically allocated memory).
94+
*
95+
* This function uses malloc to allocate memory. It is guaranteed that malloc is
96+
* called at most once for every call of this function.
97+
*
98+
* The allocated memory must be freed with secp256k1_schnorrsig_config_destroy.
99+
*
100+
* Returns: a newly created schnorrsig config
101+
* Args: ctx: an existing context object (cannot be NULL)
102+
*/
103+
SECP256K1_API secp256k1_schnorrsig_config* secp256k1_schnorrsig_config_create(
104+
const secp256k1_context* ctx
105+
) SECP256K1_ARG_NONNULL(1);
106+
107+
/** Destroy a schnorrsig config (created in dynamically allocated memory).
108+
*
109+
* The config pointer may not be used afterwards.
110+
* Args: ctx: a secp256k1 context object
111+
* In: config: the config to destroy
112+
*/
113+
SECP256K1_API void secp256k1_schnorrsig_config_destroy(
114+
const secp256k1_context* ctx,
115+
secp256k1_schnorrsig_config *config
116+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
117+
118+
/** Set nonce function pointer and nonce data of a config object
119+
*
120+
* Returns: 1 if the arguments are valid. 0 otherwise
121+
* Args: ctx: a secp256k1 context object
122+
* In: config: the config to set the noncefp and ndata for
123+
* noncefp: the nonce function pointer to set
124+
* ndata: the nonce data to set
125+
*/
126+
SECP256K1_API int secp256k1_schnorrsig_config_set_nonce(
127+
const secp256k1_context* ctx,
128+
secp256k1_schnorrsig_config *config,
129+
secp256k1_nonce_function_hardened noncefp,
130+
void *ndata
131+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
132+
89133
/** Create a Schnorr signature with a more flexible API.
90134
*
91-
* Same arguments as secp256k1_schnorrsig_sign except that it misses aux_rand32
92-
* and instead allows allows providing a different nonce derivation function
93-
* with its own data argument.
135+
* Same arguments as secp256k1_schnorrsig_sign except that it accepts a pointer
136+
* to a config object that allows customizing signing by passing additional
137+
* arguments.
94138
*
95139
* In: noncefp: pointer to a nonce generation function. If NULL,
96140
* secp256k1_nonce_function_bip340 is used
97141
* ndata: pointer to arbitrary data used by the nonce generation function
98142
* (can be NULL). If it is non-NULL and
99143
* secp256k1_nonce_function_bip340 is used, then ndata must be a
100144
* pointer to 32-byte auxiliary randomness as per BIP-340.
145+
* config: pointer to a config object.
101146
*/
102147
SECP256K1_API int secp256k1_schnorrsig_sign_custom(
103148
const secp256k1_context* ctx,
104149
unsigned char *sig64,
105150
const unsigned char *msg,
106151
size_t msg_len,
107152
const secp256k1_keypair *keypair,
108-
secp256k1_nonce_function_hardened noncefp,
109-
void *ndata
110-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
153+
secp256k1_schnorrsig_config *config
154+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
111155

112156

113157
/** Verify a Schnorr signature.

src/modules/schnorrsig/main_impl.h

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,7 @@ static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned c
124124
secp256k1_scalar_set_b32(e, buf, NULL);
125125
}
126126

127-
128-
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) {
129-
return secp256k1_schnorrsig_sign_custom(ctx, sig64, msg, msg_len, keypair, NULL, aux_rand32);
130-
}
131-
132-
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) {
127+
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) {
133128
secp256k1_scalar sk;
134129
secp256k1_scalar e;
135130
secp256k1_scalar k;
@@ -192,6 +187,47 @@ int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char
192187
return ret;
193188
}
194189

190+
191+
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) {
192+
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg, msg_len, keypair, secp256k1_nonce_function_bip340, aux_rand32);
193+
}
194+
195+
struct secp256k1_schnorrsig_config_struct {
196+
secp256k1_nonce_function_hardened noncefp;
197+
void *ndata;
198+
};
199+
200+
secp256k1_schnorrsig_config* secp256k1_schnorrsig_config_create(const secp256k1_context* ctx) {
201+
secp256k1_schnorrsig_config *config;
202+
config = (secp256k1_schnorrsig_config*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_schnorrsig_config));
203+
config->noncefp = NULL;
204+
config->ndata = NULL;
205+
return config;
206+
}
207+
208+
void secp256k1_schnorrsig_config_destroy(const secp256k1_context* ctx, secp256k1_schnorrsig_config *config) {
209+
VERIFY_CHECK(ctx != NULL);
210+
211+
if (config != NULL) {
212+
free(config);
213+
}
214+
}
215+
216+
int secp256k1_schnorrsig_config_set_nonce(const secp256k1_context* ctx, secp256k1_schnorrsig_config *config, secp256k1_nonce_function_hardened noncefp, void *ndata) {
217+
VERIFY_CHECK(ctx != NULL);
218+
ARG_CHECK(config != NULL);
219+
220+
config->noncefp = noncefp;
221+
config->ndata = ndata;
222+
return 1;
223+
}
224+
225+
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) {
226+
VERIFY_CHECK(ctx != NULL);
227+
ARG_CHECK(config != NULL);
228+
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg, msg_len, keypair, config->noncefp, config->ndata);
229+
}
230+
195231
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) {
196232
secp256k1_scalar s;
197233
secp256k1_scalar e;

src/modules/schnorrsig/tests_exhaustive_impl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,10 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons
137137
}
138138

139139
static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) {
140+
secp256k1_schnorrsig_config *config = secp256k1_schnorrsig_config_create(ctx);
140141
int d, k;
141142
uint64_t iter = 0;
143+
142144
/* Loop over keys. */
143145
for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) {
144146
int actual_d = d;
@@ -151,6 +153,7 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign
151153
unsigned char sig64[64];
152154
int actual_k = k;
153155
if (skip_section(&iter)) continue;
156+
VERIFY_CHECK(secp256k1_schnorrsig_config_set_nonce(ctx, config, secp256k1_hardened_nonce_function_smallint, &k));
154157
if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k;
155158
/* Generate random messages until all challenges have been tried. */
156159
while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
@@ -163,7 +166,7 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign
163166
unsigned char expected_s_bytes[32];
164167
secp256k1_scalar_get_b32(expected_s_bytes, &expected_s);
165168
/* Invoke the real function to construct a signature. */
166-
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], secp256k1_hardened_nonce_function_smallint, &k));
169+
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], config));
167170
/* The first 32 bytes must match the xonly pubkey for the specified k. */
168171
CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0);
169172
/* The last 32 bytes must match the expected s value. */
@@ -175,6 +178,7 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign
175178
}
176179
}
177180
}
181+
secp256k1_schnorrsig_config_destroy(ctx, config);
178182
}
179183

180184
static void test_exhaustive_schnorrsig(const secp256k1_context *ctx) {

0 commit comments

Comments
 (0)