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 }