coordinator: use generics

This commit is contained in:
Conrado Gouvea 2024-06-21 18:06:15 -03:00 committed by natalie
parent ee7f341910
commit 50c4a21d13
14 changed files with 199 additions and 167 deletions

2
Cargo.lock generated
View File

@ -402,7 +402,9 @@ dependencies = [
"clap", "clap",
"exitcode", "exitcode",
"eyre", "eyre",
"frost-core",
"frost-ed25519", "frost-ed25519",
"frost-rerandomized",
"hex", "hex",
"itertools 0.13.0", "itertools 0.13.0",
"message-io", "message-io",

View File

@ -8,6 +8,8 @@ edition = "2021"
[dependencies] [dependencies]
async-trait = "0.1.80" async-trait = "0.1.80"
eyre = "0.6.12" eyre = "0.6.12"
frost-core = { version = "1.0.0", features = ["serde"] }
frost-rerandomized = { version = "1.0.0", features = ["serde"] }
frost-ed25519 = { version = "1.0.0", features = ["serde"] } frost-ed25519 = { version = "1.0.0", features = ["serde"] }
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "81c649c412e5b6ba56d491d2857f91fbd28adbc7", features = ["frost", "serde"] } reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "81c649c412e5b6ba56d491d2857f91fbd28adbc7", features = ["frost", "serde"] }
hex = { version = "0.4", features = ["serde"] } hex = { version = "0.4", features = ["serde"] }

View File

