Skip to content

Commit 8fa102c

Browse files
committed
Add verification of schnorrsig sign-to-contract commitments
1 parent 6ddb655 commit 8fa102c

3 files changed

Lines changed: 122 additions & 4 deletions

File tree

include/secp256k1_schnorrsig.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ SECP256K1_API int secp256k1_schnorrsig_parse(
6565
* nonce (can be NULL)
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)
68-
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bipschnorr is used
68+
* noncefp: pointer to a nonce generation function. If NULL,
69+
* secp256k1_nonce_function_bipschnorr is used
6970
* 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)
71+
* be a pointer to an s2c_context object when using the default nonce function
72+
* secp256k1_nonce_function_bipschnorr. s2c_context must be initialized with
73+
* secp256k1_s2c_commit_context_create. (can be NULL)
7274
*/
7375
SECP256K1_API int secp256k1_schnorrsig_sign(
7476
const secp256k1_context* ctx,
@@ -117,4 +119,23 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify_batch
117119
const secp256k1_pubkey *const *pk,
118120
size_t n_sigs
119121
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
122+
123+
/** Verify a sign-to-contract commitment.
124+
*
125+
* Returns: 1: the signature contains a commitment to data32
126+
* 0: incorrect opening
127+
* Args: ctx: a secp256k1 context object, initialized for verification.
128+
* In: sig: the signature containing the sign-to-contract commitment (cannot be NULL)
129+
* data32: the 32-byte data that was committed to (cannot be NULL)
130+
* original_nonce: pointer to the original_nonce created when signing (cannot be NULL)
131+
* negated_nonce: integer indicating if signing algorithm negated the nonce
132+
*/
133+
SECP256K1_API int secp256k1_schnorrsig_verify_s2c_commit(
134+
const secp256k1_context* ctx,
135+
const secp256k1_schnorrsig *sig,
136+
const unsigned char *data32,
137+
const secp256k1_pubkey *original_nonce,
138+
int negated_nonce
139+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
140+
120141
#endif

src/modules/schnorrsig/main_impl.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,29 @@ int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsi
2929
return 1;
3030
}
3131

32+
int secp256k1_schnorrsig_verify_s2c_commit(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *data32, const secp256k1_pubkey *original_nonce, int negated_nonce) {
33+
secp256k1_fe rx;
34+
secp256k1_ge R;
35+
secp256k1_pubkey pubnonce;
36+
37+
VERIFY_CHECK(ctx != NULL);
38+
ARG_CHECK(sig != NULL);
39+
ARG_CHECK(data32 != NULL);
40+
ARG_CHECK(original_nonce != NULL);
41+
42+
if (!secp256k1_fe_set_b32(&rx, &sig->data[0])) {
43+
return 0;
44+
}
45+
if (!secp256k1_ge_set_xquad(&R, &rx)) {
46+
return 0;
47+
}
48+
if(negated_nonce) {
49+
secp256k1_ge_neg(&R, &R);
50+
}
51+
secp256k1_pubkey_save(&pubnonce, &R);
52+
return secp256k1_ec_commit_verify(ctx, &pubnonce, original_nonce, data32, 32);
53+
}
54+
3255
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig *sig, int *nonce_is_negated, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, void *ndata) {
3356
secp256k1_scalar x;
3457
secp256k1_scalar e;

src/modules/schnorrsig/tests_impl.h

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,25 @@ void test_schnorrsig_api(secp256k1_scratch_space *scratch) {
2525
unsigned char sk2[32];
2626
unsigned char sk3[32];
2727
unsigned char msg[32];
28+
unsigned char data32[32];
2829
unsigned char sig64[64];
2930
secp256k1_pubkey pk[3];
3031
secp256k1_schnorrsig sig;
32+
secp256k1_s2c_commit_context s2c_ctx;
33+
secp256k1_pubkey s2c_original_nonce;
3134
const secp256k1_schnorrsig *sigptr = &sig;
3235
const unsigned char *msgptr = msg;
3336
const secp256k1_pubkey *pkptr = &pk[0];
3437
int nonce_is_negated;
38+
unsigned char ones[32];
3539

3640
/** setup **/
3741
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
3842
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
3943
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
4044
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
4145
int ecount;
46+
memset(ones, 0xff, 32);
4247

4348
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
4449
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
@@ -88,6 +93,29 @@ void test_schnorrsig_api(secp256k1_scratch_space *scratch) {
8893
CHECK(secp256k1_schnorrsig_parse(none, &sig, NULL) == 0);
8994
CHECK(ecount == 4);
9095

96+
/* Create sign-to-contract commitment to data32 for testing verify_s2c_commit */
97+
secp256k1_rand256(data32);
98+
CHECK(secp256k1_s2c_commit_context_create(ctx, &s2c_ctx, data32) == 1);
99+
CHECK(secp256k1_schnorrsig_sign(sign, &sig, &nonce_is_negated, msg, sk1, NULL, &s2c_ctx) == 1);
100+
CHECK(secp256k1_s2c_commit_get_original_nonce(ctx, &s2c_original_nonce, &s2c_ctx) == 1);
101+
ecount = 0;
102+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(none, &sig, data32, &s2c_original_nonce, nonce_is_negated) == 0);
103+
CHECK(ecount == 1);
104+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(vrfy, &sig, data32, &s2c_original_nonce, nonce_is_negated) == 1);
105+
CHECK(ecount == 1);
106+
{
107+
/* Overflowing x-coordinate in signature */
108+
secp256k1_schnorrsig sig_tmp = sig;
109+
memcpy(&sig_tmp.data[0], ones, 32);
110+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(vrfy, &sig_tmp, data32, &s2c_original_nonce, nonce_is_negated) == 0);
111+
}
112+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(vrfy, NULL, data32, &s2c_original_nonce, nonce_is_negated) == 0);
113+
CHECK(ecount == 2);
114+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(vrfy, &sig, NULL, &s2c_original_nonce, nonce_is_negated) == 0);
115+
CHECK(ecount == 3);
116+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(vrfy, &sig, data32, NULL, nonce_is_negated) == 0);
117+
CHECK(ecount == 4);
118+
91119
ecount = 0;
92120
CHECK(secp256k1_schnorrsig_verify(none, &sig, msg, &pk[0]) == 0);
93121
CHECK(ecount == 1);
@@ -713,15 +741,61 @@ void test_schnorrsig_sign_verify(secp256k1_scratch_space *scratch) {
713741
}
714742
#undef N_SIGS
715743

