Skip to content

Commit

Permalink
Merge pull request #175 from piotr-roslaniec/rewrite-refreshing
Browse files Browse the repository at this point in the history
Key share refreshing ceremony refactor
  • Loading branch information
cygnusv authored Mar 19, 2024
2 parents 2fe8753 + 4713848 commit 2c97934
Show file tree
Hide file tree
Showing 17 changed files with 1,300 additions and 473 deletions.
9 changes: 5 additions & 4 deletions ferveo-common/src/keypair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use ark_std::{
rand::{prelude::StdRng, RngCore, SeedableRng},
UniformRand,
};
use generic_array::{typenum::U96, GenericArray};
use generic_array::{
typenum::{Unsigned, U96},
GenericArray,
};
use serde::*;
use serde_with::serde_as;

Expand Down Expand Up @@ -55,7 +58,7 @@ impl<E: Pairing> PublicKey<E> {
}

pub fn serialized_size() -> usize {
96
U96::to_usize()
}
}

Expand Down Expand Up @@ -106,7 +109,6 @@ impl<E: Pairing> Ord for Keypair<E> {

impl<E: Pairing> Keypair<E> {
/// Returns the public session key for the publicly verifiable DKG participant

pub fn public_key(&self) -> PublicKey<E> {
PublicKey::<E> {
encryption_key: E::G2Affine::generator()
Expand All @@ -116,7 +118,6 @@ impl<E: Pairing> Keypair<E> {
}

/// Creates a new ephemeral session key for participating in the DKG

pub fn new<R: RngCore>(rng: &mut R) -> Self {
Self {
decryption_key: E::ScalarField::rand(rng),
Expand Down
1 change: 1 addition & 0 deletions ferveo-python/ferveo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@
DuplicatedShareIndex,
NoTranscriptsToAggregate,
InvalidAggregateVerificationParameters,
UnknownValidator,
)
3 changes: 3 additions & 0 deletions ferveo-python/ferveo/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,6 @@ class NoTranscriptsToAggregate(Exception):

class InvalidAggregateVerificationParameters(Exception):
pass

class UnknownValidator(Exception):
pass
8 changes: 4 additions & 4 deletions ferveo-tdec/benches/tpke.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(clippy::redundant_closure)]

use ark_bls12_381::{Bls12_381, Fr, G1Affine as G1, G2Affine as G2};
use ark_bls12_381::{Bls12_381, Fr};
use ark_ec::pairing::Pairing;
use criterion::{
black_box, criterion_group, criterion_main, BenchmarkId, Criterion,
Expand All @@ -25,8 +25,8 @@ struct SetupShared {
shares_num: usize,
msg: Vec<u8>,
aad: Vec<u8>,
pubkey: G1,
privkey: G2,
pubkey: PublicKeyShare<E>,
privkey: PrivateKeyShare<E>,
ciphertext: Ciphertext<E>,
shared_secret: SharedSecret<E>,
}
Expand Down Expand Up @@ -550,7 +550,7 @@ pub fn bench_decryption_share_validity_checks(c: &mut Criterion) {
// for &shares_num in NUM_SHARES_CASES.iter() {
// let setup = SetupSimple::new(shares_num, msg_size, rng);
// let threshold = setup.shared.threshold;
// let polynomial = make_random_polynomial_with_root::<E>(
// let polynomial = create_random_polynomial_with_root::<E>(
// threshold - 1,
// &Fr::zero(),
// rng,
Expand Down
14 changes: 9 additions & 5 deletions ferveo-tdec/src/ciphertext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ use serde_with::serde_as;
use sha2::{digest::Digest, Sha256};
use zeroize::ZeroizeOnDrop;

use crate::{htp_bls12381_g2, Error, Result, SecretBox, SharedSecret};
use crate::{
htp_bls12381_g2, Error, PrivateKeyShare, PublicKeyShare, Result, SecretBox,
SharedSecret,
};

#[serde_as]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -95,7 +98,7 @@ impl<E: Pairing> CiphertextHeader<E> {
pub fn encrypt<E: Pairing>(
message: SecretBox<Vec<u8>>,
aad: &[u8],
pubkey: &E::G1Affine,
pubkey: &PublicKeyShare<E>,
rng: &mut impl rand::Rng,
) -> Result<Ciphertext<E>> {
// r
Expand All @@ -105,7 +108,8 @@ pub fn encrypt<E: Pairing>(
// h
let h_gen = E::G2Affine::generator();

let ry_prep = E::G1Prepared::from(pubkey.mul(rand_element).into());
let ry_prep =
E::G1Prepared::from(pubkey.public_key_share.mul(rand_element).into());
// s
let product = E::pairing(ry_prep, h_gen).0;
// u
Expand Down Expand Up @@ -140,13 +144,13 @@ pub fn encrypt<E: Pairing>(
pub fn decrypt_symmetric<E: Pairing>(
ciphertext: &Ciphertext<E>,
aad: &[u8],
private_key: &E::G2Affine,
private_key: &PrivateKeyShare<E>,
g_inv: &E::G1Prepared,
) -> Result<Vec<u8>> {
ciphertext.check(aad, g_inv)?;
let shared_secret = E::pairing(
E::G1Prepared::from(ciphertext.commitment),
E::G2Prepared::from(*private_key),
E::G2Prepared::from(private_key.private_key_share),
)
.0;
let shared_secret = SharedSecret(shared_secret);
Expand Down
2 changes: 0 additions & 2 deletions ferveo-tdec/src/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ pub fn prepare_combine_fast<E: Pairing>(
.collect::<Vec<_>>()
}

// TODO: Combine `tpke::prepare_combine_simple` and `tpke::share_combine_simple` into
// one function and expose it in the tpke::api?
pub fn prepare_combine_simple<E: Pairing>(
domain: &[E::ScalarField],
) -> Vec<E::ScalarField> {
Expand Down
37 changes: 23 additions & 14 deletions ferveo-tdec/src/decryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ use std::ops::Mul;

use ark_ec::{pairing::Pairing, CurveGroup};
use ark_ff::{Field, One, Zero};
use ark_std::UniformRand;
use ferveo_common::serialization;
use itertools::{izip, zip_eq};
use rand_core::RngCore;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_with::serde_as;

use crate::{
generate_random, Ciphertext, CiphertextHeader, PrivateKeyShare,
PublicDecryptionContextFast, PublicDecryptionContextSimple, Result,
Ciphertext, CiphertextHeader, PrivateKeyShare, PublicDecryptionContextFast,
PublicDecryptionContextSimple, Result,
};

#[serde_as]
Expand All @@ -36,9 +37,6 @@ impl<E: Pairing> ValidatorShareChecksum<E> {
// C_i = dk_i^{-1} * U
let checksum = ciphertext_header
.commitment
// TODO: Should we panic here? I think we should since that would mean that the decryption key is invalid.
// And so, the validator should not be able to create a decryption share.
// And so, the validator should remake their keypair.
.mul(
validator_decryption_key
.inverse()
Expand Down Expand Up @@ -226,6 +224,15 @@ impl<E: Pairing> DecryptionSharePrecomputed<E> {
}
}

pub fn generate_random_scalars<R: RngCore, E: Pairing>(
n: usize,
rng: &mut R,
) -> Vec<E::ScalarField> {
(0..n)
.map(|_| E::ScalarField::rand(rng))
.collect::<Vec<_>>()
}

// TODO: Remove this code? Currently only used in benchmarks. Move to benchmark suite?
pub fn batch_verify_decryption_shares<R: RngCore, E: Pairing>(
pub_contexts: &[PublicDecryptionContextFast<E>],
Expand All @@ -240,16 +247,17 @@ pub fn batch_verify_decryption_shares<R: RngCore, E: Pairing>(
let blinding_keys = decryption_shares[0]
.iter()
.map(|d| {
pub_contexts[d.decrypter_index]
.blinded_key_share
.blinding_key_prepared
.clone()
E::G2Prepared::from(
pub_contexts[d.decrypter_index]
.blinded_key_share
.blinding_key,
)
})
.collect::<Vec<_>>();

// For each ciphertext, generate num_shares random scalars
let alpha_ij = (0..num_ciphertexts)
.map(|_| generate_random::<_, E>(num_shares, rng))
.map(|_| generate_random_scalars::<_, E>(num_shares, rng))
.collect::<Vec<_>>();

let mut pairings_a = Vec::with_capacity(num_shares + 1);
Expand Down Expand Up @@ -302,10 +310,11 @@ pub fn verify_decryption_shares_fast<E: Pairing>(
let blinding_keys = decryption_shares
.iter()
.map(|d| {
pub_contexts[d.decrypter_index]
.blinded_key_share
.blinding_key_prepared
.clone()
E::G2Prepared::from(
pub_contexts[d.decrypter_index]
.blinded_key_share
.blinding_key,
)
})
.collect::<Vec<_>>();

Expand Down
24 changes: 11 additions & 13 deletions ferveo-tdec/src/key_share.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ use std::ops::Mul;
use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup};
use ark_ff::One;
use ark_std::UniformRand;
use ferveo_common::serialization;
use rand_core::RngCore;
use zeroize::ZeroizeOnDrop;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use zeroize::{Zeroize, ZeroizeOnDrop};

#[derive(Debug, Clone)]
// TODO: Should we rename it to PublicKey or SharedPublicKey?
pub struct PublicKeyShare<E: Pairing> {
pub public_key_share: E::G1Affine, // A_{i, \omega_i}
}
Expand All @@ -15,16 +19,6 @@ pub struct PublicKeyShare<E: Pairing> {
pub struct BlindedKeyShare<E: Pairing> {
pub blinding_key: E::G2Affine, // [b] H
pub blinded_key_share: E::G2Affine, // [b] Z_{i, \omega_i}
pub blinding_key_prepared: E::G2Prepared,
}

pub fn generate_random<R: RngCore, E: Pairing>(
n: usize,
rng: &mut R,
) -> Vec<E::ScalarField> {
(0..n)
.map(|_| E::ScalarField::rand(rng))
.collect::<Vec<_>>()
}

impl<E: Pairing> BlindedKeyShare<E> {
Expand Down Expand Up @@ -58,8 +52,13 @@ impl<E: Pairing> BlindedKeyShare<E> {
}
}

#[derive(Debug, Clone, PartialEq, Eq, ZeroizeOnDrop)]
#[serde_as]
#[derive(
Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize, ZeroizeOnDrop,
)]
pub struct PrivateKeyShare<E: Pairing> {
// TODO: Replace with a tuple?
#[serde_as(as = "serialization::SerdeAs")]
pub private_key_share: E::G2Affine,
}

Expand All @@ -68,7 +67,6 @@ impl<E: Pairing> PrivateKeyShare<E> {
let blinding_key = E::G2Affine::generator().mul(b).into_affine();
BlindedKeyShare::<E> {
blinding_key,
blinding_key_prepared: E::G2Prepared::from(blinding_key),
blinded_key_share: self.private_key_share.mul(b).into_affine(),
}
}
Expand Down
42 changes: 29 additions & 13 deletions ferveo-tdec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ pub mod test_common {
shares_num: usize,
rng: &mut impl RngCore,
) -> (
E::G1Affine,
E::G2Affine,
PublicKeyShare<E>,
PrivateKeyShare<E>,
Vec<PrivateDecryptionContextFast<E>>,
) {
assert!(shares_num >= threshold);
Expand Down Expand Up @@ -138,7 +138,7 @@ pub mod test_common {
)
.enumerate()
{
let private_key_share = PrivateKeyShare::<E> {
let private_key_share = PrivateKeyShare {
private_key_share: *private,
};
let b = E::ScalarField::rand(rng);
Expand Down Expand Up @@ -171,16 +171,24 @@ pub mod test_common {
private.public_decryption_contexts = public_contexts.clone();
}

(pubkey.into(), privkey.into(), private_contexts)
(
PublicKeyShare {
public_key_share: pubkey.into(),
},
PrivateKeyShare {
private_key_share: privkey.into(),
},
private_contexts,
)
}

pub fn setup_simple<E: Pairing>(
threshold: usize,
shares_num: usize,
rng: &mut impl rand::Rng,
) -> (
E::G1Affine,
E::G2Affine,
PublicKeyShare<E>,
PrivateKeyShare<E>,
Vec<PrivateDecryptionContextSimple<E>>,
) {
assert!(shares_num >= threshold);
Expand Down Expand Up @@ -259,22 +267,30 @@ pub mod test_common {
private.public_decryption_contexts = public_contexts.clone();
}

(pubkey.into(), privkey.into(), private_contexts)
(
PublicKeyShare {
public_key_share: pubkey.into(),
},
PrivateKeyShare {
private_key_share: privkey.into(),
},
private_contexts,
)
}

pub fn setup_precomputed<E: Pairing>(
shares_num: usize,
rng: &mut impl rand::Rng,
) -> (
E::G1Affine,
E::G2Affine,
PublicKeyShare<E>,
PrivateKeyShare<E>,
Vec<PrivateDecryptionContextSimple<E>>,
) {
// In precomputed variant, the security threshold is equal to the number of shares
setup_simple::<E>(shares_num, shares_num, rng)
}

pub fn make_shared_secret<E: Pairing>(
pub fn create_shared_secret<E: Pairing>(
pub_contexts: &[PublicDecryptionContextSimple<E>],
decryption_shares: &[DecryptionShareSimple<E>],
) -> SharedSecret<E> {
Expand All @@ -292,7 +308,7 @@ mod tests {
use ark_std::{test_rng, UniformRand};
use ferveo_common::{FromBytes, ToBytes};

use crate::test_common::{make_shared_secret, setup_simple, *};
use crate::test_common::{create_shared_secret, setup_simple, *};

type E = ark_bls12_381::Bls12_381;
type TargetField = <E as Pairing>::TargetField;
Expand Down Expand Up @@ -465,7 +481,7 @@ mod tests {
let pub_contexts =
contexts[0].public_decryption_contexts[..threshold].to_vec();
let shared_secret =
make_shared_secret(&pub_contexts, &decryption_shares);
create_shared_secret(&pub_contexts, &decryption_shares);

test_ciphertext_validation_fails(
&msg,
Expand All @@ -479,7 +495,7 @@ mod tests {
let decryption_shares = decryption_shares[..threshold - 1].to_vec();
let pub_contexts = pub_contexts[..threshold - 1].to_vec();
let shared_secret =
make_shared_secret(&pub_contexts, &decryption_shares);
create_shared_secret(&pub_contexts, &decryption_shares);

let result =
decrypt_with_shared_secret(&ciphertext, aad, &shared_secret, g_inv);
Expand Down
Loading

0 comments on commit 2c97934

Please sign in to comment.