From cfa8c990aa166623d4c596f2a4eb5638ab8a8848 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Wed, 7 Feb 2024 13:26:06 +0100
Subject: [PATCH] refactor: avoid using crypto primitives directly, part 2
---
ferveo/src/api.rs | 8 +--
ferveo/src/dkg.rs | 25 +++++---
ferveo/src/lib.rs | 99 +++++++++++++++++------------
ferveo/src/pvss.rs | 94 +++++++++++++---------------
ferveo/src/refresh.rs | 141 ++++++++++++++++++++++++++++++++----------
5 files changed, 234 insertions(+), 133 deletions(-)
diff --git a/ferveo/src/api.rs b/ferveo/src/api.rs
index ad9d23b6..01c6f0ab 100644
--- a/ferveo/src/api.rs
+++ b/ferveo/src/api.rs
@@ -351,8 +351,8 @@ impl AggregatedTranscript {
self.0.make_decryption_share_simple_precomputed(
&ciphertext_header.0,
aad,
- &validator_keypair.decryption_key,
- dkg.0.me.share_index as usize,
+ validator_keypair,
+ dkg.0.me.share_index,
&dkg.0.domain_points(),
&dkg.0.pvss_params.g_inv(),
)
@@ -368,8 +368,8 @@ impl AggregatedTranscript {
let share = self.0.make_decryption_share_simple(
&ciphertext_header.0,
aad,
- &validator_keypair.decryption_key,
- dkg.0.me.share_index as usize,
+ validator_keypair,
+ dkg.0.me.share_index,
&dkg.0.pvss_params.g_inv(),
)?;
let domain_point = dkg.0.get_domain_point(dkg.0.me.share_index)?;
diff --git a/ferveo/src/dkg.rs b/ferveo/src/dkg.rs
index b309449e..bc4acdfd 100644
--- a/ferveo/src/dkg.rs
+++ b/ferveo/src/dkg.rs
@@ -11,8 +11,8 @@ use serde_with::serde_as;
use crate::{
aggregate, assert_no_share_duplicates, AggregatedPvss, Error,
- EthereumAddress, PubliclyVerifiableParams, PubliclyVerifiableSS, Result,
- Validator,
+ EthereumAddress, PrivateKeyShare, PubliclyVerifiableParams,
+ PubliclyVerifiableSS, Result, Validator,
};
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
@@ -216,13 +216,24 @@ impl PubliclyVerifiableDkg {
self.domain.elements().take(self.validators.len()).collect()
}
- /// `payload` is the content of the message
+ /// Return a private key for the share_index
+ pub fn get_private_key_share(
+ &self,
+ keypair: &ferveo_common::Keypair,
+ ) -> Result> {
+ // TODO: Use self.aggregate upon simplifying Message handling
+ let pvss_list = self.vss.values().cloned().collect::>();
+ aggregate(&pvss_list)
+ .unwrap()
+ .decrypt_private_key_share(keypair, self.me.share_index)
+ }
+
pub fn verify_message(
&self,
sender: &Validator,
- payload: &Message,
+ message: &Message,
) -> Result<()> {
- match payload {
+ match message {
Message::Deal(pvss)
if matches!(
self.state,
@@ -650,8 +661,8 @@ mod test_aggregation {
use crate::{dkg::*, test_common::*, DkgState, Message};
/// Test that if the security threshold is met, we can create a final key
- #[test_case(4,4; "number of validators equal to the number of shares")]
- #[test_case(4,6; "number of validators greater than the number of shares")]
+ #[test_case(4, 4; "number of validators equal to the number of shares")]
+ #[test_case(4, 6; "number of validators greater than the number of shares")]
fn test_aggregate(shares_num: u32, validators_num: u32) {
let security_threshold = shares_num - 1;
let (mut dkg, _) = setup_dealt_dkg_with_n_validators(
diff --git a/ferveo/src/lib.rs b/ferveo/src/lib.rs
index 0e9cc3ca..8ef4c8e7 100644
--- a/ferveo/src/lib.rs
+++ b/ferveo/src/lib.rs
@@ -171,8 +171,8 @@ mod test_dkg_full {
.make_decryption_share_simple(
ciphertext_header,
aad,
- &validator_keypair.decryption_key,
- validator.share_index as usize,
+ validator_keypair,
+ validator.share_index,
&dkg.pvss_params.g_inv(),
)
.unwrap()
@@ -280,8 +280,8 @@ mod test_dkg_full {
.make_decryption_share_simple_precomputed(
&ciphertext.header().unwrap(),
AAD,
- &validator_keypair.decryption_key,
- validator.share_index as usize,
+ validator_keypair,
+ validator.share_index,
&domain_points,
&dkg.pvss_params.g_inv(),
)
@@ -305,7 +305,8 @@ mod test_dkg_full {
assert_eq!(plaintext, MSG);
}
- #[test_case(4, 4; "number of validators equal to the number of shares")]
+ #[test_case(4, 4; "number of shares (validators) is a power of 2")]
+ #[test_case(7, 7; "number of shares (validators) is not a power of 2")]
#[test_case(4, 6; "number of validators greater than the number of shares")]
fn test_dkg_simple_tdec_share_verification(
shares_num: u32,
@@ -376,12 +377,21 @@ mod test_dkg_full {
));
}
- #[test]
- fn test_dkg_simple_tdec_share_recovery() {
+ #[test_case(4, 4; "number of shares (validators) is a power of 2")]
+ #[test_case(7, 7; "number of shares (validators) is not a power of 2")]
+ #[test_case(4, 6; "number of validators greater than the number of shares")]
+ fn test_dkg_simple_tdec_share_recovery(
+ shares_num: u32,
+ validators_num: u32,
+ ) {
let rng = &mut test_rng();
+ let security_threshold = shares_num / 2 + 1;
- let (dkg, validator_keypairs) =
- setup_dealt_dkg_with(SECURITY_THRESHOLD, SHARES_NUM);
+ let (dkg, validator_keypairs) = setup_dealt_dkg_with_n_validators(
+ security_threshold,
+ shares_num,
+ validators_num,
+ );
let public_key = &dkg.public_key();
let ciphertext = ferveo_tdec::encrypt::(
SecretBox::new(MSG.to_vec()),
@@ -400,6 +410,7 @@ mod test_dkg_full {
);
// Remove one participant from the contexts and all nested structure
+ // TODO: Improve by removing a random participant and/or adding test cases
let removed_validator_addr =
dkg.validators.keys().last().unwrap().clone();
let mut remaining_validators = dkg.validators.clone();
@@ -427,7 +438,7 @@ mod test_dkg_full {
&domain_points,
&dkg.pvss_params.h.into_affine(),
&x_r,
- dkg.dkg_params.security_threshold() as usize,
+ dkg.dkg_params.security_threshold(),
rng,
);
(v_addr.clone(), deltas_i)
@@ -451,19 +462,18 @@ mod test_dkg_full {
.collect();
// Each validator uses their decryption key to update their share
- let decryption_key = validator_keypairs
+ let validator_keypair = validator_keypairs
.get(validator.share_index as usize)
- .unwrap()
- .decryption_key;
+ .unwrap();
// Creates updated private key shares
- // TODO: Why not using dkg.aggregate()?
+ // TODO: Use self.aggregate upon simplifying Message handling
let pvss_list = dkg.vss.values().cloned().collect::>();
let pvss_aggregated = aggregate(&pvss_list).unwrap();
pvss_aggregated
.make_updated_private_key_share(
- &decryption_key,
- validator.share_index as usize,
+ validator_keypair,
+ validator.share_index,
updates_for_participant.as_slice(),
)
.unwrap()
@@ -488,7 +498,7 @@ mod test_dkg_full {
.iter()
.enumerate()
.map(|(share_index, validator_keypair)| {
- // TODO: Why not using dkg.aggregate()?
+ // TODO: Use self.aggregate upon simplifying Message handling
let pvss_list =
dkg.vss.values().cloned().collect::>();
let pvss_aggregated = aggregate(&pvss_list).unwrap();
@@ -496,8 +506,8 @@ mod test_dkg_full {
.make_decryption_share_simple(
&ciphertext.header().unwrap(),
AAD,
- &validator_keypair.decryption_key,
- share_index,
+ validator_keypair,
+ share_index as u32,
&dkg.pvss_params.g_inv(),
)
.unwrap()
@@ -509,7 +519,7 @@ mod test_dkg_full {
decryption_shares.push(
DecryptionShareSimple::create(
&new_validator_decryption_key,
- &recovered_key_share,
+ &recovered_key_share.0,
&ciphertext.header().unwrap(),
AAD,
&dkg.pvss_params.g_inv(),
@@ -518,14 +528,15 @@ mod test_dkg_full {
);
domain_points.push(x_r);
- assert_eq!(domain_points.len(), SHARES_NUM as usize);
- assert_eq!(decryption_shares.len(), SHARES_NUM as usize);
+ assert_eq!(domain_points.len(), validators_num as usize);
+ assert_eq!(decryption_shares.len(), validators_num as usize);
- // Maybe parametrize this test with [1..] and [..threshold]
- let domain_points = &domain_points[1..];
- let decryption_shares = &decryption_shares[1..];
- assert_eq!(domain_points.len(), SECURITY_THRESHOLD as usize);
- assert_eq!(decryption_shares.len(), SECURITY_THRESHOLD as usize);
+ // TODO: Maybe parametrize this test with [1..] and [..threshold]
+ let domain_points = &domain_points[..security_threshold as usize];
+ let decryption_shares =
+ &decryption_shares[..security_threshold as usize];
+ assert_eq!(domain_points.len(), security_threshold as usize);
+ assert_eq!(decryption_shares.len(), security_threshold as usize);
let lagrange = ferveo_tdec::prepare_combine_simple::(domain_points);
let new_shared_secret = ferveo_tdec::share_combine_simple::(
@@ -539,12 +550,21 @@ mod test_dkg_full {
);
}
- #[test]
- fn test_dkg_simple_tdec_share_refreshing() {
+ #[test_case(4, 4; "number of shares (validators) is a power of 2")]
+ #[test_case(7, 7; "number of shares (validators) is not a power of 2")]
+ #[test_case(4, 6; "number of validators greater than the number of shares")]
+ fn test_dkg_simple_tdec_share_refreshing(
+ shares_num: u32,
+ validators_num: u32,
+ ) {
let rng = &mut test_rng();
+ let security_threshold = shares_num / 2 + 1;
- let (dkg, validator_keypairs) =
- setup_dealt_dkg_with(SECURITY_THRESHOLD, SHARES_NUM);
+ let (dkg, validator_keypairs) = setup_dealt_dkg_with_n_validators(
+ security_threshold,
+ shares_num,
+ validators_num,
+ );
let public_key = &dkg.public_key();
let ciphertext = ferveo_tdec::encrypt::(
SecretBox::new(MSG.to_vec()),
@@ -571,7 +591,7 @@ mod test_dkg_full {
ShareRefreshUpdate::make_share_updates_for_refresh(
&dkg.domain_points(),
&dkg.pvss_params.h.into_affine(),
- dkg.dkg_params.security_threshold() as usize,
+ dkg.dkg_params.security_threshold(),
rng,
);
(v_addr.clone(), deltas_i)
@@ -598,19 +618,18 @@ mod test_dkg_full {
.collect();
// Each validator uses their decryption key to update their share
- let decryption_key = validator_keypairs
+ let validator_keypair = validator_keypairs
.get(validator.share_index as usize)
- .unwrap()
- .decryption_key;
+ .unwrap();
// Creates updated private key shares
- // TODO: Why not using dkg.aggregate()?
+ // TODO: Use self.aggregate upon simplifying Message handling
let pvss_list = dkg.vss.values().cloned().collect::>();
let pvss_aggregated = aggregate(&pvss_list).unwrap();
pvss_aggregated
.make_updated_private_key_share(
- &decryption_key,
- validator.share_index as usize,
+ validator_keypair,
+ validator.share_index,
updates_for_participant.as_slice(),
)
.unwrap()
@@ -640,10 +659,10 @@ mod test_dkg_full {
.collect();
let lagrange = ferveo_tdec::prepare_combine_simple::(
- &dkg.domain_points()[..SECURITY_THRESHOLD as usize],
+ &dkg.domain_points()[..security_threshold as usize],
);
let new_shared_secret = ferveo_tdec::share_combine_simple::(
- &decryption_shares[..SECURITY_THRESHOLD as usize],
+ &decryption_shares[..security_threshold as usize],
&lagrange,
);
diff --git a/ferveo/src/pvss.rs b/ferveo/src/pvss.rs
index 1d68622e..39919f9a 100644
--- a/ferveo/src/pvss.rs
+++ b/ferveo/src/pvss.rs
@@ -6,9 +6,9 @@ use ark_poly::{
polynomial::univariate::DensePolynomial, DenseUVPolynomial,
EvaluationDomain, Polynomial,
};
+use ferveo_common::Keypair;
use ferveo_tdec::{
- prepare_combine_simple, CiphertextHeader, DecryptionSharePrecomputed,
- DecryptionShareSimple,
+ CiphertextHeader, DecryptionSharePrecomputed, DecryptionShareSimple,
};
use itertools::Itertools;
use rand::RngCore;
@@ -24,6 +24,7 @@ use crate::{
};
/// These are the blinded evaluations of shares of a single random polynomial
+// TODO: Are these really blinded like in tdec or encrypted?
pub type ShareEncryptions = ::G2Affine;
/// Marker struct for unaggregated PVSS transcripts
@@ -302,82 +303,75 @@ impl PubliclyVerifiableSS {
pub fn decrypt_private_key_share(
&self,
- validator_decryption_key: &E::ScalarField,
- share_index: usize,
+ validator_keypair: &Keypair,
+ share_index: u32,
) -> Result> {
// Decrypt private key share https://nikkolasg.github.io/ferveo/pvss.html#validator-decryption-of-private-key-shares
- let private_key_share = self
- .shares
- .get(share_index)
- .ok_or(Error::InvalidShareIndex(share_index as u32))?
- .mul(
- validator_decryption_key
- .inverse()
- .expect("Validator decryption key must have an inverse"),
- )
- .into_affine();
- // TODO: Consider adding a from trait to simplify this conversion
let private_key_share =
- ferveo_tdec::PrivateKeyShare { private_key_share };
- Ok(PrivateKeyShare(private_key_share))
+ self.shares
+ .get(share_index as usize)
+ .ok_or(Error::InvalidShareIndex(share_index))?
+ .mul(
+ validator_keypair.decryption_key.inverse().expect(
+ "Validator decryption key must have an inverse",
+ ),
+ )
+ .into_affine();
+ Ok(PrivateKeyShare(ferveo_tdec::PrivateKeyShare {
+ private_key_share,
+ }))
}
+ /// Make a decryption share (simple variant) for a given ciphertext
+ /// With this method, we wrap the PrivateKeyShare method to avoid exposing the private key share
pub fn make_decryption_share_simple(
&self,
ciphertext: &CiphertextHeader,
aad: &[u8],
- validator_decryption_key: &E::ScalarField,
- share_index: usize,
+ validator_keypair: &Keypair,
+ share_index: u32,
g_inv: &E::G1Prepared,
) -> Result> {
- let private_key_share = self
- .decrypt_private_key_share(validator_decryption_key, share_index)?;
- DecryptionShareSimple::create(
- validator_decryption_key,
- &private_key_share.0,
- ciphertext,
- aad,
- g_inv,
- )
- .map_err(|e| e.into())
+ self.decrypt_private_key_share(validator_keypair, share_index)?
+ .make_decryption_share_simple(
+ ciphertext,
+ aad,
+ validator_keypair,
+ g_inv,
+ )
}
+ /// Make a decryption share (precomputed variant) for a given ciphertext
+ /// With this method, we wrap the PrivateKeyShare method to avoid exposing the private key share
pub fn make_decryption_share_simple_precomputed(
&self,
ciphertext_header: &CiphertextHeader,
aad: &[u8],
- validator_decryption_key: &E::ScalarField,
- share_index: usize,
+ validator_keypair: &Keypair,
+ share_index: u32,
domain_points: &[E::ScalarField],
g_inv: &E::G1Prepared,
) -> Result> {
- let private_key_share = self
- .decrypt_private_key_share(validator_decryption_key, share_index)?;
-
- // We use the `prepare_combine_simple` function to precompute the lagrange coefficients
- let lagrange_coeffs = prepare_combine_simple::(domain_points);
-
- DecryptionSharePrecomputed::new(
- share_index,
- validator_decryption_key,
- &private_key_share.0,
- ciphertext_header,
- aad,
- &lagrange_coeffs[share_index],
- g_inv,
- )
- .map_err(|e| e.into())
+ self.decrypt_private_key_share(validator_keypair, share_index)?
+ .make_decryption_share_simple_precomputed(
+ ciphertext_header,
+ aad,
+ validator_keypair,
+ share_index,
+ domain_points,
+ g_inv,
+ )
}
pub fn make_updated_private_key_share(
&self,
- validator_decryption_key: &E::ScalarField,
- share_index: usize,
+ validator_keypair: &Keypair,
+ share_index: u32,
share_updates: &[impl PrivateKeyShareUpdate],
) -> Result> {
// Retrieve the private key share and apply the updates
Ok(self
- .decrypt_private_key_share(validator_decryption_key, share_index)?
+ .decrypt_private_key_share(validator_keypair, share_index)?
.make_updated_key_share(share_updates))
}
}
diff --git a/ferveo/src/refresh.rs b/ferveo/src/refresh.rs
index 761481fa..126e281a 100644
--- a/ferveo/src/refresh.rs
+++ b/ferveo/src/refresh.rs
@@ -3,17 +3,31 @@ use std::{ops::Mul, usize};
use ark_ec::{pairing::Pairing, CurveGroup};
use ark_ff::Zero;
use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, Polynomial};
-use ferveo_tdec::lagrange_basis_at;
+use ferveo_common::Keypair;
+use ferveo_tdec::{
+ lagrange_basis_at, prepare_combine_simple, CiphertextHeader,
+ DecryptionSharePrecomputed, DecryptionShareSimple,
+};
use itertools::zip_eq;
use rand_core::RngCore;
use zeroize::ZeroizeOnDrop;
+use crate::{Error, Result};
+
+// TODO: Rename refresh.rs to key_share.rs?
+
type InnerPrivateKeyShare = ferveo_tdec::PrivateKeyShare;
/// Private key share held by a participant in the DKG protocol.
#[derive(Debug, Clone, PartialEq, Eq, ZeroizeOnDrop)]
pub struct PrivateKeyShare(pub InnerPrivateKeyShare);
+impl PrivateKeyShare {
+ pub fn new(private_key_share: InnerPrivateKeyShare) -> Self {
+ Self(private_key_share)
+ }
+}
+
impl PrivateKeyShare {
/// From PSS paper, section 4.2.3, (https://link.springer.com/content/pdf/10.1007/3-540-44750-4_27.pdf)
pub fn make_updated_key_share(
@@ -36,19 +50,64 @@ impl PrivateKeyShare {
x_r: &E::ScalarField,
domain_points: &[E::ScalarField],
updated_private_shares: &[UpdatedPrivateKeyShare],
- ) -> ferveo_tdec::PrivateKeyShare {
+ ) -> PrivateKeyShare {
// Interpolate new shares to recover y_r
let lagrange = lagrange_basis_at::(domain_points, x_r);
let prods = zip_eq(updated_private_shares, lagrange)
.map(|(y_j, l)| y_j.0.private_key_share.mul(l));
let y_r = prods.fold(E::G2::zero(), |acc, y_j| acc + y_j);
- ferveo_tdec::PrivateKeyShare {
+ PrivateKeyShare(ferveo_tdec::PrivateKeyShare {
private_key_share: y_r.into_affine(),
- }
+ })
+ }
+
+ pub fn make_decryption_share_simple(
+ &self,
+ ciphertext: &CiphertextHeader,
+ aad: &[u8],
+ validator_keypair: &Keypair,
+ g_inv: &E::G1Prepared,
+ ) -> Result> {
+ DecryptionShareSimple::create(
+ &validator_keypair.decryption_key,
+ &self.0,
+ ciphertext,
+ aad,
+ g_inv,
+ )
+ .map_err(|e| e.into())
+ }
+
+ pub fn make_decryption_share_simple_precomputed(
+ &self,
+ ciphertext_header: &CiphertextHeader,
+ aad: &[u8],
+ validator_keypair: &Keypair,
+ share_index: u32,
+ domain_points: &[E::ScalarField],
+ g_inv: &E::G1Prepared,
+ ) -> Result> {
+ // In precomputed variant, we offload the some of the decryption related computation to the server-side:
+ // We use the `prepare_combine_simple` function to precompute the lagrange coefficients
+ let lagrange_coeffs = prepare_combine_simple::(domain_points);
+ let lagrange_coeff = &lagrange_coeffs
+ .get(share_index as usize)
+ .ok_or(Error::InvalidShareIndex(share_index))?;
+ DecryptionSharePrecomputed::new(
+ share_index as usize,
+ &validator_keypair.decryption_key,
+ &self.0,
+ ciphertext_header,
+ aad,
+ lagrange_coeff,
+ g_inv,
+ )
+ .map_err(|e| e.into())
}
}
/// An updated private key share, resulting from an intermediate step in a share recovery or refresh operation.
+// TODO: After recovery, should we replace existing private key shares with updated ones?
#[derive(Debug, Clone, PartialEq, Eq, ZeroizeOnDrop)]
pub struct UpdatedPrivateKeyShare(InnerPrivateKeyShare);
@@ -88,7 +147,7 @@ impl ShareRecoveryUpdate {
domain_points: &[E::ScalarField],
h: &E::G2Affine,
x_r: &E::ScalarField,
- threshold: usize,
+ threshold: u32,
rng: &mut impl RngCore,
) -> Vec> {
// Update polynomial has root at x_r
@@ -120,7 +179,7 @@ impl ShareRefreshUpdate {
pub fn make_share_updates_for_refresh(
domain_points: &[E::ScalarField],
h: &E::G2Affine,
- threshold: usize,
+ threshold: u32,
rng: &mut impl RngCore,
) -> Vec> {
// Update polynomial has root at 0
@@ -147,7 +206,7 @@ fn prepare_share_updates_with_root(
domain_points: &[E::ScalarField],
h: &E::G2Affine,
root: &E::ScalarField,
- threshold: usize,
+ threshold: u32,
rng: &mut impl RngCore,
) -> Vec> {
// Generate a new random polynomial with defined root
@@ -168,12 +227,13 @@ fn prepare_share_updates_with_root(
/// Generate a random polynomial with a given root
fn make_random_polynomial_with_root(
- degree: usize,
+ degree: u32,
root: &E::ScalarField,
rng: &mut impl RngCore,
) -> DensePolynomial {
// [c_0, c_1, ..., c_{degree}] (Random polynomial)
- let mut poly = DensePolynomial::::rand(degree, rng);
+ let mut poly =
+ DensePolynomial::::rand(degree as usize, rng);
// [0, c_1, ... , c_{degree}] (We zeroize the free term)
poly[0] = E::ScalarField::zero();
@@ -184,7 +244,7 @@ fn make_random_polynomial_with_root(
// Evaluating the polynomial at the root should result in 0
debug_assert!(poly.evaluate(root) == E::ScalarField::zero());
- debug_assert!(poly.coeffs.len() == degree + 1);
+ debug_assert!(poly.coeffs.len() == (degree + 1) as usize);
poly
}
@@ -199,16 +259,19 @@ mod tests_refresh {
test_common::setup_simple, PrivateDecryptionContextSimple,
};
use rand_core::RngCore;
- use test_case::test_matrix;
+ use test_case::{test_case, test_matrix};
use crate::{
test_common::*, PrivateKeyShare, ShareRecoveryUpdate,
ShareRefreshUpdate, UpdatedPrivateKeyShare,
};
+ /// Using tdec test utilities here instead of PVSS to test the internals of the shared key recovery
+ // TODO: Can I fix that using combine_shared_secret?
+
fn make_updated_private_key_shares(
rng: &mut R,
- threshold: usize,
+ threshold: u32,
x_r: &Fr,
remaining_participants: &[PrivateDecryptionContextSimple],
) -> Vec> {
@@ -257,13 +320,20 @@ mod tests_refresh {
/// Ñ parties (where t <= Ñ <= N) jointly execute a "share recovery" algorithm, and the output is 1 new share.
/// The new share is intended to restore a previously existing share, e.g., due to loss or corruption.
- #[test_matrix([4, 7, 11, 16])]
- fn tdec_simple_variant_share_recovery_at_selected_point(shares_num: usize) {
+ #[test_case(4, 4; "number of shares (validators) is a power of 2")]
+ #[test_case(7, 7; "number of shares (validators) is not a power of 2")]
+ fn tdec_simple_variant_share_recovery_at_selected_point(
+ shares_num: u32,
+ _validators_num: u32,
+ ) {
let rng = &mut test_rng();
let security_threshold = shares_num * 2 / 3;
- let (_, _, mut contexts) =
- setup_simple::(security_threshold, shares_num, rng);
+ let (_, _, mut contexts) = setup_simple::(
+ security_threshold as usize,
+ shares_num as usize,
+ rng,
+ );
// Prepare participants
@@ -274,7 +344,8 @@ mod tests_refresh {
.last()
.unwrap()
.domain;
- let original_private_key_share = selected_participant.private_key_share;
+ let original_private_key_share =
+ PrivateKeyShare(selected_participant.private_key_share);
// Remove the selected participant from the contexts and all nested structures
let mut remaining_participants = contexts;
@@ -299,8 +370,8 @@ mod tests_refresh {
let new_private_key_share =
PrivateKeyShare::recover_share_from_updated_private_shares(
&x_r,
- &domain_points[..security_threshold],
- &updated_private_key_shares[..security_threshold],
+ &domain_points[..security_threshold as usize],
+ &updated_private_key_shares[..security_threshold as usize],
);
assert_eq!(new_private_key_share, original_private_key_share);
@@ -310,8 +381,9 @@ mod tests_refresh {
let incorrect_private_key_share =
PrivateKeyShare::recover_share_from_updated_private_shares(
&x_r,
- &domain_points[..(security_threshold - 1)],
- &updated_private_key_shares[..(security_threshold - 1)],
+ &domain_points[..(security_threshold - 1) as usize],
+ &updated_private_key_shares
+ [..(security_threshold - 1) as usize],
);
assert_ne!(incorrect_private_key_share, original_private_key_share);
@@ -319,13 +391,17 @@ mod tests_refresh {
/// Ñ parties (where t <= Ñ <= N) jointly execute a "share recovery" algorithm, and the output is 1 new share.
/// The new share is independent from the previously existing shares. We can use this to on-board a new participant into an existing cohort.
- #[test_matrix([4, 7, 11, 16])]
- fn tdec_simple_variant_share_recovery_at_random_point(shares_num: usize) {
+ #[test_case(4, 4; "number of shares (validators) is a power of 2")]
+ #[test_case(7, 7; "number of shares (validators) is not a power of 2")]
+ fn tdec_simple_variant_share_recovery_at_random_point(
+ shares_num: u32,
+ _validators_num: u32,
+ ) {
let rng = &mut test_rng();
let threshold = shares_num * 2 / 3;
let (_, shared_private_key, mut contexts) =
- setup_simple::(threshold, shares_num, rng);
+ setup_simple::(threshold as usize, shares_num as usize, rng);
// Prepare participants
@@ -358,8 +434,8 @@ mod tests_refresh {
let recovered_private_key_share =
PrivateKeyShare::recover_share_from_updated_private_shares(
&x_r,
- &domain_points[..threshold],
- &share_recovery_fragmetns[..threshold],
+ &domain_points[..threshold as usize],
+ &share_recovery_fragmetns[..threshold as usize],
);
let mut private_shares = contexts
@@ -370,7 +446,8 @@ mod tests_refresh {
// Finally, let's recreate the shared private key from some original shares and the recovered one
domain_points.push(x_r);
- private_shares.push(recovered_private_key_share);
+ private_shares.push(recovered_private_key_share.0.clone());
+
// This is a workaround for a type mismatch - We need to convert the private shares to updated private shares
// This is just to test that we are able to recover the shared private key from the updated private shares
let updated_private_key_shares = private_shares
@@ -382,11 +459,11 @@ mod tests_refresh {
let new_shared_private_key =
PrivateKeyShare::recover_share_from_updated_private_shares(
&ScalarField::zero(),
- &domain_points[start_from..],
- &updated_private_key_shares[start_from..],
+ &domain_points[start_from as usize..],
+ &updated_private_key_shares[start_from as usize..],
);
- assert_eq!(shared_private_key, new_shared_private_key);
+ assert_eq!(shared_private_key, new_shared_private_key.0);
}
/// Ñ parties (where t <= Ñ <= N) jointly execute a "share refresh" algorithm.
@@ -415,7 +492,7 @@ mod tests_refresh {
ShareRefreshUpdate::::make_share_updates_for_refresh(
domain_points,
&h,
- threshold,
+ threshold as u32,
rng,
);
(p.index, deltas_i)
@@ -447,6 +524,6 @@ mod tests_refresh {
&refreshed_shares[..threshold],
);
- assert_eq!(private_key_share, new_shared_private_key);
+ assert_eq!(private_key_share, new_shared_private_key.0);
}
}