Skip to content

Commit

Permalink
Merge pull request #57 from Yoii-Inc/feat/anonymous_voting
Browse files Browse the repository at this point in the history
Feat/anonymous voting
  • Loading branch information
sheagrief authored Aug 15, 2024
2 parents 92f6c37 + a671ec7 commit 459984c
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/rust_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,6 @@ jobs:

- name: Run werewolf night
run: ./run_werewolf.zsh night

- name: Run werewolf vote
run: ./run_werewolf.zsh vote
87 changes: 86 additions & 1 deletion examples/bin_werewolf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ use mpc_net::{MpcMultiNet as Net, MpcNet};
use serde::Deserialize;
use std::{fs::File, path::PathBuf};
use structopt::StructOpt;
use zk_mpc::circuits::{DivinationCircuit, ElGamalLocalOrMPC, KeyPublicizeCircuit};
use zk_mpc::circuits::{
AnonymousVotingCircuit, DivinationCircuit, ElGamalLocalOrMPC, KeyPublicizeCircuit,
};
use zk_mpc::input::MpcInputTrait;
use zk_mpc::input::WerewolfKeyInput;
use zk_mpc::input::WerewolfMpcInput;
use zk_mpc::marlin::LocalMarlin;
use zk_mpc::marlin::MFr;
use zk_mpc::marlin::MpcMarlin;
use zk_mpc::marlin::{prove_and_verify, setup_and_index};
use zk_mpc::preprocessing;
use zk_mpc::serialize::{write_r, write_to_file};
use zk_mpc::she;
Expand All @@ -46,6 +49,16 @@ struct Opt {
input: Option<PathBuf>,
}

struct VoteArg {
target_id: usize,
}

impl VoteArg {
fn new(target_id: usize) -> Self {
Self { target_id }
}
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
let opt = Opt::from_args();

Expand All @@ -72,6 +85,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// run the night phase
night_werewolf(&opt)?;
}
"vote" => {
println!("Vote mode");
// run the vote phase
voting(&opt)?;
}
_ => {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
Expand Down Expand Up @@ -503,6 +521,73 @@ fn multi_divination(_opt: &Opt) -> Result<(), std::io::Error> {
Ok(())
}

fn voting(opt: &Opt) -> Result<(), std::io::Error> {
// init
Net::init_from_file(
opt.input.clone().unwrap().to_str().unwrap(),
opt.id.unwrap(),
);
// calc
let most_voted_id = Fr::from(1);
let invalid_most_voted_id = Fr::from(0);

// prove
let local_voting_circuit = AnonymousVotingCircuit {
is_target_id: vec![
vec![Fr::from(0), Fr::from(1), Fr::from(0)],
vec![Fr::from(0), Fr::from(1), Fr::from(0)],
vec![Fr::from(0), Fr::from(0), Fr::from(1)],
],
is_most_voted_id: Fr::from(1),
};

let (mpc_index_pk, index_vk) = setup_and_index(local_voting_circuit);

let rng = &mut test_rng();

let mpc_voting_circuit = AnonymousVotingCircuit {
is_target_id: vec![
vec![
MFr::king_share(Fr::from(0), rng),
MFr::king_share(Fr::from(1), rng),
MFr::king_share(Fr::from(0), rng),
],
vec![
MFr::king_share(Fr::from(0), rng),
MFr::king_share(Fr::from(1), rng),
MFr::king_share(Fr::from(0), rng),
],
vec![
MFr::king_share(Fr::from(0), rng),
MFr::king_share(Fr::from(0), rng),
MFr::king_share(Fr::from(1), rng),
],
],
is_most_voted_id: MFr::king_share(Fr::from(1), rng),
};

let inputs = vec![most_voted_id];
let invalid_inputs = vec![invalid_most_voted_id];

assert!(prove_and_verify(
&mpc_index_pk,
&index_vk,
mpc_voting_circuit.clone(),
inputs
));

assert!(!prove_and_verify(
&mpc_index_pk,
&index_vk,
mpc_voting_circuit,
invalid_inputs
));

println!("Player {} received the most votes", most_voted_id);

Ok(())
}

#[derive(Debug, Deserialize)]
struct ElGamalPubKey {
// public_key: GroupAffine<ark_ed_on_bls12_377::EdwardsParameters>,
Expand Down
2 changes: 1 addition & 1 deletion mpc-algebra/src/r1cs_helper/mpc_fp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ impl<F: PrimeField> MpcAllocatedFp<F> {
pub fn from(other: MpcBoolean<F>) -> Self {
let cs = other.cs();
let variable = cs.new_lc(other.lc()).unwrap();
Self::new(other.value().ok().map(|b| F::from(b as u8)), variable, cs)
Self::new(other.value_field().ok(), variable, cs)
}

/// Returns the value assigned to `self` in the underlying constraint system
Expand Down
17 changes: 17 additions & 0 deletions run_werewolf.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,23 @@ night)
fi
done

for pid in ${PROCS[@]}; do
wait $pid
done
;;
vote)
for i in $(seq 0 $((players - 1))); do
if [ $i == 0 ]; then
RUST_BACKTRACE=1 $BIN vote $i ./data/address &
pid=$!
PROCS[$i]=$pid
else
$BIN vote $i ./data/address >/dev/null &
pid=$!
PROCS[$i]=$pid
fi
done

for pid in ${PROCS[@]}; do
wait $pid
done
Expand Down
161 changes: 158 additions & 3 deletions src/circuits/werewolf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ use ark_r1cs_std::eq::EqGadget;
use ark_r1cs_std::fields::fp::FpVar;
use ark_r1cs_std::fields::FieldVar;
use ark_r1cs_std::groups::CurveVar;
use ark_r1cs_std::select::CondSelectGadget;
use ark_r1cs_std::ToBitsGadget;
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError};
use ark_std::One;
use ark_std::Zero;
use ark_std::{test_rng, One, Zero};
use mpc_algebra::groups::MpcCurveVar;
use mpc_algebra::{MpcBoolean, MpcEqGadget, Reveal};
use mpc_algebra::mpc_fields::MpcFieldVar;
use mpc_algebra::{
MpcBoolean, MpcCondSelectGadget, MpcEqGadget, MpcFpVar, MpcToBitsGadget, Reveal,
};

