Skip to content

Commit

Permalink
encrypt voting
Browse files Browse the repository at this point in the history
  • Loading branch information
vincenthz committed Sep 21, 2020
1 parent b4e837b commit f91b3ee
Show file tree
Hide file tree
Showing 16 changed files with 2,446 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -3,6 +3,7 @@ members = [
"imhamt",
"chain-ser",
"chain-core",
"chain-vote",
"chain-addr",
"chain-time",
"chain-crypto",
Expand Down
37 changes: 37 additions & 0 deletions chain-vote/Cargo.toml
@@ -0,0 +1,37 @@
[package]
name = "chain-vote"
version = "0.1.0"
authors = ["Vincent Hanquez <vincent.hanquez@iohk.io>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand_core = "0.5"
cryptoxide = "0.2"
eccoxide = { git = "https://github.com/vincenthz/eccoxide", optional = true }
zerocaf = { version = "0.2", optional = true }
#eccoxide = { path = "/Users/tab/Work/crypto/eccoxide", optional = true }

criterion = { version = "0.3", optional = true }
rand_chacha = { version = "0.2", optional = true }

[dev-dependencies]
rand_chacha = "0.2"
smoke = "^0.2.1"

[features]
default = ["p256k1"]
p256k1 = ["eccoxide"]
ed = ["zerocaf"]
with-bench = ["criterion"]

[[bench]]
harness = false
name = "shvzk"
required-features = ["with-bench"]

[[bench]]
harness = false
name = "gmul"
required-features = ["with-bench"]
11 changes: 11 additions & 0 deletions chain-vote/benches/gmul.rs
@@ -0,0 +1,11 @@
use chain_vote::debug::gang;
use criterion::{criterion_group, criterion_main, Criterion};
use rand_chacha::ChaCha20Rng;

fn mul(c: &mut Criterion) {
let mut g = gang::GroupElement::generator() * gang::Scalar::from_u64(100);
c.bench_function("mul", |b| b.iter(|| &g + &g));
}

criterion_group!(gmul, mul);
criterion_main!(gmul);
45 changes: 45 additions & 0 deletions chain-vote/benches/shvzk.rs
@@ -0,0 +1,45 @@
use chain_vote::debug::{gang, shvzk};
use chain_vote::*;
use criterion::{criterion_group, criterion_main, Criterion};
use rand_chacha::ChaCha20Rng;
use rand_core::SeedableRng;

fn common(rng: &mut ChaCha20Rng) -> (EncryptingVoteKey, EncryptingVote) {
let h = gang::GroupElement::random(rng);

let mc1 = MemberCommunicationKey::new(rng);
let mc = [mc1.to_public()];

let threshold = 1;

let m1 = MemberState::new(rng, threshold, &h, &mc, 0);

let participants = vec![m1.public_key()];
let ek = EncryptingVoteKey::from_participants(&participants);

let vote_options = 2;
let vote = Vote::new(vote_options, 0);

let ev = EncryptingVote::prepare(rng, ek.as_raw(), &vote);
(ek, ev)
}

fn generate(c: &mut Criterion) {
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
let (ek, ev) = common(&mut rng);
c.bench_function("generate", |b| {
b.iter(|| shvzk::prove(&mut rng, ek.as_raw(), ev.clone()))
});
}

fn verify(c: &mut Criterion) {
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
let (ek, ev) = common(&mut rng);
let proof = shvzk::prove(&mut rng, ek.as_raw(), ev.clone());
c.bench_function("verify", |b| {
b.iter(|| shvzk::verify(&ek.as_raw(), &ev.ciphertexts, &proof))
});
}

criterion_group!(shvzk, generate, verify);
criterion_main!(shvzk);
94 changes: 94 additions & 0 deletions chain-vote/src/commitment.rs
@@ -0,0 +1,94 @@
use crate::gang::{GroupElement, Scalar};
use rand_core::{CryptoRng, RngCore};
use std::ops::{Add, Mul};

/// Pedersen commitment
#[derive(Clone, PartialEq, Eq)]
pub struct Commitment {
c: GroupElement,
}

#[derive(Clone)]
pub struct CommitmentKey {
pub h: GroupElement,
}

impl CommitmentKey {
pub fn generate<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let h = GroupElement::random(rng);
CommitmentKey { h }
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Validity {
Valid,
Invalid,
}

#[derive(Clone)]
pub struct Open {
m: Scalar,
r: Scalar,
}

impl Commitment {
pub fn new_open(ck: &CommitmentKey, o: &Open) -> Self {
let c = GroupElement::generator() * &o.m + &ck.h * &o.r;
Commitment { c }
}

pub fn new(ck: &CommitmentKey, m: &Scalar, r: &Scalar) -> Self {
let c = GroupElement::generator() * m + &ck.h * r;
Commitment { c }
}

pub fn verify(&self, ck: &CommitmentKey, o: &Open) -> Validity {
let other = GroupElement::generator() * &o.m + &ck.h * &o.r;
if self.c == other {
Validity::Valid
} else {
Validity::Invalid
}
}
pub fn to_bytes(&self) -> Vec<u8> {
self.c.to_bytes().to_vec()
}
}

impl<'a, 'b> Add<&'b Commitment> for &'a Commitment {
type Output = Commitment;
fn add(self, rhs: &'b Commitment) -> Self::Output {
let c = &self.c + &rhs.c;
Commitment { c }
}
}

impl<'b> Add<&'b Commitment> for Commitment {
type Output = Commitment;
fn add(self, rhs: &'b Commitment) -> Self::Output {
let c = &self.c + &rhs.c;
Commitment { c }
}
}

impl<'a, 'b> Mul<&'b Scalar> for &'a Commitment {
type Output = Commitment;
fn mul(self, rhs: &'b Scalar) -> Self::Output {
Commitment { c: &self.c * rhs }
}
}

impl<'a> Mul<Scalar> for &'a Commitment {
type Output = Commitment;
fn mul(self, rhs: Scalar) -> Self::Output {
Commitment { c: &self.c * rhs }
}
}

impl Mul<Scalar> for Commitment {
type Output = Commitment;
fn mul(self, rhs: Scalar) -> Self::Output {
Commitment { c: &self.c * &rhs }
}
}
144 changes: 144 additions & 0 deletions chain-vote/src/committee.rs
@@ -0,0 +1,144 @@
use crate::commitment::CommitmentKey;
use crate::gang::{GroupElement, Scalar};
use crate::gargamel::{PublicKey, SecretKey};
use crate::hybrid;
use crate::math::Polynomial;
use rand_core::{CryptoRng, RngCore};

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

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

#[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);

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<GroupElement>,
es: Vec<GroupElement>,
encrypted: Vec<(hybrid::Encrypted, hybrid::Encrypted)>,
}

pub type CRS = GroupElement;

impl MemberState {
/// Generate a new member state from random, where the number
pub fn new<R: RngCore + CryptoRng>(
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();
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 ck_comm = CommitmentKey::generate(rng);
let ck_shek = CommitmentKey::generate(rng);

let rcomm = Scalar::random(rng);
let rshek = Scalar::random(rng);
let ecomm = hybrid::encrypt(&pk.0, &ck_comm, &share_comm.to_bytes(), &rcomm);
let eshek = hybrid::encrypt(&pk.0, &ck_shek, &share_shek.to_bytes(), &rshek);

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 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,
})
}
}

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;
}
ElectionPublicKey(PublicKey { pk: k })
}
}

0 comments on commit f91b3ee

Please sign in to comment.