-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add refresh shares with dealer functionality (#245)
- Loading branch information
1 parent
c205ef7
commit fff737d
Showing
18 changed files
with
793 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
//! Refresh Shares | ||
//! | ||
//! Implements the functionality to refresh a share. This requires the participation | ||
//! of all the remaining signers. This can be done using a Trusted Dealer or | ||
//! DKG (not yet implemented) | ||
|
||
use std::collections::BTreeMap; | ||
|
||
use crate::{ | ||
keys::{ | ||
generate_coefficients, generate_secret_shares, validate_num_of_signers, | ||
CoefficientCommitment, PublicKeyPackage, SigningKey, SigningShare, VerifyingShare, | ||
}, | ||
Ciphersuite, CryptoRng, Error, Field, Group, Identifier, RngCore, Scalar, | ||
}; | ||
|
||
use super::{SecretShare, VerifiableSecretSharingCommitment}; | ||
|
||
/// Refreshes shares using a trusted dealer | ||
pub fn refresh_shares_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>( | ||
old_shares: BTreeMap<Identifier<C>, SecretShare<C>>, | ||
old_pub_key_package: PublicKeyPackage<C>, | ||
max_signers: u16, | ||
min_signers: u16, | ||
identifiers: &[Identifier<C>], | ||
rng: &mut R, | ||
) -> Result<(BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>), Error<C>> { | ||
// Validate inputs | ||
|
||
if identifiers.len() != max_signers as usize { | ||
return Err(Error::IncorrectNumberOfIdentifiers); | ||
} | ||
|
||
validate_num_of_signers(min_signers, max_signers)?; | ||
|
||
// Build zero key shares | ||
|
||
let zero_key = SigningKey { | ||
scalar: <<C::Group as Group>::Field>::zero(), | ||
}; | ||
|
||
let coefficients = generate_coefficients::<C, R>(min_signers as usize - 1, rng); | ||
|
||
let zero_key_shares = generate_secret_shares( | ||
&zero_key, | ||
max_signers, | ||
min_signers, | ||
coefficients, | ||
identifiers, | ||
)?; | ||
|
||
// Build new shares and public key package | ||
|
||
let mut new_shares: BTreeMap<Identifier<C>, SecretShare<C>> = BTreeMap::new(); | ||
let mut verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>> = BTreeMap::new(); | ||
|
||
for share in zero_key_shares { | ||
let signer_public = SigningShare::into(share.signing_share); | ||
verifying_shares.insert(share.identifier, signer_public); | ||
|
||
let old_share = old_shares.get(&share.identifier); | ||
|
||
match old_share { | ||
Some(old_share) => new_shares.insert( | ||
share.identifier, | ||
add_secret_shares::<C>(share.clone(), old_share)?, | ||
), | ||
None => return Err(Error::UnknownIdentifier), | ||
}; | ||
} | ||
|
||
let pub_key_package = PublicKeyPackage::<C> { | ||
header: old_pub_key_package.header, | ||
verifying_shares, | ||
verifying_key: old_pub_key_package.verifying_key, | ||
}; | ||
|
||
Ok((new_shares, pub_key_package)) | ||
} | ||
|
||
fn add_secret_shares<C: Ciphersuite>( | ||
zero_share: SecretShare<C>, | ||
old_share: &SecretShare<C>, | ||
) -> Result<SecretShare<C>, Error<C>> { | ||
let signing_share: Scalar<C> = | ||
zero_share.signing_share.to_scalar() + old_share.signing_share.to_scalar(); | ||
|
||
let zero_commitments = zero_share.commitment.0; | ||
let old_commitments = old_share.commitment.0.clone(); | ||
|
||
let mut commitments: Vec<CoefficientCommitment<C>> = Vec::with_capacity(zero_commitments.len()); | ||
|
||
if old_commitments.len() >= zero_commitments.len() { | ||
for i in 0..zero_commitments.len() { | ||
if let (Some(zero_commitment), Some(old_commitment)) = | ||
(zero_commitments.get(i), old_commitments.get(i)) | ||
{ | ||
commitments.push(CoefficientCommitment::new( | ||
zero_commitment.0 + old_commitment.0, | ||
)); | ||
} else { | ||
return Err(Error::IncorrectNumberOfCommitments); | ||
} | ||
} | ||
} else { | ||
return Err(Error::MissingCommitment); | ||
} | ||
|
||
let commitment = VerifiableSecretSharingCommitment::new(commitments); | ||
|
||
let signing_share = SigningShare::new(signing_share); | ||
|
||
Ok(SecretShare { | ||
header: zero_share.header, | ||
identifier: zero_share.identifier, | ||
signing_share, | ||
commitment, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
//! Test for Refreshing shares | ||
|
||
use std::collections::BTreeMap; | ||
|
||
use rand_core::{CryptoRng, RngCore}; | ||
|
||
use crate::{self as frost}; | ||
use crate::{ | ||
keys::{refresh::refresh_shares_with_dealer, PublicKeyPackage, SecretShare}, | ||
Ciphersuite, Error, Identifier, SigningKey, | ||
}; | ||
|
||
use super::ciphersuite_generic::check_sign; | ||
|
||
/// We want to test that recover share matches the original share | ||
pub fn check_refresh_shares_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(mut rng: R) { | ||
// Compute shares | ||
|
||
//////////////////////////////////////////////////////////////////////////// | ||
// Old Key generation | ||
//////////////////////////////////////////////////////////////////////////// | ||
|
||
let max_signers = 5; | ||
let min_signers = 3; | ||
let (old_shares, pub_key_package) = frost::keys::generate_with_dealer( | ||
max_signers, | ||
min_signers, | ||
frost::keys::IdentifierList::Default, | ||
&mut rng, | ||
) | ||
.unwrap(); | ||
|
||
// Try to refresh shares | ||
// Signer 2 will be removed and Signers 1, 3, 4 & 5 will remain | ||
|
||
//////////////////////////////////////////////////////////////////////////// | ||
// New Key generation | ||
//////////////////////////////////////////////////////////////////////////// | ||
|
||
let remaining_ids = vec![ | ||
Identifier::try_from(1).unwrap(), | ||
Identifier::try_from(3).unwrap(), | ||
Identifier::try_from(4).unwrap(), | ||
Identifier::try_from(5).unwrap(), | ||
]; | ||
|
||
const NEW_MAX_SIGNERS: u16 = 4; | ||
|
||
let (shares, new_pub_key_package) = refresh_shares_with_dealer( | ||
old_shares, | ||
pub_key_package, | ||
NEW_MAX_SIGNERS, | ||
min_signers, | ||
&remaining_ids, | ||
&mut rng, | ||
) | ||
.unwrap(); | ||
|
||
let mut key_packages: BTreeMap<frost::Identifier<C>, frost::keys::KeyPackage<C>> = | ||
BTreeMap::new(); | ||
|
||
for (k, v) in shares { | ||
let key_package = frost::keys::KeyPackage::try_from(v).unwrap(); | ||
key_packages.insert(k, key_package); | ||
} | ||
check_sign(min_signers, key_packages, rng, new_pub_key_package).unwrap(); | ||
} | ||
|
||
/// Check refesh shares with dealer errors | ||
pub fn check_refresh_shares_with_dealer_fails_with_invalid_signers< | ||
C: Ciphersuite, | ||
R: RngCore + CryptoRng, | ||
>( | ||
new_max_signers: u16, | ||
min_signers: u16, | ||
identifiers: &[Identifier<C>], | ||
error: Error<C>, | ||
mut rng: R, | ||
) { | ||
let (old_shares, pub_key_package) = build_old_shares::<C, R>(5, 2, &mut rng); | ||
let out = refresh_shares_with_dealer( | ||
old_shares, | ||
pub_key_package, | ||
new_max_signers, | ||
min_signers, | ||
identifiers, | ||
&mut rng, | ||
); | ||
|
||
assert!(out.is_err()); | ||
assert!(out == Err(error)) | ||
} | ||
|
||
fn build_old_shares<C: Ciphersuite, R: RngCore + CryptoRng>( | ||
max_signers: u16, | ||
min_signers: u16, | ||
mut rng: &mut R, | ||
) -> (BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>) { | ||
// Compute shares | ||
|
||
//////////////////////////////////////////////////////////////////////////// | ||
// Key generation | ||
//////////////////////////////////////////////////////////////////////////// | ||
|
||
let mut bytes = [0; 64]; | ||
rng.fill_bytes(&mut bytes); | ||
|
||
let key = SigningKey::new(&mut rng); | ||
|
||
let (old_shares, pub_key_package): ( | ||
BTreeMap<Identifier<C>, SecretShare<C>>, | ||
PublicKeyPackage<C>, | ||
) = frost::keys::split( | ||
&key, | ||
max_signers, | ||
min_signers, | ||
frost::keys::IdentifierList::Default, | ||
&mut rng, | ||
) | ||
.unwrap(); | ||
|
||
// Try to refresh shares | ||
// Signer 2 will be removed and Signers 1, 3, 4 & 5 will remain | ||
|
||
// Rerun key generation | ||
|
||
(old_shares, pub_key_package) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
//! Refresh Shares | ||
//! | ||
//! Implements the functionality to refresh a share. This requires the participation | ||
//! of all the remaining signers. This can be done using a Trusted Dealer or | ||
//! DKG (not yet implemented) | ||
|
||
use std::collections::BTreeMap; | ||
|
||
use crate::{frost, Ciphersuite, CryptoRng, Error, Identifier, RngCore}; | ||
|
||
use super::{PublicKeyPackage, SecretShare}; | ||
|
||
/// Refresh shares using a trusted dealer | ||
pub fn refresh_shares_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>( | ||
current_shares: BTreeMap<Identifier, SecretShare>, | ||
old_pub_key_package: PublicKeyPackage, | ||
max_signers: u16, | ||
min_signers: u16, | ||
identifiers: &[Identifier], | ||
mut rng: &mut R, | ||
) -> Result<(BTreeMap<Identifier, SecretShare>, PublicKeyPackage), Error> { | ||
frost::keys::refresh::refresh_shares_with_dealer( | ||
current_shares, | ||
old_pub_key_package, | ||
max_signers, | ||
min_signers, | ||
identifiers, | ||
&mut rng, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.