diff --git a/Cargo.lock b/Cargo.lock index 5f36120c..48cf303d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 2887889f..4c31801c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,6 @@ members = [ "participant", "trusted-dealer", - "dkg" + "dkg", + "coordinator" ] diff --git a/coordinator/Cargo.toml b/coordinator/Cargo.toml new file mode 100644 index 00000000..af20fa1c --- /dev/null +++ b/coordinator/Cargo.toml @@ -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" diff --git a/coordinator/README.md b/coordinator/README.md new file mode 100644 index 00000000..b3b2df76 --- /dev/null +++ b/coordinator/README.md @@ -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`) diff --git a/coordinator/src/cli.rs b/coordinator/src/cli.rs new file mode 100644 index 00000000..d7a615e0 --- /dev/null +++ b/coordinator/src/cli.rs @@ -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> { + 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(()) +} diff --git a/coordinator/src/lib.rs b/coordinator/src/lib.rs new file mode 100644 index 00000000..bbcee9f2 --- /dev/null +++ b/coordinator/src/lib.rs @@ -0,0 +1,6 @@ +pub mod cli; +pub mod step_1; +mod step_2; +mod step_3; +#[cfg(test)] +mod tests; diff --git a/coordinator/src/main.rs b/coordinator/src/main.rs new file mode 100755 index 00000000..fdb7a75a --- /dev/null +++ b/coordinator/src/main.rs @@ -0,0 +1,19 @@ +use std::io; + +use coordinator::cli::cli; + +fn main() -> Result<(), Box> { + 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 diff --git a/coordinator/src/step_1.rs b/coordinator/src/step_1.rs new file mode 100755 index 00000000..b3247125 --- /dev/null +++ b/coordinator/src/step_1.rs @@ -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, + 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 { + 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> { + 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 { + 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::().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) { + 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)) + } +} diff --git a/coordinator/src/step_2.rs b/coordinator/src/step_2.rs new file mode 100644 index 00000000..58112555 --- /dev/null +++ b/coordinator/src/step_2.rs @@ -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, + pub signer_commitments: BTreeMap, +} + +pub fn step_2( + input: &mut impl BufRead, + logger: &mut dyn Write, + participants: Vec, +) -> Result> { + 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, +) -> Result> { + 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 = 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(); +} diff --git a/coordinator/src/step_3.rs b/coordinator/src/step_3.rs new file mode 100644 index 00000000..c7ba1175 --- /dev/null +++ b/coordinator/src/step_3.rs @@ -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> { + let mut signatures_list: HashMap = 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(); +} diff --git a/coordinator/src/tests.rs b/coordinator/src/tests.rs new file mode 100644 index 00000000..3adc5bff --- /dev/null +++ b/coordinator/src/tests.rs @@ -0,0 +1 @@ +mod steps; diff --git a/coordinator/src/tests/steps.rs b/coordinator/src/tests/steps.rs new file mode 100644 index 00000000..0fd517a2 --- /dev/null +++ b/coordinator/src/tests/steps.rs @@ -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) +} diff --git a/coordinator/src/tests/values.md b/coordinator/src/tests/values.md new file mode 100644 index 00000000..6d24a8ed --- /dev/null +++ b/coordinator/src/tests/values.md @@ -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" +``` \ No newline at end of file diff --git a/coordinator/tests.rs b/coordinator/tests.rs new file mode 100644 index 00000000..633668fc --- /dev/null +++ b/coordinator/tests.rs @@ -0,0 +1,2 @@ +#[cfg(test)] +mod integration_tests; \ No newline at end of file diff --git a/coordinator/tests/integration_tests.rs b/coordinator/tests/integration_tests.rs new file mode 100644 index 00000000..675ef0b5 --- /dev/null +++ b/coordinator/tests/integration_tests.rs @@ -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) -> HashMap { +// 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, +// ) -> ( +// HashMap, +// BTreeMap, +// ) { +// // 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, +// key_packages: &HashMap, +// signing_package: SigningPackage, +// ) -> HashMap { +// 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 +// }