Skip to content

Commit

Permalink
mockchain modifs
Browse files Browse the repository at this point in the history
  • Loading branch information
iquerejeta committed Jun 8, 2021
1 parent 29779f5 commit ea26cbd
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 157 deletions.
3 changes: 2 additions & 1 deletion chain-impl-mockchain/src/certificate/test.rs
Expand Up @@ -189,7 +189,8 @@ 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());
}

Expand Down
7 changes: 4 additions & 3 deletions chain-impl-mockchain/src/testing/data/vote.rs
@@ -1,7 +1,8 @@
use crate::vote::VotePlanStatus;
use chain_vote::{
committee::MemberSecretKey, Crs, MemberCommunicationKey, MemberPublicKey, MemberState,
MemberSecretKey, Crs, MemberCommunicationKey, MemberPublicKey,
TallyDecryptShare,
DistributedKeyGeneration,
};
use rand_core::CryptoRng;
use rand_core::RngCore;
Expand All @@ -11,7 +12,7 @@ pub struct CommitteeMembersManager {
}

pub struct CommitteeMember {
state: MemberState,
state: DistributedKeyGeneration,
}

impl CommitteeMembersManager {
Expand All @@ -32,7 +33,7 @@ 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 })
}

Expand Down
5 changes: 3 additions & 2 deletions chain-impl-mockchain/src/vote/payload.rs
Expand Up @@ -205,7 +205,7 @@ mod tests {
impl Arbitrary for Payload {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
use chain_vote::{
encrypt_vote, Crs, EncryptingVoteKey, MemberCommunicationKey, MemberState, Vote,
encrypt_vote, Crs, EncryptingVoteKey, MemberCommunicationKey, DistributedKeyGeneration, Vote,
};
use rand_core::SeedableRng;

Expand All @@ -217,8 +217,9 @@ 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;
Expand Down
216 changes: 71 additions & 145 deletions chain-vote/src/committee.rs → chain-vote/src/dkg/committee.rs
Expand Up @@ -12,58 +12,61 @@ use crate::math::Polynomial;
use crate::Crs;
use crate::errors::DkgError;
use rand_core::{CryptoRng, RngCore};

/// Committee member election secret key
#[derive(Clone)]
pub struct MemberSecretKey(pub(crate) SecretKey);

/// Committee member election public key
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MemberPublicKey(pub(crate) PublicKey);

/// Committee member communication private key
#[derive(Clone)]
pub struct MemberCommunicationKey(SecretKey);

/// Committee Member communication public key (with other committee members)
#[derive(Clone)]
pub struct MemberCommunicationPublicKey(PublicKey);

/// The overall committee public key used for everyone to encrypt their vote to.
#[derive(Clone)]
pub struct ElectionPublicKey(pub(crate) PublicKey);
use super::procedure_keys::{MemberCommunicationKey, MemberPublicKey, MemberSecretKey, MemberCommunicationPublicKey};

pub type DistributedKeyGeneration = MemberState1;

/// Initial state generated by a Member, corresponding to round 1.
#[derive(Clone)]
pub struct MemberState1 {
sk: MemberSecretKey,
sk_share: MemberSecretKey,
threshold: usize,
nr_members: usize,
owner_index: usize,
crs: Crs,
apubs: Vec<GroupElement>,
es: Vec<GroupElement>,
encrypted: Vec<IndexedEncryptedShares>,
coeff_comms: Vec<GroupElement>,
encrypted_shares: Vec<IndexedEncryptedShares>,
}

/// State of the member corresponding to round 2.
#[derive(Clone)]
pub struct MemberState2 {
threshold: usize,
misbehaving_parties: Vec<MisbehavingPartiesState1>,
}

// state of members, with the index, the hybrid ctxts and the commitment to
type MembersFetchedState1 = (IndexedEncryptedShares, Vec<GroupElement>);
type IndexedEncryptedShares = (usize, HybridCiphertext, HybridCiphertext);
// todo: third element should be a proof of misbehaviour.
/// 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<GroupElement>
}

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.
/// `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<R: RngCore + CryptoRng>(
rng: &mut R,
t: usize,
Expand All @@ -81,14 +84,14 @@ impl MemberState1 {
let pcomm = Polynomial::random(rng, t);
let pshek = Polynomial::random(rng, t);

let mut coeff_comm = Vec::with_capacity(t);
let mut es = Vec::with_capacity(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 e = &apub + crs * bi;
coeff_comm.push(apub);
es.push(e);
let coeff_comm = &apub + crs * bi;
apubs.push(apub);
coeff_comms.push(coeff_comm);
}

let mut encrypted_shares: Vec<IndexedEncryptedShares> = Vec::with_capacity(n - 1);
Expand All @@ -104,72 +107,65 @@ impl MemberState1 {

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);
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: MemberSecretKey(SecretKey {
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_comm,
es,
encrypted: encrypted_shares,
apubs,
coeff_comms,
encrypted_shares,
}
}

// todo: is vectors a correct way to handle the indexed members (e.g.: coeff_comms and pks in
// a vec will certainly enduce errors)?
/// 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: &Vec<MembersFetchedState1>,
) -> Result<MemberState2, DkgError> {
) -> MemberState2 {
let mut misbehaving_parties: Vec<MisbehavingPartiesState1> = Vec::new();
for fetched_data in members_state {
let comm_scalar = Scalar::from_bytes(
&secret_key.0.hybrid_decrypt(&fetched_data.0.1));
let shek_scalar = Scalar::from_bytes(
&secret_key.0.hybrid_decrypt(&fetched_data.0.2));

if let (Some(comm), Some(shek)) = (comm_scalar, shek_scalar) {
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.1.clone());
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.1.clone());
let multi_scalar = GroupElement::multiscalar_multiplication(index_pow, fetched_data.committed_coeffs.clone());

if check_element != multi_scalar {
misbehaving_parties.push((fetched_data.0.0.clone(), DkgError::ShareValidityFailed, 0));
// todo: should we instead store the sender's index?
misbehaving_parties.push((fetched_data.get_index().clone(), DkgError::ShareValidityFailed, 0));
}
}
else {
// todo: handle the proofs. Might not be the most optimal way of handling these two
misbehaving_parties.push((fetched_data.0.0.clone(), DkgError::ScalarOutOfBounds, 0));
misbehaving_parties.push((fetched_data.get_index().clone(), DkgError::ScalarOutOfBounds, 0));
}
}

