Skip to content

Commit 3b81570

Browse files
committed
frost-client: fix DKG with 2 participants
1 parent 95c3f8c commit 3b81570

File tree

2 files changed

+87
-60
lines changed

2 files changed

+87
-60
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
}
@@ -536,6 +553,11 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
536553
))
537554
})
538555
.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+
539561
// Copy the pubkeys into the state.
540562
match self.state {
541563
SessionState::WaitingForRound1Packages {
@@ -653,65 +675,70 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
653675
}
654676
eprintln!();
655677

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() {
665685
continue;
666686
}
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,
678723
})
679724
.send()
725+
.await?
726+
.json::<frostd::ReceiveOutput>()
680727
.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+
}
681738
}
739+
eprintln!();
682740
}
683741

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!();
715742
self.state.round1_packages()
716743
}
717744

frost-client/src/contact.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@ pub(crate) fn import(args: &Command) -> Result<(), Box<dyn Error>> {
7575
if config.contact.values().any(|c| c.pubkey == contact.pubkey) {
7676
return Err(eyre!(
7777
"pubkey {} already registered for {}",
78-
hex::encode(&contact.pubkey),
78+
hex::encode(&contact.pubkey.0),
7979
&contact.name,
8080
)
8181
.into());
8282
}
8383
if config.communication_key.as_ref().map(|c| &c.pubkey) == Some(&contact.pubkey) {
8484
return Err(eyre!(
8585
"pubkey {} already registered for yourself",
86-
hex::encode(&contact.pubkey)
86+
hex::encode(&contact.pubkey.0)
8787
)
8888
.into());
8989
}

0 commit comments

Comments
 (0)