clean up reading, writing and error handling

This commit is contained in:
Conrado Gouvea 2023-06-23 18:55:10 -03:00
parent d9e7df2365
commit 02910565bf
3 changed files with 64 additions and 108 deletions

View File

@ -1,35 +1,17 @@
use frost::keys::dkg::{round1, round2}; use frost::keys::dkg::{round1, round2};
use frost::{Error, Identifier}; use frost::Identifier;
use frost_ed25519 as frost; use frost_ed25519 as frost;
use rand::thread_rng; use rand::thread_rng;
use std::collections::HashMap; use std::collections::HashMap;
use std::io; use std::io::{BufRead, Write};
use crate::inputs::{read_round1_package, read_round2_package, request_inputs}; use crate::inputs::{read_round1_package, read_round2_package, request_inputs};
use crate::output::Logger;
#[derive(PartialEq)] pub fn cli(
pub enum CliError { reader: &mut impl BufRead,
Config, logger: &mut impl Write,
Keygen, ) -> Result<(), Box<dyn std::error::Error>> {
} let config = request_inputs(reader, logger)?;
pub struct TrustedDealerError {
pub frost_error: Error,
pub cli_error: CliError,
}
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();
let rng = thread_rng(); let rng = thread_rng();
@ -38,106 +20,80 @@ pub fn cli() -> Result<(), TrustedDealerError> {
config.max_signers, config.max_signers,
config.min_signers, config.min_signers,
rng, rng,
) )?;
.map_err(|e| TrustedDealerError {
frost_error: e,
cli_error: CliError::Keygen,
})?;
let mut console_logger = ConsoleLogger::default(); writeln!(logger, "\n=== ROUND 1: SEND PACKAGES ===\n")?;
console_logger.log("\n=== ROUND 1: SEND PACKAGES ===\n".to_string()); writeln!(
logger,
console_logger.log(format!(
"Round 1 Package to send to all other participants (your identifier: {}):\n\n{}\n", "Round 1 Package to send to all other participants (your identifier: {}):\n\n{}\n",
serde_json::to_string(&config.identifier).unwrap(), serde_json::to_string(&config.identifier).unwrap(),
serde_json::to_string(&package).unwrap() serde_json::to_string(&package).unwrap()
)); )?;
console_logger.log("=== ROUND 1: RECEIVE PACKAGES ===\n".to_string()); writeln!(logger, "=== ROUND 1: RECEIVE PACKAGES ===\n")?;
console_logger.log(format!( writeln!(
logger,
"Input Round 1 Packages from the other {} participants.\n", "Input Round 1 Packages from the other {} participants.\n",
config.max_signers - 1, config.max_signers - 1,
)); )?;
let mut received_round1_packages: HashMap<Identifier, round1::Package> = HashMap::new(); let mut received_round1_packages: HashMap<Identifier, round1::Package> = HashMap::new();
for _ in 0..config.max_signers - 1 { for _ in 0..config.max_signers - 1 {
let (identifier, round1_package) = let (identifier, round1_package) = read_round1_package(reader, logger)?;
read_round1_package(&mut reader).map_err(|e| TrustedDealerError {
frost_error: e,
cli_error: CliError::Keygen,
})?;
received_round1_packages.insert(identifier, round1_package); received_round1_packages.insert(identifier, round1_package);
console_logger.log("".to_string()); writeln!(logger)?;
} }
let received_round1_packages = received_round1_packages.into_values().collect::<Vec<_>>(); let received_round1_packages = received_round1_packages.into_values().collect::<Vec<_>>();
let (round2_secret_package, round2_packages) = let (round2_secret_package, round2_packages) =
frost::keys::dkg::part2(secret_package, &received_round1_packages).map_err(|e| { frost::keys::dkg::part2(secret_package, &received_round1_packages)?;
TrustedDealerError {
frost_error: e,
cli_error: CliError::Keygen,
}
})?;
console_logger.log("=== ROUND 2: SEND PACKAGES ===\n".to_string()); writeln!(logger, "=== ROUND 2: SEND PACKAGES ===\n")?;
for package in round2_packages { for package in round2_packages {
console_logger.log(format!( writeln!(
logger,
"Round 2 Package to send to participant {} (your identifier: {}):\n\n{}\n", "Round 2 Package to send to participant {} (your identifier: {}):\n\n{}\n",
serde_json::to_string(package.receiver_identifier()).unwrap(), serde_json::to_string(package.receiver_identifier()).unwrap(),
serde_json::to_string(&config.identifier).unwrap(), serde_json::to_string(&config.identifier).unwrap(),
serde_json::to_string(&package).unwrap() serde_json::to_string(&package).unwrap()
)); )?;
} }
console_logger.log("=== ROUND 2: RECEIVE PACKAGES ===\n".to_string()); writeln!(logger, "=== ROUND 2: RECEIVE PACKAGES ===\n")?;
console_logger.log(format!( writeln!(
logger,
"Input Round 2 Packages from the other {} participants.\n", "Input Round 2 Packages from the other {} participants.\n",
config.max_signers - 1, config.max_signers - 1,
)); )?;
let mut received_round2_packages: HashMap<Identifier, round2::Package> = HashMap::new(); let mut received_round2_packages: HashMap<Identifier, round2::Package> = HashMap::new();
for _ in 0..config.max_signers - 1 { for _ in 0..config.max_signers - 1 {
let (identifier, round2_package) = let (identifier, round2_package) = read_round2_package(reader, logger)?;
read_round2_package(&mut reader).map_err(|e| TrustedDealerError {
frost_error: e,
cli_error: CliError::Keygen,
})?;
received_round2_packages.insert(identifier, round2_package); received_round2_packages.insert(identifier, round2_package);
console_logger.log("".to_string()); writeln!(logger)?;
} }
let received_round2_packages = received_round2_packages.into_values().collect::<Vec<_>>(); let received_round2_packages = received_round2_packages.into_values().collect::<Vec<_>>();
console_logger.log("=== DKG FINISHED ===".to_string()); writeln!(logger, "=== DKG FINISHED ===")?;
let (key_package, public_key_package) = frost::keys::dkg::part3( let (key_package, public_key_package) = frost::keys::dkg::part3(
&round2_secret_package, &round2_secret_package,
&received_round1_packages, &received_round1_packages,
&received_round2_packages, &received_round2_packages,
) )?;
.map_err(|e| TrustedDealerError {
frost_error: e,
cli_error: CliError::Keygen,
})?;
console_logger.log(format!( writeln!(
logger,
"Participant key package:\n\n{}\n", "Participant key package:\n\n{}\n",
serde_json::to_string(&key_package).unwrap(), serde_json::to_string(&key_package).unwrap(),
)); )?;
console_logger.log(format!( writeln!(
logger,
"Partcipant public key package:\n\n{}\n", "Partcipant public key package:\n\n{}\n",
serde_json::to_string(&public_key_package).unwrap(), serde_json::to_string(&public_key_package).unwrap(),
)); )?;
Ok(()) Ok(())
} }
#[derive(Default)]
pub struct ConsoleLogger;
impl Logger for ConsoleLogger {
fn log(&mut self, value: String) {
println!("{}", value);
}
}

