@@ -117,6 +117,23 @@ static int secp256k1_frost_session_load(const secp256k1_context* ctx, secp256k1_
117117 return 1 ;
118118}
119119
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+
120137int secp256k1_frost_pubnonce_serialize (const secp256k1_context * ctx , unsigned char * out66 , const secp256k1_frost_pubnonce * nonce ) {
121138 secp256k1_ge ge [2 ];
122139 int i ;
@@ -163,6 +180,29 @@ int secp256k1_frost_pubnonce_parse(const secp256k1_context* ctx, secp256k1_frost
163180 return 1 ;
164181}
165182
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+
166206static 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 ) {
167207 secp256k1_sha256 sha ;
168208 unsigned char seed [32 ];
@@ -469,4 +509,154 @@ int secp256k1_frost_nonce_process(const secp256k1_context* ctx, secp256k1_frost_
469509 return 1 ;
470510}
471511
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+
472662#endif
0 commit comments