@@ -117,6 +117,23 @@ static int secp256k1_frost_session_load(const secp256k1_context* ctx, secp256k1_
117
117
return 1 ;
118
118
}
119
119
120
+ static const unsigned char secp256k1_frost_partial_sig_magic [4 ] = { 0x8d , 0xd8 , 0x31 , 0x6e };
121
+
122
+ static void secp256k1_frost_partial_sig_save (secp256k1_frost_partial_sig * sig , secp256k1_scalar * s ) {
123
+ memcpy (& sig -> data [0 ], secp256k1_frost_partial_sig_magic , 4 );
124
+ secp256k1_scalar_get_b32 (& sig -> data [4 ], s );
125
+ }
126
+
127
+ static int secp256k1_frost_partial_sig_load (const secp256k1_context * ctx , secp256k1_scalar * s , const secp256k1_frost_partial_sig * sig ) {
128
+ int overflow ;
129
+
130
+ ARG_CHECK (secp256k1_memcmp_var (& sig -> data [0 ], secp256k1_frost_partial_sig_magic , 4 ) == 0 );
131
+ secp256k1_scalar_set_b32 (s , & sig -> data [4 ], & overflow );
132
+ /* Parsed signatures can not overflow */
133
+ VERIFY_CHECK (!overflow );
134
+ return 1 ;
135
+ }
136
+
120
137
int secp256k1_frost_pubnonce_serialize (const secp256k1_context * ctx , unsigned char * out66 , const secp256k1_frost_pubnonce * nonce ) {
121
138
secp256k1_ge ge [2 ];
122
139
int i ;
@@ -163,6 +180,29 @@ int secp256k1_frost_pubnonce_parse(const secp256k1_context* ctx, secp256k1_frost
163
180
return 1 ;
164
181
}
165
182
183
+ int secp256k1_frost_partial_sig_serialize (const secp256k1_context * ctx , unsigned char * out32 , const secp256k1_frost_partial_sig * sig ) {
184
+ VERIFY_CHECK (ctx != NULL );
185
+ ARG_CHECK (out32 != NULL );
186
+ ARG_CHECK (sig != NULL );
187
+ memcpy (out32 , & sig -> data [4 ], 32 );
188
+ return 1 ;
189
+ }
190
+
191
+ int secp256k1_frost_partial_sig_parse (const secp256k1_context * ctx , secp256k1_frost_partial_sig * sig , const unsigned char * in32 ) {
192
+ secp256k1_scalar tmp ;
193
+ int overflow ;
194
+ VERIFY_CHECK (ctx != NULL );
195
+ ARG_CHECK (sig != NULL );
196
+ ARG_CHECK (in32 != NULL );
197
+
198
+ secp256k1_scalar_set_b32 (& tmp , in32 , & overflow );
199
+ if (overflow ) {
200
+ return 0 ;
201
+ }
202
+ secp256k1_frost_partial_sig_save (sig , & tmp );
203
+ return 1 ;
204
+ }
205
+
166
206
static void secp256k1_nonce_function_frost (secp256k1_scalar * k , const unsigned char * session_id , const unsigned char * msg32 , const unsigned char * key32 , const unsigned char * pk32 , const unsigned char * extra_input32 ) {
167
207
secp256k1_sha256 sha ;
168
208
unsigned char seed [32 ];
@@ -469,4 +509,154 @@ int secp256k1_frost_nonce_process(const secp256k1_context* ctx, secp256k1_frost_
469
509
return 1 ;
470
510
}
471
511
512
+ void secp256k1_frost_partial_sign_clear (secp256k1_scalar * sk , secp256k1_scalar * k ) {
513
+ secp256k1_scalar_clear (sk );
514
+ secp256k1_scalar_clear (& k [0 ]);
515
+ secp256k1_scalar_clear (& k [1 ]);
516
+ }
517
+
518
+ int secp256k1_frost_partial_sign (const secp256k1_context * ctx , secp256k1_frost_partial_sig * partial_sig , secp256k1_frost_secnonce * secnonce , const secp256k1_frost_share * share , const secp256k1_frost_session * session , const secp256k1_frost_tweak_cache * tweak_cache ) {
519
+ secp256k1_scalar sk ;
520
+ secp256k1_scalar k [2 ];
521
+ secp256k1_scalar s ;
522
+ secp256k1_frost_session_internal session_i ;
523
+ int ret ;
524
+
525
+ VERIFY_CHECK (ctx != NULL );
526
+
527
+ ARG_CHECK (secnonce != NULL );
528
+ /* Fails if the magic doesn't match */
529
+ ret = secp256k1_frost_secnonce_load (ctx , k , secnonce );
530
+ /* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls
531
+ * of this function to fail */
532
+ memset (secnonce , 0 , sizeof (* secnonce ));
533
+ if (!ret ) {
534
+ secp256k1_frost_partial_sign_clear (& sk , k );
535
+ return 0 ;
536
+ }
537
+
538
+ ARG_CHECK (partial_sig != NULL );
539
+ ARG_CHECK (share != NULL );
540
+ ARG_CHECK (session != NULL );
541
+
542
+ if (!secp256k1_frost_share_load (ctx , & sk , share )) {
543
+ secp256k1_frost_partial_sign_clear (& sk , k );
544
+ return 0 ;
545
+ }
546
+ if (!secp256k1_frost_session_load (ctx , & session_i , session )) {
547
+ secp256k1_frost_partial_sign_clear (& sk , k );
548
+ return 0 ;
549
+ }
550
+
551
+ if (tweak_cache != NULL ) {
552
+ secp256k1_tweak_cache_internal cache_i ;
553
+ if (!secp256k1_tweak_cache_load (ctx , & cache_i , tweak_cache )) {
554
+ secp256k1_frost_partial_sign_clear (& sk , k );
555
+ return 0 ;
556
+ }
557
+ if (secp256k1_fe_is_odd (& cache_i .pk .y ) != cache_i .parity_acc ) {
558
+ secp256k1_scalar_negate (& sk , & sk );
559
+ }
560
+ }
561
+
562
+ if (session_i .fin_nonce_parity ) {
563
+ secp256k1_scalar_negate (& k [0 ], & k [0 ]);
564
+ secp256k1_scalar_negate (& k [1 ], & k [1 ]);
565
+ }
566
+
567
+ /* Sign */
568
+ secp256k1_scalar_mul (& s , & session_i .challenge , & sk );
569
+ secp256k1_scalar_mul (& k [1 ], & session_i .noncecoef , & k [1 ]);
570
+ secp256k1_scalar_add (& k [0 ], & k [0 ], & k [1 ]);
571
+ secp256k1_scalar_add (& s , & s , & k [0 ]);
572
+ secp256k1_frost_partial_sig_save (partial_sig , & s );
573
+ secp256k1_frost_partial_sign_clear (& sk , k );
574
+ return 1 ;
575
+ }
576
+
577
+ int secp256k1_frost_partial_sig_verify (const secp256k1_context * ctx , const secp256k1_frost_partial_sig * partial_sig , const secp256k1_frost_pubnonce * pubnonce , const secp256k1_pubkey * pubshare , const secp256k1_frost_session * session , const secp256k1_frost_tweak_cache * tweak_cache ) {
578
+ secp256k1_frost_session_internal session_i ;
579
+ secp256k1_scalar e , s ;
580
+ secp256k1_gej pkj ;
581
+ secp256k1_ge nonce_pt [2 ];
582
+ secp256k1_gej rj ;
583
+ secp256k1_gej tmp ;
584
+ secp256k1_ge pkp ;
585
+
586
+ VERIFY_CHECK (ctx != NULL );
587
+ ARG_CHECK (partial_sig != NULL );
588
+ ARG_CHECK (pubnonce != NULL );
589
+ ARG_CHECK (pubshare != NULL );
590
+ ARG_CHECK (session != NULL );
591
+
592
+ if (!secp256k1_frost_session_load (ctx , & session_i , session )) {
593
+ return 0 ;
594
+ }
595
+
596
+ /* Compute "effective" nonce rj = aggnonce[0] + b*aggnonce[1] */
597
+ /* TODO: use multiexp to compute -s*G + e*pubshare + aggnonce[0] + b*aggnonce[1] */
598
+ if (!secp256k1_frost_pubnonce_load (ctx , nonce_pt , pubnonce )) {
599
+ return 0 ;
600
+ }
601
+ secp256k1_gej_set_ge (& rj , & nonce_pt [1 ]);
602
+ secp256k1_ecmult (& rj , & rj , & session_i .noncecoef , NULL );
603
+ secp256k1_gej_add_ge_var (& rj , & rj , & nonce_pt [0 ], NULL );
604
+
605
+ if (!secp256k1_pubkey_load (ctx , & pkp , pubshare )) {
606
+ return 0 ;
607
+ }
608
+
609
+ secp256k1_scalar_set_int (& e , 1 );
610
+ if (tweak_cache != NULL ) {
611
+ secp256k1_tweak_cache_internal cache_i ;
612
+ if (!secp256k1_tweak_cache_load (ctx , & cache_i , tweak_cache )) {
613
+ return 0 ;
614
+ }
615
+ if (secp256k1_fe_is_odd (& cache_i .pk .y )
616
+ != cache_i .parity_acc ) {
617
+ secp256k1_scalar_negate (& e , & e );
618
+ }
619
+ }
620
+ secp256k1_scalar_mul (& e , & e , & session_i .challenge );
621
+
622
+ if (!secp256k1_frost_partial_sig_load (ctx , & s , partial_sig )) {
623
+ return 0 ;
624
+ }
625
+ /* Compute -s*G + e*pkj + rj (e already includes the lagrange coefficient l) */
626
+ secp256k1_scalar_negate (& s , & s );
627
+ secp256k1_gej_set_ge (& pkj , & pkp );
628
+ secp256k1_ecmult (& tmp , & pkj , & e , & s );
629
+ if (session_i .fin_nonce_parity ) {
630
+ secp256k1_gej_neg (& rj , & rj );
631
+ }
632
+ secp256k1_gej_add_var (& tmp , & tmp , & rj , NULL );
633
+
634
+ return secp256k1_gej_is_infinity (& tmp );
635
+ }
636
+
637
+ int secp256k1_frost_partial_sig_agg (const secp256k1_context * ctx , unsigned char * sig64 , const secp256k1_frost_session * session , const secp256k1_frost_partial_sig * const * partial_sigs , size_t n_sigs ) {
638
+ size_t i ;
639
+ secp256k1_frost_session_internal session_i ;
640
+
641
+ VERIFY_CHECK (ctx != NULL );
642
+ ARG_CHECK (sig64 != NULL );
643
+ ARG_CHECK (session != NULL );
644
+ ARG_CHECK (partial_sigs != NULL );
645
+ ARG_CHECK (n_sigs > 0 );
646
+
647
+ if (!secp256k1_frost_session_load (ctx , & session_i , session )) {
648
+ return 0 ;
649
+ }
650
+ for (i = 0 ; i < n_sigs ; i ++ ) {
651
+ secp256k1_scalar term ;
652
+ if (!secp256k1_frost_partial_sig_load (ctx , & term , partial_sigs [i ])) {
653
+ return 0 ;
654
+ }
655
+ secp256k1_scalar_add (& session_i .s_part , & session_i .s_part , & term );
656
+ }
657
+ secp256k1_scalar_get_b32 (& sig64 [32 ], & session_i .s_part );
658
+ memcpy (& sig64 [0 ], session_i .fin_nonce , 32 );
659
+ return 1 ;
660
+ }
661
+
472
662
#endif
0 commit comments