@@ -133,10 +133,21 @@ impl<C: Ciphersuite> SessionState<C> {
133
133
134
134
// If complete, advance to next state
135
135
if round1_packages. len ( ) == pubkeys. len ( ) - 1 {
136
- * self = SessionState :: WaitingForRound1PackagesBroadcast {
137
- pubkeys : pubkeys. clone ( ) ,
138
- round1_packages : round1_packages. clone ( ) ,
139
- round1_broadcasted_packages : Default :: default ( ) ,
136
+ if pubkeys. len ( ) > 2 {
137
+ * self = SessionState :: WaitingForRound1PackagesBroadcast {
138
+ pubkeys : pubkeys. clone ( ) ,
139
+ round1_packages : round1_packages. clone ( ) ,
140
+ round1_broadcasted_packages : Default :: default ( ) ,
141
+ }
142
+ } else {
143
+ // if pubkeys.len() == 2 then the echo broadcast protocol
144
+ // degenerates into a simple broadcast, so we can just skip
145
+ // the echo broadcast round.
146
+ * self = SessionState :: WaitingForRound2Packages {
147
+ pubkeys : pubkeys. clone ( ) ,
148
+ round1_packages : round1_packages. clone ( ) ,
149
+ round2_packages : Default :: default ( ) ,
150
+ }
140
151
}
141
152
}
142
153
Ok ( ( ) )
@@ -265,7 +276,11 @@ impl<C: Ciphersuite> SessionState<C> {
265
276
/// When this returns `true`, [`round1_packages()`] can be called, but
266
277
/// its contents have not been checked via echo broadcast.
267
278
pub fn has_round1_packages ( & self ) -> bool {
268
- matches ! ( self , SessionState :: WaitingForRound1PackagesBroadcast { .. } )
279
+ matches ! (
280
+ self ,
281
+ SessionState :: WaitingForRound1PackagesBroadcast { .. }
282
+ | SessionState :: WaitingForRound2Packages { .. }
283
+ )
269
284
}
270
285
271
286
/// Returns a map linking a participant identifier and the Round 1 Package
@@ -285,9 +300,11 @@ impl<C: Ciphersuite> SessionState<C> {
285
300
}
286
301
}
287
302
288
- /// Returns if all participants sent their broadcast Round 1 Packages.
303
+ /// Returns if all participants sent their broadcast Round 1 Packages,
304
+ /// or if the echo broadcast round should be skipped.
305
+ ///
289
306
/// When this returns `true`, [`round1_packages()`] can be called,
290
- /// and its contents are ensure to be checked via echo broadcast.
307
+ /// and its contents are ensured to be checked via echo broadcast.
291
308
pub fn has_round1_broadcast_packages ( & self ) -> bool {
292
309
matches ! ( self , SessionState :: WaitingForRound2Packages { .. } )
293
310
}
@@ -542,6 +559,11 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
542
559
) )
543
560
} )
544
561
. collect :: < Result < _ , frost_core:: Error < C > > > ( ) ?;
562
+
563
+ if self . pubkeys . len ( ) < 2 {
564
+ return Err ( eyre ! ( "DKG session must have at least 2 participants" ) . into ( ) ) ;
565
+ }
566
+
545
567
// Copy the pubkeys into the state.
546
568
match self . state {
547
569
SessionState :: WaitingForRound1Packages {
@@ -659,65 +681,70 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
659
681
}
660
682
eprintln ! ( ) ;
661
683
662
- // Broadcast received Round 1 Packages to all other participants
663
- for ( recipient_pubkey, recipient_identifier) in self . pubkeys . clone ( ) . iter ( ) {
664
- // No need to broadcast to oneself
665
- if Some ( recipient_pubkey) == self . args . comm_pubkey . as_ref ( ) {
666
- continue ;
667
- }
668
- for ( sender_identifier, package) in self . state . round1_packages ( ) ?. iter ( ) {
669
- // No need to broadcast back to the sender
670
- if * sender_identifier == * recipient_identifier {
684
+ // We might need to skip the echo broadcast if its not needed (e.g.
685
+ // only 2 participants)
686
+ if !self . state . has_round1_broadcast_packages ( ) {
687
+ // Broadcast received Round 1 Packages to all other participants
688
+ for ( recipient_pubkey, recipient_identifier) in self . pubkeys . clone ( ) . iter ( ) {
689
+ // No need to broadcast to oneself
690
+ if Some ( recipient_pubkey) == self . args . comm_pubkey . as_ref ( ) {
671
691
continue ;
672
692
}
673
- let msg = self . encrypt (
674
- recipient_pubkey,
675
- serde_json:: to_vec ( & ( * sender_identifier, package) ) ?,
676
- ) ?;
677
- self . client
678
- . post ( format ! ( "{}/send" , self . host_port) )
679
- . bearer_auth ( self . access_token . as_ref ( ) . expect ( "was just set" ) )
680
- . json ( & frostd:: SendArgs {
681
- session_id : self . session_id . expect ( "set before" ) ,
682
- recipients : vec ! [ PublicKey ( recipient_pubkey. clone( ) ) ] ,
683
- msg,
693
+ for ( sender_identifier, package) in self . state . round1_packages ( ) ?. iter ( ) {
694
+ // No need to broadcast back to the sender
695
+ if * sender_identifier == * recipient_identifier {
696
+ continue ;
697
+ }
698
+ let msg = self . encrypt (
699
+ recipient_pubkey,
700
+ serde_json:: to_vec ( & ( * sender_identifier, package) ) ?,
701
+ ) ?;
702
+ self . client
703
+ . post ( format ! ( "{}/send" , self . host_port) )
704
+ . bearer_auth ( self . access_token . as_ref ( ) . expect ( "was just set" ) )
705
+ . json ( & frostd:: SendArgs {
706
+ session_id : self . session_id . expect ( "set before" ) ,
707
+ recipients : vec ! [ PublicKey ( recipient_pubkey. clone( ) ) ] ,
708
+ msg,
709
+ } )
710
+ . send ( )
711
+ . await ?;
712
+ }
713
+ }
714
+
715
+ eprint ! ( "Waiting for other participants to send their broadcasted Round 1 Packages..." ) ;
716
+
717
+ loop {
718
+ let r = self
719
+ . client
720
+ . post ( format ! ( "{}/receive" , self . host_port) )
721
+ . bearer_auth (
722
+ self . access_token
723
+ . as_ref ( )
724
+ . expect ( "must have been set before" ) ,
725
+ )
726
+ . json ( & frostd:: ReceiveArgs {
727
+ session_id : self . session_id . unwrap ( ) ,
728
+ as_coordinator : false ,
684
729
} )
685
730
. send ( )
731
+ . await ?
732
+ . json :: < frostd:: ReceiveOutput > ( )
686
733
. await ?;
734
+ for msg in r. msgs {
735
+ let msg = self . decrypt ( msg) ?;
736
+ self . state
737
+ . recv ( msg, self . identifier . expect ( "must have been set" ) ) ?;
738
+ }
739
+ tokio:: time:: sleep ( Duration :: from_secs ( 2 ) ) . await ;
740
+ eprint ! ( "." ) ;
741
+ if self . state . has_round1_broadcast_packages ( ) {
742
+ break ;
743
+ }
687
744
}
745
+ eprintln ! ( ) ;
688
746
}
689
747
690
- eprint ! ( "Waiting for other participants to send their broadcasted Round 1 Packages..." ) ;
691
-
692
- loop {
693
- let r = self
694
- . client
695
- . post ( format ! ( "{}/receive" , self . host_port) )
696
- . bearer_auth (
697
- self . access_token
698
- . as_ref ( )
699
- . expect ( "must have been set before" ) ,
700
- )
701
- . json ( & frostd:: ReceiveArgs {
702
- session_id : self . session_id . unwrap ( ) ,
703
- as_coordinator : false ,
704
- } )
705
- . send ( )
706
- . await ?
707
- . json :: < frostd:: ReceiveOutput > ( )
708
- . await ?;
709
- for msg in r. msgs {
710
- let msg = self . decrypt ( msg) ?;
711
- self . state
712
- . recv ( msg, self . identifier . expect ( "must have been set" ) ) ?;
713
- }
714
- tokio:: time:: sleep ( Duration :: from_secs ( 2 ) ) . await ;
715
- eprint ! ( "." ) ;
716
- if self . state . has_round1_broadcast_packages ( ) {
717
- break ;
718
- }
719
- }
720
- eprintln ! ( ) ;
721
748
self . state . round1_packages ( )
722
749
}
723
750
0 commit comments