744+
void test_schnorrsig_s2c_commit_verify(void) {
745+
secp256k1_s2c_commit_context s2c_ctx;
746+
unsigned char data32[32];
747+
secp256k1_schnorrsig sig;
748+
int nonce_is_negated;
749+
unsigned char msg[32];
750+
unsigned char sk[32];
751+
secp256k1_pubkey pk;
752+
secp256k1_pubkey s2c_original_nonce;
753+
754+
secp256k1_rand256(data32);
755+
secp256k1_rand256(msg);
756+
secp256k1_rand256(sk);
757+
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
758+
759+
/* Create and verify correct commitment */
760+
CHECK(secp256k1_s2c_commit_context_create(ctx, &s2c_ctx, data32) == 1);
761+
CHECK(secp256k1_schnorrsig_sign(ctx, &sig, &nonce_is_negated, msg, sk, NULL, &s2c_ctx) == 1);
762+
CHECK(secp256k1_schnorrsig_verify(ctx, &sig, msg, &pk));
763+
764+
CHECK(secp256k1_s2c_commit_get_original_nonce(ctx, &s2c_original_nonce, &s2c_ctx) == 1);
765+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(ctx, &sig, data32, &s2c_original_nonce, nonce_is_negated) == 1);
766+
/* verify_s2c_commit fails if nonce_is_negated is wrong */
767+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(ctx, &sig, data32, &s2c_original_nonce, !nonce_is_negated) == 0);
768+
769+
{
770+
/* verify_s2c_commit fails if given data does not match committed data */
771+
unsigned char data32_tmp[32];
772+
memcpy(data32_tmp, data32, sizeof(data32_tmp));
773+
data32_tmp[31] ^= 1;
774+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(ctx, &sig, data32_tmp, &s2c_original_nonce, nonce_is_negated) == 0);
775+
}
776+
{
777+
/* verify_s2c_commit fails if signature does not commit to data */
778+
secp256k1_schnorrsig sig_tmp;
779+
sig_tmp = sig;
780+
secp256k1_rand256(&sig_tmp.data[0]);
781+
CHECK(secp256k1_schnorrsig_verify_s2c_commit(ctx, &sig_tmp, data32, &s2c_original_nonce, nonce_is_negated) == 0);
782+
}
783+
}
784+
716785
void run_schnorrsig_tests(void) {
786+
int i;
717787
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024);
718788

719789
test_schnorrsig_serialize();
720790
test_schnorrsig_api(scratch);
721791
test_schnorrsig_bip_vectors(scratch);
722792
test_schnorrsig_sign();
723793
test_schnorrsig_sign_verify(scratch);
724-
794+
for (i = 0; i < count; i++) {
795+
/* Run multiple times to increase probability that the nonce is negated in
796+
* a test. */
797+
test_schnorrsig_s2c_commit_verify();
798+
}
725799
secp256k1_scratch_space_destroy(scratch);
726800
}
727801

0 commit comments

Comments
 (0)