@ -3,6 +3,9 @@ use clap::Parser;
#[derive(Parser, Debug, Default)] #[derive(Parser, Debug, Default)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
pub struct Args { pub struct Args {
#[arg(short = 'C', long, default_value = "ed25519")]
pub ciphersuite: String,
/// CLI mode. If enabled, it will prompt for inputs from stdin /// CLI mode. If enabled, it will prompt for inputs from stdin
/// and print values to stdout, ignoring other flags. /// and print values to stdout, ignoring other flags.
/// If false, socket communication is enabled. /// If false, socket communication is enabled.
@ -32,7 +35,6 @@ pub struct Args {
/// The randomizer to use. Can be a file with the raw randomizer, empty, or /// 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 /// "-". If empty, a random one will be generated. If "-" is specified, then
/// it will be read from standard input as a hex string. /// it will be read from standard input as a hex string.
#[cfg(feature = "redpallas")]
#[arg(short = 'r', long, default_value = "")] #[arg(short = 'r', long, default_value = "")]
pub randomizer: String, pub randomizer: String,

View File

@ -1,5 +1,7 @@
use std::io::{BufRead, Write}; use std::io::{BufRead, Write};
use frost_rerandomized::RandomizedCiphersuite;
use crate::args::Args; use crate::args::Args;
use crate::comms::cli::CLIComms; use crate::comms::cli::CLIComms;
use crate::comms::http::HTTPComms; use crate::comms::http::HTTPComms;
@ -7,20 +9,18 @@ use crate::comms::socket::SocketComms;
use crate::comms::Comms; use crate::comms::Comms;
use crate::step_1::step_1; use crate::step_1::step_1;
use crate::step_2::step_2; use crate::step_2::step_2;
use crate::step_3::request_randomizer;
use crate::step_3::step_3; use crate::step_3::step_3;
#[cfg(feature = "redpallas")] pub async fn cli<C: RandomizedCiphersuite + 'static>(
use crate::step_3::request_randomizer;
pub async fn cli(
args: &Args, args: &Args,
reader: &mut impl BufRead, reader: &mut impl BufRead,
logger: &mut impl Write, logger: &mut impl Write,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
writeln!(logger, "\n=== STEP 1: CHOOSE PARTICIPANTS ===\n")?; writeln!(logger, "\n=== STEP 1: CHOOSE PARTICIPANTS ===\n")?;
let mut comms: Box<dyn Comms> = if args.cli { let mut comms: Box<dyn Comms<C>> = if args.cli {
Box::new(CLIComms {}) Box::new(CLIComms::new())
} else if args.http { } else if args.http {
Box::new(HTTPComms::new(args)) Box::new(HTTPComms::new(args))
} else { } else {
@ -41,8 +41,11 @@ pub async fn cli(
participants_config.commitments.clone(), participants_config.commitments.clone(),
)?; )?;
#[cfg(feature = "redpallas")] let randomizer = if args.ciphersuite == "redpallas" {
let randomizer = request_randomizer(args, reader, logger, &signing_package)?; Some(request_randomizer(args, reader, logger, &signing_package)?)
} else {
None
};
writeln!(logger, "=== STEP 3: BUILD GROUP SIGNATURE ===\n")?; writeln!(logger, "=== STEP 3: BUILD GROUP SIGNATURE ===\n")?;
@ -53,7 +56,6 @@ pub async fn cli(
logger, logger,
participants_config, participants_config,
&signing_package, &signing_package,
#[cfg(feature = "redpallas")]
randomizer, randomizer,
) )
.await?; .await?;

View File

@ -2,10 +2,7 @@ pub mod cli;
pub mod http; pub mod http;
pub mod socket; pub mod socket;
#[cfg(not(feature = "redpallas"))] use frost_core::{self as frost, Ciphersuite};
use frost_ed25519 as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas as frost;
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
@ -25,37 +22,35 @@ use frost::{
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(crate = "self::serde")] #[serde(crate = "self::serde")]
#[serde(bound = "C: Ciphersuite")]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum Message { pub enum Message<C: Ciphersuite> {
IdentifiedCommitments { IdentifiedCommitments {
identifier: Identifier, identifier: Identifier<C>,
commitments: SigningCommitments, commitments: SigningCommitments<C>,
}, },
#[cfg(not(feature = "redpallas"))]
SigningPackage(SigningPackage),
#[cfg(feature = "redpallas")]
SigningPackageAndRandomizer { SigningPackageAndRandomizer {
signing_package: SigningPackage, signing_package: SigningPackage<C>,
randomizer: frost::round2::Randomizer, randomizer: Option<frost_rerandomized::Randomizer<C>>,
}, },
SignatureShare(SignatureShare), SignatureShare(SignatureShare<C>),
} }
#[async_trait(?Send)] #[async_trait(?Send)]
pub trait Comms { pub trait Comms<C: Ciphersuite> {
async fn get_signing_commitments( async fn get_signing_commitments(
&mut self, &mut self,
input: &mut dyn BufRead, input: &mut dyn BufRead,
output: &mut dyn Write, output: &mut dyn Write,
pub_key_package: &PublicKeyPackage, pub_key_package: &PublicKeyPackage<C>,
num_of_participants: u16, num_of_participants: u16,
) -> Result<BTreeMap<Identifier, SigningCommitments>, Box<dyn Error>>; ) -> Result<BTreeMap<Identifier<C>, SigningCommitments<C>>, Box<dyn Error>>;
async fn get_signature_shares( async fn get_signature_shares(
&mut self, &mut self,
input: &mut dyn BufRead, input: &mut dyn BufRead,
output: &mut dyn Write, output: &mut dyn Write,
signing_package: &SigningPackage, signing_package: &SigningPackage<C>,
#[cfg(feature = "redpallas")] randomizer: frost::round2::Randomizer, randomizer: Option<frost_rerandomized::Randomizer<C>>,
) -> Result<BTreeMap<Identifier, SignatureShare>, Box<dyn Error>>; ) -> Result<BTreeMap<Identifier<C>, SignatureShare<C>>, Box<dyn Error>>;
} }

View File

@ -1,9 +1,8 @@
//! Command line interface implementation of the Comms trait. //! Command line interface implementation of the Comms trait.
#[cfg(not(feature = "redpallas"))] use frost_core as frost;
use frost_ed25519 as frost;
#[cfg(feature = "redpallas")] use frost_core::Ciphersuite;
use reddsa::frost::redpallas as frost;
use eyre::eyre; use eyre::eyre;
@ -18,23 +17,49 @@ use std::{
collections::BTreeMap, collections::BTreeMap,
error::Error, error::Error,
io::{BufRead, Write}, io::{BufRead, Write},
marker::PhantomData,
}; };
use super::Comms; use super::Comms;
pub struct CLIComms {} pub struct CLIComms<C: Ciphersuite> {
_phantom: PhantomData<C>,
}
impl<C> CLIComms<C>
where
C: Ciphersuite,
{
pub fn new() -> Self {
Self {
_phantom: Default::default(),
}
}
}
impl<C> Default for CLIComms<C>
where
C: Ciphersuite,
{
fn default() -> Self {
Self::new()
}
}
#[async_trait(?Send)] #[async_trait(?Send)]
impl Comms for CLIComms { impl<C> Comms<C> for CLIComms<C>
where
C: Ciphersuite + 'static,
{
async fn get_signing_commitments( async fn get_signing_commitments(
&mut self, &mut self,
input: &mut dyn BufRead, input: &mut dyn BufRead,
output: &mut dyn Write, output: &mut dyn Write,
pub_key_package: &PublicKeyPackage, pub_key_package: &PublicKeyPackage<C>,
num_of_participants: u16, num_of_participants: u16,
) -> Result<BTreeMap<Identifier, SigningCommitments>, Box<dyn Error>> { ) -> Result<BTreeMap<Identifier<C>, SigningCommitments<C>>, Box<dyn Error>> {
let mut participants_list = Vec::new(); let mut participants_list = Vec::new();
let mut commitments_list: BTreeMap<Identifier, SigningCommitments> = BTreeMap::new(); let mut commitments_list: BTreeMap<Identifier<C>, SigningCommitments<C>> = BTreeMap::new();
for i in 1..=num_of_participants { for i in 1..=num_of_participants {
writeln!(output, "Identifier for participant {:?} (hex encoded): ", i)?; writeln!(output, "Identifier for participant {:?} (hex encoded): ", i)?;
@ -60,10 +85,13 @@ impl Comms for CLIComms {
&mut self, &mut self,
input: &mut dyn BufRead, input: &mut dyn BufRead,
output: &mut dyn Write, output: &mut dyn Write,
signing_package: &SigningPackage, signing_package: &SigningPackage<C>,
#[cfg(feature = "redpallas")] _randomizer: frost::round2::Randomizer, randomizer: Option<frost_rerandomized::Randomizer<C>>,
) -> Result<BTreeMap<Identifier, SignatureShare>, Box<dyn Error>> { ) -> Result<BTreeMap<Identifier<C>, SignatureShare<C>>, Box<dyn Error>> {
let mut signatures_list: BTreeMap<Identifier, SignatureShare> = BTreeMap::new(); if randomizer.is_some() {
panic!("rerandomized not supported");
}
let mut signatures_list: BTreeMap<Identifier<C>, SignatureShare<C>> = BTreeMap::new();
for p in signing_package.signing_commitments().keys() { for p in signing_package.signing_commitments().keys() {
writeln!( writeln!(
output, output,
@ -80,20 +108,22 @@ impl Comms for CLIComms {
} }
} }
pub fn read_identifier(input: &mut dyn BufRead) -> Result<Identifier, Box<dyn Error>> { pub fn read_identifier<C: Ciphersuite + 'static>(
input: &mut dyn BufRead,
) -> Result<Identifier<C>, Box<dyn Error>> {
let mut identifier_input = String::new(); let mut identifier_input = String::new();
input.read_line(&mut identifier_input)?; input.read_line(&mut identifier_input)?;
let bytes = hex::decode(identifier_input.trim())?; let bytes = hex::decode(identifier_input.trim())?;
let serialization = bytes.try_into().map_err(|_| eyre!("Invalid Identifier"))?; let serialization = bytes.try_into().map_err(|_| eyre!("Invalid Identifier"))?;
let identifier = Identifier::deserialize(&serialization)?; let identifier = Identifier::<C>::deserialize(&serialization)?;
Ok(identifier) Ok(identifier)
} }
pub fn validate( pub fn validate<C: Ciphersuite>(
id: Identifier, id: Identifier<C>,
key_package: &PublicKeyPackage, key_package: &PublicKeyPackage<C>,
id_list: &[Identifier], id_list: &[Identifier<C>],
) -> Result<(), frost::Error> { ) -> Result<(), frost::Error<C>> {
if !key_package.verifying_shares().contains_key(&id) { if !key_package.verifying_shares().contains_key(&id) {
return Err(frost::Error::MalformedIdentifier); return Err(frost::Error::MalformedIdentifier);
}; // TODO: Error is actually that the identifier does not exist }; // TODO: Error is actually that the identifier does not exist

View File

@ -2,10 +2,9 @@
use async_trait::async_trait; use async_trait::async_trait;
#[cfg(not(feature = "redpallas"))] use frost_core as frost;
use frost_ed25519 as frost;
#[cfg(feature = "redpallas")] use frost_core::Ciphersuite;
use reddsa::frost::redpallas as frost;
use eyre::eyre; use eyre::eyre;
use server::Uuid; use server::Uuid;
@ -19,38 +18,41 @@ use std::{
collections::BTreeMap, collections::BTreeMap,
error::Error, error::Error,
io::{BufRead, Write}, io::{BufRead, Write},
marker::PhantomData,
time::Duration, time::Duration,
}; };
use super::Comms; use super::Comms;
use crate::args::Args; use crate::args::Args;
pub struct HTTPComms { pub struct HTTPComms<C: Ciphersuite> {
client: reqwest::Client, client: reqwest::Client,
host_port: String, host_port: String,
session_id: Option<Uuid>, session_id: Option<Uuid>,
_phantom: PhantomData<C>,
} }
impl HTTPComms { impl<C: Ciphersuite> HTTPComms<C> {
pub fn new(args: &Args) -> Self { pub fn new(args: &Args) -> Self {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
Self { Self {
client, client,
host_port: format!("http://{}:{}", args.ip, args.port), host_port: format!("http://{}:{}", args.ip, args.port),
session_id: None, session_id: None,
_phantom: Default::default(),
} }
} }
} }
#[async_trait(?Send)] #[async_trait(?Send)]
impl Comms for HTTPComms { impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
async fn get_signing_commitments( async fn get_signing_commitments(
&mut self, &mut self,
_input: &mut dyn BufRead, _input: &mut dyn BufRead,
_output: &mut dyn Write, _output: &mut dyn Write,
_pub_key_package: &PublicKeyPackage, _pub_key_package: &PublicKeyPackage<C>,
num_signers: u16, num_signers: u16,
) -> Result<BTreeMap<Identifier, SigningCommitments>, Box<dyn Error>> { ) -> Result<BTreeMap<Identifier<C>, SigningCommitments<C>>, Box<dyn Error>> {
let r = self let r = self
.client .client
.post(format!("{}/create_new_session", self.host_port)) .post(format!("{}/create_new_session", self.host_port))
@ -103,9 +105,9 @@ impl Comms for HTTPComms {
&mut self, &mut self,
_input: &mut dyn BufRead, _input: &mut dyn BufRead,
_output: &mut dyn Write, _output: &mut dyn Write,
signing_package: &SigningPackage, signing_package: &SigningPackage<C>,
#[cfg(feature = "redpallas")] randomizer: frost::round2::Randomizer, randomizer: Option<frost_rerandomized::Randomizer<C>>,
) -> Result<BTreeMap<Identifier, SignatureShare>, Box<dyn Error>> { ) -> Result<BTreeMap<Identifier<C>, SignatureShare<C>>, Box<dyn Error>> {
// Send SigningPackage to all participants // Send SigningPackage to all participants
eprintln!("Sending SigningPackage to participants..."); eprintln!("Sending SigningPackage to participants...");
@ -116,10 +118,7 @@ impl Comms for HTTPComms {
aux_msg: Default::default(), aux_msg: Default::default(),
session_id: self.session_id.unwrap(), session_id: self.session_id.unwrap(),
signing_package: vec![signing_package.try_into()?], signing_package: vec![signing_package.try_into()?],
#[cfg(feature = "redpallas")] randomizer: randomizer.map(|r| vec![r.into()]).unwrap_or_default(),
randomizer: vec![randomizer.into()],
#[cfg(not(feature = "redpallas"))]
randomizer: vec![],
}) })
.send() .send()
.await? .await?

View File

@ -1,10 +1,10 @@
//! Socket implementation of the Comms trait, using message-io. //! Socket implementation of the Comms trait, using message-io.
use async_trait::async_trait; use async_trait::async_trait;
#[cfg(not(feature = "redpallas"))]
use frost_ed25519 as frost; use frost_core as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas as frost; use frost_core::Ciphersuite;
use eyre::eyre; use eyre::eyre;
use message_io::{ use message_io::{
@ -22,18 +22,20 @@ use std::{
collections::BTreeMap, collections::BTreeMap,
error::Error, error::Error,
io::{BufRead, Write}, io::{BufRead, Write},
marker::PhantomData,
}; };
use super::{Comms, Message}; use super::{Comms, Message};
use crate::args::Args; use crate::args::Args;
pub struct SocketComms { pub struct SocketComms<C: Ciphersuite> {
input_rx: Receiver<(Endpoint, Vec<u8>)>, input_rx: Receiver<(Endpoint, Vec<u8>)>,
endpoints: BTreeMap<Identifier, Endpoint>, endpoints: BTreeMap<Identifier<C>, Endpoint>,
handler: NodeHandler<()>, handler: NodeHandler<()>,
_phantom: PhantomData<C>,
} }
impl SocketComms { impl<C: Ciphersuite> SocketComms<C> {
pub fn new(args: &Args) -> Self { pub fn new(args: &Args) -> Self {
let (handler, listener) = node::split::<()>(); let (handler, listener) = node::split::<()>();
let addr = format!("{}:{}", args.ip, args.port); let addr = format!("{}:{}", args.ip, args.port);
@ -48,6 +50,7 @@ impl SocketComms {
input_rx: rx, input_rx: rx,
endpoints: BTreeMap::new(), endpoints: BTreeMap::new(),
handler, handler,
_phantom: Default::default(),
}; };
// TODO: save handle // TODO: save handle
@ -71,14 +74,14 @@ impl SocketComms {
} }
#[async_trait(?Send)] #[async_trait(?Send)]
impl Comms for SocketComms { impl<C: Ciphersuite> Comms<C> for SocketComms<C> {
async fn get_signing_commitments( async fn get_signing_commitments(
&mut self, &mut self,
_input: &mut dyn BufRead, _input: &mut dyn BufRead,
_output: &mut dyn Write, _output: &mut dyn Write,
_pub_key_package: &PublicKeyPackage, _pub_key_package: &PublicKeyPackage<C>,
num_of_participants: u16, num_of_participants: u16,
) -> Result<BTreeMap<Identifier, SigningCommitments>, Box<dyn Error>> { ) -> Result<BTreeMap<Identifier<C>, SigningCommitments<C>>, Box<dyn Error>> {
self.endpoints = BTreeMap::new(); self.endpoints = BTreeMap::new();
let mut signing_commitments = BTreeMap::new(); let mut signing_commitments = BTreeMap::new();
eprintln!("Waiting for participants to send their commitments..."); eprintln!("Waiting for participants to send their commitments...");
@ -88,7 +91,7 @@ impl Comms for SocketComms {
.recv() .recv()
.await .await
.ok_or(eyre!("Did not receive all commitments"))?; .ok_or(eyre!("Did not receive all commitments"))?;
let message: Message = serde_json::from_slice(&data)?; let message: Message<C> = serde_json::from_slice(&data)?;
if let Message::IdentifiedCommitments { if let Message::IdentifiedCommitments {
identifier, identifier,
commitments, commitments,
@ -107,15 +110,12 @@ impl Comms for SocketComms {
&mut self, &mut self,
_input: &mut dyn BufRead, _input: &mut dyn BufRead,
_output: &mut dyn Write, _output: &mut dyn Write,
signing_package: &SigningPackage, signing_package: &SigningPackage<C>,
#[cfg(feature = "redpallas")] randomizer: frost::round2::Randomizer, randomizer: Option<frost_rerandomized::Randomizer<C>>,
) -> Result<BTreeMap<Identifier, SignatureShare>, Box<dyn Error>> { ) -> Result<BTreeMap<Identifier<C>, SignatureShare<C>>, Box<dyn Error>> {
// Send SigningPackage to all participants // Send SigningPackage to all participants
eprintln!("Sending SigningPackage to participants..."); eprintln!("Sending SigningPackage to participants...");
#[cfg(not(feature = "redpallas"))]
let data = serde_json::to_vec(&Message::SigningPackage(signing_package.clone()))?;
#[cfg(feature = "redpallas")]
let data = serde_json::to_vec(&Message::SigningPackageAndRandomizer { let data = serde_json::to_vec(&Message::SigningPackageAndRandomizer {
signing_package: signing_package.clone(), signing_package: signing_package.clone(),
randomizer, randomizer,
@ -138,7 +138,7 @@ impl Comms for SocketComms {
.recv() .recv()
.await .await
.ok_or(eyre!("Did not receive all commitments"))?; .ok_or(eyre!("Did not receive all commitments"))?;
let message: Message = serde_json::from_slice(&data)?; let message: Message<C> = serde_json::from_slice(&data)?;
if let Message::SignatureShare(signature_share) = message { if let Message::SignatureShare(signature_share) = message {
let identifier = self let identifier = self
.endpoints .endpoints

View File

@ -1,4 +1,3 @@
#[cfg(all(test, not(feature = "redpallas")))]
mod tests; mod tests;
use std::io; use std::io;
@ -13,7 +12,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut reader = Box::new(io::stdin().lock()); let mut reader = Box::new(io::stdin().lock());
let mut logger = io::stdout(); let mut logger = io::stdout();
let r = cli(&args, &mut reader, &mut logger).await; let r = if args.ciphersuite == "ed25519" {
cli::<frost_ed25519::Ed25519Sha512>(&args, &mut reader, &mut logger).await
} else if args.ciphersuite == "redpallas" {
cli::<reddsa::frost::redpallas::PallasBlake2b512>(&args, &mut reader, &mut logger).await
} else {
panic!("invalid ciphersuite");
};
// Force process to exit; since socket comms spawn a thread, it will keep // 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 // running forever. Ideally we should join() the thread but this works for

View File

@ -1,7 +1,4 @@
#[cfg(not(feature = "redpallas"))] use frost_core::{self as frost, Ciphersuite};
use frost_ed25519 as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas as frost;
use frost::{keys::PublicKeyPackage, round1::SigningCommitments, Identifier}; use frost::{keys::PublicKeyPackage, round1::SigningCommitments, Identifier};
@ -13,18 +10,18 @@ use std::{
use crate::{args::Args, comms::Comms, input::read_from_file_or_stdin}; use crate::{args::Args, comms::Comms, input::read_from_file_or_stdin};
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub struct ParticipantsConfig { pub struct ParticipantsConfig<C: Ciphersuite> {
pub commitments: BTreeMap<Identifier, SigningCommitments>, pub commitments: BTreeMap<Identifier<C>, SigningCommitments<C>>,
pub pub_key_package: PublicKeyPackage, pub pub_key_package: PublicKeyPackage<C>,
} }
// TODO: needs to include the coordinator's keys! // TODO: needs to include the coordinator's keys!
pub async fn step_1( pub async fn step_1<C: Ciphersuite>(
args: &Args, args: &Args,
comms: &mut dyn Comms, comms: &mut dyn Comms<C>,
reader: &mut dyn BufRead, reader: &mut dyn BufRead,
logger: &mut dyn Write, logger: &mut dyn Write,
) -> Result<ParticipantsConfig, Box<dyn std::error::Error>> { ) -> Result<ParticipantsConfig<C>, Box<dyn std::error::Error>> {
let participants = read_commitments(args, comms, reader, logger).await?; let participants = read_commitments(args, comms, reader, logger).await?;
print_participants(logger, &participants.commitments); print_participants(logger, &participants.commitments);
Ok(participants) Ok(participants)
@ -36,12 +33,12 @@ pub async fn step_1(
// 1. public key package // 1. public key package
// 2. number of participants // 2. number of participants
// 3. identifiers for all participants // 3. identifiers for all participants
async fn read_commitments( async fn read_commitments<C: Ciphersuite>(
args: &Args, args: &Args,
comms: &mut dyn Comms, comms: &mut dyn Comms<C>,
input: &mut dyn BufRead, input: &mut dyn BufRead,
logger: &mut dyn Write, logger: &mut dyn Write,
) -> Result<ParticipantsConfig, Box<dyn std::error::Error>> { ) -> Result<ParticipantsConfig<C>, Box<dyn std::error::Error>> {
let out = read_from_file_or_stdin( let out = read_from_file_or_stdin(
input, input,
logger, logger,
@ -49,7 +46,7 @@ async fn read_commitments(
&args.public_key_package, &args.public_key_package,
)?; )?;
let pub_key_package: PublicKeyPackage = serde_json::from_str(&out)?; let pub_key_package: PublicKeyPackage<C> = serde_json::from_str(&out)?;
let num_of_participants = if args.num_signers == 0 { let num_of_participants = if args.num_signers == 0 {
writeln!(logger, "The number of participants: ")?; writeln!(logger, "The number of participants: ")?;
@ -71,9 +68,9 @@ async fn read_commitments(
}) })
} }
pub fn print_participants( pub fn print_participants<C: Ciphersuite>(
logger: &mut dyn Write, logger: &mut dyn Write,
participants: &BTreeMap<Identifier, SigningCommitments>, participants: &BTreeMap<Identifier<C>, SigningCommitments<C>>,
) { ) {
writeln!(logger, "Selected participants: ",).unwrap(); writeln!(logger, "Selected participants: ",).unwrap();
@ -82,15 +79,14 @@ pub fn print_participants(
} }
} }
#[cfg(all(test, not(feature = "redpallas")))] #[cfg(test)]
mod tests { mod tests {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use frost::{ use frost_ed25519::{
keys::{PublicKeyPackage, VerifyingShare}, keys::{PublicKeyPackage, VerifyingShare},
Error, Identifier, VerifyingKey, Error, Identifier, VerifyingKey,
}; };
use frost_ed25519 as frost;
use hex::FromHex; use hex::FromHex;
use crate::comms::cli::validate; use crate::comms::cli::validate;

View File

@ -1,7 +1,4 @@
#[cfg(not(feature = "redpallas"))] use frost_core::{self as frost, Ciphersuite};
use frost_ed25519 as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas as frost;
use frost::{round1::SigningCommitments, Identifier, SigningPackage}; use frost::{round1::SigningCommitments, Identifier, SigningPackage};
@ -14,17 +11,17 @@ use std::{
use crate::args::Args; use crate::args::Args;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct CommitmentsConfig { pub struct CommitmentsConfig<C: Ciphersuite> {
pub message: Vec<u8>, pub message: Vec<u8>,
pub signer_commitments: BTreeMap<Identifier, SigningCommitments>, pub signer_commitments: BTreeMap<Identifier<C>, SigningCommitments<C>>,
} }
pub fn step_2( pub fn step_2<C: Ciphersuite>(
args: &Args, args: &Args,
input: &mut impl BufRead, input: &mut impl BufRead,
logger: &mut dyn Write, logger: &mut dyn Write,
commitments: BTreeMap<Identifier, SigningCommitments>, commitments: BTreeMap<Identifier<C>, SigningCommitments<C>>,
) -> Result<SigningPackage, Box<dyn std::error::Error>> { ) -> Result<SigningPackage<C>, Box<dyn std::error::Error>> {
let signing_package = request_message(args, input, logger, commitments)?; let signing_package = request_message(args, input, logger, commitments)?;
print_signing_package(logger, &signing_package); print_signing_package(logger, &signing_package);
Ok(signing_package) Ok(signing_package)
@ -32,12 +29,12 @@ pub fn step_2(
// Input required: // Input required:
// 1. message // 1. message
fn request_message( fn request_message<C: Ciphersuite>(
args: &Args, args: &Args,
input: &mut impl BufRead, input: &mut impl BufRead,
logger: &mut dyn Write, logger: &mut dyn Write,
commitments: BTreeMap<Identifier, SigningCommitments>, commitments: BTreeMap<Identifier<C>, SigningCommitments<C>>,
) -> Result<SigningPackage, Box<dyn std::error::Error>> { ) -> Result<SigningPackage<C>, Box<dyn std::error::Error>> {
let message = if args.message.is_empty() { let message = if args.message.is_empty() {
writeln!(logger, "The message to be signed (hex encoded)")?; writeln!(logger, "The message to be signed (hex encoded)")?;
@ -55,7 +52,10 @@ fn request_message(
Ok(signing_package) Ok(signing_package)
} }
fn print_signing_package(logger: &mut dyn Write, signing_package: &SigningPackage) { fn print_signing_package<C: Ciphersuite>(
logger: &mut dyn Write,
signing_package: &SigningPackage<C>,
) {
writeln!( writeln!(
logger, logger,
"Signing Package:\n{}", "Signing Package:\n{}",

View File

@ -1,9 +1,7 @@
#[cfg(not(feature = "redpallas"))] use frost_core::{self as frost, Ciphersuite};
use frost_ed25519 as frost;
#[cfg(feature = "redpallas")]
use reddsa::frost::redpallas as frost;
use frost::{Signature, SigningPackage}; use frost::{Signature, SigningPackage};
use frost_rerandomized::RandomizedCiphersuite;
use std::{ use std::{
fs, fs,
@ -12,16 +10,15 @@ use std::{
use crate::{args::Args, comms::Comms, step_1::ParticipantsConfig}; use crate::{args::Args, comms::Comms, step_1::ParticipantsConfig};
#[cfg(feature = "redpallas")] pub fn request_randomizer<C: RandomizedCiphersuite + 'static>(
pub fn request_randomizer(
args: &Args, args: &Args,
input: &mut impl BufRead, input: &mut impl BufRead,
logger: &mut dyn Write, logger: &mut dyn Write,
signing_package: &SigningPackage, signing_package: &SigningPackage<C>,
) -> Result<frost::round2::Randomizer, Box<dyn std::error::Error>> { ) -> Result<frost_rerandomized::Randomizer<C>, Box<dyn std::error::Error>> {
if args.randomizer.is_empty() { if args.randomizer.is_empty() {
let rng = rand::thread_rng(); let rng = rand::thread_rng();
return Ok(frost::round2::Randomizer::new(rng, signing_package)?); return Ok(frost_rerandomized::Randomizer::new(rng, signing_package)?);
}; };
let randomizer = if args.randomizer == "-" { let randomizer = if args.randomizer == "-" {
writeln!(logger, "Enter the randomizer (hex string):")?; writeln!(logger, "Enter the randomizer (hex string):")?;
@ -35,29 +32,28 @@ pub fn request_randomizer(
fs::read(&args.randomizer)? fs::read(&args.randomizer)?
}; };
Ok(frost::round2::Randomizer::deserialize( Ok(frost_rerandomized::Randomizer::deserialize(
&randomizer &randomizer
.try_into() .try_into()
.map_err(|_| frost::Error::MalformedIdentifier)?, .map_err(|_| frost::Error::<C>::MalformedIdentifier)?,
)?) )?)
} }
pub async fn step_3( pub async fn step_3<C: Ciphersuite>(
args: &Args, args: &Args,
comms: &mut dyn Comms, comms: &mut dyn Comms<C>,
input: &mut dyn BufRead, input: &mut dyn BufRead,
logger: &mut dyn Write, logger: &mut dyn Write,
participants: ParticipantsConfig, participants: ParticipantsConfig<C>,
signing_package: &SigningPackage, signing_package: &SigningPackage<C>,
#[cfg(feature = "redpallas")] randomizer: frost::round2::Randomizer, randomizer: Option<frost_rerandomized::Randomizer<C>>,
) -> Result<Signature, Box<dyn std::error::Error>> { ) -> Result<Signature<C>, Box<dyn std::error::Error>> {
let group_signature = request_inputs_signature_shares( let group_signature = request_inputs_signature_shares(
comms, comms,
input, input,
logger, logger,
participants, participants,
signing_package, signing_package,
#[cfg(feature = "redpallas")]
randomizer, randomizer,
) )
.await?; .await?;
@ -68,46 +64,47 @@ pub async fn step_3(
// Input required: // Input required:
// 1. number of signers (TODO: maybe pass this in?) // 1. number of signers (TODO: maybe pass this in?)
// 2. signatures for all signers // 2. signatures for all signers
async fn request_inputs_signature_shares( async fn request_inputs_signature_shares<C: Ciphersuite>(
comms: &mut dyn Comms, comms: &mut dyn Comms<C>,
input: &mut dyn BufRead, input: &mut dyn BufRead,
logger: &mut dyn Write, logger: &mut dyn Write,
participants: ParticipantsConfig, participants: ParticipantsConfig<C>,
signing_package: &SigningPackage, signing_package: &SigningPackage<C>,
#[cfg(feature = "redpallas")] randomizer: frost::round2::Randomizer, randomizer: Option<frost_rerandomized::Randomizer<C>>,
) -> Result<Signature, Box<dyn std::error::Error>> { ) -> Result<Signature<C>, Box<dyn std::error::Error>> {
let signatures_list = comms let signatures_list = comms
.get_signature_shares( .get_signature_shares(input, logger, signing_package, randomizer)
input,
logger,
signing_package,
#[cfg(feature = "redpallas")]
randomizer,
)
.await?; .await?;
#[cfg(feature = "redpallas")] let group_signature = if let Some(randomizer) = randomizer {
let randomizer_params = frost::RandomizedParams::from_randomizer( let randomizer_params = frost_rerandomized::RandomizedParams::<C>::from_randomizer(
participants.pub_key_package.verifying_key(), participants.pub_key_package.verifying_key(),
randomizer, randomizer,
); );
let group_signature = frost::aggregate( frost_rerandomized::aggregate(
signing_package, signing_package,
&signatures_list, &signatures_list,
&participants.pub_key_package, &participants.pub_key_package,
#[cfg(feature = "redpallas")]
&randomizer_params, &randomizer_params,
) )
.unwrap(); .unwrap()
} else {
frost::aggregate::<C>(
signing_package,
&signatures_list,
&participants.pub_key_package,
)
.unwrap()
};
Ok(group_signature) Ok(group_signature)
} }
fn print_signature( fn print_signature<C: Ciphersuite>(
args: &Args, args: &Args,
logger: &mut dyn Write, logger: &mut dyn Write,
group_signature: Signature, group_signature: Signature<C>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
if args.signature.is_empty() { if args.signature.is_empty() {
writeln!( writeln!(

View File

@ -1,4 +1,4 @@
#[cfg(test)] #![cfg(test)]
pub struct Helpers { pub struct Helpers {
pub participant_id_1: String, pub participant_id_1: String,

View File

@ -1,4 +1,5 @@
#[cfg(test)] #![cfg(test)]
use coordinator::{ use coordinator::{
args::Args, args::Args,
comms::cli::CLIComms, comms::cli::CLIComms,
@ -96,7 +97,7 @@ async fn check_step_1() {
.. ..
} = get_helpers(); } = get_helpers();
let mut comms = CLIComms {}; let mut comms = CLIComms::new();
let args = Args::default(); let args = Args::default();
let mut buf = BufWriter::new(Vec::new()); let mut buf = BufWriter::new(Vec::new());
@ -201,7 +202,7 @@ async fn check_step_3() {
.. ..
} = get_helpers(); } = get_helpers();
let mut comms = CLIComms {}; let mut comms = CLIComms::new();
let mut buf = BufWriter::new(Vec::new()); let mut buf = BufWriter::new(Vec::new());
let args = Args::default(); let args = Args::default();
@ -235,6 +236,7 @@ async fn check_step_3() {
&mut buf, &mut buf,
participants_config, participants_config,
&signing_package, &signing_package,
None,
) )
.await .await
.unwrap(); .unwrap();