change coordinator and participant to allow them to be non-interactive (#133)

* trusted-dealer: allow reading params from arguments, and writing to files

* change coordinator and participant to allow them to be non-interactive

* allow reading message from file

* remove warnings

* fix tests
This commit is contained in:
Conrado Gouvea 2024-01-31 11:07:44 -03:00 committed by GitHub
parent d0c8949c32
commit a04a829930
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 88 additions and 24 deletions

View File

@ -3,12 +3,26 @@ use clap::Parser;
#[derive(Parser, Debug, Default)]
#[command(author, version, about, long_about = None)]
pub struct Args {
/// The number of participants. If 0, will prompt for a value.
#[arg(short = 'n', long, default_value_t = 0)]
pub num_signers: u16,
/// Public key package to use. Can be a file with a JSON-encoded
/// package, or "-". If the file does not exist or if "-" is specified,
/// then it will be read from standard input.
#[arg(short = 'P', long, default_value = "public-key-package.json")]
pub public_key_package: String,
/// The message to sign. Can be a file with the raw message, or "-". If "-"
/// is specified, then it will be read from standard input as a hex string.
#[arg(short = 'm', long, default_value = "-")]
pub message: String,
/// Where to write the generated raw bytes signature. If "-", the
/// human-readable hex-string is printed to stdout.
#[arg(short = 's', long, default_value = "-")]
pub signature: String,
/// IP to bind to, if using online comms
#[arg(short, long, default_value = "0.0.0.0")]
pub ip: String,

View File

@ -32,7 +32,13 @@ pub async fn cli(
"=== STEP 2: CHOOSE MESSAGE AND GENERATE COMMITMENT PACKAGE ===\n"
)?;
let signing_package = step_2(reader, logger, participants_config.commitments.clone()).await?;
let signing_package = step_2(
args,
reader,
logger,
participants_config.commitments.clone(),
)
.await?;
#[cfg(feature = "redpallas")]
let randomizer = request_randomizer(reader, logger)?;
@ -40,6 +46,7 @@ pub async fn cli(
writeln!(logger, "=== STEP 3: BUILD GROUP SIGNATURE ===\n")?;
step_3(
args,
&mut comms,
reader,
logger,

View File

@ -81,6 +81,7 @@ impl Comms for SocketComms {
) -> Result<BTreeMap<Identifier, SigningCommitments>, Box<dyn Error>> {
self.endpoints = BTreeMap::new();
let mut signing_commitments = BTreeMap::new();
eprintln!("Waiting for participants to send their commitments...");
for _ in 0..num_of_participants {
let (endpoint, data) = self
.input_rx
@ -109,6 +110,7 @@ impl Comms for SocketComms {
signing_package: &SigningPackage,
#[cfg(feature = "redpallas")] _randomizer: frost::round2::Randomizer,
) -> Result<BTreeMap<Identifier, SignatureShare>, Box<dyn Error>> {
eprintln!("Sending SigningPackage to participants...");
// Send SigningPackage to all participants
let data = serde_json::to_vec(&Message::SigningPackage(signing_package.clone()))?;
for identifier in signing_package.signing_commitments().keys() {
@ -118,6 +120,7 @@ impl Comms for SocketComms {
.ok_or(eyre!("unknown identifier"))?;
self.handler.network().send(*endpoint, &data);
}
eprintln!("Waiting for participants to send their SignatureShares...");
// Read SignatureShare from all participants
let mut signature_shares = BTreeMap::new();
for _ in 0..signing_package.signing_commitments().len() {

View File

@ -15,7 +15,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = io::stdout();
cli(&args, &mut reader, &mut logger).await?;
Ok(())
// Force process to exit; since socket comms spawn a thread, it will keep
// running forever. Ideally we should join() the thread but this works for
// now.
std::process::exit(0);
}
// Choose participants -> send message to those participants - gen message to send

View File

@ -50,11 +50,15 @@ async fn read_commitments(
)?;
let pub_key_package: PublicKeyPackage = serde_json::from_str(&pub_key_package)?;
writeln!(logger, "The number of participants: ")?;
let num_of_participants = if args.num_signers == 0 {
writeln!(logger, "The number of participants: ")?;
let mut participants = String::new();
input.read_line(&mut participants)?;
let num_of_participants = participants.trim().parse::<u16>()?;
let mut participants = String::new();
input.read_line(&mut participants)?;
participants.trim().parse::<u16>()?
} else {
args.num_signers
};
let commitments_list = comms
.get_signing_commitments(input, logger, &pub_key_package, num_of_participants)

View File

@ -7,9 +7,12 @@ use frost::{round1::SigningCommitments, Identifier, SigningPackage};
use std::{
collections::BTreeMap,
fs,
io::{BufRead, Write},
};
use crate::args::Args;
#[derive(Debug, PartialEq, Clone)]
pub struct CommitmentsConfig {
pub message: Vec<u8>,
@ -17,11 +20,12 @@ pub struct CommitmentsConfig {
}
pub async fn step_2(
args: &Args,
input: &mut impl BufRead,
logger: &mut dyn Write,
commitments: BTreeMap<Identifier, SigningCommitments>,
) -> Result<SigningPackage, Box<dyn std::error::Error>> {
let signing_package = request_message(input, logger, commitments)?;
let signing_package = request_message(args, input, logger, commitments)?;
print_signing_package(logger, &signing_package);
Ok(signing_package)
}
@ -29,16 +33,21 @@ pub async fn step_2(
// Input required:
// 1. message
fn request_message(
args: &Args,
input: &mut impl BufRead,
logger: &mut dyn Write,
commitments: BTreeMap<Identifier, SigningCommitments>,
) -> Result<SigningPackage, Box<dyn std::error::Error>> {
writeln!(logger, "The message to be signed (hex encoded)")?;
let message = if args.message == "-" {
writeln!(logger, "The message to be signed (hex encoded)")?;
let mut msg = String::new();
input.read_line(&mut msg)?;
let mut msg = String::new();
input.read_line(&mut msg)?;
let message = hex::decode(msg.trim())?;
hex::decode(msg.trim())?
} else {
fs::read(&args.message)?
};
let signing_package = SigningPackage::new(commitments, &message);

View File

@ -5,9 +5,12 @@ use reddsa::frost::redpallas as frost;
use frost::{Signature, SigningPackage};
use std::io::{BufRead, Write};
use std::{
fs,
io::{BufRead, Write},
};
use crate::{comms::Comms, step_1::ParticipantsConfig};
use crate::{args::Args, comms::Comms, step_1::ParticipantsConfig};
#[cfg(feature = "redpallas")]
pub fn request_randomizer(
@ -27,6 +30,7 @@ pub fn request_randomizer(
}
pub async fn step_3(
args: &Args,
comms: &mut impl Comms,
input: &mut dyn BufRead,
logger: &mut dyn Write,
@ -44,7 +48,7 @@ pub async fn step_3(
randomizer,
)
.await?;
print_signature(logger, group_signature);
print_signature(args, logger, group_signature)?;
Ok(group_signature)
}
@ -87,11 +91,20 @@ async fn request_inputs_signature_shares(
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();
fn print_signature(
args: &Args,
logger: &mut dyn Write,
group_signature: Signature,
) -> Result<(), Box<dyn std::error::Error>> {
if args.signature == "-" {
writeln!(
logger,
"Group signature: {}",
serde_json::to_string(&group_signature)?
)?;
} else {
fs::write(&args.signature, group_signature.serialize())?;
eprintln!("Raw signature written to {}", &args.signature);
};
Ok(())
}

View File

@ -1,6 +1,7 @@
use crate::args::Args;
use crate::comms::cli::CLIComms;
#[cfg(not(feature = "sockets"))]
use crate::comms::cli::CLIComms;
#[cfg(feature = "sockets")]
use crate::comms::socket::SocketComms;

View File

@ -15,5 +15,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = io::stdout();
cli(&args, &mut reader, &mut logger).await?;
Ok(())
// Force process to exit; since socket comms spawn a thread, it will keep
// running forever. Ideally we should join() the thread but this works for
// now.
std::process::exit(0);
}

View File

@ -30,7 +30,12 @@ async fn trusted_dealer_journey() {
let mut buf = BufWriter::new(Vec::new());
let mut rng = thread_rng();
let coordinator_args = CoordinatorArgs::default();
let coordinator_args = CoordinatorArgs {
public_key_package: "-".to_string(),
signature: "-".to_string(),
message: "-".to_string(),
..Default::default()
};
let mut coordinator_comms = CoordinatorCLIComms {};
// For a CLI test we can use the same CLIComms instance
@ -132,6 +137,7 @@ async fn trusted_dealer_journey() {
let step_2_input = format!("{}\n", message);
let signing_package = coordinator::step_2::step_2(
&coordinator_args,
&mut step_2_input.as_bytes(),
&mut buf,
commitments_map.clone(),
@ -172,6 +178,7 @@ async fn trusted_dealer_journey() {
serde_json::to_string(&signature_shares[&participant_id_3]).unwrap()
);
let group_signature = coordinator::step_3::step_3(
&coordinator_args,
&mut coordinator_comms,
&mut step_3_input.as_bytes(),
&mut buf,