frost-client: add encryption and authentication (#336)

This commit is contained in:
Conrado Gouvea 2024-11-20 12:11:47 -03:00 committed by GitHub
parent a4011301ce
commit 36772857ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 415 additions and 41 deletions

6
Cargo.lock generated
View File

@ -621,6 +621,7 @@ dependencies = [
"hex",
"itertools",
"message-io",
"participant",
"rand",
"reddsa",
"reqwest",
@ -628,6 +629,7 @@ dependencies = [
"serde_json",
"serdect",
"server",
"snow",
"thiserror 2.0.3",
"tokio",
]
@ -811,7 +813,7 @@ checksum = "74ef43543e701c01ad77d3a5922755c6a1d71b22d942cb8042be4994b380caff"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.72",
"syn 2.0.87",
]
[[package]]
@ -1056,6 +1058,7 @@ dependencies = [
"frost-ed25519",
"frost-rerandomized",
"hex",
"itertools",
"participant",
"postcard",
"rand",
@ -2028,6 +2031,7 @@ dependencies = [
"serde_json",
"serdect",
"server",
"snow",
"tokio",
]

View File

@ -23,9 +23,11 @@ exitcode = "1.1.2"
clap = { version = "4.5.20", features = ["derive"] }
reqwest = { version = "0.12.8", features = ["json"] }
server = { path = "../server" }
participant = { path = "../participant" }
tokio = { version = "1", features = ["full"] }
message-io = "0.18"
rpassword = "7.3.1"
snow = "0.9.6"
[features]
default = []

View File

@ -3,6 +3,7 @@ use std::{
error::Error,
fs,
io::{BufRead, Write},
rc::Rc,
};
use clap::Parser;
@ -87,7 +88,7 @@ pub struct Args {
pub port: u16,
}
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct ProcessedArgs<C: Ciphersuite> {
/// CLI mode. If enabled, it will prompt for inputs from stdin
/// and print values to stdout, ignoring other flags.
@ -136,6 +137,18 @@ pub struct ProcessedArgs<C: Ciphersuite> {
/// Port to bind to, if using socket comms.
/// Port to connect to, if using HTTP mode.
pub port: u16,
/// The coordinator's communication private key. Specifying this along with
/// `comm_participant_pubkey_getter` enables encryption.
pub comm_privkey: Option<Vec<u8>>,
/// A function that returns the public key for a given username, or None
/// if not available.
// It is a `Rc<dyn Fn>` to make it easier to use;
// using `fn()` would preclude using closures and using generics would
// require a lot of code change for something simple.
#[allow(clippy::type_complexity)]
pub comm_participant_pubkey_getter: Option<Rc<dyn Fn(&str) -> Option<Vec<u8>>>>,
}
impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
@ -193,6 +206,8 @@ impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
ip: args.ip.clone(),
port: args.port,
authentication_token: None,
comm_privkey: None,
comm_participant_pubkey_getter: None,
})
}
}

View File

