Improve consistency of testing across projects (#76)

* Update participant tests to use DKG format (#37)

Update Makefile to not run --all-features in tests
cli tests were not touched

* Update tests in trusted dealer (#37)

* Refactor test files structure to be consistent across projects (#37)

* Add cross project integration test (#37)

* Remove empty test files (#37)

* Remove reference to old test (#37)

* print entire identifier instead of converting back to integer

* Remove commented code (#37)

* Add signature verification step to participant demo (#78)

* Add verification step to participant demo (#56)

* Add cli test to participant (#56)

Clean up some comments and prints

---------

Co-authored-by: Conrado Gouvea <conradoplg@gmail.com>
This commit is contained in:
natalie 2023-09-27 17:27:01 +01:00 committed by GitHub
parent c6056d0e45
commit 0c528929c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 654 additions and 718 deletions

16
Cargo.lock generated
View File

@ -1142,6 +1142,22 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "tests"
version = "0.1.0"
dependencies = [
"coordinator",
"dkg",
"exitcode",
"frost-ed25519",
"hex",
"participant",
"rand",
"reddsa",
"serde_json",
"trusted-dealer",
]
[[package]]
name = "thiserror"
version = "1.0.48"

View File

@ -3,5 +3,10 @@ members = [
"participant",
"trusted-dealer",
"dkg",
"coordinator"
"coordinator", "tests"
]
default-members = ["participant",
"trusted-dealer",
"dkg",
"coordinator", "tests"]

View File

@ -5,7 +5,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
script = "cargo fmt"
[tasks.clippy-full]
script = "cargo clippy --all-features --all-targets -- -D warnings"
script = "cargo clippy --all-targets -- -D warnings"
[tasks.all]
dependencies = [

View File

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

View File

@ -35,7 +35,7 @@ pub fn step_3(
participants: ParticipantsConfig,
signing_package: SigningPackage,
#[cfg(feature = "redpallas")] randomizer: frost::round2::Randomizer,
) {
) -> Signature {
let group_signature = request_inputs_signature_shares(
input,
logger,
@ -46,6 +46,7 @@ pub fn step_3(
)
.unwrap();
print_signature(logger, group_signature);
group_signature
}
// Input required:

View File

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

View File

@ -1,96 +0,0 @@
// 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
// }

2
dkg/src/lib.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod cli;
pub mod inputs;

View File

@ -6,7 +6,7 @@ mod tests;
use std::io;
use crate::cli::cli;
use cli::cli;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut reader = Box::new(io::stdin().lock());

View File

@ -1,2 +1 @@
mod inputs_tests;
mod integration_test;
mod inputs;

View File

@ -85,7 +85,6 @@ fn return_malformed_identifier_error_if_identifier_invalid() {
let mut buf = BufWriter::new(Vec::new());
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
println!("{:?}", expected);
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::MalformedIdentifier

2
dkg/tests.rs Normal file
View File

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

View File

@ -1,3 +1,5 @@
use dkg::cli::cli;
use std::collections::HashMap;
use std::io::{BufRead, Write};
use std::thread;
@ -5,8 +7,6 @@ use std::thread;
use frost_ed25519::keys::{KeyPackage, PublicKeyPackage};
use frost_ed25519::Identifier;
use crate::cli::cli;
// Read a single line from the given reader.
fn read_line(mut reader: impl BufRead) -> Result<String, std::io::Error> {
let mut s = String::new();

View File

@ -1,71 +1,63 @@
use frost::{Error, Signature};
#[cfg(not(feature = "redpallas"))]
use frost_ed25519 as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas as frost;
use frost::{round1, Error};
use participant::round1::{print_values, request_inputs};
use participant::round2::{generate_signature, print_values_round_2, round_2_request_inputs};
use participant::Logger;
use crate::round1::{print_values, request_inputs};
use crate::round2::{generate_signature, print_values_round_2, round_2_request_inputs};
use rand::thread_rng;
use std::io::BufRead;
use std::io::{BufRead, Write};
#[derive(PartialEq)]
pub enum CliError {
Config,
Signing,
}
pub fn cli(
input: &mut impl BufRead,
logger: &mut impl Write,
) -> Result<(), Box<dyn std::error::Error>> {
let round_1_config = request_inputs(input, logger)?;
pub struct ParticipantError {
pub frost_error: Error,
pub cli_error: CliError,
}
let key_package = round_1_config.key_package;
// This is a little messy because of the use of unwrap(). This can be improved.
pub fn cli(input: &mut impl BufRead, logger: &mut dyn Logger) -> Result<(), ParticipantError> {
let round_1_config = request_inputs(input, logger);
if let Err(e) = round_1_config {
return Err(ParticipantError {
frost_error: e,
cli_error: CliError::Config,
});
}
let round_1_config_ok = round_1_config.unwrap();
let key_package_ok = round_1_config_ok.key_package;
logger.log("Key Package succesfully created.".to_string());
writeln!(logger, "Key Package succesfully created.")?;
let mut rng = thread_rng();
let (nonces, commitments) = round1::commit(key_package_ok.secret_share(), &mut rng);
let (nonces, commitments) = frost::round1::commit(key_package.secret_share(), &mut rng);
print_values(commitments, logger);
print_values(commitments, logger)?;
let round_2_config = round_2_request_inputs(input, logger); // TODO: handle errors
let round_2_config = round_2_request_inputs(input, logger)?;
if let Err(e) = round_2_config {
return Err(ParticipantError {
frost_error: e,
cli_error: CliError::Config,
});
}
let round_2_config_ok = round_2_config.unwrap();
let config_message = round_2_config.clone();
// Sign
let signature = generate_signature(round_2_config_ok, &key_package_ok, &nonces); // TODO: handle errors
let signature = generate_signature(round_2_config, &key_package, &nonces)?;
if let Err(e) = signature {
return Err(ParticipantError {
frost_error: e,
cli_error: CliError::Signing,
});
}
print_values_round_2(signature, logger)?;
print_values_round_2(signature.unwrap(), logger);
let group_signature = request_signature(input, logger)?;
key_package
.group_public()
.verify(config_message.signing_package.message(), &group_signature)?;
writeln!(logger, "Group Signature verified.")?;
Ok(())
}
fn request_signature(
input: &mut impl BufRead,
logger: &mut impl Write,
) -> Result<Signature, Box<dyn std::error::Error>> {
writeln!(logger, "The group signature:")?;
let mut signature_input = String::new();
input.read_line(&mut signature_input)?;
let group_signature =
serde_json::from_str(signature_input.trim()).map_err(|_| Error::InvalidSignature)?;
// TODO: add redpallas feature
Ok(group_signature)
}

View File

@ -1,6 +1,3 @@
pub mod cli;
pub mod round1;
pub mod round2;
pub trait Logger {
fn log(&mut self, value: String);
}

View File

@ -1,38 +1,19 @@
mod cli;
mod round1;
mod round2;
#[cfg(test)]
mod tests;
use cli::{cli, CliError};
use participant::Logger;
use cli::cli;
use std::io;
fn main() -> io::Result<()> {
// TODO: Update to use exit codes
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut reader = Box::new(io::stdin().lock());
let mut logger = ConsoleLogger;
let out = cli(&mut reader, &mut logger);
if let Err(e) = out {
if e.cli_error == CliError::Config {
{
eprintln!("Error: {}", e.frost_error);
std::process::exit(exitcode::DATAERR)
};
};
if e.cli_error == CliError::Signing {
eprintln!("Error: {}", e.frost_error);
std::process::exit(1)
};
}
let mut logger = io::stdout();
cli(&mut reader, &mut logger)?;
Ok(())
}
#[derive(Default)]
pub struct ConsoleLogger;
impl Logger for ConsoleLogger {
fn log(&mut self, value: String) {
println!("{}", value);
}
}

View File

@ -5,13 +5,12 @@ use reddsa::frost::redpallas as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas::keys::PositiveY;
use crate::Logger;
use frost::{
keys::{KeyPackage, SecretShare},
round1::SigningCommitments,
Error,
};
use std::io::BufRead;
use std::io::{BufRead, Write};
// TODO: Rethink the types here. They're inconsistent with each other
#[derive(Debug, PartialEq)]
@ -22,13 +21,13 @@ pub struct Round1Config {
// TODO: refactor to generate config
pub fn request_inputs(
input: &mut impl BufRead,
logger: &mut dyn Logger,
) -> Result<Round1Config, Error> {
logger.log("Your JSON-encoded secret share or key package:".to_string());
logger: &mut impl Write,
) -> Result<Round1Config, Box<dyn std::error::Error>> {
writeln!(logger, "Your JSON-encoded secret share or key package:")?;
let mut json = String::new();
input.read_line(&mut json).unwrap();
input.read_line(&mut json)?;
let key_package = if let Ok(secret_share) = serde_json::from_str::<SecretShare>(&json) {
KeyPackage::try_from(secret_share)?
@ -43,14 +42,22 @@ pub fn request_inputs(
Ok(Round1Config { key_package })
}
// The nonces are printed out here for demo purposes only. The hiding and binding nonces are SECRET and not to be shared.
pub fn print_values(commitments: SigningCommitments, logger: &mut dyn Logger) {
logger.log("=== Round 1 ===".to_string());
logger.log("SigningNonces were generated and stored in memory".to_string());
logger.log(format!(
pub fn print_values(
commitments: SigningCommitments,
logger: &mut dyn Write,
) -> Result<(), Box<dyn std::error::Error>> {
writeln!(logger, "=== Round 1 ===")?;
writeln!(logger, "SigningNonces were generated and stored in memory")?;
writeln!(
logger,
"SigningCommitments:\n{}",
serde_json::to_string(&commitments).unwrap(),
));
logger.log("=== Round 1 Completed ===".to_string());
logger.log("Please send your SigningCommitments to the coordinator".to_string());
)?;
writeln!(logger, "=== Round 1 Completed ===")?;
writeln!(
logger,
"Please send your SigningCommitments to the coordinator"
)?;
Ok(())
}

View File

@ -5,16 +5,15 @@ use frost_ed25519 as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas as frost;
use crate::Logger;
use frost::{
keys::KeyPackage,
round1::SigningNonces,
round2::{self, SignatureShare},
Error, SigningPackage,
};
use std::io::BufRead;
use std::io::{BufRead, Write};
// #[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Round2Config {
pub signing_package: SigningPackage,
#[cfg(feature = "redpallas")]
@ -25,15 +24,15 @@ pub struct Round2Config {
// TODO: handle errors
pub fn round_2_request_inputs(
input: &mut impl BufRead,
logger: &mut dyn Logger,
) -> Result<Round2Config, Error> {
logger.log("=== Round 2 ===".to_string());
logger: &mut dyn Write,
) -> Result<Round2Config, Box<dyn std::error::Error>> {
writeln!(logger, "=== Round 2 ===")?;
logger.log("Enter the JSON-encoded SigningPackage:".to_string());
writeln!(logger, "Enter the JSON-encoded SigningPackage:")?;
let mut signing_package_json = String::new();
input.read_line(&mut signing_package_json).unwrap();
input.read_line(&mut signing_package_json)?;
// TODO: change to return a generic Error and use a better error
let signing_package: SigningPackage = serde_json::from_str(signing_package_json.trim())
@ -41,7 +40,7 @@ pub fn round_2_request_inputs(
#[cfg(feature = "redpallas")]
{
logger.log("Enter the randomizer (hex string):".to_string());
writeln!(logger, "Enter the randomizer (hex string):")?;
let mut json = String::new();
@ -81,11 +80,17 @@ pub fn generate_signature(
Ok(signature)
}
pub fn print_values_round_2(signature: SignatureShare, logger: &mut dyn Logger) {
logger.log("Please send the following to the Coordinator".to_string());
logger.log(format!(
pub fn print_values_round_2(
signature: SignatureShare,
logger: &mut dyn Write,
) -> Result<(), Box<dyn std::error::Error>> {
writeln!(logger, "Please send the following to the Coordinator")?;
writeln!(
logger,
"SignatureShare:\n{}",
serde_json::to_string(&signature).unwrap()
));
logger.log("=== End of Round 2 ===".to_string());
)?;
writeln!(logger, "=== End of Round 2 ===")?;
Ok(())
}

View File

@ -1,103 +1,21 @@
// use crate::cli::cli;
// use frost::{keys::SigningShare, round1};
// use frost_ed25519 as frost;
// use hex::FromHex;
// use participant::Logger;
// use rand::thread_rng;
use std::io::BufWriter;
// pub struct TestLogger(Vec<String>);
use crate::cli::cli;
// impl Logger for TestLogger {
// fn log(&mut self, value: String) {
// self.0.push(value);
// }
// }
#[test]
fn check_cli() {
let key_package = r#"{"identifier":"0100000000000000000000000000000000000000000000000000000000000000","value":"ee4a66fec3ced53cac04b0abc309bb57f03f8d7dede033e4ae7b6ef57630120f","commitment":["21446705fa7da298998a567a3c2fdd7274903a886dcde9a77f615d915feb6764","56ce223ffbde8ce5971be587cbb0b8b31aa2bc220a6803b9ce73c63f9f432514","6dcc10da9443ef2c9bbd5fc6a9c3bcd4c5ede8048cc0b1342b091fd1ff6dc53c"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
// #[test]
// fn check_cli() {
// // Round 1 inputs
// let identifier = "1";
// let pub_key = "470f53fb724502bf5b851471e9f8317616fcc7be9405ccff3347c232a3052ce7";
// let group_pub_key = "42ae1baa1bce5a38c130e60aade154ec8775076e729881aba66dabd0c0ac6332";
// let signing_share = "1edfa2ebd280cba9a72f0bc027d21c30078c11f92e0c908addb958062c1ac900";
// let vss_commitment = "0342ae1baa1bce5a38c130e60aade154ec8775076e729881aba66dabd0c0ac6332393a813a6b47782f0fbe653593cbb7b0e0e13f01b54b801144545cb774c0fe5683d8bee3cd63b10523ccace10044869c56bce8a6061950f9aebd7f2e36249571";
let signing_package = r#"{"signing_commitments":{"0100000000000000000000000000000000000000000000000000000000000000":{"hiding":"710a280fcedbcbe626fff055f682e4a525c31f157dd6071ef2c04ea0ecbe8de9","binding":"6dc707cdf26a589b3e2de4f6bae09b94d5d3bb939937b52bc6b16bdecd0b041f","ciphersuite":"FROST(Ed25519, SHA-512)"},"0200000000000000000000000000000000000000000000000000000000000000":{"hiding":"777f011bf695e27ce62474747a9c110cc3b827268047913a21030c3eba0e1eed","binding":"67f051035284cd619f0e7fc583eb3cb0c88d993aad621c856edc0f995f4588b2","ciphersuite":"FROST(Ed25519, SHA-512)"},"0300000000000000000000000000000000000000000000000000000000000000":{"hiding":"c052599bb7a52911b6b58e7c20747f12d45d23aab4aec98aaecdc7909dc6aff3","binding":"b3fbefc67070b1b56203ef875a2c7caf24802dbc943bdc62decac33287b63b23","ciphersuite":"FROST(Ed25519, SHA-512)"}},"message":"74657374","ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
let group_signature = "\"daae8e867c1c3000687a819262099c44e4799853729d87738b4811637a659f3075829c4ee6c5f6767e11b937e18dce20886b0d3f015caaf4ccdb76d4d185910c\"";
// // Round 2 inputs
// let min_signers = "3";
// const MESSAGE: &str = "15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673";
// const IDENTIFIER_2: &str = "2";
// const HIDING_COMMITMENT_2: &str =
// "30f3f03bd739024dc5b1e9d422745a7f32b0971d5cef302106b30bd9f5642d70";
// const BINDING_COMMITMENT_2: &str =
// "a7ccae3750846fbd7d132efec85e96236a711b2097a6f03b1afa04f6029458cc";
// const IDENTIFIER_3: &str = "3";
// const HIDING_COMMITMENT_3: &str =
// "d31bd81ce216b1c83912803a574a0285796275cb8b14f6dc92c8b09a6951f0a2";
// const BINDING_COMMITMENT_3: &str =
// "e1c863cfd08df775b6747ef2456e9bf9a03cc281a479a95261dc39137fcf0967";
let mut buf = BufWriter::new(Vec::new());
// let input = format!(
// "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n",
// identifier,
// pub_key,
// group_pub_key,
// signing_share,
// vss_commitment,
// min_signers,
// MESSAGE,
// IDENTIFIER_2,
// HIDING_COMMITMENT_2,
// BINDING_COMMITMENT_2,
// IDENTIFIER_3,
// HIDING_COMMITMENT_3,
// BINDING_COMMITMENT_3
// );
// let mut reader = input.as_bytes();
// let mut test_logger = TestLogger(Vec::new());
// let _out = cli(&mut reader, &mut test_logger);
let input = format!(
"{}\n{}\n{}\n",
key_package, signing_package, group_signature
);
// let mut rng = thread_rng();
// // We aren't testing randomness so this needs to be generated in the tests. TODO: mock the round1::commit function. To be improved in a later issue.
// let (nonces, commitments) =
// round1::commit(&SigningShare::from_hex(signing_share).unwrap(), &mut rng);
// let _hiding_nonce = hex::encode(nonces.hiding().serialize());
// let _binding_nonce = hex::encode(nonces.binding().serialize());
// let _hiding_commitment = hex::encode(commitments.hiding().serialize());
// let _binding_commitment = hex::encode(commitments.binding().serialize());
// // let signature_share = hex::encode(sig_share.to_bytes());
// let log = [
// "Your identifier (this should be an integer between 1 and 65535):",
// "Your public key:",
// "The group public key:",
// "Your secret share:",
// "Your verifiable secret sharing commitment:",
// "Key Package succesfully created.",
// "=== Round 1 ===",
// "Hiding nonce: {}",
// "Binding nonce: {}",
// "Hiding commitment: {}",
// "Binding commitment: {}",
// "=== Round 1 Completed ===",
// "Please send your Hiding and Binding Commitments to the coordinator",
// "=== Round 2 ===",
// "Number of signers:",
// "Enter the message to sign (received from the coordinator):",
// "Identifier:",
// "Hiding commitment 2:",
// "Binding commitment 2:",
// "Identifier:",
// "Hiding commitment 3:",
// "Binding commitment 3:",
// // "Signature share: {}", // TODO: this tests the signature share value returned is correct. The calculation is done in lib.rs tests.
// // "=== Round 2 Completed ==="
// ]
// .to_vec();
// assert_eq!(test_logger.0[0..7], log[0..7]);
// assert_eq!(test_logger.0[12..22], log[12..22]);
// // TODO: test nonce and commitment values
// }
let signature = cli(&mut input.as_bytes(), &mut buf);
assert!(signature.is_ok());
}

View File

@ -1,14 +1,15 @@
use std::io::BufWriter;
#[cfg(test)]
use frost::Identifier;
use frost::{
keys::{KeyPackage, SigningShare, VerifyingShare},
round1, VerifyingKey,
round1, Error, VerifyingKey,
};
use frost_ed25519 as frost;
use hex::FromHex;
use participant::round1::{print_values, request_inputs, Round1Config};
use participant::Logger;
use rand::thread_rng;
const PUBLIC_KEY: &str = "adf6ab1f882d04988eadfaa52fb175bf37b6247785d7380fde3fb9d68032470d";
@ -16,14 +17,6 @@ const GROUP_PUBLIC_KEY: &str = "087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34f
const SIGNING_SHARE: &str = "ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104";
const SECRET_SHARE_JSON: &str = r#"{"identifier":"0100000000000000000000000000000000000000000000000000000000000000","value":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","926d5910e146dccb9148ca39dc7607f4f7123ff1c0ffaf109add1d165c568bf2", "291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
pub struct TestLogger(Vec<String>);
impl Logger for TestLogger {
fn log(&mut self, value: String) {
self.0.push(value);
}
}
fn build_key_package() -> KeyPackage {
KeyPackage::new(
Identifier::try_from(1).unwrap(),
@ -39,81 +32,90 @@ fn check_valid_round_1_inputs() {
key_package: build_key_package(),
};
let mut test_logger = TestLogger(Vec::new());
let mut buf = BufWriter::new(Vec::new());
let input = SECRET_SHARE_JSON;
let mut valid_input = input.as_bytes();
let expected = request_inputs(&mut valid_input, &mut test_logger).unwrap();
let expected = request_inputs(&mut valid_input, &mut buf).unwrap();
assert_eq!(expected, config);
}
#[test]
fn check_0_input_for_identifier() {
let mut test_logger = TestLogger(Vec::new());
let mut buf = BufWriter::new(Vec::new());
let input = r#"{"identifier":"0000000000000000000000000000000000000000000000000000000000000000","value":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
let mut invalid_input = input.as_bytes();
let expected = request_inputs(&mut invalid_input, &mut test_logger);
// let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
assert!(expected.is_err());
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::InvalidSecretShare
);
}
#[test]
fn check_invalid_length_signing_share() {
let mut test_logger = TestLogger(Vec::new());
let mut buf = BufWriter::new(Vec::new());
let input = r#"{"identifier":"0100000000000000000000000000000000000000000000000000000000000000","value":"ed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
let mut invalid_input = input.as_bytes();
let expected = request_inputs(&mut invalid_input, &mut test_logger);
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
assert!(expected.is_err());
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::InvalidSecretShare
);
}
#[test]
fn check_invalid_round_1_inputs() {
let input = r#"{"value":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","926d5910e146dccb9148ca39dc7607f4f7123ff1c0ffaf109add1d165c568bf2", "291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
let mut test_logger = TestLogger(Vec::new());
let mut buf = BufWriter::new(Vec::new());
let mut valid_input = input.as_bytes();
let expected = request_inputs(&mut valid_input, &mut test_logger);
assert!(expected.is_err());
let expected = request_inputs(&mut valid_input, &mut buf).unwrap_err();
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::InvalidSecretShare
);
}
// TODO: Handle this error differently
#[test]
fn check_invalid_length_vss_commitment() {
let mut test_logger = TestLogger(Vec::new());
let mut buf = BufWriter::new(Vec::new());
let input = r#"{"identifier":"0100000000000000000000000000000000000000000000000000000000000000","value":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["7e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
let mut invalid_input = input.as_bytes();
let expected = request_inputs(&mut invalid_input, &mut test_logger);
let expected = request_inputs(&mut invalid_input, &mut buf);
assert!(expected.is_err())
}
#[test]
fn check_print_values() {
let mut test_logger = TestLogger(Vec::new());
let mut buf = BufWriter::new(Vec::new());
let signing_share =
SigningShare::deserialize(<[u8; 32]>::from_hex(SIGNING_SHARE).unwrap()).unwrap();
let mut rng = thread_rng();
let (_nonces, commitments) = round1::commit(&signing_share, &mut rng);
print_values(commitments, &mut test_logger); // TODO: Run test without random
print_values(commitments, &mut buf).unwrap(); // TODO: Run test without random
let log = [
"=== Round 1 ===",
"SigningNonces were generated and stored in memory",
&format!("SigningCommitments:\n{{\"hiding\":\"{}\",\"binding\":\"{}\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}}", &hex::encode(commitments.hiding().serialize()), &hex::encode(commitments.binding().serialize())),
"=== Round 1 Completed ===",
"Please send your SigningCommitments to the coordinator"];
assert_eq!(test_logger.0, log)
let out = String::from_utf8(buf.into_inner().unwrap()).unwrap();
let log = format!("=== Round 1 ===\nSigningNonces were generated and stored in memory\nSigningCommitments:\n{{\"hiding\":\"{}\",\"binding\":\"{}\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}}\n=== Round 1 Completed ===\nPlease send your SigningCommitments to the coordinator\n", &hex::encode(commitments.hiding().serialize()), &hex::encode(commitments.binding().serialize()));
assert_eq!(out, log)
}

View File

@ -1,4 +1,4 @@
use std::collections::BTreeMap;
use std::{collections::BTreeMap, io::BufWriter};
#[cfg(test)]
use frost::Identifier;
@ -12,17 +12,8 @@ use frost_ed25519 as frost;
use hex::FromHex;
use participant::round2::print_values_round_2;
use participant::round2::{generate_signature, round_2_request_inputs, Round2Config};
use participant::Logger;
use rand::thread_rng;
pub struct TestLogger(Vec<String>);
impl Logger for TestLogger {
fn log(&mut self, value: String) {
self.0.push(value);
}
}
const PUBLIC_KEY: &str = "adf6ab1f882d04988eadfaa52fb175bf37b6247785d7380fde3fb9d68032470d";
const GROUP_PUBLIC_KEY: &str = "087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e";
const SIGNING_SHARE: &str = "ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104";
@ -68,14 +59,12 @@ fn check_valid_round_2_inputs() {
signing_package: SigningPackage::new(signer_commitments, &message),
};
let mut test_logger = TestLogger(Vec::new());
let mut buf = BufWriter::new(Vec::new());
let input = format!("{}\n", signing_package);
let mut valid_input = input.as_bytes();
println!("After valid input");
let round_2_config = round_2_request_inputs(&mut valid_input, &mut test_logger);
let round_2_config = round_2_request_inputs(&mut valid_input, &mut buf);
assert!(round_2_config.is_ok());
assert_eq!(
@ -129,19 +118,20 @@ fn check_sign() {
#[test]
fn check_print_values_round_2() {
let mut test_logger = TestLogger(Vec::new());
let mut buf = BufWriter::new(Vec::new());
const SIGNATURE_SHARE: &str =
"44055c54d0604cbd006f0d1713a22474d7735c5e8816b1878f62ca94bf105900";
let signature_response =
SignatureShare::deserialize(<[u8; 32]>::from_hex(SIGNATURE_SHARE).unwrap()).unwrap();
print_values_round_2(signature_response, &mut test_logger);
print_values_round_2(signature_response, &mut buf).unwrap();
let log = [
"Please send the following to the Coordinator",
"SignatureShare:\n{\"share\":\"44055c54d0604cbd006f0d1713a22474d7735c5e8816b1878f62ca94bf105900\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}",
"=== End of Round 2 ==="];
let log = "Please send the following to the Coordinator\n".to_owned() +
"SignatureShare:\n{\"share\":\"44055c54d0604cbd006f0d1713a22474d7735c5e8816b1878f62ca94bf105900\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}\n" +
"=== End of Round 2 ===\n";
assert_eq!(test_logger.0, log);
let out = String::from_utf8(buf.into_inner().unwrap()).unwrap();
assert_eq!(out, log);
}

20
tests/Cargo.toml Normal file
View File

@ -0,0 +1,20 @@
[package]
name = "tests"
version = "0.1.0"
edition = "2021"
[dependencies]
frost-ed25519 = { version = "0.6.0", features = ["serde"] }
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "8534e283acf0015cc2450e2a6b49685a3bb3145d", features = ["frost"] }
hex = "0.4"
rand = "0.8"
exitcode = "1.1.2"
serde_json = "1.0"
[dev-dependencies]
frost-ed25519 = { version = "0.6.0", features = ["serde"] }
dkg = { path = "../dkg"}
trusted-dealer = { path = "../trusted-dealer"}
participant = { path = "../participant"}
coordinator = { path = "../coordinator"}
rand = "0.8"

View File

@ -0,0 +1,150 @@
use frost_ed25519 as frost;
use frost::keys::IdentifierList;
use frost::Identifier;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::io::BufWriter;
use rand::thread_rng;
use trusted_dealer::inputs::request_inputs as trusted_dealer_input;
use trusted_dealer::trusted_dealer_keygen::trusted_dealer_keygen;
use participant::round2::round_2_request_inputs as participant_input_round_2;
use participant::{
round1::request_inputs as participant_input_round_1, round2::generate_signature,
};
#[test]
fn trusted_dealer_journey() {
let mut buf = BufWriter::new(Vec::new());
let mut rng = thread_rng();
// Trusted dealer
let dealer_input = "3\n5\n\n";
let dealer_config = trusted_dealer_input(&mut dealer_input.as_bytes(), &mut buf).unwrap();
let (shares, pubkeys) =
trusted_dealer_keygen(&dealer_config, IdentifierList::Default, &mut rng).unwrap();
// Coordinator step 1
let num_of_participants = 3;
let id_input_1 = "0100000000000000000000000000000000000000000000000000000000000000";
let id_input_2 = "0200000000000000000000000000000000000000000000000000000000000000";
let id_input_3 = "0300000000000000000000000000000000000000000000000000000000000000";
let participant_id_1 = Identifier::try_from(1).unwrap();
let participant_id_2 = Identifier::try_from(2).unwrap();
let participant_id_3 = Identifier::try_from(3).unwrap();
let step_1_input = format!(
"{}\n{}\n{}\n{}\n{}\n",
serde_json::to_string(&pubkeys).unwrap(),
num_of_participants,
id_input_1,
id_input_2,
id_input_3
);
let participants_config =
coordinator::step_1::step_1(&mut step_1_input.as_bytes(), &mut buf).unwrap();
// Participants round 1
let mut key_packages: HashMap<_, _> = HashMap::new();
for (identifier, secret_share) in shares {
let key_package = frost::keys::KeyPackage::try_from(secret_share).unwrap();
key_packages.insert(identifier, key_package);
}
let mut nonces_map = HashMap::new();
let mut commitments_map = BTreeMap::new();
for participant_index in 1..=3 {
let participant_identifier = Identifier::try_from(participant_index).unwrap();
let share = key_packages[&participant_identifier].secret_share();
let round_1_input = format!(
"{}\n",
&serde_json::to_string(&key_packages[&participant_identifier]).unwrap()
);
let round_1_config =
participant_input_round_1(&mut round_1_input.as_bytes(), &mut buf).unwrap();
assert_eq!(
round_1_config.key_package,
key_packages[&participant_identifier]
);
let (nonces, commitments) = frost::round1::commit(share, &mut rng);
nonces_map.insert(participant_identifier, nonces);
commitments_map.insert(participant_identifier, commitments);
}
// Coordinator step 2
let mut signature_shares = HashMap::new();
let message = "74657374";
let step_2_input = format!(
"{}\n{}\n{}\n{}\n",
message,
serde_json::to_string(&commitments_map[&participant_id_1]).unwrap(),
serde_json::to_string(&commitments_map[&participant_id_2]).unwrap(),
serde_json::to_string(&commitments_map[&participant_id_3]).unwrap()
);
let signing_package = coordinator::step_2::step_2(
&mut step_2_input.as_bytes(),
&mut buf,
vec![participant_id_1, participant_id_2, participant_id_3],
)
.unwrap();
// Participants round 2
for participant_identifier in nonces_map.keys() {
let round_2_input = format!("{}\n", serde_json::to_string(&signing_package).unwrap());
let round_2_config =
participant_input_round_2(&mut round_2_input.as_bytes(), &mut buf).unwrap();
let signature = generate_signature(
round_2_config,
&key_packages[participant_identifier],
&nonces_map[participant_identifier],
)
.unwrap();
signature_shares.insert(*participant_identifier, signature);
}
// coordinator step 3
let step_3_input = format!(
"{}\n{}\n{}\n",
serde_json::to_string(&signature_shares[&participant_id_1]).unwrap(),
serde_json::to_string(&signature_shares[&participant_id_2]).unwrap(),
serde_json::to_string(&signature_shares[&participant_id_3]).unwrap()
);
let group_signature = coordinator::step_3::step_3(
&mut step_3_input.as_bytes(),
&mut buf,
participants_config,
signing_package,
);
// verify
let is_signature_valid = pubkeys
.group_public()
.verify("test".as_bytes(), &group_signature)
.is_ok();
assert!(is_signature_valid);
}

View File

@ -4,37 +4,18 @@ use frost_ed25519 as frost;
use reddsa::frost::redpallas as frost;
use frost::keys::IdentifierList;
use frost::Error;
use rand::thread_rng;
use std::io;
use std::io::{BufRead, Write};
use crate::inputs::request_inputs;
use crate::output::{print_values, Logger};
use crate::inputs::{print_values, request_inputs};
use crate::trusted_dealer_keygen::{split_secret, trusted_dealer_keygen};
#[derive(PartialEq)]
pub enum CliError {
Config,
Keygen,
}
pub struct TrustedDealerError {
pub frost_error: Error,
pub cli_error: CliError,
}
// Currently this defaults to the Default value for Identifiers
pub fn cli() -> Result<(), TrustedDealerError> {
let mut reader = Box::new(io::stdin().lock());
let config = request_inputs(&mut reader);
if let Err(e) = config {
return Err(TrustedDealerError {
frost_error: e,
cli_error: CliError::Config,
});
}
let config = config.unwrap();
// Currently this uses the Default Identifiers
pub fn cli(
input: &mut impl BufRead,
logger: &mut impl Write,
) -> Result<(), Box<dyn std::error::Error>> {
let config = request_inputs(input, logger)?;
let mut rng = thread_rng();
@ -44,27 +25,9 @@ pub fn cli() -> Result<(), TrustedDealerError> {
split_secret(&config, IdentifierList::Default, &mut rng)
};
if let Err(e) = keygen {
return Err(TrustedDealerError {
frost_error: e,
cli_error: CliError::Keygen,
});
}
let (shares, pubkeys) = keygen?;
let (shares, pubkeys) = keygen.unwrap();
let mut console_logger = ConsoleLogger;
print_values(&shares, &pubkeys, &mut console_logger);
print_values(&shares, &pubkeys, logger)?;
Ok(())
}
#[derive(Default)]
pub struct ConsoleLogger;
impl Logger for ConsoleLogger {
fn log(&mut self, value: String) {
println!("{}", value);
}
}

View File

@ -3,8 +3,12 @@ use frost_ed25519 as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas as frost;
use frost::keys::{PublicKeyPackage, SecretShare};
use frost::Error;
use std::io::BufRead;
use frost::Identifier;
use itertools::Itertools;
use std::collections::HashMap;
use std::io::{BufRead, Write};
#[derive(Debug, PartialEq, Clone)]
pub struct Config {
@ -29,30 +33,36 @@ fn validate_inputs(config: &Config) -> Result<(), Error> {
Ok(())
}
pub fn request_inputs(input: &mut impl BufRead) -> Result<Config, Error> {
println!("The minimum number of signers: (2 or more)");
pub fn request_inputs(
input: &mut impl BufRead,
logger: &mut impl Write,
) -> Result<Config, Box<dyn std::error::Error>> {
writeln!(logger, "The minimum number of signers: (2 or more)")?;
let mut min = String::new();
input.read_line(&mut min).unwrap();
input.read_line(&mut min)?;
let min_signers = min
.trim()
.parse::<u16>()
.map_err(|_| Error::InvalidMinSigners)?;
println!("The maximum number of signers: ");
writeln!(logger, "The maximum number of signers: ")?;
let mut max = String::new();
input.read_line(&mut max).unwrap();
input.read_line(&mut max)?;
let max_signers = max
.trim()
.parse::<u16>()
.map_err(|_| Error::InvalidMaxSigners)?;
println!("Secret key (press enter to randomly generate a fresh one): ");
writeln!(
logger,
"Secret key (press enter to randomly generate a fresh one): "
)?;
let mut secret_input = String::new();
input.read_line(&mut secret_input).unwrap();
input.read_line(&mut secret_input)?;
let secret = hex::decode(secret_input.trim()).map_err(|_| Error::MalformedSigningKey)?;
let config = Config {
@ -65,3 +75,31 @@ pub fn request_inputs(input: &mut impl BufRead) -> Result<Config, Error> {
Ok(config)
}
pub fn print_values(
keys: &HashMap<Identifier, SecretShare>,
pubkeys: &PublicKeyPackage,
logger: &mut dyn Write,
) -> Result<(), Box<dyn std::error::Error>> {
#[cfg(feature = "redpallas")]
let pubkeys = pubkeys.clone().into_positive_y();
#[cfg(feature = "redpallas")]
let pubkeys = &pubkeys;
writeln!(
logger,
"Public key package:\n{}",
serde_json::to_string(pubkeys).unwrap()
)?;
for (k, v) in keys.iter().sorted_by_key(|x| x.0) {
writeln!(logger, "Participant: {}", hex::encode(k.serialize()))?;
writeln!(
logger,
"Secret share:\n{}",
serde_json::to_string(v).unwrap()
)?;
}
Ok(())
}

View File

@ -0,0 +1,3 @@
pub mod cli;
pub mod inputs;
pub mod trusted_dealer_keygen;

View File

@ -1,31 +1,15 @@
mod cli;
mod inputs;
mod output;
mod trusted_dealer_keygen;
#[cfg(test)]
mod tests;
use cli::CliError;
use std::io;
use crate::cli::cli;
use trusted_dealer::cli::cli;
fn main() -> io::Result<()> {
let out = cli();
if let Err(e) = out {
if e.cli_error == CliError::Config {
{
eprintln!("Error: {}", e.frost_error);
std::process::exit(exitcode::DATAERR)
};
};
if e.cli_error == CliError::Keygen {
eprintln!("Error: {}", e.frost_error);
std::process::exit(1)
};
}
// TODO: Update to use exit codes
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(())
}

View File

@ -1,68 +0,0 @@
#[cfg(not(feature = "redpallas"))]
use frost_ed25519 as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas::keys::PositiveY;
use frost::keys::{PublicKeyPackage, SecretShare};
use frost::Identifier;
use itertools::Itertools;
use std::collections::HashMap;
pub trait Logger {
fn log(&mut self, value: String);
}
fn get_identifier_value(i: Identifier) -> String {
let s = i.serialize();
let le_bytes: [u8; 2] = [s[0], s[1]];
u16::from_le_bytes(le_bytes).to_string()
}
pub fn print_values(
keys: &HashMap<Identifier, SecretShare>,
pubkeys: &PublicKeyPackage,
logger: &mut dyn Logger,
) {
#[cfg(feature = "redpallas")]
let pubkeys = pubkeys.clone().into_positive_y();
#[cfg(feature = "redpallas")]
let pubkeys = &pubkeys;
logger.log(format!(
"Public key package:\n{}",
serde_json::to_string(pubkeys).unwrap()
));
println!("---");
for (k, v) in keys.iter().sorted_by_key(|x| x.0) {
logger.log(format!("Participant: {}", get_identifier_value(*k)));
logger.log(format!(
"Secret share:\n{}",
serde_json::to_string(v).unwrap()
));
println!("---")
}
}
#[cfg(test)]
mod tests {
use crate::output::get_identifier_value;
use frost::Identifier;
use frost_ed25519 as frost;
#[test]
fn check_get_identifier_value() {
let min = "1";
let identifier_min = Identifier::try_from(1).unwrap();
assert!(get_identifier_value(identifier_min) == min);
let max = "65535";
let identifier_max = Identifier::try_from(65535).unwrap();
assert!(get_identifier_value(identifier_max) == max);
}
}

View File

@ -1,3 +1,2 @@
mod inputs_tests;
mod integration_test;
mod output_tests;
mod inputs;
mod print_values;

View File

@ -0,0 +1,114 @@
use std::io::BufWriter;
use frost::Error;
use frost_ed25519 as frost;
use trusted_dealer::inputs::{request_inputs, Config};
#[test]
fn check_valid_input_for_signers() {
let mut buf = BufWriter::new(Vec::new());
let config = Config {
min_signers: 2,
max_signers: 3,
secret: Vec::new(),
};
let mut valid_input = "2\n3\n\n".as_bytes();
let expected = request_inputs(&mut valid_input, &mut buf).unwrap();
assert_eq!(expected, config);
}
#[test]
fn return_error_if_min_participant_greater_than_max_participant() {
let mut buf = BufWriter::new(Vec::new());
let mut invalid_input = "4\n3\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::InvalidMinSigners
);
}
#[test]
fn return_error_if_min_participant_is_less_than_2() {
let mut buf = BufWriter::new(Vec::new());
let mut invalid_input = "1\n3\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::InvalidMinSigners
);
}
#[test]
fn return_error_if_max_participant_is_less_than_2() {
let mut buf = BufWriter::new(Vec::new());
let mut invalid_input = "2\n1\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::InvalidMaxSigners
);
}
// Testing inclusion of secret input
#[test]
fn check_valid_input_with_secret() {
let mut buf = BufWriter::new(Vec::new());
let mut valid_input =
"3\n6\n7b1c33d3f5291d85de664833beb1ad469f7fb6025a0ec78b3a790c6e13a98304\n".as_bytes();
let config = request_inputs(&mut valid_input, &mut buf).unwrap();
let secret: Vec<u8> = vec![
123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2,
90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4,
];
let expected = Config {
min_signers: 3,
max_signers: 6,
secret,
};
assert_eq!(expected, config)
}
#[test]
fn return_error_if_invalid_min_signers_input() {
let mut buf = BufWriter::new(Vec::new());
let mut invalid_input = "hello\n6\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::InvalidMinSigners
);
}
#[test]
fn return_error_if_invalid_max_signers_input() {
let mut buf = BufWriter::new(Vec::new());
let mut invalid_input = "4\nworld\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::InvalidMaxSigners
);
}
#[test]
fn return_malformed_signing_key_error_if_secret_is_invalid() {
let mut buf = BufWriter::new(Vec::new());
let mut secret_input = "4\n6\nasecret\n".as_bytes();
let expected = request_inputs(&mut secret_input, &mut buf).unwrap_err();
assert_eq!(
*expected.downcast::<Error>().unwrap(),
Error::MalformedSigningKey
);
}

View File

@ -1,86 +0,0 @@
use crate::inputs::{request_inputs, Config};
use frost::Error;
use frost_ed25519 as frost;
#[test]
fn check_valid_input_for_signers() {
let config = Config {
min_signers: 2,
max_signers: 3,
secret: Vec::new(),
};
let mut valid_input = "2\n3\n\n".as_bytes();
let expected = request_inputs(&mut valid_input);
assert_eq!(expected, Ok(config));
}
#[test]
fn return_error_if_min_participant_greater_than_max_participant() {
let mut invalid_input = "4\n3\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
assert_eq!(expected, Err(Error::InvalidMinSigners));
}
#[test]
fn return_error_if_min_participant_is_less_than_2() {
let mut invalid_input = "1\n3\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
assert_eq!(expected, Err(Error::InvalidMinSigners));
}
#[test]
fn return_error_if_max_participant_is_less_than_2() {
let mut invalid_input = "2\n1\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
assert_eq!(expected, Err(Error::InvalidMaxSigners));
}
// Testing inclusion of secret input
#[test]
fn check_valid_input_with_secret() {
let mut valid_input =
"3\n6\n7b1c33d3f5291d85de664833beb1ad469f7fb6025a0ec78b3a790c6e13a98304\n".as_bytes();
let config = request_inputs(&mut valid_input).unwrap();
let secret: Vec<u8> = vec![
123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2,
90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4,
];
let expected = Config {
min_signers: 3,
max_signers: 6,
secret,
};
assert_eq!(expected, config)
}
#[test]
fn return_error_if_invalid_min_signers_input() {
let mut invalid_input = "hello\n6\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
assert_eq!(expected, Err(Error::InvalidMinSigners))
}
#[test]
fn return_error_if_invalid_max_signers_input() {
let mut invalid_input = "4\nworld\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
assert_eq!(expected, Err(Error::InvalidMaxSigners))
}
#[test]
fn return_malformed_signing_key_error_if_secret_is_invalid() {
let mut secret_input = "4\n6\nasecret\n".as_bytes();
let expected = request_inputs(&mut secret_input);
assert_eq!(expected, Err(Error::MalformedSigningKey))
}

View File

@ -1,109 +0,0 @@
use frost::keys::IdentifierList;
use frost_ed25519 as frost;
use rand::thread_rng;
use crate::inputs::Config;
use crate::output::{print_values, Logger};
use crate::trusted_dealer_keygen::{split_secret, trusted_dealer_keygen};
struct TestLogger(Vec<String>);
impl Logger for TestLogger {
fn log(&mut self, value: String) {
self.0.push(value);
}
}
#[test]
fn check_output_without_secret() {
let mut test_logger = TestLogger(Vec::new());
let mut rng = thread_rng();
let config = Config {
min_signers: 2,
max_signers: 3,
secret: Vec::new(),
};
let (shares, pubkeys) =
trusted_dealer_keygen(&config, IdentifierList::Default, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut test_logger); // TODO: do we need shares here?
let public_key_package = serde_json::to_string(&pubkeys).unwrap();
assert_eq!(
test_logger.0[0],
format!("Public key package:\n{}", public_key_package)
);
}
#[test]
fn check_output_with_secret() {
let mut test_logger = TestLogger(Vec::new());
let mut rng = thread_rng();
let secret: Vec<u8> = vec![
123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2,
90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4,
];
let config = Config {
min_signers: 2,
max_signers: 3,
secret,
};
let (shares, pubkeys) = split_secret(&config, IdentifierList::Default, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut test_logger);
let public_key_package = serde_json::to_string(&pubkeys).unwrap();
assert_eq!(
test_logger.0[0],
format!("Public key package:\n{}", public_key_package)
);
}
#[test]
fn check_output_with_large_num_of_signers() {
let mut test_logger = TestLogger(Vec::new());
let mut rng = thread_rng();
let config = Config {
min_signers: 10,
max_signers: 20,
secret: Vec::new(),
};
let (shares, pubkeys) =
trusted_dealer_keygen(&config, IdentifierList::Default, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut test_logger);
let public_key_package = serde_json::to_string(&pubkeys).unwrap();
assert_eq!(
test_logger.0[0],
format!("Public key package:\n{}", public_key_package)
);
}
#[test]
fn check_output_with_secret_with_large_num_of_signers() {
let mut test_logger = TestLogger(Vec::new());
let mut rng = thread_rng();
let secret: Vec<u8> = vec![
123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2,
90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4,
];
let config = Config {
min_signers: 10,
max_signers: 20,
secret,
};
let (shares, pubkeys) = split_secret(&config, IdentifierList::Default, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut test_logger);
let public_key_package = serde_json::to_string(&pubkeys).unwrap();
assert_eq!(
test_logger.0[0],
format!("Public key package:\n{}", public_key_package)
);
}

View File

@ -0,0 +1,110 @@
use frost::keys::{IdentifierList, PublicKeyPackage, SecretShare};
use frost::Identifier;
use frost_ed25519 as frost;
use itertools::Itertools;
use rand::thread_rng;
use std::collections::HashMap;
use std::io::BufWriter;
use trusted_dealer::inputs::print_values;
use trusted_dealer::inputs::Config;
use trusted_dealer::trusted_dealer_keygen::{split_secret, trusted_dealer_keygen};
fn build_output(shares: HashMap<Identifier, SecretShare>, pubkeys: PublicKeyPackage) -> String {
let pub_key_package = format!(
"Public key package:\n{}",
serde_json::to_string(&pubkeys).unwrap()
);
let mut out = pub_key_package;
for (k, v) in shares.iter().sorted_by_key(|x| x.0) {
out = out
+ &format!("\nParticipant: {}", hex::encode(k.serialize()))
+ &format!("\nSecret share:\n{}", serde_json::to_string(v).unwrap())
}
out + "\n"
}
#[test]
fn check_output_without_secret() {
let mut buf = BufWriter::new(Vec::new());
let mut rng = thread_rng();
let config = Config {
min_signers: 2,
max_signers: 3,
secret: Vec::new(),
};
let identifiers = IdentifierList::Default;
let (shares, pubkeys) = trusted_dealer_keygen(&config, identifiers, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut buf).unwrap(); // TODO: do we need shares here?
let out = String::from_utf8(buf.into_inner().unwrap()).unwrap();
assert_eq!(out, build_output(shares, pubkeys));
}
#[test]
fn check_output_with_secret() {
let mut buf = BufWriter::new(Vec::new());
let mut rng = thread_rng();
let secret: Vec<u8> = vec![
123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2,
90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4,
];
let config = Config {
min_signers: 2,
max_signers: 3,
secret,
};
let (shares, pubkeys) = split_secret(&config, IdentifierList::Default, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut buf).unwrap();
let out = String::from_utf8(buf.into_inner().unwrap()).unwrap();
assert_eq!(out, build_output(shares, pubkeys));
}
#[test]
fn check_output_with_large_num_of_signers() {
let mut buf = BufWriter::new(Vec::new());
let mut rng = thread_rng();
let config = Config {
min_signers: 10,
max_signers: 20,
secret: Vec::new(),
};
let (shares, pubkeys) =
trusted_dealer_keygen(&config, IdentifierList::Default, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut buf).unwrap();
let out = String::from_utf8(buf.into_inner().unwrap()).unwrap();
assert_eq!(out, build_output(shares, pubkeys));
}
#[test]
fn check_output_with_secret_with_large_num_of_signers() {
let mut buf = BufWriter::new(Vec::new());
let mut rng = thread_rng();
let secret: Vec<u8> = vec![
123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2,
90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4,
];
let config = Config {
min_signers: 10,
max_signers: 20,
secret,
};
let (shares, pubkeys) = split_secret(&config, IdentifierList::Default, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut buf).unwrap();
let out = String::from_utf8(buf.into_inner().unwrap()).unwrap();
assert_eq!(out, build_output(shares, pubkeys));
}

View File

@ -0,0 +1 @@
pub mod signature_gen;

View File

@ -1,13 +1,14 @@
use crate::inputs::Config;
use crate::tests::integration_test::signature_gen::{key_package, round_1, round_2};
use crate::trusted_dealer_keygen::split_secret;
mod helpers;
use frost::aggregate;
use frost::keys::IdentifierList;
use frost_ed25519 as frost;
use helpers::signature_gen::{key_package, round_1, round_2};
use rand::thread_rng;
use trusted_dealer::inputs::Config;
use trusted_dealer::trusted_dealer_keygen::split_secret;
use crate::trusted_dealer_keygen::trusted_dealer_keygen;
mod signature_gen;
use trusted_dealer::trusted_dealer_keygen::trusted_dealer_keygen;
#[test]
fn check_keygen_with_dealer() {