From 8a0467eff5ad04723a4af8098191b0872f462e21 Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Fri, 13 Sep 2024 20:02:41 -0300 Subject: [PATCH 1/3] add frost-client trusted-dealer --- Cargo.lock | 6 ++ frost-client/Cargo.toml | 6 ++ frost-client/src/args.rs | 22 +++++ frost-client/src/config.rs | 18 ++++- frost-client/src/main.rs | 1 + frost-client/src/trusted_dealer.rs | 90 +++++++++++++++++++++ trusted-dealer/src/cli.rs | 62 +------------- trusted-dealer/src/lib.rs | 75 +++++++++++++++++ trusted-dealer/src/trusted_dealer_keygen.rs | 10 +-- 9 files changed, 226 insertions(+), 64 deletions(-) create mode 100644 frost-client/src/trusted_dealer.rs diff --git a/Cargo.lock b/Cargo.lock index 3f597882..f4282c36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1022,17 +1022,23 @@ dependencies = [ "directories", "dirs", "eyre", + "frost-core", + "frost-ed25519", "hex", "postcard", + "rand", + "reddsa 0.5.1 (git+https://github.com/ZcashFoundation/reddsa.git?rev=4d8c4bb337231e6e89117334d7c61dada589a953)", "reqwest", "rpassword", "serde", + "serde_json", "serdect", "server", "snow", "tempfile", "tokio", "toml", + "trusted-dealer", ] [[package]] diff --git a/frost-client/Cargo.toml b/frost-client/Cargo.toml index 1d614b10..40fa1a5a 100644 --- a/frost-client/Cargo.toml +++ b/frost-client/Cargo.toml @@ -10,6 +10,7 @@ serde = { version = "1.0", features = ["derive"] } snow = "0.9.6" toml = "0.8.19" server = { path = "../server" } +trusted-dealer = { path = "../trusted-dealer" } eyre = "0.6.12" rpassword = "7.3.1" directories = "5.0.1" @@ -20,3 +21,8 @@ serdect = "0.2.0" bech32 = "0.11.0" postcard = "1.0.10" tempfile = "3.12.0" +serde_json = "1.0" +frost-core = { version = "2.0.0-rc.0", features = ["serde"] } +frost-ed25519 = { version = "2.0.0-rc.0", features = ["serde"] } +reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "4d8c4bb337231e6e89117334d7c61dada589a953", features = ["frost"] } +rand = "0.8" diff --git a/frost-client/src/args.rs b/frost-client/src/args.rs index 2984ecee..98dda5f3 100644 --- a/frost-client/src/args.rs +++ b/frost-client/src/args.rs @@ -70,4 +70,26 @@ pub(crate) enum Command { #[arg(short, long)] config: Option, }, + TrustedDealer { + /// The path to the config file to manage. + /// + /// You can specify `num_signers` different paths. In that case, the + /// group information will be added to each config file. This is + /// particularly useful for tests, where all participants are run in the + /// same machine with a config file for each. + /// + /// If a single path is specified (or none, which will use + /// $HOME/.local/frost/credentials.toml), then it will run the trusted + /// dealer process via the FROST server (TODO: this is not supported yet) + #[arg(short, long)] + config: Vec, + #[arg(short = 'C', long, default_value = "ed25519")] + ciphersuite: String, + /// The threshold (minimum number of signers). + #[arg(short = 't', long, default_value_t = 2)] + threshold: u16, + /// The total number of participants (maximum number of signers). + #[arg(short = 'n', long, default_value_t = 3)] + num_signers: u16, + }, } diff --git a/frost-client/src/config.rs b/frost-client/src/config.rs index 11bcdfcf..82b404e0 100644 --- a/frost-client/src/config.rs +++ b/frost-client/src/config.rs @@ -31,7 +31,7 @@ pub struct Config { pub contact: BTreeMap, /// The FROST groups the user belongs to, keyed by (TODO) #[serde(default)] - pub groups: BTreeMap, + pub group: BTreeMap, } /// A registry entry. Note that the server URL is not in the struct; @@ -66,8 +66,16 @@ pub struct CommunicationKey { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Group { /// The encoded public key package for the group. + #[serde( + serialize_with = "serdect::slice::serialize_hex_lower_or_bin", + deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec" + )] pub public_key_package: Vec, /// The user's encodede key package for the group. + #[serde( + serialize_with = "serdect::slice::serialize_hex_lower_or_bin", + deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec" + )] pub key_package: Vec, /// The group participants, keyed by (TODO) pub participant: BTreeMap, @@ -77,8 +85,16 @@ pub struct Group { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Participant { /// The identifier of the participant in the group. + #[serde( + serialize_with = "serdect::slice::serialize_hex_lower_or_bin", + deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec" + )] pub identifier: Vec, /// The communication public key for the participant. + #[serde( + serialize_with = "serdect::slice::serialize_hex_lower_or_bin", + deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec" + )] pub pubkey: Vec, /// The server the participant is registered in, if any. pub server_url: Option, diff --git a/frost-client/src/main.rs b/frost-client/src/main.rs index b7ef5f15..4ad325c2 100644 --- a/frost-client/src/main.rs +++ b/frost-client/src/main.rs @@ -4,6 +4,7 @@ pub mod contact; pub mod init; pub mod login; pub mod write_atomic; +pub mod trusted_dealer; use std::error::Error; diff --git a/frost-client/src/trusted_dealer.rs b/frost-client/src/trusted_dealer.rs new file mode 100644 index 00000000..90540561 --- /dev/null +++ b/frost-client/src/trusted_dealer.rs @@ -0,0 +1,90 @@ +use eyre::{eyre, OptionExt}; +use std::{collections::BTreeMap, error::Error}; + +use frost_core::{keys::KeyPackage, Ciphersuite}; +use frost_ed25519::Ed25519Sha512; +use rand::thread_rng; +use trusted_dealer::MaybeIntoEvenY; + +use crate::{ + args::Command, + config::{Config, Group, Participant}, +}; + +pub(crate) fn trusted_dealer(args: &Command) -> Result<(), Box> { + let Command::TrustedDealer { ciphersuite, .. } = (*args).clone() else { + panic!("invalid Command"); + }; + + if ciphersuite == "ed25519" { + trusted_dealer_for_ciphersuite::(args) + } else { + Err(eyre!("unsupported ciphersuite").into()) + } +} + +pub(crate) fn trusted_dealer_for_ciphersuite( + args: &Command, +) -> Result<(), Box> { + let Command::TrustedDealer { + config, + ciphersuite: _, + threshold, + num_signers, + } = (*args).clone() + else { + panic!("invalid Command"); + }; + + if config.len() != num_signers as usize { + return Err( + eyre!("The `config` option must specify `num_signers` different config files").into(), + ); + } + + let trusted_dealer_config = trusted_dealer::Config { + max_signers: num_signers, + min_signers: threshold, + secret: vec![], + }; + let mut rng = thread_rng(); + + // Generate key shares + let (shares, public_key_package) = + trusted_dealer::trusted_dealer::(&trusted_dealer_config, &mut rng)?; + + // First pass over configs; create participants map + let mut participants = BTreeMap::new(); + for (identifier, path) in shares.keys().zip(config.iter()) { + let config = Config::read(Some(path.to_string()))?; + let pubkey = config + .communication_key + .ok_or_eyre("config not initialized")? + .pubkey; + let participant = Participant { + identifier: identifier.serialize(), + pubkey, + server_url: None, + username: None, + }; + participants.insert(hex::encode(identifier.serialize()), participant); + } + + // Second pass over configs; write group information + for (share, path) in shares.values().zip(config.iter()) { + let mut config = Config::read(Some(path.to_string()))?; + let key_package: KeyPackage = share.clone().try_into()?; + let group = Group { + key_package: postcard::to_allocvec(&key_package)?, + public_key_package: postcard::to_allocvec(&public_key_package)?, + participant: participants.clone(), + }; + config.group.insert( + hex::encode(public_key_package.verifying_key().serialize()?), + group, + ); + config.write()?; + } + + Ok(()) +} diff --git a/trusted-dealer/src/cli.rs b/trusted-dealer/src/cli.rs index b424beb8..8ae22095 100644 --- a/trusted-dealer/src/cli.rs +++ b/trusted-dealer/src/cli.rs @@ -1,59 +1,11 @@ use rand::thread_rng; -use std::collections::BTreeMap; use std::io::{BufRead, Write}; -use frost_core::keys::{IdentifierList, PublicKeyPackage, SecretShare}; -use frost_core::{Ciphersuite, Identifier}; -use reddsa::frost::redpallas::keys::EvenY; +use frost_core::Ciphersuite; use crate::args::Args; use crate::inputs::{print_values, request_inputs}; -use crate::trusted_dealer_keygen::{split_secret, trusted_dealer_keygen}; - -// The redpallas ciphersuite, when used for generating Orchard spending key -// signatures, requires ensuring public key have an even Y coordinate. Since the -// code uses generics, this trait is used to convert if needed depending on the -// ciphersuite. -// -// If you are adding a new ciphersuite to this tool which does note require -// this, just implement it and the default implementation (which does nothing) -// will suffice. See below. -pub trait MaybeIntoEvenY: Ciphersuite { - fn into_even_y( - secret_shares_and_public_key_package: ( - BTreeMap, SecretShare>, - PublicKeyPackage, - ), - ) -> ( - BTreeMap, SecretShare>, - PublicKeyPackage, - ) { - secret_shares_and_public_key_package - } -} - -// A ciphersuite that does not need the conversion. -impl MaybeIntoEvenY for frost_ed25519::Ed25519Sha512 {} - -impl MaybeIntoEvenY for reddsa::frost::redpallas::PallasBlake2b512 { - fn into_even_y( - (secret_shares, public_key_package): ( - BTreeMap, SecretShare>, - PublicKeyPackage, - ), - ) -> ( - BTreeMap, SecretShare>, - PublicKeyPackage, - ) { - let is_even = public_key_package.has_even_y(); - let public_key_package = public_key_package.into_even_y(Some(is_even)); - let secret_shares = secret_shares - .iter() - .map(|(i, s)| (*i, s.clone().into_even_y(Some(is_even)))) - .collect(); - (secret_shares, public_key_package) - } -} +use crate::{trusted_dealer, MaybeIntoEvenY}; pub fn cli( args: &Args, @@ -64,15 +16,9 @@ pub fn cli( let mut rng = thread_rng(); - let shares_and_package = if config.secret.is_empty() { - trusted_dealer_keygen(&config, IdentifierList::::Default, &mut rng)? - } else { - split_secret(&config, IdentifierList::::Default, &mut rng)? - }; - - let (shares, pubkeys) = MaybeIntoEvenY::into_even_y(shares_and_package); + let (shares, pubkeys) = trusted_dealer(&config, &mut rng)?; - print_values(args, &shares, &pubkeys, logger)?; + print_values::(args, &shares, &pubkeys, logger)?; Ok(()) } diff --git a/trusted-dealer/src/lib.rs b/trusted-dealer/src/lib.rs index 0bde2a27..830cdba9 100644 --- a/trusted-dealer/src/lib.rs +++ b/trusted-dealer/src/lib.rs @@ -2,3 +2,78 @@ pub mod args; pub mod cli; pub mod inputs; pub mod trusted_dealer_keygen; + +pub use inputs::Config; + +use rand::{CryptoRng, RngCore}; +use std::collections::BTreeMap; + +use frost_core::keys::{IdentifierList, PublicKeyPackage, SecretShare}; +use frost_core::{Ciphersuite, Identifier}; +use reddsa::frost::redpallas::keys::EvenY; + +use crate::trusted_dealer_keygen::{split_secret, trusted_dealer_keygen}; + +// The redpallas ciphersuite, when used for generating Orchard spending key +// signatures, requires ensuring public key have an even Y coordinate. Since the +// code uses generics, this trait is used to convert if needed depending on the +// ciphersuite. +// +// If you are adding a new ciphersuite to this tool which does note require +// this, just implement it and the default implementation (which does nothing) +// will suffice. See below. +pub trait MaybeIntoEvenY: Ciphersuite { + fn into_even_y( + secret_shares_and_public_key_package: ( + BTreeMap, SecretShare>, + PublicKeyPackage, + ), + ) -> ( + BTreeMap, SecretShare>, + PublicKeyPackage, + ) { + secret_shares_and_public_key_package + } +} + +// A ciphersuite that does not need the conversion. +impl MaybeIntoEvenY for frost_ed25519::Ed25519Sha512 {} + +impl MaybeIntoEvenY for reddsa::frost::redpallas::PallasBlake2b512 { + fn into_even_y( + (secret_shares, public_key_package): ( + BTreeMap, SecretShare>, + PublicKeyPackage, + ), + ) -> ( + BTreeMap, SecretShare>, + PublicKeyPackage, + ) { + let is_even = public_key_package.has_even_y(); + let public_key_package = public_key_package.into_even_y(Some(is_even)); + let secret_shares = secret_shares + .iter() + .map(|(i, s)| (*i, s.clone().into_even_y(Some(is_even)))) + .collect(); + (secret_shares, public_key_package) + } +} + +#[allow(clippy::type_complexity)] +pub fn trusted_dealer( + config: &Config, + rng: &mut R, +) -> Result< + (BTreeMap, SecretShare>, PublicKeyPackage), + Box, +> { + let shares_and_package = if config.secret.is_empty() { + trusted_dealer_keygen(config, IdentifierList::::Default, rng)? + } else { + split_secret(config, IdentifierList::::Default, rng)? + }; + + let (shares, pubkeys) = MaybeIntoEvenY::into_even_y(shares_and_package); + + Ok((shares, pubkeys)) +} diff --git a/trusted-dealer/src/trusted_dealer_keygen.rs b/trusted-dealer/src/trusted_dealer_keygen.rs index 3c8bde8b..09bbaef8 100644 --- a/trusted-dealer/src/trusted_dealer_keygen.rs +++ b/trusted-dealer/src/trusted_dealer_keygen.rs @@ -2,16 +2,16 @@ use frost_core::{self as frost, Ciphersuite}; use frost::keys::{IdentifierList, PublicKeyPackage, SecretShare}; use frost::{Error, Identifier, SigningKey}; -use rand::rngs::ThreadRng; +use rand::{CryptoRng, RngCore}; use std::collections::BTreeMap; use crate::inputs::Config; #[allow(clippy::type_complexity)] -pub fn trusted_dealer_keygen( +pub fn trusted_dealer_keygen( config: &Config, identifiers: IdentifierList, - rng: &mut ThreadRng, + rng: &mut R, ) -> Result<(BTreeMap, SecretShare>, PublicKeyPackage), Error> { let (shares, pubkeys) = frost::keys::generate_with_dealer( config.max_signers, @@ -28,10 +28,10 @@ pub fn trusted_dealer_keygen( } #[allow(clippy::type_complexity)] -pub fn split_secret( +pub fn split_secret( config: &Config, identifiers: IdentifierList, - rng: &mut ThreadRng, + rng: &mut R, ) -> Result<(BTreeMap, SecretShare>, PublicKeyPackage), Error> { let secret_key = SigningKey::deserialize(&config.secret)?; let (shares, pubkeys) = frost::keys::split( From 3cea6b6b0b446d375ac79dcb32e2df8d7fe897f3 Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Fri, 20 Sep 2024 19:03:50 -0300 Subject: [PATCH 2/3] also write contacts to configs; move URL from Participant to Group; add 'groups' --- frost-client/src/args.rs | 10 ++++ frost-client/src/ciphersuite_helper.rs | 72 ++++++++++++++++++++++++++ frost-client/src/config.rs | 47 ++++++++++++++--- frost-client/src/group.rs | 18 +++++++ frost-client/src/main.rs | 5 +- frost-client/src/trusted_dealer.rs | 22 +++++++- 6 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 frost-client/src/ciphersuite_helper.rs create mode 100644 frost-client/src/group.rs diff --git a/frost-client/src/args.rs b/frost-client/src/args.rs index 98dda5f3..b962122a 100644 --- a/frost-client/src/args.rs +++ b/frost-client/src/args.rs @@ -83,6 +83,9 @@ pub(crate) enum Command { /// dealer process via the FROST server (TODO: this is not supported yet) #[arg(short, long)] config: Vec, + /// The name of each participant. + #[arg(short = 'N', long, value_delimiter = ',')] + names: Vec, #[arg(short = 'C', long, default_value = "ed25519")] ciphersuite: String, /// The threshold (minimum number of signers). @@ -92,4 +95,11 @@ pub(crate) enum Command { #[arg(short = 'n', long, default_value_t = 3)] num_signers: u16, }, + /// Lists the groups the user is in. + Groups { + /// The path to the config file to manage. If not specified, it uses + /// $HOME/.local/frost/credentials.toml + #[arg(short, long)] + config: Option, + }, } diff --git a/frost-client/src/ciphersuite_helper.rs b/frost-client/src/ciphersuite_helper.rs new file mode 100644 index 00000000..87f5fd4d --- /dev/null +++ b/frost-client/src/ciphersuite_helper.rs @@ -0,0 +1,72 @@ +use std::{error::Error, marker::PhantomData}; + +use eyre::eyre; +use frost_core::{ + keys::{KeyPackage, PublicKeyPackage}, + Ciphersuite, +}; +use frost_ed25519::Ed25519Sha512; + +/// Additional information about a group, derived from the key packages. +#[derive(Debug, Clone)] +pub struct GroupInfo { + pub hex_verifying_key: String, + pub threshold: usize, + pub num_participants: usize, +} + +/// A trait that helps obtaining ciphersuite-dependent information. +pub trait CiphersuiteHelper { + fn group_info( + &self, + encoded_key_package: &[u8], + encoded_public_key_package: &[u8], + ) -> Result>; +} + +/// An implementation of CiphersuiteHelper that works for any Ciphersuite. +struct CiphersuiteHelperImpl { + _phantom: PhantomData, +} + +impl Default for CiphersuiteHelperImpl +where + C: Ciphersuite, +{ + fn default() -> Self { + Self { + _phantom: Default::default(), + } + } +} + +/// Get a CiphersuiteHelper for the given ciphersuite. +pub(crate) fn ciphersuite_helper( + ciphersuite_id: &str, +) -> Result, Box> { + if ciphersuite_id == "ed25519" { + return Ok(Box::new(CiphersuiteHelperImpl::::default())); + } + Err(eyre!("invalid ciphersuite ID").into()) +} + +impl CiphersuiteHelper for CiphersuiteHelperImpl +where + C: Ciphersuite + 'static, +{ + fn group_info( + &self, + encoded_key_package: &[u8], + encoded_public_key_package: &[u8], + ) -> Result> { + let key_package: KeyPackage = postcard::from_bytes(encoded_key_package)?; + let public_key_package: PublicKeyPackage = + postcard::from_bytes(encoded_public_key_package)?; + let hex_verifying_key = hex::encode(public_key_package.verifying_key().serialize()?); + Ok(GroupInfo { + hex_verifying_key, + threshold: *key_package.min_signers() as usize, + num_participants: public_key_package.verifying_shares().len(), + }) + } +} diff --git a/frost-client/src/config.rs b/frost-client/src/config.rs index 82b404e0..db9ab53f 100644 --- a/frost-client/src/config.rs +++ b/frost-client/src/config.rs @@ -8,10 +8,10 @@ use std::{ str::FromStr, }; -use eyre::eyre; +use eyre::{eyre, OptionExt}; use serde::{Deserialize, Serialize}; -use crate::{contact::Contact, write_atomic}; +use crate::{ciphersuite_helper::ciphersuite_helper, contact::Contact, write_atomic}; /// The config file, which is serialized with serde. #[derive(Clone, Debug, Serialize, Deserialize, Default)] @@ -29,11 +29,22 @@ pub struct Config { /// The address book of the user, keyed by each contact's name. #[serde(default)] pub contact: BTreeMap, - /// The FROST groups the user belongs to, keyed by (TODO) + /// The FROST groups the user belongs to, keyed by hex-encoded verifying key #[serde(default)] pub group: BTreeMap, } +impl Config { + pub fn contact_by_pubkey(&self, pubkey: &[u8]) -> Result> { + Ok(self + .contact + .values() + .find(|c| c.pubkey == pubkey) + .cloned() + .ok_or_eyre("contact not found")?) + } +} + /// A registry entry. Note that the server URL is not in the struct; /// it is the key in the `registry` map in Config. #[derive(Clone, Debug, Serialize, Deserialize)] @@ -65,6 +76,7 @@ pub struct CommunicationKey { // TODO: add a textual name for the group? #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Group { + pub ciphersuite: String, /// The encoded public key package for the group. #[serde( serialize_with = "serdect::slice::serialize_hex_lower_or_bin", @@ -77,11 +89,34 @@ pub struct Group { deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec" )] pub key_package: Vec, - /// The group participants, keyed by (TODO) + /// The server the participants are registered in, if any. + pub server_url: Option, + /// The group participants, keyed by hex-encoded identifier pub participant: BTreeMap, } -/// A FROST grou participant. +impl Group { + /// Returns a human-readable summary of the contact; used when it is + /// printed to the terminal. + pub fn as_human_readable_summary(&self, config: &Config) -> Result> { + let helper = ciphersuite_helper(&self.ciphersuite)?; + let info = helper.group_info(&self.key_package, &self.public_key_package)?; + let mut s = format!( + "Group with public key {}\nServer URL: {}\nThreshold: {}\nParticipants: {}\n", + info.hex_verifying_key, + self.server_url.clone().unwrap_or_default(), + info.threshold, + info.num_participants + ); + for participant in self.participant.values() { + let contact = config.contact_by_pubkey(&participant.pubkey)?; + s += &format!("\tName: {}", contact.name); + } + Ok(s) + } +} + +/// A FROST group participant. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Participant { /// The identifier of the participant in the group. @@ -96,8 +131,6 @@ pub struct Participant { deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec" )] pub pubkey: Vec, - /// The server the participant is registered in, if any. - pub server_url: Option, /// The username of the participant in the server, if any. pub username: Option, } diff --git a/frost-client/src/group.rs b/frost-client/src/group.rs new file mode 100644 index 00000000..ecea153a --- /dev/null +++ b/frost-client/src/group.rs @@ -0,0 +1,18 @@ +use std::error::Error; + +use crate::{args::Command, config::Config}; + +pub(crate) fn list(args: &Command) -> Result<(), Box> { + let Command::Groups { config } = (*args).clone() else { + panic!("invalid Command"); + }; + + let config = Config::read(config)?; + + for group in config.group.values() { + eprint!("{}", group.as_human_readable_summary(&config)?); + eprintln!(); + } + + Ok(()) +} diff --git a/frost-client/src/main.rs b/frost-client/src/main.rs index 4ad325c2..257fb75d 100644 --- a/frost-client/src/main.rs +++ b/frost-client/src/main.rs @@ -1,10 +1,12 @@ pub mod args; +pub mod ciphersuite_helper; pub mod config; pub mod contact; +pub mod group; pub mod init; pub mod login; -pub mod write_atomic; pub mod trusted_dealer; +pub mod write_atomic; use std::error::Error; @@ -21,6 +23,7 @@ async fn main() -> Result<(), Box> { Command::Export { .. } => contact::export(&args.command), Command::Import { .. } => contact::import(&args.command), Command::Contacts { .. } => contact::list(&args.command), + Command::Groups { .. } => group::list(&args.command), }?; Ok(()) diff --git a/frost-client/src/trusted_dealer.rs b/frost-client/src/trusted_dealer.rs index 90540561..dd7dcd5e 100644 --- a/frost-client/src/trusted_dealer.rs +++ b/frost-client/src/trusted_dealer.rs @@ -9,6 +9,7 @@ use trusted_dealer::MaybeIntoEvenY; use crate::{ args::Command, config::{Config, Group, Participant}, + contact::Contact, }; pub(crate) fn trusted_dealer(args: &Command) -> Result<(), Box> { @@ -31,6 +32,7 @@ pub(crate) fn trusted_dealer_for_ciphersuite = share.clone().try_into()?; let group = Group { + ciphersuite: C::ID.to_string(), key_package: postcard::to_allocvec(&key_package)?, public_key_package: postcard::to_allocvec(&public_key_package)?, participant: participants.clone(), + server_url: None, }; config.group.insert( hex::encode(public_key_package.verifying_key().serialize()?), group, ); + for c in &contacts { + config.contact.insert(c.name.clone(), c.clone()); + } config.write()?; } From 64427df39584ad3063a33b35608213255af7e7dd Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Thu, 26 Sep 2024 21:50:27 -0300 Subject: [PATCH 3/3] some missing stuff --- frost-client/src/ciphersuite_helper.rs | 2 +- frost-client/src/config.rs | 4 +--- frost-client/src/main.rs | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/frost-client/src/ciphersuite_helper.rs b/frost-client/src/ciphersuite_helper.rs index 87f5fd4d..de665066 100644 --- a/frost-client/src/ciphersuite_helper.rs +++ b/frost-client/src/ciphersuite_helper.rs @@ -44,7 +44,7 @@ where pub(crate) fn ciphersuite_helper( ciphersuite_id: &str, ) -> Result, Box> { - if ciphersuite_id == "ed25519" { + if ciphersuite_id == Ed25519Sha512::ID { return Ok(Box::new(CiphersuiteHelperImpl::::default())); } Err(eyre!("invalid ciphersuite ID").into()) diff --git a/frost-client/src/config.rs b/frost-client/src/config.rs index db9ab53f..49c726dd 100644 --- a/frost-client/src/config.rs +++ b/frost-client/src/config.rs @@ -2,8 +2,6 @@ use core::str; use std::{ collections::BTreeMap, error::Error, - fs::File, - os::unix::fs::PermissionsExt, path::{Path, PathBuf}, str::FromStr, }; @@ -110,7 +108,7 @@ impl Group { ); for participant in self.participant.values() { let contact = config.contact_by_pubkey(&participant.pubkey)?; - s += &format!("\tName: {}", contact.name); + s += &format!("\t{}\n", contact.name); } Ok(s) } diff --git a/frost-client/src/main.rs b/frost-client/src/main.rs index 257fb75d..5998a4c9 100644 --- a/frost-client/src/main.rs +++ b/frost-client/src/main.rs @@ -24,6 +24,7 @@ async fn main() -> Result<(), Box> { Command::Import { .. } => contact::import(&args.command), Command::Contacts { .. } => contact::list(&args.command), Command::Groups { .. } => group::list(&args.command), + Command::TrustedDealer { .. } => trusted_dealer::trusted_dealer(&args.command), }?; Ok(())