@ -10,13 +10,13 @@ use std::{
};
use async_trait::async_trait;
use eyre::eyre;
use eyre::{eyre, OptionExt};
use frost_core::{
keys::PublicKeyPackage, round1::SigningCommitments, round2::SignatureShare, Ciphersuite,
Identifier, SigningPackage,
};
use itertools::Itertools;
use participant::comms::http::Noise;
use server::{Msg, SendCommitmentsArgs, SendSignatureSharesArgs, SendSigningPackageArgs, Uuid};
use super::Comms;
@ -268,6 +268,10 @@ pub struct HTTPComms<C: Ciphersuite> {
state: SessionState<C>,
usernames: HashMap<String, Identifier<C>>,
should_logout: bool,
// The "send" Noise objects by username of recipients.
send_noise: Option<HashMap<String, Noise>>,
// The "receive" Noise objects by username of senders.
recv_noise: Option<HashMap<String, Noise>>,
_phantom: PhantomData<C>,
}
@ -284,9 +288,51 @@ impl<C: Ciphersuite> HTTPComms<C> {
state: SessionState::new(args.messages.len(), args.num_signers as usize),
usernames: Default::default(),
should_logout: args.authentication_token.is_none(),
send_noise: None,
recv_noise: None,
_phantom: Default::default(),
})
}
// Encrypts a message for a given recipient if encryption is enabled.
fn encrypt_if_needed(
&mut self,
recipient: &str,
msg: Vec<u8>,
) -> Result<Vec<u8>, Box<dyn Error>> {
if let Some(noise_map) = &mut self.send_noise {
let noise = noise_map
.get_mut(recipient)
.ok_or_eyre("unknown recipient")?;
let mut encrypted = vec![0; 65535];
let len = noise.write_message(&msg, &mut encrypted)?;
encrypted.truncate(len);
Ok(encrypted)
} else {
Ok(msg)
}
}
// Decrypts a message if encryption is enabled.
// Note that this authenticates the `sender` in the `Msg` struct; if the
// sender is tampered with, the message would fail to decrypt.
fn decrypt_if_needed(&mut self, msg: Msg) -> Result<Msg, Box<dyn Error>> {
if let Some(noise_map) = &mut self.recv_noise {
let noise = noise_map
.get_mut(&msg.sender)
.ok_or_eyre("unknown sender")?;
let mut decrypted = vec![0; 65535];
decrypted.resize(65535, 0);
let len = noise.read_message(&msg.msg, &mut decrypted)?;
decrypted.truncate(len);
Ok(Msg {
sender: msg.sender,
msg: decrypted,
})
} else {
Ok(msg)
}
}
}
#[async_trait(?Send)]
@ -336,6 +382,49 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
}
self.session_id = Some(r.session_id);
self.num_signers = num_signers;
// If encryption is enabled, create the Noise objects
(self.send_noise, self.recv_noise) = if let (
Some(comm_privkey),
Some(comm_participant_pubkey_getter),
) = (
&self.args.comm_privkey,
&self.args.comm_participant_pubkey_getter,
) {
let mut send_noise_map = HashMap::new();
let mut recv_noise_map = HashMap::new();
for username in &self.args.signers {
let comm_participant_pubkey = comm_participant_pubkey_getter(username).ok_or_eyre("A participant in specified FROST session is not registered in the coordinator's address book")?;
let builder = snow::Builder::new(
"Noise_K_25519_ChaChaPoly_BLAKE2s"
.parse()
.expect("should be a valid cipher"),
);
let send_noise = Noise::new(
builder
.local_private_key(comm_privkey)
.remote_public_key(&comm_participant_pubkey)
.build_initiator()?,
);
let builder = snow::Builder::new(
"Noise_K_25519_ChaChaPoly_BLAKE2s"
.parse()
.expect("should be a valid cipher"),
);
let recv_noise = Noise::new(
builder
.local_private_key(comm_privkey)
.remote_public_key(&comm_participant_pubkey)
.build_responder()?,
);
send_noise_map.insert(username.clone(), send_noise);
recv_noise_map.insert(username.clone(), recv_noise);
}
(Some(send_noise_map), Some(recv_noise_map))
} else {
(None, None)
};
eprint!("Waiting for participants to send their commitments...");
loop {
@ -352,6 +441,7 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
.json::<server::ReceiveOutput>()
.await?;
for msg in r.msgs {
let msg = self.decrypt_if_needed(msg)?;
self.state.recv(msg)?;
}
tokio::time::sleep(Duration::from_secs(2)).await;
@ -382,19 +472,27 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
aux_msg: Default::default(),
randomizer: randomizer.map(|r| vec![r]).unwrap_or_default(),
};
let _r = self
.client
.post(format!("{}/send", self.host_port))
.bearer_auth(&self.access_token)
.json(&server::SendArgs {
session_id: self.session_id.unwrap(),
recipients: self.usernames.keys().cloned().collect_vec(),
msg: serde_json::to_vec(&send_signing_package_args)?,
})
.send()
.await?
.bytes()
.await?;
// We need to send a message separately for each recipient even if the
// message is the same, because they are (possibly) encrypted
// individually for each recipient.
let usernames: Vec<_> = self.usernames.keys().cloned().collect();
for recipient in usernames {
let msg = self
.encrypt_if_needed(&recipient, serde_json::to_vec(&send_signing_package_args)?)?;
let _r = self
.client
.post(format!("{}/send", self.host_port))
.bearer_auth(&self.access_token)
.json(&server::SendArgs {
session_id: self.session_id.unwrap(),
recipients: vec![recipient.clone()],
msg,
})
.send()
.await?
.bytes()
.await?;
}
eprintln!("Waiting for participants to send their SignatureShares...");
@ -412,6 +510,7 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
.json::<server::ReceiveOutput>()
.await?;
for msg in r.msgs {
let msg = self.decrypt_if_needed(msg)?;
self.state.recv(msg)?;
}
tokio::time::sleep(Duration::from_secs(2)).await;

