Return VerifiableSecretSharingCommitment (#10)

* Update frost-ed25519 crate to v0.4.0 (#324)

* Refactor keygen to return SecretShares and not KeyPackages (#324)

* Update secret key input text

Co-authored-by: Conrado Gouvea <conrado@zfnd.org>

* Add commitment output (#324)

* Refactor Errors in input tests (#324)

* Handle errors in secret key input (#324)

* Improve error handling for split_secret (#324)

* Refactor validate_inputs into request_inputs function (#324)

* Refactor main into cli function (#324)

* Fix encoding not handling more than 9 signers (#324)

* Add borrow to parameter in output to remove unecessary clones (#324)

---------

Co-authored-by: Conrado Gouvea <conrado@zfnd.org>
This commit is contained in:
natalie 2023-06-14 18:52:43 +01:00 committed by GitHub
parent ac921c364d
commit 6f33c44d22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 552 additions and 262 deletions

185
Cargo.lock generated
View File

@ -9,15 +9,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "atty"
version = "0.2.14"
name = "anstyle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
[[package]]
name = "autocfg"
@ -114,24 +109,29 @@ dependencies = [
[[package]]
name = "clap"
version = "3.2.25"
version = "4.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
checksum = "b4ed2379f8603fa2b7509891660e802b88c70a79a6427a70abb5968054de2c28"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980"
dependencies = [
"anstyle",
"bitflags",
"clap_lex",
"indexmap",
"textwrap",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "cpufeatures"
@ -144,19 +144,19 @@ dependencies = [
[[package]]
name = "criterion"
version = "0.4.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb"
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
dependencies = [
"anes",
"atty",
"cast",
"ciborium",
"clap",
"criterion-plot",
"is-terminal",
"itertools",
"lazy_static",
"num-traits",
"once_cell",
"oorandom",
"plotters",
"rayon",
@ -319,15 +319,16 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "frost-core"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2329106b2265939420de478389a83ffd63a76ec86b306c6d78ea345a5efced3"
checksum = "d2fe2b22eee8914aaf54ab74c7bc6cf71e539c40d92a746cf5c65b619acb02dc"
dependencies = [
"byteorder",
"criterion",
"debugless-unwrap",
"digest",
"hex",
"itertools",
"proptest",
"proptest-derive",
"rand_core",
@ -339,9 +340,9 @@ dependencies = [
[[package]]
name = "frost-ed25519"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b749ea831d8e9205f6c8d912d5656c5d320b0bb1489b4b6fdd715941a1e8dd1a"
checksum = "24f56348765eef8f99de247aba00c1599ba980ca372aa2e4c26c4e9d11e6e4b2"
dependencies = [
"curve25519-dalek",
"frost-core",
@ -388,21 +389,6 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.2.6"
@ -427,16 +413,6 @@ dependencies = [
"serde",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -448,15 +424,27 @@ dependencies = [
[[package]]
name = "io-lifetimes"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi 0.3.1",
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "is-terminal"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
dependencies = [
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
"windows-sys 0.48.0",
]
[[package]]
name = "itertools"
version = "0.10.5"
@ -489,9 +477,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.144"
version = "0.2.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
checksum = "fc86cde3ff845662b8f4ef6cb50ea0e20c524eb3d29ae048287e06a1b3fa6a81"
[[package]]
name = "libm"
@ -513,12 +501,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "log"
version = "0.4.17"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
[[package]]
name = "memoffset"
@ -551,9 +536,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.17.1"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "oorandom"
@ -561,12 +546,6 @@ version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "os_str_bytes"
version = "6.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
[[package]]
name = "packed_simd_2"
version = "0.3.8"
@ -628,9 +607,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8"
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
dependencies = [
"unicode-ident",
]
@ -683,11 +662,11 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.27"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
dependencies = [
"proc-macro2 1.0.58",
"proc-macro2 1.0.59",
]
[[package]]
@ -762,9 +741,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.8.2"
version = "1.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974"
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
dependencies = [
"regex-syntax 0.7.2",
]
@ -843,9 +822,9 @@ version = "1.0.163"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
dependencies = [
"proc-macro2 1.0.58",
"quote 1.0.27",
"syn 2.0.16",
"proc-macro2 1.0.59",
"quote 1.0.28",
"syn 2.0.18",
]
[[package]]
@ -893,19 +872,19 @@ version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2 1.0.58",
"quote 1.0.27",
"proc-macro2 1.0.59",
"quote 1.0.28",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.16"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
dependencies = [
"proc-macro2 1.0.58",
"quote 1.0.27",
"proc-macro2 1.0.59",
"quote 1.0.28",
"unicode-ident",
]
@ -922,12 +901,6 @@ dependencies = [
"windows-sys 0.45.0",
]
[[package]]
name = "textwrap"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
version = "1.0.40"
@ -943,9 +916,9 @@ version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2 1.0.58",
"quote 1.0.27",
"syn 2.0.16",
"proc-macro2 1.0.59",
"quote 1.0.28",
"syn 2.0.18",
]
[[package]]
@ -972,9 +945,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
[[package]]
name = "unicode-ident"
version = "1.0.8"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "unicode-xid"
@ -994,8 +967,8 @@ version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8881d5cc0ae34e3db2f1de5af81e5117a420d2f937506c2dc20d6f4cfb069051"
dependencies = [
"proc-macro2 1.0.58",
"quote 1.0.27",
"proc-macro2 1.0.59",
"quote 1.0.28",
"syn 1.0.109",
]
@ -1043,9 +1016,9 @@ dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2 1.0.58",
"quote 1.0.27",
"syn 2.0.16",
"proc-macro2 1.0.59",
"quote 1.0.28",
"syn 2.0.18",
"wasm-bindgen-shared",
]
@ -1055,7 +1028,7 @@ version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
dependencies = [
"quote 1.0.27",
"quote 1.0.28",
"wasm-bindgen-macro-support",
]
@ -1065,9 +1038,9 @@ version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
dependencies = [
"proc-macro2 1.0.58",
"quote 1.0.27",
"syn 2.0.16",
"proc-macro2 1.0.59",
"quote 1.0.28",
"syn 2.0.18",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -1266,7 +1239,7 @@ version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2 1.0.58",
"quote 1.0.27",
"syn 2.0.16",
"proc-macro2 1.0.59",
"quote 1.0.28",
"syn 2.0.18",
]

View File

@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
frost-ed25519 = "0.3.0"
frost-ed25519 = "0.4.0"
thiserror = "1.0"
rand = "0.8"
hex = "0.4"

64
src/cli.rs Normal file
View File

@ -0,0 +1,64 @@
use frost::Error;
use frost_ed25519 as frost;
use rand::thread_rng;
use std::io;
use crate::inputs::request_inputs;
use crate::output::{print_values, Logger};
use crate::trusted_dealer_keygen::{split_secret, trusted_dealer_keygen};
#[derive(PartialEq)]
pub enum CliError {
Config,
Keygen,
}
pub struct TrustedDealerError {
pub frost_error: Error,
pub cli_error: CliError,
}
pub fn cli() -> Result<(), TrustedDealerError> {
let mut reader = Box::new(io::stdin().lock());
let config = request_inputs(&mut reader);
if let Err(e) = config {
return Err(TrustedDealerError {
frost_error: e,
cli_error: CliError::Config,
});
}
let config = config.unwrap();
let mut rng = thread_rng();
let keygen = if config.secret.is_empty() {
trusted_dealer_keygen(&config, &mut rng)
} else {
split_secret(&config, &mut rng)
};
if let Err(e) = keygen {
return Err(TrustedDealerError {
frost_error: e,
cli_error: CliError::Keygen,
});
}
let (shares, pubkeys) = keygen.unwrap();
let mut console_logger = ConsoleLogger::default();
print_values(&shares, &pubkeys, &mut console_logger);
Ok(())
}
#[derive(Default)]
pub struct ConsoleLogger;
impl Logger for ConsoleLogger {
fn log(&mut self, value: String) {
println!("{}", value);
}
}

View File

@ -6,10 +6,10 @@ use std::io::BufRead;
pub struct Config {
pub min_signers: u16,
pub max_signers: u16,
pub secret: Vec<u8>, // todo
pub secret: Vec<u8>,
}
pub fn validate_inputs(config: &Config) -> Result<(), Error> {
fn validate_inputs(config: &Config) -> Result<(), Error> {
if config.min_signers < 2 {
return Err(Error::InvalidMinSigners);
}
@ -57,5 +57,7 @@ pub fn request_inputs(input: &mut impl BufRead) -> Result<Config, Error> {
secret,
};
validate_inputs(&config)?;
Ok(config)
}

View File

@ -1,62 +1,31 @@
mod cli;
mod inputs;
#[cfg(test)]
mod tests;
mod output;
mod trusted_dealer_keygen;
#[cfg(test)]
mod tests;
use cli::CliError;
use std::io;
use output::{print_values, Logger};
use rand::thread_rng;
use trusted_dealer_keygen::split_secret;
mod output;
use crate::inputs::{request_inputs, validate_inputs};
use crate::trusted_dealer_keygen::trusted_dealer_keygen;
use crate::cli::cli;
fn main() -> io::Result<()> {
let mut reader = Box::new(io::stdin().lock());
let config = request_inputs(&mut reader);
if let Err(e) = config {
eprintln!("Error: {}", e);
std::process::exit(exitcode::DATAERR)
let out = cli();
if let Err(e) = out {
if e.cli_error == CliError::Config {
{
eprintln!("Error: {}", e.frost_error);
std::process::exit(exitcode::DATAERR)
};
};
if e.cli_error == CliError::Keygen {
eprintln!("Error: {}", e.frost_error);
std::process::exit(1)
};
}
let config = config.unwrap();
let mut rng = thread_rng();
let valid = validate_inputs(&config);
if let Err(e) = valid {
eprintln!("Error: {}", e);
std::process::exit(exitcode::DATAERR)
}
let keygen = if config.secret.is_empty() {
trusted_dealer_keygen(&config, &mut rng)
} else {
split_secret(&config, &mut rng)
};
// Print outputs
if let Err(e) = keygen {
eprintln!("Error: {}", e);
std::process::exit(1)
}
let (key_packages, pubkeys) = keygen.unwrap();
let mut console_logger = ConsoleLogger::default();
print_values(&key_packages, pubkeys, &mut console_logger);
Ok(())
}
#[derive(Default)]
pub struct ConsoleLogger;
impl Logger for ConsoleLogger {
fn log(&mut self, value: String) {
println!("{}", value);
}
}

View File

@ -1,26 +1,33 @@
use std::collections::HashMap;
use frost_ed25519 as frost;
use frost::keys::{KeyPackage, PublicKeyPackage};
use frost::keys::{PublicKeyPackage, SecretShare, VerifiableSecretSharingCommitment};
use frost::Identifier;
use frost_ed25519 as frost;
use itertools::Itertools;
use std::collections::HashMap;
pub trait Logger {
fn log(&mut self, value: String);
}
fn encode_commitment(vss_commitment: &VerifiableSecretSharingCommitment) -> String {
let serialized = vss_commitment.serialize();
let num = serialized.len();
let mut out = hex::encode([num as u8]);
for cc in serialized {
out = out + &hex::encode(cc)
}
out
}
pub fn print_values(
keys: &HashMap<Identifier, KeyPackage>,
pubkeys: PublicKeyPackage,
keys: &HashMap<Identifier, SecretShare>,
pubkeys: &PublicKeyPackage,
logger: &mut dyn Logger,
) {
logger.log(format!(
"Group public key: {:x?}",
hex::encode(pubkeys.group_public.to_bytes())
));
// Need to be able to extract value for VerifiableSecretSharingCommitment that isn't currently accessible
// println!("Commitment: {:x?}", shares[0].commitment[0]);
println!("---");
@ -28,12 +35,40 @@ pub fn print_values(
logger.log(format!("Participant {:?}", k));
logger.log(format!(
"Secret share: {:?}",
hex::encode(v.secret_share.to_bytes())
hex::encode(v.value.to_bytes())
));
logger.log(format!(
"Public key: {:?}",
hex::encode(v.public.to_bytes())
hex::encode(pubkeys.signer_pubkeys[k].to_bytes())
));
logger.log(format!("Commitment: {}", encode_commitment(&v.commitment)));
println!("---")
}
}
#[cfg(test)]
mod tests {
use crate::output::encode_commitment;
use frost::keys::VerifiableSecretSharingCommitment;
use frost_ed25519 as frost;
use hex::FromHex;
#[test]
fn check_encode_commitment() {
let coeff_comm_1 = "538d43e67bc9c22a3befdf24e68f29bfc9bcbd844736e5b82fdab1545bceddcf";
let coeff_comm_2 = "6bc2053a2bedc6a071c74495965c960a6d2655720edba2a5aa68b8e160c9f55d";
let coeff_comm_3 = "eb73cfae619afa59984754e5f3e93ba2357164ce113b09e542365d8313d6f091";
let expected = "03".to_string() + coeff_comm_1 + coeff_comm_2 + coeff_comm_3;
let decoded_1 = <[u8; 32]>::from_hex(coeff_comm_1).unwrap();
let decoded_2 = <[u8; 32]>::from_hex(coeff_comm_2).unwrap();
let decoded_3 = <[u8; 32]>::from_hex(coeff_comm_3).unwrap();
let vss_commitment =
VerifiableSecretSharingCommitment::deserialize(vec![decoded_1, decoded_2, decoded_3])
.unwrap();
let commitment = encode_commitment(&vss_commitment);
assert!(commitment == expected)
}
}

View File

@ -1,4 +1,6 @@
use crate::inputs::{request_inputs, validate_inputs, Config};
use crate::inputs::{request_inputs, Config};
use frost::Error;
use frost_ed25519 as frost;
#[test]
fn check_valid_input_for_signers() {
@ -8,48 +10,34 @@ fn check_valid_input_for_signers() {
secret: Vec::new(),
};
let expected = validate_inputs(&config);
let mut valid_input = "2\n3\n\n".as_bytes();
let expected = request_inputs(&mut valid_input);
assert_eq!(expected, Ok(()));
assert_eq!(expected, Ok(config));
}
#[test]
fn return_error_if_min_participant_greater_than_max_participant() {
let config = Config {
min_signers: 4,
max_signers: 3,
secret: Vec::new(),
};
let mut invalid_input = "4\n3\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
let expected = validate_inputs(&config);
assert_eq!(expected, Err(frost_ed25519::Error::InvalidMinSigners));
assert_eq!(expected, Err(Error::InvalidMinSigners));
}
#[test]
fn return_error_if_min_participant_is_less_than_2() {
let config = Config {
min_signers: 1,
max_signers: 3,
secret: Vec::new(),
};
let mut invalid_input = "1\n3\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
let expected = validate_inputs(&config);
assert_eq!(expected, Err(frost_ed25519::Error::InvalidMinSigners));
assert_eq!(expected, Err(Error::InvalidMinSigners));
}
#[test]
fn return_error_if_max_participant_is_less_than_2() {
let config = Config {
min_signers: 2,
max_signers: 1,
secret: Vec::new(),
};
let mut invalid_input = "2\n1\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
let expected = validate_inputs(&config);
assert_eq!(expected, Err(frost_ed25519::Error::InvalidMaxSigners));
assert_eq!(expected, Err(Error::InvalidMaxSigners));
}
// Testing inclusion of secret input
@ -78,7 +66,7 @@ fn return_error_if_invalid_min_signers_input() {
let mut invalid_input = "hello\n6\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
assert_eq!(expected, Err(frost_ed25519::Error::InvalidMinSigners))
assert_eq!(expected, Err(Error::InvalidMinSigners))
}
#[test]
@ -86,13 +74,13 @@ fn return_error_if_invalid_max_signers_input() {
let mut invalid_input = "4\nworld\n\n".as_bytes();
let expected = request_inputs(&mut invalid_input);
assert_eq!(expected, Err(frost_ed25519::Error::InvalidMaxSigners))
assert_eq!(expected, Err(Error::InvalidMaxSigners))
}
#[test]
fn return_error_if_secret_is_invalid() {
fn return_malformed_signing_key_error_if_secret_is_invalid() {
let mut secret_input = "4\n6\nasecret\n".as_bytes();
let expected = request_inputs(&mut secret_input);
assert_eq!(expected, Err(frost_ed25519::Error::MalformedSigningKey))
assert_eq!(expected, Err(Error::MalformedSigningKey))
}

View File

@ -1,4 +1,5 @@
use crate::inputs::Config;
use crate::tests::integration_test::signature_gen::generate_key_packages;
use crate::trusted_dealer_keygen::split_secret;
use frost_ed25519 as frost;
use rand::thread_rng;
@ -14,7 +15,32 @@ fn check_keygen_with_dealer() {
max_signers: 3,
secret: Vec::new(),
};
let (key_packages, pubkeys) = trusted_dealer_keygen(&config, &mut rng).unwrap();
let (shares, pubkeys) = trusted_dealer_keygen(&config, &mut rng).unwrap();
let key_packages = generate_key_packages(shares);
let (nonces, commitments) =
signature_gen::generate_nonces_and_commitments(config.min_signers, &key_packages, &mut rng);
let message = "message to sign".as_bytes();
let comms = commitments.into_values().collect();
let signing_package = frost::SigningPackage::new(comms, message.to_vec());
let signature_shares =
signature_gen::generate_signature_shares(nonces, &key_packages, &signing_package);
let group_signature =
frost::aggregate(&signing_package, &signature_shares[..], &pubkeys).unwrap();
let verify_signature = pubkeys.group_public.verify(message, &group_signature);
assert!(verify_signature.is_ok());
}
#[test]
fn check_keygen_with_dealer_with_large_num_of_signers() {
let mut rng = thread_rng();
let config = Config {
min_signers: 14,
max_signers: 20,
secret: Vec::new(),
};
let (shares, pubkeys) = trusted_dealer_keygen(&config, &mut rng).unwrap();
let key_packages = generate_key_packages(shares);
let (nonces, commitments) =
signature_gen::generate_nonces_and_commitments(config.min_signers, &key_packages, &mut rng);
let message = "message to sign".as_bytes();
@ -41,7 +67,39 @@ fn check_keygen_with_dealer_with_secret() {
max_signers: 3,
secret,
};
let (key_packages, pubkeys) = split_secret(&secret_config, &mut rng).unwrap();
let (shares, pubkeys) = split_secret(&secret_config, &mut rng).unwrap();
let key_packages = generate_key_packages(shares);
let (nonces, commitments) = signature_gen::generate_nonces_and_commitments(
secret_config.min_signers,
&key_packages,
&mut rng,
);
let message = "message to sign".as_bytes();
let comms = commitments.into_values().collect();
let signing_package = frost::SigningPackage::new(comms, message.to_vec());
let signature_shares =
signature_gen::generate_signature_shares(nonces, &key_packages, &signing_package);
let group_signature =
frost::aggregate(&signing_package, &signature_shares[..], &pubkeys).unwrap();
let verify_signature = pubkeys.group_public.verify(message, &group_signature);
assert!(verify_signature.is_ok());
}
#[test]
fn check_keygen_with_dealer_with_secret_with_large_num_of_signers() {
let mut rng = thread_rng();
let secret: Vec<u8> = vec![
123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2,
90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4,
];
let secret_config = Config {
min_signers: 14,
max_signers: 20,
secret,
};
let (shares, pubkeys) = split_secret(&secret_config, &mut rng).unwrap();
let key_packages = generate_key_packages(shares);
let (nonces, commitments) = signature_gen::generate_nonces_and_commitments(
secret_config.min_signers,
&key_packages,

View File

@ -1,4 +1,4 @@
use frost::keys::KeyPackage;
use frost::keys::{KeyPackage, SecretShare};
use frost::round1::{SigningCommitments, SigningNonces};
use frost::round2::SignatureShare;
use frost::{Identifier, SigningPackage};
@ -6,6 +6,18 @@ use frost_ed25519 as frost;
use rand::rngs::ThreadRng;
use std::collections::HashMap;
pub fn generate_key_packages(
shares: HashMap<Identifier, SecretShare>,
) -> HashMap<Identifier, KeyPackage> {
let mut key_packages: HashMap<_, _> = HashMap::new();
for (k, v) in shares {
let key_package = frost::keys::KeyPackage::try_from(v).unwrap();
key_packages.insert(k, key_package);
}
key_packages
}
pub fn generate_nonces_and_commitments(
min_signers: u16,
key_packages: &HashMap<Identifier, KeyPackage>,

View File

@ -14,6 +14,15 @@ impl Logger for TestLogger {
}
}
fn encode_commitment_helper(commitment: Vec<[u8; 32]>) -> String {
let len_test = commitment.len() as u8;
let mut out = hex::encode([len_test]);
for c in commitment {
out = out + &hex::encode(c)
}
out
}
#[test]
fn check_output_without_secret() {
let mut test_logger = TestLogger(Vec::new());
@ -23,9 +32,9 @@ fn check_output_without_secret() {
max_signers: 3,
secret: Vec::new(),
};
let (key_packages, pubkeys) = trusted_dealer_keygen(&config, &mut rng).unwrap();
let (shares, pubkeys) = trusted_dealer_keygen(&config, &mut rng).unwrap();
print_values(&key_packages, pubkeys, &mut test_logger);
print_values(&shares, &pubkeys, &mut test_logger);
let signer_1 = Identifier::try_from(1).unwrap();
let signer_2 = Identifier::try_from(2).unwrap();
@ -35,7 +44,7 @@ fn check_output_without_secret() {
test_logger.0[0],
format!(
"Group public key: \"{}\"",
hex::encode(key_packages[&signer_1].group_public.to_bytes())
hex::encode(pubkeys.group_public.to_bytes())
)
);
@ -44,46 +53,67 @@ fn check_output_without_secret() {
test_logger.0[2],
format!(
"Secret share: \"{}\"",
hex::encode(key_packages[&signer_1].secret_share.to_bytes())
hex::encode(shares[&signer_1].value.to_bytes())
)
);
assert_eq!(
test_logger.0[3],
format!(
"Public key: \"{}\"",
hex::encode(key_packages[&signer_1].public.to_bytes())
hex::encode(pubkeys.signer_pubkeys[&signer_1].to_bytes())
)
);
assert_eq!(
test_logger.0[4],
format!(
"Commitment: {}",
encode_commitment_helper(shares[&signer_1].commitment.serialize())
)
);
assert_eq!(test_logger.0[4], format!("Participant {:?}", signer_2));
assert_eq!(
test_logger.0[5],
format!(
"Secret share: \"{}\"",
hex::encode(key_packages[&signer_2].secret_share.to_bytes())
)
);
assert_eq!(test_logger.0[5], format!("Participant {:?}", signer_2));
assert_eq!(
test_logger.0[6],
format!(
"Public key: \"{}\"",
hex::encode(key_packages[&signer_2].public.to_bytes())
"Secret share: \"{}\"",
hex::encode(shares[&signer_2].value.to_bytes())
)
);
assert_eq!(
test_logger.0[7],
format!(
"Public key: \"{}\"",
hex::encode(pubkeys.signer_pubkeys[&signer_2].to_bytes())
)
);
assert_eq!(test_logger.0[7], format!("Participant {:?}", signer_3));
assert_eq!(
test_logger.0[8],
format!(
"Commitment: {}",
encode_commitment_helper(shares[&signer_2].commitment.serialize())
)
);
assert_eq!(test_logger.0[9], format!("Participant {:?}", signer_3));
assert_eq!(
test_logger.0[10],
format!(
"Secret share: \"{}\"",
hex::encode(key_packages[&signer_3].secret_share.to_bytes())
hex::encode(shares[&signer_3].value.to_bytes())
)
);
assert_eq!(
test_logger.0[9],
test_logger.0[11],
format!(
"Public key: \"{}\"",
hex::encode(key_packages[&signer_3].public.to_bytes())
hex::encode(pubkeys.signer_pubkeys[&signer_3].to_bytes())
)
);
assert_eq!(
test_logger.0[12],
format!(
"Commitment: {}",
encode_commitment_helper(shares[&signer_3].commitment.serialize())
)
);
}
@ -101,9 +131,9 @@ fn check_output_with_secret() {
max_signers: 3,
secret,
};
let (key_packages, pubkeys) = split_secret(&config, &mut rng).unwrap();
let (shares, pubkeys) = split_secret(&config, &mut rng).unwrap();
print_values(&key_packages, pubkeys, &mut test_logger);
print_values(&shares, &pubkeys, &mut test_logger);
let signer_1 = Identifier::try_from(1).unwrap();
let signer_2 = Identifier::try_from(2).unwrap();
@ -113,7 +143,7 @@ fn check_output_with_secret() {
test_logger.0[0],
format!(
"Group public key: \"{}\"",
hex::encode(key_packages[&signer_1].group_public.to_bytes())
hex::encode(pubkeys.group_public.to_bytes())
)
);
@ -122,46 +152,165 @@ fn check_output_with_secret() {
test_logger.0[2],
format!(
"Secret share: \"{}\"",
hex::encode(key_packages[&signer_1].secret_share.to_bytes())
hex::encode(shares[&signer_1].value.to_bytes())
)
);
assert_eq!(
test_logger.0[3],
format!(
"Public key: \"{}\"",
hex::encode(key_packages[&signer_1].public.to_bytes())
hex::encode(pubkeys.signer_pubkeys[&signer_1].to_bytes())
)
);
assert_eq!(
test_logger.0[4],
format!(
"Commitment: {}",
encode_commitment_helper(shares[&signer_1].commitment.serialize())
)
);
assert_eq!(test_logger.0[4], format!("Participant {:?}", signer_2));
assert_eq!(
test_logger.0[5],
format!(
"Secret share: \"{}\"",
hex::encode(key_packages[&signer_2].secret_share.to_bytes())
)
);
assert_eq!(test_logger.0[5], format!("Participant {:?}", signer_2));
assert_eq!(
test_logger.0[6],
format!(
"Public key: \"{}\"",
hex::encode(key_packages[&signer_2].public.to_bytes())
"Secret share: \"{}\"",
hex::encode(shares[&signer_2].value.to_bytes())
)
);
assert_eq!(
test_logger.0[7],
format!(
"Public key: \"{}\"",
hex::encode(pubkeys.signer_pubkeys[&signer_2].to_bytes())
)
);
assert_eq!(test_logger.0[7], format!("Participant {:?}", signer_3));
assert_eq!(
test_logger.0[8],
format!(
"Commitment: {}",
encode_commitment_helper(shares[&signer_2].commitment.serialize())
)
);
assert_eq!(test_logger.0[9], format!("Participant {:?}", signer_3));
assert_eq!(
test_logger.0[10],
format!(
"Secret share: \"{}\"",
hex::encode(key_packages[&signer_3].secret_share.to_bytes())
hex::encode(shares[&signer_3].value.to_bytes())
)
);
assert_eq!(
test_logger.0[9],
test_logger.0[11],
format!(
"Public key: \"{}\"",
hex::encode(key_packages[&signer_3].public.to_bytes())
hex::encode(pubkeys.signer_pubkeys[&signer_3].to_bytes())
)
);
assert_eq!(
test_logger.0[12],
format!(
"Commitment: {}",
encode_commitment_helper(shares[&signer_3].commitment.serialize())
)
);
}
#[test]
fn check_output_with_large_num_of_signers() {
let mut test_logger = TestLogger(Vec::new());
let mut rng = thread_rng();
let config = Config {
min_signers: 10,
max_signers: 20,
secret: Vec::new(),
};
let (shares, pubkeys) = trusted_dealer_keygen(&config, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut test_logger);
let signer_10 = Identifier::try_from(10).unwrap();
assert_eq!(
test_logger.0[0],
format!(
"Group public key: \"{}\"",
hex::encode(pubkeys.group_public.to_bytes())
)
);
assert_eq!(test_logger.0[37], format!("Participant {:?}", signer_10));
assert_eq!(
test_logger.0[38],
format!(
"Secret share: \"{}\"",
hex::encode(shares[&signer_10].value.to_bytes())
)
);
assert_eq!(
test_logger.0[39],
format!(
"Public key: \"{}\"",
hex::encode(pubkeys.signer_pubkeys[&signer_10].to_bytes())
)
);
assert_eq!(
test_logger.0[40],
format!(
"Commitment: {}",
encode_commitment_helper(shares[&signer_10].commitment.serialize())
)
);
}
#[test]
fn check_output_with_secret_with_large_num_of_signers() {
let mut test_logger = TestLogger(Vec::new());
let mut rng = thread_rng();
let secret: Vec<u8> = vec![
123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2,
90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4,
];
let config = Config {
min_signers: 10,
max_signers: 20,
secret,
};
let (shares, pubkeys) = split_secret(&config, &mut rng).unwrap();
print_values(&shares, &pubkeys, &mut test_logger);
let signer_10 = Identifier::try_from(10).unwrap();
assert_eq!(
test_logger.0[0],
format!(
"Group public key: \"{}\"",
hex::encode(pubkeys.group_public.to_bytes())
)
);
assert_eq!(test_logger.0[37], format!("Participant {:?}", signer_10));
assert_eq!(
test_logger.0[38],
format!(
"Secret share: \"{}\"",
hex::encode(shares[&signer_10].value.to_bytes())
)
);
assert_eq!(
test_logger.0[39],
format!(
"Public key: \"{}\"",
hex::encode(pubkeys.signer_pubkeys[&signer_10].to_bytes())
)
);
assert_eq!(
test_logger.0[40],
format!(
"Commitment: {}",
encode_commitment_helper(shares[&signer_10].commitment.serialize())
)
);
}

View File

@ -1,4 +1,4 @@
use frost::keys::{KeyPackage, PublicKeyPackage};
use frost::keys::{PublicKeyPackage, SecretShare};
use frost::{Error, Identifier, SigningKey};
use frost_ed25519 as frost;
use rand::rngs::ThreadRng;
@ -9,34 +9,74 @@ use crate::inputs::Config;
pub fn trusted_dealer_keygen(
config: &Config,
rng: &mut ThreadRng,
) -> Result<(HashMap<Identifier, KeyPackage>, PublicKeyPackage), Error> {
) -> Result<(HashMap<Identifier, SecretShare>, PublicKeyPackage), Error> {
let (shares, pubkeys) =
frost::keys::generate_with_dealer(config.max_signers, config.min_signers, rng)?;
let mut key_packages: HashMap<_, _> = HashMap::new();
for (k, v) in shares {
let key_package = frost::keys::KeyPackage::try_from(v)?;
key_packages.insert(k, key_package);
for (_k, v) in shares.clone() {
frost::keys::KeyPackage::try_from(v)?;
}
Ok((key_packages, pubkeys))
Ok((shares, pubkeys))
}
pub fn split_secret(
config: &Config,
rng: &mut ThreadRng,
) -> Result<(HashMap<Identifier, KeyPackage>, PublicKeyPackage), Error> {
let sec = config.secret.clone();
let again = sec.try_into().unwrap();
let secret_key = SigningKey::from_bytes(again)?;
) -> Result<(HashMap<Identifier, SecretShare>, PublicKeyPackage), Error> {
let secret_key = SigningKey::from_bytes(
config
.secret
.clone()
.try_into()
.map_err(|_| Error::MalformedSigningKey)?,
)?;
let (shares, pubkeys) =
frost::keys::split(&secret_key, config.max_signers, config.min_signers, rng)?;
let mut key_packages: HashMap<_, _> = HashMap::new();
for (k, v) in shares {
let key_package = frost::keys::KeyPackage::try_from(v)?;
key_packages.insert(k, key_package);
for (_k, v) in shares.clone() {
frost::keys::KeyPackage::try_from(v)?;
}
Ok((shares, pubkeys))
}
#[cfg(test)]
mod tests {
use rand::thread_rng;
use crate::{inputs::Config, trusted_dealer_keygen::split_secret};
#[test]
fn return_malformed_signing_key_error_if_secret_is_invalid() {
let mut rng = thread_rng();
let secret_config = Config {
min_signers: 2,
max_signers: 3,
secret: b"helloIamaninvalidsecret111111111".to_vec(),
};
let out = split_secret(&secret_config, &mut rng);
assert!(out.is_err());
}
#[test]
fn return_malformed_signing_key_error_if_secret_is_invalid_type() {
let mut rng = thread_rng();
let secret: Vec<u8> = vec![
123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182,
2, 90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131,
];
let secret_config = Config {
min_signers: 2,
max_signers: 3,
secret,
};
let out = split_secret(&secret_config, &mut rng);
assert!(out.is_err());
}
Ok((key_packages, pubkeys))
}