Serialize round 2 output in Participant demo (#44)
* Add round 2 inputs for participant demo (#20) * Generate signature in participant demo (#20) Add integration test * Refactor rounds into own files in participant demo (#20) * Refactor rounds tests into own files in participant demo (#20) * Remove unnecessary test lib file from participant (#20) * Add test for round 1 output for participant (#20) * Print values for round 2 participant (#20) Add back in decode_vss_commitment test * Add in some errors (#23) * Fix test for invalid length of vss commitment (#23) * Improve readability of text output Co-authored-by: Conrado Gouvea <conrado@zfnd.org> * Improve readability of text output Co-authored-by: Conrado Gouvea <conrado@zfnd.org> * Refactor and rename (#23) --------- Co-authored-by: Conrado Gouvea <conrado@zfnd.org>
This commit is contained in:
parent
a70d0342e0
commit
0831c3053a
|
@ -1,15 +1,29 @@
|
|||
use frost::round1;
|
||||
use frost_ed25519 as frost;
|
||||
use participant::{generate_key_package, print_values, request_inputs, Logger};
|
||||
use participant::round1::{generate_key_package, print_values, request_inputs};
|
||||
use participant::round2::{generate_signature, print_values_round_2, round_2_request_inputs};
|
||||
use participant::Logger;
|
||||
use rand::thread_rng;
|
||||
use std::io::BufRead;
|
||||
|
||||
pub fn cli(input: &mut impl BufRead, logger: &mut dyn Logger) {
|
||||
let config = request_inputs(input, logger).unwrap(); // TODO: handle error
|
||||
let _key_package = generate_key_package(&config);
|
||||
let round_1_config = request_inputs(input, logger).unwrap(); // TODO: handle error
|
||||
let key_package = generate_key_package(&round_1_config).unwrap();
|
||||
logger.log("Key Package succesfully created.".to_string());
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let (nonces, commitments) = round1::commit(config.identifier, &config.signing_share, &mut rng);
|
||||
print_values(nonces, commitments, logger);
|
||||
let (nonces, commitments) = round1::commit(
|
||||
round_1_config.identifier,
|
||||
&round_1_config.signing_share,
|
||||
&mut rng,
|
||||
);
|
||||
print_values(&nonces, commitments, logger);
|
||||
|
||||
let round_2_config = round_2_request_inputs(commitments, input, logger).unwrap(); // TODO: handle errors
|
||||
|
||||
// Sign
|
||||
|
||||
let signature = generate_signature(round_2_config, &key_package, &nonces).unwrap(); // TODO: handle errors
|
||||
|
||||
print_values_round_2(signature, logger);
|
||||
}
|
||||
|
|
|
@ -1,183 +1,6 @@
|
|||
use frost::{
|
||||
keys::{
|
||||
KeyPackage, SecretShare, SigningShare, VerifiableSecretSharingCommitment, VerifyingShare,
|
||||
},
|
||||
round1::{SigningCommitments, SigningNonces},
|
||||
Error, Identifier, VerifyingKey,
|
||||
};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use std::io::BufRead;
|
||||
|
||||
// TODO: Rethink the types here. They're inconsistent with each other
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Config {
|
||||
pub identifier: Identifier,
|
||||
pub public_key: VerifyingShare,
|
||||
pub group_public_key: VerifyingKey,
|
||||
pub signing_share: SigningShare,
|
||||
pub vss_commitment: Vec<u8>,
|
||||
}
|
||||
pub mod round1;
|
||||
pub mod round2;
|
||||
|
||||
pub trait Logger {
|
||||
fn log(&mut self, value: String);
|
||||
}
|
||||
|
||||
// TODO: refactor to generate config
|
||||
pub fn request_inputs(input: &mut impl BufRead, logger: &mut dyn Logger) -> Result<Config, Error> {
|
||||
logger.log("Your identifier (this should be an integer between 1 and 65535):".to_string());
|
||||
|
||||
let mut identifier_input = String::new();
|
||||
|
||||
input.read_line(&mut identifier_input).unwrap();
|
||||
|
||||
let identifier = identifier_input
|
||||
.trim()
|
||||
.parse::<u16>()
|
||||
.map_err(|_| Error::MalformedIdentifier)?;
|
||||
|
||||
logger.log("Your public key:".to_string());
|
||||
|
||||
let mut public_key_input = String::new();
|
||||
|
||||
input.read_line(&mut public_key_input).unwrap();
|
||||
|
||||
// A specific VerifyingShare error does not currently exist in Frost so `MalformedVerifyingKey`
|
||||
// has been used. This should either be added to Frost or the error handling here can be reconsidered
|
||||
let public_key = VerifyingShare::from_bytes(
|
||||
<[u8; 32]>::from_hex(public_key_input.trim()).map_err(|_| Error::MalformedVerifyingKey)?,
|
||||
)?; //TODO: test error
|
||||
|
||||
logger.log("The group public key:".to_string());
|
||||
let mut group_public_key_input = String::new();
|
||||
|
||||
input.read_line(&mut group_public_key_input).unwrap();
|
||||
|
||||
let group_public_key = VerifyingKey::from_bytes(
|
||||
<[u8; 32]>::from_hex(group_public_key_input.trim())
|
||||
.map_err(|_| Error::MalformedVerifyingKey)?,
|
||||
)
|
||||
.map_err(|_| Error::MalformedVerifyingKey)?; // TODO: Add test for correct error to be returned on failing deserialisation
|
||||
|
||||
logger.log("Your secret share:".to_string());
|
||||
|
||||
let mut signing_share_input = String::new();
|
||||
|
||||
input.read_line(&mut signing_share_input).unwrap();
|
||||
|
||||
// A specific SigningShare error does not currently exist in Frost so `MalformedSigningKey`
|
||||
// has been used. This should either be added to Frost or the error handling here can be reconsidered
|
||||
let signing_share = SigningShare::from_bytes(
|
||||
<[u8; 32]>::from_hex(signing_share_input.trim()).map_err(|_| Error::MalformedSigningKey)?,
|
||||
)?; //TODO: test error
|
||||
|
||||
logger.log("Your verifiable secret sharing commitment:".to_string());
|
||||
|
||||
let mut vss_commitment_input = String::new();
|
||||
|
||||
input.read_line(&mut vss_commitment_input).unwrap();
|
||||
|
||||
let vss_commitment = hex::decode(vss_commitment_input.trim()).unwrap();
|
||||
|
||||
Ok(Config {
|
||||
identifier: Identifier::try_from(identifier)?,
|
||||
public_key,
|
||||
group_public_key,
|
||||
signing_share,
|
||||
vss_commitment,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generate_key_package(config: &Config) -> Result<KeyPackage, Error> {
|
||||
let secret_share = SecretShare::new(
|
||||
config.identifier,
|
||||
config.signing_share,
|
||||
decode_vss_commitment(&config.vss_commitment).unwrap(),
|
||||
);
|
||||
let key_package = KeyPackage::try_from(secret_share)?;
|
||||
|
||||
Ok(key_package)
|
||||
}
|
||||
|
||||
fn decode_vss_commitment(
|
||||
vss_commitment: &Vec<u8>,
|
||||
) -> Result<VerifiableSecretSharingCommitment, Error> {
|
||||
let coeff_commitments_data = vss_commitment[1..vss_commitment.len()].to_vec();
|
||||
|
||||
let n = vss_commitment[0] as usize;
|
||||
let l = coeff_commitments_data.len() / n;
|
||||
|
||||
let mut coeff_commitments = Vec::with_capacity(n);
|
||||
|
||||
for i in 0..n {
|
||||
let commitment_value = hex::encode(&coeff_commitments_data[(i * l)..((i * l) + l)]);
|
||||
let serialized =
|
||||
<[u8; 32]>::from_hex(commitment_value).map_err(|_| Error::InvalidCoefficients)?; // TODO: Is this the right error? Need to add test
|
||||
coeff_commitments.push(serialized)
|
||||
}
|
||||
|
||||
let out = VerifiableSecretSharingCommitment::deserialize(coeff_commitments)?; //TODO: test for this error
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
// The nonces are printed out here for demo purposes only. The hiding and binding nonces are SECRET and not to be shared.
|
||||
pub fn print_values(
|
||||
nonces: SigningNonces,
|
||||
commitments: SigningCommitments,
|
||||
logger: &mut dyn Logger,
|
||||
) {
|
||||
logger.log("=== Round 1 ===".to_string());
|
||||
logger.log(format!(
|
||||
"Hiding nonce: {}",
|
||||
hex::encode(nonces.hiding().to_bytes())
|
||||
));
|
||||
|
||||
logger.log(format!(
|
||||
"Binding nonce: {}",
|
||||
hex::encode(nonces.binding().to_bytes())
|
||||
));
|
||||
|
||||
logger.log(format!(
|
||||
"Hiding commitment: {}",
|
||||
hex::encode(commitments.hiding().to_bytes())
|
||||
));
|
||||
|
||||
logger.log(format!(
|
||||
"Binding commitment: {}",
|
||||
hex::encode(commitments.binding().to_bytes())
|
||||
));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use frost::keys::VerifiableSecretSharingCommitment;
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
|
||||
use crate::decode_vss_commitment;
|
||||
|
||||
// TODO: Add details of encoding
|
||||
#[test]
|
||||
fn check_decode_vss_commitment() {
|
||||
let vss_commitment_input = hex::decode("0353e4f0ed77543d021eb12cac53c35d4d99f5fc0fa5c3dfd82a3e1e296fba01bdcad2a298d93b5f0079f5f3874599ca2295482e9a4fa75be6c6deb273b61ee441e30ae9f78c1b56a4648130417247826afe3499c0d80b449740f8c968c64df0a4").unwrap();
|
||||
let expected = VerifiableSecretSharingCommitment::deserialize(vec![
|
||||
<[u8; 32]>::from_hex(
|
||||
"53e4f0ed77543d021eb12cac53c35d4d99f5fc0fa5c3dfd82a3e1e296fba01bd",
|
||||
)
|
||||
.unwrap(),
|
||||
<[u8; 32]>::from_hex(
|
||||
"cad2a298d93b5f0079f5f3874599ca2295482e9a4fa75be6c6deb273b61ee441",
|
||||
)
|
||||
.unwrap(),
|
||||
<[u8; 32]>::from_hex(
|
||||
"e30ae9f78c1b56a4648130417247826afe3499c0d80b449740f8c968c64df0a4",
|
||||
)
|
||||
.unwrap(),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
let actual = decode_vss_commitment(&vss_commitment_input).unwrap();
|
||||
|
||||
assert!(expected == actual);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
use crate::Logger;
|
||||
use frost::{
|
||||
keys::{
|
||||
KeyPackage, SecretShare, SigningShare, VerifiableSecretSharingCommitment, VerifyingShare,
|
||||
},
|
||||
round1::{SigningCommitments, SigningNonces},
|
||||
Error, GroupError, Identifier, VerifyingKey,
|
||||
};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use std::io::BufRead;
|
||||
|
||||
// TODO: Rethink the types here. They're inconsistent with each other
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Round1Config {
|
||||
pub identifier: Identifier,
|
||||
pub public_key: VerifyingShare,
|
||||
pub group_public_key: VerifyingKey,
|
||||
pub signing_share: SigningShare,
|
||||
pub vss_commitment: Vec<u8>,
|
||||
}
|
||||
|
||||
// pub trait Logger {
|
||||
// fn log(&mut self, value: String);
|
||||
// }
|
||||
|
||||
// TODO: refactor to generate config
|
||||
pub fn request_inputs(
|
||||
input: &mut impl BufRead,
|
||||
logger: &mut dyn Logger,
|
||||
) -> Result<Round1Config, Error> {
|
||||
logger.log("Your identifier (this should be an integer between 1 and 65535):".to_string());
|
||||
|
||||
let mut identifier_input = String::new();
|
||||
|
||||
input.read_line(&mut identifier_input).unwrap();
|
||||
|
||||
let identifier = identifier_input
|
||||
.trim()
|
||||
.parse::<u16>()
|
||||
.map_err(|_| Error::MalformedIdentifier)?;
|
||||
|
||||
logger.log("Your public key:".to_string());
|
||||
|
||||
let mut public_key_input = String::new();
|
||||
|
||||
input.read_line(&mut public_key_input).unwrap();
|
||||
|
||||
// A specific VerifyingShare error does not currently exist in Frost so `MalformedVerifyingKey`
|
||||
// has been used. This should either be added to Frost or the error handling here can be reconsidered
|
||||
let public_key = VerifyingShare::from_bytes(
|
||||
<[u8; 32]>::from_hex(public_key_input.trim()).map_err(|_| Error::MalformedVerifyingKey)?,
|
||||
)?; //TODO: test error
|
||||
|
||||
logger.log("The group public key:".to_string());
|
||||
let mut group_public_key_input = String::new();
|
||||
|
||||
input.read_line(&mut group_public_key_input).unwrap();
|
||||
|
||||
let group_public_key = VerifyingKey::from_bytes(
|
||||
<[u8; 32]>::from_hex(group_public_key_input.trim())
|
||||
.map_err(|_| Error::MalformedVerifyingKey)?,
|
||||
)
|
||||
.map_err(|_| Error::MalformedVerifyingKey)?; // TODO: Add test for correct error to be returned on failing deserialisation
|
||||
|
||||
logger.log("Your secret share:".to_string());
|
||||
|
||||
let mut signing_share_input = String::new();
|
||||
|
||||
input.read_line(&mut signing_share_input).unwrap();
|
||||
|
||||
// A specific SigningShare error does not currently exist in Frost so `MalformedSigningKey`
|
||||
// has been used. This should either be added to Frost or the error handling here can be reconsidered
|
||||
let signing_share = SigningShare::from_bytes(
|
||||
<[u8; 32]>::from_hex(signing_share_input.trim()).map_err(|_| Error::MalformedSigningKey)?,
|
||||
)?; //TODO: test error
|
||||
|
||||
logger.log("Your verifiable secret sharing commitment:".to_string());
|
||||
|
||||
let mut vss_commitment_input = String::new();
|
||||
|
||||
input.read_line(&mut vss_commitment_input).unwrap();
|
||||
|
||||
let vss_commitment =
|
||||
hex::decode(vss_commitment_input.trim()).map_err(|_| GroupError::MalformedElement)?;
|
||||
|
||||
Ok(Round1Config {
|
||||
identifier: Identifier::try_from(identifier)?,
|
||||
public_key,
|
||||
group_public_key,
|
||||
signing_share,
|
||||
vss_commitment,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generate_key_package(config: &Round1Config) -> Result<KeyPackage, Error> {
|
||||
let secret_share = SecretShare::new(
|
||||
config.identifier,
|
||||
config.signing_share,
|
||||
decode_vss_commitment(&config.vss_commitment)?,
|
||||
);
|
||||
let key_package = KeyPackage::try_from(secret_share)?;
|
||||
|
||||
Ok(key_package)
|
||||
}
|
||||
|
||||
fn decode_vss_commitment(
|
||||
vss_commitment: &Vec<u8>,
|
||||
) -> Result<VerifiableSecretSharingCommitment, Error> {
|
||||
let coeff_commitments_data = vss_commitment[1..vss_commitment.len()].to_vec();
|
||||
|
||||
let n = vss_commitment[0] as usize;
|
||||
let l = coeff_commitments_data.len() / n;
|
||||
|
||||
let mut coeff_commitments = Vec::with_capacity(n);
|
||||
|
||||
for i in 0..n {
|
||||
let commitment_value = hex::encode(&coeff_commitments_data[(i * l)..((i * l) + l)]);
|
||||
let serialized =
|
||||
<[u8; 32]>::from_hex(commitment_value).map_err(|_| Error::InvalidCoefficients)?; // TODO: Is this the right error? Need to add test
|
||||
coeff_commitments.push(serialized)
|
||||
}
|
||||
|
||||
let out = VerifiableSecretSharingCommitment::deserialize(coeff_commitments)?; //TODO: test for this error
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
// The nonces are printed out here for demo purposes only. The hiding and binding nonces are SECRET and not to be shared.
|
||||
pub fn print_values(
|
||||
nonces: &SigningNonces,
|
||||
commitments: SigningCommitments,
|
||||
logger: &mut dyn Logger,
|
||||
) {
|
||||
logger.log("=== Round 1 ===".to_string());
|
||||
logger.log(format!(
|
||||
"Hiding nonce: {}",
|
||||
hex::encode(nonces.hiding().to_bytes())
|
||||
));
|
||||
|
||||
logger.log(format!(
|
||||
"Binding nonce: {}",
|
||||
hex::encode(nonces.binding().to_bytes())
|
||||
));
|
||||
|
||||
logger.log(format!(
|
||||
"Hiding commitment: {}",
|
||||
hex::encode(commitments.hiding().to_bytes())
|
||||
));
|
||||
|
||||
logger.log(format!(
|
||||
"Binding commitment: {}",
|
||||
hex::encode(commitments.binding().to_bytes())
|
||||
));
|
||||
logger.log("=== Round 1 Completed ===".to_string());
|
||||
logger.log("Please send your Hiding and Binding Commitments to the coordinator".to_string());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use frost::keys::VerifiableSecretSharingCommitment;
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
|
||||
use crate::round1::decode_vss_commitment;
|
||||
|
||||
// TODO: Add details of encoding
|
||||
#[test]
|
||||
fn check_decode_vss_commitment() {
|
||||
let vss_commitment_input = hex::decode("0353e4f0ed77543d021eb12cac53c35d4d99f5fc0fa5c3dfd82a3e1e296fba01bdcad2a298d93b5f0079f5f3874599ca2295482e9a4fa75be6c6deb273b61ee441e30ae9f78c1b56a4648130417247826afe3499c0d80b449740f8c968c64df0a4").unwrap();
|
||||
let expected = VerifiableSecretSharingCommitment::deserialize(vec![
|
||||
<[u8; 32]>::from_hex(
|
||||
"53e4f0ed77543d021eb12cac53c35d4d99f5fc0fa5c3dfd82a3e1e296fba01bd",
|
||||
)
|
||||
.unwrap(),
|
||||
<[u8; 32]>::from_hex(
|
||||
"cad2a298d93b5f0079f5f3874599ca2295482e9a4fa75be6c6deb273b61ee441",
|
||||
)
|
||||
.unwrap(),
|
||||
<[u8; 32]>::from_hex(
|
||||
"e30ae9f78c1b56a4648130417247826afe3499c0d80b449740f8c968c64df0a4",
|
||||
)
|
||||
.unwrap(),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
let actual = decode_vss_commitment(&vss_commitment_input).unwrap();
|
||||
|
||||
assert!(expected == actual);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
use crate::Logger;
|
||||
use frost::{
|
||||
keys::KeyPackage,
|
||||
round1::{NonceCommitment, SigningCommitments, SigningNonces},
|
||||
round2::{self, SignatureShare},
|
||||
Error, Identifier, SigningPackage,
|
||||
};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use std::io::BufRead;
|
||||
|
||||
// #[derive(Debug)]
|
||||
pub struct Round2Config {
|
||||
pub message: Vec<u8>,
|
||||
pub signer_commitments: Vec<SigningCommitments>,
|
||||
}
|
||||
|
||||
// TODO: refactor to generate config
|
||||
// TODO: handle errors
|
||||
pub fn round_2_request_inputs(
|
||||
signing_commitments: SigningCommitments,
|
||||
input: &mut impl BufRead,
|
||||
logger: &mut dyn Logger,
|
||||
) -> Result<Round2Config, Error> {
|
||||
logger.log("=== Round 2 ===".to_string());
|
||||
|
||||
logger.log("Number of signers:".to_string());
|
||||
|
||||
let mut signers_input = String::new();
|
||||
|
||||
input.read_line(&mut signers_input).unwrap();
|
||||
|
||||
let signers = signers_input.trim().parse::<u16>().unwrap();
|
||||
|
||||
logger.log("Enter the message to sign (received from the coordinator):".to_string());
|
||||
|
||||
let mut message_input = String::new();
|
||||
|
||||
input.read_line(&mut message_input).unwrap();
|
||||
|
||||
let message = hex::decode(message_input.trim()).unwrap();
|
||||
|
||||
let mut commitments = vec![signing_commitments];
|
||||
|
||||
for _ in 2..=signers {
|
||||
logger.log("Identifier:".to_string());
|
||||
|
||||
let mut identifier_input = String::new();
|
||||
|
||||
input.read_line(&mut identifier_input).unwrap();
|
||||
|
||||
let id_value = identifier_input.trim().parse::<u16>().unwrap();
|
||||
let identifier = Identifier::try_from(id_value).unwrap();
|
||||
|
||||
logger.log(format!("Hiding commitment {}:", id_value));
|
||||
let mut hiding_commitment_input = String::new();
|
||||
|
||||
input.read_line(&mut hiding_commitment_input).unwrap();
|
||||
let hiding_commitment = NonceCommitment::from_bytes(
|
||||
<[u8; 32]>::from_hex(hiding_commitment_input.trim()).unwrap(),
|
||||
)?;
|
||||
|
||||
logger.log(format!("Binding commitment {}:", id_value));
|
||||
let mut binding_commitment_input = String::new();
|
||||
|
||||
input.read_line(&mut binding_commitment_input).unwrap();
|
||||
let binding_commitment = NonceCommitment::from_bytes(
|
||||
<[u8; 32]>::from_hex(binding_commitment_input.trim()).unwrap(),
|
||||
)?;
|
||||
|
||||
let signer_commitments =
|
||||
SigningCommitments::new(identifier, hiding_commitment, binding_commitment); // TODO: Add test for correct error to be returned on failing deserialisation
|
||||
|
||||
commitments.push(signer_commitments);
|
||||
}
|
||||
|
||||
Ok(Round2Config {
|
||||
message,
|
||||
signer_commitments: commitments,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generate_signature(
|
||||
config: Round2Config,
|
||||
key_package: &KeyPackage,
|
||||
signing_nonces: &SigningNonces,
|
||||
) -> Result<SignatureShare, Error> {
|
||||
let signing_package = SigningPackage::new(config.signer_commitments, &config.message);
|
||||
let signature = round2::sign(&signing_package, signing_nonces, key_package)?;
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
fn encode_signature_response(signature_share: SignatureShare) -> String {
|
||||
let id = hex::encode(signature_share.identifier().serialize());
|
||||
let sig = hex::encode(signature_share.signature().to_bytes());
|
||||
id + &sig
|
||||
}
|
||||
|
||||
pub fn print_values_round_2(signature: SignatureShare, logger: &mut dyn Logger) {
|
||||
logger.log("Please send the following to the Coordinator".to_string());
|
||||
logger.log(format!(
|
||||
"Signature share: {}",
|
||||
encode_signature_response(signature)
|
||||
));
|
||||
logger.log("=== End of Round 2 ===".to_string());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use frost::{
|
||||
round2::{SignatureResponse, SignatureShare},
|
||||
Identifier,
|
||||
};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
|
||||
use crate::round2::encode_signature_response;
|
||||
|
||||
// TODO: Add details of encoding
|
||||
#[test]
|
||||
fn check_encode_signature_response() {
|
||||
const SIGNATURE_RESPONSE: &str =
|
||||
"44055c54d0604cbd006f0d1713a22474d7735c5e8816b1878f62ca94bf105900";
|
||||
let signature_response =
|
||||
SignatureResponse::from_bytes(<[u8; 32]>::from_hex(SIGNATURE_RESPONSE).unwrap())
|
||||
.unwrap();
|
||||
let signature_share =
|
||||
SignatureShare::new(Identifier::try_from(1).unwrap(), signature_response);
|
||||
|
||||
let expected = "010000000000000000000000000000000000000000000000000000000000000044055c54d0604cbd006f0d1713a22474d7735c5e8816b1878f62ca94bf105900";
|
||||
let signature = encode_signature_response(signature_share);
|
||||
|
||||
assert!(expected == signature)
|
||||
}
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
mod cli;
|
||||
mod lib;
|
||||
mod round1;
|
||||
mod round2;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
use crate::cli::cli;
|
||||
use frost::{keys::SigningShare, round1, Identifier};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use participant::Logger;
|
||||
use rand::thread_rng;
|
||||
|
||||
pub struct TestLogger(Vec<String>);
|
||||
|
||||
|
@ -11,32 +15,92 @@ impl Logger for TestLogger {
|
|||
|
||||
#[test]
|
||||
fn check_cli() {
|
||||
let identifier: u16 = 1;
|
||||
// Round 1 inputs
|
||||
let identifier = "1";
|
||||
let pub_key = "470f53fb724502bf5b851471e9f8317616fcc7be9405ccff3347c232a3052ce7";
|
||||
let group_pub_key = "42ae1baa1bce5a38c130e60aade154ec8775076e729881aba66dabd0c0ac6332";
|
||||
let signing_share = "1edfa2ebd280cba9a72f0bc027d21c30078c11f92e0c908addb958062c1ac900";
|
||||
let vss_commitment = "0342ae1baa1bce5a38c130e60aade154ec8775076e729881aba66dabd0c0ac6332393a813a6b47782f0fbe653593cbb7b0e0e13f01b54b801144545cb774c0fe5683d8bee3cd63b10523ccace10044869c56bce8a6061950f9aebd7f2e36249571";
|
||||
|
||||
// Round 2 inputs
|
||||
let min_signers = "3";
|
||||
const MESSAGE: &str = "15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673";
|
||||
const IDENTIFIER_2: &str = "2";
|
||||
const HIDING_COMMITMENT_2: &str =
|
||||
"30f3f03bd739024dc5b1e9d422745a7f32b0971d5cef302106b30bd9f5642d70";
|
||||
const BINDING_COMMITMENT_2: &str =
|
||||
"a7ccae3750846fbd7d132efec85e96236a711b2097a6f03b1afa04f6029458cc";
|
||||
const IDENTIFIER_3: &str = "3";
|
||||
const HIDING_COMMITMENT_3: &str =
|
||||
"d31bd81ce216b1c83912803a574a0285796275cb8b14f6dc92c8b09a6951f0a2";
|
||||
const BINDING_COMMITMENT_3: &str =
|
||||
"e1c863cfd08df775b6747ef2456e9bf9a03cc281a479a95261dc39137fcf0967";
|
||||
|
||||
let input = format!(
|
||||
"{}\n{}\n{}\n{}\n{}\n",
|
||||
identifier, pub_key, group_pub_key, signing_share, vss_commitment
|
||||
"{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n",
|
||||
identifier,
|
||||
pub_key,
|
||||
group_pub_key,
|
||||
signing_share,
|
||||
vss_commitment,
|
||||
min_signers,
|
||||
MESSAGE,
|
||||
IDENTIFIER_2,
|
||||
HIDING_COMMITMENT_2,
|
||||
BINDING_COMMITMENT_2,
|
||||
IDENTIFIER_3,
|
||||
HIDING_COMMITMENT_3,
|
||||
BINDING_COMMITMENT_3
|
||||
);
|
||||
let mut reader = input.as_bytes();
|
||||
let mut test_logger = TestLogger(Vec::new());
|
||||
cli(&mut reader, &mut test_logger);
|
||||
|
||||
// We aren't testing randomness so we are not testing the generation of the nonces and commitments at the top level.
|
||||
// TODO: mock the round1::commit function. To be improved in a later issue.
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// We aren't testing randomness so this needs to be generated in the tests. TODO: mock the round1::commit function. To be improved in a later issue.
|
||||
let (nonces, commitments) = round1::commit(
|
||||
Identifier::try_from(1).unwrap(),
|
||||
&SigningShare::from_hex(signing_share).unwrap(),
|
||||
&mut rng,
|
||||
);
|
||||
|
||||
let _hiding_nonce = hex::encode(nonces.hiding().to_bytes());
|
||||
let _binding_nonce = hex::encode(nonces.binding().to_bytes());
|
||||
let _hiding_commitment = hex::encode(commitments.hiding().to_bytes());
|
||||
let _binding_commitment = hex::encode(commitments.binding().to_bytes());
|
||||
|
||||
// let signature_share = hex::encode(sig_share.to_bytes());
|
||||
|
||||
let log = [
|
||||
"Your identifier (this should be an integer between 1 and 65535):".to_string(),
|
||||
"Your public key:".to_string(),
|
||||
"The group public key:".to_string(),
|
||||
"Your secret share:".to_string(),
|
||||
"Your verifiable secret sharing commitment:".to_string(),
|
||||
"Key Package succesfully created.".to_string(),
|
||||
"=== Round 1 ===".to_string(),
|
||||
];
|
||||
"Your identifier (this should be an integer between 1 and 65535):",
|
||||
"Your public key:",
|
||||
"The group public key:",
|
||||
"Your secret share:",
|
||||
"Your verifiable secret sharing commitment:",
|
||||
"Key Package succesfully created.",
|
||||
"=== Round 1 ===",
|
||||
"Hiding nonce: {}",
|
||||
"Binding nonce: {}",
|
||||
"Hiding commitment: {}",
|
||||
"Binding commitment: {}",
|
||||
"=== Round 1 Completed ===",
|
||||
"Please send your Hiding and Binding Commitments to the coordinator",
|
||||
"=== Round 2 ===",
|
||||
"Number of signers:",
|
||||
"Enter the message to sign (received from the coordinator):",
|
||||
"Identifier:",
|
||||
"Hiding commitment 2:",
|
||||
"Binding commitment 2:",
|
||||
"Identifier:",
|
||||
"Hiding commitment 3:",
|
||||
"Binding commitment 3:",
|
||||
// "Signature share: {}", // TODO: this tests the signature share value returned is correct. The calculation is done in lib.rs tests.
|
||||
// "=== Round 2 Completed ==="
|
||||
]
|
||||
.to_vec();
|
||||
|
||||
assert_eq!(test_logger.0[0..=6], log)
|
||||
assert_eq!(test_logger.0[0..7], log[0..7]);
|
||||
assert_eq!(test_logger.0[12..22], log[12..22]);
|
||||
// TODO: test nonce and commitment values
|
||||
}
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
use frost::{
|
||||
keys::{KeyPackage, SigningShare, VerifyingShare},
|
||||
VerifyingKey,
|
||||
round1, VerifyingKey,
|
||||
};
|
||||
#[cfg(test)]
|
||||
use frost::{Error, Identifier};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use participant::{generate_key_package, request_inputs, Config};
|
||||
use participant::round1::{generate_key_package, print_values, request_inputs, Round1Config};
|
||||
|
||||
use crate::Logger;
|
||||
use participant::Logger;
|
||||
use rand::thread_rng;
|
||||
|
||||
const IDENTIFIER: &str = "1";
|
||||
const PUBLIC_KEY: &str = "adf6ab1f882d04988eadfaa52fb175bf37b6247785d7380fde3fb9d68032470d";
|
||||
const GROUP_PUBLIC_KEY: &str = "087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e";
|
||||
const SIGNING_SHARE: &str = "ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104";
|
||||
const VSS_COMMITMENT : &str = "03087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e926d5910e146dccb9148ca39dc7607f4f7123ff1c0ffaf109add1d165c568bf2291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc";
|
||||
|
||||
pub struct TestLogger(Vec<String>);
|
||||
|
||||
|
@ -18,15 +25,9 @@ impl Logger for TestLogger {
|
|||
}
|
||||
}
|
||||
|
||||
const IDENTIFIER: &str = "1";
|
||||
const PUBLIC_KEY: &str = "adf6ab1f882d04988eadfaa52fb175bf37b6247785d7380fde3fb9d68032470d";
|
||||
const GROUP_PUBLIC_KEY: &str = "087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e";
|
||||
const SIGNING_SHARE: &str = "ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104";
|
||||
const VSS_COMMITMENT : &str = "03087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e926d5910e146dccb9148ca39dc7607f4f7123ff1c0ffaf109add1d165c568bf2291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc";
|
||||
|
||||
#[test]
|
||||
fn check_valid_inputs() {
|
||||
let config = Config {
|
||||
fn check_valid_round_1_inputs() {
|
||||
let config = Round1Config {
|
||||
identifier: Identifier::try_from(1).unwrap(),
|
||||
public_key: VerifyingShare::from_bytes(<[u8; 32]>::from_hex(PUBLIC_KEY).unwrap()).unwrap(),
|
||||
group_public_key: VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap(),
|
||||
|
@ -130,7 +131,6 @@ fn check_invalid_length_signing_share() {
|
|||
|
||||
// TODO: Handle this error differently
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn check_invalid_length_vss_commitment() {
|
||||
let mut test_logger = TestLogger(Vec::new());
|
||||
|
||||
|
@ -141,12 +141,13 @@ fn check_invalid_length_vss_commitment() {
|
|||
);
|
||||
let mut invalid_input = input.as_bytes();
|
||||
|
||||
let _expected = request_inputs(&mut invalid_input, &mut test_logger);
|
||||
let expected = request_inputs(&mut invalid_input, &mut test_logger);
|
||||
assert!(expected.is_err())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_key_package_generation() {
|
||||
let config = Config {
|
||||
let config = Round1Config {
|
||||
identifier: Identifier::try_from(1).unwrap(),
|
||||
public_key: VerifyingShare::from_bytes(<[u8; 32]>::from_hex(PUBLIC_KEY).unwrap()).unwrap(),
|
||||
group_public_key: VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap(),
|
||||
|
@ -170,7 +171,7 @@ fn check_key_package_generation() {
|
|||
fn check_key_package_generation_fails_with_invalid_secret_share() {
|
||||
let incorrect_signing_share =
|
||||
"afc0ba51fd450297725f9efe714400d51a1180a273177b5dd8ad3b8cba41560d";
|
||||
let config = Config {
|
||||
let config = Round1Config {
|
||||
identifier: Identifier::try_from(1).unwrap(),
|
||||
public_key: VerifyingShare::from_bytes(<[u8; 32]>::from_hex(PUBLIC_KEY).unwrap()).unwrap(),
|
||||
group_public_key: VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap(),
|
||||
|
@ -180,8 +181,38 @@ fn check_key_package_generation_fails_with_invalid_secret_share() {
|
|||
.unwrap(),
|
||||
vss_commitment: hex::decode(VSS_COMMITMENT).unwrap(),
|
||||
};
|
||||
|
||||
let key_package = generate_key_package(&config);
|
||||
|
||||
assert!(key_package.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_print_values() {
|
||||
let mut test_logger = TestLogger(Vec::new());
|
||||
let signing_share =
|
||||
SigningShare::from_bytes(<[u8; 32]>::from_hex(SIGNING_SHARE).unwrap()).unwrap();
|
||||
let mut rng = thread_rng();
|
||||
let (nonces, commitments) =
|
||||
round1::commit(Identifier::try_from(1).unwrap(), &signing_share, &mut rng);
|
||||
|
||||
print_values(&nonces, commitments, &mut test_logger);
|
||||
|
||||
let log = [
|
||||
"=== Round 1 ===".to_string(),
|
||||
format!("Hiding nonce: {}", hex::encode(nonces.hiding().to_bytes())),
|
||||
format!(
|
||||
"Binding nonce: {}",
|
||||
hex::encode(nonces.binding().to_bytes())
|
||||
),
|
||||
format!(
|
||||
"Hiding commitment: {}",
|
||||
hex::encode(commitments.hiding().to_bytes())
|
||||
),
|
||||
format!(
|
||||
"Binding commitment: {}",
|
||||
hex::encode(commitments.binding().to_bytes())
|
||||
),
|
||||
"=== Round 1 Completed ===".to_string(),
|
||||
"Please send your Hiding and Binding Commitments to the coordinator".to_string(),
|
||||
];
|
||||
assert_eq!(test_logger.0, log)
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
#[cfg(test)]
|
||||
use frost::Identifier;
|
||||
use frost::{
|
||||
keys::{KeyPackage, SigningShare, VerifyingShare},
|
||||
round1::{self, NonceCommitment, SigningCommitments},
|
||||
round2::{SignatureResponse, SignatureShare},
|
||||
VerifyingKey,
|
||||
};
|
||||
use frost_ed25519 as frost;
|
||||
use hex::FromHex;
|
||||
use participant::round2::{generate_signature, round_2_request_inputs, Round2Config};
|
||||
use participant::Logger;
|
||||
use participant::{round1::Round1Config, round2::print_values_round_2};
|
||||
use rand::thread_rng;
|
||||
|
||||
pub struct TestLogger(Vec<String>);
|
||||
|
||||
impl Logger for TestLogger {
|
||||
fn log(&mut self, value: String) {
|
||||
self.0.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
const PUBLIC_KEY: &str = "adf6ab1f882d04988eadfaa52fb175bf37b6247785d7380fde3fb9d68032470d";
|
||||
const GROUP_PUBLIC_KEY: &str = "087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e";
|
||||
const SIGNING_SHARE: &str = "ceed7dd148a1a1ec2e65b50ecab6a7c453ccbd38c397c3506a540b7cf0dd9104";
|
||||
const VSS_COMMITMENT : &str = "03087e22f970daf6ac5b07b55bd7fc0af6dea199ab847dc34fc92a6f8641a1bb8e926d5910e146dccb9148ca39dc7607f4f7123ff1c0ffaf109add1d165c568bf2291bb78d7e4ef124f5aa6a36cbcf8c276e70fbb4e208212e916d762fc42c1bbc";
|
||||
const MESSAGE: &str = "15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673";
|
||||
const MY_HIDING_COMMITMENT: &str =
|
||||
"44105304351ceddc58e15ddea35b2cb48e60ced54ceb22c3b0e5d42d098aa1d8";
|
||||
const MY_BINDING_COMMITMENT: &str =
|
||||
"b8274b18a12f2cef74ae42f876cec1e31daab5cb162f95a56cd2487409c9d1dd";
|
||||
const IDENTIFIER_2: &str = "2";
|
||||
const HIDING_COMMITMENT_2: &str =
|
||||
"30f3f03bd739024dc5b1e9d422745a7f32b0971d5cef302106b30bd9f5642d70";
|
||||
const BINDING_COMMITMENT_2: &str =
|
||||
"a7ccae3750846fbd7d132efec85e96236a711b2097a6f03b1afa04f6029458cc";
|
||||
const IDENTIFIER_3: &str = "3";
|
||||
const HIDING_COMMITMENT_3: &str =
|
||||
"d31bd81ce216b1c83912803a574a0285796275cb8b14f6dc92c8b09a6951f0a2";
|
||||
const BINDING_COMMITMENT_3: &str =
|
||||
"e1c863cfd08df775b6747ef2456e9bf9a03cc281a479a95261dc39137fcf0967";
|
||||
|
||||
#[test]
|
||||
fn check_valid_round_2_inputs() {
|
||||
// TODO: refactor
|
||||
let my_signer_commitments = SigningCommitments::new(
|
||||
Identifier::try_from(1).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(MY_HIDING_COMMITMENT).unwrap()).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(MY_BINDING_COMMITMENT).unwrap()).unwrap(),
|
||||
);
|
||||
|
||||
let signer_commitments_2 = SigningCommitments::new(
|
||||
Identifier::try_from(2).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(HIDING_COMMITMENT_2).unwrap()).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(BINDING_COMMITMENT_2).unwrap()).unwrap(),
|
||||
);
|
||||
let signer_commitments_3 = SigningCommitments::new(
|
||||
Identifier::try_from(3).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(HIDING_COMMITMENT_3).unwrap()).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(BINDING_COMMITMENT_3).unwrap()).unwrap(),
|
||||
);
|
||||
|
||||
let config = Round2Config {
|
||||
message: hex::decode("15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673")
|
||||
.unwrap(),
|
||||
signer_commitments: vec![
|
||||
my_signer_commitments,
|
||||
signer_commitments_2,
|
||||
signer_commitments_3,
|
||||
],
|
||||
};
|
||||
|
||||
let mut test_logger = TestLogger(Vec::new());
|
||||
|
||||
let input = format!(
|
||||
"{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n",
|
||||
"3",
|
||||
MESSAGE,
|
||||
IDENTIFIER_2,
|
||||
HIDING_COMMITMENT_2,
|
||||
BINDING_COMMITMENT_2,
|
||||
IDENTIFIER_3,
|
||||
HIDING_COMMITMENT_3,
|
||||
BINDING_COMMITMENT_3
|
||||
);
|
||||
let mut valid_input = input.as_bytes();
|
||||
|
||||
let expected =
|
||||
round_2_request_inputs(my_signer_commitments, &mut valid_input, &mut test_logger).unwrap();
|
||||
|
||||
assert_eq!(expected.message, config.message);
|
||||
// TODO: This is easily resolved in the latest release of Frost which includes the Debug trait
|
||||
// assert_eq!(expected.signer_commitments[&Identifier::try_from(1).unwrap()], config.signer_commitments[&Identifier::try_from(1).unwrap()]);
|
||||
}
|
||||
|
||||
// TODO: test for invalid inputs
|
||||
|
||||
#[test]
|
||||
fn check_sign() {
|
||||
let config = Round1Config {
|
||||
identifier: Identifier::try_from(1).unwrap(),
|
||||
public_key: VerifyingShare::from_bytes(<[u8; 32]>::from_hex(PUBLIC_KEY).unwrap()).unwrap(),
|
||||
group_public_key: VerifyingKey::from_hex(GROUP_PUBLIC_KEY).unwrap(),
|
||||
signing_share: SigningShare::from_bytes(<[u8; 32]>::from_hex(SIGNING_SHARE).unwrap())
|
||||
.unwrap(),
|
||||
vss_commitment: hex::decode(VSS_COMMITMENT).unwrap(),
|
||||
};
|
||||
|
||||
let key_package = KeyPackage::new(
|
||||
config.identifier,
|
||||
config.signing_share,
|
||||
config.public_key,
|
||||
config.group_public_key,
|
||||
);
|
||||
|
||||
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(
|
||||
Identifier::try_from(1).unwrap(),
|
||||
&SigningShare::from_hex(SIGNING_SHARE).unwrap(),
|
||||
&mut rng,
|
||||
);
|
||||
|
||||
let signer_commitments_2 = SigningCommitments::new(
|
||||
Identifier::try_from(2).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(HIDING_COMMITMENT_2).unwrap()).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(BINDING_COMMITMENT_2).unwrap()).unwrap(),
|
||||
);
|
||||
|
||||
let signer_commitments_3 = SigningCommitments::new(
|
||||
Identifier::try_from(3).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(HIDING_COMMITMENT_3).unwrap()).unwrap(),
|
||||
NonceCommitment::from_bytes(<[u8; 32]>::from_hex(BINDING_COMMITMENT_3).unwrap()).unwrap(),
|
||||
);
|
||||
|
||||
let config = Round2Config {
|
||||
message: hex::decode("15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673")
|
||||
.unwrap(),
|
||||
signer_commitments: vec![my_commitments, signer_commitments_2, signer_commitments_3],
|
||||
};
|
||||
|
||||
let signature = generate_signature(config, &key_package, &nonces);
|
||||
|
||||
assert!(signature.is_ok()) // TODO: Should be able to test this more specifically when I remove randomness from the test
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_print_values_round_2() {
|
||||
let mut test_logger = TestLogger(Vec::new());
|
||||
|
||||
const IDENTIFIER: &str = "0100000000000000000000000000000000000000000000000000000000000000";
|
||||
const SIGNATURE_RESPONSE: &str =
|
||||
"44055c54d0604cbd006f0d1713a22474d7735c5e8816b1878f62ca94bf105900";
|
||||
let signature_response =
|
||||
SignatureResponse::from_bytes(<[u8; 32]>::from_hex(SIGNATURE_RESPONSE).unwrap()).unwrap();
|
||||
let signature = SignatureShare::new(Identifier::try_from(1).unwrap(), signature_response);
|
||||
|
||||
print_values_round_2(signature, &mut test_logger);
|
||||
|
||||
let log = [
|
||||
"Please send the following to the Coordinator".to_string(),
|
||||
format!(
|
||||
"Signature share: {}",
|
||||
IDENTIFIER.to_string() + SIGNATURE_RESPONSE
|
||||
),
|
||||
"=== End of Round 2 ===".to_string(),
|
||||
];
|
||||
|
||||
assert_eq!(test_logger.0, log);
|
||||
}
|
|
@ -1,2 +1,86 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use frost::SigningPackage;
|
||||
use frost_ed25519 as frost;
|
||||
use participant::round1::Round1Config;
|
||||
use participant::round2::{generate_signature, Round2Config};
|
||||
use rand::thread_rng;
|
||||
|
||||
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_test() {}
|
||||
fn check_participant() {
|
||||
let mut rng = thread_rng();
|
||||
let (shares, pubkeys) = frost::keys::generate_with_dealer(3, 2, &mut rng).unwrap();
|
||||
|
||||
let mut key_packages: HashMap<_, _> = HashMap::new();
|
||||
|
||||
for (k, v) in shares.clone() {
|
||||
let key_package = frost::keys::KeyPackage::try_from(v).unwrap();
|
||||
key_packages.insert(k, key_package);
|
||||
}
|
||||
|
||||
// Round 1
|
||||
|
||||
let mut nonces = HashMap::new();
|
||||
let mut commitments = HashMap::new();
|
||||
|
||||
for i in shares.keys() {
|
||||
let config = Round1Config {
|
||||
identifier: *i,
|
||||
public_key: pubkeys.signer_pubkeys()[i],
|
||||
group_public_key: *pubkeys.group_public(),
|
||||
signing_share: *shares[i].secret(),
|
||||
vss_commitment: hex::decode(encode_commitment_helper(
|
||||
shares[i].commitment().serialize(),
|
||||
))
|
||||
.unwrap(),
|
||||
};
|
||||
let (nonce, commitment) = frost::round1::commit(
|
||||
config.identifier,
|
||||
key_packages[&config.identifier].secret_share(),
|
||||
&mut rng,
|
||||
);
|
||||
nonces.insert(config.identifier, nonce);
|
||||
commitments.insert(config.identifier, commitment);
|
||||
}
|
||||
|
||||
// Coordinator sends message
|
||||
|
||||
let message = "a message".as_bytes().to_vec();
|
||||
|
||||
// Round 2
|
||||
|
||||
let mut signature_shares = Vec::new();
|
||||
|
||||
for participant_identifier in nonces.keys() {
|
||||
let config = Round2Config {
|
||||
message: message.clone(),
|
||||
signer_commitments: commitments.values().cloned().collect(),
|
||||
};
|
||||
let signature = generate_signature(
|
||||
config,
|
||||
&key_packages[participant_identifier],
|
||||
&nonces[participant_identifier],
|
||||
)
|
||||
.unwrap();
|
||||
signature_shares.push(signature);
|
||||
}
|
||||
|
||||
// Coordinator aggregates signatures
|
||||
|
||||
let signing_package = SigningPackage::new(commitments.values().cloned().collect(), &message);
|
||||
|
||||
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());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue