Add initial implementation of socket communications to the demo (phase 1) - Coordinator (#89)
* move commitments to step_1 * halfway through making things async; need to fix handling input/output * async step_1 * async step_3 * started SocketComms * SocketComms compiling * Finished SocketComms; untested * fixed existing tests * update frost-rerandomized; skip tests if redpallas enabled * ci: use nightly, and overall cleanup * point frost to 1.0.0-rc.0
This commit is contained in:
parent
3cd81382e5
commit
0a9e830fa0
|
@ -27,11 +27,8 @@ jobs:
|
|||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions-rs/toolchain@v1.0.7
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
profile: minimal
|
||||
components: llvm-tools-preview
|
||||
|
||||
- name: Install cargo-llvm-cov cargo command
|
||||
|
|
|
@ -10,14 +10,26 @@ on:
|
|||
|
||||
jobs:
|
||||
|
||||
build_redpallas:
|
||||
name: Build with redpallas
|
||||
# We're using nightly for the async traits.
|
||||
# TODO: Revert back to stable when that is stabilized.
|
||||
|
||||
test_ed25519:
|
||||
name: Test with ed25519
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo build --features redpallas
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cargo test
|
||||
|
||||
test_redpallas:
|
||||
name: Test with redpallas
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cargo test --features redpallas
|
||||
|
||||
clippy:
|
||||
name: Clippy
|
||||
|
@ -27,34 +39,10 @@ jobs:
|
|||
- uses: actions/checkout@v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions-rs/toolchain@v1.0.7
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
- name: Check workflow permissions
|
||||
id: check_permissions
|
||||
uses: scherermichael-oss/action-has-permission@1.0.6
|
||||
with:
|
||||
required-permission: write
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Run clippy action to produce annotations
|
||||
uses: actions-rs/clippy-check@v1.0.7
|
||||
if: ${{ steps.check_permissions.outputs.has-permission }}
|
||||
with:
|
||||
# GitHub displays the clippy job and its results as separate entries
|
||||
name: Clippy (stable) Results
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Notet that we don't use --all-features because we go against Rust
|
||||
# convention and have a non-additive "redpallas" feature, and the
|
||||
# tests only work without it currently.
|
||||
args: --all-targets -- -D warnings
|
||||
|
||||
components: rustfmt, clippy
|
||||
- name: Run clippy manually without annotations
|
||||
if: ${{ !steps.check_permissions.outputs.has-permission }}
|
||||
run: cargo clippy --all-targets -- -D warnings
|
||||
|
||||
fmt:
|
||||
|
@ -65,19 +53,12 @@ jobs:
|
|||
- uses: actions/checkout@v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions-rs/toolchain@v1.0.7
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
toolchain: stable
|
||||
components: rustfmt
|
||||
override: true
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- uses: actions-rs/cargo@v1.0.3
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
- name: Run rustfmt
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
actionlint:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,14 +7,17 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
eyre = "0.6.9"
|
||||
frost-ed25519 = { version = "0.6.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "5ea1293bb8df90c8a19dedf7ab5510903650dda9", features = ["frost"] }
|
||||
frost-ed25519 = { version = "1.0.0-rc.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "6e55be4da9fa7beec9f744d49a1bad844318a932", features = ["frost", "serde"] }
|
||||
hex = { version = "0.4", features = ["serde"] }
|
||||
thiserror = "1.0"
|
||||
rand = "0.8"
|
||||
serde_json = "1.0"
|
||||
itertools = "0.12.0"
|
||||
exitcode = "1.1.2"
|
||||
clap = { version = "4.4.7", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
message-io = "0.18"
|
||||
|
||||
[features]
|
||||
redpallas = []
|
||||
|
|
|
@ -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 = 'P', long, default_value = "public-key-package.json")]
|
||||
pub public_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,5 +1,7 @@
|
|||
use std::io::{BufRead, Write};
|
||||
|
||||
use crate::args::Args;
|
||||
use crate::comms::cli::CLIComms;
|
||||
use crate::step_1::step_1;
|
||||
use crate::step_2::step_2;
|
||||
use crate::step_3::step_3;
|
||||
|
@ -7,20 +9,23 @@ use crate::step_3::step_3;
|
|||
#[cfg(feature = "redpallas")]
|
||||
use crate::step_3::request_randomizer;
|
||||
|
||||
pub fn cli(
|
||||
pub async fn cli(
|
||||
args: &Args,
|
||||
reader: &mut impl BufRead,
|
||||
logger: &mut impl Write,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
writeln!(logger, "\n=== STEP 1: CHOOSE PARTICIPANTS ===\n")?;
|
||||
|
||||
let participants_config = step_1(reader, logger)?;
|
||||
let mut comms = CLIComms {};
|
||||
|
||||
let participants_config = step_1(args, &mut comms, reader, logger).await?;
|
||||
|
||||
writeln!(
|
||||
logger,
|
||||
"=== STEP 2: CHOOSE MESSAGE AND GENERATE COMMITMENT PACKAGE ===\n"
|
||||
)?;
|
||||
|
||||
let signing_package = step_2(reader, logger, participants_config.participants.clone())?;
|
||||
let signing_package = step_2(reader, logger, participants_config.commitments.clone())?;
|
||||
|
||||
#[cfg(feature = "redpallas")]
|
||||
let randomizer = request_randomizer(reader, logger)?;
|
||||
|
@ -28,13 +33,15 @@ pub fn cli(
|
|||
writeln!(logger, "=== STEP 3: BUILD GROUP SIGNATURE ===\n")?;
|
||||
|
||||
step_3(
|
||||
&mut comms,
|
||||
reader,
|
||||
logger,
|
||||
participants_config,
|
||||
signing_package,
|
||||
&signing_package,
|
||||
#[cfg(feature = "redpallas")]
|
||||
randomizer,
|
||||
);
|
||||
)
|
||||
.await?;
|
||||
|
||||
writeln!(logger, "=== END ===")?;
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
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 frost::{
|
||||
keys::PublicKeyPackage,
|
||||
round1::SigningCommitments,
|
||||
round2::SignatureShare,
|
||||
serde::{self, Deserialize, Serialize},
|
||||
Identifier, SigningPackage,
|
||||
};
|
||||
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
error::Error,
|
||||
io::{BufRead, Write},
|
||||
};
|
||||
|
||||
#[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_commitments(
|
||||
&mut self,
|
||||
input: &mut dyn BufRead,
|
||||
output: &mut dyn Write,
|
||||
pub_key_package: &PublicKeyPackage,
|
||||
num_of_participants: u16,
|
||||
) -> Result<BTreeMap<Identifier, SigningCommitments>, Box<dyn Error>>;
|
||||
|
||||
async fn get_signature_shares(
|
||||
&mut self,
|
||||
input: &mut dyn BufRead,
|
||||
output: &mut dyn Write,
|
||||
signing_package: &SigningPackage,
|
||||
#[cfg(feature = "redpallas")] randomizer: frost::round2::Randomizer,
|
||||
) -> Result<BTreeMap<Identifier, SignatureShare>, Box<dyn Error>>;
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
//! 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::{
|
||||
collections::BTreeMap,
|
||||
error::Error,
|
||||
io::{BufRead, Write},
|
||||
};
|
||||
|
||||
use super::Comms;
|
||||
|
||||
pub struct CLIComms {}
|
||||
|
||||
impl Comms for CLIComms {
|
||||
async fn get_signing_commitments(
|
||||
&mut self,
|
||||
input: &mut dyn BufRead,
|
||||
output: &mut dyn Write,
|
||||
pub_key_package: &PublicKeyPackage,
|
||||
num_of_participants: u16,
|
||||
) -> Result<BTreeMap<Identifier, SigningCommitments>, Box<dyn Error>> {
|
||||
let mut participants_list = Vec::new();
|
||||
let mut commitments_list: BTreeMap<Identifier, SigningCommitments> = BTreeMap::new();
|
||||
|
||||
for i in 1..=num_of_participants {
|
||||
writeln!(output, "Identifier for participant {:?} (hex encoded): ", i)?;
|
||||
let id_value = read_identifier(input)?;
|
||||
validate(id_value, pub_key_package, &participants_list)?;
|
||||
participants_list.push(id_value);
|
||||
|
||||
writeln!(
|
||||
output,
|
||||
"Please enter JSON encoded commitments for participant {}:",
|
||||
hex::encode(id_value.serialize())
|
||||
)?;
|
||||
let mut commitments_input = String::new();
|
||||
input.read_line(&mut commitments_input)?;
|
||||
let commitments = serde_json::from_str(&commitments_input)?;
|
||||
commitments_list.insert(id_value, commitments);
|
||||
}
|
||||
|
||||
Ok(commitments_list)
|
||||
}
|
||||
|
||||
async fn get_signature_shares(
|
||||
&mut self,
|
||||
input: &mut dyn BufRead,
|
||||
output: &mut dyn Write,
|
||||
signing_package: &SigningPackage,
|
||||
#[cfg(feature = "redpallas")] _randomizer: frost::round2::Randomizer,
|
||||
) -> Result<BTreeMap<Identifier, SignatureShare>, Box<dyn Error>> {
|
||||
let mut signatures_list: BTreeMap<Identifier, SignatureShare> = BTreeMap::new();
|
||||
for p in signing_package.signing_commitments().keys() {
|
||||
writeln!(
|
||||
output,
|
||||
"Please enter JSON encoded signature shares for participant {}:",
|
||||
hex::encode(p.serialize())
|
||||
)?;
|
||||
|
||||
let mut signature_input = String::new();
|
||||
input.read_line(&mut signature_input)?;
|
||||
let signatures = serde_json::from_str(&signature_input)?;
|
||||
signatures_list.insert(*p, signatures);
|
||||
}
|
||||
Ok(signatures_list)
|
||||
}
|
||||
}
|
||||
|
||||
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,142 @@
|
|||
//! 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::{
|
||||
keys::PublicKeyPackage, round1::SigningCommitments, round2::SignatureShare, Identifier,
|
||||
SigningPackage,
|
||||
};
|
||||
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
error::Error,
|
||||
io::{BufRead, Write},
|
||||
};
|
||||
|
||||
use super::{Comms, Message};
|
||||
use crate::args::Args;
|
||||
|
||||
pub struct SocketComms {
|
||||
input_rx: Receiver<(Endpoint, Vec<u8>)>,
|
||||
endpoints: BTreeMap<Identifier, 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(100);
|
||||
|
||||
handler
|
||||
.network()
|
||||
.listen(Transport::FramedTcp, addr)
|
||||
.unwrap();
|
||||
|
||||
let socket_comm = Self {
|
||||
input_rx: rx,
|
||||
endpoints: BTreeMap::new(),
|
||||
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(_, _) => unreachable!(), // Used for explicit connections.
|
||||
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()));
|
||||
}
|
||||
NetEvent::Disconnected(_endpoint) => println!("Client disconnected"), //Tcp or Ws
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Comms for SocketComms {
|
||||
async fn get_signing_commitments(
|
||||
&mut self,
|
||||
_input: &mut dyn BufRead,
|
||||
_output: &mut dyn Write,
|
||||
_pub_key_package: &PublicKeyPackage,
|
||||
num_of_participants: u16,
|
||||
) -> Result<BTreeMap<Identifier, SigningCommitments>, Box<dyn Error>> {
|
||||
self.endpoints = BTreeMap::new();
|
||||
let mut signing_commitments = BTreeMap::new();
|
||||
for _ in 0..num_of_participants {
|
||||
let (endpoint, data) = self
|
||||
.input_rx
|
||||
.recv()
|
||||
.await
|
||||
.ok_or(eyre!("Did not receive all commitments"))?;
|
||||
let message: Message = serde_json::from_slice(&data)?;
|
||||
if let Message::IdentifiedCommitments {
|
||||
identifier,
|
||||
commitments,
|
||||
} = message
|
||||
{
|
||||
self.endpoints.insert(identifier, endpoint);
|
||||
signing_commitments.insert(identifier, commitments);
|
||||
} else {
|
||||
Err(eyre!("Expected IdentifiedCommitments message"))?;
|
||||
}
|
||||
}
|
||||
Ok(signing_commitments)
|
||||
}
|
||||
|
||||
async fn get_signature_shares(
|
||||
&mut self,
|
||||
_input: &mut dyn BufRead,
|
||||
_output: &mut dyn Write,
|
||||
signing_package: &SigningPackage,
|
||||
#[cfg(feature = "redpallas")] _randomizer: frost::round2::Randomizer,
|
||||
) -> Result<BTreeMap<Identifier, SignatureShare>, Box<dyn Error>> {
|
||||
// Send SigningPackage to all participants
|
||||
let data = serde_json::to_vec(&Message::SigningPackage(signing_package.clone()))?;
|
||||
for identifier in signing_package.signing_commitments().keys() {
|
||||
let endpoint = self
|
||||
.endpoints
|
||||
.get(identifier)
|
||||
.ok_or(eyre!("unknown identifier"))?;
|
||||
self.handler.network().send(*endpoint, &data);
|
||||
}
|
||||
// Read SignatureShare from all participants
|
||||
let mut signature_shares = BTreeMap::new();
|
||||
for _ in 0..signing_package.signing_commitments().len() {
|
||||
let (endpoint, data) = self
|
||||
.input_rx
|
||||
.recv()
|
||||
.await
|
||||
.ok_or(eyre!("Did not receive all commitments"))?;
|
||||
let message: Message = serde_json::from_slice(&data)?;
|
||||
if let Message::SignatureShare(signature_share) = message {
|
||||
let identifier = self
|
||||
.endpoints
|
||||
.iter()
|
||||
.find_map(|(i, e)| if *e == endpoint { Some(i) } else { None })
|
||||
.ok_or(eyre!("Unknown participant"))?;
|
||||
signature_shares.insert(*identifier, signature_share);
|
||||
} else {
|
||||
Err(eyre!("Expected IdentifiedCommitments message"))?;
|
||||
}
|
||||
}
|
||||
Ok(signature_shares)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
pub mod args;
|
||||
pub mod cli;
|
||||
pub mod comms;
|
||||
|
||||
pub mod input;
|
||||
pub mod step_1;
|
||||
pub mod step_2;
|
||||
pub mod step_3;
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
use std::io;
|
||||
|
||||
use coordinator::cli::cli;
|
||||
use clap::Parser;
|
||||
|
||||
use coordinator::{args::Args, cli::cli};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = Args::parse();
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
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,100 +3,83 @@ use frost_ed25519 as frost;
|
|||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas as frost;
|
||||
|
||||
use frost::{keys::PublicKeyPackage, Error, Identifier};
|
||||
use frost::{keys::PublicKeyPackage, round1::SigningCommitments, Identifier};
|
||||
|
||||
use eyre::eyre;
|
||||
use std::io::{BufRead, Write};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
io::{BufRead, Write},
|
||||
};
|
||||
|
||||
use crate::{args::Args, comms::Comms, input::read_from_file_or_stdin};
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct ParticipantsConfig {
|
||||
pub participants: Vec<Identifier>,
|
||||
pub commitments: BTreeMap<Identifier, SigningCommitments>,
|
||||
pub pub_key_package: PublicKeyPackage,
|
||||
}
|
||||
|
||||
// TODO: needs to include the coordinator's keys!
|
||||
pub fn step_1(
|
||||
reader: &mut impl BufRead,
|
||||
pub async fn step_1(
|
||||
args: &Args,
|
||||
comms: &mut impl Comms,
|
||||
reader: &mut dyn BufRead,
|
||||
logger: &mut dyn Write,
|
||||
) -> Result<ParticipantsConfig, Error> {
|
||||
let participants = choose_participants(reader, logger)?;
|
||||
print_participants(logger, &participants.participants);
|
||||
) -> Result<ParticipantsConfig, Box<dyn std::error::Error>> {
|
||||
let participants = read_commitments(args, comms, reader, logger).await?;
|
||||
print_participants(logger, &participants.commitments);
|
||||
Ok(participants)
|
||||
}
|
||||
|
||||
fn validate(
|
||||
id: Identifier,
|
||||
key_package: PublicKeyPackage,
|
||||
id_list: &[Identifier],
|
||||
) -> Result<(), Error> {
|
||||
if !key_package.signer_pubkeys().contains_key(&id) {
|
||||
return Err(Error::MalformedIdentifier);
|
||||
}; // TODO: Error is actually that the identifier does not exist
|
||||
if id_list.contains(&id) {
|
||||
return Err(Error::DuplicatedIdentifier);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: validate min num of participants
|
||||
|
||||
pub fn read_identifier(input: &mut impl BufRead) -> Result<Identifier, Box<dyn std::error::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)
|
||||
}
|
||||
|
||||
// Input required:
|
||||
// 1. public key package
|
||||
// 2. number of participants
|
||||
// 3. identifiers for all participants
|
||||
fn choose_participants(
|
||||
input: &mut impl BufRead,
|
||||
async fn read_commitments(
|
||||
args: &Args,
|
||||
comms: &mut impl Comms,
|
||||
input: &mut dyn BufRead,
|
||||
logger: &mut dyn Write,
|
||||
) -> Result<ParticipantsConfig, Error> {
|
||||
writeln!(logger, "Paste the JSON public key package: ").unwrap();
|
||||
let mut key_package = String::new();
|
||||
input.read_line(&mut key_package).unwrap();
|
||||
let pub_key_package: PublicKeyPackage = serde_json::from_str(&key_package).unwrap();
|
||||
) -> Result<ParticipantsConfig, Box<dyn std::error::Error>> {
|
||||
let pub_key_package = read_from_file_or_stdin(
|
||||
input,
|
||||
logger,
|
||||
"public key package",
|
||||
&args.public_key_package,
|
||||
)?;
|
||||
let pub_key_package: PublicKeyPackage = serde_json::from_str(&pub_key_package)?;
|
||||
|
||||
writeln!(logger, "The number of participants: ").unwrap();
|
||||
writeln!(logger, "The number of participants: ")?;
|
||||
|
||||
let mut participants = String::new();
|
||||
input.read_line(&mut participants).unwrap();
|
||||
let num_of_participants = participants.trim().parse::<u16>().unwrap();
|
||||
input.read_line(&mut participants)?;
|
||||
let num_of_participants = participants.trim().parse::<u16>()?;
|
||||
|
||||
let mut participants_list = Vec::new();
|
||||
let commitments_list = comms
|
||||
.get_signing_commitments(input, logger, &pub_key_package, num_of_participants)
|
||||
.await?;
|
||||
|
||||
for i in 1..=num_of_participants {
|
||||
let package = pub_key_package.clone();
|
||||
writeln!(logger, "Identifier for participant {:?} (hex encoded): ", i).unwrap();
|
||||
|
||||
let id_value = read_identifier(input).unwrap();
|
||||
|
||||
validate(id_value, package, &participants_list)?;
|
||||
|
||||
participants_list.push(id_value)
|
||||
}
|
||||
Ok(ParticipantsConfig {
|
||||
participants: participants_list,
|
||||
commitments: commitments_list,
|
||||
pub_key_package,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn print_participants(logger: &mut dyn Write, participants: &Vec<Identifier>) {
|
||||
pub fn print_participants(
|
||||
logger: &mut dyn Write,
|
||||
participants: &BTreeMap<Identifier, SigningCommitments>,
|
||||
) {
|
||||
writeln!(logger, "Selected participants: ",).unwrap();
|
||||
|
||||
for p in participants {
|
||||
for p in participants.keys() {
|
||||
writeln!(logger, "{}", serde_json::to_string(p).unwrap()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, not(feature = "redpallas")))]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use frost::{
|
||||
keys::{PublicKeyPackage, VerifyingShare},
|
||||
|
@ -105,7 +88,7 @@ mod tests {
|
|||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
|
||||
use crate::step_1::validate;
|
||||
use crate::comms::cli::validate;
|
||||
|
||||
const PUBLIC_KEY_1: &str = "fc2c9b8e335c132d9ebe0403c9317aac480bbbf8cbdb1bc3730bb68eb60dadf9";
|
||||
const PUBLIC_KEY_2: &str = "2cff4148a2f965801fb1f25f1d2a4e5df2f75b3a57cd06f30471c2c774419a41";
|
||||
|
@ -116,7 +99,7 @@ mod tests {
|
|||
let id_1 = Identifier::try_from(1).unwrap();
|
||||
let id_2 = Identifier::try_from(2).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(),
|
||||
|
@ -126,7 +109,8 @@ mod tests {
|
|||
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY_2).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)
|
||||
}
|
||||
|
@ -139,7 +123,7 @@ mod tests {
|
|||
let id_list = [id_1];
|
||||
let key_package = build_pub_key_package();
|
||||
|
||||
let validated = validate(id_2, key_package, &id_list);
|
||||
let validated = validate(id_2, &key_package, &id_list);
|
||||
|
||||
assert!(validated.is_ok())
|
||||
}
|
||||
|
@ -153,7 +137,7 @@ mod tests {
|
|||
let id_list = [id_1, id_2];
|
||||
let key_package = build_pub_key_package();
|
||||
|
||||
let validated = validate(id_3, key_package, &id_list);
|
||||
let validated = validate(id_3, &key_package, &id_list);
|
||||
assert!(validated.is_err());
|
||||
assert!(validated == Err(Error::MalformedIdentifier))
|
||||
}
|
||||
|
@ -166,7 +150,7 @@ mod tests {
|
|||
let id_list = [id_1, id_2];
|
||||
let key_package = build_pub_key_package();
|
||||
|
||||
let validated = validate(id_1, key_package, &id_list);
|
||||
let validated = validate(id_1, &key_package, &id_list);
|
||||
assert!(validated.is_err());
|
||||
assert!(validated == Err(Error::DuplicatedIdentifier))
|
||||
}
|
||||
|
|
|
@ -19,21 +19,19 @@ pub struct CommitmentsConfig {
|
|||
pub fn step_2(
|
||||
input: &mut impl BufRead,
|
||||
logger: &mut dyn Write,
|
||||
participants: Vec<Identifier>,
|
||||
commitments: BTreeMap<Identifier, SigningCommitments>,
|
||||
) -> Result<SigningPackage, Box<dyn std::error::Error>> {
|
||||
let signing_package = request_inputs_commitments(input, logger, participants)?;
|
||||
print_commitments(logger, &signing_package);
|
||||
let signing_package = request_message(input, logger, commitments)?;
|
||||
print_signing_package(logger, &signing_package);
|
||||
Ok(signing_package)
|
||||
}
|
||||
|
||||
// Input required:
|
||||
// 1. message
|
||||
// 2. number of signers
|
||||
// 3. commitments for all signers
|
||||
fn request_inputs_commitments(
|
||||
fn request_message(
|
||||
input: &mut impl BufRead,
|
||||
logger: &mut dyn Write,
|
||||
participants: Vec<Identifier>,
|
||||
commitments: BTreeMap<Identifier, SigningCommitments>,
|
||||
) -> Result<SigningPackage, Box<dyn std::error::Error>> {
|
||||
writeln!(logger, "The message to be signed (hex encoded)")?;
|
||||
|
||||
|
@ -42,27 +40,12 @@ fn request_inputs_commitments(
|
|||
|
||||
let message = hex::decode(msg.trim())?;
|
||||
|
||||
let mut commitments_list: BTreeMap<Identifier, SigningCommitments> = BTreeMap::new();
|
||||
|
||||
for p in participants {
|
||||
writeln!(
|
||||
logger,
|
||||
"Please enter JSON encoded commitments for participant {}:",
|
||||
hex::encode(p.serialize())
|
||||
)?; // TODO: improve printing
|
||||
|
||||
let mut commitments_input = String::new();
|
||||
input.read_line(&mut commitments_input)?;
|
||||
let commitments = serde_json::from_str(&commitments_input)?;
|
||||
commitments_list.insert(p, commitments);
|
||||
}
|
||||
|
||||
let signing_package = SigningPackage::new(commitments_list, &message);
|
||||
let signing_package = SigningPackage::new(commitments, &message);
|
||||
|
||||
Ok(signing_package)
|
||||
}
|
||||
|
||||
fn print_commitments(logger: &mut dyn Write, signing_package: &SigningPackage) {
|
||||
fn print_signing_package(logger: &mut dyn Write, signing_package: &SigningPackage) {
|
||||
writeln!(
|
||||
logger,
|
||||
"Signing Package:\n{}",
|
||||
|
|
|
@ -3,14 +3,11 @@ use frost_ed25519 as frost;
|
|||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas as frost;
|
||||
|
||||
use frost::{round2::SignatureShare, Identifier, Signature, SigningPackage};
|
||||
use frost::{Signature, SigningPackage};
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{BufRead, Write},
|
||||
};
|
||||
use std::io::{BufRead, Write};
|
||||
|
||||
use crate::step_1::ParticipantsConfig;
|
||||
use crate::{comms::Comms, step_1::ParticipantsConfig};
|
||||
|
||||
#[cfg(feature = "redpallas")]
|
||||
pub fn request_randomizer(
|
||||
|
@ -29,14 +26,16 @@ pub fn request_randomizer(
|
|||
)?)
|
||||
}
|
||||
|
||||
pub fn step_3(
|
||||
input: &mut impl BufRead,
|
||||
pub async fn step_3(
|
||||
comms: &mut impl Comms,
|
||||
input: &mut dyn BufRead,
|
||||
logger: &mut dyn Write,
|
||||
participants: ParticipantsConfig,
|
||||
signing_package: SigningPackage,
|
||||
signing_package: &SigningPackage,
|
||||
#[cfg(feature = "redpallas")] randomizer: frost::round2::Randomizer,
|
||||
) -> Signature {
|
||||
) -> Result<Signature, Box<dyn std::error::Error>> {
|
||||
let group_signature = request_inputs_signature_shares(
|
||||
comms,
|
||||
input,
|
||||
logger,
|
||||
participants,
|
||||
|
@ -44,45 +43,40 @@ pub fn step_3(
|
|||
#[cfg(feature = "redpallas")]
|
||||
randomizer,
|
||||
)
|
||||
.unwrap();
|
||||
.await?;
|
||||
print_signature(logger, group_signature);
|
||||
group_signature
|
||||
Ok(group_signature)
|
||||
}
|
||||
|
||||
// Input required:
|
||||
// 1. number of signers (TODO: maybe pass this in?)
|
||||
// 2. signatures for all signers
|
||||
fn request_inputs_signature_shares(
|
||||
input: &mut impl BufRead,
|
||||
async fn request_inputs_signature_shares(
|
||||
comms: &mut impl Comms,
|
||||
input: &mut dyn BufRead,
|
||||
logger: &mut dyn Write,
|
||||
participants: ParticipantsConfig,
|
||||
signing_package: SigningPackage,
|
||||
signing_package: &SigningPackage,
|
||||
#[cfg(feature = "redpallas")] randomizer: frost::round2::Randomizer,
|
||||
) -> Result<Signature, Box<dyn std::error::Error>> {
|
||||
let mut signatures_list: HashMap<Identifier, SignatureShare> = HashMap::new();
|
||||
|
||||
for p in participants.participants {
|
||||
writeln!(
|
||||
let signatures_list = comms
|
||||
.get_signature_shares(
|
||||
input,
|
||||
logger,
|
||||
"Please enter JSON encoded signature shares for participant {}:",
|
||||
hex::encode(p.serialize())
|
||||
signing_package,
|
||||
#[cfg(feature = "redpallas")]
|
||||
randomizer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut signature_input = String::new();
|
||||
input.read_line(&mut signature_input)?;
|
||||
let signatures = serde_json::from_str(&signature_input)?;
|
||||
signatures_list.insert(p, signatures);
|
||||
}
|
||||
.await?;
|
||||
|
||||
#[cfg(feature = "redpallas")]
|
||||
let randomizer_params = frost::RandomizedParams::from_randomizer(
|
||||
participants.pub_key_package.group_public(),
|
||||
participants.pub_key_package.verifying_key(),
|
||||
randomizer,
|
||||
);
|
||||
|
||||
let group_signature = frost::aggregate(
|
||||
&signing_package,
|
||||
signing_package,
|
||||
&signatures_list,
|
||||
&participants.pub_key_package,
|
||||
#[cfg(feature = "redpallas")]
|
||||
|
|
|
@ -7,8 +7,8 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
eyre = "0.6.9"
|
||||
frost-ed25519 = { version = "0.6.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "5ea1293bb8df90c8a19dedf7ab5510903650dda9", features = ["frost"] }
|
||||
frost-ed25519 = { version = "1.0.0-rc.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "6e55be4da9fa7beec9f744d49a1bad844318a932", features = ["frost"] }
|
||||
hex = { version = "0.4", features = ["serde"] }
|
||||
thiserror = "1.0"
|
||||
rand = "0.8"
|
||||
|
|
|
@ -5,10 +5,8 @@ use reddsa::frost::redpallas as frost;
|
|||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas::keys::PositiveY;
|
||||
|
||||
use frost::keys::dkg::{round1, round2};
|
||||
use frost::Identifier;
|
||||
use rand::thread_rng;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::{BufRead, Write};
|
||||
|
||||
use crate::inputs::{read_round1_package, read_round2_package, request_inputs};
|
||||
|
@ -44,7 +42,7 @@ pub fn cli(
|
|||
"Input Round 1 Packages from the other {} participants.\n",
|
||||
config.max_signers - 1,
|
||||
)?;
|
||||
let mut received_round1_packages: HashMap<Identifier, round1::Package> = HashMap::new();
|
||||
let mut received_round1_packages = BTreeMap::new();
|
||||
for _ in 0..config.max_signers - 1 {
|
||||
let (identifier, round1_package) = read_round1_package(reader, logger)?;
|
||||
received_round1_packages.insert(identifier, round1_package);
|
||||
|
@ -73,7 +71,7 @@ pub fn cli(
|
|||
"Input Round 2 Packages from the other {} participants.\n",
|
||||
config.max_signers - 1,
|
||||
)?;
|
||||
let mut received_round2_packages: HashMap<Identifier, round2::Package> = HashMap::new();
|
||||
let mut received_round2_packages = BTreeMap::new();
|
||||
for _ in 0..config.max_signers - 1 {
|
||||
let (identifier, round2_package) = read_round2_package(reader, logger)?;
|
||||
received_round2_packages.insert(identifier, round2_package);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg(not(feature = "redpallas"))]
|
||||
|
||||
use std::io::BufWriter;
|
||||
|
||||
use crate::inputs::{request_inputs, Config};
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
#[cfg(not(feature = "redpallas"))]
|
||||
use frost_ed25519 as frost;
|
||||
#[cfg(feature = "redpallas")]
|
||||
use reddsa::frost::redpallas as frost;
|
||||
|
||||
use dkg::cli::cli;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io::{BufRead, Write};
|
||||
use std::thread;
|
||||
|
||||
use frost_ed25519::keys::{KeyPackage, PublicKeyPackage};
|
||||
use frost_ed25519::Identifier;
|
||||
use frost::keys::{KeyPackage, PublicKeyPackage};
|
||||
use frost::Identifier;
|
||||
|
||||
// Read a single line from the given reader.
|
||||
fn read_line(mut reader: impl BufRead) -> Result<String, std::io::Error> {
|
||||
|
|
|
@ -6,10 +6,11 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
frost-ed25519 = { version = "0.6.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "5ea1293bb8df90c8a19dedf7ab5510903650dda9", features = ["frost"] }
|
||||
frost-ed25519 = { version = "1.0.0-rc.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "6e55be4da9fa7beec9f744d49a1bad844318a932", features = ["frost"] }
|
||||
hex = "0.4"
|
||||
rand = "0.8"
|
||||
eyre = "0.6.8"
|
||||
exitcode = "1.1.2"
|
||||
serde_json = "1.0"
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ pub fn cli(
|
|||
writeln!(logger, "Key Package succesfully created.")?;
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let (nonces, commitments) = frost::round1::commit(key_package.secret_share(), &mut rng);
|
||||
let (nonces, commitments) = frost::round1::commit(key_package.signing_share(), &mut rng);
|
||||
|
||||
print_values(commitments, logger)?;
|
||||
|
||||
|
@ -36,7 +36,7 @@ pub fn cli(
|
|||
|
||||
let group_signature = request_signature(input, logger)?;
|
||||
key_package
|
||||
.group_public()
|
||||
.verifying_key()
|
||||
.verify(config_message.signing_package.message(), &group_signature)?;
|
||||
|
||||
writeln!(logger, "Group Signature verified.")?;
|
||||
|
|
|
@ -2,7 +2,7 @@ mod cli;
|
|||
mod round1;
|
||||
mod round2;
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, not(feature = "redpallas")))]
|
||||
mod tests;
|
||||
|
||||
use cli::cli;
|
||||
|
|
|
@ -2,11 +2,14 @@ use std::io::BufWriter;
|
|||
|
||||
use crate::cli::cli;
|
||||
|
||||
#[test]
|
||||
// TODO: to restore this test, we need to intercept that generated commitments
|
||||
// to put them inside the SigningPackage
|
||||
// #[test]
|
||||
#[allow(unused)]
|
||||
fn check_cli() {
|
||||
let key_package = r#"{"identifier":"0100000000000000000000000000000000000000000000000000000000000000","value":"ee4a66fec3ced53cac04b0abc309bb57f03f8d7dede033e4ae7b6ef57630120f","commitment":["21446705fa7da298998a567a3c2fdd7274903a886dcde9a77f615d915feb6764","56ce223ffbde8ce5971be587cbb0b8b31aa2bc220a6803b9ce73c63f9f432514","6dcc10da9443ef2c9bbd5fc6a9c3bcd4c5ede8048cc0b1342b091fd1ff6dc53c"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
|
||||
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#"{"signing_commitments":{"0100000000000000000000000000000000000000000000000000000000000000":{"hiding":"710a280fcedbcbe626fff055f682e4a525c31f157dd6071ef2c04ea0ecbe8de9","binding":"6dc707cdf26a589b3e2de4f6bae09b94d5d3bb939937b52bc6b16bdecd0b041f","ciphersuite":"FROST(Ed25519, SHA-512)"},"0200000000000000000000000000000000000000000000000000000000000000":{"hiding":"777f011bf695e27ce62474747a9c110cc3b827268047913a21030c3eba0e1eed","binding":"67f051035284cd619f0e7fc583eb3cb0c88d993aad621c856edc0f995f4588b2","ciphersuite":"FROST(Ed25519, SHA-512)"},"0300000000000000000000000000000000000000000000000000000000000000":{"hiding":"c052599bb7a52911b6b58e7c20747f12d45d23aab4aec98aaecdc7909dc6aff3","binding":"b3fbefc67070b1b56203ef875a2c7caf24802dbc943bdc62decac33287b63b23","ciphersuite":"FROST(Ed25519, SHA-512)"}},"message":"74657374","ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
|
||||
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"}"#;
|
||||
let group_signature = "\"daae8e867c1c3000687a819262099c44e4799853729d87738b4811637a659f3075829c4ee6c5f6767e11b937e18dce20886b0d3f015caaf4ccdb76d4d185910c\"";
|
||||
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
|
@ -17,5 +20,9 @@ fn check_cli() {
|
|||
);
|
||||
|
||||
let signature = cli(&mut input.as_bytes(), &mut buf);
|
||||
assert!(signature.is_ok());
|
||||
assert!(
|
||||
signature.is_ok(),
|
||||
"invalid signature: {}",
|
||||
signature.unwrap_err()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,14 +15,15 @@ use rand::thread_rng;
|
|||
const PUBLIC_KEY: &str = "adf6ab1f882d04988eadfaa52fb175bf37b6247785d7380fde3fb9d68032470d";
|
||||
const GROUP_PUBLIC_KEY: &str = "087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e";
|
||||
const SIGNING_SHARE: &str = "ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104";
|
||||
const SECRET_SHARE_JSON: &str = r#"{"identifier":"0100000000000000000000000000000000000000000000000000000000000000","value":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","926d5910e146dccb9148ca39dc7607f4f7123ff1c0ffaf109add1d165c568bf2", "291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
|
||||
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 {
|
||||
KeyPackage::new(
|
||||
Identifier::try_from(1).unwrap(),
|
||||
SigningShare::deserialize(<[u8; 32]>::from_hex(SIGNING_SHARE).unwrap()).unwrap(),
|
||||
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY).unwrap()).unwrap(),
|
||||
VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap(),
|
||||
VerifyingKey::deserialize(<[u8; 32]>::from_hex(GROUP_PUBLIC_KEY).unwrap()).unwrap(),
|
||||
3,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -77,7 +78,7 @@ fn check_invalid_length_signing_share() {
|
|||
|
||||
#[test]
|
||||
fn check_invalid_round_1_inputs() {
|
||||
let input = r#"{"value":"ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104","commitment":["087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e","926d5910e146dccb9148ca39dc7607f4f7123ff1c0ffaf109add1d165c568bf2", "291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc"],"ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
|
||||
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());
|
||||
|
||||
|
@ -115,7 +116,7 @@ fn check_print_values() {
|
|||
|
||||
let out = String::from_utf8(buf.into_inner().unwrap()).unwrap();
|
||||
|
||||
let log = format!("=== Round 1 ===\nSigningNonces were generated and stored in memory\nSigningCommitments:\n{{\"hiding\":\"{}\",\"binding\":\"{}\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}}\n=== Round 1 Completed ===\nPlease send your SigningCommitments to the coordinator\n", &hex::encode(commitments.hiding().serialize()), &hex::encode(commitments.binding().serialize()));
|
||||
let log = format!("=== Round 1 ===\nSigningNonces were generated and stored in memory\nSigningCommitments:\n{{\"header\":{{\"version\":0,\"ciphersuite\":\"FROST-ED25519-SHA512-v1\"}},\"hiding\":\"{}\",\"binding\":\"{}\"}}\n=== Round 1 Completed ===\nPlease send your SigningCommitments to the coordinator\n", &hex::encode(commitments.hiding().serialize()), &hex::encode(commitments.binding().serialize()));
|
||||
|
||||
assert_eq!(out, log)
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ fn check_valid_round_2_inputs() {
|
|||
|
||||
let message = <[u8; 32]>::from_hex(MESSAGE).unwrap();
|
||||
|
||||
let signing_package = r#"{"signing_commitments":{"0100000000000000000000000000000000000000000000000000000000000000":{"hiding":"beb81feb53ed75a2695b07f377b464a88c4c2824e7d7b63911b745df01dc2d87","binding":"d2102c5f8b8abb7ad2f1706f47a4aab3be6ede28e408f3e74baeff1f6fbcd5c0","ciphersuite":"FROST(Ed25519, SHA-512)"},"0200000000000000000000000000000000000000000000000000000000000000":{"hiding":"cc9e9503921cdd3f4d64f2c9e7b22c9ab6d7c940111ce36f84e4a114331c6edd","binding":"b0e13794eaf00be2e430b16ec7f72ab0b6579e52ca604d17406a4fd1597afd66","ciphersuite":"FROST(Ed25519, SHA-512)"}},"message":"15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673","ciphersuite":"FROST(Ed25519, SHA-512)"}"#;
|
||||
let signing_package = r#"{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"signing_commitments":{"0100000000000000000000000000000000000000000000000000000000000000":{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"hiding":"beb81feb53ed75a2695b07f377b464a88c4c2824e7d7b63911b745df01dc2d87","binding":"d2102c5f8b8abb7ad2f1706f47a4aab3be6ede28e408f3e74baeff1f6fbcd5c0"},"0200000000000000000000000000000000000000000000000000000000000000":{"header":{"version":0,"ciphersuite":"FROST-ED25519-SHA512-v1"},"hiding":"cc9e9503921cdd3f4d64f2c9e7b22c9ab6d7c940111ce36f84e4a114331c6edd","binding":"b0e13794eaf00be2e430b16ec7f72ab0b6579e52ca604d17406a4fd1597afd66"}},"message":"15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673"}"#;
|
||||
|
||||
let expected = Round2Config {
|
||||
signing_package: SigningPackage::new(signer_commitments, &message),
|
||||
|
@ -81,7 +81,8 @@ fn check_sign() {
|
|||
Identifier::try_from(1).unwrap(),
|
||||
SigningShare::deserialize(<[u8; 32]>::from_hex(SIGNING_SHARE).unwrap()).unwrap(),
|
||||
VerifyingShare::deserialize(<[u8; 32]>::from_hex(PUBLIC_KEY).unwrap()).unwrap(),
|
||||
VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap(),
|
||||
VerifyingKey::deserialize(<[u8; 32]>::from_hex(GROUP_PUBLIC_KEY).unwrap()).unwrap(),
|
||||
2,
|
||||
);
|
||||
|
||||
// let config = Round1Config {
|
||||
|
@ -91,8 +92,10 @@ fn check_sign() {
|
|||
let mut rng = thread_rng();
|
||||
|
||||
// TODO: Nonce doesn't seem to be exported. Look into this to improve these tests
|
||||
let (nonces, my_commitments) =
|
||||
round1::commit(&SigningShare::from_hex(SIGNING_SHARE).unwrap(), &mut rng);
|
||||
let (nonces, my_commitments) = round1::commit(
|
||||
&SigningShare::deserialize(<[u8; 32]>::from_hex(SIGNING_SHARE).unwrap()).unwrap(),
|
||||
&mut rng,
|
||||
);
|
||||
|
||||
let signer_commitments_2 = SigningCommitments::new(
|
||||
NonceCommitment::deserialize(<[u8; 32]>::from_hex(HIDING_COMMITMENT_2).unwrap()).unwrap(),
|
||||
|
@ -127,9 +130,7 @@ fn check_print_values_round_2() {
|
|||
|
||||
print_values_round_2(signature_response, &mut buf).unwrap();
|
||||
|
||||
let log = "Please send the following to the Coordinator\n".to_owned() +
|
||||
"SignatureShare:\n{\"share\":\"44055c54d0604cbd006f0d1713a22474d7735c5e8816b1878f62ca94bf105900\",\"ciphersuite\":\"FROST(Ed25519, SHA-512)\"}\n" +
|
||||
"=== End of Round 2 ===\n";
|
||||
let log = "Please send the following to the Coordinator\nSignatureShare:\n{\"header\":{\"version\":0,\"ciphersuite\":\"FROST-ED25519-SHA512-v1\"},\"share\":\"44055c54d0604cbd006f0d1713a22474d7735c5e8816b1878f62ca94bf105900\"}\n=== End of Round 2 ===\n";
|
||||
|
||||
let out = String::from_utf8(buf.into_inner().unwrap()).unwrap();
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg(not(feature = "redpallas"))]
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use frost::keys::IdentifierList;
|
||||
|
@ -25,7 +27,7 @@ fn check_participant() {
|
|||
let mut commitments = BTreeMap::new();
|
||||
|
||||
for i in shares.keys() {
|
||||
let (nonce, commitment) = frost::round1::commit(key_packages[&i].secret_share(), &mut rng);
|
||||
let (nonce, commitment) = frost::round1::commit(key_packages[&i].signing_share(), &mut rng);
|
||||
nonces.insert(*i, nonce);
|
||||
commitments.insert(*i, commitment);
|
||||
}
|
||||
|
@ -36,7 +38,7 @@ fn check_participant() {
|
|||
|
||||
// Round 2
|
||||
|
||||
let mut signature_shares = HashMap::new();
|
||||
let mut signature_shares = BTreeMap::new();
|
||||
|
||||
for participant_identifier in nonces.keys() {
|
||||
let config = Round2Config {
|
||||
|
@ -56,7 +58,7 @@ fn check_participant() {
|
|||
let signing_package = SigningPackage::new(commitments, &message);
|
||||
|
||||
let group_signature = aggregate(&signing_package, &signature_shares, &pubkeys).unwrap();
|
||||
let verify_signature = pubkeys.group_public().verify(&message, &group_signature);
|
||||
let verify_signature = pubkeys.verifying_key().verify(&message, &group_signature);
|
||||
|
||||
assert!(verify_signature.is_ok());
|
||||
}
|
||||
|
|
|
@ -4,17 +4,22 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
frost-ed25519 = { version = "0.6.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "5ea1293bb8df90c8a19dedf7ab5510903650dda9", features = ["frost"] }
|
||||
frost-ed25519 = { version = "1.0.0-rc.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "6e55be4da9fa7beec9f744d49a1bad844318a932", features = ["frost"] }
|
||||
hex = "0.4"
|
||||
rand = "0.8"
|
||||
exitcode = "1.1.2"
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
frost-ed25519 = { version = "0.6.0", features = ["serde"] }
|
||||
frost-ed25519 = { version = "1.0.0-rc.0", features = ["serde"] }
|
||||
dkg = { path = "../dkg"}
|
||||
trusted-dealer = { path = "../trusted-dealer"}
|
||||
participant = { path = "../participant"}
|
||||
coordinator = { path = "../coordinator"}
|
||||
rand = "0.8"
|
||||
|
||||
[features]
|
||||
redpallas = []
|
||||
default = []
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#![cfg(not(feature = "redpallas"))]
|
||||
|
||||
use coordinator::args::Args;
|
||||
use coordinator::comms::cli::CLIComms;
|
||||
use frost_ed25519 as frost;
|
||||
|
||||
use frost::keys::IdentifierList;
|
||||
|
@ -17,11 +21,14 @@ use participant::{
|
|||
round1::request_inputs as participant_input_round_1, round2::generate_signature,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn trusted_dealer_journey() {
|
||||
#[tokio::test]
|
||||
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 {};
|
||||
|
||||
// Trusted dealer
|
||||
|
||||
let dealer_input = "3\n5\n\n";
|
||||
|
@ -43,20 +50,6 @@ fn trusted_dealer_journey() {
|
|||
let participant_id_2 = Identifier::try_from(2).unwrap();
|
||||
let participant_id_3 = Identifier::try_from(3).unwrap();
|
||||
|
||||
let step_1_input = format!(
|
||||
"{}\n{}\n{}\n{}\n{}\n",
|
||||
serde_json::to_string(&pubkeys).unwrap(),
|
||||
num_of_participants,
|
||||
id_input_1,
|
||||
id_input_2,
|
||||
id_input_3
|
||||
);
|
||||
|
||||
let participants_config =
|
||||
coordinator::step_1::step_1(&mut step_1_input.as_bytes(), &mut buf).unwrap();
|
||||
|
||||
// Participants round 1
|
||||
|
||||
let mut key_packages: HashMap<_, _> = HashMap::new();
|
||||
|
||||
for (identifier, secret_share) in shares {
|
||||
|
@ -70,7 +63,7 @@ fn trusted_dealer_journey() {
|
|||
for participant_index in 1..=3 {
|
||||
let participant_identifier = Identifier::try_from(participant_index).unwrap();
|
||||
|
||||
let share = key_packages[&participant_identifier].secret_share();
|
||||
let share = key_packages[&participant_identifier].signing_share();
|
||||
|
||||
let round_1_input = format!(
|
||||
"{}\n",
|
||||
|
@ -90,25 +83,33 @@ fn trusted_dealer_journey() {
|
|||
commitments_map.insert(participant_identifier, commitments);
|
||||
}
|
||||
|
||||
let step_1_input = format!(
|
||||
"{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n",
|
||||
serde_json::to_string(&pubkeys).unwrap(),
|
||||
num_of_participants,
|
||||
id_input_1,
|
||||
serde_json::to_string(&commitments_map[&participant_id_1]).unwrap(),
|
||||
id_input_2,
|
||||
serde_json::to_string(&commitments_map[&participant_id_2]).unwrap(),
|
||||
id_input_3,
|
||||
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();
|
||||
|
||||
// Coordinator step 2
|
||||
|
||||
let mut signature_shares = HashMap::new();
|
||||
|
||||
let message = "74657374";
|
||||
let step_2_input = format!("{}\n", message);
|
||||
|
||||
let step_2_input = format!(
|
||||
"{}\n{}\n{}\n{}\n",
|
||||
message,
|
||||
serde_json::to_string(&commitments_map[&participant_id_1]).unwrap(),
|
||||
serde_json::to_string(&commitments_map[&participant_id_2]).unwrap(),
|
||||
serde_json::to_string(&commitments_map[&participant_id_3]).unwrap()
|
||||
);
|
||||
|
||||
let signing_package = coordinator::step_2::step_2(
|
||||
&mut step_2_input.as_bytes(),
|
||||
&mut buf,
|
||||
vec![participant_id_1, participant_id_2, participant_id_3],
|
||||
)
|
||||
.unwrap();
|
||||
let signing_package =
|
||||
coordinator::step_2::step_2(&mut step_2_input.as_bytes(), &mut buf, commitments_map)
|
||||
.unwrap();
|
||||
|
||||
// Participants round 2
|
||||
|
||||
|
@ -134,16 +135,19 @@ 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 step_3_input.as_bytes(),
|
||||
&mut buf,
|
||||
participants_config,
|
||||
signing_package,
|
||||
);
|
||||
&signing_package,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// verify
|
||||
|
||||
let is_signature_valid = pubkeys
|
||||
.group_public()
|
||||
.verifying_key()
|
||||
.verify("test".as_bytes(), &group_signature)
|
||||
.is_ok();
|
||||
assert!(is_signature_valid);
|
||||
|
|
|
@ -6,8 +6,8 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
frost-ed25519 = { version = "0.6.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "5ea1293bb8df90c8a19dedf7ab5510903650dda9", features = ["frost"] }
|
||||
frost-ed25519 = { version = "1.0.0-rc.0", features = ["serde"] }
|
||||
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "6e55be4da9fa7beec9f744d49a1bad844318a932", features = ["frost"] }
|
||||
thiserror = "1.0"
|
||||
rand = "0.8"
|
||||
hex = "0.4"
|
||||
|
|
|
@ -9,7 +9,7 @@ use frost::keys::{PublicKeyPackage, SecretShare};
|
|||
use frost::Error;
|
||||
use frost::Identifier;
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::{BufRead, Write};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
|
@ -79,7 +79,7 @@ pub fn request_inputs(
|
|||
}
|
||||
|
||||
pub fn print_values(
|
||||
keys: &HashMap<Identifier, SecretShare>,
|
||||
keys: &BTreeMap<Identifier, SecretShare>,
|
||||
pubkeys: &PublicKeyPackage,
|
||||
logger: &mut dyn Write,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg(not(feature = "redpallas"))]
|
||||
|
||||
use std::io::BufWriter;
|
||||
|
||||
use frost::Error;
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
#![cfg(not(feature = "redpallas"))]
|
||||
|
||||
use frost::keys::{IdentifierList, PublicKeyPackage, SecretShare};
|
||||
use frost::Identifier;
|
||||
use frost_ed25519 as frost;
|
||||
use itertools::Itertools;
|
||||
use rand::thread_rng;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::BufWriter;
|
||||
|
||||
use trusted_dealer::inputs::print_values;
|
||||
use trusted_dealer::inputs::Config;
|
||||
use trusted_dealer::trusted_dealer_keygen::{split_secret, trusted_dealer_keygen};
|
||||
|
||||
fn build_output(shares: HashMap<Identifier, SecretShare>, pubkeys: PublicKeyPackage) -> String {
|
||||
fn build_output(shares: BTreeMap<Identifier, SecretShare>, pubkeys: PublicKeyPackage) -> String {
|
||||
let pub_key_package = format!(
|
||||
"Public key package:\n{}",
|
||||
serde_json::to_string(&pubkeys).unwrap()
|
||||
|
|
|
@ -6,7 +6,7 @@ use reddsa::frost::redpallas as frost;
|
|||
use frost::keys::{IdentifierList, PublicKeyPackage, SecretShare};
|
||||
use frost::{Error, Identifier, SigningKey};
|
||||
use rand::rngs::ThreadRng;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::inputs::Config;
|
||||
|
||||
|
@ -14,7 +14,7 @@ pub fn trusted_dealer_keygen(
|
|||
config: &Config,
|
||||
identifiers: IdentifierList,
|
||||
rng: &mut ThreadRng,
|
||||
) -> Result<(HashMap<Identifier, SecretShare>, PublicKeyPackage), Error> {
|
||||
) -> Result<(BTreeMap<Identifier, SecretShare>, PublicKeyPackage), Error> {
|
||||
let (shares, pubkeys) = frost::keys::generate_with_dealer(
|
||||
config.max_signers,
|
||||
config.min_signers,
|
||||
|
@ -33,7 +33,7 @@ pub fn split_secret(
|
|||
config: &Config,
|
||||
identifiers: IdentifierList,
|
||||
rng: &mut ThreadRng,
|
||||
) -> Result<(HashMap<Identifier, SecretShare>, PublicKeyPackage), Error> {
|
||||
) -> Result<(BTreeMap<Identifier, SecretShare>, PublicKeyPackage), Error> {
|
||||
let secret_key = SigningKey::deserialize(
|
||||
config
|
||||
.secret
|
||||
|
@ -56,6 +56,7 @@ pub fn split_secret(
|
|||
Ok((shares, pubkeys))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "redpallas"))]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@ use frost::round2::SignatureShare;
|
|||
use frost::{Identifier, SigningPackage};
|
||||
use frost_ed25519 as frost;
|
||||
use rand::rngs::ThreadRng;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub fn key_package(shares: &HashMap<Identifier, SecretShare>) -> HashMap<Identifier, KeyPackage> {
|
||||
let mut key_packages: HashMap<_, _> = HashMap::new();
|
||||
pub fn key_package(shares: &BTreeMap<Identifier, SecretShare>) -> BTreeMap<Identifier, KeyPackage> {
|
||||
let mut key_packages: BTreeMap<_, _> = BTreeMap::new();
|
||||
|
||||
for (identifier, secret_share) in shares {
|
||||
let key_package = frost::keys::KeyPackage::try_from(secret_share.clone()).unwrap();
|
||||
|
@ -20,20 +20,20 @@ pub fn key_package(shares: &HashMap<Identifier, SecretShare>) -> HashMap<Identif
|
|||
pub fn round_1(
|
||||
min_signers: u16,
|
||||
mut rng: &mut ThreadRng,
|
||||
key_packages: &HashMap<Identifier, KeyPackage>,
|
||||
key_packages: &BTreeMap<Identifier, KeyPackage>,
|
||||
) -> (
|
||||
HashMap<Identifier, SigningNonces>,
|
||||
BTreeMap<Identifier, SigningNonces>,
|
||||
BTreeMap<Identifier, SigningCommitments>,
|
||||
) {
|
||||
// Participant Round 1
|
||||
|
||||
let mut nonces_map = HashMap::new();
|
||||
let mut nonces_map = BTreeMap::new();
|
||||
let mut commitments_map = BTreeMap::new();
|
||||
|
||||
for participant_index in 1..(min_signers + 1) {
|
||||
let participant_identifier = participant_index.try_into().expect("should be nonzero");
|
||||
let key_package = &key_packages[&participant_identifier];
|
||||
let (nonces, commitments) = frost::round1::commit(key_package.secret_share(), &mut rng);
|
||||
let (nonces, commitments) = frost::round1::commit(key_package.signing_share(), &mut rng);
|
||||
nonces_map.insert(participant_identifier, nonces);
|
||||
commitments_map.insert(participant_identifier, commitments);
|
||||
}
|
||||
|
@ -41,13 +41,13 @@ pub fn round_1(
|
|||
}
|
||||
|
||||
pub fn round_2(
|
||||
nonces_map: HashMap<Identifier, SigningNonces>,
|
||||
key_packages: &HashMap<Identifier, KeyPackage>,
|
||||
nonces_map: BTreeMap<Identifier, SigningNonces>,
|
||||
key_packages: &BTreeMap<Identifier, KeyPackage>,
|
||||
commitments_map: BTreeMap<Identifier, SigningCommitments>,
|
||||
message: &[u8],
|
||||
) -> (SigningPackage, HashMap<Identifier, SignatureShare>) {
|
||||
) -> (SigningPackage, BTreeMap<Identifier, SignatureShare>) {
|
||||
let signing_package = frost::SigningPackage::new(commitments_map, message);
|
||||
let mut signature_shares = HashMap::new();
|
||||
let mut signature_shares = BTreeMap::new();
|
||||
for participant_identifier in nonces_map.keys() {
|
||||
let key_package = &key_packages[participant_identifier];
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg(not(feature = "redpallas"))]
|
||||
|
||||
mod helpers;
|
||||
|
||||
use frost::aggregate;
|
||||
|
@ -26,7 +28,7 @@ fn check_keygen_with_dealer() {
|
|||
let message = "i am a message".as_bytes();
|
||||
let (signing_package, signature_shares) = round_2(nonces, &key_packages, commitments, message);
|
||||
let group_signature = aggregate(&signing_package, &signature_shares, &pubkeys).unwrap();
|
||||
let verify_signature = pubkeys.group_public().verify(message, &group_signature);
|
||||
let verify_signature = pubkeys.verifying_key().verify(message, &group_signature);
|
||||
|
||||
assert!(verify_signature.is_ok());
|
||||
}
|
||||
|
@ -47,7 +49,7 @@ fn check_keygen_with_dealer_with_large_num_of_signers() {
|
|||
let message = "i am a message".as_bytes();
|
||||
let (signing_package, signature_shares) = round_2(nonces, &key_packages, commitments, message);
|
||||
let group_signature = aggregate(&signing_package, &signature_shares, &pubkeys).unwrap();
|
||||
let verify_signature = pubkeys.group_public().verify(message, &group_signature);
|
||||
let verify_signature = pubkeys.verifying_key().verify(message, &group_signature);
|
||||
|
||||
assert!(verify_signature.is_ok());
|
||||
}
|
||||
|
@ -72,7 +74,7 @@ fn check_keygen_with_dealer_with_secret() {
|
|||
let message = "i am a message".as_bytes();
|
||||
let (signing_package, signature_shares) = round_2(nonces, &key_packages, commitments, message);
|
||||
let group_signature = aggregate(&signing_package, &signature_shares, &pubkeys).unwrap();
|
||||
let verify_signature = pubkeys.group_public().verify(message, &group_signature);
|
||||
let verify_signature = pubkeys.verifying_key().verify(message, &group_signature);
|
||||
|
||||
assert!(verify_signature.is_ok());
|
||||
}
|
||||
|
@ -96,7 +98,7 @@ fn check_keygen_with_dealer_with_secret_with_large_num_of_signers() {
|
|||
let message = "i am a message".as_bytes();
|
||||
let (signing_package, signature_shares) = round_2(nonces, &key_packages, commitments, message);
|
||||
let group_signature = aggregate(&signing_package, &signature_shares, &pubkeys).unwrap();
|
||||
let verify_signature = pubkeys.group_public().verify(message, &group_signature);
|
||||
let verify_signature = pubkeys.verifying_key().verify(message, &group_signature);
|
||||
|
||||
assert!(verify_signature.is_ok());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue