Skip to content

Commit

Permalink
Make server act as "aggregator" (#265)
Browse files Browse the repository at this point in the history
  • Loading branch information
conradoplg committed Aug 14, 2024
1 parent 4c6e860 commit 21a1531
Show file tree
Hide file tree
Showing 19 changed files with 828 additions and 864 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions coordinator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"

[dependencies]
async-trait = "0.1.81"
derivative = "2.2.0"
eyre = "0.6.12"
frost-core = { version = "2.0.0-rc.0", features = ["serde"] }
frost-rerandomized = { version = "2.0.0-rc.0", features = ["serde"] }
Expand All @@ -16,6 +17,7 @@ hex = { version = "0.4", features = ["serde"] }
thiserror = "1.0"
rand = "0.8"
serde_json = "1.0"
serdect = { version = "0.2.0" }
itertools = "0.13.0"
exitcode = "1.1.2"
clap = { version = "4.5.13", features = ["derive"] }
Expand Down
193 changes: 181 additions & 12 deletions coordinator/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
use std::{
env,
error::Error,
fs,
io::{BufRead, Write},
};

use clap::Parser;
use eyre::eyre;

use frost_core::{keys::PublicKeyPackage, Ciphersuite};
use frost_rerandomized::Randomizer;

#[derive(Parser, Debug, Default)]
use crate::input::read_from_file_or_stdin;

#[derive(Clone, Parser, Debug, Default)]
#[command(author, version, about, long_about = None)]
pub struct Args {
#[arg(short = 'C', long, default_value = "ed25519")]
Expand Down Expand Up @@ -32,26 +45,31 @@ pub struct Args {
#[arg(short = 'S', long, value_delimiter = ',')]
pub signers: Vec<String>,

/// The number of participants. If 0, will prompt for a value.
/// The number of participants. If `signers` is specified, it will use the
/// length of `signers`. Otherwise, if 0, it 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,
/// 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,
/// The messages to sign. Each instance can be a file with the raw message,
/// "" or "-". If "" or "-" is specified, then it will be read from standard
/// input as a hex string. If none are passed, a single one will be read
/// from standard input as a hex string.
#[arg(short = 'm', long)]
pub message: Vec<String>,

/// The randomizer to use. Can be a file with the raw randomizer, empty, or
/// "-". If empty, a random one will be generated. If "-" is specified, then
/// it will be read from standard input as a hex string.
#[arg(short = 'r', long, default_value = "")]
pub randomizer: String,
/// The randomizers to use. Each instance can be a file with the raw
/// randomizer, "" or "-". If "" or "-" is specified, then it will be read
/// from standard input as a hex string. If none are passed, random ones
/// will be generated. If one or more are passed, the number should match
/// the `message` parameter.
#[arg(short = 'r', long)]
pub randomizer: Vec<String>,

/// Where to write the generated raw bytes signature. If "-", the
/// human-readable hex-string is printed to stdout.
Expand All @@ -66,3 +84,154 @@ pub struct Args {
#[arg(short, long, default_value_t = 2744)]
pub port: u16,
}

#[derive(Clone, Debug)]
pub struct ProcessedArgs<C: Ciphersuite> {
pub ciphersuite: String,

/// CLI mode. If enabled, it will prompt for inputs from stdin
/// and print values to stdout, ignoring other flags.
/// If false, socket communication is enabled.
pub cli: bool,

/// HTTP mode. If enabled, it will use HTTP communication with a
/// FROST server.
pub http: bool,

/// The username to use in HTTP mode.
pub username: String,

/// The (actual) password to use in HTTP mode.
pub password: String,

/// The comma-separated usernames of the signers to use in HTTP mode.
/// If HTTP mode is enabled and this is empty, then the session ID
/// will be printed and will have to be shared manually.
pub signers: Vec<String>,

/// The number of participants.
pub num_signers: u16,

/// Public key package to use.
pub public_key_package: PublicKeyPackage<C>,

/// The messages to sign.
pub messages: Vec<Vec<u8>>,

/// The randomizers to use.
pub randomizers: Vec<Randomizer<C>>,

/// Where to write the generated raw bytes signature. If "-", the
/// human-readable hex-string is printed to stdout.
pub signature: String,

/// IP to bind to, if using online comms
pub ip: String,

/// Port to bind to, if using online comms
pub port: u16,
}

impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
/// Create a ProcessedArgs from a Args.
///
/// Validates inputs and reads/parses arguments.
pub fn new(
args: &Args,
input: &mut dyn BufRead,
output: &mut dyn Write,
) -> Result<Self, Box<dyn Error>> {
let password = if args.http {
env::var(&args.password).map_err(|_| eyre!("The password argument must specify the name of a environment variable containing the password"))?
} else {
String::new()
};

let num_signers = if !args.signers.is_empty() {
args.signers.len() as u16
} else if args.num_signers == 0 {
writeln!(output, "The number of participants: ")?;

let mut participants = String::new();
input.read_line(&mut participants)?;
participants.trim().parse::<u16>()?
} else {
args.num_signers
};

let out = read_from_file_or_stdin(
input,
output,
"public key package",
&args.public_key_package,
)?;

let public_key_package: PublicKeyPackage<C> = serde_json::from_str(&out)?;

let messages = if args.message.is_empty() {
writeln!(output, "The message to be signed (hex encoded)")?;
let mut msg = String::new();
input.read_line(&mut msg)?;
vec![hex::decode(msg.trim())?]
} else {
args.message
.iter()
.map(|filename| {
let msg = if filename == "-" || filename.is_empty() {
writeln!(output, "The message to be signed (hex encoded)")?;
let mut msg = String::new();
input.read_line(&mut msg)?;
hex::decode(msg.trim())?
} else {
eprintln!("Reading message from {}...", &filename);
fs::read(filename)?
};
Ok(msg)
})
.collect::<Result<_, Box<dyn Error>>>()?
};

println!("Processing randomizer {:?}", args.randomizer);
let randomizers = if args.ciphersuite == "redpallas" {
if args.randomizer.is_empty() {
Vec::new()
} else {
args.randomizer
.iter()
.map(|filename| {
let randomizer = if filename == "-" || filename.is_empty() {
writeln!(output, "Enter the randomizer (hex string):")?;
let mut randomizer = String::new();
input.read_line(&mut randomizer)?;
let bytes = hex::decode(randomizer.trim())?;
frost_rerandomized::Randomizer::deserialize(&bytes)?
} else {
eprintln!("Reading randomizer from {}...", &filename);
let bytes = fs::read(filename)?;
frost_rerandomized::Randomizer::deserialize(&bytes)?
};
Ok(randomizer)
})
.collect::<Result<_, Box<dyn Error>>>()?
}
} else {
Vec::new()
};

Ok(ProcessedArgs {
ciphersuite: args.ciphersuite.clone(),
cli: args.cli,
http: args.http,
username: args.username.clone(),
password,
signers: args.signers.clone(),
num_signers,
public_key_package,
messages,
randomizers,
signature: args.signature.clone(),
ip: args.ip.clone(),
port: args.port,
})
}
}
24 changes: 7 additions & 17 deletions coordinator/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,50 @@ use std::io::{BufRead, Write};
use frost_rerandomized::RandomizedCiphersuite;

use crate::args::Args;
use crate::args::ProcessedArgs;
use crate::comms::cli::CLIComms;
use crate::comms::http::HTTPComms;
use crate::comms::socket::SocketComms;
use crate::comms::Comms;
use crate::step_1::step_1;
use crate::step_2::step_2;
use crate::step_3::request_randomizer;
use crate::step_3::step_3;

pub async fn cli<C: RandomizedCiphersuite + 'static>(
args: &Args,
reader: &mut impl BufRead,
logger: &mut impl Write,
) -> Result<(), Box<dyn std::error::Error>> {
let pargs = ProcessedArgs::<C>::new(args, reader, logger)?;

writeln!(logger, "\n=== STEP 1: CHOOSE PARTICIPANTS ===\n")?;

let mut comms: Box<dyn Comms<C>> = if args.cli {
Box::new(CLIComms::new())
} else if args.http {
Box::new(HTTPComms::new(args)?)
Box::new(HTTPComms::new(&pargs)?)
} else {
Box::new(SocketComms::new(args))
};

let participants_config = step_1(args, &mut *comms, reader, logger).await?;
let participants_config = step_1(&pargs, &mut *comms, reader, logger).await?;

writeln!(
logger,
"=== STEP 2: CHOOSE MESSAGE AND GENERATE COMMITMENT PACKAGE ===\n"
)?;

let signing_package = step_2(
args,
reader,
logger,
participants_config.commitments.clone(),
)?;

let randomizer = if args.ciphersuite == "redpallas" {
Some(request_randomizer(args, reader, logger, &signing_package)?)
} else {
None
};
let signing_package = step_2(&pargs, logger, participants_config.commitments.clone())?;

writeln!(logger, "=== STEP 3: BUILD GROUP SIGNATURE ===\n")?;

step_3(
args,
&pargs,
&mut *comms,
reader,
logger,
participants_config,
&signing_package,
randomizer,
)
.await?;

Expand Down
Loading

0 comments on commit 21a1531

Please sign in to comment.