roast

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

main.rs (6317B)


      1 fn main() {}
      2 
      3 #[cfg(test)]
      4 mod test {
      5     use roast::coordinator;
      6     use roast::frost;
      7     use roast::signer;
      8     use schnorr_fun::frost as secp_frost;
      9     use schnorr_fun::musig::Nonce;
     10     use schnorr_fun::nonce::Deterministic;
     11     use schnorr_fun::Message;
     12     use sha2::Sha256;
     13 
     14     use secp256kfun::proptest::{
     15         proptest,
     16         strategy::{Just, Strategy},
     17     };
     18 
     19     #[test]
     20     fn test_2_of_3_sequential() {
     21         let frost = secp_frost::Frost::<Sha256, Deterministic<Sha256>>::default();
     22         let (secret_shares, frost_keys) = frost::frost_keygen(2, 3);
     23 
     24         let message = Message::plain("test", b"test");
     25         let roast = coordinator::Coordinator::new(frost.clone(), frost_keys[0].clone(), message);
     26 
     27         // Create each signer session and create an initial nonce
     28         let (mut signer1, nonce1) = signer::RoastSigner::new(
     29             frost.clone(),
     30             frost_keys[0].clone(),
     31             0,
     32             secret_shares[0].clone(),
     33             [].as_slice(),
     34             message,
     35         );
     36         let (mut signer2, nonce2) = signer::RoastSigner::new(
     37             frost,
     38             frost_keys[1].clone(),
     39             1,
     40             secret_shares[1].clone(),
     41             [1].as_slice(),
     42             message,
     43         );
     44 
     45         // Begin with each signer sending a nonce to ROAST, marking these signers as responsive.
     46         let response = roast.receive(0, None, nonce1);
     47         assert!(response.nonce_set.is_none());
     48         assert!(response.combined_signature.is_none());
     49 
     50         let response2 = roast.receive(1, None, nonce2);
     51         assert!(response2.nonce_set.is_some());
     52 
     53         // Once ROAST receives the threshold number of nonces, it responds to the group of
     54         // responsive signers with a nonce set to the group of responsive signers.
     55         assert!(response2.recipients.contains(&0) && response2.recipients.contains(&1));
     56         let sign_session_nonces = response2.nonce_set.expect("roast responded with nonces");
     57 
     58         // The signer signs using this the nonces for this sign session,
     59         // and responds to ROAST with a signature share.
     60         let (sig_share2, nonce2) = signer2.sign(sign_session_nonces.clone());
     61         let response = roast.receive(1, Some(sig_share2), nonce2);
     62         dbg!(
     63             &response.combined_signature.is_some(),
     64             &response.nonce_set.is_some()
     65         );
     66         assert!(response.combined_signature.is_none());
     67 
     68         // ROAST also sends the nonce set to the other signer, who also signs
     69         let (sig_share1, nonce1) = signer1.sign(sign_session_nonces);
     70 
     71         let response = roast.receive(0, Some(sig_share1), nonce1);
     72         dbg!(
     73             &response.combined_signature.is_some(),
     74             &response.nonce_set.is_some()
     75         );
     76         assert!(response.combined_signature.is_some());
     77 
     78         // Once the threshold number of signature shares have been received,
     79         // ROAST combines the signature shares into the aggregate signature
     80         dbg!(response.combined_signature);
     81     }
     82 
     83     // This test works, but slowly since it goes through a few sets of responsive signers
     84     // before producing a complete signature. This is because we aren't accurately replicating
     85     // any asynchronous messages.
     86     fn t_of_n_sequential(threshold: usize, n_parties: usize) {
     87         let frost = secp_frost::Frost::<Sha256, Deterministic<Sha256>>::default();
     88         let (secret_shares, frost_keys) = frost::frost_keygen(threshold, n_parties);
     89 
     90         let message = Message::plain("test", b"test");
     91         let roast = coordinator::Coordinator::new(frost.clone(), frost_keys[0].clone(), message);
     92 
     93         // Create each signer session and create an initial nonce
     94         let (mut signers, mut nonces): (Vec<_>, Vec<_>) = frost_keys
     95             .into_iter()
     96             .zip(secret_shares)
     97             .enumerate()
     98             .map(|(i, (frost_key, secret_share))| {
     99                 signer::RoastSigner::new(
    100                     frost.clone(),
    101                     frost_key,
    102                     i,
    103                     secret_share,
    104                     [i as u8].as_slice(),
    105                     message,
    106                 )
    107             })
    108             .unzip();
    109 
    110         let mut sig_shares = vec![];
    111         let mut nonce_set: Vec<Option<Vec<(usize, Nonce)>>> = vec![None; n_parties + 1];
    112         let mut finished_signature = None;
    113         let mut n_rounds = 0;
    114 
    115         while finished_signature.is_none() {
    116             n_rounds += 1;
    117             for signer_index in 0..n_parties {
    118                 // Check to see if this signer has recieved any nonces
    119                 let (sig, new_nonce) = match nonce_set[signer_index].clone() {
    120                     // If we have nonces, sign and send sig and a new nonce
    121                     Some(signing_nonces) => {
    122                         // dbg!(&signing_nonces);
    123                         let (sig, nonce) = signers[signer_index].sign(signing_nonces);
    124                         (Some(sig), nonce)
    125                     }
    126                     // Otherwise, just create a new nonce
    127                     None => (
    128                         None,
    129                         signers[signer_index]
    130                             .new_nonce([signer_index as u8].as_slice())
    131                             .public(),
    132                     ),
    133                 };
    134                 // Send signature and our next nonce to ROAST
    135                 let response = roast.receive(signer_index, sig, new_nonce);
    136                 nonces[signer_index] = new_nonce;
    137 
    138                 if response.combined_signature.is_some() {
    139                     finished_signature = response.combined_signature;
    140                     break;
    141                 }
    142 
    143                 for index in response.recipients {
    144                     nonce_set[index] = response.nonce_set.clone();
    145                 }
    146 
    147                 if sig.is_some() {
    148                     sig_shares.push(sig);
    149                 }
    150                 // dbg!(&sig_shares);
    151             }
    152         }
    153         dbg!(&finished_signature, &n_rounds);
    154         assert!(finished_signature.is_some())
    155     }
    156 
    157     proptest! {
    158             #[test]
    159             fn roast_proptest_t_of_n(
    160                 (n_parties, threshold) in (2usize..5).prop_flat_map(|n| (Just(n), 2usize..=n))
    161             ) {
    162             t_of_n_sequential(threshold, n_parties);
    163         }
    164     }
    165 }