Add socket comms for Participant demo (#131)
* Add CLI comms to participant demo (#92) * Update Coordinator unit tests after comms changes (#92) * Update integration tests with participant cli comms (#92) * Add socket comms to Participant demo (#92) Remove group signature verification from participant demo * Update participant cli test (#92) * fix redpallas compile issue * Update participant/src/args.rs --------- Co-authored-by: Conrado Gouvea <conradoplg@gmail.com> Co-authored-by: Conrado Gouvea <conrado@zfnd.org>
This commit is contained in:
parent
e9269f204e
commit
4925183519
|
@ -843,13 +843,16 @@ dependencies = [
|
|||
name = "participant"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"exitcode",
|
||||
"eyre",
|
||||
"frost-ed25519",
|
||||
"hex",
|
||||
"message-io",
|
||||
"rand",
|
||||
"reddsa",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -21,4 +21,5 @@ message-io = "0.18"
|
|||
|
||||
[features]
|
||||
redpallas = []
|
||||
sockets = []
|
||||
default = []
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use std::io::{BufRead, Write};
|
||||
|
||||
use crate::args::Args;
|
||||
#[cfg(not(feature = "sockets"))]
|
||||
use crate::comms::cli::CLIComms;
|
||||
#[cfg(feature = "sockets")]
|
||||
use crate::comms::socket::SocketComms;
|
||||
use crate::step_1::step_1;
|
||||
use crate::step_2::step_2;
|
||||
use crate::step_3::step_3;
|
||||
|
@ -16,8 +19,12 @@ pub async fn cli(
|
|||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
writeln!(logger, "\n=== STEP 1: CHOOSE PARTICIPANTS ===\n")?;
|
||||
|
||||
#[cfg(not(feature = "sockets"))]
|
||||
let mut comms = CLIComms {};
|
||||
|
||||
#[cfg(feature = "sockets")]
|
||||
let mut comms = SocketComms::new(&args);
|
||||
|
||||
let participants_config = step_1(args, &mut comms, reader, logger).await?;
|
||||
|
||||
writeln!(
|
||||
|
@ -25,7 +32,7 @@ pub async fn cli(
|
|||
"=== STEP 2: CHOOSE MESSAGE AND GENERATE COMMITMENT PACKAGE ===\n"
|
||||
)?;
|
||||
|
||||
let signing_package = step_2(reader, logger, participants_config.commitments.clone())?;
|
||||
let signing_package = step_2(reader, logger, participants_config.commitments.clone()).await?;
|
||||
|
||||
#[cfg(feature = "redpallas")]
|
||||
let randomizer = request_randomizer(reader, logger)?;
|
||||
|
|
|
@ -36,12 +36,12 @@ impl SocketComms {
|
|||
pub fn new(args: &Args) -> Self {
|
||||
let (handler, listener) = node::split::<()>();
|
||||
let addr = format!("{}:{}", args.ip, args.port);
|
||||
let (tx, rx) = mpsc::channel(100);
|
||||
let (tx, rx) = mpsc::channel(2000);
|
||||
|
||||
handler
|
||||
let _ = handler
|
||||
.network()
|
||||
.listen(Transport::FramedTcp, addr)
|
||||
.unwrap();
|
||||
.map_err(|e| println!("{}", e));
|
||||
|
||||
let socket_comm = Self {
|
||||
input_rx: rx,
|
||||
|
@ -62,8 +62,9 @@ impl SocketComms {
|
|||
NetEvent::Accepted(_endpoint, _listener) => println!("Client connected"), // Tcp or Ws
|
||||
NetEvent::Message(endpoint, data) => {
|
||||
println!("Received: {}", String::from_utf8_lossy(data));
|
||||
// TODO: handle error
|
||||
let _ = input_tx.try_send((endpoint, data.to_vec()));
|
||||
let _ = input_tx
|
||||
.try_send((endpoint, data.to_vec()))
|
||||
.map_err(|e| println!("{}", e));
|
||||
}
|
||||
NetEvent::Disconnected(_endpoint) => println!("Client disconnected"), //Tcp or Ws
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
};
|
||||
|
||||
/// Read the contents of a file or from a stdin.
|
||||
/// If `object_name` is "-" or a file that does not exist, then it reads from
|
||||
/// If `file_path` is "-" or a file that does not exist, then it reads from
|
||||
/// stdin.
|
||||
/// `object_name` is used for printing prompts and it should describe what
|
||||
/// is being read.
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#[cfg(all(test, not(feature = "redpallas")))]
|
||||
mod tests;
|
||||
|
||||
use std::io;
|
||||
|
||||
use clap::Parser;
|
||||
|
|
|
@ -16,7 +16,7 @@ pub struct CommitmentsConfig {
|
|||
pub signer_commitments: BTreeMap<Identifier, SigningCommitments>,
|
||||
}
|
||||
|
||||
pub fn step_2(
|
||||
pub async fn step_2(
|
||||
input: &mut impl BufRead,
|
||||
logger: &mut dyn Write,
|
||||
commitments: BTreeMap<Identifier, SigningCommitments>,
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
// mod steps;
|
|
@ -1,3 +1,20 @@
|
|||
#[cfg(test)]
|
||||
use coordinator::{
|
||||
args::Args,
|
||||
comms::cli::CLIComms,
|
||||
step_1::{step_1, ParticipantsConfig},
|
||||
step_2::step_2,
|
||||
step_3::step_3,
|
||||
};
|
||||
use frost::{
|
||||
keys::{PublicKeyPackage, VerifyingShare},
|
||||
round1::{NonceCommitment, SigningCommitments},
|
||||
Identifier, SigningPackage, VerifyingKey,
|
||||
};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use std::{collections::BTreeMap, io::BufWriter};
|
||||
|
||||
// Test values from https://github.com/ZcashFoundation/frost/blob/main/frost-ed25519/tests/helpers/vectors.json
|
||||
|
||||
const PUBLIC_KEY_1: &str = "fc2c9b8e335c132d9ebe0403c9317aac480bbbf8cbdb1bc3730bb68eb60dadf9";
|
||||
|
@ -10,7 +27,7 @@ fn build_pub_key_package() -> PublicKeyPackage {
|
|||
let id_2 = Identifier::try_from(2).unwrap();
|
||||
let id_3 = Identifier::try_from(3).unwrap();
|
||||
|
||||
let mut signer_pubkeys = HashMap::new();
|
||||
let mut signer_pubkeys = BTreeMap::new();
|
||||
signer_pubkeys.insert(
|
||||
id_1,
|
||||
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY_1).unwrap()).unwrap(),
|
||||
|
@ -24,12 +41,13 @@ fn build_pub_key_package() -> PublicKeyPackage {
|
|||
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY_3).unwrap()).unwrap(),
|
||||
);
|
||||
|
||||
let group_public = VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap();
|
||||
let group_public =
|
||||
VerifyingKey::deserialize(<[u8; 32]>::from_hex(GROUP_PUBLIC_KEY).unwrap()).unwrap();
|
||||
|
||||
PublicKeyPackage::new(signer_pubkeys, group_public)
|
||||
}
|
||||
|
||||
fn build_signing_package() -> SigningPackage {
|
||||
fn build_signing_commitments() -> BTreeMap<Identifier, SigningCommitments> {
|
||||
let id_1 = Identifier::try_from(1).unwrap();
|
||||
let id_3 = Identifier::try_from(3).unwrap();
|
||||
|
||||
|
@ -55,15 +73,19 @@ fn build_signing_package() -> SigningPackage {
|
|||
signing_commitments.insert(id_1, signer_commitments_1);
|
||||
signing_commitments.insert(id_3, signer_commitments_3);
|
||||
|
||||
SigningPackage::new(signing_commitments, b"test")
|
||||
signing_commitments
|
||||
|
||||
// SigningPackage::new(signing_commitments, b"test")
|
||||
}
|
||||
|
||||
// Input required:
|
||||
// 1. public key package
|
||||
// 2. number of signers
|
||||
// 3. identifiers for all signers
|
||||
#[test]
|
||||
fn check_step_1() {
|
||||
#[tokio::test]
|
||||
async fn check_step_1() {
|
||||
let mut comms = CLIComms {};
|
||||
let args = Args::default();
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
|
||||
let id_1 = Identifier::try_from(1).unwrap();
|
||||
|
@ -87,16 +109,6 @@ fn check_step_1() {
|
|||
|
||||
// --
|
||||
|
||||
let expected_participants_config = ParticipantsConfig {
|
||||
participants: vec![id_1, id_3],
|
||||
pub_key_package: build_pub_key_package(),
|
||||
};
|
||||
|
||||
let participants_config = step_1(&mut valid_input, &mut buf);
|
||||
|
||||
assert!(participants_config.is_ok());
|
||||
assert!(participants_config.unwrap() == expected_participants_config);
|
||||
|
||||
let expected = "Paste the JSON public key package: \nThe number of participants: \nIdentifier for participant 1 (hex encoded): \nIdentifier for participant 2 (hex encoded): \nSelected participants: \n\"0100000000000000000000000000000000000000000000000000000000000000\"\n\"0300000000000000000000000000000000000000000000000000000000000000\"\n";
|
||||
|
||||
let (_, res) = &buf.into_parts();
|
||||
|
@ -109,16 +121,18 @@ fn check_step_1() {
|
|||
// 1. message
|
||||
// 2. number of signers
|
||||
// 3. commitments for all signers
|
||||
#[test]
|
||||
fn check_step_2() {
|
||||
#[tokio::test]
|
||||
async fn check_step_2() {
|
||||
let mut comms = CLIComms {};
|
||||
let args = Args::default();
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
|
||||
// -- INPUTS --
|
||||
|
||||
let message = "74657374";
|
||||
|
||||
let commitments_input_1 = "{\"hiding\":\"5078f5c6d679654bb88a8887242d49cc21a553ed26caed4d52570c6656fb9b92\", \"binding\":\"936b660d3008d8298b0a7220a327a0813ffedd9d07604bdc73d7cffef63c0da0\", \"ciphersuite\":\"FROST(Ed25519, SHA-512)\" }";
|
||||
let commitments_input_3 = "{\"hiding\":\"91c2469b501fe5af8493f9ae77c8f57999460af317f2d9f2d4378ae0e665860e\", \"binding\":\"c225618accff2266a45d87dc3219b04c774ca26c8629c4fa483e7e87da820007\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}";
|
||||
let commitments_input_1 = "{\"header\":{\"version\":0,\"ciphersuite\":\"FROST-ED25519-SHA512-v1\"},\"identifier\":\"0100000000000000000000000000000000000000000000000000000000000000\",\"signing_share\":\"4ca8a14c31582e92770b23d8b4e5f253d94cbbdc34332cbbb9972f7d0a16a106\",\"commitment\":[\"c0b1eb84bc74624e9196a4ae01d7b784133dd714943001524e33f62ac09fe6df\",\"a4ed252f52e34077e990f70a743a261ff74cbda88173269cc1feeb0616af734b\",\"0fe7ced03a6d5cc4286d050f20fea6dbc14f412a430fc21f92ee2861011fb93c\"]}";
|
||||
let commitments_input_3 = "{\"header\":{\"version\":0,\"ciphersuite\":\"FROST-ED25519-SHA512-v1\"},\"identifier\":\"0300000000000000000000000000000000000000000000000000000000000000\",\"signing_share\":\"4ca8a14c31582e92770b23d8b4e5f253d94cbbdc34332cbbb9972f7d0a16a106\",\"commitment\":[\"c0b1eb84bc74624e9196a4ae01d7b784133dd714943001524e33f62ac09fe6df\",\"a4ed252f52e34077e990f70a743a261ff74cbda88173269cc1feeb0616af734b\",\"0fe7ced03a6d5cc4286d050f20fea6dbc14f412a430fc21f92ee2861011fb93c\"]}";
|
||||
|
||||
let input = format!(
|
||||
"{}\n{}\n{}\n",
|
||||
|
@ -131,15 +145,25 @@ fn check_step_2() {
|
|||
|
||||
let id_1 = Identifier::try_from(1).unwrap();
|
||||
let id_3 = Identifier::try_from(3).unwrap();
|
||||
let participants = vec![id_1, id_3];
|
||||
|
||||
let expected_signing_package = build_signing_package();
|
||||
let signing_commitments = build_signing_commitments();
|
||||
|
||||
let signing_package = step_2(&mut valid_input, &mut buf, participants);
|
||||
let expected_signing_package = SigningPackage::new(signing_commitments.clone(), b"test");
|
||||
|
||||
let signing_package = step_2(&mut valid_input, &mut buf, signing_commitments.clone());
|
||||
|
||||
assert!(signing_package.is_ok());
|
||||
assert!(signing_package.unwrap() == expected_signing_package);
|
||||
|
||||
let expected_participants_config = ParticipantsConfig {
|
||||
commitments: signing_commitments.clone(),
|
||||
pub_key_package: build_pub_key_package(),
|
||||
};
|
||||
|
||||
let participants_config = step_1(&args, &mut comms, &mut valid_input, &mut buf);
|
||||
|
||||
assert!(participants_config.await.unwrap() == expected_participants_config);
|
||||
|
||||
let expected = "The message to be signed (hex encoded)\nPlease enter JSON encoded commitments for participant 0100000000000000000000000000000000000000000000000000000000000000:\nPlease enter JSON encoded commitments for participant 0300000000000000000000000000000000000000000000000000000000000000:\nSigning Package:\n{\"signing_commitments\":{\"0100000000000000000000000000000000000000000000000000000000000000\":{\"hiding\":\"5078f5c6d679654bb88a8887242d49cc21a553ed26caed4d52570c6656fb9b92\",\"binding\":\"936b660d3008d8298b0a7220a327a0813ffedd9d07604bdc73d7cffef63c0da0\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"},\"0300000000000000000000000000000000000000000000000000000000000000\":{\"hiding\":\"91c2469b501fe5af8493f9ae77c8f57999460af317f2d9f2d4378ae0e665860e\",\"binding\":\"c225618accff2266a45d87dc3219b04c774ca26c8629c4fa483e7e87da820007\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}},\"message\":\"74657374\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}\n";
|
||||
|
||||
let (_, res) = &buf.into_parts();
|
||||
|
@ -148,28 +172,13 @@ fn check_step_2() {
|
|||
assert_eq!(expected, actual)
|
||||
}
|
||||
|
||||
use crate::{
|
||||
step_1::{step_1, ParticipantsConfig},
|
||||
step_2::step_2,
|
||||
step_3::step_3,
|
||||
};
|
||||
use frost::{
|
||||
keys::{PublicKeyPackage, VerifyingShare},
|
||||
round1::{NonceCommitment, SigningCommitments},
|
||||
Identifier, SigningPackage, VerifyingKey,
|
||||
};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
io::BufWriter,
|
||||
};
|
||||
|
||||
// // Input required:
|
||||
// // 1. number of signers (TODO: maybe pass this in?)
|
||||
// // 2. signatures for all signers
|
||||
#[test]
|
||||
fn check_step_3() {
|
||||
#[tokio::test]
|
||||
async fn check_step_3() {
|
||||
let mut comms = CLIComms {};
|
||||
let args = Args::default();
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
|
||||
let id_1 = Identifier::try_from(1).unwrap();
|
||||
|
@ -180,7 +189,7 @@ fn check_step_3() {
|
|||
const GROUP_PUBLIC_KEY: &str =
|
||||
"15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673";
|
||||
|
||||
let mut signer_pubkeys = HashMap::new();
|
||||
let mut signer_pubkeys = BTreeMap::new();
|
||||
signer_pubkeys.insert(
|
||||
id_1,
|
||||
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY_1).unwrap()).unwrap(),
|
||||
|
@ -190,7 +199,8 @@ fn check_step_3() {
|
|||
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY_3).unwrap()).unwrap(),
|
||||
);
|
||||
|
||||
let group_public = VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap();
|
||||
let group_public =
|
||||
VerifyingKey::deserialize(<[u8; 32]>::from_hex(GROUP_PUBLIC_KEY).unwrap()).unwrap();
|
||||
|
||||
let signature_1 = "{\"share\":\"b97409beff18861f0959530db091a64b812e3fefaa87e1e3d2c039f11d96cc09\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}";
|
||||
let signature_3 = "{\"share\":\"9816a14e7cdecfcb240976f564cf98c5640e596b6ddf270379efbef4e9f7db0b\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}";
|
||||
|
@ -199,17 +209,20 @@ fn check_step_3() {
|
|||
|
||||
let mut valid_input = input.as_bytes();
|
||||
|
||||
let commitments = build_signing_commitments();
|
||||
|
||||
let participants_config = ParticipantsConfig {
|
||||
participants: vec![id_1, id_3],
|
||||
commitments: commitments.clone(),
|
||||
pub_key_package: PublicKeyPackage::new(signer_pubkeys, group_public),
|
||||
};
|
||||
let signing_package = build_signing_package();
|
||||
let signing_package = SigningPackage::new(commitments, b"test");
|
||||
|
||||
step_3(
|
||||
&mut comms,
|
||||
&mut valid_input,
|
||||
&mut buf,
|
||||
participants_config,
|
||||
signing_package,
|
||||
&signing_package,
|
||||
);
|
||||
|
||||
let expected = "Please enter JSON encoded signature shares for participant 0100000000000000000000000000000000000000000000000000000000000000:\nPlease enter JSON encoded signature shares for participant 0300000000000000000000000000000000000000000000000000000000000000:\nGroup signature: \"72c948a63797c693e8e978fdb703a1f5a7590472a539da13b71dd6c2b8c1b2a664b7b4af6194439357c5d15f366760fce53c985a186709e74bb0f8e5078ea805\"\n";
|
||||
|
|
|
@ -13,7 +13,11 @@ rand = "0.8"
|
|||
eyre = "0.6.11"
|
||||
exitcode = "1.1.2"
|
||||
serde_json = "1.0"
|
||||
clap = { version = "4.4.7", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
message-io = "0.18"
|
||||
|
||||
[features]
|
||||
redpallas = []
|
||||
sockets = []
|
||||
default = []
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug, Default)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Args {
|
||||
/// 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 = 'k', long, default_value = "key-package-1.json")]
|
||||
pub key_package: String,
|
||||
|
||||
/// IP to bind to, if using online comms
|
||||
#[arg(short, long, default_value = "0.0.0.0")]
|
||||
pub ip: String,
|
||||
|
||||
/// Port to bind to, if using online comms
|
||||
#[arg(short, long, default_value_t = 2744)]
|
||||
pub port: u16,
|
||||
}
|
|
@ -1,63 +1,54 @@
|
|||
use frost::{Error, Signature};
|
||||
#[cfg(not(feature = "redpallas"))]
|
||||
use frost_ed25519 as frost;
|
||||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas as frost;
|
||||
use crate::args::Args;
|
||||
use crate::comms::cli::CLIComms;
|
||||
|
||||
use crate::round1::{print_values, request_inputs};
|
||||
#[cfg(feature = "sockets")]
|
||||
use crate::comms::socket::SocketComms;
|
||||
|
||||
use crate::comms::Comms;
|
||||
|
||||
use crate::round1::{generate_nonces_and_commitments, print_values, request_inputs};
|
||||
use crate::round2::{generate_signature, print_values_round_2, round_2_request_inputs};
|
||||
use rand::thread_rng;
|
||||
use std::io::{BufRead, Write};
|
||||
|
||||
pub fn cli(
|
||||
pub async fn cli(
|
||||
args: &Args,
|
||||
input: &mut impl BufRead,
|
||||
logger: &mut impl Write,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let round_1_config = request_inputs(input, logger)?;
|
||||
#[cfg(not(feature = "sockets"))]
|
||||
let mut comms = CLIComms {};
|
||||
|
||||
#[cfg(feature = "sockets")]
|
||||
let mut comms = SocketComms::new(&args);
|
||||
|
||||
// Round 1
|
||||
|
||||
let round_1_config = request_inputs(args, input, logger).await?;
|
||||
let key_package = round_1_config.key_package;
|
||||
|
||||
writeln!(logger, "Key Package succesfully created.")?;
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let (nonces, commitments) = frost::round1::commit(key_package.signing_share(), &mut rng);
|
||||
let (nonces, commitments) = generate_nonces_and_commitments(&key_package, &mut rng);
|
||||
|
||||
print_values(commitments, logger)?;
|
||||
|
||||
let round_2_config = round_2_request_inputs(input, logger)?;
|
||||
|
||||
let config_message = round_2_config.clone();
|
||||
|
||||
// Sign
|
||||
// Round 2 - Sign
|
||||
|
||||
let round_2_config = round_2_request_inputs(
|
||||
&mut comms,
|
||||
input,
|
||||
logger,
|
||||
commitments,
|
||||
*key_package.identifier(),
|
||||
)
|
||||
.await?;
|
||||
let signature = generate_signature(round_2_config, &key_package, &nonces)?;
|
||||
|
||||
comms.send_signature_share(signature).await?;
|
||||
|
||||
print_values_round_2(signature, logger)?;
|
||||
|
||||
let group_signature = request_signature(input, logger)?;
|
||||
key_package
|
||||
.verifying_key()
|
||||
.verify(config_message.signing_package.message(), &group_signature)?;
|
||||
|
||||
writeln!(logger, "Group Signature verified.")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn request_signature(
|
||||
input: &mut impl BufRead,
|
||||
logger: &mut impl Write,
|
||||
) -> Result<Signature, Box<dyn std::error::Error>> {
|
||||
writeln!(logger, "The group signature (as a \"quoted_string\"):")?;
|
||||
|
||||
let mut signature_input = String::new();
|
||||
|
||||
input.read_line(&mut signature_input)?;
|
||||
|
||||
let group_signature =
|
||||
serde_json::from_str(signature_input.trim()).map_err(|_| Error::InvalidSignature)?;
|
||||
|
||||
// TODO: add redpallas feature
|
||||
|
||||
Ok(group_signature)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
pub mod cli;
|
||||
pub mod socket;
|
||||
|
||||
#[cfg(not(feature = "redpallas"))]
|
||||
use frost_ed25519 as frost;
|
||||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas as frost;
|
||||
|
||||
use std::{
|
||||
error::Error,
|
||||
io::{BufRead, Write},
|
||||
};
|
||||
|
||||
use frost::{
|
||||
round1::SigningCommitments,
|
||||
round2::SignatureShare,
|
||||
serde::{self, Deserialize, Serialize},
|
||||
Identifier, SigningPackage,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(crate = "self::serde")]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum Message {
|
||||
IdentifiedCommitments {
|
||||
identifier: Identifier,
|
||||
commitments: SigningCommitments,
|
||||
},
|
||||
SigningPackage(SigningPackage),
|
||||
SignatureShare(SignatureShare),
|
||||
}
|
||||
|
||||
#[allow(async_fn_in_trait)]
|
||||
pub trait Comms {
|
||||
async fn get_signing_package(
|
||||
&mut self,
|
||||
input: &mut dyn BufRead,
|
||||
output: &mut dyn Write,
|
||||
commitments: SigningCommitments,
|
||||
identifier: Identifier,
|
||||
) -> Result<SigningPackage, Box<dyn Error>>;
|
||||
|
||||
async fn send_signature_share(
|
||||
&mut self,
|
||||
signature_share: SignatureShare,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
//! Command line interface implementation of the Comms trait.
|
||||
|
||||
#[cfg(not(feature = "redpallas"))]
|
||||
use frost_ed25519 as frost;
|
||||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas as frost;
|
||||
|
||||
use eyre::eyre;
|
||||
|
||||
use frost::{
|
||||
keys::PublicKeyPackage, round1::SigningCommitments, round2::SignatureShare, Identifier,
|
||||
SigningPackage,
|
||||
};
|
||||
|
||||
use std::{
|
||||
error::Error,
|
||||
io::{BufRead, Write},
|
||||
};
|
||||
|
||||
use crate::comms::Comms;
|
||||
// use super::Comms;
|
||||
|
||||
pub struct CLIComms {}
|
||||
|
||||
impl Comms for CLIComms {
|
||||
async fn get_signing_package(
|
||||
&mut self,
|
||||
input: &mut dyn BufRead,
|
||||
output: &mut dyn Write,
|
||||
_commitments: SigningCommitments,
|
||||
_identifier: Identifier,
|
||||
) -> Result<SigningPackage, Box<dyn Error>> {
|
||||
writeln!(output, "Enter the JSON-encoded SigningPackage:")?;
|
||||
|
||||
let mut signing_package_json = String::new();
|
||||
|
||||
input.read_line(&mut signing_package_json)?;
|
||||
|
||||
// TODO: change to return a generic Error and use a better error
|
||||
let signing_package: SigningPackage = serde_json::from_str(signing_package_json.trim())?;
|
||||
|
||||
Ok(signing_package)
|
||||
}
|
||||
|
||||
async fn send_signature_share(
|
||||
&mut self,
|
||||
_signature_share: SignatureShare,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_identifier(input: &mut dyn BufRead) -> Result<Identifier, Box<dyn Error>> {
|
||||
let mut identifier_input = String::new();
|
||||
input.read_line(&mut identifier_input)?;
|
||||
let bytes = hex::decode(identifier_input.trim())?;
|
||||
let serialization = bytes.try_into().map_err(|_| eyre!("Invalid Identifier"))?;
|
||||
let identifier = Identifier::deserialize(&serialization)?;
|
||||
Ok(identifier)
|
||||
}
|
||||
|
||||
pub fn validate(
|
||||
id: Identifier,
|
||||
key_package: &PublicKeyPackage,
|
||||
id_list: &[Identifier],
|
||||
) -> Result<(), frost::Error> {
|
||||
if !key_package.verifying_shares().contains_key(&id) {
|
||||
return Err(frost::Error::MalformedIdentifier);
|
||||
}; // TODO: Error is actually that the identifier does not exist
|
||||
if id_list.contains(&id) {
|
||||
return Err(frost::Error::DuplicatedIdentifier);
|
||||
};
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
//! Socket implementation of the Comms trait, using message-io.
|
||||
|
||||
#[cfg(not(feature = "redpallas"))]
|
||||
use frost_ed25519 as frost;
|
||||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas as frost;
|
||||
|
||||
use eyre::eyre;
|
||||
use message_io::{
|
||||
network::{Endpoint, NetEvent, Transport},
|
||||
node::{self, NodeHandler, NodeListener},
|
||||
};
|
||||
use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||
|
||||
use frost::{round1::SigningCommitments, round2::SignatureShare, Identifier, SigningPackage};
|
||||
|
||||
use std::{
|
||||
error::Error,
|
||||
io::{BufRead, Write},
|
||||
};
|
||||
|
||||
use super::{Comms, Message};
|
||||
use crate::args::Args;
|
||||
|
||||
pub struct SocketComms {
|
||||
input_rx: Receiver<(Endpoint, Vec<u8>)>,
|
||||
endpoint: Endpoint,
|
||||
handler: NodeHandler<()>,
|
||||
}
|
||||
|
||||
impl SocketComms {
|
||||
pub fn new(args: &Args) -> Self {
|
||||
let (handler, listener) = node::split::<()>();
|
||||
let addr = format!("{}:{}", args.ip, args.port);
|
||||
let (tx, rx) = mpsc::channel(2000); // Don't need to receive the endpoint. Change this
|
||||
|
||||
let (endpoint, _addr) = handler
|
||||
.network()
|
||||
.connect(Transport::FramedTcp, addr)
|
||||
.unwrap();
|
||||
|
||||
let socket_comm = Self {
|
||||
input_rx: rx,
|
||||
endpoint,
|
||||
handler,
|
||||
};
|
||||
|
||||
// TODO: save handle
|
||||
let _handle = tokio::spawn(async move { Self::run(listener, tx) });
|
||||
|
||||
socket_comm
|
||||
}
|
||||
|
||||
fn run(listener: NodeListener<()>, input_tx: Sender<(Endpoint, Vec<u8>)>) {
|
||||
// Read incoming network events.
|
||||
listener.for_each(|event| match event.network() {
|
||||
NetEvent::Connected(endpoint, false) => {
|
||||
println!("Error connecting to server at {}", endpoint)
|
||||
} // Used for explicit connections.
|
||||
NetEvent::Connected(endpoint, true) => println!("Connected to server at {}", endpoint), // Used for explicit connections.
|
||||
NetEvent::Accepted(endpoint, _listener) => {
|
||||
println!("Server accepted connection at {}", endpoint)
|
||||
} // Tcp or Ws
|
||||
NetEvent::Message(endpoint, data) => {
|
||||
println!("Received: {}", String::from_utf8_lossy(data));
|
||||
let _ = input_tx
|
||||
.try_send((endpoint, data.to_vec()))
|
||||
.map_err(|e| println!("{}", e));
|
||||
}
|
||||
NetEvent::Disconnected(endpoint) => {
|
||||
println!("Disconnected from server at {}", endpoint)
|
||||
} //Tcp or Ws
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Comms for SocketComms {
|
||||
async fn get_signing_package(
|
||||
&mut self,
|
||||
_input: &mut dyn BufRead,
|
||||
_output: &mut dyn Write,
|
||||
commitments: SigningCommitments,
|
||||
identifier: Identifier,
|
||||
) -> Result<SigningPackage, Box<dyn Error>> {
|
||||
// Send Commitments to Coordinator
|
||||
let data = serde_json::to_vec(&Message::IdentifiedCommitments {
|
||||
identifier,
|
||||
commitments,
|
||||
})?;
|
||||
self.handler.network().send(self.endpoint, &data);
|
||||
|
||||
// Receive SigningPackage from Coordinator
|
||||
let (_endpoint, data) = self
|
||||
.input_rx
|
||||
.recv()
|
||||
.await
|
||||
.ok_or(eyre!("Did not receive signing package!"))?;
|
||||
|
||||
let message: Message = serde_json::from_slice(&data)?;
|
||||
if let Message::SigningPackage(signing_package) = message {
|
||||
Ok(signing_package)
|
||||
} else {
|
||||
Err(eyre!("Expected SigningPackage message"))?
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_signature_share(
|
||||
&mut self,
|
||||
signature_share: SignatureShare,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
// Send signature shares to Coordinator
|
||||
let data = serde_json::to_vec(&Message::SignatureShare(signature_share))?;
|
||||
self.handler.network().send(self.endpoint, &data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
use std::{
|
||||
error::Error,
|
||||
fs,
|
||||
io::{BufRead, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
/// Read the contents of a file or from a stdin.
|
||||
/// If `object_name` is "-" or a file that does not exist, then it reads from
|
||||
/// stdin.
|
||||
/// `object_name` is used for printing prompts and it should describe what
|
||||
/// is being read.
|
||||
pub fn read_from_file_or_stdin(
|
||||
input: &mut dyn BufRead,
|
||||
output: &mut dyn Write,
|
||||
object_name: &str,
|
||||
file_path: &str,
|
||||
) -> Result<String, Box<dyn Error>> {
|
||||
let file_path = {
|
||||
if file_path == "-" {
|
||||
None
|
||||
} else {
|
||||
let p = Path::new(&file_path);
|
||||
if p.exists() {
|
||||
writeln!(output, "Reading {} from {}", object_name, file_path)?;
|
||||
Some(p)
|
||||
} else {
|
||||
writeln!(
|
||||
output,
|
||||
"File not found: {}\nWill read from stdin",
|
||||
file_path
|
||||
)?;
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
match file_path {
|
||||
Some(file_path) => Ok(fs::read_to_string(file_path)?),
|
||||
None => {
|
||||
writeln!(output, "Paste the {}: ", object_name)?;
|
||||
let mut key_package = String::new();
|
||||
input.read_line(&mut key_package)?;
|
||||
Ok(key_package)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: write to file
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
pub mod args;
|
||||
pub mod cli;
|
||||
pub mod comms;
|
||||
|
||||
pub mod input;
|
||||
pub mod round1;
|
||||
pub mod round2;
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
mod cli;
|
||||
mod round1;
|
||||
mod round2;
|
||||
|
||||
#[cfg(all(test, not(feature = "redpallas")))]
|
||||
mod tests;
|
||||
|
||||
use cli::cli;
|
||||
use clap::Parser;
|
||||
use participant::args::Args;
|
||||
use participant::cli::cli;
|
||||
|
||||
use std::io;
|
||||
|
||||
// TODO: Update to use exit codes
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = Args::parse();
|
||||
let mut reader = Box::new(io::stdin().lock());
|
||||
let mut logger = io::stdout();
|
||||
cli(&mut reader, &mut logger)?;
|
||||
cli(&args, &mut reader, &mut logger).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,11 +3,15 @@ use frost_ed25519 as frost;
|
|||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas as frost;
|
||||
|
||||
use crate::args::Args;
|
||||
use crate::input::read_from_file_or_stdin;
|
||||
use frost::{
|
||||
keys::{KeyPackage, SecretShare},
|
||||
round1::SigningCommitments,
|
||||
round1::SigningNonces,
|
||||
Error,
|
||||
};
|
||||
use rand::rngs::ThreadRng;
|
||||
use std::io::{BufRead, Write};
|
||||
|
||||
// TODO: Rethink the types here. They're inconsistent with each other
|
||||
|
@ -17,26 +21,36 @@ pub struct Round1Config {
|
|||
}
|
||||
|
||||
// TODO: refactor to generate config
|
||||
pub fn request_inputs(
|
||||
pub async fn request_inputs(
|
||||
args: &Args,
|
||||
input: &mut impl BufRead,
|
||||
logger: &mut impl Write,
|
||||
) -> Result<Round1Config, Box<dyn std::error::Error>> {
|
||||
writeln!(logger, "Your JSON-encoded secret share or key package:")?;
|
||||
|
||||
let mut json = String::new();
|
||||
let secret_share = read_from_file_or_stdin(input, logger, "key package", &args.key_package)?;
|
||||
|
||||
input.read_line(&mut json)?;
|
||||
|
||||
let key_package = if let Ok(secret_share) = serde_json::from_str::<SecretShare>(&json) {
|
||||
let key_package = if let Ok(secret_share) = serde_json::from_str::<SecretShare>(&secret_share) {
|
||||
KeyPackage::try_from(secret_share)?
|
||||
} else {
|
||||
// TODO: Improve error
|
||||
serde_json::from_str::<KeyPackage>(&json).map_err(|_| Error::InvalidSecretShare)?
|
||||
serde_json::from_str::<KeyPackage>(&secret_share).map_err(|_| Error::InvalidSecretShare)?
|
||||
};
|
||||
|
||||
Ok(Round1Config { key_package })
|
||||
}
|
||||
|
||||
pub fn generate_nonces_and_commitments(
|
||||
key_package: &KeyPackage,
|
||||
rng: &mut ThreadRng,
|
||||
) -> (SigningNonces, SigningCommitments) {
|
||||
let (nonces, commitments) = frost::round1::commit(key_package.signing_share(), rng);
|
||||
|
||||
// TODO: Store nonces
|
||||
|
||||
(nonces, commitments)
|
||||
}
|
||||
|
||||
pub fn print_values(
|
||||
commitments: SigningCommitments,
|
||||
logger: &mut dyn Write,
|
||||
|
|
|
@ -5,11 +5,12 @@ use frost_ed25519 as frost;
|
|||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas as frost;
|
||||
|
||||
use crate::comms::Comms;
|
||||
use frost::{
|
||||
keys::KeyPackage,
|
||||
round1::SigningNonces,
|
||||
round1::{SigningCommitments, SigningNonces},
|
||||
round2::{self, SignatureShare},
|
||||
Error, SigningPackage,
|
||||
Error, Identifier, SigningPackage,
|
||||
};
|
||||
use std::io::{BufRead, Write};
|
||||
|
||||
|
@ -22,21 +23,18 @@ pub struct Round2Config {
|
|||
|
||||
// TODO: refactor to generate config
|
||||
// TODO: handle errors
|
||||
pub fn round_2_request_inputs(
|
||||
pub async fn round_2_request_inputs(
|
||||
comms: &mut impl Comms,
|
||||
input: &mut impl BufRead,
|
||||
logger: &mut dyn Write,
|
||||
commitments: SigningCommitments,
|
||||
identifier: Identifier,
|
||||
) -> Result<Round2Config, Box<dyn std::error::Error>> {
|
||||
writeln!(logger, "=== Round 2 ===")?;
|
||||
|
||||
writeln!(logger, "Enter the JSON-encoded SigningPackage:")?;
|
||||
|
||||
let mut signing_package_json = String::new();
|
||||
|
||||
input.read_line(&mut signing_package_json)?;
|
||||
|
||||
// TODO: change to return a generic Error and use a better error
|
||||
let signing_package: SigningPackage = serde_json::from_str(signing_package_json.trim())
|
||||
.map_err(|_| Error::MalformedSigningKey)?;
|
||||
let signing_package = comms
|
||||
.get_signing_package(input, logger, commitments, identifier)
|
||||
.await?;
|
||||
|
||||
#[cfg(feature = "redpallas")]
|
||||
{
|
||||
|
@ -70,6 +68,7 @@ pub fn generate_signature(
|
|||
let signing_package = config.signing_package;
|
||||
#[cfg(not(feature = "redpallas"))]
|
||||
let signature = round2::sign(&signing_package, signing_nonces, key_package)?;
|
||||
|
||||
#[cfg(feature = "redpallas")]
|
||||
let signature = round2::sign(
|
||||
&signing_package,
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
use std::io::BufWriter;
|
||||
|
||||
use crate::cli::cli;
|
||||
use participant::args::Args;
|
||||
use participant::cli::cli;
|
||||
|
||||
// TODO: to restore this test, we need to intercept that generated commitments
|
||||
// to put them inside the SigningPackage
|
||||
// #[test]
|
||||
#[allow(unused)]
|
||||
fn check_cli() {
|
||||
async fn check_cli() {
|
||||
let args = Args::default();
|
||||
let key_package = r#"{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"identifier":"0100000000000000000000000000000000000000000000000000000000000000","signing_share":"ee4a66fec3ced53cac04b0abc309bb57f03f8d7dede033e4ae7b6ef57630120f","commitment":["21446705fa7da298998a567a3c2fdd7274903a886dcde9a77f615d915feb6764","56ce223ffbde8ce5971be587cbb0b8b31aa2bc220a6803b9ce73c63f9f432514","6dcc10da9443ef2c9bbd5fc6a9c3bcd4c5ede8048cc0b1342b091fd1ff6dc53c"]}"#;
|
||||
|
||||
let signing_package = r#"{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"signing_commitments":{"0100000000000000000000000000000000000000000000000000000000000000":{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"hiding":"710a280fcedbcbe626fff055f682e4a525c31f157dd6071ef2c04ea0ecbe8de9","binding":"6dc707cdf26a589b3e2de4f6bae09b94d5d3bb939937b52bc6b16bdecd0b041f"},"0200000000000000000000000000000000000000000000000000000000000000":{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"hiding":"777f011bf695e27ce62474747a9c110cc3b827268047913a21030c3eba0e1eed","binding":"67f051035284cd619f0e7fc583eb3cb0c88d993aad621c856edc0f995f4588b2"},"0300000000000000000000000000000000000000000000000000000000000000":{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"hiding":"c052599bb7a52911b6b58e7c20747f12d45d23aab4aec98aaecdc7909dc6aff3","binding":"b3fbefc67070b1b56203ef875a2c7caf24802dbc943bdc62decac33287b63b23"}},"message":"74657374"}"#;
|
||||
|
@ -19,7 +21,7 @@ fn check_cli() {
|
|||
key_package, signing_package, group_signature
|
||||
);
|
||||
|
||||
let signature = cli(&mut input.as_bytes(), &mut buf);
|
||||
let signature = cli(&args, &mut input.as_bytes(), &mut buf).await;
|
||||
assert!(
|
||||
signature.is_ok(),
|
||||
"invalid signature: {}",
|
||||
|
|
|
@ -8,7 +8,10 @@ use frost::{
|
|||
};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use participant::round1::{print_values, request_inputs, Round1Config};
|
||||
use participant::{
|
||||
args::Args,
|
||||
round1::{print_values, request_inputs, Round1Config},
|
||||
};
|
||||
|
||||
use rand::thread_rng;
|
||||
|
||||
|
@ -17,7 +20,7 @@ const GROUP_PUBLIC_KEY: &str = "087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34f
|
|||
const SIGNING_SHARE: &str = "ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104";
|
||||
const SECRET_SHARE_JSON: &str = r#"{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"identifier":"0100000000000000000000000000000000000000000000000000000000000000","signing_share":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","926d5910e146dccb9148ca39dc7607f4f7123ff1c0ffaf109add1d165c568bf2", "291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"]}"#;
|
||||
|
||||
fn build_key_package() -> KeyPackage {
|
||||
async fn build_key_package() -> KeyPackage {
|
||||
KeyPackage::new(
|
||||
Identifier::try_from(1).unwrap(),
|
||||
SigningShare::deserialize(<[u8; 32]>::from_hex(SIGNING_SHARE).unwrap()).unwrap(),
|
||||
|
@ -27,32 +30,40 @@ fn build_key_package() -> KeyPackage {
|
|||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_valid_round_1_inputs() {
|
||||
#[tokio::test]
|
||||
async fn check_valid_round_1_inputs() {
|
||||
let config = Round1Config {
|
||||
key_package: build_key_package(),
|
||||
key_package: build_key_package().await,
|
||||
};
|
||||
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
let args = Args {
|
||||
key_package: "-".to_string(),
|
||||
ip: "0.0.0.0".to_string(),
|
||||
port: 80,
|
||||
};
|
||||
|
||||
let input = SECRET_SHARE_JSON;
|
||||
let mut valid_input = input.as_bytes();
|
||||
|
||||
let expected = request_inputs(&mut valid_input, &mut buf).unwrap();
|
||||
let expected = request_inputs(&args, &mut valid_input, &mut buf)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(expected, config);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_0_input_for_identifier() {
|
||||
#[tokio::test]
|
||||
async fn check_0_input_for_identifier() {
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
let args = Args::default();
|
||||
|
||||
let input = r#"{"identifier":"0000000000000000000000000000000000000000000000000000000000000000","value":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
|
||||
let mut invalid_input = input.as_bytes();
|
||||
|
||||
// let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
|
||||
|
||||
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
|
||||
let expected = request_inputs(&args, &mut invalid_input, &mut buf)
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
*expected.downcast::<Error>().unwrap(),
|
||||
|
@ -60,15 +71,18 @@ fn check_0_input_for_identifier() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_invalid_length_signing_share() {
|
||||
#[tokio::test]
|
||||
async fn check_invalid_length_signing_share() {
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
let args = Args::default();
|
||||
|
||||
let input = r#"{"identifier":"0100000000000000000000000000000000000000000000000000000000000000","value":"ed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
|
||||
|
||||
let mut invalid_input = input.as_bytes();
|
||||
|
||||
let expected = request_inputs(&mut invalid_input, &mut buf).unwrap_err();
|
||||
let expected = request_inputs(&args, &mut invalid_input, &mut buf)
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
*expected.downcast::<Error>().unwrap(),
|
||||
|
@ -76,15 +90,18 @@ fn check_invalid_length_signing_share() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_invalid_round_1_inputs() {
|
||||
#[tokio::test]
|
||||
async fn check_invalid_round_1_inputs() {
|
||||
let input = r#"{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"signing_share":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","926d5910e146dccb9148ca39dc7607f4f7123ff1c0ffaf109add1d165c568bf2", "291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"]}"#;
|
||||
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
let args = Args::default();
|
||||
|
||||
let mut valid_input = input.as_bytes();
|
||||
|
||||
let expected = request_inputs(&mut valid_input, &mut buf).unwrap_err();
|
||||
let expected = request_inputs(&args, &mut valid_input, &mut buf)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
*expected.downcast::<Error>().unwrap(),
|
||||
Error::InvalidSecretShare
|
||||
|
@ -92,21 +109,23 @@ fn check_invalid_round_1_inputs() {
|
|||
}
|
||||
|
||||
// TODO: Handle this error differently
|
||||
#[test]
|
||||
fn check_invalid_length_vss_commitment() {
|
||||
#[tokio::test]
|
||||
async fn check_invalid_length_vss_commitment() {
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
let args = Args::default();
|
||||
|
||||
let input = r#"{"identifier":"0100000000000000000000000000000000000000000000000000000000000000","value":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["7e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
|
||||
|
||||
let mut invalid_input = input.as_bytes();
|
||||
|
||||
let expected = request_inputs(&mut invalid_input, &mut buf);
|
||||
assert!(expected.is_err())
|
||||
let expected = request_inputs(&args, &mut invalid_input, &mut buf);
|
||||
assert!(expected.await.is_err())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_print_values() {
|
||||
#[tokio::test]
|
||||
async fn check_print_values() {
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
|
||||
let signing_share =
|
||||
SigningShare::deserialize(<[u8; 32]>::from_hex(SIGNING_SHARE).unwrap()).unwrap();
|
||||
let mut rng = thread_rng();
|
||||
|
|
|
@ -10,6 +10,7 @@ use frost::{
|
|||
};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use participant::comms::cli::CLIComms;
|
||||
use participant::round2::print_values_round_2;
|
||||
use participant::round2::{generate_signature, round_2_request_inputs, Round2Config};
|
||||
use rand::thread_rng;
|
||||
|
@ -31,12 +32,13 @@ pub fn nonce_commitment(input: &str) -> NonceCommitment {
|
|||
NonceCommitment::deserialize(<[u8; 32]>::from_hex(input).unwrap()).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_valid_round_2_inputs() {
|
||||
#[tokio::test]
|
||||
async fn check_valid_round_2_inputs() {
|
||||
// TODO: refactor
|
||||
|
||||
// Generate commitments
|
||||
|
||||
let mut comms = CLIComms {};
|
||||
let my_signer_commitments = SigningCommitments::new(
|
||||
nonce_commitment(MY_HIDING_COMMITMENT),
|
||||
nonce_commitment(MY_BINDING_COMMITMENT),
|
||||
|
@ -64,7 +66,14 @@ fn check_valid_round_2_inputs() {
|
|||
let input = format!("{}\n", signing_package);
|
||||
let mut valid_input = input.as_bytes();
|
||||
|
||||
let round_2_config = round_2_request_inputs(&mut valid_input, &mut buf);
|
||||
let round_2_config = round_2_request_inputs(
|
||||
&mut comms,
|
||||
&mut valid_input,
|
||||
&mut buf,
|
||||
my_signer_commitments,
|
||||
Identifier::try_from(1).unwrap(),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(round_2_config.is_ok());
|
||||
assert_eq!(
|
||||
|
@ -75,8 +84,8 @@ fn check_valid_round_2_inputs() {
|
|||
|
||||
// TODO: test for invalid inputs
|
||||
|
||||
#[test]
|
||||
fn check_sign() {
|
||||
#[tokio::test]
|
||||
async fn check_sign() {
|
||||
let key_package = KeyPackage::new(
|
||||
Identifier::try_from(1).unwrap(),
|
||||
SigningShare::deserialize(<[u8; 32]>::from_hex(SIGNING_SHARE).unwrap()).unwrap(),
|
||||
|
@ -85,10 +94,6 @@ fn check_sign() {
|
|||
2,
|
||||
);
|
||||
|
||||
// let config = Round1Config {
|
||||
// key_package
|
||||
// };
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// TODO: Nonce doesn't seem to be exported. Look into this to improve these tests
|
||||
|
@ -119,8 +124,8 @@ fn check_sign() {
|
|||
assert!(signature.is_ok()) // TODO: Should be able to test this more specifically when I remove randomness from the test
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_print_values_round_2() {
|
||||
#[tokio::test]
|
||||
async fn check_print_values_round_2() {
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
|
||||
const SIGNATURE_SHARE: &str =
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#![cfg(not(feature = "redpallas"))]
|
||||
|
||||
use coordinator::args::Args;
|
||||
use coordinator::comms::cli::CLIComms;
|
||||
use coordinator::args::Args as CoordinatorArgs;
|
||||
use coordinator::comms::cli::CLIComms as CoordinatorCLIComms;
|
||||
|
||||
use participant::args::Args as ParticipantArgs;
|
||||
use participant::comms::cli::CLIComms as ParticipantCLIComms;
|
||||
|
||||
use frost_ed25519 as frost;
|
||||
|
||||
use frost::keys::IdentifierList;
|
||||
|
@ -26,8 +30,12 @@ async fn trusted_dealer_journey() {
|
|||
let mut buf = BufWriter::new(Vec::new());
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let args = Args::default();
|
||||
let mut comms = CLIComms {};
|
||||
let coordinator_args = CoordinatorArgs::default();
|
||||
let mut coordinator_comms = CoordinatorCLIComms {};
|
||||
|
||||
// For a CLI test we can use the same CLIComms instance
|
||||
let mut participant_comms = ParticipantCLIComms {};
|
||||
let participant_args = ParticipantArgs::default();
|
||||
|
||||
// Trusted dealer
|
||||
|
||||
|
@ -57,10 +65,12 @@ async fn trusted_dealer_journey() {
|
|||
key_packages.insert(identifier, key_package);
|
||||
}
|
||||
|
||||
let mut nonces_map = HashMap::new();
|
||||
// Round 1
|
||||
|
||||
let mut nonces_map = BTreeMap::new();
|
||||
let mut commitments_map = BTreeMap::new();
|
||||
|
||||
for participant_index in 1..=3 {
|
||||
for participant_index in 1..=3u16 {
|
||||
let participant_identifier = Identifier::try_from(participant_index).unwrap();
|
||||
|
||||
let share = key_packages[&participant_identifier].signing_share();
|
||||
|
@ -70,7 +80,9 @@ async fn trusted_dealer_journey() {
|
|||
&serde_json::to_string(&key_packages[&participant_identifier]).unwrap()
|
||||
);
|
||||
let round_1_config =
|
||||
participant_input_round_1(&mut round_1_input.as_bytes(), &mut buf).unwrap();
|
||||
participant_input_round_1(&participant_args, &mut round_1_input.as_bytes(), &mut buf)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
round_1_config.key_package,
|
||||
|
@ -95,10 +107,14 @@ async fn trusted_dealer_journey() {
|
|||
serde_json::to_string(&commitments_map[&participant_id_3]).unwrap(),
|
||||
);
|
||||
|
||||
let participants_config =
|
||||
coordinator::step_1::step_1(&args, &mut comms, &mut step_1_input.as_bytes(), &mut buf)
|
||||
.await
|
||||
.unwrap();
|
||||
let participants_config = coordinator::step_1::step_1(
|
||||
&coordinator_args,
|
||||
&mut coordinator_comms,
|
||||
&mut step_1_input.as_bytes(),
|
||||
&mut buf,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Coordinator step 2
|
||||
|
||||
|
@ -107,23 +123,36 @@ async fn trusted_dealer_journey() {
|
|||
let message = "74657374";
|
||||
let step_2_input = format!("{}\n", message);
|
||||
|
||||
let signing_package =
|
||||
coordinator::step_2::step_2(&mut step_2_input.as_bytes(), &mut buf, commitments_map)
|
||||
.unwrap();
|
||||
let signing_package = coordinator::step_2::step_2(
|
||||
&mut step_2_input.as_bytes(),
|
||||
&mut buf,
|
||||
commitments_map.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Participants round 2
|
||||
// Round 2
|
||||
|
||||
for participant_identifier in nonces_map.keys() {
|
||||
for participant_index in 1..=3 {
|
||||
let participant_identifier = Identifier::try_from(participant_index).unwrap();
|
||||
let signing_commitments = commitments_map[&participant_identifier];
|
||||
let round_2_input = format!("{}\n", serde_json::to_string(&signing_package).unwrap());
|
||||
let round_2_config =
|
||||
participant_input_round_2(&mut round_2_input.as_bytes(), &mut buf).unwrap();
|
||||
let round_2_config = participant_input_round_2(
|
||||
&mut participant_comms,
|
||||
&mut round_2_input.as_bytes(),
|
||||
&mut buf,
|
||||
signing_commitments,
|
||||
participant_identifier,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let signature = generate_signature(
|
||||
round_2_config,
|
||||
&key_packages[participant_identifier],
|
||||
&nonces_map[participant_identifier],
|
||||
&key_packages[&participant_identifier],
|
||||
&nonces_map[&participant_identifier],
|
||||
)
|
||||
.unwrap();
|
||||
signature_shares.insert(*participant_identifier, signature);
|
||||
signature_shares.insert(participant_identifier, signature);
|
||||
}
|
||||
|
||||
// coordinator step 3
|
||||
|
@ -135,7 +164,7 @@ async fn trusted_dealer_journey() {
|
|||
serde_json::to_string(&signature_shares[&participant_id_3]).unwrap()
|
||||
);
|
||||
let group_signature = coordinator::step_3::step_3(
|
||||
&mut comms,
|
||||
&mut coordinator_comms,
|
||||
&mut step_3_input.as_bytes(),
|
||||
&mut buf,
|
||||
participants_config,
|
||||
|
|
Loading…
Reference in New Issue