Skip to content

Commit b3c62d5

Browse files
committed
frost-client: fix DKG with 2 participants
1 parent 0cfe769 commit b3c62d5

File tree

1 file changed

+85
-58
lines changed

1 file changed

+85
-58
lines changed

dkg/src/comms/http.rs

+85-58
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,21 @@ impl<C: Ciphersuite> SessionState<C> {
133133

134134
// If complete, advance to next state
135135
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+
}
140151
}
141152
}
142153
Ok(())
@@ -265,7 +276,11 @@ impl<C: Ciphersuite> SessionState<C> {
265276
/// When this returns `true`, [`round1_packages()`] can be called, but
266277
/// its contents have not been checked via echo broadcast.
267278
pub fn has_round1_packages(&self) -> bool {
268-
matches!(self, SessionState::WaitingForRound1PackagesBroadcast { .. })
279+
matches!(
280+
self,
281+
SessionState::WaitingForRound1PackagesBroadcast { .. }
282+
| SessionState::WaitingForRound2Packages { .. }
283+
)
269284
}
270285

271286
/// Returns a map linking a participant identifier and the Round 1 Package
@@ -285,9 +300,11 @@ impl<C: Ciphersuite> SessionState<C> {
285300
}
286301
}
287302

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+
///
289306
/// 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.
291308
pub fn has_round1_broadcast_packages(&self) -> bool {
292309
matches!(self, SessionState::WaitingForRound2Packages { .. })
293310
}
@@ -542,6 +559,11 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
542559
))
543560
})
544561
.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+
545567
// Copy the pubkeys into the state.
546568
match self.state {
547569
SessionState::WaitingForRound1Packages {
@@ -659,65 +681,70 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
659681
}
660682
eprintln!();
661683

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() {
671691
continue;
672692
}
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,
684729
})
685730
.send()
731+
.await?
732+
.json::<frostd::ReceiveOutput>()
686733
.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+
}
687744
}
745+
eprintln!();
688746
}
689747

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!();
721748
self.state.round1_packages()
722749
}
723750

0 commit comments

Comments
 (0)