@@ -439,3 +439,311 @@ func (mr *memsetRandReader) Read(buf []byte) (n int, err error) {
439439 }
440440 return len (buf ), nil
441441}
442+
443+ // TestSigningWithAggregatedNonce tests the aggregated nonce signing flow where
444+ // nonces are aggregated externally and provided to participants via
445+ // RegisterCombinedNonce, rather than each participant aggregating nonces
446+ // themselves via RegisterPubNonce.
447+ func TestSigningWithAggregatedNonce (t * testing.T ) {
448+ t .Run ("basic flow" , func (t * testing.T ) {
449+ const numSigners = 5
450+
451+ // Generate signers.
452+ signerKeys := make ([]* btcec.PrivateKey , numSigners )
453+ signSet := make ([]* btcec.PublicKey , numSigners )
454+ for i := 0 ; i < numSigners ; i ++ {
455+ privKey , err := btcec .NewPrivateKey ()
456+ if err != nil {
457+ t .Fatalf ("unable to gen priv key: %v" , err )
458+ }
459+ signerKeys [i ] = privKey
460+ signSet [i ] = privKey .PubKey ()
461+ }
462+
463+ // Each signer creates a context and session.
464+ sessions := make ([]* Session , numSigners )
465+ for i , signerKey := range signerKeys {
466+ signCtx , err := NewContext (
467+ signerKey , false , WithKnownSigners (signSet ),
468+ )
469+ if err != nil {
470+ t .Fatalf ("unable to generate context: %v" , err )
471+ }
472+
473+ session , err := signCtx .NewSession ()
474+ if err != nil {
475+ t .Fatalf ("unable to generate new session: %v" , err )
476+ }
477+ sessions [i ] = session
478+ }
479+
480+ // Phase 1: Collect all public nonces.
481+ pubNonces := make ([][PubNonceSize ]byte , numSigners )
482+ for i , session := range sessions {
483+ pubNonces [i ] = session .PublicNonce ()
484+ }
485+
486+ // Phase 2: Aggregate nonces externally.
487+ combinedNonce , err := AggregateNonces (pubNonces )
488+ if err != nil {
489+ t .Fatalf ("unable to aggregate nonces: %v" , err )
490+ }
491+
492+ // Phase 3: Participants register combined nonce and sign.
493+ msg := sha256 .Sum256 ([]byte ("aggregated nonce signing" ))
494+
495+ partialSigs := make ([]* PartialSignature , numSigners )
496+ for i , session := range sessions {
497+ err = session .RegisterCombinedNonce (combinedNonce )
498+ if err != nil {
499+ t .Fatalf ("signer %d unable to register combined nonce: %v" ,
500+ i , err )
501+ }
502+ sig , err := session .Sign (msg )
503+ if err != nil {
504+ t .Fatalf ("signer %d unable to sign: %v" , i , err )
505+ }
506+ partialSigs [i ] = sig
507+ }
508+
509+ // Phase 4: Combine all partial signatures.
510+ finalSig := CombineSigs (partialSigs [0 ].R , partialSigs )
511+
512+ // Verify the final signature.
513+ combinedKey , _ , _ , err := AggregateKeys (signSet , false )
514+ if err != nil {
515+ t .Fatalf ("unable to aggregate keys: %v" , err )
516+ }
517+
518+ if ! finalSig .Verify (msg [:], combinedKey .FinalKey ) {
519+ t .Fatalf ("final signature is invalid" )
520+ }
521+ })
522+
523+ t .Run ("error: register combined nonce twice" , func (t * testing.T ) {
524+ privKey , _ := btcec .NewPrivateKey ()
525+ privKey2 , _ := btcec .NewPrivateKey ()
526+ signSet := []* btcec.PublicKey {privKey .PubKey (), privKey2 .PubKey ()}
527+
528+ signCtx , _ := NewContext (privKey , false , WithKnownSigners (signSet ))
529+ session , _ := signCtx .NewSession ()
530+
531+ fakeCombinedNonce := [PubNonceSize ]byte {}
532+
533+ // First call should succeed.
534+ err := session .RegisterCombinedNonce (fakeCombinedNonce )
535+ if err != nil {
536+ t .Fatalf ("first RegisterCombinedNonce failed: %v" , err )
537+ }
538+
539+ // Second call should fail.
540+ err = session .RegisterCombinedNonce (fakeCombinedNonce )
541+ if err != ErrAlredyHaveAllNonces {
542+ t .Fatalf ("expected ErrAlredyHaveAllNonces, got: %v" , err )
543+ }
544+ })
545+
546+ t .Run ("error: register combined nonce after register pub nonce" ,
547+ func (t * testing.T ) {
548+
549+ privKey , _ := btcec .NewPrivateKey ()
550+ privKey2 , _ := btcec .NewPrivateKey ()
551+ privKey3 , _ := btcec .NewPrivateKey ()
552+ signSet := []* btcec.PublicKey {
553+ privKey .PubKey (),
554+ privKey2 .PubKey (),
555+ privKey3 .PubKey (),
556+ }
557+
558+ signCtx , _ := NewContext (privKey , false , WithKnownSigners (signSet ))
559+ session , _ := signCtx .NewSession ()
560+
561+ signCtx2 , _ := NewContext (privKey2 , false , WithKnownSigners (signSet ))
562+ session2 , _ := signCtx2 .NewSession ()
563+
564+ // Register one public nonce first.
565+ _ , err := session .RegisterPubNonce (session2 .PublicNonce ())
566+ if err != nil {
567+ t .Fatalf ("RegisterPubNonce failed: %v" , err )
568+ }
569+
570+ // Now try to register a combined nonce - this should fail.
571+ fakeCombinedNonce := [PubNonceSize ]byte {}
572+ err = session .RegisterCombinedNonce (fakeCombinedNonce )
573+ if err == nil {
574+ t .Fatalf ("expected error when calling RegisterCombinedNonce " +
575+ "after RegisterPubNonce" )
576+ }
577+ })
578+
579+ t .Run ("error: register pub nonce after register combined nonce" ,
580+ func (t * testing.T ) {
581+
582+ const numSigners = 3
583+
584+ signerKeys := make ([]* btcec.PrivateKey , numSigners )
585+ signSet := make ([]* btcec.PublicKey , numSigners )
586+ for i := 0 ; i < numSigners ; i ++ {
587+ privKey , _ := btcec .NewPrivateKey ()
588+ signerKeys [i ] = privKey
589+ signSet [i ] = privKey .PubKey ()
590+ }
591+
592+ sessions := make ([]* Session , numSigners )
593+ for i , signerKey := range signerKeys {
594+ signCtx , _ := NewContext (signerKey , false , WithKnownSigners (signSet ))
595+ session , _ := signCtx .NewSession ()
596+ sessions [i ] = session
597+ }
598+
599+ pubNonces := make ([][PubNonceSize ]byte , numSigners )
600+ for i , session := range sessions {
601+ pubNonces [i ] = session .PublicNonce ()
602+ }
603+
604+ combinedNonce , _ := AggregateNonces (pubNonces )
605+
606+ // Register the combined nonce first.
607+ err := sessions [0 ].RegisterCombinedNonce (combinedNonce )
608+ if err != nil {
609+ t .Fatalf ("RegisterCombinedNonce failed: %v" , err )
610+ }
611+
612+ // Now try to register individual nonces - this should fail.
613+ _ , err = sessions [0 ].RegisterPubNonce (pubNonces [1 ])
614+ if err == nil {
615+ t .Fatalf ("expected error when calling RegisterPubNonce " +
616+ "after RegisterCombinedNonce" )
617+ }
618+ })
619+
620+ t .Run ("nonce reuse prevention" , func (t * testing.T ) {
621+ privKey , _ := btcec .NewPrivateKey ()
622+ privKey2 , _ := btcec .NewPrivateKey ()
623+ signSet := []* btcec.PublicKey {privKey .PubKey (), privKey2 .PubKey ()}
624+
625+ signCtx , _ := NewContext (privKey , false , WithKnownSigners (signSet ))
626+ session , _ := signCtx .NewSession ()
627+
628+ fakeCombinedNonce := [PubNonceSize ]byte {}
629+ session .RegisterCombinedNonce (fakeCombinedNonce )
630+
631+ msg := sha256 .Sum256 ([]byte ("nonce reuse test" ))
632+
633+ // First sign should succeed.
634+ _ , err := session .Sign (msg )
635+ if err != nil {
636+ t .Fatalf ("first sign failed: %v" , err )
637+ }
638+
639+ // Second sign should fail due to nonce reuse.
640+ _ , err = session .Sign (msg )
641+ if err != ErrSigningContextReuse {
642+ t .Fatalf ("expected nonce reuse error, got: %v" , err )
643+ }
644+ })
645+
646+ t .Run ("incorrect combined nonce produces invalid sig" , func (t * testing.T ) {
647+ const numSigners = 3
648+
649+ signerKeys := make ([]* btcec.PrivateKey , numSigners )
650+ signSet := make ([]* btcec.PublicKey , numSigners )
651+ for i := 0 ; i < numSigners ; i ++ {
652+ privKey , _ := btcec .NewPrivateKey ()
653+ signerKeys [i ] = privKey
654+ signSet [i ] = privKey .PubKey ()
655+ }
656+
657+ sessions := make ([]* Session , numSigners )
658+ for i , signerKey := range signerKeys {
659+ signCtx , _ := NewContext (signerKey , false , WithKnownSigners (signSet ))
660+ session , _ := signCtx .NewSession ()
661+ sessions [i ] = session
662+ }
663+
664+ pubNonces := make ([][PubNonceSize ]byte , numSigners )
665+ for i , session := range sessions {
666+ pubNonces [i ] = session .PublicNonce ()
667+ }
668+
669+ // Create INCORRECT combined nonce using only a subset.
670+ wrongNonces := pubNonces [:2 ]
671+ incorrectCombinedNonce , _ := AggregateNonces (wrongNonces )
672+
673+ msg := sha256 .Sum256 ([]byte ("incorrect nonce test" ))
674+
675+ partialSigs := make ([]* PartialSignature , numSigners )
676+ for i , session := range sessions {
677+ session .RegisterCombinedNonce (incorrectCombinedNonce )
678+ sig , _ := session .Sign (msg )
679+ partialSigs [i ] = sig
680+ }
681+
682+ finalSig := CombineSigs (partialSigs [0 ].R , partialSigs )
683+ combinedKey , _ , _ , _ := AggregateKeys (signSet , false )
684+
685+ // Final signature should be INVALID.
686+ if finalSig .Verify (msg [:], combinedKey .FinalKey ) {
687+ t .Fatalf ("final signature should be invalid with incorrect nonce" )
688+ }
689+ })
690+
691+ t .Run ("mixed registration methods" , func (t * testing.T ) {
692+ const numSigners = 4
693+
694+ signerKeys := make ([]* btcec.PrivateKey , numSigners )
695+ signSet := make ([]* btcec.PublicKey , numSigners )
696+ for i := 0 ; i < numSigners ; i ++ {
697+ privKey , _ := btcec .NewPrivateKey ()
698+ signerKeys [i ] = privKey
699+ signSet [i ] = privKey .PubKey ()
700+ }
701+
702+ sessions := make ([]* Session , numSigners )
703+ for i , signerKey := range signerKeys {
704+ signCtx , _ := NewContext (signerKey , false , WithKnownSigners (signSet ))
705+ session , _ := signCtx .NewSession ()
706+ sessions [i ] = session
707+ }
708+
709+ pubNonces := make ([][PubNonceSize ]byte , numSigners )
710+ for i , session := range sessions {
711+ pubNonces [i ] = session .PublicNonce ()
712+ }
713+
714+ combinedNonce , _ := AggregateNonces (pubNonces )
715+ msg := sha256 .Sum256 ([]byte ("mixed registration test" ))
716+
717+ // Half use RegisterCombinedNonce.
718+ for i := 0 ; i < numSigners / 2 ; i ++ {
719+ sessions [i ].RegisterCombinedNonce (combinedNonce )
720+ }
721+
722+ // Other half use RegisterPubNonce.
723+ for i := numSigners / 2 ; i < numSigners ; i ++ {
724+ for j , nonce := range pubNonces {
725+ if i == j {
726+ continue
727+ }
728+ sessions [i ].RegisterPubNonce (nonce )
729+ }
730+ }
731+
732+ // All should be able to sign.
733+ partialSigs := make ([]* PartialSignature , numSigners )
734+ for i , session := range sessions {
735+ sig , err := session .Sign (msg )
736+ if err != nil {
737+ t .Fatalf ("signer %d unable to sign: %v" , i , err )
738+ }
739+ partialSigs [i ] = sig
740+ }
741+
742+ finalSig := CombineSigs (partialSigs [0 ].R , partialSigs )
743+ combinedKey , _ , _ , _ := AggregateKeys (signSet , false )
744+
745+ if ! finalSig .Verify (msg [:], combinedKey .FinalKey ) {
746+ t .Fatalf ("final signature is invalid" )
747+ }
748+ })
749+ }
0 commit comments