Create Coordinator CLI (#59)

* Add coordinator demo (#48)

* Add test for step_3 in coordinator (#48)

* Add validation for participant selection in coordinator demo (#48)

* Add tests for validation in step_1 for coordinator (#48)

* Improve error handling in Coordinator (#48)

* Fix clippy error (#48)

* Improve usability for coordinator demo (#48)

Fix test values
Improve identifier input so it doesn't need to be in quotes
Remove unecessary text
This commit is contained in:
natalie 2023-07-20 15:13:14 +01:00 committed by GitHub
parent 2c26bf99ab
commit 58abe8d3e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 715 additions and 1 deletions

14
Cargo.lock generated
View File

@ -153,6 +153,20 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "coordinator"
version = "0.1.0"
dependencies = [
"exitcode",
"eyre",
"frost-ed25519",
"hex",
"itertools 0.11.0",
"rand",
"serde_json",
"thiserror",
]
[[package]]
name = "cpufeatures"
version = "0.2.9"

View File

@ -2,5 +2,6 @@
members = [
"participant",
"trusted-dealer",
"dkg"
"dkg",
"coordinator"
]

16
coordinator/Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
name = "coordinator"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
eyre = "0.6.8"
frost-ed25519 = { version = "0.6.0", features = ["serde"] }
hex = { version = "0.4", features = ["serde"] }
thiserror = "1.0"
rand = "0.8"
serde_json = "1.0"
itertools = "0.11.0"
exitcode = "1.1.2"

55
coordinator/README.md Normal file
View File

@ -0,0 +1,55 @@
# FROST Coordinator Demo
TODO
This will be part of a set of demos and a proof of concept application that uses the FROST libraries and reference implementation. The purpose of these demos is to:
1. identify gaps in our documentation
2. provide usage examples for developer facing documentation
3. provide reference implementations for developers wanting to use FROST in a “real world” scenario.
This demo uses the (Ed25519, SHA-512) ciphersuite. The crate can be found [here](https://crates.io/crates/frost-ed25519).
## About FROST (Flexible Round-Optimised Schnorr Threshold signatures)
Unlike signatures in a single-party setting, threshold signatures require cooperation among a threshold number of signers, each holding a share of a common private key. The security of threshold
schemes in general assume that an adversary can corrupt strictly fewer than a threshold number of participants.
[Two-Round Threshold Schnorr Signatures with FROST](https://datatracker.ietf.org/doc/draft-irtf-cfrg-frost/) presents a variant of a Flexible Round-Optimized Schnorr Threshold (FROST) signature scheme originally defined in [FROST20](https://eprint.iacr.org/2020/852.pdf). FROST reduces network overhead during threshold
signing operations while employing a novel technique to protect against forgery attacks applicable to prior Schnorr-based threshold signature constructions. This variant of FROST requires two rounds to compute a signature, and implements signing efficiency improvements described by [Schnorr21](https://eprint.iacr.org/2021/1375.pdf). Single-round signing with FROST is not implemented here.
## Status ⚠
The Coordinator Demo is a WIP
## Usage
NOTE: This is for demo purposes only and should not be used in production.
You will need to have [Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) installed.
To run:
1. Clone the repo. Run `git clone https://github.com/ZcashFoundation/frost-zcash-demo.git`
2. Run `cargo install`
3. Run `cargo run`
TODO
## Using the output
TODO
## Developer information
TODO
### Pre-commit checks
1. Run `cargo make all`
### Coverage
Test coverage checks are performed in the pipeline. This is configured here: `.github/workflows/coverage.yaml`
To run these locally:
1. Install coverage tool by running `cargo install cargo-llvm-cov`
2. Run `cargo make cov` (you may be asked if you want to install `llvm-tools-preview`, if so type `Y`)

29
coordinator/src/cli.rs Normal file
View File

@ -0,0 +1,29 @@
use std::io::{BufRead, Write};
use crate::step_1::step_1;
use crate::step_2::step_2;
use crate::step_3::step_3;
pub fn cli(
reader: &mut impl BufRead,
logger: &mut impl Write,
) -> Result<(), Box<dyn std::error::Error>> {
writeln!(logger, "\n=== STEP 1: CHOOSE PARTICIPANTS ===\n")?;
let participants_config = step_1(reader, logger)?;
writeln!(
logger,
"=== STEP 2: CHOOSE MESSAGE AND GENERATE COMMITMENT PACKAGE ===\n"
)?;
let signing_package = step_2(reader, logger, participants_config.participants.clone())?;
writeln!(logger, "=== STEP 3: BUILD GROUP SIGNATURE ===\n")?;
step_3(reader, logger, participants_config, signing_package);
writeln!(logger, "=== END ===")?;
Ok(())
}

6
coordinator/src/lib.rs Normal file
View File

@ -0,0 +1,6 @@
pub mod cli;
pub mod step_1;
mod step_2;
mod step_3;
#[cfg(test)]
mod tests;

19
coordinator/src/main.rs Executable file
View File

@ -0,0 +1,19 @@
use std::io;
use coordinator::cli::cli;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut reader = Box::new(io::stdin().lock());
let mut logger = io::stdout();
cli(&mut reader, &mut logger)?;
Ok(())
}
// Choose participants -> send message to those participants - gen message to send
// Choose message - receive commitments - build commitment list - send to participants
// Receive signature shares - aggregate - send to participants. signautre shares must be validated first
// Verify group signature

169
coordinator/src/step_1.rs Executable file
View File

@ -0,0 +1,169 @@
use frost_ed25519 as frost;
use frost::{keys::PublicKeyPackage, Error, Identifier};
use eyre::eyre;
use std::io::{BufRead, Write};
pub struct ParticipantsConfig {
pub participants: Vec<Identifier>,
pub pub_key_package: PublicKeyPackage,
}
// TODO: needs to include the coordinator's keys!
pub fn step_1(
reader: &mut impl BufRead,
logger: &mut dyn Write,
) -> Result<ParticipantsConfig, Error> {
let participants = choose_participants(reader, logger)?;
print_participants(logger, &participants.participants);
Ok(participants)
}
fn validate(
id: Identifier,
key_package: PublicKeyPackage,
id_list: &[Identifier],
) -> Result<(), Error> {
if !key_package.signer_pubkeys().contains_key(&id) {
return Err(Error::MalformedIdentifier);
}; // TODO: Error is actually that the identifier does not exist
if id_list.contains(&id) {
return Err(Error::DuplicatedIdentifier);
};
Ok(())
}
// TODO: validate min num of participants
pub fn read_identifier(input: &mut impl BufRead) -> Result<Identifier, Box<dyn std::error::Error>> {
let mut identifier_input = String::new();
input.read_line(&mut identifier_input)?;
let bytes = hex::decode(identifier_input.trim())?;
let serialization = bytes.try_into().map_err(|_| eyre!("Invalid Identifier"))?;
let identifier = Identifier::deserialize(&serialization)?;
Ok(identifier)
}
// Input required:
// 1. public key package
// 2. number of participants
// 3. identifiers for all participants
fn choose_participants(
input: &mut impl BufRead,
logger: &mut dyn Write,
) -> Result<ParticipantsConfig, Error> {
writeln!(logger, "Paste the JSON public key package: ").unwrap();
let mut key_package = String::new();
input.read_line(&mut key_package).unwrap();
let pub_key_package: PublicKeyPackage = serde_json::from_str(&key_package).unwrap();
writeln!(logger, "The number of participants: ").unwrap();
let mut participants = String::new();
input.read_line(&mut participants).unwrap();
let num_of_participants = participants.trim().parse::<u16>().unwrap();
let mut participants = Vec::new();
for i in 1..=num_of_participants {
let package = pub_key_package.clone();
writeln!(logger, "Identifier for participant {:?} (hex encoded):", i).unwrap();
let id_value = read_identifier(input).unwrap();
validate(id_value, package, &participants)?;
participants.push(id_value)
}
Ok(ParticipantsConfig {
participants,
pub_key_package,
})
}
pub fn print_participants(logger: &mut dyn Write, participants: &Vec<Identifier>) {
writeln!(logger, "Selected participants:",).unwrap();
for p in participants {
writeln!(logger, "{}", serde_json::to_string(p).unwrap()).unwrap();
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use frost::{
keys::{PublicKeyPackage, VerifyingShare},
Error, Identifier, VerifyingKey,
};
use frost_ed25519 as frost;
use hex::FromHex;
use crate::step_1::validate;
const PUBLIC_KEY_1: &str = "fc2c9b8e335c132d9ebe0403c9317aac480bbbf8cbdb1bc3730bb68eb60dadf9";
const PUBLIC_KEY_2: &str = "2cff4148a2f965801fb1f25f1d2a4e5df2f75b3a57cd06f30471c2c774419a41";
const GROUP_PUBLIC_KEY: &str =
"15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673";
fn build_pub_key_package() -> PublicKeyPackage {
let id_1 = Identifier::try_from(1).unwrap();
let id_2 = Identifier::try_from(2).unwrap();
let mut signer_pubkeys = HashMap::new();
signer_pubkeys.insert(
id_1,
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY_1).unwrap()).unwrap(),
);
signer_pubkeys.insert(
id_2,
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY_2).unwrap()).unwrap(),
);
let group_public = VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap();
PublicKeyPackage::new(signer_pubkeys, group_public)
}
#[test]
fn check_validate() {
let id_1 = Identifier::try_from(1).unwrap();
let id_2 = Identifier::try_from(2).unwrap();
let id_list = [id_1];
let key_package = build_pub_key_package();
let validated = validate(id_2, key_package, &id_list);
assert!(validated.is_ok())
}
#[test]
fn check_validation_errors_for_missing_identifiers() {
let id_1 = Identifier::try_from(1).unwrap();
let id_2 = Identifier::try_from(2).unwrap();
let id_3 = Identifier::try_from(3).unwrap();
let id_list = [id_1, id_2];
let key_package = build_pub_key_package();
let validated = validate(id_3, key_package, &id_list);
assert!(validated.is_err());
assert!(validated == Err(Error::MalformedIdentifier))
}
#[test]
fn check_validation_errors_for_duplicate_identifiers() {
let id_1 = Identifier::try_from(1).unwrap();
let id_2 = Identifier::try_from(2).unwrap();
let id_list = [id_1, id_2];
let key_package = build_pub_key_package();
let validated = validate(id_1, key_package, &id_list);
assert!(validated.is_err());
assert!(validated == Err(Error::DuplicatedIdentifier))
}
}

69
coordinator/src/step_2.rs Normal file
View File

@ -0,0 +1,69 @@
use frost::{round1::SigningCommitments, Identifier, SigningPackage};
use frost_ed25519 as frost;
use std::{
collections::BTreeMap,
io::{BufRead, Write},
};
#[derive(Debug, PartialEq, Clone)]
pub struct CommitmentsConfig {
pub message: Vec<u8>,
pub signer_commitments: BTreeMap<Identifier, SigningCommitments>,
}
pub fn step_2(
input: &mut impl BufRead,
logger: &mut dyn Write,
participants: Vec<Identifier>,
) -> Result<SigningPackage, Box<dyn std::error::Error>> {
let signing_package = request_inputs_commitments(input, logger, participants)?;
print_commitments(logger, &signing_package);
Ok(signing_package)
}
// Input required:
// 1. message
// 2. number of signers
// 3. commitments for all signers
fn request_inputs_commitments(
input: &mut impl BufRead,
logger: &mut dyn Write,
participants: Vec<Identifier>,
) -> Result<SigningPackage, Box<dyn std::error::Error>> {
writeln!(logger, "The message to be signed (hex encoded)")?;
let mut msg = String::new();
input.read_line(&mut msg)?;
let message = hex::decode(msg.trim())?;
let mut commitments_list: BTreeMap<Identifier, SigningCommitments> = BTreeMap::new();
for p in participants {
writeln!(
logger,
"Please enter JSON encoded commitments for participant {:#?}:",
p
)?; // TODO: improve printing
let mut commitments_input = String::new();
input.read_line(&mut commitments_input)?;
let commitments = serde_json::from_str(&commitments_input)?;
commitments_list.insert(p, commitments);
}
let signing_package = SigningPackage::new(commitments_list, &message);
Ok(signing_package)
}
fn print_commitments(logger: &mut dyn Write, signing_package: &SigningPackage) {
writeln!(
logger,
"Signing Package: {}",
serde_json::to_string(&signing_package).unwrap()
)
.unwrap();
}

65
coordinator/src/step_3.rs Normal file
View File

@ -0,0 +1,65 @@
use frost::{round2::SignatureShare, Identifier, Signature, SigningPackage};
use frost_ed25519 as frost;
use std::{
collections::HashMap,
io::{BufRead, Write},
};
use crate::step_1::ParticipantsConfig;
pub fn step_3(
input: &mut impl BufRead,
logger: &mut dyn Write,
participants: ParticipantsConfig,
signing_package: SigningPackage,
) {
let group_signature =
request_inputs_signature_shares(input, logger, participants, signing_package).unwrap();
print_signature(logger, group_signature);
}
// Input required:
// 1. number of signers (TODO: maybe pass this in?)
// 2. signatures for all signers
fn request_inputs_signature_shares(
input: &mut impl BufRead,
logger: &mut dyn Write,
participants: ParticipantsConfig,
signing_package: SigningPackage,
) -> Result<Signature, Box<dyn std::error::Error>> {
let mut signatures_list: HashMap<Identifier, SignatureShare> = HashMap::new();
for p in participants.participants {
writeln!(
logger,
"Please enter JSON encoded signatures for participant {:?}:",
p
)
.unwrap();
let mut signature_input = String::new();
input.read_line(&mut signature_input)?;
let signatures = serde_json::from_str(&signature_input)?;
signatures_list.insert(p, signatures);
}
let group_signature = frost::aggregate(
&signing_package,
&signatures_list,
&participants.pub_key_package,
)
.unwrap();
Ok(group_signature)
}
fn print_signature(logger: &mut dyn Write, group_signature: Signature) {
writeln!(
logger,
"Group signature: {}",
serde_json::to_string(&group_signature).unwrap()
)
.unwrap();
}

1
coordinator/src/tests.rs Normal file
View File

@ -0,0 +1 @@
mod steps;

View File

@ -0,0 +1,107 @@
// Test values from https://github.com/ZcashFoundation/frost/blob/main/frost-ed25519/tests/helpers/vectors.json
// // Input required:
// // 1. public key package
// // 2. number of signparticipantsers
// // 3. identifiers for all signers
// #[test]
// fn check_step_1() {
// }
// // Input required:
// // 1. message
// // 2. number of signers
// // 3. commitments for all signers
// #[test]
// fn check_step_2() {
// }
use crate::{step_1::ParticipantsConfig, step_3::step_3};
use frost::{
keys::{PublicKeyPackage, VerifyingShare},
round1::{NonceCommitment, SigningCommitments},
Identifier, SigningPackage, VerifyingKey,
};
use frost_ed25519 as frost;
use hex::FromHex;
use std::{
collections::{BTreeMap, HashMap},
io::BufWriter,
};
// // Input required:
// // 1. number of signers (TODO: maybe pass this in?)
// // 2. signatures for all signers
#[test]
fn check_step_3() {
let mut buf = BufWriter::new(Vec::new());
let id_1 = Identifier::try_from(1).unwrap();
let id_3 = Identifier::try_from(3).unwrap();
const PUBLIC_KEY_1: &str = "fc2c9b8e335c132d9ebe0403c9317aac480bbbf8cbdb1bc3730bb68eb60dadf9";
const PUBLIC_KEY_3: &str = "2cff4148a2f965801fb1f25f1d2a4e5df2f75b3a57cd06f30471c2c774419a41";
const GROUP_PUBLIC_KEY: &str =
"15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673";
let mut signer_pubkeys = HashMap::new();
signer_pubkeys.insert(
id_1,
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY_1).unwrap()).unwrap(),
);
signer_pubkeys.insert(
id_3,
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY_3).unwrap()).unwrap(),
);
let group_public = VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap();
let signature_1 = "{\"share\":\"b97409beff18861f0959530db091a64b812e3fefaa87e1e3d2c039f11d96cc09\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}";
let signature_3 = "{\"share\":\"9816a14e7cdecfcb240976f564cf98c5640e596b6ddf270379efbef4e9f7db0b\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}";
let input = format!("{}\n{}\n", signature_1, signature_3);
let mut valid_input = input.as_bytes();
let participants_config = ParticipantsConfig {
participants: vec![id_1, id_3],
pub_key_package: PublicKeyPackage::new(signer_pubkeys, group_public),
};
const HIDING_COMMITMENT_1: &str =
"5078f5c6d679654bb88a8887242d49cc21a553ed26caed4d52570c6656fb9b92";
const BINDING_COMMITMENT_1: &str =
"936b660d3008d8298b0a7220a327a0813ffedd9d07604bdc73d7cffef63c0da0";
const HIDING_COMMITMENT_3: &str =
"91c2469b501fe5af8493f9ae77c8f57999460af317f2d9f2d4378ae0e665860e";
const BINDING_COMMITMENT_3: &str =
"c225618accff2266a45d87dc3219b04c774ca26c8629c4fa483e7e87da820007";
let signer_commitments_1 = SigningCommitments::new(
NonceCommitment::deserialize(<[u8; 32]>::from_hex(HIDING_COMMITMENT_1).unwrap()).unwrap(),
NonceCommitment::deserialize(<[u8; 32]>::from_hex(BINDING_COMMITMENT_1).unwrap()).unwrap(),
);
let signer_commitments_3 = SigningCommitments::new(
NonceCommitment::deserialize(<[u8; 32]>::from_hex(HIDING_COMMITMENT_3).unwrap()).unwrap(),
NonceCommitment::deserialize(<[u8; 32]>::from_hex(BINDING_COMMITMENT_3).unwrap()).unwrap(),
);
let mut signing_commitments = BTreeMap::new();
signing_commitments.insert(id_1, signer_commitments_1);
signing_commitments.insert(id_3, signer_commitments_3);
let signing_package = SigningPackage::new(signing_commitments, b"test");
step_3(
&mut valid_input,
&mut buf,
participants_config,
signing_package,
);
let expected = "Please enter JSON encoded signatures for participant Identifier(\"0100000000000000000000000000000000000000000000000000000000000000\"):\nPlease enter JSON encoded signatures for participant Identifier(\"0300000000000000000000000000000000000000000000000000000000000000\"):\nGroup signature: \"72c948a63797c693e8e978fdb703a1f5a7590472a539da13b71dd6c2b8c1b2a664b7b4af6194439357c5d15f366760fce53c985a186709e74bb0f8e5078ea805\"\n";
let (_, res) = &buf.into_parts();
let actual = hex::encode(res.as_ref().unwrap());
assert_eq!(hex::encode(expected), actual)
}

View File

@ -0,0 +1,65 @@
# Helper values for manual testing
Public key package:
```
{"signer_pubkeys":{"0100000000000000000000000000000000000000000000000000000000000000":"fc2c9b8e335c132d9ebe0403c9317aac480bbbf8cbdb1bc3730bb68eb60dadf9", "0300000000000000000000000000000000000000000000000000000000000000":"2cff4148a2f965801fb1f25f1d2a4e5df2f75b3a57cd06f30471c2c774419a41", "0200000000000000000000000000000000000000000000000000000000000000":"f7c3031debffbaf121022409d057e6e1034a532636301d12e26beddff58d05c7"}, "group_public":"15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673", "ciphersuite":"FROST(Ed25519, SHA-512)"}
```
num of participants:
```
2
```
Identifier for participant 1:
```
0100000000000000000000000000000000000000000000000000000000000000
```
Identifier for participant 3:
```
0300000000000000000000000000000000000000000000000000000000000000
```
Message to be signed:
```
74657374
```
Commitment for Identifier 1:
```
{"hiding": "5078f5c6d679654bb88a8887242d49cc21a553ed26caed4d52570c6656fb9b92", "binding": "936b660d3008d8298b0a7220a327a0813ffedd9d07604bdc73d7cffef63c0da0", "ciphersuite":"FROST(Ed25519, SHA-512)" }
```
Commitment for Identifier 3:
```
{"hiding":"91c2469b501fe5af8493f9ae77c8f57999460af317f2d9f2d4378ae0e665860e","binding":"c225618accff2266a45d87dc3219b04c774ca26c8629c4fa483e7e87da820007","ciphersuite":"FROST(Ed25519, SHA-512)"}
```
Signing package (expected):
```
{"signing_commitments":{"0100000000000000000000000000000000000000000000000000000000000000":{"hiding":"5078f5c6d679654bb88a8887242d49cc21a553ed26caed4d52570c6656fb9b92","binding":"936b660d3008d8298b0a7220a327a0813ffedd9d07604bdc73d7cffef63c0da0","ciphersuite":"FROST(Ed25519, SHA-512)"},"0300000000000000000000000000000000000000000000000000000000000000":{"hiding":"91c2469b501fe5af8493f9ae77c8f57999460af317f2d9f2d4378ae0e665860e","binding":"c225618accff2266a45d87dc3219b04c774ca26c8629c4fa483e7e87da820007","ciphersuite":"FROST(Ed25519, SHA-512)"}},"message":"74657374","ciphersuite":"FROST(Ed25519, SHA-512)"}
```
Signature share for ID 1:
```
{"share":"b97409beff18861f0959530db091a64b812e3fefaa87e1e3d2c039f11d96cc09","ciphersuite":"FROST(Ed25519, SHA-512)"}
```
Signature share for ID 2:
```
{"share":"9816a14e7cdecfcb240976f564cf98c5640e596b6ddf270379efbef4e9f7db0b","ciphersuite":"FROST(Ed25519, SHA-512)"}
```
Group signature share (expected):
```
"72c948a63797c693e8e978fdb703a1f5a7590472a539da13b71dd6c2b8c1b2a664b7b4af6194439357c5d15f366760fce53c985a186709e74bb0f8e5078ea805"
```

2
coordinator/tests.rs Normal file
View File

@ -0,0 +1,2 @@
#[cfg(test)]
mod integration_tests;

View File

@ -0,0 +1,96 @@
// use frost::keys::{IdentifierList, KeyPackage, SecretShare};
// use frost::round1::{SigningCommitments, SigningNonces};
// use frost::round2::SignatureShare;
// use frost::{Identifier, SigningPackage};
// use frost_ed25519 as frost;
// use rand::rngs::ThreadRng;
// use rand::thread_rng;
// use std::collections::{BTreeMap, HashMap};
// // #[test]
// fn check_keygen_with_dealer() {
// let mut rng = thread_rng();
// let (shares, pubkeys) =
// frost::keys::generate_with_dealer(3, 2, IdentifierList::Default, &mut rng).unwrap();
// let key_packages = key_package(&shares);
// let (nonces, commitments) = round_1(2, &mut rng, &key_packages);
// let message = "i am a message".as_bytes();
// let signing_packages = step_2()
// let signature_shares = round_2(nonces, &key_packages, signing_packages);
// let signing_packages = step_2()
// // Coordinator
// let config = Config {
// message,
// signing_package,
// signature_shares,
// pubkeys,
// };
// // let group_signature = aggregate_and_verify(config);
// // let expected = aggregate(
// // config.signing_package,
// // config.signature_shares,
// // config.pubkeys,
// // )
// // .unwrap();
// // assert!(group_signature.is_ok());
// // assert!(group_signature == expected)
// }
// fn key_package(shares: &HashMap<Identifier, SecretShare>) -> HashMap<Identifier, KeyPackage> {
// let mut key_packages: HashMap<_, _> = HashMap::new();
// for (identifier, secret_share) in shares {
// let key_package = frost::keys::KeyPackage::try_from(secret_share.clone()).unwrap();
// key_packages.insert(*identifier, key_package);
// }
// key_packages
// }
// fn round_1(
// min_signers: u16,
// mut rng: &mut ThreadRng,
// key_packages: &HashMap<Identifier, KeyPackage>,
// ) -> (
// HashMap<Identifier, SigningNonces>,
// BTreeMap<Identifier, SigningCommitments>,
// ) {
// // Participant Round 1
// let mut nonces_map = HashMap::new();
// let mut commitments_map = BTreeMap::new();
// for participant_index in 1..(min_signers + 1) {
// let participant_identifier = participant_index.try_into().expect("should be nonzero");
// let key_package = &key_packages[&participant_identifier];
// let (nonces, commitments) = frost::round1::commit(key_package.secret_share(), &mut rng);
// nonces_map.insert(participant_identifier, nonces);
// commitments_map.insert(participant_identifier, commitments);
// }
// (nonces_map, commitments_map)
// }
// fn round_2(
// nonces_map: HashMap<Identifier, SigningNonces>,
// key_packages: &HashMap<Identifier, KeyPackage>,
// signing_package: SigningPackage,
// ) -> HashMap<Identifier, SignatureShare> {
// let mut signature_shares = HashMap::new();
// for participant_identifier in nonces_map.keys() {
// let key_package = &key_packages[participant_identifier];
// let nonces = &nonces_map[participant_identifier];
// let signature_share = frost::round2::sign(&signing_package, nonces, key_package).unwrap();
// signature_shares.insert(*participant_identifier, signature_share);
// }
// signature_shares
// }