Merge pull request #2 from ZcashFoundation/generate_secret_share_283
Generate secret share 283
This commit is contained in:
commit
15100a28b7
|
@ -1 +1,2 @@
|
|||
/target
|
||||
.vscode/*
|
File diff suppressed because it is too large
Load Diff
|
@ -6,3 +6,8 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
frost-ed25519 = "0.2.0"
|
||||
thiserror = "1.0"
|
||||
rand = "0.8"
|
||||
hex = "0.4"
|
||||
itertools = "0.10.5"
|
||||
|
|
|
@ -188,7 +188,7 @@ APPENDIX: How to apply the Apache License to your work.
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2023 Zcash Foundation
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# Frost Trusted Dealer Demo
|
||||
|
||||
A CLI demo for running trusted dealer key generation with FROST
|
||||
|
||||
This demo uses ed25519
|
||||
|
||||
https://crates.io/crates/frost-ed25519
|
|
@ -0,0 +1,43 @@
|
|||
use std::io;
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub struct Config {
|
||||
pub min_signers: u16,
|
||||
pub max_signers: u16,
|
||||
}
|
||||
|
||||
pub fn validate_inputs(config: &Config) -> Result<Config, frost_ed25519::Error> {
|
||||
if config.min_signers < 2 {
|
||||
return Err(frost_ed25519::Error::InvalidMinSigners);
|
||||
}
|
||||
|
||||
if config.max_signers < 2 {
|
||||
return Err(frost_ed25519::Error::InvalidMaxSigners);
|
||||
}
|
||||
|
||||
if config.min_signers > config.max_signers {
|
||||
return Err(frost_ed25519::Error::InvalidMinSigners);
|
||||
}
|
||||
|
||||
Ok(*config)
|
||||
}
|
||||
|
||||
pub fn request_inputs() -> Config {
|
||||
println!("The minimum number of signers: (2 or more)");
|
||||
|
||||
let mut min = String::new();
|
||||
io::stdin().read_line(&mut min).expect("invalid input");
|
||||
|
||||
let min_signers = min.trim().parse::<u16>().expect("Invalid input");
|
||||
|
||||
println!("The maximum number of signers: (must be greater than minimum number of signers)");
|
||||
|
||||
let mut max = String::new();
|
||||
io::stdin().read_line(&mut max).expect("invalid input");
|
||||
let max_signers = max.trim().parse::<u16>().expect("invalid input");
|
||||
|
||||
Config {
|
||||
min_signers,
|
||||
max_signers,
|
||||
}
|
||||
}
|
|
@ -1,6 +1,38 @@
|
|||
mod inputs;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod trusted_dealer_keygen;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::io;
|
||||
|
||||
use output::{print_values, Logger};
|
||||
use rand::thread_rng;
|
||||
mod output;
|
||||
|
||||
use crate::inputs::{request_inputs, validate_inputs};
|
||||
use crate::trusted_dealer_keygen::trusted_dealer_keygen;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let config = request_inputs();
|
||||
let mut rng = thread_rng();
|
||||
|
||||
validate_inputs(&config).expect("An error occurred");
|
||||
|
||||
// Print outputs
|
||||
let (key_packages, pubkeys) = trusted_dealer_keygen(config, &mut rng);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use frost_ed25519 as frost;
|
||||
|
||||
use frost::keys::{KeyPackage, PublicKeyPackage};
|
||||
use frost::Identifier;
|
||||
use itertools::Itertools;
|
||||
|
||||
pub trait Logger {
|
||||
fn log(&mut self, value: String);
|
||||
}
|
||||
|
||||
pub fn print_values(
|
||||
keys: &HashMap<Identifier, KeyPackage>,
|
||||
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!("---");
|
||||
|
||||
for (k, v) in keys.iter().sorted_by_key(|x| x.0) {
|
||||
logger.log(format!("Participant {:?}", k));
|
||||
logger.log(format!(
|
||||
"Secret share: {:?}",
|
||||
hex::encode(v.secret_share.to_bytes())
|
||||
));
|
||||
logger.log(format!(
|
||||
"Public key: {:?}",
|
||||
hex::encode(v.public.to_bytes())
|
||||
));
|
||||
println!("---")
|
||||
}
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
#[test]
|
||||
fn check_test() {}
|
||||
mod inputs_tests;
|
||||
mod integration_test;
|
||||
mod output_tests;
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
use crate::inputs::{validate_inputs, Config};
|
||||
|
||||
#[test]
|
||||
fn check_valid_input_for_signers() {
|
||||
let config = Config {
|
||||
min_signers: 2,
|
||||
max_signers: 3,
|
||||
};
|
||||
|
||||
let expected = validate_inputs(&config);
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
let expected = validate_inputs(&config);
|
||||
|
||||
assert_eq!(expected, Err(frost_ed25519::Error::InvalidMinSigners));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_error_if_min_participant_is_less_than_2() {
|
||||
let config = Config {
|
||||
min_signers: 1,
|
||||
max_signers: 3,
|
||||
};
|
||||
|
||||
let expected = validate_inputs(&config);
|
||||
|
||||
assert_eq!(expected, Err(frost_ed25519::Error::InvalidMinSigners));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_error_if_max_participant_is_less_than_2() {
|
||||
let config = Config {
|
||||
min_signers: 2,
|
||||
max_signers: 1,
|
||||
};
|
||||
|
||||
let expected = validate_inputs(&config);
|
||||
|
||||
assert_eq!(expected, Err(frost_ed25519::Error::InvalidMaxSigners));
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
use crate::inputs::Config;
|
||||
use frost_ed25519 as frost;
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::trusted_dealer_keygen::trusted_dealer_keygen;
|
||||
mod signature_gen;
|
||||
|
||||
#[test]
|
||||
fn check_keygen() {
|
||||
let mut rng = thread_rng();
|
||||
let config = Config {
|
||||
min_signers: 2,
|
||||
max_signers: 3,
|
||||
};
|
||||
let (key_packages, pubkeys) = trusted_dealer_keygen(config, &mut rng);
|
||||
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());
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
use frost::keys::KeyPackage;
|
||||
use frost::round1::{SigningCommitments, SigningNonces};
|
||||
use frost::round2::SignatureShare;
|
||||
use frost::{Identifier, SigningPackage};
|
||||
use frost_ed25519 as frost;
|
||||
use rand::rngs::ThreadRng;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn generate_nonces_and_commitments(
|
||||
min_signers: u16,
|
||||
key_packages: &HashMap<Identifier, KeyPackage>,
|
||||
rng: &mut ThreadRng,
|
||||
) -> (
|
||||
HashMap<Identifier, SigningNonces>,
|
||||
HashMap<Identifier, SigningCommitments>,
|
||||
) {
|
||||
let mut nonces = HashMap::new();
|
||||
let mut commitments = HashMap::new();
|
||||
|
||||
for participant_index in 1..(min_signers + 1) {
|
||||
let participant_identifier = participant_index.try_into().expect("should be nonzero");
|
||||
let (nonce, commitment) = frost::round1::commit(
|
||||
participant_identifier,
|
||||
key_packages[&participant_identifier].secret_share(),
|
||||
rng,
|
||||
);
|
||||
nonces.insert(participant_identifier, nonce);
|
||||
commitments.insert(participant_identifier, commitment);
|
||||
}
|
||||
|
||||
(nonces, commitments)
|
||||
}
|
||||
|
||||
pub fn generate_signature_shares(
|
||||
nonces: HashMap<Identifier, SigningNonces>,
|
||||
key_packages: &HashMap<Identifier, KeyPackage>,
|
||||
signing_package: &SigningPackage,
|
||||
) -> Vec<SignatureShare> {
|
||||
let mut signature_shares = Vec::new();
|
||||
|
||||
for participant_identifier in nonces.keys() {
|
||||
let key_package = &key_packages[participant_identifier];
|
||||
let nonces_to_use = &nonces[participant_identifier];
|
||||
let signature_share =
|
||||
frost::round2::sign(signing_package, nonces_to_use, key_package).unwrap(); //TODO: handle errors
|
||||
|
||||
signature_shares.push(signature_share);
|
||||
}
|
||||
|
||||
signature_shares
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
use frost::Identifier;
|
||||
use frost_ed25519 as frost;
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::inputs::Config;
|
||||
use crate::output::{print_values, Logger};
|
||||
use crate::trusted_dealer_keygen;
|
||||
|
||||
struct TestLogger(Vec<String>);
|
||||
|
||||
impl Logger for TestLogger {
|
||||
fn log(&mut self, value: String) {
|
||||
self.0.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_output() {
|
||||
let mut test_logger = TestLogger(Vec::new());
|
||||
let mut rng = thread_rng();
|
||||
let config = Config {
|
||||
min_signers: 2,
|
||||
max_signers: 3,
|
||||
};
|
||||
let (key_packages, pubkeys) = trusted_dealer_keygen(config, &mut rng);
|
||||
|
||||
print_values(&key_packages, pubkeys, &mut test_logger);
|
||||
|
||||
let signer_1 = Identifier::try_from(1).unwrap();
|
||||
let signer_2 = Identifier::try_from(2).unwrap();
|
||||
let signer_3 = Identifier::try_from(3).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
test_logger.0[0],
|
||||
format!(
|
||||
"Group public key: \"{}\"",
|
||||
hex::encode(key_packages[&signer_1].group_public.to_bytes())
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(test_logger.0[1], format!("Participant {:?}", signer_1));
|
||||
assert_eq!(
|
||||
test_logger.0[2],
|
||||
format!(
|
||||
"Secret share: \"{}\"",
|
||||
hex::encode(key_packages[&signer_1].secret_share.to_bytes())
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
test_logger.0[3],
|
||||
format!(
|
||||
"Public key: \"{}\"",
|
||||
hex::encode(key_packages[&signer_1].public.to_bytes())
|
||||
)
|
||||
);
|
||||
|
||||
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[6],
|
||||
format!(
|
||||
"Public key: \"{}\"",
|
||||
hex::encode(key_packages[&signer_2].public.to_bytes())
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(test_logger.0[7], format!("Participant {:?}", signer_3));
|
||||
assert_eq!(
|
||||
test_logger.0[8],
|
||||
format!(
|
||||
"Secret share: \"{}\"",
|
||||
hex::encode(key_packages[&signer_3].secret_share.to_bytes())
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
test_logger.0[9],
|
||||
format!(
|
||||
"Public key: \"{}\"",
|
||||
hex::encode(key_packages[&signer_3].public.to_bytes())
|
||||
)
|
||||
);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
use frost::keys::{KeyPackage, PublicKeyPackage};
|
||||
use frost::Identifier;
|
||||
use frost_ed25519 as frost;
|
||||
use rand::rngs::ThreadRng;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::inputs::Config;
|
||||
|
||||
pub fn trusted_dealer_keygen(
|
||||
config: Config,
|
||||
rng: &mut ThreadRng,
|
||||
) -> (HashMap<Identifier, KeyPackage>, PublicKeyPackage) {
|
||||
let (shares, pubkeys) =
|
||||
frost::keys::keygen_with_dealer(config.max_signers, config.min_signers, rng)
|
||||
.expect("Error generating keys"); // TODO: handle error
|
||||
|
||||
let mut key_packages: HashMap<_, _> = HashMap::new();
|
||||
|
||||
for (k, v) in shares {
|
||||
let key_package = frost::keys::KeyPackage::try_from(v).unwrap(); // TODO: handle error
|
||||
key_packages.insert(k, key_package);
|
||||
}
|
||||
|
||||
(key_packages, pubkeys)
|
||||
}
|
Loading…
Reference in New Issue