diff --git a/chain-impl-mockchain/src/certificate/test.rs b/chain-impl-mockchain/src/certificate/test.rs index a14092da9..dbb397b22 100644 --- a/chain-impl-mockchain/src/certificate/test.rs +++ b/chain-impl-mockchain/src/certificate/test.rs @@ -189,7 +189,15 @@ impl Arbitrary for VotePlan { for _i in 0..keys_n { let mc = chain_vote::MemberCommunicationKey::new(&mut rng); let threshold = 1; - let m1 = chain_vote::MemberState::new(&mut rng, threshold, &h, &[mc.to_public()], 0); + let nr_members = 1; + let m1 = chain_vote::DistributedKeyGeneration::init( + &mut rng, + threshold, + nr_members, + &h, + &[mc.to_public()], + 0, + ); keys.push(m1.public_key()); } diff --git a/chain-impl-mockchain/src/testing/data/vote.rs b/chain-impl-mockchain/src/testing/data/vote.rs index f79d496c8..b4375465e 100644 --- a/chain-impl-mockchain/src/testing/data/vote.rs +++ b/chain-impl-mockchain/src/testing/data/vote.rs @@ -1,6 +1,6 @@ use crate::vote::VotePlanStatus; use chain_vote::{ - committee::MemberSecretKey, Crs, MemberCommunicationKey, MemberPublicKey, MemberState, + Crs, DistributedKeyGeneration, MemberCommunicationKey, MemberPublicKey, MemberSecretKey, TallyDecryptShare, }; use rand_core::CryptoRng; @@ -11,7 +11,7 @@ pub struct CommitteeMembersManager { } pub struct CommitteeMember { - state: MemberState, + state: DistributedKeyGeneration, } impl CommitteeMembersManager { @@ -32,7 +32,8 @@ impl CommitteeMembersManager { let mut members = Vec::new(); for i in 0..members_no { - let state = MemberState::new(rng, threshold, &crs, &public_keys, i); + let state = + DistributedKeyGeneration::init(rng, threshold, members_no, &crs, &public_keys, i); members.push(CommitteeMember { state }) } diff --git a/chain-impl-mockchain/src/vote/payload.rs b/chain-impl-mockchain/src/vote/payload.rs index 78fff5c35..eb738fdd5 100644 --- a/chain-impl-mockchain/src/vote/payload.rs +++ b/chain-impl-mockchain/src/vote/payload.rs @@ -205,7 +205,8 @@ mod tests { impl Arbitrary for Payload { fn arbitrary(g: &mut G) -> Self { use chain_vote::{ - encrypt_vote, Crs, EncryptingVoteKey, MemberCommunicationKey, MemberState, Vote, + encrypt_vote, Crs, DistributedKeyGeneration, EncryptingVoteKey, + MemberCommunicationKey, Vote, }; use rand_core::SeedableRng; @@ -217,8 +218,16 @@ mod tests { let mut gen = rand_chacha::ChaCha20Rng::from_seed(seed); let mc = MemberCommunicationKey::new(&mut gen); let threshold = 1; + let nr_members = 1; let h = Crs::from_hash(&mut seed); - let m = MemberState::new(&mut gen, threshold, &h, &[mc.to_public()], 0); + let m = DistributedKeyGeneration::init( + &mut gen, + threshold, + nr_members, + &h, + &[mc.to_public()], + 0, + ); let participants = vec![m.public_key()]; let ek = EncryptingVoteKey::from_participants(&participants); let vote_options = 3; diff --git a/chain-vote/benches/shvzk.rs b/chain-vote/benches/shvzk.rs index 2c83fc8cf..237359086 100644 --- a/chain-vote/benches/shvzk.rs +++ b/chain-vote/benches/shvzk.rs @@ -10,8 +10,9 @@ fn common(rng: &mut ChaCha20Rng) -> (EncryptingVoteKey, EncryptingVote) { let mc = [mc1.to_public()]; let threshold = 1; + let nr_members = 1; - let m1 = MemberState::new(rng, threshold, &h, &mc, 0); + let m1 = DistributedKeyGeneration::init(rng, threshold, nr_members, &h, &mc, 0); let participants = vec![m1.public_key()]; let ek = EncryptingVoteKey::from_participants(&participants); diff --git a/chain-vote/src/dkg/committee.rs b/chain-vote/src/dkg/committee.rs new file mode 100644 index 000000000..f1e3b764a --- /dev/null +++ b/chain-vote/src/dkg/committee.rs @@ -0,0 +1,276 @@ +//! Implementation of the distributed key generation (DKG) +//! procedure presented by Gennaro, Jarecki, Krawczyk and Rabin in +//! ["Secure distributed key generation for discrete-log based cryptosystems."](https://link.springer.com/article/10.1007/s00145-006-0347-3). +//! The distinction with the original protocol lies in the use of hybrid +//! encryption. We use the description and notation presented in the technical +//! [spec](https://github.com/input-output-hk/treasury-crypto/blob/master/docs/voting_protocol_spec/Treasury_voting_protocol_spec.pdf), +//! written by Dmytro Kaidalov. + +use super::procedure_keys::{ + MemberCommunicationKey, MemberCommunicationPublicKey, MemberPublicKey, MemberSecretKey, +}; +use crate::encryption::{HybridCiphertext, PublicKey, SecretKey}; +use crate::errors::DkgError; +use crate::gang::{GroupElement, Scalar}; +use crate::math::Polynomial; +use crate::Crs; +use rand_core::{CryptoRng, RngCore}; + +pub type DistributedKeyGeneration = MemberState1; + +/// Initial state generated by a Member, corresponding to round 1. +#[derive(Clone)] +pub struct MemberState1 { + sk_share: MemberSecretKey, + threshold: usize, + nr_members: usize, + owner_index: usize, + crs: Crs, + apubs: Vec, + coeff_comms: Vec, + encrypted_shares: Vec, +} + +/// State of the member corresponding to round 2. +#[derive(Clone)] +pub struct MemberState2 { + threshold: usize, + misbehaving_parties: Vec, +} + +/// Type that contains the index of the receiver, and its two encrypted +/// shares. +pub(crate) type IndexedEncryptedShares = (usize, HybridCiphertext, HybridCiphertext); + +// todo: third element should be a proof of misbehaviour. waiting for PR542 to resolve +/// Type that contains misbehaving parties detected in round 1. These +/// consist of the misbehaving member's index, the error which failed, +/// and a proof of correctness of the misbehaviour claim. +type MisbehavingPartiesState1 = (usize, DkgError, usize); + +/// State of the members after round 1. This structure contains the indexed encrypted +/// shares of every other participant, `indexed_shares`, and the committed coefficients +/// of the generated polynomials, `committed_coeffs`. +#[derive(Clone)] +pub struct MembersFetchedState1 { + indexed_shares: IndexedEncryptedShares, + committed_coeffs: Vec, +} + +impl MembersFetchedState1 { + fn get_index(&self) -> usize { + self.indexed_shares.0 + } +} + +impl MemberState1 { + /// Generate a new member state from random. This is round 1 of the protocol. Receives as + /// input the threshold `t`, the expected number of participants, `n`, common reference string + /// `crs`, `committee_pks`, and the party's index `my`. Initiates a Pedersen-VSS as a dealer, + /// and returns the committed coefficients of its polynomials, together with encryption of the + /// shares of the other different members. + pub fn init( + rng: &mut R, + t: usize, + n: usize, + crs: &Crs, // TODO: document + committee_pks: &[MemberCommunicationPublicKey], + my: usize, + ) -> MemberState1 { + assert_eq!(committee_pks.len(), n); + assert!(t > 0); + assert!(t <= n); + assert!(t > n / 2); + assert!(my < n); + + let pcomm = Polynomial::random(rng, t); + let pshek = Polynomial::random(rng, t); + + let mut apubs = Vec::with_capacity(t); + let mut coeff_comms = Vec::with_capacity(t); + + for (ai, bi) in pshek.get_coefficients().zip(pcomm.get_coefficients()) { + let apub = GroupElement::generator() * ai; + let coeff_comm = &apub + crs * bi; + apubs.push(apub); + coeff_comms.push(coeff_comm); + } + + let mut encrypted_shares: Vec = Vec::with_capacity(n - 1); + #[allow(clippy::needless_range_loop)] + for i in 0..n { + // don't generate share for self + if i == my { + continue; + } else { + let idx = Scalar::from_u64((i + 1) as u64); + let share_comm = pcomm.evaluate(&idx); + let share_shek = pshek.evaluate(&idx); + + let pk = &committee_pks[i]; + + let ecomm = pk.hybrid_encrypt(&share_comm.to_bytes(), rng); + let eshek = pk.hybrid_encrypt(&share_shek.to_bytes(), rng); + + encrypted_shares.push((i, ecomm, eshek)); + } + } + + MemberState1 { + sk_share: MemberSecretKey(SecretKey { + sk: pshek.at_zero(), + }), + crs: crs.clone(), + threshold: t, + nr_members: n, + owner_index: my + 1, // committee member are 1-indexed + apubs, + coeff_comms, + encrypted_shares, + } + } + + /// Function to proceed to phase 2. It checks and keeps track of misbehaving parties. If this + /// step does not validate, the member is not allowed to proceed to phase 3. + pub fn to_phase_2( + &self, + secret_key: &MemberCommunicationKey, + members_state: &[MembersFetchedState1], + ) -> MemberState2 { + let mut misbehaving_parties: Vec = Vec::new(); + for fetched_data in members_state { + if let (Some(comm), Some(shek)) = + secret_key.decrypt_shares(fetched_data.indexed_shares.clone()) + { + let index_pow = Scalar::from_u64(self.owner_index as u64) + .exp_iter() + .take(self.threshold + 1); + + let check_element = GroupElement::generator() * shek + &self.crs * comm; + #[cfg(feature = "ristretto255")] + let multi_scalar = GroupElement::vartime_multiscalar_multiplication( + index_pow, + fetched_data.committed_coeffs.clone(), + ); + #[cfg(not(feature = "ristretto255"))] + let multi_scalar = GroupElement::multiscalar_multiplication( + index_pow, + fetched_data.committed_coeffs.clone(), + ); + + if check_element != multi_scalar { + // todo: should we instead store the sender's index? + misbehaving_parties.push(( + fetched_data.get_index(), + DkgError::ShareValidityFailed, + 0, + )); + } + } else { + // todo: handle the proofs. Might not be the most optimal way of handling these two + misbehaving_parties.push(( + fetched_data.get_index(), + DkgError::ScalarOutOfBounds, + 0, + )); + } + } + + MemberState2 { + misbehaving_parties, + threshold: self.threshold, + } + } + + pub fn secret_key(&self) -> &MemberSecretKey { + &self.sk_share + } + + pub fn public_key(&self) -> MemberPublicKey { + MemberPublicKey(PublicKey { + pk: self.apubs[0].clone(), + }) + } +} + +impl MemberState2 { + pub fn validate(&self) -> Result { + if self.misbehaving_parties.len() == self.threshold { + return Err(DkgError::MisbehaviourHigherThreshold); + } + + Ok(self.clone()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rand_chacha::ChaCha20Rng; + use rand_core::SeedableRng; + + #[test] + fn valid_phase_2() { + let mut rng = ChaCha20Rng::from_seed([0u8; 32]); + + let mut shared_string = + b"Example of a shared string. This should be VotePlan.to_id()".to_owned(); + let h = Crs::from_hash(&mut shared_string); + + let mc1 = MemberCommunicationKey::new(&mut rng); + let mc2 = MemberCommunicationKey::new(&mut rng); + let mc = [mc1.to_public(), mc2.to_public()]; + + let threshold = 2; + let nr_members = 2; + + let m1 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 0); + let m2 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 1); + + // Now, party one fetches the state of the other parties, mainly party two and three + let fetched_state = vec![MembersFetchedState1 { + indexed_shares: m2.encrypted_shares[0].clone(), + committed_coeffs: m2.coeff_comms.clone(), + }]; + + let phase_2 = m1.to_phase_2(&mc1, &fetched_state); + + assert!(phase_2.validate().is_ok()); + } + #[test] + fn invalid_phase_2() { + let mut rng = ChaCha20Rng::from_seed([0u8; 32]); + + let mut shared_string = + b"Example of a shared string. This should be VotePlan.to_id()".to_owned(); + let h = Crs::from_hash(&mut shared_string); + + let mc1 = MemberCommunicationKey::new(&mut rng); + let mc2 = MemberCommunicationKey::new(&mut rng); + let mc3 = MemberCommunicationKey::new(&mut rng); + let mc = [mc1.to_public(), mc2.to_public(), mc3.to_public()]; + + let threshold = 2; + let nr_members = 3; + + let m1 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 0); + let m2 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 1); + let m3 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 2); + + // Now, party one fetches invalid state of the other parties, mainly party two and three + let fetched_state = vec![ + MembersFetchedState1 { + indexed_shares: m2.encrypted_shares[0].clone(), + committed_coeffs: vec![GroupElement::zero(); 3], + }, + MembersFetchedState1 { + indexed_shares: m3.encrypted_shares[0].clone(), + committed_coeffs: vec![GroupElement::zero(); 3], + }, + ]; + + let phase_2_faked = m1.to_phase_2(&mc1, &fetched_state); + // todo: we probably want to check for a particular error here + assert!(phase_2_faked.validate().is_err()); + } +} diff --git a/chain-vote/src/dkg/mod.rs b/chain-vote/src/dkg/mod.rs new file mode 100644 index 000000000..c7d25336f --- /dev/null +++ b/chain-vote/src/dkg/mod.rs @@ -0,0 +1,2 @@ +pub mod committee; +pub mod procedure_keys; diff --git a/chain-vote/src/committee.rs b/chain-vote/src/dkg/procedure_keys.rs similarity index 53% rename from chain-vote/src/committee.rs rename to chain-vote/src/dkg/procedure_keys.rs index 7dcdc73a8..164173059 100644 --- a/chain-vote/src/committee.rs +++ b/chain-vote/src/dkg/procedure_keys.rs @@ -1,7 +1,6 @@ +use super::committee::IndexedEncryptedShares; use crate::encryption::{HybridCiphertext, PublicKey, SecretKey}; use crate::gang::{GroupElement, Scalar}; -use crate::math::Polynomial; -use crate::Crs; use rand_core::{CryptoRng, RngCore}; /// Committee member election secret key @@ -12,6 +11,7 @@ pub struct MemberSecretKey(pub(crate) SecretKey); #[derive(Debug, Clone, Eq, PartialEq)] pub struct MemberPublicKey(pub(crate) PublicKey); +/// Committee member communication private key #[derive(Clone)] pub struct MemberCommunicationKey(SecretKey); @@ -23,96 +23,6 @@ pub struct MemberCommunicationPublicKey(PublicKey); #[derive(Clone)] pub struct ElectionPublicKey(pub(crate) PublicKey); -impl ElectionPublicKey { - #[doc(hidden)] - pub fn as_raw(&self) -> &PublicKey { - &self.0 - } -} - -/// Initial state generated by a Member, which include keys for this election -#[derive(Clone)] -pub struct MemberState { - sk: MemberSecretKey, - owner_index: usize, - apubs: Vec, - es: Vec, - encrypted: Vec<(HybridCiphertext, HybridCiphertext)>, -} - -impl MemberState { - /// Generate a new member state from random, where the number - pub fn new( - rng: &mut R, - t: usize, - h: &Crs, // TODO: document - committee_pks: &[MemberCommunicationPublicKey], - my: usize, - ) -> MemberState { - let n = committee_pks.len(); - assert!(t > 0); - assert!(t <= n); - assert!(my < n); - - let pcomm = Polynomial::random(rng, t); - let pshek = Polynomial::random(rng, t); - - let mut apubs = Vec::new(); - let mut es = Vec::new(); - - for (ai, bi) in pshek.get_coefficients().zip(pcomm.get_coefficients()) { - let apub = GroupElement::generator() * ai; - let e = &apub + h * bi; - apubs.push(apub); - es.push(e); - } - - let mut encrypted = Vec::new(); - #[allow(clippy::needless_range_loop)] - for i in 0..n { - // don't generate share for self - if i == my { - continue; - } else { - let idx = Scalar::from_u64((i + 1) as u64); - let share_comm = pcomm.evaluate(&idx); - let share_shek = pshek.evaluate(&idx); - - let pk = &committee_pks[i]; - - let ecomm = pk.0.hybrid_encrypt(&share_comm.to_bytes(), rng); - let eshek = pk.0.hybrid_encrypt(&share_shek.to_bytes(), rng); - - encrypted.push((ecomm, eshek)); - } - } - - assert_eq!(apubs.len(), t + 1); - assert_eq!(es.len(), t + 1); - assert_eq!(encrypted.len(), n - 1); - - MemberState { - sk: MemberSecretKey(SecretKey { - sk: pshek.at_zero(), - }), - owner_index: my + 1, // committee member are 1-indexed - apubs, - es, - encrypted, - } - } - - pub fn secret_key(&self) -> &MemberSecretKey { - &self.sk - } - - pub fn public_key(&self) -> MemberPublicKey { - MemberPublicKey(PublicKey { - pk: self.apubs[0].clone(), - }) - } -} - impl MemberSecretKey { pub fn to_bytes(&self) -> [u8; 32] { self.0.sk.to_bytes() @@ -161,6 +71,20 @@ impl MemberCommunicationKey { pub fn to_bytes(&self) -> [u8; 32] { self.0.sk.to_bytes() } + + pub fn hybrid_decrypt(&self, ciphertext: &HybridCiphertext) -> Vec { + self.0.hybrid_decrypt(ciphertext) + } + + pub(crate) fn decrypt_shares( + &self, + shares: IndexedEncryptedShares, + ) -> (Option, Option) { + let comm_scalar = Scalar::from_bytes(&self.hybrid_decrypt(&shares.1)); + let shek_scalar = Scalar::from_bytes(&self.hybrid_decrypt(&shares.2)); + + (comm_scalar, shek_scalar) + } } impl MemberCommunicationPublicKey { @@ -171,6 +95,17 @@ impl MemberCommunicationPublicKey { pub fn to_bytes(&self) -> Vec { self.0.to_bytes() } + + pub fn from_bytes(bytes: &[u8]) -> Option { + PublicKey::from_bytes(bytes).map(Self) + } + + pub fn hybrid_encrypt(&self, message: &[u8], rng: &mut R) -> HybridCiphertext + where + R: RngCore + CryptoRng, + { + self.0.hybrid_encrypt(message, rng) + } } impl ElectionPublicKey { @@ -190,4 +125,9 @@ impl ElectionPublicKey { pub fn from_bytes(buf: &[u8]) -> Option { PublicKey::from_bytes(buf).map(ElectionPublicKey) } + + #[doc(hidden)] + pub fn as_raw(&self) -> &PublicKey { + &self.0 + } } diff --git a/chain-vote/src/encryption.rs b/chain-vote/src/encryption.rs index d58a40760..f61b97bf2 100644 --- a/chain-vote/src/encryption.rs +++ b/chain-vote/src/encryption.rs @@ -11,6 +11,7 @@ use std::ops::{Add, Mul, Sub}; use cryptoxide::blake2b::Blake2b; use cryptoxide::chacha20::ChaCha20; use cryptoxide::digest::Digest; +use std::fmt; #[derive(Debug, Clone, Eq, PartialEq)] /// ElGamal public key. pk = sk * G, where sk is the `SecretKey` and G is the group @@ -48,6 +49,12 @@ pub struct HybridCiphertext { e2: Box<[u8]>, } +impl fmt::Debug for HybridCiphertext { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Point: {:?}\nBox: {:?}", self.e1.to_bytes(), self.e2) + } +} + /// The hybrid encryption scheme uses a group element as a /// representation of the symmetric key. This facilitates /// its exchange using ElGamal encryption. diff --git a/chain-vote/src/errors.rs b/chain-vote/src/errors.rs new file mode 100644 index 000000000..26724ae73 --- /dev/null +++ b/chain-vote/src/errors.rs @@ -0,0 +1,16 @@ +/// Represents an error in Distributed Key Generation protocol. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "std", derive(Error))] +pub enum DkgError { + /// This error occurs when a scalar parsing failed, due to the + /// byte-array representing a scalar out of bounds. + #[cfg_attr(feature = "std", error("Scalar out of bounds."))] + ScalarOutOfBounds, + /// This error occurs when the check of validity of the shares + /// fails. + #[cfg_attr(feature = "std", error("Share validity check failed."))] + ShareValidityFailed, + /// This error occurs when too many members misbehaved. + #[cfg_attr(feature = "std", error("Misbehaviours higher than threshold."))] + MisbehaviourHigherThreshold, +} diff --git a/chain-vote/src/gang/p256k1.rs b/chain-vote/src/gang/p256k1.rs index 336050590..1aaa2e08e 100644 --- a/chain-vote/src/gang/p256k1.rs +++ b/chain-vote/src/gang/p256k1.rs @@ -147,6 +147,20 @@ impl GroupElement { } sum } + + /// Non-optimised multiscalar multiplication. If we use the sec2 backend, this function could + /// be optimised. + pub fn multiscalar_multiplication(scalars: I, points: J) -> Self + where + I: IntoIterator, + J: IntoIterator, + { + let mut sum = GroupElement::zero(); + for (scalar, point) in scalars.into_iter().zip(points.into_iter()) { + sum = sum + scalar * point; + } + sum + } } impl Scalar { diff --git a/chain-vote/src/gang/ristretto255.rs b/chain-vote/src/gang/ristretto255.rs index 9a1716d6f..065e47fc5 100644 --- a/chain-vote/src/gang/ristretto255.rs +++ b/chain-vote/src/gang/ristretto255.rs @@ -81,7 +81,11 @@ impl GroupElement { } sum } - pub fn multiscalar_multiplication(scalars: I, points: J) -> Self + + /// Variable time multiscalar multiplication. Takes as input an iterator of scalar, and an + /// iterator over group elements, and computes a variable time multiscalar operation. Should + /// only be used when the scalar are not secret. + pub fn vartime_multiscalar_multiplication(scalars: I, points: J) -> Self where I: IntoIterator, J: IntoIterator, diff --git a/chain-vote/src/lib.rs b/chain-vote/src/lib.rs index 6e17ea0a6..73a097c97 100644 --- a/chain-vote/src/lib.rs +++ b/chain-vote/src/lib.rs @@ -3,9 +3,10 @@ #[macro_use] mod macros; mod commitment; -pub mod committee; +mod dkg; mod encrypted; pub mod encryption; +mod errors; mod gang; mod math; pub mod private_voting; @@ -22,8 +23,9 @@ pub mod debug { } } -pub use committee::{ - MemberCommunicationKey, MemberCommunicationPublicKey, MemberPublicKey, MemberState, +pub use dkg::committee::DistributedKeyGeneration; +pub use dkg::procedure_keys::{ + MemberCommunicationKey, MemberCommunicationPublicKey, MemberPublicKey, MemberSecretKey, }; pub use encrypted::EncryptingVote; pub use encryption::Ciphertext; @@ -33,10 +35,10 @@ use rand_core::{CryptoRng, RngCore}; pub use unit_vector::UnitVector; /// Secret key for opening vote -pub type OpeningVoteKey = committee::MemberSecretKey; +pub type OpeningVoteKey = dkg::procedure_keys::MemberSecretKey; /// Public Key for the vote -pub type EncryptingVoteKey = committee::ElectionPublicKey; +pub type EncryptingVoteKey = dkg::procedure_keys::ElectionPublicKey; /// A vote is represented by a standard basis unit vector of a N dimension space /// @@ -306,8 +308,9 @@ mod tests { let mc = [mc1.to_public()]; let threshold = 1; + let nr_members = 1; - let m1 = MemberState::new(&mut rng, threshold, &h, &mc, 0); + let m1 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 0); let participants = vec![m1.public_key()]; let ek = EncryptingVoteKey::from_participants(&participants); @@ -359,10 +362,11 @@ mod tests { let mc = [mc1.to_public(), mc2.to_public(), mc3.to_public()]; let threshold = 3; + let nr_members = 3; - let m1 = MemberState::new(&mut rng, threshold, &h, &mc, 0); - let m2 = MemberState::new(&mut rng, threshold, &h, &mc, 1); - let m3 = MemberState::new(&mut rng, threshold, &h, &mc, 2); + let m1 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 0); + let m2 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 1); + let m3 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 2); let participants = vec![m1.public_key(), m2.public_key(), m3.public_key()]; let ek = EncryptingVoteKey::from_participants(&participants); @@ -415,8 +419,9 @@ mod tests { let mc = [mc1.to_public()]; let threshold = 1; + let nr_members = 1; - let m1 = MemberState::new(&mut rng, threshold, &h, &mc, 0); + let m1 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 0); let participants = vec![m1.public_key()]; let ek = EncryptingVoteKey::from_participants(&participants); @@ -462,8 +467,9 @@ mod tests { let mc = [mc1.to_public()]; let threshold = 1; + let nr_members = 1; - let m1 = MemberState::new(&mut rng, threshold, &h, &mc, 0); + let m1 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 0); let vote_options = 2; @@ -503,10 +509,11 @@ mod tests { let mc = [mc1.to_public(), mc2.to_public(), mc3.to_public()]; let threshold = 3; + let nr_members = 3; - let m1 = MemberState::new(&mut rng, threshold, &h, &mc, 0); - let m2 = MemberState::new(&mut rng, threshold, &h, &mc, 1); - let m3 = MemberState::new(&mut rng, threshold, &h, &mc, 2); + let m1 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 0); + let m2 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 1); + let m3 = DistributedKeyGeneration::init(&mut rng, threshold, nr_members, &h, &mc, 2); let participants = vec![m1.public_key(), m2.public_key(), m3.public_key()]; let ek = EncryptingVoteKey::from_participants(&participants); diff --git a/chain-vote/src/private_voting/unit_vector_zkp.rs b/chain-vote/src/private_voting/unit_vector_zkp.rs index 5d70d25e6..fa7b3fef2 100644 --- a/chain-vote/src/private_voting/unit_vector_zkp.rs +++ b/chain-vote/src/private_voting/unit_vector_zkp.rs @@ -192,7 +192,7 @@ impl Proof { let batch_challenge = Scalar::random(&mut thread_rng()); for (zwv, iba) in self.zwvs.iter().zip(self.ibas.iter()) { - if GroupElement::multiscalar_multiplication( + if GroupElement::vartime_multiscalar_multiplication( iter::once(zwv.z) .chain(iter::once(zwv.w + batch_challenge * zwv.v)) .chain(iter::once( @@ -211,7 +211,7 @@ impl Proof { } } - let mega_check = GroupElement::multiscalar_multiplication( + let mega_check = GroupElement::vartime_multiscalar_multiplication( powers_cy .take(length) .map(|s| s * cx_pow)