use mpc_algebra::honest_but_curious as hbc;
use mpc_algebra::malicious_majority as mm;
Expand Down Expand Up @@ -564,6 +568,157 @@ impl ConstraintSynthesizer<mm::MpcField<Fr>> for DivinationCircuit<mm::MpcField<
}
}

#[derive(Clone)]
pub struct AnonymousVotingCircuit<F: PrimeField + LocalOrMPC<F>> {
pub is_target_id: Vec<Vec<F>>,
pub is_most_voted_id: F,
}

impl ConstraintSynthesizer<Fr> for AnonymousVotingCircuit<Fr> {
fn generate_constraints(self, cs: ConstraintSystemRef<Fr>) -> ark_relations::r1cs::Result<()> {
// initialize
let player_num = self.is_target_id.len();

let is_target_id_var = self
.is_target_id
.iter()
.map(|id| {
id.iter()
.map(|b| FpVar::new_witness(cs.clone(), || Ok(b)))
.collect::<Result<Vec<_>, _>>()
})
.collect::<Result<Vec<_>, _>>()?;

let is_most_voted_id_var = FpVar::new_input(cs.clone(), || Ok(self.is_most_voted_id))?;

// calculate
let mut num_voted_var = Vec::new();

for i in 0..player_num {
let mut each_num_voted = FpVar::zero();

for j in 0..player_num {
each_num_voted += is_target_id_var[j][i].clone();
}

num_voted_var.push(each_num_voted);
}

let constant = (0..4)
.map(|i| FpVar::Constant(Fr::from(i as i32)))
.collect::<Vec<_>>();

let mut calced_is_most_voted_id = FpVar::new_witness(cs.clone(), || Ok(Fr::zero()))?;

for i in 0..player_num {
let a_now = FpVar::conditionally_select_power_of_two_vector(
&calced_is_most_voted_id.to_bits_le().unwrap()[..2],
&constant,
)?;

let res = FpVar::is_cmp(
//&num_voted_var[calced_is_most_voted_id],
&a_now,
&num_voted_var[i],
std::cmp::Ordering::Greater,
true,
)?;

let false_value = FpVar::new_witness(cs.clone(), || Ok(Fr::from(i as i32)))?;

calced_is_most_voted_id =
FpVar::conditionally_select(&res, &calced_is_most_voted_id, &false_value)?;
}

// enforce equal
is_most_voted_id_var.enforce_equal(&calced_is_most_voted_id);

println!("total number of constraints: {}", cs.num_constraints());

Ok(())
}
}

impl ConstraintSynthesizer<mm::MpcField<Fr>> for AnonymousVotingCircuit<mm::MpcField<Fr>> {
fn generate_constraints(
self,
cs: ConstraintSystemRef<mm::MpcField<Fr>>,
) -> ark_relations::r1cs::Result<()> {
// initialize
let player_num = self.is_target_id.len();

let is_target_id_var = self
.is_target_id
.iter()
.map(|id| {
id.iter()
.map(|b| MpcFpVar::new_witness(cs.clone(), || Ok(b)))
.collect::<Result<Vec<_>, _>>()
})
.collect::<Result<Vec<_>, _>>()?;

let is_most_voted_id_var = MpcFpVar::new_input(cs.clone(), || Ok(self.is_most_voted_id))?;

// calculate
let mut num_voted_var = Vec::new();

for i in 0..player_num {
let mut each_num_voted = MpcFpVar::zero();

for j in 0..player_num {
each_num_voted += is_target_id_var[j][i].clone();
}

num_voted_var.push(each_num_voted);
}

let constant = (0..4)
.map(|i| {
MpcFpVar::Constant(mm::MpcField::<Fr>::king_share(
Fr::from(i as i32),
&mut test_rng(),
))
})
.collect::<Vec<_>>();

let mut calced_is_most_voted_id = MpcFpVar::new_witness(cs.clone(), || {
Ok(mm::MpcField::<Fr>::king_share(Fr::zero(), &mut test_rng()))
})?;

for i in 0..player_num {
let a_now = MpcFpVar::conditionally_select_power_of_two_vector(
&calced_is_most_voted_id.to_bits_le().unwrap()[..2],
&constant,
)?;

let res = MpcFpVar::is_cmp(
//&num_voted_var[calced_is_most_voted_id],
&a_now,
&num_voted_var[i],
std::cmp::Ordering::Greater,
true,
)?;

let false_value = MpcFpVar::new_witness(cs.clone(), || {
Ok(mm::MpcField::<Fr>::king_share(
Fr::from(i as i32),
&mut test_rng(),
))
})?;

calced_is_most_voted_id =
MpcFpVar::conditionally_select(&res, &calced_is_most_voted_id, &false_value)?;
}

// enforce equal
is_most_voted_id_var.enforce_equal(&calced_is_most_voted_id);

println!("total number of constraints: {}", cs.num_constraints());

Ok(())
}
}

pub trait ElGamalLocalOrMPC<ConstraintF: PrimeField> {
type JubJub: ProjectiveCurve;

Expand Down
4 changes: 2 additions & 2 deletions src/marlin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
input::{MpcInputTrait, SampleMpcInput},
};

fn setup_and_index<C: ConstraintSynthesizer<Fr>>(
pub fn setup_and_index<C: ConstraintSynthesizer<Fr>>(
circuit: C,
) -> (
IndexProverKey<MFr, MpcMarlinKZG10>,
Expand All @@ -39,7 +39,7 @@ fn setup_and_index<C: ConstraintSynthesizer<Fr>>(
(mpc_index_pk, index_vk)
}

fn prove_and_verify<C: ConstraintSynthesizer<MFr>>(
pub fn prove_and_verify<C: ConstraintSynthesizer<MFr>>(
mpc_index_pk: &IndexProverKey<MFr, MpcMarlinKZG10>,
index_vk: &IndexVerifierKey<Fr, LocalMarlinKZG10>,
circuit: C,
Expand Down

0 comments on commit 459984c

Please sign in to comment.