roast

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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:
Mroastlib/src/coordinator.rs | 75+++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mroastlib/src/main.rs | 65+++++++++++++++++++++++++++++------------------------------------
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); }