Skip to content

Commit d12ca15

Browse files
committed
schnorrsig: allow signing and verification of variable length msgs
1 parent 383b791 commit d12ca15

File tree

5 files changed

+47
-37
lines changed

5 files changed

+47
-37
lines changed

include/secp256k1_schnorrsig.h

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ extern "C" {
2424
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to
2525
* return an error.
2626
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
27-
* In: msg32: the 32-byte message hash being verified (will not be NULL)
27+
* In: msg: the message being verified (will not be NULL)
28+
* msg_len: the length of the message (will not be NULL)
2829
* key32: pointer to a 32-byte secret key (will not be NULL)
2930
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
3031
* (will not be NULL)
@@ -37,7 +38,8 @@ extern "C" {
3738
*/
3839
typedef int (*secp256k1_nonce_function_hardened)(
3940
unsigned char *nonce32,
40-
const unsigned char *msg32,
41+
const unsigned char *msg,
42+
size_t msg_len,
4143
const unsigned char *key32,
4244
const unsigned char *xonly_pk32,
4345
const unsigned char *algo16,
@@ -67,7 +69,8 @@ SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_fun
6769
* Returns 1 on success, 0 on failure.
6870
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
6971
* Out: sig64: pointer to a 64-byte array to store the serialized signature (cannot be NULL)
70-
* In: msg32: the 32-byte message being signed (cannot be NULL)
72+
* In: msg: the message being signed (cannot be NULL)
73+
* msg_len: length of the message
7174
* keypair: pointer to an initialized keypair (cannot be NULL)
7275
* aux_rand32: 32 bytes of fresh randomness. While recommended to provide
7376
* this, it is only supplemental to security and can be NULL. See
@@ -77,10 +80,11 @@ SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_fun
7780
SECP256K1_API int secp256k1_schnorrsig_sign(
7881
const secp256k1_context* ctx,
7982
unsigned char *sig64,
80-
const unsigned char *msg32,
83+
const unsigned char *msg,
84+
size_t msg_len,
8185
const secp256k1_keypair *keypair,
8286
unsigned char *aux_rand32
83-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
87+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
8488

8589
/** Create a Schnorr signature with a more flexible API.
8690
*
@@ -98,11 +102,12 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
98102
SECP256K1_API int secp256k1_schnorrsig_sign_custom(
99103
const secp256k1_context* ctx,
100104
unsigned char *sig64,
101-
const unsigned char *msg32,
105+
const unsigned char *msg,
106+
size_t msg_len,
102107
const secp256k1_keypair *keypair,
103108
secp256k1_nonce_function_hardened noncefp,
104109
void *ndata
105-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
110+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
106111

107112

108113
/** Verify a Schnorr signature.
@@ -111,15 +116,17 @@ SECP256K1_API int secp256k1_schnorrsig_sign_custom(
111116
* 0: incorrect signature
112117
* Args: ctx: a secp256k1 context object, initialized for verification.
113118
* In: sig64: pointer to the 64-byte signature to verify (cannot be NULL)
114-
* msg32: the 32-byte message being verified (cannot be NULL)
119+
* msg: the message being verified (cannot be NULL)
120+
* msg_len: length of the message (cannot be NULL)
115121
* pubkey: pointer to an x-only public key to verify with (cannot be NULL)
116122
*/
117123
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
118124
const secp256k1_context* ctx,
119125
const unsigned char *sig64,
120-
const unsigned char *msg32,
126+
const unsigned char *msg,
127+
size_t msg_len,
121128
const secp256k1_xonly_pubkey *pubkey
122-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
129+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
123130

124131
#ifdef __cplusplus
125132
}

src/bench_schnorrsig.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
#include <string.h>
88
#include <stdlib.h>
99

10-
1110
#include "include/secp256k1.h"
1211
#include "include/secp256k1_schnorrsig.h"
1312
#include "util.h"
1413
#include "bench.h"
1514

15+
#define MSG_LEN 32
16+
1617
typedef struct {
1718
secp256k1_context *ctx;
1819
int n;
@@ -26,13 +27,13 @@ typedef struct {
2627
void bench_schnorrsig_sign(void* arg, int iters) {
2728
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
2829
int i;
29-
unsigned char msg[32] = "benchmarkexamplemessagetemplate";
30+
unsigned char msg[MSG_LEN] = "benchmarkexamplemessagetemplate";
3031
unsigned char sig[64];
3132

3233
for (i = 0; i < iters; i++) {
3334
msg[0] = i;
3435
msg[1] = i >> 8;
35-
CHECK(secp256k1_schnorrsig_sign(data->ctx, sig, msg, data->keypairs[i], NULL));
36+
CHECK(secp256k1_schnorrsig_sign(data->ctx, sig, msg, MSG_LEN, data->keypairs[i], NULL));
3637
}
3738
}
3839

@@ -43,7 +44,7 @@ void bench_schnorrsig_verify(void* arg, int iters) {
4344
for (i = 0; i < iters; i++) {
4445
secp256k1_xonly_pubkey pk;
4546
CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1);
46-
CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk));
47+
CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], MSG_LEN, &pk));
4748
}
4849
}
4950

@@ -60,7 +61,7 @@ int main(void) {
6061

6162
for (i = 0; i < iters; i++) {
6263
unsigned char sk[32];
63-
unsigned char *msg = (unsigned char *)malloc(32);
64+
unsigned char *msg = (unsigned char *)malloc(MSG_LEN);
6465
unsigned char *sig = (unsigned char *)malloc(64);
6566
secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair));
6667
unsigned char *pk_char = (unsigned char *)malloc(32);
@@ -78,7 +79,7 @@ int main(void) {
7879
data.sigs[i] = sig;
7980

8081
CHECK(secp256k1_keypair_create(data.ctx, keypair, sk));
81-
CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, keypair, NULL));
82+
CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, MSG_LEN, keypair, NULL));
8283
CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair));
8384
CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1);
8485
}

src/modules/schnorrsig/main_impl.h

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *
4747
* by using the correct tagged hash function. */
4848
static const unsigned char bip340_algo16[16] = "BIP0340/nonce\0\0\0";
4949

50-
static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
50+
static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msg_len, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
5151
secp256k1_sha256 sha;
5252
unsigned char masked_key[32];
5353
int i;
@@ -86,7 +86,7 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms
8686
secp256k1_sha256_write(&sha, key32, 32);
8787
}
8888
secp256k1_sha256_write(&sha, xonly_pk32, 32);
89-
secp256k1_sha256_write(&sha, msg32, 32);
89+
secp256k1_sha256_write(&sha, msg, msg_len);
9090
secp256k1_sha256_finalize(&sha, nonce32);
9191
return 1;
9292
}
@@ -108,28 +108,28 @@ static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) {
108108
sha->bytes = 64;
109109
}
110110

111-
static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg32, const unsigned char *pubkey32)
111+
static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msg_len, const unsigned char *pubkey32)
112112
{
113113
unsigned char buf[32];
114114
secp256k1_sha256 sha;
115115

116-
/* tagged hash(r.x, pk.x, msg32) */
116+
/* tagged hash(r.x, pk.x, msg) */
117117
secp256k1_schnorrsig_sha256_tagged(&sha);
118118
secp256k1_sha256_write(&sha, r32, 32);
119119
secp256k1_sha256_write(&sha, pubkey32, 32);
120-
secp256k1_sha256_write(&sha, msg32, 32);
120+
secp256k1_sha256_write(&sha, msg, msg_len);
121121
secp256k1_sha256_finalize(&sha, buf);
122122
/* Set scalar e to the challenge hash modulo the curve order as per
123123
* BIP340. */
124124
secp256k1_scalar_set_b32(e, buf, NULL);
125125
}
126126

127127

128-
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, unsigned char *aux_rand32) {
129-
return secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, keypair, NULL, aux_rand32);
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);
130130
}
131131

132-
int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) {
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) {
133133
secp256k1_scalar sk;
134134
secp256k1_scalar e;
135135
secp256k1_scalar k;
@@ -144,7 +144,7 @@ int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char
144144
VERIFY_CHECK(ctx != NULL);
145145
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
146146
ARG_CHECK(sig64 != NULL);
147-
ARG_CHECK(msg32 != NULL);
147+
ARG_CHECK(msg != NULL);
148148
ARG_CHECK(keypair != NULL);
149149

150150
if (noncefp == NULL) {
@@ -161,7 +161,7 @@ int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char
161161

162162
secp256k1_scalar_get_b32(seckey, &sk);
163163
secp256k1_fe_get_b32(pk_buf, &pk.x);
164-
ret &= !!noncefp(buf, msg32, seckey, pk_buf, bip340_algo16, ndata);
164+
ret &= !!noncefp(buf, msg, msg_len, seckey, pk_buf, bip340_algo16, ndata);
165165
secp256k1_scalar_set_b32(&k, buf, NULL);
166166
ret &= !secp256k1_scalar_is_zero(&k);
167167
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
@@ -179,7 +179,7 @@ int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char
179179
secp256k1_fe_normalize_var(&r.x);
180180
secp256k1_fe_get_b32(&sig64[0], &r.x);
181181

182-
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg32, pk_buf);
182+
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msg_len, pk_buf);
183183
secp256k1_scalar_mul(&e, &e, &sk);
184184
secp256k1_scalar_add(&e, &e, &k);
185185
secp256k1_scalar_get_b32(&sig64[32], &e);
@@ -192,7 +192,7 @@ int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char
192192
return ret;
193193
}
194194