View File

@ -3,7 +3,7 @@ use frost::{
Error, Identifier, Error, Identifier,
}; };
use frost_ed25519 as frost; use frost_ed25519 as frost;
use std::io::BufRead; use std::io::{BufRead, Write};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Config { pub struct Config {
@ -12,6 +12,10 @@ pub struct Config {
pub identifier: Identifier, pub identifier: Identifier,
} }
pub trait Logger {
fn log(&mut self, value: String);
}
fn validate_inputs(config: &Config) -> Result<(), Error> { fn validate_inputs(config: &Config) -> Result<(), Error> {
if config.min_signers < 2 { if config.min_signers < 2 {
return Err(Error::InvalidMinSigners); return Err(Error::InvalidMinSigners);
@ -28,8 +32,11 @@ fn validate_inputs(config: &Config) -> Result<(), Error> {
Ok(()) Ok(())
} }
pub fn request_inputs(input: &mut impl BufRead) -> Result<Config, Error> { pub fn request_inputs(
println!("The minimum number of signers: (2 or more)"); input: &mut impl BufRead,
logger: &mut dyn Write,
) -> Result<Config, Box<dyn std::error::Error>> {
writeln!(logger, "The minimum number of signers: (2 or more)")?;
let mut min = String::new(); let mut min = String::new();
input.read_line(&mut min).unwrap(); input.read_line(&mut min).unwrap();
@ -39,7 +46,7 @@ pub fn request_inputs(input: &mut impl BufRead) -> Result<Config, Error> {
.parse::<u16>() .parse::<u16>()
.map_err(|_| Error::InvalidMinSigners)?; .map_err(|_| Error::InvalidMinSigners)?;
println!("The maximum number of signers: "); writeln!(logger, "The maximum number of signers: ")?;
let mut max = String::new(); let mut max = String::new();
input.read_line(&mut max).unwrap(); input.read_line(&mut max).unwrap();
@ -48,7 +55,10 @@ pub fn request_inputs(input: &mut impl BufRead) -> Result<Config, Error> {
.parse::<u16>() .parse::<u16>()
.map_err(|_| Error::InvalidMaxSigners)?; .map_err(|_| Error::InvalidMaxSigners)?;
println!("Your identifier (this should be an integer between 1 and 65535):"); writeln!(
logger,
"Your identifier (this should be an integer between 1 and 65535):"
)?;
let mut identifier_input = String::new(); let mut identifier_input = String::new();
@ -73,8 +83,9 @@ pub fn request_inputs(input: &mut impl BufRead) -> Result<Config, Error> {
pub fn read_round1_package( pub fn read_round1_package(
input: &mut impl BufRead, input: &mut impl BufRead,
) -> Result<(Identifier, round1::Package), Error> { logger: &mut dyn Write,
println!("The sender's identifier (hex string):"); ) -> Result<(Identifier, round1::Package), Box<dyn std::error::Error>> {
writeln!(logger, "The sender's identifier (hex string):")?;
let mut identifier_input = String::new(); let mut identifier_input = String::new();
input.read_line(&mut identifier_input).unwrap(); input.read_line(&mut identifier_input).unwrap();
@ -86,7 +97,7 @@ pub fn read_round1_package(
) )
.unwrap(); .unwrap();
println!("Their JSON-encoded Round 1 Package:"); writeln!(logger, "Their JSON-encoded Round 1 Package:")?;
let mut package_input = String::new(); let mut package_input = String::new();
input.read_line(&mut package_input).unwrap(); input.read_line(&mut package_input).unwrap();
@ -97,8 +108,9 @@ pub fn read_round1_package(
pub fn read_round2_package( pub fn read_round2_package(
input: &mut impl BufRead, input: &mut impl BufRead,
) -> Result<(Identifier, round2::Package), Error> { logger: &mut dyn Write,
println!("The participant identifier (this should be an integer between 1 and 65535):"); ) -> Result<(Identifier, round2::Package), Box<dyn std::error::Error>> {
writeln!(logger, "The sender's identifier (hex string):")?;
let mut identifier_input = String::new(); let mut identifier_input = String::new();
input.read_line(&mut identifier_input).unwrap(); input.read_line(&mut identifier_input).unwrap();
@ -110,7 +122,7 @@ pub fn read_round2_package(
) )
.unwrap(); .unwrap();
println!("Their JSON-encoded Round 1 Package:"); writeln!(logger, "Their JSON-encoded Round 1 Package:")?;
let mut package_input = String::new(); let mut package_input = String::new();
input.read_line(&mut package_input).unwrap(); input.read_line(&mut package_input).unwrap();

View File

@ -6,26 +6,14 @@ mod trusted_dealer_keygen;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use cli::CliError;
use std::io; use std::io;
use crate::cli::cli; use crate::cli::cli;
fn main() -> io::Result<()> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let out = cli(); let mut reader = Box::new(io::stdin().lock());
let mut logger = io::stdout();
if let Err(e) = out { cli(&mut reader, &mut logger)?;
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)
};
}
Ok(()) Ok(())
} }