roast

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

commit 317ca1c257763e1307b3cfaab47d07c96cd41ab3
Author: nickfarrow <nick@nickfarrow.com>
Date:   Tue, 27 Sep 2022 18:06:32 +1000

inital roast attempt

Diffstat:
A.gitignore | 1+
ACargo.lock | 347+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ACargo.toml | 15+++++++++++++++
Aroast.md | 39+++++++++++++++++++++++++++++++++++++++
Asrc/main.rs | 414+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 816 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock @@ -0,0 +1,347 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clightningrpc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ae583d1efb5a0cb21d77ef53f872f104c872b5e05cc150b277d15afe13e974" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "itoa" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "libc" +version = "0.2.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rng" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa6bba2ae9b3232e194e86d9a407e28c5d02fdfb85ea0e7e2e60f4d1e78aff2" +dependencies = [ + "rand 0.3.23", +] + +[[package]] +name = "roast" +version = "0.1.0" +dependencies = [ + "clightningrpc", + "rand 0.8.5", + "rng", + "schnorr_fun", + "secp256kfun", + "sha2", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "schnorr_fun" +version = "0.7.1" +dependencies = [ + "secp256kfun", +] + +[[package]] +name = "secp256kfun" +version = "0.7.1" +dependencies = [ + "digest", + "rand_core 0.6.4", + "serde", + "subtle-ng", +] + +[[package]] +name = "serde" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[package]] +name = "syn" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "roast" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +schnorr_fun = { path = "../secp256kfun/schnorr_fun" } +secp256kfun = { path = "../secp256kfun/secp256kfun" } +rand = "0.8.5" +sha2 = "0.10" +rng = "0.1.0" +clightningrpc = "0.2.0" +\ No newline at end of file diff --git a/roast.md b/roast.md @@ -0,0 +1,38 @@ +Roast is a simple wrapper that turns a given threshold signature scheme into a scheme with a robust and asynchronous signing protocol, as long as the underlying signing protocol is semi-interactive (i.e. has one preprocessing round and one actual signing round), proviceds identifiable aborts, and is unforgable under concurrent signing sessions. + + +Robustness is the guarentee that t honest signers are able to obtain a valid signature even in the presence of other malicious signers who try to disrupt the protocol. + + +FROST provides identifiable aborts (IA): if signing session fails, then honest signers can identify at least one malicious signer responsible for the failure. + +We cant run every combination of signers n choose t, too computationally expensive -> ROAST tackles this problem. +>an algorithmic approach to choosing signer sets based on past behaviour? + + + + +Security of Threshold Signatures + +Identifiable aborts: + - Ensures that ShareVal reliably identifies disruptive signers who send wrong shares. The IA-CMA (identifiable abort, chosen message attack) game: A controls all but one signer and can ask the remaining honest signer to take part in arbitrary number of concurrent sign sessions. Wins if the malicious signers all submit presignature or signature shares that somehow pass validation but lead to an output of an invalid signature (break of accountability). Or A wins if the honest signer outputs a presignatures and signature shares that will not pass validation. + + +Unforgability: a threshold signature scheme is existentially unforgable under CMA and concurrent sessions if no adversary A which controls t-1 signers during keygen and signing and can ask the remaining n-t+1 honest signers to take part in arbitrarily many concurrent signing sessions on messages of its choice, + +-> ie.e for every honest signer, A has oracles simulating PreRound(PK) and SignRound(sk_i, PK, State_i_sid) on an already preprocessed but unfinished session sid of its choice.can + +can produce a valid signature on a message that was never used in a signing session and A never asked in any query round. + +FROST3 -> PreAgg (nonce agg) -> Aggregate two presignature products D=prod(d_i), and E=prod(e_i) for i in T. Whereas FROST2 the aggregated presignature is not really aggregated, just the set {(D_i, E_i) for i in T}. The SignRound algorightm takes care of computing the products, as before. Other FROST versions include 2-BTZ and 2-CKM. + +FROSTLAND +A majority of t of 15 council members is needed to sign a bill for it to pass. + +Each counci member has its own twatermark and a bill is only vaild if it carries the watermarks of all signers (and no others). + +Find a majority of council members, use thier watermarks to create the paper, then collect their signatures. However if one of them fail to sign at the final step, then the process talls. It is not possible to ask anyone else since the watermark on the page corresponds to the disruptive signer. So we must start the signing process from scratch. + + + +The signing process is +\ No newline at end of file diff --git a/src/main.rs b/src/main.rs @@ -0,0 +1,414 @@ +use std::{ + collections::{HashMap, HashSet}, + sync::{Arc, Mutex}, +}; + +use secp256kfun::{ + digest::typenum::U32, + marker::{Public, Zero}, + rand_core::RngCore, + Scalar, +}; + +use schnorr_fun::{ + frost::{Frost, PointPoly, ScalarPoly, XOnlyFrostKey}, + musig::{Nonce, NonceKeyPair}, + nonce::Deterministic, + Message, Signature, +}; +use sha2::Digest; + +use schnorr_fun::Schnorr; +use sha2::Sha256; + +struct Roast<'a, H, NG> { + frost: Frost<H, NG>, + frost_key: XOnlyFrostKey, + state: Arc<Mutex<RoastState<'a>>>, +} + +struct RoastState<'a> { + message: Message<'a, Public>, + responsive_signers: HashSet<usize>, + malicious_signers: HashSet<usize>, + latest_nonces: HashMap<usize, Nonce>, + sessions: HashMap<usize, Arc<Mutex<RoastSession>>>, + session_counter: usize, +} + +struct RoastSession { + signers: HashSet<usize>, + nonces: Vec<(usize, Nonce)>, + sig_shares: Vec<Scalar<Public, Zero>>, +} + +impl<'a, H: Digest + Clone + Digest<OutputSize = U32>, NG> Roast<'a, H, NG> { + pub fn new( + frost: Frost<H, NG>, + frost_key: XOnlyFrostKey, + message: Message<'a, Public>, + ) -> Self { + return Self { + frost, + frost_key, + state: Arc::new(Mutex::new(RoastState { + message, + responsive_signers: HashSet::new(), + malicious_signers: HashSet::new(), + latest_nonces: HashMap::new(), + sessions: HashMap::new(), + session_counter: 0, + })), + }; + } + + pub fn mark_malicious(&self, index: &usize) { + let mut roast_state = self.state.lock().expect("got lock"); + roast_state.malicious_signers.insert(*index); + if roast_state.malicious_signers.len() >= self.frost_key.threshold() { + panic!("not enough singers left to continue!"); + } + } + + pub fn create_signature( + self, + secret_share: &Scalar, + secret_nonce: NonceKeyPair, + my_index: usize, + nonces: Vec<(usize, Nonce)>, + message: Message<'_>, + ) -> Scalar<Public, Zero> { + let session = self + .frost + .start_sign_session(&self.frost_key, nonces, message); + self.frost.sign( + &self.frost_key, + &session, + my_index, + secret_share, + secret_nonce, + ) + } + + pub async fn recieve_signature( + &self, + index: usize, + signature_share: Scalar<Public, Zero>, + new_nonce: Nonce, + ) -> Option<Signature> { + let mut roast_state = self.state.lock().expect("got lock"); + + // if index is malicious then return + if roast_state.malicious_signers.contains(&index) { + return None; + } + + // if this was an unsolicited reply mark malicious + if roast_state.responsive_signers.contains(&index) { + self.mark_malicious(&index); + return None; + } + + // If this is not the inital message from S_i + if roast_state.sessions.contains_key(&index) { + let mut roast_session = roast_state + .sessions + .get(&index) + .unwrap() + .lock() + .expect("got lock"); + + let session = self.frost.start_sign_session( + &self.frost_key, + roast_session.nonces.clone(), + roast_state.message, + ); + + if !self + .frost + .verify_signature_share(&self.frost_key, &session, index, signature_share) + { + self.mark_malicious(&index); + return None; + } + + // Store valid signature + roast_session.sig_shares.push(signature_share); + + // if we have t-of-n, combine! + if roast_session.sig_shares.len() >= self.frost_key.threshold() { + let combined_sig = self.frost.combine_signature_shares( + &self.frost_key, + &session, + roast_session.sig_shares.clone(), + ); + // return combined signature + return Some(combined_sig); + } + } + + // Store the recieved presignature shares + roast_state.latest_nonces.insert(index, new_nonce); + + // Mark S_i as responsive + roast_state.responsive_signers.insert(index); + + // if we now have t responsive signers: + if roast_state.responsive_signers.len() >= self.frost_key.threshold() { + roast_state.session_counter += 1; + // build the presignature (aggregate the nonces). + let r_signers = roast_state.responsive_signers.clone(); + // we're not actually aggregating any nonces in this core yet since this will + // require changes to frost.rs + let nonces: Vec<_> = r_signers + .iter() + .cloned() + .map(|i| { + ( + i, + *roast_state + .latest_nonces + .get(&i) + .expect("has submitted nonce"), + ) + }) + .collect(); + + for i in r_signers.clone() { + // send agg nonce to signers (rho, R) + roast_state.sessions.insert( + i, + Arc::new(Mutex::new(RoastSession { + signers: r_signers.clone(), + nonces: nonces.clone(), + sig_shares: vec![], + })), + ); + // SEND NONCES AND R + // (if we are running ourselves then we sign too after communicating!) + } + } + + // Return None if we get to here? + // Better API would be return the number of remaining signatures or th remaining signature if complete. + // Non complex RecieveSigResponse Result + None + } +} + +fn main() { + // Do frost keygen for 9-of-15 + let threshold: usize = 9; + let n_parties: usize = 15; + + let frost = Frost::new(Schnorr::<Sha256, Deterministic<Sha256>>::new( + Deterministic::<Sha256>::default(), + )); + dbg!(threshold, n_parties); + assert!(threshold <= n_parties); + + // create some scalar polynomial for each party + let mut scalar_polys = vec![]; + for i in 1..=n_parties { + println!("Creating scalar poly {}", i); + let scalar_poly = (1..=threshold) + .map(|_| { + let mut rng: rand::rngs::StdRng = rand::SeedableRng::from_entropy(); + Scalar::from(rng.next_u32()) + .non_zero() + .expect("computationally unreachable") + }) + .collect(); + scalar_polys.push(ScalarPoly::new(scalar_poly)); + } + let point_polys: Vec<PointPoly> = scalar_polys.iter().map(|sp| sp.to_point_poly()).collect(); + + let keygen = frost.new_keygen(point_polys).unwrap(); + + let mut proofs_of_possession = vec![]; + let mut shares_vec = vec![]; + for (i, sp) in scalar_polys.into_iter().enumerate() { + println!("calculating shares and pop {}", i); + let (shares, pop) = frost.create_shares(&keygen, sp); + proofs_of_possession.push(pop); + shares_vec.push(shares); + } + println!("Calculated shares and pops"); + + // collect the recieved shares for each party + let mut recieved_shares: Vec<Vec<_>> = vec![]; + for party_index in 0..n_parties { + println!("Collecting shares for {}", party_index); + recieved_shares.push(vec![]); + for share_index in 0..n_parties { + recieved_shares[party_index].push(shares_vec[share_index][party_index].clone()); + } + } + + println!("{:?}", recieved_shares); + + // finish keygen for each party + let (secret_shares, frost_keys): (Vec<Scalar>, Vec<XOnlyFrostKey>) = (0..n_parties) + .map(|i| { + println!("Finishing keygen for participant {}", i); + std::thread::sleep(std::time::Duration::from_secs(1)); + let (secret_share, frost_key) = frost + .finish_keygen( + keygen.clone(), + i, + recieved_shares[i].clone(), + proofs_of_possession.clone(), + ) + .expect("collected shares"); + println!("got secret share"); + let xonly_frost_key = frost_key.into_xonly_key(); + (secret_share, xonly_frost_key) + }) + .unzip(); + println!("Finished keygen!"); + + // Now time for ROAST + let message = Message::plain("test", b"test"); + let roast1 = Roast::new(frost.clone(), frost_keys[0].clone(), message); + let roast2 = Roast::new(frost.clone(), frost_keys[1].clone(), message); + + let verification_shares_bytes: Vec<_> = frost_keys[0] + .verification_shares() + .map(|share| share.to_bytes()) + .collect(); + + let sid = [ + frost_keys[0].public_key().to_xonly_bytes().as_slice(), + verification_shares_bytes.concat().as_slice(), + b"frost-prop-test".as_slice(), + ] + .concat(); + + let nonces: Vec<NonceKeyPair> = (0..n_parties) + .map(|i| { + let nonce = frost.gen_nonce( + &secret_shares[i], + &sid, + Some(frost_keys[i].public_key().normalize()), + None, + ); + + nonce + }) + .collect(); + + let pub_nonces: Vec<_> = nonces + .iter() + .enumerate() + .map(|(i, nonce)| (i, nonce.public())) + .collect(); + + let sig1 = roast1.create_signature( + &secret_shares[0], + nonces[0].clone(), + 0, + pub_nonces.clone(), + message, + ); + + let next_nonce = frost.gen_nonce( + &secret_shares[0], + &sid, + Some(frost_keys[0].public_key().normalize()), + None, + ); + roast1.recieve_signature(0, sig1, next_nonce).await; + // let sig2 = + // roast2.create_signature(&secret_shares[1], nonces[1].clone(), 1, pub_nonces, message); +} +// println!("selecting signers..."); + +// // use a boolean mask for which t participants are signers +// let mut signer_mask = vec![true; threshold]; +// signer_mask.append(&mut vec![false; n_parties - threshold]); +// // shuffle the mask for random signers + +// let signer_indexes: Vec<_> = signer_mask +// .iter() +// .enumerate() +// .filter(|(_, is_signer)| **is_signer) +// .map(|(i, _)| i) +// .collect(); + +// println!("Preparing for signing session..."); + +// let verification_shares_bytes: Vec<_> = frost_keys[signer_indexes[0]] +// .verification_shares() +// .map(|share| share.to_bytes()) +// .collect(); + +// let sid = [ +// frost_keys[signer_indexes[0]] +// .public_key() +// .to_xonly_bytes() +// .as_slice(), +// verification_shares_bytes.concat().as_slice(), +// b"frost-prop-test".as_slice(), +// ] +// .concat(); +// let nonces: Vec<NonceKeyPair> = signer_indexes +// .iter() +// .map(|i| { +// frost.gen_nonce( +// &secret_shares[*i], +// &[sid.as_slice(), [*i as u8].as_slice()].concat(), +// Some(frost_keys[signer_indexes[0]].public_key().normalize()), +// None, +// ) +// }) +// .collect(); + +// let mut recieved_nonces: Vec<_> = vec![]; +// for (i, nonce) in signer_indexes.iter().zip(nonces.clone()) { +// recieved_nonces.push((*i, nonce.public())); +// } +// println!("Recieved nonces.."); + +// // Create Frost signing session +// let signing_session = frost.start_sign_session( +// &frost_keys[signer_indexes[0]], +// recieved_nonces.clone(), +// Message::plain("test", b"test"), +// ); + +// let mut signatures = vec![]; +// for i in 0..signer_indexes.len() { +// println!("Signing for participant {}", signer_indexes[i]); +// let signer_index = signer_indexes[i]; +// let session = frost.start_sign_session( +// &frost_keys[signer_index], +// recieved_nonces.clone(), +// Message::plain("test", b"test"), +// ); +// let sig = frost.sign( +// &frost_keys[signer_index], +// &session, +// signer_index, +// &secret_shares[signer_index], +// nonces[i].clone(), +// ); +// assert!(frost.verify_signature_share( +// &frost_keys[signer_index], +// &session, +// signer_index, +// sig +// )); +// signatures.push(sig); +// } +// let combined_sig = frost.combine_signature_shares( +// &frost_keys[signer_indexes[0]], +// &signing_session, +// signatures, +// ); + +// assert!(frost.schnorr.verify( +// &frost_keys[signer_indexes[0]].public_key(), +// Message::<Public>::plain("test", b"test"), +// &combined_sig +// )); +// }