Skip to content

Commit

Permalink
refactor key refreshing
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-roslaniec committed Jan 25, 2023
1 parent d499c28 commit 864dbc2
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 217 deletions.
2 changes: 1 addition & 1 deletion ferveo/src/dkg/pv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct PubliclyVerifiableDkg<E: PairingEngine> {
impl<E: PairingEngine> PubliclyVerifiableDkg<E> {
/// Create a new DKG context to participate in the DKG
/// Every identity in the DKG is linked to an ed25519 public key;
/// `validatorst`: List of validators
/// `validators`: List of validators
/// `params` contains the parameters of the DKG such as number of shares
/// `me` the validator creating this instance
/// `session_keypair` the keypair for `me`
Expand Down
187 changes: 148 additions & 39 deletions ferveo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,23 @@ mod test_dkg_full {
use super::*;

use crate::dkg::pv::test_common::*;
use ark_bls12_381::{Bls12_381 as EllipticCurve, Bls12_381, G2Projective};
use ark_bls12_381::{
Bls12_381 as EllipticCurve, Bls12_381, Fr, G1Affine, G2Projective,
};
use ark_ec::bls12::G2Affine;
use ark_ec::group::Group;
use ark_ff::{Fp12, UniformRand};
use ark_std::test_rng;
use ferveo_common::{ExternalValidator, Keypair};
use group_threshold_cryptography as tpke;
use group_threshold_cryptography::Ciphertext;
use group_threshold_cryptography::{Ciphertext, DecryptionShareSimple};
use itertools::{zip_eq, Itertools};

type E = Bls12_381;

#[test]
fn test_dkg_simple_decryption_variant_single_validator() {
let rng = &mut ark_std::test_rng();
let rng = &mut test_rng();
let dkg = setup_dealt_dkg_with_n_validators(1, 1);

let msg: &[u8] = "abc".as_bytes();
Expand All @@ -61,24 +64,32 @@ mod test_dkg_full {

let ciphertext = tpke::encrypt::<_, E>(msg, aad, &public_key, rng);

let share_aggregate = aggregate_for_decryption(&dkg);
// Aggregate contains only one set of shares
assert_eq!(share_aggregate, dkg.vss.get(&0).unwrap().shares);
let pvss_aggregated = aggregate(&dkg);
// Aggregate contains only one set of shares because we only have one validator here
assert_eq!(aggregate(&dkg).shares, dkg.vss.get(&0).unwrap().shares);

let validator_keypairs = gen_n_keypairs(1);
let decryption_shares = make_decryption_shares(
&ciphertext,
&validator_keypairs,
&share_aggregate,
aad,
);

let shares_x = &dkg
let decryption_shares: Vec<DecryptionShareSimple<E>> =
validator_keypairs
.iter()
.enumerate()
.map(|(validator_index, validator_keypair)| {
pvss_aggregated.make_decryption_share_simple(
&ciphertext,
aad,
&validator_keypair.decryption_key,
validator_index,
)
})
.collect();

let domain = &dkg
.domain
.elements()
.take(decryption_shares.len())
.collect::<Vec<_>>();
let lagrange_coeffs = tpke::prepare_combine_simple::<E>(shares_x);
let lagrange_coeffs = tpke::prepare_combine_simple::<E>(domain);

let shared_secret = tpke::share_combine_simple::<E>(
&decryption_shares,
Expand All @@ -96,16 +107,14 @@ mod test_dkg_full {

#[test]
fn test_dkg_simple_decryption_variant() {
let rng = &mut ark_std::test_rng();
let rng = &mut test_rng();
let dkg = setup_dealt_dkg_with_n_validators(3, 4);

let msg: &[u8] = "abc".as_bytes();
let aad: &[u8] = "my-aad".as_bytes();
let public_key = dkg.final_key();
let ciphertext = tpke::encrypt::<_, E>(msg, aad, &public_key, rng);

let share_aggregate = aggregate_for_decryption(&dkg);

let validator_keypairs = gen_n_keypairs(4);
// Make sure validators are in the same order dkg is by comparing their public keys
dkg.validators
Expand All @@ -114,19 +123,26 @@ mod test_dkg_full {
.for_each(|(v, k)| {
assert_eq!(v.validator.public_key, k.public());
});
let decryption_shares = make_decryption_shares(
&ciphertext,
&validator_keypairs,
&share_aggregate,
aad,
);

let shares_x = &dkg
.domain
.elements()
.take(decryption_shares.len()) // TODO: Assert length instead?
.collect::<Vec<_>>();
let lagrange_coeffs = tpke::prepare_combine_simple::<E>(shares_x);
let pvss_aggregated = aggregate(&dkg);

let decryption_shares: Vec<DecryptionShareSimple<E>> =
validator_keypairs
.iter()
.enumerate()
.map(|(validator_index, validator_keypair)| {
pvss_aggregated.make_decryption_share_simple(
&ciphertext,
aad,
&validator_keypair.decryption_key,
validator_index,
)
})
.collect();

let domain = &dkg.domain.elements().collect::<Vec<_>>();
assert_eq!(domain.len(), decryption_shares.len());
let lagrange_coeffs = tpke::prepare_combine_simple::<E>(domain);

let shared_secret = tpke::share_combine_simple::<E>(
&decryption_shares,
Expand All @@ -144,15 +160,108 @@ mod test_dkg_full {
assert_eq!(plaintext, msg);

// Testing green-path decryption share verification
izip!(decryption_shares, share_aggregate, validator_keypairs).for_each(
|(decryption_share, y_i, validator_keypair)| {
assert!(decryption_share.verify(
&y_i,
&validator_keypair.public().encryption_key,
&dkg.pvss_params.h,
&ciphertext
));
},
);
izip!(
decryption_shares,
pvss_aggregated.shares,
validator_keypairs
)
.for_each(|(decryption_share, y_i, validator_keypair)| {
assert!(decryption_share.verify(
&y_i,
&validator_keypair.public().encryption_key,
&dkg.pvss_params.h,
&ciphertext,
));
});
}

// fn test_dkg_simple_decryption_variant_share_recovery() {
// let rng = &mut test_rng();
// let dkg = setup_dealt_dkg_with_n_validators(3, 4);
//
// let msg: &[u8] = "abc".as_bytes();
// let aad: &[u8] = "my-aad".as_bytes();
// let public_key = dkg.final_key();
// let ciphertext = tpke::encrypt::<_, E>(msg, aad, &public_key, rng);
//
// let validator_keypairs = gen_n_keypairs(4);
// // Make sure validators are in the same order dkg is by comparing their public keys
// dkg.validators
// .iter()
// .zip_eq(validator_keypairs.iter())
// .for_each(|(v, k)| {
// assert_eq!(v.validator.public_key, k.public());
// });
//
// let pvss_aggregated = aggregate(&dkg);
//
// let decryption_shares: Vec<DecryptionShareSimple<E>> =
// validator_keypairs
// .iter()
// .enumerate()
// .map(|(validator_index, validator_keypair)| {
// pvss_aggregated.make_decryption_share_simple(
// &ciphertext,
// aad,
// &validator_keypair.decryption_key,
// validator_index,
// )
// })
// .collect();
//
// let domain = &dkg
// .domain
// .elements()
// .collect::<Vec<_>>();
// assert_eq!(domain.len(), decryption_shares.len());
// let lagrange_coeffs = tpke::prepare_combine_simple::<E>(domain);
//
// // Create an initial shared secret
//
// let old_shared_secret = tpke::share_combine_simple::<E>(
// &decryption_shares,
// &lagrange_coeffs,
// );
//
// // Now, we're going to recover a new share at a random point and check that the shared secret is still the same
//
// // Remove one participant from the contexts and all nested structure
// let mut new_dkg = dkg;
// let removed_validator = new_dkg.validators.pop().unwrap();
//
// // Recover the share
// let x_r = Fr::rand(rng);
// let y_r = tpke::recover_share_at_point(
// &remaining_participants,
// threshold,
// &x_r,
// rng,
// );
// let recovered_key_share = tpke::PrivateKeyShare {
// private_key_share: y_r.into_affine(),
// };
//
// // Creating decryption shares
// let mut decryption_shares: Vec<_> = remaining_participants
// .iter()
// .map(|c| c.create_share(&ciphertext, aad).unwrap())
// .collect();
// decryption_shares.push(DecryptionShareSimple {
// decrypter_index: removed_participant.index,
// decryption_share: make_decryption_share(
// &recovered_key_share,
// &ciphertext,
// ),
// // TODO: Implement a method to make a proper decryption share after refreshing
// validator_checksum: G1Affine::zero(),
// });
//
// // Creating a shared secret from remaining shares and the recovered one
// let new_shared_secret = make_shared_secret(
// &remaining_participants[0].public_decryption_contexts,
// &decryption_shares,
// );
//
// assert_eq!(old_shared_secret, new_shared_secret);
// }
}
88 changes: 31 additions & 57 deletions ferveo/src/vss/pvss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ark_ff::UniformRand;
use ark_serialize::*;
use ferveo_common::{Keypair, PublicKey};
use group_threshold_cryptography::{
Ciphertext, DecryptionShareSimple, PrivateKeyShare,
Ciphertext, DecryptionShareFast, DecryptionShareSimple, PrivateKeyShare,
};
use itertools::{zip_eq, Itertools};
use subproductdomain::fast_multiexp;
Expand All @@ -33,6 +33,7 @@ impl Aggregate for Aggregated {}

/// Type alias for non aggregated PVSS transcripts
pub type Pvss<E> = PubliclyVerifiableSS<E>;

/// Type alias for aggregated PVSS transcripts
pub type AggregatedPvss<E> = PubliclyVerifiableSS<E, Aggregated>;

Expand Down Expand Up @@ -166,7 +167,7 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
}
}

/// Extra method available to aggregated PVSS transcripts
/// Extra methods available to aggregated PVSS transcripts
impl<E: PairingEngine, T: Aggregate> PubliclyVerifiableSS<E, T> {
/// Verify that this PVSS instance is a valid aggregation of
/// the PVSS instances, produced by [`aggregate`],
Expand Down Expand Up @@ -195,10 +196,38 @@ impl<E: PairingEngine, T: Aggregate> PubliclyVerifiableSS<E, T> {
))
}
}

pub fn make_decryption_share_simple(
&self,
ciphertext: &Ciphertext<E>,
aad: &[u8],
validator_decryption_key: &E::Fr,
validator_index: usize,
) -> DecryptionShareSimple<E> {
// Decrypt private key shares https://nikkolasg.github.io/ferveo/pvss.html#validator-decryption-of-private-key-shares
let private_key_share = self
.shares
.get(validator_index)
.unwrap()
.mul(validator_decryption_key.inverse().unwrap().into_repr())
.into_affine();
// TODO: Consider using "container" structs from `tpke` for other primitives,
// just like we use `PrivateKeyShare` here for `DecryptionShareSimple`
let private_key_share = PrivateKeyShare { private_key_share };
DecryptionShareSimple::create(
validator_index,
validator_decryption_key,
&private_key_share,
ciphertext,
aad,
)
.unwrap()
}
}

/// Aggregate the PVSS instances in `pvss` from DKG session `dkg`
/// into a new PVSS instance
/// See: https://nikkolasg.github.io/ferveo/pvss.html?highlight=aggregate#aggregation
pub fn aggregate<E: PairingEngine>(
dkg: &PubliclyVerifiableDkg<E>,
) -> PubliclyVerifiableSS<E, Aggregated> {
Expand Down Expand Up @@ -234,61 +263,6 @@ pub fn aggregate<E: PairingEngine>(
}
}

pub fn aggregate_for_decryption<E: PairingEngine>(
dkg: &PubliclyVerifiableDkg<E>,
) -> Vec<ShareEncryptions<E>> {
// From docs: https://nikkolasg.github.io/ferveo/pvss.html?highlight=aggregate#aggregation
// "Two PVSS instances may be aggregated into a single PVSS instance by adding elementwise each of the corresponding group elements."
let shares = dkg
.vss
.values()
.map(|pvss| pvss.shares.clone())
.collect::<Vec<_>>();
let first_share = shares.first().unwrap().to_vec();
shares
.into_iter()
.skip(1)
// We're assuming that in every PVSS instance, the shares are in the same order
.fold(first_share, |acc, shares| {
acc.into_iter()
.zip_eq(shares.into_iter())
.map(|(a, b)| a + b)
.collect()
})
}

pub fn make_decryption_shares<E: PairingEngine>(
ciphertext: &Ciphertext<E>,
validator_keypairs: &[Keypair<E>],
aggregate: &[E::G2Affine],
aad: &[u8],
) -> Vec<DecryptionShareSimple<E>> {
// TODO: Calculate separately for each validator
aggregate
.iter()
.zip_eq(validator_keypairs.iter())
.enumerate()
.map(|(decrypter_index, (encrypted_share, keypair))| {
// Decrypt private key shares https://nikkolasg.github.io/ferveo/pvss.html#validator-decryption-of-private-key-shares
let z_i = encrypted_share
.mul(keypair.decryption_key.inverse().unwrap().into_repr());
// TODO: Consider using "container" structs from `tpke` for other primitives
let private_key_share = PrivateKeyShare {
private_key_share: z_i.into_affine(),
};

DecryptionShareSimple::create(
decrypter_index,
&keypair.decryption_key,
&private_key_share,
ciphertext,
aad,
)
.unwrap() // Unwrapping here only because this is a test method!
})
.collect::<Vec<_>>()
}

#[cfg(test)]
mod test_pvss {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion tpke/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct SetupParams<E: PairingEngine> {
pub b_inv: E::Fr,
pub g: E::G1Affine,
pub g_inv: E::G1Prepared,
pub h_inv: E::G2Prepared,
pub h: E::G2Affine,
}

Expand All @@ -35,7 +36,6 @@ pub struct PrivateDecryptionContextFast<E: PairingEngine> {
pub setup_params: SetupParams<E>,
pub private_key_share: PrivateKeyShare<E>,
pub public_decryption_contexts: Vec<PublicDecryptionContextFast<E>>,
pub scalar_bits: usize,
}

impl<E: PairingEngine> PrivateDecryptionContextFast<E> {
Expand Down
Loading

0 comments on commit 864dbc2

Please sign in to comment.