commit 55c5cb0e9f795556870e8e38dba6fa6e293d4464
parent c3d49d6115e3448e4a7371a08e06b4fc4e278f69
Author: Nick <nick@nickfarrow.com>
Date: Tue, 11 Oct 2022 01:49:33 +1100
RoastResponse includes intended recipients (#1)
* RoastResponse includes intended recipients
Diffstat:
2 files changed, 80 insertions(+), 60 deletions(-)
diff --git a/roastlib/src/coordinator.rs b/roastlib/src/coordinator.rs
@@ -23,6 +23,7 @@ pub struct Coordinator<'a, H, NG> {
state: Arc<Mutex<RoastState<'a>>>,
}
+#[derive(Debug)]
pub struct RoastState<'a> {
message: Message<'a, Public>,
responsive_signers: HashSet<usize>,
@@ -33,12 +34,20 @@ pub struct RoastState<'a> {
signer_session_map: HashMap<usize, usize>,
}
+#[derive(Debug)]
pub struct RoastSignSession {
pub signers: HashSet<usize>,
nonces: Vec<(usize, Nonce)>,
sig_shares: Vec<Scalar<Public, Zero>>,
}
+#[derive(Debug)]
+pub struct RoastResponse {
+ pub recipients: Vec<usize>,
+ pub combined_signature: Option<Signature>,
+ pub nonce_set: Option<Vec<(usize, Nonce)>>,
+}
+
impl<'a, H: Digest + Clone + Digest<OutputSize = U32>, NG> Coordinator<'a, H, NG> {
pub fn new(
frost: Frost<H, NG>,
@@ -73,12 +82,17 @@ impl<'a, H: Digest + Clone + Digest<OutputSize = U32>, NG> Coordinator<'a, H, NG
index: usize,
signature_share: Option<Scalar<Public, Zero>>,
new_nonce: Nonce,
- ) -> (Option<Signature>, Option<Vec<(usize, Nonce)>>) {
+ ) -> RoastResponse {
let mut roast_state = self.state.lock().expect("got lock");
+ // dbg!(&roast_state);
if roast_state.malicious_signers.contains(&index) {
println!("Malicious signer tried to send signature! {}", index);
- return (None, None);
+ return RoastResponse {
+ recipients: vec![index],
+ combined_signature: None,
+ nonce_set: None,
+ };
}
if roast_state.responsive_signers.contains(&index) {
@@ -93,7 +107,11 @@ impl<'a, H: Digest + Clone + Digest<OutputSize = U32>, NG> Coordinator<'a, H, NG
panic!("not enough singers left to continue!");
}
- return (None, None);
+ return RoastResponse {
+ recipients: vec![index],
+ combined_signature: None,
+ nonce_set: None,
+ };
}
// If this is not the inital message from S_i
@@ -123,7 +141,9 @@ impl<'a, H: Digest + Clone + Digest<OutputSize = U32>, NG> Coordinator<'a, H, NG
&self.frost_key.clone(),
&session,
index,
- signature_share.expect("party unexpectedly provided None signature share"),
+ signature_share.expect(
+ "party unexpectedly provided None signature share for a sign session",
+ ),
) {
println!("Invalid signature, marking {} malicious.", index);
roast_state.malicious_signers.insert(index);
@@ -131,7 +151,11 @@ impl<'a, H: Digest + Clone + Digest<OutputSize = U32>, NG> Coordinator<'a, H, NG
panic!("not enough singers left to continue!");
}
- return (None, None);
+ return RoastResponse {
+ recipients: vec![index],
+ combined_signature: None,
+ nonce_set: None,
+ };
}
// Reopen session within the roast state for writting
@@ -149,7 +173,6 @@ impl<'a, H: Digest + Clone + Digest<OutputSize = U32>, NG> Coordinator<'a, H, NG
println!("New signature from party {}", index);
// if we have t-of-n, combine!
-
if roast_session.sig_shares.len() >= self.frost_key.clone().threshold() {
println!("We have the threshold number of signatures, combining!");
dbg!(&roast_session.sig_shares);
@@ -159,7 +182,11 @@ impl<'a, H: Digest + Clone + Digest<OutputSize = U32>, NG> Coordinator<'a, H, NG
roast_session.sig_shares.clone(),
);
// return combined signature
- return (Some(combined_sig), None);
+ return RoastResponse {
+ recipients: (0..self.frost_key.n_signers()).collect(),
+ combined_signature: Some(combined_sig),
+ nonce_set: None,
+ };
}
}
None => {}
@@ -197,35 +224,35 @@ impl<'a, H: Digest + Clone + Digest<OutputSize = U32>, NG> Coordinator<'a, H, NG
.collect();
let sid = roast_state.session_counter.clone();
- for i in r_signers.clone() {
- // Remember the session of this signer
- roast_state.signer_session_map.insert(i, sid);
-
- // send agg nonce to signers (rho, R)
- let _nonces: Vec<_> = roast_state
- .latest_nonces
- .iter()
- .map(|(i, nonce)| (*i, *nonce))
- .collect();
- // DO THIS FOR EVERY S_i...>!>!> need async
- // OPEN MANY THREADS AND THEN AWAIT COLLECTION
- }
-
// Clear responsive signers (otherwise we ban everyone and hang)
roast_state.responsive_signers = HashSet::new();
roast_state.sessions.insert(
sid,
Arc::new(Mutex::new(RoastSignSession {
- signers: r_signers,
+ signers: r_signers.clone(),
nonces: nonces.clone(),
sig_shares: vec![],
})),
);
- return (None, Some(nonces));
+ // Remember the session for signers S_i
+ for i in &r_signers {
+ roast_state.signer_session_map.insert(*i, sid);
+ }
+
+ // Send nonces to each signer S_i
+ return RoastResponse {
+ recipients: r_signers.into_iter().collect(),
+ combined_signature: None,
+ nonce_set: Some(nonces),
+ };
}
// (None, Some(roast_state.latest_nonces))
- (None, None)
+ return RoastResponse {
+ recipients: vec![index],
+ combined_signature: None,
+ nonce_set: None,
+ };
}
}
diff --git a/roastlib/src/main.rs b/roastlib/src/main.rs
@@ -43,33 +43,41 @@ mod test {
);
// Begin with each signer sending a nonce to ROAST, marking these signers as responsive.
- let (combined_signature, nonce_set) = roast.receive(0, None, nonce1);
- assert!(nonce_set.is_none());
- assert!(combined_signature.is_none());
+ let response = roast.receive(0, None, nonce1);
+ assert!(response.nonce_set.is_none());
+ assert!(response.combined_signature.is_none());
- let (_combined_signature, nonce_set) = roast.receive(1, None, nonce2);
- assert!(nonce_set.is_some());
+ let response2 = roast.receive(1, None, nonce2);
+ assert!(response2.nonce_set.is_some());
- // Once ROAST receives the threshold number of nonces, it responds with a nonce set
- let sign_session_nonces = nonce_set.expect("roast responded with nonces");
+ // Once ROAST receives the threshold number of nonces, it responds to the group of
+ // responsive signers with a nonce set to the group of responsive signers.
+ assert!(response2.recipients.contains(&0) && response2.recipients.contains(&1));
+ let sign_session_nonces = response2.nonce_set.expect("roast responded with nonces");
// The signer signs using this the nonces for this sign session,
// and responds to ROAST with a signature share.
let (sig_share2, nonce2) = signer2.sign(sign_session_nonces.clone());
- let (combined_signature, nonce_set) = roast.receive(1, Some(sig_share2), nonce2);
- dbg!(&combined_signature.is_some(), &nonce_set.is_some());
- assert!(combined_signature.is_none());
+ let response = roast.receive(1, Some(sig_share2), nonce2);
+ dbg!(
+ &response.combined_signature.is_some(),
+ &response.nonce_set.is_some()
+ );
+ assert!(response.combined_signature.is_none());
// ROAST also sends the nonce set to the other signer, who also signs
let (sig_share1, nonce1) = signer1.sign(sign_session_nonces);
- let (combined_signature, nonce_set) = roast.receive(0, Some(sig_share1), nonce1);
- dbg!(&combined_signature.is_some(), &nonce_set.is_some());
- assert!(combined_signature.is_some());
+ let response = roast.receive(0, Some(sig_share1), nonce1);
+ dbg!(
+ &response.combined_signature.is_some(),
+ &response.nonce_set.is_some()
+ );
+ assert!(response.combined_signature.is_some());
// Once the threshold number of signature shares have been received,
// ROAST combines the signature shares into the aggregate signature
- dbg!(combined_signature);
+ dbg!(response.combined_signature);
}
// This test works, but slowly since it goes through a few sets of responsive signers
@@ -109,7 +117,7 @@ mod test {
for signer_index in 0..n_parties {
// Check to see if this signer has recieved any nonces
let (sig, new_nonce) = match nonce_set[signer_index].clone() {
- // Sign if we have recieved nonces, and create new nonce
+ // If we have nonces, sign and send sig and a new nonce
Some(signing_nonces) => {
// dbg!(&signing_nonces);
let (sig, nonce) = signers[signer_index].sign(signing_nonces);
@@ -124,33 +132,18 @@ mod test {
),
};
// Send signature and our next nonce to ROAST
- let (combined_sig, updated_nonce_set) = roast.receive(signer_index, sig, new_nonce);
+ let response = roast.receive(signer_index, sig, new_nonce);
+ nonces[signer_index] = new_nonce;
- if combined_sig.is_some() {
- finished_signature = combined_sig;
+ if response.combined_signature.is_some() {
+ finished_signature = response.combined_signature;
break;
}
- // hacky mimic broadcast
- // Store the new nonce_set for this caller,
- // and for peers who are have not recieved any nonces yet.
- // this will probably break when introducing malicious signers
- if updated_nonce_set.is_some() {
- nonce_set[signer_index] = updated_nonce_set.clone();
- nonce_set = nonce_set
- .into_iter()
- .map(|nonce| {
- if nonce.is_some() {
- nonce
- } else {
- updated_nonce_set.clone()
- }
- })
- .collect()
+ for index in response.recipients {
+ nonce_set[index] = response.nonce_set.clone();
}
- nonces[signer_index] = new_nonce;
-
if sig.is_some() {
sig_shares.push(sig);
}