use alloc::collections::BTreeMap;
use debugless_unwrap::DebuglessUnwrapExt;
use rand_core::{CryptoRng, RngCore};
use serde_json::Value;
use crate as frost;
use crate::keys::repairable::{Delta, Sigma};
use crate::keys::KeyPackage;
use crate::{
compute_lagrange_coefficient,
keys::{
repairable::{repair_share_part1, repair_share_part2, repair_share_part3},
PublicKeyPackage, SecretShare,
},
Ciphersuite, Error, Field, Group, Identifier,
};
pub fn check_rts<C: Ciphersuite, R: RngCore + CryptoRng>(mut rng: R) {
let max_signers = 5;
let min_signers = 3;
let (shares, public_key_package): (
BTreeMap<Identifier<C>, SecretShare<C>>,
PublicKeyPackage<C>,
) = frost::keys::generate_with_dealer(
max_signers,
min_signers,
frost::keys::IdentifierList::Default,
&mut rng,
)
.unwrap();
let key_packages = shares
.into_iter()
.map(|(id, share)| (id, share.try_into().unwrap()))
.collect::<BTreeMap<Identifier<C>, KeyPackage<C>>>();
let helper_1 = &key_packages[&Identifier::try_from(1).unwrap()];
let helper_4 = &key_packages[&Identifier::try_from(4).unwrap()];
let helper_5 = &key_packages[&Identifier::try_from(5).unwrap()];
let participant = &key_packages[&Identifier::try_from(2).unwrap()];
let helpers: [Identifier<C>; 3] = [
helper_1.identifier,
helper_4.identifier,
helper_5.identifier,
];
let helper_1_deltas =
repair_share_part1(&helpers, helper_1, &mut rng, participant.identifier).unwrap();
let helper_4_deltas =
repair_share_part1(&helpers, helper_4, &mut rng, participant.identifier).unwrap();
let helper_5_deltas =
repair_share_part1(&helpers, helper_5, &mut rng, participant.identifier).unwrap();
let helper_1_sigma: Sigma<C> = repair_share_part2::<C>(&[
helper_1_deltas[&helpers[0]],
helper_4_deltas[&helpers[0]],
helper_5_deltas[&helpers[0]],
]);
let helper_4_sigma: Sigma<C> = repair_share_part2::<C>(&[
helper_1_deltas[&helpers[1]],
helper_4_deltas[&helpers[1]],
helper_5_deltas[&helpers[1]],
]);
let helper_5_sigma: Sigma<C> = repair_share_part2::<C>(&[
helper_1_deltas[&helpers[2]],
helper_4_deltas[&helpers[2]],
helper_5_deltas[&helpers[2]],
]);
let participant_recovered_share = repair_share_part3(
&[helper_1_sigma, helper_4_sigma, helper_5_sigma],
participant.identifier,
&public_key_package,
)
.unwrap();
assert!(participant.signing_share() == participant_recovered_share.signing_share())
}
fn generate_scalar_from_byte_string<C: Ciphersuite>(
bs: &str,
) -> <<C::Group as Group>::Field as Field>::Scalar {
let decoded = hex::decode(bs).unwrap();
let out = <<C::Group as Group>::Field>::deserialize(
&decoded.as_slice().try_into().debugless_unwrap(),
);
out.unwrap()
}
pub fn check_repair_share_part1<C: Ciphersuite, R: RngCore + CryptoRng>(mut rng: R) {
let max_signers = 5;
let min_signers = 3;
let (shares, _pubkeys): (BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>) =
frost::keys::generate_with_dealer(
max_signers,
min_signers,
frost::keys::IdentifierList::Default,
&mut rng,
)
.unwrap();
let key_packages = shares
.into_iter()
.map(|(id, share)| (id, share.try_into().unwrap()))
.collect::<BTreeMap<Identifier<C>, KeyPackage<C>>>();
let helper_1 = &key_packages[&Identifier::try_from(1).unwrap()];
let helper_4 = &key_packages[&Identifier::try_from(4).unwrap()];
let helper_5 = &key_packages[&Identifier::try_from(5).unwrap()];
let participant = &key_packages[&Identifier::try_from(2).unwrap()];
let helpers: [Identifier<C>; 3] = [
helper_1.identifier,
helper_4.identifier,
helper_5.identifier,
];
let deltas = repair_share_part1(&helpers, helper_4, &mut rng, participant.identifier).unwrap();
let lagrange_coefficient = compute_lagrange_coefficient(
&helpers.iter().cloned().collect(),
Some(participant.identifier),
helpers[1],
)
.unwrap();
let mut rhs = <<C::Group as Group>::Field>::zero();
for (_k, v) in deltas {
rhs = rhs + v.to_scalar();
}
let lhs = lagrange_coefficient * helper_4.signing_share.to_scalar();
assert!(lhs == rhs)
}
pub fn check_repair_share_part2<C: Ciphersuite>(repair_share_helpers: &Value) {
let values = &repair_share_helpers["scalar_generation"];
let value_1 = Delta::new(generate_scalar_from_byte_string::<C>(
values["random_scalar_1"].as_str().unwrap(),
));
let value_2 = Delta::new(generate_scalar_from_byte_string::<C>(
values["random_scalar_2"].as_str().unwrap(),
));
let value_3 = Delta::new(generate_scalar_from_byte_string::<C>(
values["random_scalar_3"].as_str().unwrap(),
));
let expected = repair_share_part2::<C>(&[value_1, value_2, value_3]);
let actual = Sigma::new(generate_scalar_from_byte_string::<C>(
values["random_scalar_sum"].as_str().unwrap(),
));
assert!(actual == expected);
}
pub fn check_repair_share_part3<C: Ciphersuite, R: RngCore + CryptoRng>(
mut rng: R,
repair_share_helpers: &Value,
) {
let max_signers = 5;
let min_signers = 3;
let (_shares, public_key_package): (
BTreeMap<Identifier<C>, SecretShare<C>>,
PublicKeyPackage<C>,
) = frost::keys::generate_with_dealer(
max_signers,
min_signers,
frost::keys::IdentifierList::Default,
&mut rng,
)
.unwrap();
let sigmas: &Value = &repair_share_helpers["sigma_generation"];
let sigma_1 = Sigma::new(generate_scalar_from_byte_string::<C>(
sigmas["sigma_1"].as_str().unwrap(),
));
let sigma_2 = Sigma::new(generate_scalar_from_byte_string::<C>(
sigmas["sigma_2"].as_str().unwrap(),
));
let sigma_3 = Sigma::new(generate_scalar_from_byte_string::<C>(
sigmas["sigma_3"].as_str().unwrap(),
));
let sigma_4 = Sigma::new(generate_scalar_from_byte_string::<C>(
sigmas["sigma_4"].as_str().unwrap(),
));
let actual = repair_share_part3::<C>(
&[sigma_1, sigma_2, sigma_3, sigma_4],
Identifier::try_from(2).unwrap(),
&public_key_package,
)
.unwrap();
let expected: <<C::Group as Group>::Field as Field>::Scalar =
generate_scalar_from_byte_string::<C>(sigmas["sigma_sum"].as_str().unwrap());
assert!(expected == actual.signing_share().to_scalar());
}
pub fn check_repair_share_part1_fails_with_invalid_min_signers<
C: Ciphersuite,
R: RngCore + CryptoRng,
>(
mut rng: R,
) {
let max_signers = 3;
let min_signers = 2; let (shares, _pubkeys): (BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>) =
frost::keys::generate_with_dealer(
max_signers,
min_signers,
frost::keys::IdentifierList::Default,
&mut rng,
)
.unwrap();
let key_packages = shares
.into_iter()
.map(|(id, share)| (id, share.try_into().unwrap()))
.collect::<BTreeMap<Identifier<C>, KeyPackage<C>>>();
let helper = Identifier::try_from(3).unwrap();
let out = repair_share_part1(
&[helper],
&key_packages[&helper],
&mut rng,
Identifier::try_from(2).unwrap(),
);
assert!(out.is_err());
assert!(out == Err(Error::IncorrectNumberOfIdentifiers))
}