Skip to content

Commit 01dd66c

Browse files
committed
Add and expose sign-to-contract contexts and make nonce_function_bipschnorr do sign-to-contract commitments if an s2c context is provided as nonce data
1 parent 97118ca commit 01dd66c

File tree

4 files changed

+143
-22
lines changed

4 files changed

+143
-22
lines changed

include/secp256k1.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,22 @@ typedef struct {
8080
unsigned char data[64];
8181
} secp256k1_ecdsa_signature;
8282

83+
/** Opaque data structured that holds a sign-to-contract ("s2c") context
84+
* structure. Sign-to-contract allows a signer to commit to some data as part of
85+
* a signature. If the nonce function supports sign-to-contract, the context can
86+
* be given to a signing algorithm via the nonce argument after creating it with
87+
* secp256k1_s2c_commit_context_create.
88+
*
89+
* The exact representation of data inside is implementation defined and not
90+
* guaranteed to be portable between different platforms or versions. It is
91+
* however guaranteed to be 128 bytes in size, and can be safely copied/moved.
92+
*/
93+
typedef struct {
94+
unsigned char data[32];
95+
unsigned char data_commitment[32];
96+
secp256k1_pubkey original_pubnonce;
97+
} secp256k1_s2c_commit_context;
98+
8399
/** A pointer to a function to deterministically generate a nonce.
84100
*
85101
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
@@ -471,6 +487,33 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize(
471487
const secp256k1_ecdsa_signature *sigin
472488
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3);
473489

490+
/** Creates a sign-to-contract context.
491+
*
492+
* Returns: 1 if the context was created successfully, 0 otherwise
493+
* Args: ctx: a secp256k1 context object
494+
* Out: s2c_ctx: pointer to an s2c context to initialize (cannot be NULL)
495+
* In: data32: the 32-byte data to commit to (cannot be NULL)
496+
*/
497+
SECP256K1_API int secp256k1_s2c_commit_context_create(
498+
secp256k1_context *ctx,
499+
secp256k1_s2c_commit_context *s2c_ctx,
500+
const unsigned char *data32
501+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
502+
503+
/** Gets the opening of a sign-to-contract commitment from an s2c_ctx after signing.
504+
* The "opening" is the original public nonce before adding the s2c commitment tweak.
505+
*
506+
* Returns: 1 if getting the opening was successful, 0 otherwise
507+
* Args: ctx: a secp256k1 context object
508+
* Out: opening: pointer to a pubkey object where the opening will be placed (cannot be NULL)
509+
* In: s2c_ctx: pointer to an s2c context to get the opening from (cannot be NULL)
510+
*/
511+
SECP256K1_API int secp256k1_s2c_commit_get_opening(
512+
secp256k1_context *ctx,
513+
secp256k1_pubkey *opening,
514+
const secp256k1_s2c_commit_context *s2c_ctx
515+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
516+
474517
/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function.
475518
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
476519
* extra entropy.

include/secp256k1_schnorrsig.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ SECP256K1_API int secp256k1_schnorrsig_parse(
6666
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
6767
* seckey: pointer to a 32-byte secret key (cannot be NULL)
6868
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bipschnorr is used
69-
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
69+
* ndata: pointer to arbitrary data used by the nonce generation function. If non-NULL must
70+
* be a pointer to a s2c_context object when using the default nonce function
71+
* secp256k1_nonce_function_bipschnorr (can be NULL)
7072
*/
7173
SECP256K1_API int secp256k1_schnorrsig_sign(
7274
const secp256k1_context* ctx,

src/secp256k1.c

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -322,27 +322,6 @@ static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *off
322322
*offset += len;
323323
}
324324

325-
/* This nonce function is described in BIP-schnorr
326-
* (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */
327-
static int secp256k1_nonce_function_bipschnorr(const secp256k1_context *ctx, unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
328-
secp256k1_sha256 sha;
329-
(void) data;
330-
(void) counter;
331-
VERIFY_CHECK(counter == 0);
332-
333-
/* Hash x||msg as per the spec */
334-
secp256k1_sha256_initialize(&sha);
335-
secp256k1_sha256_write(&sha, key32, 32);
336-
secp256k1_sha256_write(&sha, msg32, 32);
337-
/* Hash in algorithm, which is not in the spec, but may be critical to
338-
* users depending on it to avoid nonce reuse across algorithms. */
339-
if (algo16 != NULL) {
340-
secp256k1_sha256_write(&sha, algo16, 16);
341-
}
342-
secp256k1_sha256_finalize(&sha, nonce32);
343-
return 1;
344-
}
345-
346325
static int nonce_function_rfc6979(const secp256k1_context *ctx, unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
347326
unsigned char keydata[112];
348327
unsigned int offset = 0;
@@ -707,6 +686,72 @@ int secp256k1_ec_commit_verify(const secp256k1_context* ctx, const secp256k1_pub
707686
return secp256k1_gej_is_infinity(&pj);
708687
}
709688

689+
int secp256k1_s2c_commit_context_create(secp256k1_context *ctx, secp256k1_s2c_commit_context *s2c_ctx, const unsigned char *data32) {
690+
secp256k1_sha256 sha;
691+
692+
VERIFY_CHECK(ctx != NULL);
693+
ARG_CHECK(s2c_ctx != NULL);
694+
ARG_CHECK(data32 != NULL);
695+
696+
memcpy(s2c_ctx->data, data32, 32);
697+
secp256k1_sha256_initialize(&sha);
698+
secp256k1_sha256_write(&sha, data32, 32);
699+
secp256k1_sha256_finalize(&sha, s2c_ctx->data_commitment);
700+
return 1;
701+
}
702+
703+
int secp256k1_s2c_commit_get_opening(secp256k1_context *ctx, secp256k1_pubkey *opening, const secp256k1_s2c_commit_context *s2c_ctx) {
704+
VERIFY_CHECK(ctx != NULL);
705+
ARG_CHECK(opening != NULL);
706+
ARG_CHECK(s2c_ctx != NULL);
707+
708+
memcpy(opening, &s2c_ctx->original_pubnonce, sizeof(secp256k1_pubkey));
709+
return 1;
710+
}
711+
712+
static int secp256k1_nonce_function_bipschnorr_no_s2c(const secp256k1_context *ctx, unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
713+
secp256k1_sha256 sha;
714+
715+
VERIFY_CHECK(counter == 0);
716+
(void) counter;
717+
718+
/* Hash x||msg as per the spec */
719+
secp256k1_sha256_initialize(&sha);
720+
secp256k1_sha256_write(&sha, key32, 32);
721+
secp256k1_sha256_write(&sha, msg32, 32);
722+
/* Hash in algorithm, which is not in the spec, but may be critical to
723+
* users depending on it to avoid nonce reuse across algorithms. */
724+
if (algo16 != NULL) {
725+
secp256k1_sha256_write(&sha, algo16, 16);
726+
}
727+
if (data == NULL) {
728+
secp256k1_sha256_finalize(&sha, nonce32);
729+
} else {
730+
/* Do a sign-to-contract commitment if data is provided */
731+
secp256k1_s2c_commit_context *s2c_ctx = (secp256k1_s2c_commit_context *)data;
732+
secp256k1_sha256_write(&sha, s2c_ctx->data_commitment, 32);
733+
secp256k1_sha256_finalize(&sha, nonce32);
734+
735+
if (!secp256k1_ec_pubkey_create(ctx, &s2c_ctx->original_pubnonce, nonce32)) {
736+
return 0;
737+
}
738+
}
739+
return 1;
740+
}
741+
742+
/* This nonce function is described in BIP-schnorr
743+
* (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */
744+
static int secp256k1_nonce_function_bipschnorr(const secp256k1_context *ctx, unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
745+
if (!secp256k1_nonce_function_bipschnorr_no_s2c(ctx, nonce32, msg32, key32, algo16, data, counter)) {
746+
return 0;
747+
}
748+
if (data != NULL) {
749+
secp256k1_s2c_commit_context *s2c_ctx = (secp256k1_s2c_commit_context *)data;
750+
return secp256k1_ec_commit_seckey(ctx, nonce32, &s2c_ctx->original_pubnonce, s2c_ctx->data, 32);
751+
}
752+
return 1;
753+
}
754+
710755
#ifdef ENABLE_MODULE_ECDH
711756
# include "modules/ecdh/main_impl.h"
712757
#endif

src/tests.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4054,6 +4054,35 @@ void run_eckey_edge_case_test(void) {
40544054
secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
40554055
}
40564056

4057+
void test_nonce_function_bipschnorr_s2c(void) {
4058+
unsigned char nonce32[32];
4059+
unsigned char msg32[32];
4060+
unsigned char key32[32];
4061+
unsigned char algo16[16];
4062+
unsigned char data32[32];
4063+
secp256k1_s2c_commit_context s2c_ctx;
4064+
secp256k1_pubkey pubnonce;
4065+
secp256k1_pubkey opening;
4066+
4067+
secp256k1_rand256(msg32);
4068+
secp256k1_rand256(key32);
4069+
secp256k1_rand256(data32);
4070+
memset(algo16, 23, sizeof(algo16));
4071+
4072+
CHECK(secp256k1_s2c_commit_context_create(ctx, &s2c_ctx, data32) == 1);
4073+
CHECK(secp256k1_nonce_function_bipschnorr(ctx, nonce32, msg32, key32, NULL, &s2c_ctx, 0) == 1);
4074+
CHECK(secp256k1_s2c_commit_get_opening(ctx, &opening, &s2c_ctx) == 1);
4075+
CHECK(secp256k1_ec_pubkey_create(ctx, &pubnonce, nonce32) == 1);
4076+
CHECK(secp256k1_ec_commit_verify(ctx, &pubnonce, &opening, data32, 32) == 1);
4077+
}
4078+
4079+
void run_nonce_function_bipschnorr_tests(void) {
4080+
int i;
4081+
for (i = 0; i < count * 8; i++) {
4082+
test_nonce_function_bipschnorr_s2c();
4083+
}
4084+
}
4085+
40574086
void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {
40584087
secp256k1_scalar nonce;
40594088
do {
@@ -5229,6 +5258,8 @@ int main(int argc, char **argv) {
52295258
run_ecdh_tests();
52305259
#endif
52315260

5261+
run_nonce_function_bipschnorr_tests();
5262+
52325263
#ifdef ENABLE_MODULE_SCHNORRSIG
52335264
/* Schnorrsig tests */
52345265
run_schnorrsig_tests();

0 commit comments

Comments
 (0)