@@ -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
}
@@ -536,6 +553,11 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
536
553
) )
537
554
} )
538
555
. collect :: < Result < _ , frost_core:: Error < C > > > ( ) ?;
556
+
557
+ if self . pubkeys . len ( ) < 2 {
558
+ return Err ( eyre ! ( "DKG session must have at least 2 participants" ) . into ( ) ) ;
559
+ }
560
+
539
561
// Copy the pubkeys into the state.
540
562
match self . state {
541
563
SessionState :: WaitingForRound1Packages {
@@ -653,65 +675,70 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
653
675
}
654
676
eprintln ! ( ) ;
655
677
656
- // Broadcast received Round 1 Packages to all other participants
657
- for ( recipient_pubkey, recipient_identifier) in self . pubkeys . clone ( ) . iter ( ) {
658
- // No need to broadcast to oneself
659
- if Some ( recipient_pubkey) == self . args . comm_pubkey . as_ref ( ) {
660
- continue ;
661
- }
662
- for ( sender_identifier, package) in self . state . round1_packages ( ) ?. iter ( ) {
663
- // No need to broadcast back to the sender
664
- if * sender_identifier == * recipient_identifier {
678
+ // We might need to skip the echo broadcast if its not needed (e.g.
679
+ // only 2 participants)
680
+ if !self . state . has_round1_broadcast_packages ( ) {
681
+ // Broadcast received Round 1 Packages to all other participants
682
+ for ( recipient_pubkey, recipient_identifier) in self . pubkeys . clone ( ) . iter ( ) {
683
+ // No need to broadcast to oneself
684
+ if Some ( recipient_pubkey) == self . args . comm_pubkey . as_ref ( ) {
665
685
continue ;
666
686
}
667
- let msg = self . encrypt (
668
- recipient_pubkey,
669
- serde_json:: to_vec ( & ( * sender_identifier, package) ) ?,
670
- ) ?;
671
- self . client
672
- . post ( format ! ( "{}/send" , self . host_port) )
673
- . bearer_auth ( self . access_token . as_ref ( ) . expect ( "was just set" ) )
674
- . json ( & frostd:: SendArgs {
675
- session_id : self . session_id . expect ( "set before" ) ,
676
- recipients : vec ! [ recipient_pubkey. clone( ) ] ,
677
- msg,
687
+ for ( sender_identifier, package) in self . state . round1_packages ( ) ?. iter ( ) {
688
+ // No need to broadcast back to the sender
689
+ if * sender_identifier == * recipient_identifier {
690
+ continue ;
691
+ }
692
+ let msg = self . encrypt (
693
+ recipient_pubkey,
694
+ serde_json:: to_vec ( & ( * sender_identifier, package) ) ?,
695
+ ) ?;
696
+ self . client
697
+ . post ( format ! ( "{}/send" , self . host_port) )
698
+ . bearer_auth ( self . access_token . as_ref ( ) . expect ( "was just set" ) )
699
+ . json ( & frostd:: SendArgs {
700
+ session_id : self . session_id . expect ( "set before" ) ,
701
+ recipients : vec ! [ recipient_pubkey. clone( ) ] ,
702
+ msg,
703
+ } )
704
+ . send ( )
705
+ . await ?;
706
+ }
707
+ }
708
+
709
+ eprint ! ( "Waiting for other participants to send their broadcasted Round 1 Packages..." ) ;
710
+
711
+ loop {
712
+ let r = self
713
+ . client
714
+ . post ( format ! ( "{}/receive" , self . host_port) )
715
+ . bearer_auth (
716
+ self . access_token
717
+ . as_ref ( )
718
+ . expect ( "must have been set before" ) ,
719
+ )
720
+ . json ( & frostd:: ReceiveArgs {
721
+ session_id : self . session_id . unwrap ( ) ,
722
+ as_coordinator : false ,
678
723
} )
679
724
. send ( )
725
+ . await ?
726
+ . json :: < frostd:: ReceiveOutput > ( )
680
727
. await ?;
728
+ for msg in r. msgs {
729
+ let msg = self . decrypt ( msg) ?;
730
+ self . state
731
+ . recv ( msg, self . identifier . expect ( "must have been set" ) ) ?;
732
+ }
733
+ tokio:: time:: sleep ( Duration :: from_secs ( 2 ) ) . await ;
734
+ eprint ! ( "." ) ;
735
+ if self . state . has_round1_broadcast_packages ( ) {
736
+ break ;
737
+ }
681
738
}
739
+ eprintln ! ( ) ;
682
740
}
683
741
684
- eprint ! ( "Waiting for other participants to send their broadcasted Round 1 Packages..." ) ;
685
-
686
- loop {
687
- let r = self
688
- . client
689
- . post ( format ! ( "{}/receive" , self . host_port) )
690
- . bearer_auth (
691
- self . access_token
692
- . as_ref ( )
693
- . expect ( "must have been set before" ) ,
694
- )
695
- . json ( & frostd:: ReceiveArgs {
696
- session_id : self . session_id . unwrap ( ) ,
697
- as_coordinator : false ,
698
- } )
699
- . send ( )
700
- . await ?
701
- . json :: < frostd:: ReceiveOutput > ( )
702
- . await ?;
703
- for msg in r. msgs {
704
- let msg = self . decrypt ( msg) ?;
705
- self . state
706
- . recv ( msg, self . identifier . expect ( "must have been set" ) ) ?;
707
- }
708
- tokio:: time:: sleep ( Duration :: from_secs ( 2 ) ) . await ;
709
- eprint ! ( "." ) ;
710
- if self . state . has_round1_broadcast_packages ( ) {
711
- break ;
712
- }
713
- }
714
- eprintln ! ( ) ;
715
742
self . state . round1_packages ( )
716
743
}
717
744
0 commit comments