View File

@ -30,3 +30,4 @@ frost-rerandomized = { version = "2.0.0-rc.0", features = ["serde"] }
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "ed49e9ca0699a6450f6d4a9fe62ff168f5ea1ead", features = ["frost"] }
rand = "0.8"
stable-eyre = "0.2"
itertools = "0.13.0"

View File

@ -83,9 +83,18 @@ pub(crate) enum Command {
/// dealer process via the FROST server (TODO: this is not supported yet)
#[arg(short, long)]
config: Vec<String>,
/// The name of each participant.
/// The comma-separated name of each participant.
#[arg(short = 'N', long, value_delimiter = ',')]
names: Vec<String>,
/// The comma-separated username of each participant in the same order
/// as `names`. Note: these won't be checked in the server.
#[arg(short, long, value_delimiter = ',')]
usernames: Vec<String>,
/// The server URL, if desired. Note that this does not connect to the
/// server; it will just associated the server URL with the group in the
/// config file.
#[arg(short, long)]
server_url: Option<String>,
#[arg(short = 'C', long, default_value = "ed25519")]
ciphersuite: String,
/// The threshold (minimum number of signers).
@ -107,11 +116,11 @@ pub(crate) enum Command {
/// $HOME/.local/frost/credentials.toml
#[arg(short, long)]
config: Option<String>,
/// The server URL to use. You can use a substring of the URL. It will
/// use the username previously logged in via the `login` subcommand for
/// the given server.
/// The server URL to use. If not specified, it will use the server URL
/// for the specified group, if any. It will use the username previously
/// logged in via the `login` subcommand for the given server.
#[arg(short, long)]
server_url: String,
server_url: Option<String>,
/// The group to use, identified by the group public key (use `groups`
/// to list)
#[arg(short, long)]
@ -142,11 +151,11 @@ pub(crate) enum Command {
/// $HOME/.local/frost/credentials.toml
#[arg(short, long)]
config: Option<String>,
/// The server URL to use. You can use a substring of the URL. It will
/// use the username previously logged in via the `login` subcommand for
/// the given server.
/// The server URL to use. If not specified, it will use the server URL
/// for the specified group, if any. It will use the username previously
/// logged in via the `login` subcommand for the given server.
#[arg(short, long)]
server_url: String,
server_url: Option<String>,
/// The group to use, identified by the group public key (use `groups`
/// to list)
#[arg(short, long)]

View File

@ -1,4 +1,5 @@
use std::error::Error;
use std::rc::Rc;
use coordinator::cli::cli_for_processed_args;
use eyre::eyre;
@ -57,6 +58,8 @@ pub(crate) async fn run_for_ciphersuite<C: RandomizedCiphersuite + 'static>(
let mut input = Box::new(std::io::stdin().lock());
let mut output = std::io::stdout();
let server_url =
server_url.unwrap_or(group.server_url.clone().ok_or_eyre("server-url required")?);
let server_url_parsed =
Url::parse(&format!("http://{}", server_url)).wrap_err("error parsing server-url")?;
@ -65,6 +68,7 @@ pub(crate) async fn run_for_ciphersuite<C: RandomizedCiphersuite + 'static>(
.get(&server_url)
.ok_or_eyre("Not registered in the given server")?;
let group_participants = group.participant.clone();
let pargs = coordinator::args::ProcessedArgs {
cli: false,
http: true,
@ -87,6 +91,19 @@ pub(crate) async fn run_for_ciphersuite<C: RandomizedCiphersuite + 'static>(
.clone()
.ok_or_eyre("Not logged in in the given server")?,
),
comm_privkey: Some(
config
.communication_key
.ok_or_eyre("user not initialized")?
.privkey
.clone(),
),
comm_participant_pubkey_getter: Some(Rc::new(move |participant_username| {
group_participants
.values()
.find(|p| p.username == Some(participant_username.to_string()))
.map(|p| p.pubkey.clone())
})),
};
cli_for_processed_args(pargs, &mut input, &mut output).await?;

View File

@ -1,4 +1,5 @@
use std::error::Error;
use std::rc::Rc;
use eyre::eyre;
use eyre::Context;
@ -53,6 +54,8 @@ pub(crate) async fn run_for_ciphersuite<C: RandomizedCiphersuite + 'static>(
let mut input = Box::new(std::io::stdin().lock());
let mut output = std::io::stdout();
let server_url =
server_url.unwrap_or(group.server_url.clone().ok_or_eyre("server-url required")?);
let server_url_parsed =
Url::parse(&format!("http://{}", server_url)).wrap_err("error parsing server-url")?;
@ -61,6 +64,7 @@ pub(crate) async fn run_for_ciphersuite<C: RandomizedCiphersuite + 'static>(
.get(&server_url)
.ok_or_eyre("Not registered in the given server")?;
let group_participants = group.participant.clone();
let pargs = participant::args::ProcessedArgs {
cli: false,
http: true,
@ -79,6 +83,19 @@ pub(crate) async fn run_for_ciphersuite<C: RandomizedCiphersuite + 'static>(
.ok_or_eyre("Not logged in in the given server")?,
),
session_id: String::new(),
comm_privkey: Some(
config
.communication_key
.ok_or_eyre("user not initialized")?
.privkey
.clone(),
),
comm_coordinator_pubkey_getter: Some(Rc::new(move |coordinator_username| {
group_participants
.values()
.find(|p| p.username == Some(coordinator_username.to_string()))
.map(|p| p.pubkey.clone())
})),
};
cli_for_processed_args(pargs, &mut input, &mut output).await?;

View File

@ -1,6 +1,7 @@
use std::{collections::BTreeMap, error::Error};
use eyre::{eyre, OptionExt};
use itertools::izip;
use rand::thread_rng;
use frost_core::{keys::KeyPackage, Ciphersuite};
@ -36,6 +37,8 @@ pub(crate) fn trusted_dealer_for_ciphersuite<C: Ciphersuite + MaybeIntoEvenY + '
threshold,
num_signers,
names,
usernames,
server_url,
} = (*args).clone()
else {
panic!("invalid Command");
@ -64,16 +67,28 @@ pub(crate) fn trusted_dealer_for_ciphersuite<C: Ciphersuite + MaybeIntoEvenY + '
// First pass over configs; create participants map
let mut participants = BTreeMap::new();
let mut contacts = Vec::new();
for ((identifier, path), name) in shares.keys().zip(config.iter()).zip(names.iter()) {
for (idx, (identifier, path, name)) in
izip!(shares.keys(), config.iter(), names.iter()).enumerate()
{
let config = Config::read(Some(path.to_string()))?;
let pubkey = config
.communication_key
.ok_or_eyre("config not initialized")?
.pubkey;
let username = if server_url.is_some() {
Some(
usernames
.get(idx)
.ok_or_eyre("must specify usernames of all users")?
.clone(),
)
} else {
None
};
let participant = Participant {
identifier: identifier.serialize(),
pubkey: pubkey.clone(),
username: None,
username,
};
participants.insert(hex::encode(identifier.serialize()), participant);
let contact = Contact {
@ -95,7 +110,7 @@ pub(crate) fn trusted_dealer_for_ciphersuite<C: Ciphersuite + MaybeIntoEvenY + '
key_package: postcard::to_allocvec(&key_package)?,
public_key_package: postcard::to_allocvec(&public_key_package)?,
participant: participants.clone(),
server_url: None,
server_url: server_url.clone(),
};
config.group.insert(
hex::encode(public_key_package.verifying_key().serialize()?),

View File

@ -24,6 +24,7 @@ message-io = "0.18"
reqwest = { version = "0.12.8", features = ["json"] }
server = { path = "../server" }
rpassword = "7.3.1"
snow = "0.9.6"
[features]
default = []

View File

@ -2,6 +2,7 @@ use std::{
env,
error::Error,
io::{BufRead, Write},
rc::Rc,
};
use clap::Parser;
@ -58,7 +59,7 @@ pub struct Args {
pub session_id: String,
}
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct ProcessedArgs<C: Ciphersuite> {
/// CLI mode. If enabled, it will prompt for inputs from stdin
/// and print values to stdout, ignoring other flags.
@ -92,6 +93,18 @@ pub struct ProcessedArgs<C: Ciphersuite> {
/// Optional Session ID
pub session_id: String,
/// The participant's communication private key. Specifying this along with
/// `comm_coordinator_pubkey_getter` enables encryption.
pub comm_privkey: Option<Vec<u8>>,
/// A function that returns the public key for the given username of the
/// coordinator, or None if not available.
// It is a `Rc<dyn Fn>` to make it easier to use;
// using `fn()` would preclude using closures and using generics would
// require a lot of code change for something simple.
#[allow(clippy::type_complexity)]
pub comm_coordinator_pubkey_getter: Option<Rc<dyn Fn(&str) -> Option<Vec<u8>>>>,
}
impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
@ -128,6 +141,8 @@ impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
port: args.port,
authentication_token: None,
session_id: args.session_id.clone(),
comm_privkey: None,
comm_coordinator_pubkey_getter: None,
})
}
}

View File

@ -8,22 +8,105 @@ use std::{
};
use async_trait::async_trait;
use eyre::eyre;
use eyre::{eyre, OptionExt};
use frost_core::{
self as frost, round1::SigningCommitments, round2::SignatureShare, Ciphersuite, Identifier,
};
use snow::{HandshakeState, TransportState};
use super::Comms;
use crate::args::ProcessedArgs;
/// A Noise state.
///
/// This abstracts away some awkwardness in the `snow` crate API, which
/// requires explicitly marking the handshake as finished and switching
/// to a new state object after the first message is sent.
pub struct Noise {
// These should ideally be a enum, but that makes the implementation much
// more awkward so I went with easier option which is using two Options.
// Only one of them must has a value at any given time.
/// The handshake state; None after handshake is complete.
handshake_state: Option<HandshakeState>,
/// The transport state; None before handshake is complete.
transport_state: Option<TransportState>,
}
impl Noise {
/// Create a new Noise state from a HandshakeState created with the `snow`
/// crate.
pub fn new(handshake_state: HandshakeState) -> Self {
Self {
handshake_state: Some(handshake_state),
transport_state: None,
}
}
/// Write (i.e. encrypts) a message following the same API as `snow`'s
/// [`HandshakeState::write_message()`] and
/// [`TransportState::write_message()`].
pub fn write_message(
&mut self,
payload: &[u8],
message: &mut [u8],
) -> Result<usize, snow::Error> {
if let Some(handshake_state) = &mut self.handshake_state {
// This does the handshake and also writes a first message.
let r = handshake_state.write_message(payload, message);
// This `if`` should always be true, we do the check regardless for safety.
if handshake_state.is_handshake_finished() {
// Get the transport state from the handshake state and update
// the struct accordingly.
let handshake_state = self
.handshake_state
.take()
.expect("there must be a handshake state set");
self.transport_state = Some(handshake_state.into_transport_mode()?);
}
r
} else if let Some(transport_state) = &mut self.transport_state {
transport_state.write_message(payload, message)
} else {
panic!("invalid state");
}
}
/// Reads (i.e. decrypts) a message following the same API as `snow`'s
/// [`HandshakeState::read_message()`] and
/// [`TransportState::read_message()`].
pub fn read_message(
&mut self,
payload: &[u8],
message: &mut [u8],
) -> Result<usize, snow::Error> {
// See comments in [`Self::write_message()`].
if let Some(handshake_state) = &mut self.handshake_state {
let r = handshake_state.read_message(payload, message);
if handshake_state.is_handshake_finished() {
let handshake_state = self
.handshake_state
.take()
.expect("there must be a handshake state set");
self.transport_state = Some(handshake_state.into_transport_mode()?);
}
r
} else if let Some(transport_state) = &mut self.transport_state {
transport_state.read_message(payload, message)
} else {
panic!("invalid state");
}
}
}
pub struct HTTPComms<C: Ciphersuite> {
client: reqwest::Client,
host_port: String,
session_id: Option<Uuid>,
username: String,
password: String,
access_token: String,
should_logout: bool,
args: ProcessedArgs<C>,
send_noise: Option<Noise>,
recv_noise: Option<Noise>,
_phantom: PhantomData<C>,
}
@ -40,13 +123,39 @@ where
client,
host_port: format!("http://{}:{}", args.ip, args.port),
session_id: Uuid::parse_str(&args.session_id).ok(),
username: args.username.clone(),
password: args.password.clone(),
access_token: args.authentication_token.clone().unwrap_or_default(),
should_logout: args.authentication_token.is_none(),
args: args.clone(),
send_noise: None,
recv_noise: None,
_phantom: Default::default(),
})
}
// Encrypts a message for the coordinator if encryption is enabled.
fn encrypt_if_needed(&mut self, msg: Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>> {
if let Some(noise) = &mut self.send_noise {
let mut encrypted = vec![0; 65535];
let len = noise.write_message(&msg, &mut encrypted)?;
encrypted.truncate(len);
Ok(encrypted)
} else {
Ok(msg)
}
}
// Decrypts a message from the coordinator if encryption is enabled.
fn decrypt_if_needed(&mut self, msg: Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>> {
if let Some(noise) = &mut self.recv_noise {
let mut decrypted = vec![0; 65535];
decrypted.resize(65535, 0);
let len = noise.read_message(&msg, &mut decrypted)?;
decrypted.truncate(len);
Ok(decrypted)
} else {
Ok(msg)
}
}
}
#[async_trait(?Send)]
@ -73,8 +182,8 @@ where
.client
.post(format!("{}/login", self.host_port))
.json(&server::LoginArgs {
username: self.username.clone(),
password: self.password.clone(),
username: self.args.username.clone(),
password: self.args.password.clone(),
})
.send()
.await?
@ -106,11 +215,60 @@ where
};
self.session_id = Some(session_id);
// If encryption is enabled, create the Noise objects
(self.send_noise, self.recv_noise) = if let (
Some(comm_privkey),
Some(comm_coordinator_pubkey_getter),
) = (
&self.args.comm_privkey,
&self.args.comm_coordinator_pubkey_getter,
) {
// We need to know what is the username of the coordinator in order
// to encrypt message to them.
let session_info = self
.client
.post(format!("{}/get_session_info", self.host_port))
.json(&server::GetSessionInfoArgs { session_id })
.bearer_auth(&self.access_token)
.send()
.await?
.json::<server::GetSessionInfoOutput>()
.await?;
let comm_coordinator_pubkey = comm_coordinator_pubkey_getter(&session_info.coordinator).ok_or_eyre("The coordinator for the specified FROST session is not registered in the user's address book")?;
let builder = snow::Builder::new(
"Noise_K_25519_ChaChaPoly_BLAKE2s"
.parse()
.expect("should be a valid cipher"),
);
let send_noise = Noise::new(
builder
.local_private_key(comm_privkey)
.remote_public_key(&comm_coordinator_pubkey)
.build_initiator()?,
);
let builder = snow::Builder::new(
"Noise_K_25519_ChaChaPoly_BLAKE2s"
.parse()
.expect("should be a valid cipher"),
);
let recv_noise = Noise::new(
builder
.local_private_key(comm_privkey)
.remote_public_key(&comm_coordinator_pubkey)
.build_responder()?,
);
(Some(send_noise), Some(recv_noise))
} else {
(None, None)
};
// Send Commitments to Server
let send_commitments_args = SendCommitmentsArgs {
identifier,
commitments: vec![commitments],
};
let msg = self.encrypt_if_needed(serde_json::to_vec(&send_commitments_args)?)?;
self.client
.post(format!("{}/send", self.host_port))
.bearer_auth(&self.access_token)
@ -118,7 +276,7 @@ where
session_id,
// Empty recipients: Coordinator
recipients: vec![],
msg: serde_json::to_vec(&send_commitments_args)?,
msg,
})
.send()
.await?;
@ -145,8 +303,9 @@ where
eprint!(".");
} else {
eprintln!("\nSigning package received");
eprintln!("\n{}", String::from_utf8(r.msgs[0].msg.clone()).unwrap());
break serde_json::from_slice(&r.msgs[0].msg)?;
let msg = self.decrypt_if_needed(r.msgs[0].msg.clone())?;
eprintln!("\n{}", String::from_utf8_lossy(&msg.clone()));
break serde_json::from_slice(&msg)?;
}
};
@ -180,6 +339,8 @@ where
signature_share: vec![signature_share],
};
let msg = self.encrypt_if_needed(serde_json::to_vec(&send_signature_shares_args)?)?;
let _r = self
.client
.post(format!("{}/send", self.host_port))
@ -188,7 +349,7 @@ where
session_id: self.session_id.unwrap(),
// Empty recipients: Coordinator
recipients: vec![],
msg: serde_json::to_vec(&send_signature_shares_args)?,
msg,
})
.send()
.await?;

View File

@ -464,6 +464,8 @@ fn test_snow() -> Result<(), Box<dyn Error>> {
.build_initiator()
.unwrap();
println!("{}", anoise.is_handshake_finished());
let mut encrypted = [0u8; 65535];
let len = anoise
.write_message("hello world".as_bytes(), &mut encrypted)
@ -481,6 +483,22 @@ fn test_snow() -> Result<(), Box<dyn Error>> {
let len = bnoise.read_message(encrypted, &mut decrypted).unwrap();
let decrypted = &decrypted[0..len];
let mut anoise = anoise.into_transport_mode()?;
let mut bnoise = bnoise.into_transport_mode()?;
println!("{}", str::from_utf8(decrypted).unwrap());
let mut encrypted = [0u8; 65535];
let len = anoise
.write_message("hello world".as_bytes(), &mut encrypted)
.unwrap();
let encrypted = &encrypted[0..len];
let mut decrypted = [0u8; 65535];
let len = bnoise.read_message(encrypted, &mut decrypted).unwrap();
let decrypted = &decrypted[0..len];
println!("{}", str::from_utf8(decrypted).unwrap());
Ok(())
}