@@ -236,4 +236,155 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
236
236
secp256k1_fe_equal_var (& rx , & r .x );
237
237
}
238
238
239
+ /* TODO: pk input should be parsed or raw bytes? */
240
+ int secp256k1_schnorrsig_halfagg (const secp256k1_context * ctx , unsigned char * aggsig , size_t * aggsig_size , unsigned char * * sig64 , const secp256k1_xonly_pubkey * pk , unsigned char * * msg32 , uint32_t n_sigs ) {
241
+ uint32_t i ;
242
+ secp256k1_scalar s ;
243
+ secp256k1_sha256 sha ;
244
+ unsigned char input_hash [32 ];
245
+
246
+ VERIFY_CHECK (ctx != NULL );
247
+ ARG_CHECK (aggsig != NULL );
248
+ ARG_CHECK (aggsig_size != NULL );
249
+ ARG_CHECK (sig64 != NULL );
250
+ ARG_CHECK (pk != NULL );
251
+ ARG_CHECK (msg32 != NULL );
252
+ /* TODO: overflow? */
253
+ ARG_CHECK (* aggsig_size >= 32 * (1 + n_sigs ));
254
+
255
+ secp256k1_scalar_clear (& s );
256
+
257
+ /* h = hash_{HalfAggregation}(sig_1[0:32] || pk_1 || m_1 || ... || sig_n[0:32] || pk_n || m_n) */
258
+ secp256k1_sha256_initialize_tagged (& sha , (unsigned char * ) "HalfAggregation" , 15 );
259
+ for (i = 0 ; i < n_sigs ; i ++ ) {
260
+ unsigned char pk_ser [32 ];
261
+ secp256k1_sha256_write (& sha , sig64 [i ], 32 );
262
+ secp256k1_xonly_pubkey_serialize (ctx , pk_ser , & pk [i ]);
263
+ secp256k1_sha256_write (& sha , pk_ser , 32 );
264
+ secp256k1_sha256_write (& sha , msg32 [i ], 32 );
265
+ }
266
+ secp256k1_sha256_finalize (& sha , input_hash );
267
+
268
+ for (i = 0 ; i < n_sigs ; i ++ ) {
269
+ /* z_i = int(hash_{HalfAggregationIndex}(h || i)) mod n */
270
+ /* s += z_i⋅int(sig[32:64]) */
271
+ unsigned char z_bytes [32 ];
272
+ secp256k1_scalar z ;
273
+ secp256k1_scalar s_i ;
274
+
275
+ secp256k1_sha256_initialize_tagged (& sha , (unsigned char * ) "HalfAggregationIndex" , 20 );
276
+ secp256k1_sha256_write (& sha , input_hash , sizeof (input_hash ));
277
+ /* TODO: fix endianness (or replace by chacha anyway) and add static test vectors */
278
+ secp256k1_sha256_write (& sha , (unsigned char * )& n_sigs , sizeof (uint32_t ));
279
+ secp256k1_sha256_finalize (& sha , z_bytes );
280
+ secp256k1_scalar_set_b32 (& z , z_bytes , NULL );
281
+ secp256k1_scalar_set_b32 (& s_i , & sig64 [i ][32 ], NULL );
282
+ secp256k1_scalar_mul (& s_i , & s_i , & z );
283
+ secp256k1_scalar_add (& s , & s , & s_i );
284
+ memcpy (& aggsig [32 * i ], sig64 [i ], 32 );
285
+ }
286
+ /* Return sig = byte(r_1) || ... || bytes(r_n) || bytes(s) */
287
+ secp256k1_scalar_get_b32 (& aggsig [32 * n_sigs ], & s );
288
+ * aggsig_size = (n_sigs + 1 ) * 32 ;
289
+
290
+ return 1 ;
291
+ }
292
+
293
+ int secp256k1_schnorrsig_halfagg_verify (const secp256k1_context * ctx , unsigned char * aggsig , size_t aggsig_size , const secp256k1_xonly_pubkey * pk , unsigned char * * msg32 , uint32_t n_sigs ) {
294
+ uint32_t i ;
295
+ secp256k1_sha256 sha ;
296
+ unsigned char input_hash [32 ];
297
+ secp256k1_gej rhs ;
298
+ secp256k1_scalar s ;
299
+ secp256k1_scalar one ;
300
+ int overflow ;
301
+
302
+ VERIFY_CHECK (ctx != NULL );
303
+ ARG_CHECK (secp256k1_ecmult_context_is_built (& ctx -> ecmult_ctx ));
304
+ ARG_CHECK (aggsig != NULL );
305
+ ARG_CHECK (pk != NULL );
306
+ ARG_CHECK (msg32 != NULL );
307
+
308
+ /* TODO: overflow? */
309
+ if (aggsig_size != 32 * (1 + n_sigs )) {
310
+ return 0 ;
311
+ }
312
+
313
+ /* rhs = 0 */
314
+ secp256k1_gej_set_infinity (& rhs );
315
+
316
+ /* h = hash_{HalfAggregation}(sig_1[0:32] || pk_1 || m_1 || ... || sig_n[0:32] || pk_n || m_n) */
317
+ secp256k1_sha256_initialize_tagged (& sha , (unsigned char * ) "HalfAggregation" , 15 );
318
+ for (i = 0 ; i < n_sigs ; i ++ ) {
319
+ unsigned char pk_ser [32 ];
320
+ secp256k1_sha256_write (& sha , & aggsig [i * 32 ], 32 );
321
+ secp256k1_xonly_pubkey_serialize (ctx , pk_ser , & pk [i ]);
322
+ secp256k1_sha256_write (& sha , pk_ser , 32 );
323
+ secp256k1_sha256_write (& sha , msg32 [i ], 32 );
324
+ }
325
+ secp256k1_sha256_finalize (& sha , input_hash );
326
+
327
+ for (i = 0 ; i < n_sigs ; i ++ ) {
328
+ secp256k1_ge P ;
329
+ secp256k1_gej Pj ;
330
+ secp256k1_fe rx ;
331
+ secp256k1_ge R ;
332
+ secp256k1_gej Rj ;
333
+ unsigned char buf [32 ];
334
+ secp256k1_scalar e ;
335
+ unsigned char z_bytes [32 ];
336
+ secp256k1_scalar z ;
337
+
338
+ /* P_i = lift_x(int(pk)); fail if that fails */
339
+ if (!secp256k1_xonly_pubkey_load (ctx , & P , & pk [i ])) {
340
+ return 0 ;
341
+ }
342
+ /* r_i = int(sig[i⋅32:(i+1)⋅32]); fail if r ≥ p */
343
+ if (!secp256k1_fe_set_b32 (& rx , & aggsig [32 * i ])) {
344
+ return 0 ;
345
+ }
346
+ /* R_i = lift_x(r_i); fail if that fails */
347
+ if (!secp256k1_ge_set_xo_var (& R , & rx , 0 )) {
348
+ return 0 ;
349
+ }
350
+ /* e_i = int(hash_{BIP0340/challenge}(bytes(r_i) || pk_i || m_i)) mod n */
351
+ secp256k1_fe_get_b32 (buf , & P .x );
352
+ secp256k1_schnorrsig_challenge (& e , & aggsig [32 * i ], msg32 [i ], buf );
353
+
354
+ /* z_i = int(hash_{HalfAggregationIndex}(h || i)) mod n */
355
+ secp256k1_sha256_initialize_tagged (& sha , (unsigned char * ) "HalfAggregationIndex" , 20 );
356
+ secp256k1_sha256_write (& sha , input_hash , sizeof (input_hash ));
357
+ /* TODO: fix endianness (or replace by chacha anyway) and add static test vectors */
358
+ secp256k1_sha256_write (& sha , (unsigned char * )& n_sigs , sizeof (uint32_t ));
359
+ secp256k1_sha256_finalize (& sha , z_bytes );
360
+ secp256k1_scalar_set_b32 (& z , z_bytes , NULL );
361
+
362
+ /* rhs += z_i⋅(R_1 + e_1⋅P_1) = z_i⋅R_1 + z_i⋅e_1⋅P_1)*/
363
+ /* P = e_i⋅R */
364
+ secp256k1_gej_set_ge (& Pj , & P );
365
+ secp256k1_ecmult (& ctx -> ecmult_ctx , & Pj , & Pj , & e , NULL );
366
+ /* P = P + R */
367
+ secp256k1_gej_set_ge (& Rj , & R );
368
+ secp256k1_gej_add_var (& Pj , & Pj , & Rj , NULL );
369
+ /* P = z_i⋅P */
370
+ secp256k1_ecmult (& ctx -> ecmult_ctx , & Pj , & Pj , & z , NULL );
371
+ /* rhs += P */
372
+ secp256k1_gej_add_var (& rhs , & rhs , & Pj , NULL );
373
+ }
374
+ /* s = int(sig[n⋅32:(n+1)⋅32]) */
375
+ secp256k1_scalar_set_b32 (& s , & aggsig [32 * n_sigs ], & overflow );
376
+ if (overflow ) {
377
+ return 0 ;
378
+ }
379
+
380
+ secp256k1_scalar_set_int (& one , 1 );
381
+ /* Fail if s⋅G ≠ rhs */
382
+ /* rhs = -rhs */
383
+ secp256k1_gej_neg (& rhs , & rhs );
384
+ /* rhs = rhs + sG */
385
+ secp256k1_ecmult (& ctx -> ecmult_ctx , & rhs , & rhs , & one , & s );
386
+
387
+ return secp256k1_gej_is_infinity (& rhs );
388
+ }
389
+
239
390
#endif
0 commit comments