13
13
14
14
static uint64_t s2c_opening_magic = 0x5d0520b8b7f2b168ULL ;
15
15
16
+ static const unsigned char s2c_data_tag [16 ] = "s2c/schnorr/data" ;
17
+
16
18
static void secp256k1_schnorr_s2c_opening_init (secp256k1_schnorr_s2c_opening * opening ) {
17
19
opening -> magic = s2c_opening_magic ;
18
20
opening -> nonce_is_negated = 0 ;
@@ -183,23 +185,31 @@ static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned c
183
185
secp256k1_scalar_set_b32 (e , buf , NULL );
184
186
}
185
187
186
- static int secp256k1_schnorrsig_sign_internal (const secp256k1_context * ctx , unsigned char * sig64 , const unsigned char * msg , size_t msglen , const secp256k1_keypair * keypair , secp256k1_nonce_function_hardened noncefp , void * ndata ) {
188
+ static int secp256k1_schnorrsig_sign_internal (const secp256k1_context * ctx , unsigned char * sig64 , const unsigned char * msg , size_t msglen , const secp256k1_keypair * keypair , secp256k1_nonce_function_hardened noncefp , void * ndata , secp256k1_schnorr_s2c_opening * s2c_opening , const unsigned char * s2c_data32 ) {
187
189
secp256k1_scalar sk ;
188
190
secp256k1_scalar e ;
189
191
secp256k1_scalar k ;
190
192
secp256k1_gej rj ;
191
193
secp256k1_ge pk ;
192
194
secp256k1_ge r ;
195
+ secp256k1_sha256 sha ;
193
196
unsigned char buf [32 ] = { 0 };
194
197
unsigned char pk_buf [32 ];
195
198
unsigned char seckey [32 ];
199
+ unsigned char noncedata [32 ];
196
200
int ret = 1 ;
197
201
198
202
VERIFY_CHECK (ctx != NULL );
199
203
ARG_CHECK (secp256k1_ecmult_gen_context_is_built (& ctx -> ecmult_gen_ctx ));
200
204
ARG_CHECK (sig64 != NULL );
201
205
ARG_CHECK (msg != NULL || msglen == 0 );
202
206
ARG_CHECK (keypair != NULL );
207
+ /* sign-to-contract commitments only work with the default nonce function,
208
+ * because we need to ensure that s2c_data is actually hashed into the nonce and
209
+ * not just ignored because otherwise this could result in nonce reuse. */
210
+ ARG_CHECK (s2c_data32 == NULL || (noncefp == NULL || noncefp == secp256k1_nonce_function_bip340 ));
211
+ /* s2c_opening and s2c_data32 should be either both non-NULL or both NULL. */
212
+ ARG_CHECK ((s2c_opening != NULL ) == (s2c_data32 != NULL ));
203
213
204
214
if (noncefp == NULL ) {
205
215
noncefp = secp256k1_nonce_function_bip340 ;
@@ -215,6 +225,25 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
215
225
216
226
secp256k1_scalar_get_b32 (seckey , & sk );
217
227
secp256k1_fe_get_b32 (pk_buf , & pk .x );
228
+
229
+ if (s2c_data32 != NULL ) {
230
+ /* Provide s2c_data32 and ndata (if not NULL) to the the nonce function
231
+ * as additional data to derive the nonce from. If both pointers are
232
+ * not NULL, they need to be hashed to get the nonce data 32 bytes.
233
+ * Even if only s2c_data32 is not NULL, it's hashed because it should
234
+ * be possible to derive nonces even if only a SHA256 commitment to the
235
+ * data is known. This is for example important in the anti nonce
236
+ * sidechannel protocol.
237
+ */
238
+ secp256k1_sha256_initialize (& sha );
239
+ secp256k1_sha256_write (& sha , s2c_data32 , 32 );
240
+ if (ndata != NULL ) {
241
+ secp256k1_sha256_write (& sha , ndata , 32 );
242
+ }
243
+ secp256k1_sha256_finalize (& sha , noncedata );
244
+ ndata = & noncedata ;
245
+ }
246
+
218
247
ret &= !!noncefp (buf , msg , msglen , seckey , pk_buf , bip340_algo , sizeof (bip340_algo ), ndata );
219
248
secp256k1_scalar_set_b32 (& k , buf , NULL );
220
249
ret &= !secp256k1_scalar_is_zero (& k );
@@ -223,12 +252,27 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
223
252
secp256k1_ecmult_gen (& ctx -> ecmult_gen_ctx , & rj , & k );
224
253
secp256k1_ge_set_gej (& r , & rj );
225
254
255
+ if (s2c_opening != NULL ) {
256
+ secp256k1_schnorr_s2c_opening_init (s2c_opening );
257
+ if (s2c_data32 != NULL ) {
258
+ secp256k1_sha256_initialize_tagged (& sha , s2c_data_tag , sizeof (s2c_data_tag ));
259
+ /* Create sign-to-contract commitment */
260
+ secp256k1_pubkey_save (& s2c_opening -> original_pubnonce , & r );
261
+ secp256k1_ec_commit_seckey (& k , & r , & sha , s2c_data32 , 32 );
262
+ secp256k1_ecmult_gen (& ctx -> ecmult_gen_ctx , & rj , & k );
263
+ secp256k1_ge_set_gej (& r , & rj );
264
+ }
265
+ }
266
+
226
267
/* We declassify r to allow using it as a branch point. This is fine
227
268
* because r is not a secret. */
228
269
secp256k1_declassify (ctx , & r , sizeof (r ));
229
270
secp256k1_fe_normalize_var (& r .y );
230
271
if (secp256k1_fe_is_odd (& r .y )) {
231
272
secp256k1_scalar_negate (& k , & k );
273
+ if (s2c_opening != NULL ) {
274
+ s2c_opening -> nonce_is_negated = 1 ;
275
+ }
232
276
}
233
277
secp256k1_fe_normalize_var (& r .x );
234
278
secp256k1_fe_get_b32 (& sig64 [0 ], & r .x );
@@ -248,7 +292,7 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
248
292
249
293
int secp256k1_schnorrsig_sign32 (const secp256k1_context * ctx , unsigned char * sig64 , const unsigned char * msg32 , const secp256k1_keypair * keypair , const unsigned char * aux_rand32 ) {
250
294
/* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */
251
- return secp256k1_schnorrsig_sign_internal (ctx , sig64 , msg32 , 32 , keypair , secp256k1_nonce_function_bip340 , (unsigned char * )aux_rand32 );
295
+ return secp256k1_schnorrsig_sign_internal (ctx , sig64 , msg32 , 32 , keypair , secp256k1_nonce_function_bip340 , (unsigned char * )aux_rand32 , NULL , NULL );
252
296
}
253
297
254
298
int secp256k1_schnorrsig_sign (const secp256k1_context * ctx , unsigned char * sig64 , const unsigned char * msg32 , const secp256k1_keypair * keypair , const unsigned char * aux_rand32 ) {
@@ -258,6 +302,8 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64
258
302
int secp256k1_schnorrsig_sign_custom (const secp256k1_context * ctx , unsigned char * sig64 , const unsigned char * msg , size_t msglen , const secp256k1_keypair * keypair , secp256k1_schnorrsig_extraparams * extraparams ) {
259
303
secp256k1_nonce_function_hardened noncefp = NULL ;
260
304
void * ndata = NULL ;
305
+ secp256k1_schnorr_s2c_opening * s2c_opening = NULL ;
306
+ const unsigned char * s2c_data32 = NULL ;
261
307
VERIFY_CHECK (ctx != NULL );
262
308
263
309
if (extraparams != NULL ) {
@@ -266,8 +312,10 @@ int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char
266
312
sizeof (extraparams -> magic )) == 0 );
267
313
noncefp = extraparams -> noncefp ;
268
314
ndata = extraparams -> ndata ;
315
+ s2c_opening = extraparams -> s2c_opening ;
316
+ s2c_data32 = extraparams -> s2c_data32 ;
269
317
}
270
- return secp256k1_schnorrsig_sign_internal (ctx , sig64 , msg , msglen , keypair , noncefp , ndata );
318
+ return secp256k1_schnorrsig_sign_internal (ctx , sig64 , msg , msglen , keypair , noncefp , ndata , s2c_opening , s2c_data32 );
271
319
}
272
320
273
321
int secp256k1_schnorrsig_verify (const secp256k1_context * ctx , const unsigned char * sig64 , const unsigned char * msg , size_t msglen , const secp256k1_xonly_pubkey * pubkey ) {
@@ -318,4 +366,34 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
318
366
secp256k1_fe_equal_var (& rx , & r .x );
319
367
}
320
368
369
+ int secp256k1_schnorrsig_verify_s2c_commit (const secp256k1_context * ctx , const unsigned char * sig64 , const unsigned char * data32 , const secp256k1_schnorr_s2c_opening * opening ) {
370
+ secp256k1_fe rx ;
371
+ secp256k1_ge original_r ;
372
+ secp256k1_ge r ;
373
+ secp256k1_sha256 sha ;
374
+
375
+ VERIFY_CHECK (ctx != NULL );
376
+ ARG_CHECK (sig64 != NULL );
377
+ ARG_CHECK (data32 != NULL );
378
+ ARG_CHECK (opening != NULL );
379
+ ARG_CHECK (secp256k1_s2c_commit_is_init (opening ));
380
+
381
+ if (!secp256k1_fe_set_b32 (& rx , & sig64 [0 ])) {
382
+ return 0 ;
383
+ }
384
+ if (!secp256k1_ge_set_xo_var (& r , & rx , 0 )) {
385
+ return 0 ;
386
+ }
387
+ if (opening -> nonce_is_negated ) {
388
+ secp256k1_ge_neg (& r , & r );
389
+ }
390
+
391
+ if (!secp256k1_pubkey_load (ctx , & original_r , & opening -> original_pubnonce )) {
392
+ return 0 ;
393
+ }
394
+
395
+ secp256k1_sha256_initialize_tagged (& sha , s2c_data_tag , sizeof (s2c_data_tag ));
396
+ return secp256k1_ec_commit_verify (& r , & original_r , & sha , data32 , 32 );
397
+ }
398
+
321
399
#endif
0 commit comments