195-
int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_xonly_pubkey *pubkey) {
195+
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) {
196196
secp256k1_scalar s;
197197
secp256k1_scalar e;
198198
secp256k1_gej rj;
@@ -206,7 +206,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
206206
VERIFY_CHECK(ctx != NULL);
207207
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
208208
ARG_CHECK(sig64 != NULL);
209-
ARG_CHECK(msg32 != NULL);
209+
ARG_CHECK(msg != NULL);
210210
ARG_CHECK(pubkey != NULL);
211211

212212
if (!secp256k1_fe_set_b32(&rx, &sig64[0])) {
@@ -224,7 +224,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
224224

225225
/* Compute e. */
226226
secp256k1_fe_get_b32(buf, &pk.x);
227-
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg32, buf);
227+
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msg_len, buf);
228228

229229
/* Compute rj = s*G + (-e)*pkj */
230230
secp256k1_scalar_negate(&e, &e);

src/modules/schnorrsig/tests_exhaustive_impl.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,14 @@ static const unsigned char invalid_pubkey_bytes[][32] = {
5858

5959
#define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0]))
6060

61-
static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
61+
static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg,
62+
size_t msg_len,
6263
const unsigned char *key32, const unsigned char *xonly_pk32,
6364
const unsigned char *algo16, void* data) {
6465
secp256k1_scalar s;
6566
int *idata = data;
66-
(void)msg32;
67+
(void)msg;
68+
(void)msg_len;
6769
(void)key32;
6870
(void)xonly_pk32;
6971
(void)algo16;
@@ -101,7 +103,7 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons
101103
secp256k1_scalar e;
102104
unsigned char msg32[32];
103105
secp256k1_testrand256(msg32);
104-
secp256k1_schnorrsig_challenge(&e, sig64, msg32, pk32);
106+
secp256k1_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32);
105107
/* Only do work if we hit a challenge we haven't tried before. */
106108
if (!e_done[e]) {
107109
/* Iterate over the possible valid last 32 bytes in the signature.
@@ -119,7 +121,7 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons
119121
secp256k1_testrand256(sig64 + 32);
120122
expect_valid = 0;
121123
}
122-
valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, &pubkeys[d - 1]);
124+
valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]);
123125
CHECK(valid == expect_valid);
124126
count_valid += valid;
125127
}
@@ -154,14 +156,14 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign
154156
while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
155157
secp256k1_scalar e;
156158
secp256k1_testrand256(msg32);
157-
secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, xonly_pubkey_bytes[d - 1]);
159+
secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]);
158160
/* Only do work if we hit a challenge we haven't tried before. */
159161
if (!e_done[e]) {
160162
secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER;
161163
unsigned char expected_s_bytes[32];
162164
secp256k1_scalar_get_b32(expected_s_bytes, &expected_s);
163165
/* Invoke the real function to construct a signature. */
164-
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, &keypairs[d - 1], secp256k1_hardened_nonce_function_smallint, &k));
166+
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], secp256k1_hardened_nonce_function_smallint, &k));
165167
/* The first 32 bytes must match the xonly pubkey for the specified k. */
166168
CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0);
167169
/* The last 32 bytes must match the expected s value. */

src/valgrind_ctime_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ int main(void) {
147147
ret = secp256k1_keypair_create(ctx, &keypair, key);
148148
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
149149
CHECK(ret == 1);
150-
ret = secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL);
150+
ret = secp256k1_schnorrsig_sign(ctx, sig, msg, sizeof(msg), &keypair, NULL);
151151
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
152152
CHECK(ret == 1);
153153
#endif

0 commit comments

Comments
 (0)