From f746edf43b156427ffc8720972a89e1369b2e289 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Mon, 19 Feb 2024 19:55:53 +0100
Subject: [PATCH] feature!: remove state from dkg, part 2
---
ferveo-python/ferveo/__init__.py | 1 +
ferveo-python/ferveo/__init__.pyi | 3 +
ferveo/src/api.rs | 139 ++++++++++--------------------
ferveo/src/bindings_python.rs | 5 ++
ferveo/src/dkg.rs | 46 +++-------
ferveo/src/lib.rs | 99 ++++++++++++---------
ferveo/src/pvss.rs | 58 +++++++------
ferveo/src/refresh.rs | 6 +-
ferveo/src/test_common.rs | 33 ++++---
9 files changed, 178 insertions(+), 212 deletions(-)
diff --git a/ferveo-python/ferveo/__init__.py b/ferveo-python/ferveo/__init__.py
index 5088675d..209741b2 100644
--- a/ferveo-python/ferveo/__init__.py
+++ b/ferveo-python/ferveo/__init__.py
@@ -41,4 +41,5 @@
InvalidAggregateVerificationParameters,
UnknownValidator,
TooManyTranscripts,
+ DuplicateTranscript,
)
diff --git a/ferveo-python/ferveo/__init__.pyi b/ferveo-python/ferveo/__init__.pyi
index f4b5fd9f..e738f2ab 100644
--- a/ferveo-python/ferveo/__init__.pyi
+++ b/ferveo-python/ferveo/__init__.pyi
@@ -226,3 +226,6 @@ class UnknownValidator(Exception):
class TooManyTranscripts(Exception):
pass
+
+class DuplicateTranscript(Exception):
+ pass
diff --git a/ferveo/src/api.rs b/ferveo/src/api.rs
index 57ae0694..32449257 100644
--- a/ferveo/src/api.rs
+++ b/ferveo/src/api.rs
@@ -25,8 +25,8 @@ use crate::bindings_python;
use crate::bindings_wasm;
pub use crate::EthereumAddress;
use crate::{
- do_verify_aggregation, DomainPoint, Error, PVSSMap,
- PubliclyVerifiableParams, PubliclyVerifiableSS, Result,
+ do_verify_aggregation, DomainPoint, Error, PubliclyVerifiableParams,
+ PubliclyVerifiableSS, Result,
};
pub type PublicKey = ferveo_common::PublicKey;
@@ -66,12 +66,12 @@ pub fn decrypt_with_shared_secret(
aad: &[u8],
shared_secret: &SharedSecret,
) -> Result> {
- let dkg_public_params = DkgPublicParameters::default();
+ let g_inv = PubliclyVerifiableParams::::default().g_inv();
ferveo_tdec::api::decrypt_with_shared_secret(
&ciphertext.0,
aad,
&shared_secret.0,
- &dkg_public_params.g1_inv,
+ &g_inv,
)
.map_err(Error::from)
}
@@ -235,13 +235,6 @@ impl Dkg {
.map(AggregatedTranscript)
}
- // TODO: Unused?
- pub fn public_params(&self) -> DkgPublicParameters {
- DkgPublicParameters {
- g1_inv: self.0.pvss_params.g_inv(),
- }
- }
-
pub fn me(&self) -> &Validator {
&self.0.me
}
@@ -251,14 +244,6 @@ impl Dkg {
}
}
-fn make_pvss_map(messages: &[ValidatorMessage]) -> PVSSMap {
- let mut pvss_map: PVSSMap = PVSSMap::new();
- messages.iter().for_each(|(validator, transcript)| {
- pvss_map.insert(validator.address.clone(), transcript.clone());
- });
- pvss_map
-}
-
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AggregatedTranscript(crate::AggregatedTranscript);
@@ -285,33 +270,34 @@ impl AggregatedTranscript {
));
}
- let pvss_params = PubliclyVerifiableParams::::default();
let domain =
GeneralEvaluationDomain::::new(validators_num as usize)
.expect("Unable to construct an evaluation domain");
-
let is_valid_optimistic = self.0.aggregate.verify_optimistic();
if !is_valid_optimistic {
return Err(Error::InvalidTranscriptAggregate);
}
- let pvss_map = make_pvss_map(messages);
+ let pvss_params = PubliclyVerifiableParams::::default();
let validators: Vec<_> = messages
.iter()
.map(|(validator, _)| validator)
.cloned()
.collect();
-
+ let pvss_list = messages
+ .iter()
+ .map(|(_validator, transcript)| transcript)
+ .cloned()
+ .collect::>();
// This check also includes `verify_full`. See impl. for details.
- let is_valid = do_verify_aggregation(
+ do_verify_aggregation(
&self.0.aggregate.coeffs,
&self.0.aggregate.shares,
&pvss_params,
&validators,
&domain,
- &pvss_map,
- )?;
- Ok(is_valid)
+ &pvss_list,
+ )
}
// TODO: Consider deprecating in favor of PrivateKeyShare::create_decryption_share_simple
@@ -354,7 +340,6 @@ impl AggregatedTranscript {
aad,
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)?;
Ok(DecryptionShareSimple {
@@ -390,32 +375,6 @@ pub struct DecryptionShareSimple {
domain_point: DomainPoint,
}
-// TODO: Deprecate?
-#[serde_as]
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct DkgPublicParameters {
- #[serde_as(as = "serialization::SerdeAs")]
- pub(crate) g1_inv: G1Prepared,
-}
-
-impl Default for DkgPublicParameters {
- fn default() -> Self {
- DkgPublicParameters {
- g1_inv: PubliclyVerifiableParams::::default().g_inv(),
- }
- }
-}
-
-impl DkgPublicParameters {
- pub fn from_bytes(bytes: &[u8]) -> Result {
- bincode::deserialize(bytes).map_err(|e| e.into())
- }
-
- pub fn to_bytes(&self) -> Result> {
- bincode::serialize(self).map_err(|e| e.into())
- }
-}
-
pub fn combine_shares_simple(shares: &[DecryptionShareSimple]) -> SharedSecret {
// Pick domain points that are corresponding to the shares we have.
let domain_points: Vec<_> = shares.iter().map(|s| s.domain_point).collect();
@@ -575,7 +534,6 @@ impl PrivateKeyShare {
&ciphertext_header.0,
aad,
validator_keypair,
- &dkg.public_params().g1_inv,
)?;
let domain_point = dkg.0.get_domain_point(dkg.0.me.share_index)?;
Ok(DecryptionShareSimple {
@@ -593,7 +551,7 @@ impl PrivateKeyShare {
share_index: u32,
domain_points: &[DomainPoint],
) -> Result {
- let dkg_public_params = DkgPublicParameters::default();
+ let g_inv = PubliclyVerifiableParams::::default().g_inv();
let share = crate::PrivateKeyShare(self.0.clone())
.create_decryption_share_simple_precomputed(
&ciphertext_header.0,
@@ -601,7 +559,7 @@ impl PrivateKeyShare {
validator_keypair,
share_index,
domain_points,
- &dkg_public_params.g1_inv,
+ &g_inv,
)?;
Ok(share)
}
@@ -918,33 +876,33 @@ mod test_ferveo_api {
assert!(result.is_err());
// Duplicated transcripts
- let message_with_duplicated_validator = (
- // Duplicating the validator but with a different, valid transcript
- messages[0].0.clone(),
- messages[security_threshold as usize].1.clone(),
- );
- let mut messages_with_duplicates = messages.clone();
- messages_with_duplicates.push(message_with_duplicated_validator);
- // assert_eq!(messages_with_duplicates.len(), security_threshold as usize);
+ let messages_with_duplicated_transcript = [
+ (
+ validators[security_threshold as usize - 1].clone(),
+ messages[security_threshold as usize - 1].1.clone(),
+ ),
+ (
+ validators[security_threshold as usize - 1].clone(),
+ messages[security_threshold as usize - 2].1.clone(),
+ ),
+ ];
assert!(dkg
- .aggregate_transcripts(&messages_with_duplicates)
+ .aggregate_transcripts(&messages_with_duplicated_transcript)
.is_err());
- // TODO: Transcripts are not hashable?
- // let message_with_duplicated_transcript = (
- // // Duplicating the transcript but with a different, valid validator
- // validators[security_threshold as usize - 1].clone(),
- // messages[security_threshold as usize - 1].1.clone(),
- // );
- // let messages_with_duplicates = [
- // &messages[..(security_threshold - 1) as usize],
- // &[message_with_duplicated_transcript],
- // ]
- // .concat();
- // assert_eq!(messages_with_duplicates.len(), security_threshold as usize);
- // assert!(dkg
- // .aggregate_transcripts(&messages_with_duplicates)
- // .is_err());
+ let messages_with_duplicated_transcript = [
+ (
+ validators[security_threshold as usize - 1].clone(),
+ messages[security_threshold as usize - 1].1.clone(),
+ ),
+ (
+ validators[security_threshold as usize - 2].clone(),
+ messages[security_threshold as usize - 1].1.clone(),
+ ),
+ ];
+ assert!(dkg
+ .aggregate_transcripts(&messages_with_duplicated_transcript)
+ .is_err());
// Unexpected transcripts in the aggregate or transcripts from a different ritual
// Using same DKG parameters, but different DKG instances and validators
@@ -1065,7 +1023,7 @@ mod test_ferveo_api {
.collect::>();
// Creating a copy to avoiding accidentally changing DKG state
- let mut dkg = dkgs[0].clone();
+ let dkg = dkgs[0].clone();
let pvss_aggregated = dkg.aggregate_transcripts(&messages).unwrap();
assert!(pvss_aggregated.verify(validators_num, &messages).unwrap());
@@ -1074,17 +1032,18 @@ mod test_ferveo_api {
let ciphertext =
encrypt(SecretBox::new(MSG.to_vec()), AAD, &public_key).unwrap();
let ciphertext_header = ciphertext.header().unwrap();
- for (validator, transcript) in messages.iter() {
- dkg.0
- .vss
- .insert(validator.address.clone(), transcript.clone());
- }
+ let transcripts = messages
+ .iter()
+ .map(|(_, transcript)| transcript)
+ .cloned()
+ .collect::>();
let (_, _, old_shared_secret) =
crate::test_dkg_full::create_shared_secret_simple_tdec(
&dkg.0,
AAD,
&ciphertext_header.0,
validator_keypairs.as_slice(),
+ &transcripts,
);
(
@@ -1142,13 +1101,7 @@ mod test_ferveo_api {
messages.pop().unwrap();
dkgs.pop();
validator_keypairs.pop().unwrap();
-
let removed_validator = validators.pop().unwrap();
- for dkg in dkgs.iter_mut() {
- dkg.0
- .offboard_validator(&removed_validator.address)
- .expect("Unable to off-board a validator from the DKG context");
- }
// Now, we're going to recover a new share at a random point or at a specific point
// and check that the shared secret is still the same.
diff --git a/ferveo/src/bindings_python.rs b/ferveo/src/bindings_python.rs
index a229568c..8505ae42 100644
--- a/ferveo/src/bindings_python.rs
+++ b/ferveo/src/bindings_python.rs
@@ -129,6 +129,9 @@ impl From for PyErr {
"expected: {expected}, received: {received}"
))
}
+ Error::DuplicateTranscript(validator) => {
+ DuplicateTranscript::new_err(validator.to_string())
+ }
// Remember to create Python exceptions using `create_exception!` macro, and to register them in the
// `make_ferveo_py_module` function. You will have to update the `ferveo/__init__.{py, pyi}` files too.
},
@@ -180,6 +183,7 @@ create_exception!(
);
create_exception!(exceptions, UnknownValidator, PyValueError);
create_exception!(exceptions, TooManyTranscripts, PyValueError);
+create_exception!(exceptions, DuplicateTranscript, PyValueError);
fn from_py_bytes(bytes: &[u8]) -> PyResult {
T::from_bytes(bytes)
@@ -796,6 +800,7 @@ pub fn make_ferveo_py_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
)?;
m.add("UnknownValidator", py.get_type::())?;
m.add("TooManyTranscripts", py.get_type::())?;
+ m.add("DuplicateTranscript", py.get_type::())?;
Ok(())
}
diff --git a/ferveo/src/dkg.rs b/ferveo/src/dkg.rs
index fe1e18c2..087b3069 100644
--- a/ferveo/src/dkg.rs
+++ b/ferveo/src/dkg.rs
@@ -76,8 +76,6 @@ pub struct PubliclyVerifiableDkg {
pub dkg_params: DkgParams,
pub pvss_params: PubliclyVerifiableParams,
pub validators: ValidatorsMap,
- // TODO: Remove vss?
- pub vss: PVSSMap,
pub domain: ark_poly::GeneralEvaluationDomain,
pub me: Validator,
}
@@ -117,7 +115,6 @@ impl PubliclyVerifiableDkg {
Ok(Self {
dkg_params: *dkg_params,
pvss_params: PubliclyVerifiableParams::::default(),
- vss: PVSSMap::::new(),
domain,
me: me.clone(),
validators,
@@ -170,42 +167,26 @@ impl PubliclyVerifiableDkg {
self.domain.elements().take(self.validators.len()).collect()
}
- /// Remove a validator from the DKG
- pub fn offboard_validator(
- &mut self,
- address: &EthereumAddress,
- ) -> Result> {
- if let Some(validator) = self.validators.remove(address) {
- self.vss.remove(address);
- Ok(validator)
- } else {
- Err(Error::UnknownValidator(address.clone()))
- }
- }
-
/// Verify PVSS transcripts against the set of validators in the DKG
- // TODO: Make private?
- pub fn verify_transcripts(
+ fn verify_transcripts(
&self,
messages: &[ValidatorMessage],
) -> Result<()> {
let mut validator_set = HashSet::::new();
- // TODO: Transcripts are not hashable?
- // let mut transcript_set = HashSet::>::new();
+ let mut transcript_set = HashSet::>::new();
for (sender, transcript) in messages.iter() {
let sender = &sender.address;
if !self.validators.contains_key(sender) {
return Err(Error::UnknownDealer(sender.clone()));
} else if validator_set.contains(sender) {
return Err(Error::DuplicateDealer(sender.clone()));
- // } else if !transcript_set.contains(transcript) {
- // return Err(Error::DuplicateTranscript(sender.clone()));
+ } else if transcript_set.contains(transcript) {
+ return Err(Error::DuplicateTranscript(sender.clone()));
} else if !transcript.verify_optimistic() {
return Err(Error::InvalidPvssTranscript(sender.clone()));
- } else {
- validator_set.insert(sender.clone());
- // transcript_set.insert(sender.clone());
}
+ validator_set.insert(sender.clone());
+ transcript_set.insert(transcript.clone());
}
if validator_set.len() > self.validators.len() {
@@ -214,12 +195,12 @@ impl PubliclyVerifiableDkg {
validator_set.len() as u32,
));
}
- // if transcript_set.len() > self.validators.len() {
- // return Err(Error::TooManyTranscripts(
- // self.validators.len() as u32,
- // transcript_set.len() as u32,
- // ));
- // }
+ if transcript_set.len() > self.validators.len() {
+ return Err(Error::TooManyTranscripts(
+ self.validators.len() as u32,
+ transcript_set.len() as u32,
+ ));
+ }
Ok(())
}
@@ -360,8 +341,7 @@ mod test_aggregation {
/// 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")]
- fn test_aggregate(shares_num: u32, _validators_num: u32) {
- let _security_threshold = shares_num - 1;
+ fn test_aggregate(_shares_num: u32, _validators_num: u32) {
let rng = &mut ark_std::test_rng();
let (dkg, _) = setup_dkg(0);
let all_messages = make_messages(rng, &dkg);
diff --git a/ferveo/src/lib.rs b/ferveo/src/lib.rs
index 94128a01..5d52a4db 100644
--- a/ferveo/src/lib.rs
+++ b/ferveo/src/lib.rs
@@ -129,10 +129,10 @@ pub enum Error {
/// Too many transcripts received by the DKG
#[error("Too many transcripts. Expected: {0}, got: {1}")]
TooManyTranscripts(u32, u32),
- // TODO: Transcripts are not hashable?
- // /// Received a duplicated transcript from a validator
- // #[error("Received a duplicated transcript from validator: {0}")]
- // DuplicateTranscript(EthereumAddress),
+
+ /// Received a duplicated transcript from a validator
+ #[error("Received a duplicated transcript from validator: {0}")]
+ DuplicateTranscript(EthereumAddress),
}
pub type Result = std::result::Result;
@@ -163,15 +163,18 @@ mod test_dkg_full {
aad: &[u8],
ciphertext_header: &ferveo_tdec::CiphertextHeader,
validator_keypairs: &[Keypair],
+ transcripts: &[PubliclyVerifiableSS],
) -> (
AggregatedTranscript,
Vec>,
SharedSecret,
) {
- let transcripts = dkg.vss.values().cloned().collect::>();
let pvss_aggregated =
- AggregatedTranscript::from_transcripts(&transcripts).unwrap();
- assert!(pvss_aggregated.aggregate.verify_aggregation(dkg).is_ok());
+ AggregatedTranscript::from_transcripts(transcripts).unwrap();
+ assert!(pvss_aggregated
+ .aggregate
+ .verify_aggregation(dkg, transcripts)
+ .is_ok());
let decryption_shares: Vec> =
validator_keypairs
@@ -187,7 +190,6 @@ mod test_dkg_full {
aad,
validator_keypair,
validator.share_index,
- &dkg.pvss_params.g_inv(),
)
.unwrap()
})
@@ -217,13 +219,14 @@ mod test_dkg_full {
let rng = &mut test_rng();
let security_threshold = shares_num / 2 + 1;
- let (dkg, validator_keypairs) = setup_dealt_dkg_with_n_validators(
- security_threshold,
- shares_num,
- validators_num,
- );
-
- let transcripts = dkg.vss.values().cloned().collect::>();
+ let (dkg, validator_keypairs, messages) =
+ setup_dealt_dkg_with_n_validators(
+ security_threshold,
+ shares_num,
+ validators_num,
+ );
+ let transcripts =
+ messages.iter().map(|m| m.1.clone()).collect::>();
let public_key = AggregatedTranscript::from_transcripts(&transcripts)
.unwrap()
.public_key;
@@ -240,6 +243,7 @@ mod test_dkg_full {
AAD,
&ciphertext.header().unwrap(),
validator_keypairs.as_slice(),
+ &transcripts,
);
let plaintext = ferveo_tdec::decrypt_with_shared_secret(
@@ -260,15 +264,20 @@ mod test_dkg_full {
// In precomputed variant, threshold must be equal to shares_num
let security_threshold = shares_num;
- let (dkg, validator_keypairs) = setup_dealt_dkg_with_n_validators(
- security_threshold,
- shares_num,
- validators_num,
- );
- let transcripts = dkg.vss.values().cloned().collect::>();
+ let (dkg, validator_keypairs, messangers) =
+ setup_dealt_dkg_with_n_validators(
+ security_threshold,
+ shares_num,
+ validators_num,
+ );
+ let transcripts =
+ messangers.iter().map(|m| m.1.clone()).collect::>();
let pvss_aggregated =
AggregatedTranscript::from_transcripts(&transcripts).unwrap();
- pvss_aggregated.aggregate.verify_aggregation(&dkg).unwrap();
+ pvss_aggregated
+ .aggregate
+ .verify_aggregation(&dkg, &transcripts)
+ .unwrap();
let public_key = pvss_aggregated.public_key;
let ciphertext = ferveo_tdec::encrypt::(
SecretBox::new(MSG.to_vec()),
@@ -331,12 +340,14 @@ mod test_dkg_full {
let rng = &mut test_rng();
let security_threshold = shares_num / 2 + 1;
- let (dkg, validator_keypairs) = setup_dealt_dkg_with_n_validators(
- security_threshold,
- shares_num,
- validators_num,
- );
- let transcripts = dkg.vss.values().cloned().collect::>();
+ let (dkg, validator_keypairs, messages) =
+ setup_dealt_dkg_with_n_validators(
+ security_threshold,
+ shares_num,
+ validators_num,
+ );
+ let transcripts =
+ messages.iter().map(|m| m.1.clone()).collect::>();
let public_key = AggregatedTranscript::from_transcripts(&transcripts)
.unwrap()
.public_key;
@@ -354,6 +365,7 @@ mod test_dkg_full {
AAD,
&ciphertext.header().unwrap(),
validator_keypairs.as_slice(),
+ &transcripts,
);
izip!(
@@ -406,12 +418,14 @@ mod test_dkg_full {
let rng = &mut test_rng();
let security_threshold = shares_num / 2 + 1;
- let (dkg, validator_keypairs) = setup_dealt_dkg_with_n_validators(
- security_threshold,
- shares_num,
- validators_num,
- );
- let transcripts = dkg.vss.values().cloned().collect::>();
+ let (dkg, validator_keypairs, messages) =
+ setup_dealt_dkg_with_n_validators(
+ security_threshold,
+ shares_num,
+ validators_num,
+ );
+ let transcripts =
+ messages.iter().map(|m| m.1.clone()).collect::>();
let public_key = AggregatedTranscript::from_transcripts(&transcripts)
.unwrap()
.public_key;
@@ -429,6 +443,7 @@ mod test_dkg_full {
AAD,
&ciphertext.header().unwrap(),
validator_keypairs.as_slice(),
+ &transcripts,
);
// Remove one participant from the contexts and all nested structure
@@ -524,7 +539,6 @@ mod test_dkg_full {
AAD,
validator_keypair,
share_index as u32,
- &dkg.pvss_params.g_inv(),
)
.unwrap()
})
@@ -576,12 +590,14 @@ mod test_dkg_full {
let rng = &mut test_rng();
let security_threshold = shares_num / 2 + 1;
- let (dkg, validator_keypairs) = setup_dealt_dkg_with_n_validators(
- security_threshold,
- shares_num,
- validators_num,
- );
- let transcripts = dkg.vss.values().cloned().collect::>();
+ let (dkg, validator_keypairs, messages) =
+ setup_dealt_dkg_with_n_validators(
+ security_threshold,
+ shares_num,
+ validators_num,
+ );
+ let transcripts =
+ messages.iter().map(|m| m.1.clone()).collect::>();
let public_key = AggregatedTranscript::from_transcripts(&transcripts)
.unwrap()
.public_key;
@@ -599,6 +615,7 @@ mod test_dkg_full {
AAD,
&ciphertext.header().unwrap(),
validator_keypairs.as_slice(),
+ &transcripts,
);
// Each participant prepares an update for each other participant
diff --git a/ferveo/src/pvss.rs b/ferveo/src/pvss.rs
index 003a411e..cba7f92c 100644
--- a/ferveo/src/pvss.rs
+++ b/ferveo/src/pvss.rs
@@ -19,7 +19,7 @@ use zeroize::{self, Zeroize, ZeroizeOnDrop};
use crate::{
assert_no_share_duplicates, batch_to_projective_g1, batch_to_projective_g2,
- DomainPoint, Error, PVSSMap, PrivateKeyShare, PrivateKeyShareUpdate,
+ DomainPoint, Error, PrivateKeyShare, PrivateKeyShareUpdate,
PubliclyVerifiableDkg, Result, UpdatedPrivateKeyShare, Validator,
};
@@ -28,7 +28,7 @@ use crate::{
pub type ShareEncryptions = ::G2Affine;
/// Marker struct for unaggregated PVSS transcripts
-#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Unaggregated;
/// Marker struct for aggregated PVSS transcripts
@@ -124,6 +124,15 @@ pub struct PubliclyVerifiableSS {
phantom: PhantomData,
}
+// Manually implementing Hash trait because of the PhantomData
+impl Hash for PubliclyVerifiableSS {
+ fn hash(&self, state: &mut H) {
+ self.coeffs.hash(state);
+ self.shares.hash(state);
+ self.sigma.hash(state);
+ }
+}
+
impl PubliclyVerifiableSS {
/// Create a new PVSS instance
/// `s`: the secret constant coefficient to share
@@ -254,7 +263,7 @@ pub fn do_verify_aggregation(
pvss_params: &PubliclyVerifiableParams,
validators: &[Validator],
domain: &ark_poly::GeneralEvaluationDomain,
- vss: &PVSSMap,
+ pvss: &[PubliclyVerifiableSS],
) -> Result {
let is_valid = do_verify_full(
pvss_agg_coefficients,
@@ -268,10 +277,9 @@ pub fn do_verify_aggregation(
}
// Now, we verify that the aggregated PVSS transcript is a valid aggregation
- let mut y = E::G1::zero();
- for pvss in vss.values() {
- y += pvss.coeffs[0].into_group();
- }
+ let y = pvss
+ .iter()
+ .fold(E::G1::zero(), |acc, pvss| acc + pvss.coeffs[0].into_group());
if y.into_affine() == pvss_agg_coefficients[0] {
Ok(true)
} else {
@@ -288,6 +296,7 @@ impl PubliclyVerifiableSS {
pub fn verify_aggregation(
&self,
dkg: &PubliclyVerifiableDkg,
+ pvss: &[PubliclyVerifiableSS],
) -> Result {
let validators = dkg.validators.values().cloned().collect::>();
do_verify_aggregation(
@@ -296,7 +305,7 @@ impl PubliclyVerifiableSS {
&dkg.pvss_params,
&validators,
&dkg.domain,
- &dkg.vss,
+ pvss,
)
}
@@ -330,14 +339,12 @@ impl PubliclyVerifiableSS {
aad: &[u8],
validator_keypair: &Keypair,
share_index: u32,
- g_inv: &E::G1Prepared,
) -> Result> {
self.decrypt_private_key_share(validator_keypair, share_index)?
.create_decryption_share_simple(
ciphertext_header,
aad,
validator_keypair,
- g_inv,
)
}
@@ -463,16 +470,16 @@ mod test_pvss {
/// security threshold is not met
#[test]
fn test_aggregate_wont_verify_if_under_threshold() {
- let (_dkg, _) = setup_dealt_dkg_with_n_transcript_dealt(
+ let (dkg, _, messages) = setup_dealt_dkg_with_n_transcript_dealt(
SECURITY_THRESHOLD,
SHARES_NUM,
VALIDATORS_NUM,
SECURITY_THRESHOLD - 1,
);
- // TODO: Fix after rewriting dkg.vss
- // let messages = dkg.vss.iter().map(|(v, t)| (v.clone(), t.clone())).collect::>();
- // let aggregate = dkg.aggregate_transcripts(&messages).unwrap();
- // assert!(aggregate.aggregate.verify_aggregation(&dkg).unwrap());
+ let pvss_list =
+ messages.iter().map(|(_, pvss)| pvss).cloned().collect_vec();
+ let aggregate = aggregate(&pvss_list).unwrap();
+ assert!(aggregate.verify_aggregation(&dkg, &pvss_list).unwrap());
}
/// Test the happy flow such that the PVSS with the correct form is created
@@ -483,7 +490,7 @@ mod test_pvss {
let rng = &mut ark_std::test_rng();
let security_threshold = shares_num - 1;
- let (dkg, _) = setup_dealt_dkg_with_n_validators(
+ let (dkg, _, _) = setup_dealt_dkg_with_n_validators(
security_threshold,
shares_num,
validators_num,
@@ -556,12 +563,13 @@ mod test_pvss {
#[test_case(4, 6; "number of validators is greater than the number of shares")]
fn test_aggregate_pvss(shares_num: u32, validators_num: u32) {
let security_threshold = shares_num - 1;
- let (dkg, _) = setup_dealt_dkg_with_n_validators(
+ let (dkg, _, messages) = setup_dealt_dkg_with_n_validators(
security_threshold,
shares_num,
validators_num,
);
- let pvss_list = dkg.vss.values().cloned().collect::>();
+ let pvss_list =
+ messages.iter().map(|(_, pvss)| pvss).cloned().collect_vec();
let aggregate = aggregate(&pvss_list).unwrap();
// Check that a polynomial of the correct degree was created
assert_eq!(
@@ -575,25 +583,27 @@ mod test_pvss {
// Check that the full verify returns true
assert!(aggregate.verify_full(&dkg).unwrap());
// Check that the verification of aggregation passes
- assert!(aggregate.verify_aggregation(&dkg).expect("Test failed"));
+ assert!(aggregate
+ .verify_aggregation(&dkg, &pvss_list)
+ .expect("Test failed"));
}
/// Check that if the aggregated PVSS transcript has an
/// incorrect constant term, the verification fails
#[test]
fn test_verify_aggregation_fails_if_constant_term_wrong() {
- let (dkg, _) = setup_dealt_dkg();
- let pvss_list = dkg.vss.values().cloned().collect::>();
+ let (dkg, _, messages) = setup_dealt_dkg();
+ let pvss_list =
+ messages.iter().map(|(_, pvss)| pvss).cloned().collect_vec();
let mut aggregated = aggregate(&pvss_list).unwrap();
while aggregated.coeffs[0] == G1::zero() {
- let (dkg, _) = setup_dkg(0);
- let pvss_list = dkg.vss.values().cloned().collect::>();
+ let (_dkg, _) = setup_dkg(0);
aggregated = aggregate(&pvss_list).unwrap();
}
aggregated.coeffs[0] = G1::zero();
assert_eq!(
aggregated
- .verify_aggregation(&dkg)
+ .verify_aggregation(&dkg, &pvss_list)
.expect_err("Test failed")
.to_string(),
"Transcript aggregate doesn't match the received PVSS instances"
diff --git a/ferveo/src/refresh.rs b/ferveo/src/refresh.rs
index 619eff1c..ddaa8215 100644
--- a/ferveo/src/refresh.rs
+++ b/ferveo/src/refresh.rs
@@ -13,7 +13,7 @@ use rand_core::RngCore;
use serde::{Deserialize, Serialize};
use zeroize::ZeroizeOnDrop;
-use crate::{DomainPoint, Error, Result};
+use crate::{DomainPoint, Error, PubliclyVerifiableParams, Result};
// TODO: Rename refresh.rs to key_share.rs?
@@ -62,14 +62,14 @@ impl PrivateKeyShare {
ciphertext_header: &CiphertextHeader,
aad: &[u8],
validator_keypair: &Keypair,
- g_inv: &E::G1Prepared,
) -> Result> {
+ let g_inv = PubliclyVerifiableParams::::default().g_inv();
DecryptionShareSimple::create(
&validator_keypair.decryption_key,
&self.0,
ciphertext_header,
aad,
- g_inv,
+ &g_inv,
)
.map_err(|e| e.into())
}
diff --git a/ferveo/src/test_common.rs b/ferveo/src/test_common.rs
index d947317c..df28f553 100644
--- a/ferveo/src/test_common.rs
+++ b/ferveo/src/test_common.rs
@@ -9,7 +9,7 @@ use rand::{seq::SliceRandom, Rng};
use crate::{
DkgParams, EthereumAddress, PubliclyVerifiableDkg, PubliclyVerifiableSS,
- Validator,
+ Validator, ValidatorMessage,
};
pub type ScalarField = ::ScalarField;
@@ -77,10 +77,16 @@ pub fn setup_dkg(my_validator_index: usize) -> TestSetup {
)
}
+pub type DealtTestSetup = (
+ PubliclyVerifiableDkg,
+ Vec>,
+ Vec>,
+);
+
/// Set up a dkg with enough pvss transcripts to meet the threshold
///
/// The correctness of this function is tested in the module [`crate::dkg::test_dealing`]
-pub fn setup_dealt_dkg() -> TestSetup {
+pub fn setup_dealt_dkg() -> DealtTestSetup {
setup_dealt_dkg_with(SECURITY_THRESHOLD, SHARES_NUM)
}
@@ -89,7 +95,7 @@ pub fn setup_dealt_dkg() -> TestSetup {
pub fn setup_dealt_dkg_with(
security_threshold: u32,
shares_num: u32,
-) -> TestSetup {
+) -> DealtTestSetup {
setup_dealt_dkg_with_n_validators(
security_threshold,
shares_num,
@@ -101,7 +107,7 @@ pub fn setup_dealt_dkg_with_n_validators(
security_threshold: u32,
shares_num: u32,
validators_num: u32,
-) -> TestSetup {
+) -> DealtTestSetup {
setup_dealt_dkg_with_n_transcript_dealt(
security_threshold,
shares_num,
@@ -129,11 +135,12 @@ pub fn setup_dealt_dkg_with_n_transcript_dealt(
shares_num: u32,
validators_num: u32,
transcripts_to_use: u32,
-) -> TestSetup {
+) -> DealtTestSetup {
let rng = &mut ark_std::test_rng();
// Gather everyone's transcripts
- let mut transcripts: Vec<_> = (0..validators_num)
+ // Use only the first `transcripts_to_use` transcripts
+ let mut transcripts: Vec<_> = (0..transcripts_to_use)
.map(|my_index| {
let (dkg, _) = setup_dkg_for_n_validators(
security_threshold,
@@ -148,23 +155,13 @@ pub fn setup_dealt_dkg_with_n_transcript_dealt(
.collect();
// Create a test DKG instance
- let (mut dkg, keypairs) = setup_dkg_for_n_validators(
+ let (dkg, keypairs) = setup_dkg_for_n_validators(
security_threshold,
shares_num,
0,
validators_num,
);
-
// The ordering of messages should not matter
transcripts.shuffle(rng);
- // Use only the first `transcripts_to_use` transcripts
- transcripts
- .iter()
- .take(transcripts_to_use as usize)
- .for_each(|(sender, message)| {
- // TODO: How to do this in user-facing API?
- // TODO: just return transcripts after getting rid of the dkg.vss
- dkg.vss.insert(sender.address.clone(), message.clone());
- });
- (dkg, keypairs)
+ (dkg, keypairs, transcripts)
}