if misbehaving_parties.len() == self.threshold {
return Err(DkgError::MisbehaviourHigherThreshold);
}

Ok(MemberState2{misbehaving_parties})
MemberState2{misbehaving_parties, threshold: self.threshold}

}

pub fn secret_key(&self) -> &MemberSecretKey {
&self.sk
&self.sk_share
}

pub fn public_key(&self) -> MemberPublicKey {
Expand All @@ -179,91 +175,13 @@ impl MemberState1 {
}
}

impl MemberSecretKey {
pub fn to_bytes(&self) -> [u8; 32] {
self.0.sk.to_bytes()
}

pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
let sk = Scalar::from_bytes(bytes)?;
Some(Self(SecretKey { sk }))
}
}

impl MemberPublicKey {
pub const BYTES_LEN: usize = PublicKey::BYTES_LEN;

pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes()
}

pub fn from_bytes(buf: &[u8]) -> Option<Self> {
Some(Self(PublicKey::from_bytes(buf)?))
}
}

impl From<PublicKey> for MemberPublicKey {
fn from(pk: PublicKey) -> MemberPublicKey {
MemberPublicKey(pk)
}
}

impl MemberCommunicationKey {
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let sk = SecretKey::generate(rng);
MemberCommunicationKey(sk)
}

pub fn to_public(&self) -> MemberCommunicationPublicKey {
MemberCommunicationPublicKey(PublicKey {
pk: &GroupElement::generator() * &self.0.sk,
})
}

pub fn from_bytes(bytes: &[u8]) -> Option<MemberCommunicationKey> {
SecretKey::from_bytes(bytes).map(MemberCommunicationKey)
}

pub fn to_bytes(&self) -> [u8; 32] {
self.0.sk.to_bytes()
}
}

impl MemberCommunicationPublicKey {
pub fn from_public_key(pk: PublicKey) -> Self {
Self(pk)
}

pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes()
}

pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
PublicKey::from_bytes(bytes).map(Self)
}
}

impl ElectionPublicKey {
/// Create an election public key from all the participants of this committee
pub fn from_participants(pks: &[MemberPublicKey]) -> Self {
let mut k = pks[0].0.pk.clone();
for pk in &pks[1..] {
k = k + &pk.0.pk;
impl MemberState2 {
pub fn validate(&self) -> Result<Self, DkgError> {
if self.misbehaving_parties.len() == self.threshold {
return Err(DkgError::MisbehaviourHigherThreshold);
}
ElectionPublicKey(PublicKey { pk: k })
}

pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes()
}

pub fn from_bytes(buf: &[u8]) -> Option<Self> {
PublicKey::from_bytes(buf).map(ElectionPublicKey)
}

#[doc(hidden)]
pub fn as_raw(&self) -> &PublicKey {
&self.0
Ok(self.clone())
}
}

Expand Down Expand Up @@ -292,11 +210,14 @@ mod tests {
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![(m2.encrypted[0].clone(), m2.es.clone())];
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.is_ok());
assert!(phase_2.validate().is_ok());
}
#[test]
fn invalid_phase_2() {
Expand All @@ -320,11 +241,16 @@ mod tests {

// Now, party one fetches invalid state of the other parties, mainly party two and three
let fetched_state = vec![
(m2.encrypted[0].clone(), vec![GroupElement::zero(); 3]),
(m3.encrypted[0].clone(), vec![GroupElement::zero(); 3])];
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.is_err());
assert!(phase_2_faked.validate().is_err());
}
}
2 changes: 2 additions & 0 deletions chain-vote/src/dkg/mod.rs
@@ -0,0 +1,2 @@
pub mod committee;
pub mod procedure_keys;

0 comments on commit ea26cbd

Please sign in to comment.