Add repair share functionality (#281)
* Add compute random value function for repair share functionality (#41) This is step 1 of 3 * Add compute random value function for repair share functionality for each ciphersuite (#41) * Add compute_sum_of_random_values function for repair share functionality (#41) This is step 2 of 3 * Add recover_share function for repair share functionality (#41) This is step 3 of 3 * Add communication rounds functions for repair share functionality for each ciphersuite (#41) Add compute_sum_of_random_variables function Add recover_share function * Fix recover_share tests so they test the right thing Fix secp256 recover share test values Fix ristretto255 recover share test values Fix ristretto255 compute sum of random values test values * Rewrite compute_random_values to generate_random_values for repair share functionality (#41) Test generate_random_values directly End to end test to be added in another commit Updated gendoc to use original file values to fix clippy complaints * Rename functions and update documentation for repair (#41) * Add end to end test for repair share (#41) Fix lagrange coefficient calculation Co-authored-by: conrado <conradoplg@gmail.com> * Fix formatting (#41) * Remove comment (#41) Co-authored-by: Conrado Gouvea <conrado@zfnd.org> * Update documentation for step 1 of RTS (#41) Co-authored-by: Conrado Gouvea <conrado@zfnd.org> * Update documentation for method of computing step 1 of RTS (#41) Co-authored-by: Conrado Gouvea <conrado@zfnd.org> * Rename repair share functions (#41) * Improve documentation for Repairable Threshold Scheme (#41) * Remove unecessary code from repairable tests (#41) * Update repairable documentation Co-authored-by: Conrado Gouvea <conrado@zfnd.org> * Rename steps in repairable to be more consistent with DKG pattern (#41) * Update gitignore (#41) * Update repairable to use new keygen_with_dealer signature (#41) * Update frost-core/src/frost/keys/repairable.rs --------- Co-authored-by: conrado <conradoplg@gmail.com> Co-authored-by: Conrado Gouvea <conrado@zfnd.org>
This commit is contained in:
parent
6554f2ba85
commit
0b981618cd
|
@ -21,6 +21,7 @@ use crate::{
|
|||
};
|
||||
|
||||
pub mod dkg;
|
||||
pub mod repairable;
|
||||
|
||||
/// Return a vector of randomly generated polynomial coefficients ([`Scalar`]s).
|
||||
pub(crate) fn generate_coefficients<C: Ciphersuite, R: RngCore + CryptoRng>(
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
//! Repairable Threshold Scheme
|
||||
//!
|
||||
//! Implements the Repairable Threshold Scheme (RTS) from <https://eprint.iacr.org/2017/1155>.
|
||||
//! The RTS is used to help a signer (participant) repair their lost share. This is achieved
|
||||
//! using a subset of the other signers know here as `helpers`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{frost::Identifier, Ciphersuite, CryptoRng, Field, Group, RngCore, Scalar};
|
||||
|
||||
use super::{generate_coefficients, SecretShare, SigningShare, VerifiableSecretSharingCommitment};
|
||||
|
||||
/// Step 1 of RTS.
|
||||
///
|
||||
/// Generates the "delta" values from `helper_i` to help `participant` recover their share
|
||||
/// where `helpers` contains the identifiers of all the helpers (including `helper_i`), and `share_i`
|
||||
/// is the share of `helper_i`.
|
||||
///
|
||||
/// Returns a HashMap mapping which value should be sent to which participant.
|
||||
pub fn repair_share_step_1<C: Ciphersuite, R: RngCore + CryptoRng>(
|
||||
helpers: &[Identifier<C>],
|
||||
share_i: &SecretShare<C>,
|
||||
rng: &mut R,
|
||||
participant: Identifier<C>,
|
||||
) -> HashMap<Identifier<C>, Scalar<C>> {
|
||||
let rand_val: Vec<Scalar<C>> = generate_coefficients::<C, R>(helpers.len() - 1, rng);
|
||||
|
||||
compute_last_random_value(helpers, share_i, &rand_val, participant)
|
||||
}
|
||||
|
||||
/// Compute the last delta value given the (generated uniformly at random) remaining ones
|
||||
/// since they all must add up to `zeta_i * share_i`.
|
||||
///
|
||||
/// Returns a HashMap mapping which value should be sent to which participant.
|
||||
fn compute_last_random_value<C: Ciphersuite>(
|
||||
helpers: &[Identifier<C>],
|
||||
share_i: &SecretShare<C>,
|
||||
random_values: &Vec<Scalar<C>>,
|
||||
participant: Identifier<C>,
|
||||
) -> HashMap<Identifier<C>, Scalar<C>> {
|
||||
// Calculate Lagrange Coefficient for helper_i
|
||||
let zeta_i = compute_lagrange_coefficient(helpers, participant, share_i.identifier);
|
||||
|
||||
let lhs = zeta_i * share_i.value.0;
|
||||
|
||||
let mut out: HashMap<Identifier<C>, Scalar<C>> = helpers
|
||||
.iter()
|
||||
.copied()
|
||||
.zip(random_values.iter().copied())
|
||||
.collect();
|
||||
|
||||
let mut sum_i_deltas = <<C::Group as Group>::Field>::zero();
|
||||
|
||||
for v in random_values {
|
||||
sum_i_deltas = sum_i_deltas + *v;
|
||||
}
|
||||
|
||||
out.insert(helpers[helpers.len() - 1], lhs - sum_i_deltas);
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
/// Compute the i-th Lagrange coefficient evaluated at `participant`, i.e.
|
||||
/// computes `zeta_i` such that f(participant) is the sum of all `zeta_i * share_i`
|
||||
/// for each `i` in `helpers`.
|
||||
pub fn compute_lagrange_coefficient<C: Ciphersuite>(
|
||||
helpers: &[Identifier<C>],
|
||||
participant: Identifier<C>,
|
||||
helper_i: Identifier<C>,
|
||||
) -> Scalar<C> {
|
||||
let mut num = <<C::Group as Group>::Field>::one();
|
||||
let mut den = <<C::Group as Group>::Field>::one();
|
||||
|
||||
for j in helpers.iter() {
|
||||
if helper_i == *j {
|
||||
continue;
|
||||
}
|
||||
|
||||
num *= participant - *j;
|
||||
den *= helper_i - *j;
|
||||
}
|
||||
|
||||
num * <<C::Group as Group>::Field>::invert(&den).unwrap()
|
||||
}
|
||||
|
||||
/// Communication round
|
||||
///
|
||||
/// `helper_i` sends 1 `delta_j` to all other helpers (j)
|
||||
/// `helper_i` retains 1 `delta_j`
|
||||
|
||||
/// Step 2 of RTS.
|
||||
///
|
||||
/// Generates the `sigma` values from all `deltas` received from `helpers`
|
||||
/// to help `participant` recover their share.
|
||||
/// `sigma` is the sum of all received `delta` and the `delta_i` generated for `helper_i`.
|
||||
///
|
||||
/// Returns a scalar
|
||||
pub fn repair_share_step_2<C: Ciphersuite>(deltas_j: &[Scalar<C>]) -> Scalar<C> {
|
||||
let mut sigma_j = <<C::Group as Group>::Field>::zero();
|
||||
|
||||
for d in deltas_j {
|
||||
sigma_j = sigma_j + *d;
|
||||
}
|
||||
|
||||
sigma_j
|
||||
}
|
||||
|
||||
/// Communication round
|
||||
///
|
||||
/// `helper_j` sends 1 `sigma_j` to the `participant` repairing their share.
|
||||
|
||||
/// Step 3 of RTS
|
||||
///
|
||||
/// The `participant` sums all `sigma_j` received to compute the `share`. The `SecretShare`
|
||||
/// is made up of the `identifier`and `commitment` of the `participant` as well as the
|
||||
/// `value` which is the `SigningShare`.
|
||||
pub fn repair_share_step_3<C: Ciphersuite>(
|
||||
sigmas: &[Scalar<C>],
|
||||
identifier: Identifier<C>,
|
||||
commitment: &VerifiableSecretSharingCommitment<C>,
|
||||
) -> SecretShare<C> {
|
||||
let mut share = <<C::Group as Group>::Field>::zero();
|
||||
|
||||
for s in sigmas {
|
||||
share = share + *s;
|
||||
}
|
||||
|
||||
SecretShare {
|
||||
identifier,
|
||||
value: SigningShare(share),
|
||||
commitment: commitment.clone(),
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ use crate::Ciphersuite;
|
|||
|
||||
pub mod batch;
|
||||
pub mod proptests;
|
||||
pub mod repairable;
|
||||
pub mod vectors;
|
||||
|
||||
/// Test share generation with a Ciphersuite
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
//! Test for Repairable Threshold Scheme
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use debugless_unwrap::DebuglessUnwrap;
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
frost::{
|
||||
self,
|
||||
keys::{
|
||||
repairable::{
|
||||
compute_lagrange_coefficient, repair_share_step_1, repair_share_step_2,
|
||||
repair_share_step_3,
|
||||
},
|
||||
PublicKeyPackage, SecretShare, SigningShare,
|
||||
},
|
||||
Identifier,
|
||||
},
|
||||
Ciphersuite, Field, Group, Scalar,
|
||||
};
|
||||
|
||||
/// We want to test that recover share matches the original share
|
||||
pub fn check_rts<C: Ciphersuite, R: RngCore + CryptoRng>(mut rng: R) {
|
||||
// Compute shares
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Key generation
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let max_signers = 5;
|
||||
let min_signers = 3;
|
||||
let (shares, _pubkeys): (HashMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>) =
|
||||
frost::keys::keygen_with_dealer(max_signers, min_signers, &mut rng).unwrap();
|
||||
|
||||
// Try to recover a share
|
||||
|
||||
// Signer 2 will lose their share
|
||||
// Signer 1, 4 and 5 will help signer 2 to recover their share
|
||||
|
||||
let helper_1 = &shares[&Identifier::try_from(1).unwrap()];
|
||||
let helper_4 = &shares[&Identifier::try_from(4).unwrap()];
|
||||
let helper_5 = &shares[&Identifier::try_from(5).unwrap()];
|
||||
let participant = &shares[&Identifier::try_from(2).unwrap()];
|
||||
|
||||
let helpers: [Identifier<C>; 3] = [
|
||||
helper_1.identifier,
|
||||
helper_4.identifier,
|
||||
helper_5.identifier,
|
||||
];
|
||||
|
||||
// Each helper generates random values for each helper
|
||||
|
||||
let helper_1_deltas = repair_share_step_1(&helpers, helper_1, &mut rng, participant.identifier);
|
||||
let helper_4_deltas = repair_share_step_1(&helpers, helper_4, &mut rng, participant.identifier);
|
||||
let helper_5_deltas = repair_share_step_1(&helpers, helper_5, &mut rng, participant.identifier);
|
||||
|
||||
// Each helper calculates their sigma from the random values received from the other helpers
|
||||
|
||||
let helper_1_sigma: Scalar<C> = repair_share_step_2::<C>(&[
|
||||
helper_1_deltas[&helpers[0]],
|
||||
helper_4_deltas[&helpers[0]],
|
||||
helper_5_deltas[&helpers[0]],
|
||||
]);
|
||||
let helper_4_sigma: Scalar<C> = repair_share_step_2::<C>(&[
|
||||
helper_1_deltas[&helpers[1]],
|
||||
helper_4_deltas[&helpers[1]],
|
||||
helper_5_deltas[&helpers[1]],
|
||||
]);
|
||||
let helper_5_sigma: Scalar<C> = repair_share_step_2::<C>(&[
|
||||
helper_1_deltas[&helpers[2]],
|
||||
helper_4_deltas[&helpers[2]],
|
||||
helper_5_deltas[&helpers[2]],
|
||||
]);
|
||||
|
||||
// The participant wishing to recover their share sums the sigmas sent from all helpers
|
||||
|
||||
let participant_recovered_share = repair_share_step_3(
|
||||
&[helper_1_sigma, helper_4_sigma, helper_5_sigma],
|
||||
participant.identifier,
|
||||
&participant.commitment,
|
||||
);
|
||||
|
||||
// TODO: assert on commitment equality as well once updates have been made to VerifiableSecretSharingCommitment
|
||||
assert!(participant.secret() == participant_recovered_share.secret())
|
||||
}
|
||||
|
||||
fn generate_scalar_from_byte_string<C: Ciphersuite>(
|
||||
bs: &str,
|
||||
) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
|
||||
let decoded = hex::decode(bs).unwrap();
|
||||
let out = <<C::Group as Group>::Field>::deserialize(&decoded.try_into().debugless_unwrap());
|
||||
out.unwrap()
|
||||
}
|
||||
|
||||
/// Test repair_share_step_1
|
||||
pub fn check_repair_share_step_1<C: Ciphersuite, R: RngCore + CryptoRng>(mut rng: R) {
|
||||
// Compute shares
|
||||
|
||||
let max_signers = 5;
|
||||
let min_signers = 3;
|
||||
let (shares, _pubkeys): (HashMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>) =
|
||||
frost::keys::keygen_with_dealer(max_signers, min_signers, &mut rng).unwrap();
|
||||
|
||||
// Signer 2 will lose their share
|
||||
// Signers (helpers) 1, 4 and 5 will help signer 2 (participant) to recover their share
|
||||
|
||||
let helper_1 = &shares[&Identifier::try_from(1).unwrap()];
|
||||
let helper_4 = &shares[&Identifier::try_from(4).unwrap()];
|
||||
let helper_5 = &shares[&Identifier::try_from(5).unwrap()];
|
||||
let participant = &shares[&Identifier::try_from(2).unwrap()];
|
||||
|
||||
let helpers: [Identifier<C>; 3] = [
|
||||
helper_1.identifier,
|
||||
helper_4.identifier,
|
||||
helper_5.identifier,
|
||||
];
|
||||
|
||||
// Generate deltas for helper 4
|
||||
let deltas = repair_share_step_1(&helpers, helper_4, &mut rng, participant.identifier);
|
||||
|
||||
let lagrange_coefficient =
|
||||
compute_lagrange_coefficient(&helpers, participant.identifier, helpers[1]);
|
||||
|
||||
let mut rhs = <<C::Group as Group>::Field>::zero();
|
||||
for (_k, v) in deltas {
|
||||
rhs = rhs + v;
|
||||
}
|
||||
|
||||
let lhs = lagrange_coefficient * helper_4.value.0;
|
||||
|
||||
assert!(lhs == rhs)
|
||||
}
|
||||
|
||||
/// Test repair_share_step_2
|
||||
pub fn check_repair_share_step_2<C: Ciphersuite>(repair_share_helper_functions: &Value) {
|
||||
let values = &repair_share_helper_functions["scalar_generation"];
|
||||
|
||||
let value_1 =
|
||||
generate_scalar_from_byte_string::<C>(values["random_scalar_1"].as_str().unwrap());
|
||||
let value_2 =
|
||||
generate_scalar_from_byte_string::<C>(values["random_scalar_2"].as_str().unwrap());
|
||||
let value_3 =
|
||||
generate_scalar_from_byte_string::<C>(values["random_scalar_3"].as_str().unwrap());
|
||||
|
||||
let expected: Scalar<C> = repair_share_step_2::<C>(&[value_1, value_2, value_3]);
|
||||
|
||||
let actual: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar =
|
||||
generate_scalar_from_byte_string::<C>(values["random_scalar_sum"].as_str().unwrap());
|
||||
|
||||
assert!(actual == expected);
|
||||
}
|
||||
|
||||
/// Test repair_share
|
||||
pub fn check_repair_share_step_3<C: Ciphersuite, R: RngCore + CryptoRng>(
|
||||
mut rng: R,
|
||||
repair_share_helper_functions: &Value,
|
||||
) {
|
||||
// Generate shares
|
||||
let max_signers = 5;
|
||||
let min_signers = 3;
|
||||
let (shares, _pubkeys): (HashMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>) =
|
||||
frost::keys::keygen_with_dealer(max_signers, min_signers, &mut rng).unwrap();
|
||||
|
||||
let sigmas: &Value = &repair_share_helper_functions["sigma_generation"];
|
||||
|
||||
let sigma_1 = generate_scalar_from_byte_string::<C>(sigmas["sigma_1"].as_str().unwrap());
|
||||
let sigma_2 = generate_scalar_from_byte_string::<C>(sigmas["sigma_2"].as_str().unwrap());
|
||||
let sigma_3 = generate_scalar_from_byte_string::<C>(sigmas["sigma_3"].as_str().unwrap());
|
||||
let sigma_4 = generate_scalar_from_byte_string::<C>(sigmas["sigma_4"].as_str().unwrap());
|
||||
|
||||
let commitment = (shares[&Identifier::try_from(1).unwrap()].commitment).clone();
|
||||
|
||||
let expected = repair_share_step_3::<C>(
|
||||
&[sigma_1, sigma_2, sigma_3, sigma_4],
|
||||
Identifier::try_from(2).unwrap(),
|
||||
&commitment,
|
||||
);
|
||||
|
||||
let actual_sigma: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar =
|
||||
generate_scalar_from_byte_string::<C>(sigmas["sigma_sum"].as_str().unwrap());
|
||||
let actual: SecretShare<C> = SecretShare {
|
||||
identifier: Identifier::try_from(2).unwrap(),
|
||||
value: SigningShare(actual_sigma),
|
||||
commitment,
|
||||
};
|
||||
|
||||
assert!(actual.value == expected.value);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/// Repairable Threshold Scheme
|
||||
|
||||
#![doc = include_str!("../../repairable.md")]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{frost::Identifier, Ciphersuite, CryptoRng, Field, Group, RngCore, Scalar};
|
||||
|
||||
use super::{SecretShare};
|
||||
|
||||
/// Generate random values for each helper - 1 for use in computing the value for the final helper
|
||||
|
||||
pub fn repair_share_step_1<R: RngCore + CryptoRng>(
|
||||
helpers: &[Identifier<C>],
|
||||
share_i: &SecretShare<C>,
|
||||
zeta_i: Scalar<C>,
|
||||
rng: &mut R,
|
||||
) -> HashMap<Identifier<C>, Scalar<C>> {
|
||||
frost::keys::repairable::repair_share_step_1(identifier, max_signers, min_signers, &mut rng)
|
||||
}
|
||||
|
||||
/// # Communication round:
|
||||
/// # Helper i sends deltas_i[j] to helper j
|
||||
|
||||
/// # deltas_j: values received by j in the communication round
|
||||
/// # Output: sigma_j
|
||||
|
||||
pub fn repair_share_step_2<C: Ciphersuite>(deltas_j: &[Scalar<C>]) -> Scalar<C> {
|
||||
frost::keys::repairable::repair_share_step_2(deltas_j)
|
||||
}
|
||||
|
||||
/// # Communication round
|
||||
/// # Helper j sends sigma_j to signer r
|
||||
|
||||
/// # sigmas: all sigma_j received from each helper j
|
||||
/// # Output: share_r: r's secret share
|
||||
|
||||
pub fn repair_share_step_3<C: Ciphersuite>(
|
||||
sigmas: &[Scalar<C>],
|
||||
identifier: Identifier<C>,
|
||||
commitment: &VerifiableSecretSharingCommitment<C>,
|
||||
) -> SecretShare<C> {
|
||||
frost::keys::repairable::repair_share(sigmas, identifier, commitment)
|
||||
}
|
|
@ -2,7 +2,9 @@ use frost_ed25519::*;
|
|||
|
||||
use curve25519_dalek::{edwards::EdwardsPoint, traits::Identity};
|
||||
use ed25519_dalek::Verifier;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::thread_rng;
|
||||
use serde_json::Value;
|
||||
|
||||
fn verify_signature(
|
||||
msg: &[u8],
|
||||
|
@ -84,3 +86,36 @@ fn check_deserialize_non_prime_order() {
|
|||
let r = <Ed25519Sha512 as Ciphersuite>::Group::deserialize(&encoded_point);
|
||||
assert_eq!(r, Err(GroupError::InvalidNonPrimeOrderElement));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_1() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_repair_share_step_1::<Ed25519Sha512, _>(rng);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref REPAIR_SHARE: Value =
|
||||
serde_json::from_str(include_str!("repair-share.json").trim()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_2() {
|
||||
frost_core::tests::repairable::check_repair_share_step_2::<Ed25519Sha512>(&REPAIR_SHARE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share() {
|
||||
let rng = thread_rng();
|
||||
frost_core::tests::repairable::check_repair_share_step_3::<Ed25519Sha512, _>(
|
||||
rng,
|
||||
&REPAIR_SHARE,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_rts() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_rts::<Ed25519Sha512, _>(rng);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"scalar_generation": {
|
||||
"random_scalar_1": "1847f6c4a85096e5dbc9e200c9691c5164f8e276d32d4a54ebaf4275474a1403",
|
||||
"random_scalar_2": "eac5595269d108812eaa865bf62c703a2c128a61fa3bd4dc837b9314bc515204",
|
||||
"random_scalar_3": "5b3b6084e41c273a39a8d9bbbd87fbcd626c07030142bf78c6c91247bf175700",
|
||||
"random_scalar_sum": "5d48b09bf63ec6a0431c43187d1e8859f37674dbceabdda935f5e8d0c2b3bd07"
|
||||
},
|
||||
"sigma_generation": {
|
||||
"sigma_1": "ec3aa83140065181d75b746bfd6bbbbaf212bdfbb3a91670f924d1ca899cbc0c",
|
||||
"sigma_2": "5dd288d659e0a2dd3ef7523a9cc4f80f4a7f919e9980005c7fbec0961d3fb500",
|
||||
"sigma_3": "3e62e7461db9ca1ed2f1549a8114bbc87fa9242ce0012ed3f9ac9dcf23f4c30a",
|
||||
"sigma_4": "684c44e7aba416a1982a8db8ec2a3095f5cc6a3f958a4716b69ae76524dd7200",
|
||||
"sigma_sum": "02e866d948e1c2c6aad2b1552976c013b208de05c3b68cb5282b1797efaca808"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/// Repairable Threshold Scheme
|
||||
|
||||
#![doc = include_str!("../../repairable.md")]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{frost::Identifier, Ciphersuite, CryptoRng, Field, Group, RngCore, Scalar};
|
||||
|
||||
use super::{SecretShare};
|
||||
|
||||
/// Generate random values for each helper - 1 for use in computing the value for the final helper
|
||||
|
||||
pub fn repair_share_step_1<R: RngCore + CryptoRng>(
|
||||
helpers: &[Identifier<C>],
|
||||
share_i: &SecretShare<C>,
|
||||
zeta_i: Scalar<C>,
|
||||
rng: &mut R,
|
||||
) -> HashMap<Identifier<C>, Scalar<C>> {
|
||||
frost::keys::repairable::repair_share_step_1(identifier, max_signers, min_signers, &mut rng)
|
||||
}
|
||||
|
||||
/// # Communication round:
|
||||
/// # Helper i sends deltas_i[j] to helper j
|
||||
|
||||
/// # deltas_j: values received by j in the communication round
|
||||
/// # Output: sigma_j
|
||||
|
||||
pub fn repair_share_step_2<C: Ciphersuite>(deltas_j: &[Scalar<C>]) -> Scalar<C> {
|
||||
frost::keys::repairable::repair_share_step_2(deltas_j)
|
||||
}
|
||||
|
||||
/// # Communication round
|
||||
/// # Helper j sends sigma_j to signer r
|
||||
|
||||
/// # sigmas: all sigma_j received from each helper j
|
||||
/// # Output: share_r: r's secret share
|
||||
|
||||
pub fn repair_share_step_3<C: Ciphersuite>(
|
||||
sigmas: &[Scalar<C>],
|
||||
identifier: Identifier<C>,
|
||||
commitment: &VerifiableSecretSharingCommitment<C>,
|
||||
) -> SecretShare<C> {
|
||||
frost::keys::repairable::repair_share(sigmas, identifier, commitment)
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
use ed448_goldilocks::curve::ExtendedPoint;
|
||||
|
||||
use frost_ed448::*;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::thread_rng;
|
||||
use serde_json::Value;
|
||||
|
||||
#[test]
|
||||
fn check_sign_with_dealer() {
|
||||
|
@ -73,3 +75,36 @@ fn check_deserialize_non_prime_order() {
|
|||
let r = <Ed448Shake256 as Ciphersuite>::Group::deserialize(&encoded_point);
|
||||
assert_eq!(r, Err(GroupError::InvalidNonPrimeOrderElement));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_1() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_repair_share_step_1::<Ed448Shake256, _>(rng);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref REPAIR_SHARE: Value =
|
||||
serde_json::from_str(include_str!("repair-share.json").trim()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_2() {
|
||||
frost_core::tests::repairable::check_repair_share_step_2::<Ed448Shake256>(&REPAIR_SHARE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share() {
|
||||
let rng = thread_rng();
|
||||
frost_core::tests::repairable::check_repair_share_step_3::<Ed448Shake256, _>(
|
||||
rng,
|
||||
&REPAIR_SHARE,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_rts() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_rts::<Ed448Shake256, _>(rng);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"scalar_generation": {
|
||||
"random_scalar_1": "eb544ffc1486f87effb0edb05612d8a7f86f78e78fedbe0e12245dc42058c207c40fcf7bcc1aeb45e7d3e1432029749aa0a952d657fec40c00",
|
||||
"random_scalar_2": "f2c074dad7fd1b69338fb88a1b5283b4612eba895139d790914645f5f394013033bec754b83da4e841bd0ca5a4b8a4937fa08bdcc0a5711300",
|
||||
"random_scalar_3": "7bd09ea1e62b16132a4a96afc427a24055ff5b8b6d3e0e4921753968d271bcdfb5e4c093d8a74233e6e95ca8fc0922c63bb4ac3ba913da3800",
|
||||
"random_scalar_sum": "65a10acd40edb1d707fb765dc4c9907b1f67b84d058a5524dbbb11a5e75e8017adb257645d00d2610f7b4b91c1eb3af45bfe8aeec1b7101900"
|
||||
},
|
||||
"sigma_generation": {
|
||||
"sigma_1": "aec016b902d5ba5d3d9ddcff116cbb7cd836c3e88f247125eaf0a37b066e5f26dfa1b0e23e700d7abba22be0ea4c8e862846d0bb3b94df0900",
|
||||
"sigma_2": "43c4a604ac2d53d0255afea625e72e0de85a7b9972e62574ef67b418f946fa4e27df04f80a7258daa64f7304f8c1eebd85302bde9742a81400",
|
||||
"sigma_3": "cfc940c8fc206b6770c399c1de1e1dc6bab542ae83b95fd4d6e41ef6bba68c5c499aa7d77032f48f10698125bcf8d374ad441c834f9a4b0500",
|
||||
"sigma_4": "7a74c45ed0c72d567bc1b70c5f22bb64a7cf5426371f5570da6a4dc897a03f78942e4c364e49dc1854b638e953bbafb35509a23132519c3100",
|
||||
"sigma_sum": "477e6a39e9282ec8f9ec66e702d2559392e0ffa77308fd19a184fad553fc254ae449a9e8085e36fdc61159f3f2c2006db1c4b94e55c26f1500"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/// Repairable Threshold Scheme
|
||||
|
||||
#![doc = include_str!("../../repairable.md")]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{frost::Identifier, Ciphersuite, CryptoRng, Field, Group, RngCore, Scalar};
|
||||
|
||||
use super::{SecretShare};
|
||||
|
||||
/// Generate random values for each helper - 1 for use in computing the value for the final helper
|
||||
|
||||
pub fn repair_share_step_1<R: RngCore + CryptoRng>(
|
||||
helpers: &[Identifier<C>],
|
||||
share_i: &SecretShare<C>,
|
||||
zeta_i: Scalar<C>,
|
||||
rng: &mut R,
|
||||
) -> HashMap<Identifier<C>, Scalar<C>> {
|
||||
frost::keys::repairable::repair_share_step_1(identifier, max_signers, min_signers, &mut rng)
|
||||
}
|
||||
|
||||
/// # Communication round:
|
||||
/// # Helper i sends deltas_i[j] to helper j
|
||||
|
||||
/// # deltas_j: values received by j in the communication round
|
||||
/// # Output: sigma_j
|
||||
|
||||
pub fn repair_share_step_2<C: Ciphersuite>(deltas_j: &[Scalar<C>]) -> Scalar<C> {
|
||||
frost::keys::repairable::repair_share_step_2(deltas_j)
|
||||
}
|
||||
|
||||
/// # Communication round
|
||||
/// # Helper j sends sigma_j to signer r
|
||||
|
||||
/// # sigmas: all sigma_j received from each helper j
|
||||
/// # Output: share_r: r's secret share
|
||||
|
||||
pub fn repair_share_step_3<C: Ciphersuite>(
|
||||
sigmas: &[Scalar<C>],
|
||||
identifier: Identifier<C>,
|
||||
commitment: &VerifiableSecretSharingCommitment<C>,
|
||||
) -> SecretShare<C> {
|
||||
frost::keys::repairable::repair_share(sigmas, identifier, commitment)
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
use frost_p256::*;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::thread_rng;
|
||||
use serde_json::Value;
|
||||
|
||||
#[test]
|
||||
fn check_sign_with_dealer() {
|
||||
|
@ -64,3 +66,33 @@ fn check_deserialize_non_canonical() {
|
|||
let r = <P256Sha256 as Ciphersuite>::Group::deserialize(&encoded_point);
|
||||
assert_eq!(r, Err(GroupError::MalformedElement));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_1() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_repair_share_step_1::<P256Sha256, _>(rng);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref REPAIR_SHARE: Value =
|
||||
serde_json::from_str(include_str!("repair-share.json").trim()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_2() {
|
||||
frost_core::tests::repairable::check_repair_share_step_2::<P256Sha256>(&REPAIR_SHARE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share() {
|
||||
let rng = thread_rng();
|
||||
frost_core::tests::repairable::check_repair_share_step_3::<P256Sha256, _>(rng, &REPAIR_SHARE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_rts() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_rts::<P256Sha256, _>(rng);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"scalar_generation": {
|
||||
"random_scalar_1": "72deefbbf904c44fe6bb41ad8fcd23e6de2bd950aa2bdd03a8d84fcf29a86e21",
|
||||
"random_scalar_2": "63d3c1867568bcf26c2c5525cbe2af1f689adfb0f7c8c2e769c1f8bca37e0e8f",
|
||||
"random_scalar_3": "90a1e9902329edc21bd8c15ceafa901ac028a543b4d06011667a29dfc377e5dd",
|
||||
"random_scalar_sum": "67549ad391976f036ec0583046aa63214a086397afad6177855aa7a8943b3d3c"
|
||||
},
|
||||
"sigma_generation": {
|
||||
"sigma_1": "6234563e6c285de9e50569948c4648ef8205294a18f994a8f61e8c9f92c1b194",
|
||||
"sigma_2": "0c9f57342d4f20f05b3c61ac049230cad852ab541ef46394778aff6e7ff55700",
|
||||
"sigma_3": "1b50eb6a1b27bfbed21076913ca2892bc35a8be1c9f61e2cfa2e9c708869c049",
|
||||
"sigma_4": "44260f9f457d96bd0dcdcd9b83c45231bca28ecc5ab52dee9cf59f6b361c520c",
|
||||
"sigma_sum": "ce4aa87bfa1cd55620200f6d513f5517da54ef4c5c99445904cdc7e9d13d1ae9"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/// Repairable Threshold Scheme
|
||||
|
||||
#![doc = include_str!("../../repairable.md")]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{frost::Identifier, Ciphersuite, CryptoRng, Field, Group, RngCore, Scalar};
|
||||
|
||||
use super::{SecretShare};
|
||||
|
||||
/// Generate random values for each helper - 1 for use in computing the value for the final helper
|
||||
|
||||
pub fn repair_share_step_1<R: RngCore + CryptoRng>(
|
||||
helpers: &[Identifier<C>],
|
||||
share_i: &SecretShare<C>,
|
||||
zeta_i: Scalar<C>,
|
||||
rng: &mut R,
|
||||
) -> HashMap<Identifier<C>, Scalar<C>> {
|
||||
frost::keys::repairable::repair_share_step_1(identifier, max_signers, min_signers, &mut rng)
|
||||
}
|
||||
|
||||
/// # Communication round:
|
||||
/// # Helper i sends deltas_i[j] to helper j
|
||||
|
||||
/// # deltas_j: values received by j in the communication round
|
||||
/// # Output: sigma_j
|
||||
|
||||
pub fn repair_share_step_2<C: Ciphersuite>(deltas_j: &[Scalar<C>]) -> Scalar<C> {
|
||||
frost::keys::repairable::repair_share_step_2(deltas_j)
|
||||
}
|
||||
|
||||
/// # Communication round
|
||||
/// # Helper j sends sigma_j to signer r
|
||||
|
||||
/// # sigmas: all sigma_j received from each helper j
|
||||
/// # Output: share_r: r's secret share
|
||||
|
||||
pub fn repair_share_step_3<C: Ciphersuite>(
|
||||
sigmas: &[Scalar<C>],
|
||||
identifier: Identifier<C>,
|
||||
commitment: &VerifiableSecretSharingCommitment<C>,
|
||||
) -> SecretShare<C> {
|
||||
frost::keys::repairable::repair_share(sigmas, identifier, commitment)
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity};
|
||||
use frost_ristretto255::*;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::thread_rng;
|
||||
use serde_json::Value;
|
||||
|
||||
#[test]
|
||||
fn check_sign_with_dealer() {
|
||||
|
@ -37,3 +39,36 @@ fn check_deserialize_identity() {
|
|||
let r = <Ristretto255Sha512 as Ciphersuite>::Group::deserialize(&encoded_identity);
|
||||
assert_eq!(r, Err(GroupError::InvalidIdentityElement));
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref REPAIR_SHARE: Value =
|
||||
serde_json::from_str(include_str!("repair-share.json").trim()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_1() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_repair_share_step_1::<Ristretto255Sha512, _>(rng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_2() {
|
||||
frost_core::tests::repairable::check_repair_share_step_2::<Ristretto255Sha512>(&REPAIR_SHARE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_3() {
|
||||
let rng = thread_rng();
|
||||
frost_core::tests::repairable::check_repair_share_step_3::<Ristretto255Sha512, _>(
|
||||
rng,
|
||||
&REPAIR_SHARE,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_rts() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_rts::<Ristretto255Sha512, _>(rng);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"scalar_generation": {
|
||||
"random_scalar_1": "7e835f4c5453aea47a09e3925bfa23876de6fc9f92e6a7f8f1b45fe273fb850e",
|
||||
"random_scalar_2": "d79cbd35ae36865692f2f31f9ab6fa9109757accb18f10b416a6c99828b82707",
|
||||
"random_scalar_3": "73398badf5e53422d721e5acf901be840dbacb7c0c644cb171bd169df360550d",
|
||||
"random_scalar_sum": "eeb1bc75c3a9446d37e4cc1932bf1e74841543e950da045e7a18401890140303"
|
||||
},
|
||||
"sigma_generation": {
|
||||
"sigma_1": "19280c3694fc2881346c73fa9024cf3b710d1bc4651b01ac47e982a0c13ef004",
|
||||
"sigma_2": "bb8e111c18df8ad1af6710bb5845ff510a96cc37ceb99079cabe635ba0d3dd08",
|
||||
"sigma_3": "e37d76cbcbc44c14ef38043bff3b2154467095f0a7c6922444a1f09e4d563f09",
|
||||
"sigma_4": "898ea31783f13def4fb0cd9d97d24a18adb48050ed8c7b2af24d246f45b28e0c",
|
||||
"sigma_sum": "661b4c7bc6cb19a676836648c3847cd06ec8fd3cc928a0744897fb09f51a9c03"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/// Repairable Threshold Scheme
|
||||
|
||||
#![doc = include_str!("../../repairable.md")]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{frost::Identifier, Ciphersuite, CryptoRng, Field, Group, RngCore, Scalar};
|
||||
|
||||
use super::{SecretShare};
|
||||
|
||||
/// Generate random values for each helper - 1 for use in computing the value for the final helper
|
||||
|
||||
pub fn repair_share_step_1<R: RngCore + CryptoRng>(
|
||||
helpers: &[Identifier<C>],
|
||||
share_i: &SecretShare<C>,
|
||||
zeta_i: Scalar<C>,
|
||||
rng: &mut R,
|
||||
) -> HashMap<Identifier<C>, Scalar<C>> {
|
||||
frost::keys::repairable::repair_share_step_1(identifier, max_signers, min_signers, &mut rng)
|
||||
}
|
||||
|
||||
/// # Communication round:
|
||||
/// # Helper i sends deltas_i[j] to helper j
|
||||
|
||||
/// # deltas_j: values received by j in the communication round
|
||||
/// # Output: sigma_j
|
||||
|
||||
pub fn repair_share_step_2<C: Ciphersuite>(deltas_j: &[Scalar<C>]) -> Scalar<C> {
|
||||
frost::keys::repairable::repair_share_step_2(deltas_j)
|
||||
}
|
||||
|
||||
/// # Communication round
|
||||
/// # Helper j sends sigma_j to signer r
|
||||
|
||||
/// # sigmas: all sigma_j received from each helper j
|
||||
/// # Output: share_r: r's secret share
|
||||
|
||||
pub fn repair_share_step_3<C: Ciphersuite>(
|
||||
sigmas: &[Scalar<C>],
|
||||
identifier: Identifier<C>,
|
||||
commitment: &VerifiableSecretSharingCommitment<C>,
|
||||
) -> SecretShare<C> {
|
||||
frost::keys::repairable::repair_share(sigmas, identifier, commitment)
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
use frost_secp256k1::*;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::thread_rng;
|
||||
use serde_json::Value;
|
||||
|
||||
#[test]
|
||||
fn check_sign_with_dealer() {
|
||||
|
@ -64,3 +66,36 @@ fn check_deserialize_non_canonical() {
|
|||
let r = <Secp256K1Sha256 as Ciphersuite>::Group::deserialize(&encoded_point);
|
||||
assert_eq!(r, Err(GroupError::MalformedElement));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_1() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_repair_share_step_1::<Secp256K1Sha256, _>(rng);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref REPAIR_SHARE: Value =
|
||||
serde_json::from_str(include_str!("repair-share.json").trim()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share_step_2() {
|
||||
frost_core::tests::repairable::check_repair_share_step_2::<Secp256K1Sha256>(&REPAIR_SHARE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_repair_share() {
|
||||
let rng = thread_rng();
|
||||
frost_core::tests::repairable::check_repair_share_step_3::<Secp256K1Sha256, _>(
|
||||
rng,
|
||||
&REPAIR_SHARE,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_rts() {
|
||||
let rng = thread_rng();
|
||||
|
||||
frost_core::tests::repairable::check_rts::<Secp256K1Sha256, _>(rng);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"scalar_generation": {
|
||||
"random_scalar_1": "1847f6c4a85096e5dbc9e200c9691c5164f8e276d32d4a54ebaf4275474a1403",
|
||||
"random_scalar_2": "eac5595269d108812eaa865bf62c703a2c128a61fa3bd4dc837b9314bc515204",
|
||||
"random_scalar_3": "5b3b6084e41c273a39a8d9bbbd87fbcd626c07030142bf78c6c91247bf175700",
|
||||
"random_scalar_sum": "5e48b09bf63dc6a1441d42187d1d885a38c896f51f633e6e76218944f27c7bc6"
|
||||
},
|
||||
"sigma_generation": {
|
||||
"sigma_1": "ec3aa83140065181d75b746bfd6bbbbaf212bdfbb3a91670f924d1ca899cbc0c",
|
||||
"sigma_2": "5dd288d659e0a2dd3ef7523a9cc4f80f4a7f919e9980005c7fbec0961d3fb500",
|
||||
"sigma_3": "3e62e7461db9ca1ed2f1549a8114bbc87fa9242ce0012ed3f9ac9dcf23f4c30a",
|
||||
"sigma_4": "684c44e7aba416a1982a8db8ec2a3095f5cc6a3f958a4716b69ae76524dd7200",
|
||||
"sigma_sum": "f0bc5d356344d51f816ea8fa076fa029f7590120136bec7c6958b9081f7864d5"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue