diff --git a/examples/werewolf_cli/game.rs b/examples/werewolf_cli/game.rs index 8ed8454..6023ca6 100644 --- a/examples/werewolf_cli/game.rs +++ b/examples/werewolf_cli/game.rs @@ -6,9 +6,12 @@ use ark_ff::UniformRand; use ark_marlin::IndexProverKey; use ark_std::test_rng; use ark_std::One; +use ark_std::PubUniformRand; use mpc_algebra::commitment::CommitmentScheme; use mpc_algebra::BooleanWire; +use mpc_algebra::EqualityZero; use mpc_algebra::FromLocal; +use mpc_algebra::LessThan; use mpc_algebra::MpcBooleanField; use mpc_algebra::Reveal; use mpc_net::{MpcMultiNet as Net, MpcNet}; @@ -18,6 +21,8 @@ use rand::Rng; use zk_mpc::circuits::AnonymousVotingCircuit; use zk_mpc::circuits::LocalOrMPC; use zk_mpc::circuits::RoleAssignmentCircuit; +use zk_mpc::circuits::WinningJudgeCircuit; +use zk_mpc::input::InputWithCommit; use zk_mpc::marlin::prove_and_verify; use zk_mpc::marlin::setup_and_index; use zk_mpc::marlin::LocalMarlin; @@ -229,12 +234,16 @@ impl Game { }; } - pub fn check_victory_condition(&self) -> Option { + pub fn check_victory_condition(&self, is_prove: bool) -> Option { let alive_players: Vec<&Player> = self.state.players.iter().filter(|p| p.is_alive).collect(); let werewolf_count = alive_players.iter().filter(|p| p.is_werewolf()).count(); let villager_count = alive_players.len() - werewolf_count; + if is_prove { + self.prove_and_verify_victory(); + } + if werewolf_count == 0 { Some("村人".to_string()) } else if werewolf_count >= villager_count { @@ -244,6 +253,124 @@ impl Game { } } + fn prove_and_verify_victory(&self) { + // setup + + let num_alive = Fr::from(self.state.players.iter().filter(|p| p.is_alive).count() as i32); + + let alive_indices = self + .state + .players + .iter() + .enumerate() + .filter(|(_, p)| p.is_alive) + .map(|(i, _)| i) + .collect::>(); + + let rng = &mut test_rng(); + + let am_werewolf_vec = alive_indices + .iter() + .map(|_| InputWithCommit::default()) + .collect::>(); + + let mpc_am_werewolf_vec = alive_indices + .iter() + .map(|&i| { + let mut a: InputWithCommit = InputWithCommit::default(); + a.allocation = i; + a.input = MFr::from(self.state.players[i].is_werewolf()); + a + }) + .collect::>(); + + let pedersen_param = self.state.pedersen_param.clone(); + let mpc_pedersen_param = + >::PedersenParam::from_local(&pedersen_param); + + let common_randomness = >::PedersenRandomness::pub_rand(rng); + let mpc_common_randomness = + >::PedersenRandomness::from_public(common_randomness); + + let mpc_am_werewolf_vec = mpc_am_werewolf_vec + .iter() + .map(|x| x.generate_input(&mpc_pedersen_param, &mpc_common_randomness)) + .collect::>(); + + let player_randomness = load_random_value().unwrap(); + let player_commitment = load_random_commitment().unwrap(); + + // calc + + let num_werewolf = mpc_am_werewolf_vec + .iter() + .fold(MFr::default(), |acc, x| acc + x.input); + let num_citizen = MFr::from_public(num_alive) - num_werewolf; + let exists_werewolf = num_werewolf.is_zero_shared(); + + let game_state = exists_werewolf.field() * MFr::from(2_u32) + + (!exists_werewolf).field() + * ((num_werewolf + MFr::one()) + .is_smaller_than(&num_citizen) + .field() + * MFr::from(3_u32) + + (MFr::one() + - ((num_werewolf + MFr::one()) + .is_smaller_than(&num_citizen) + .field())) + * MFr::from(1_u32)); + + // prove + let local_judgment_circuit = WinningJudgeCircuit { + num_alive, + pedersen_param: pedersen_param.clone(), + am_werewolf: am_werewolf_vec.clone(), + game_state: Fr::default(), + + player_randomness: player_randomness.clone(), + player_commitment: player_commitment.clone(), + }; + + let (mpc_index_pk, index_vk) = setup_and_index(local_judgment_circuit); + + let mpc_pedersen_param = + >::PedersenParam::from_local(&pedersen_param); + + let mpc_judgment_circuit = WinningJudgeCircuit { + num_alive: MFr::from_public(num_alive), + pedersen_param: mpc_pedersen_param, + am_werewolf: mpc_am_werewolf_vec.clone(), + game_state, + player_randomness: player_randomness + .iter() + .map(|x| MFr::from_public(*x)) + .collect::>(), + player_commitment: player_commitment + .iter() + .map(|x| >::PedersenCommitment::from_public(*x)) + .collect::>(), + }; + + let mut inputs = player_commitment + .iter() + .flat_map(|c| vec![c.x, c.y]) + .collect::>(); + + inputs.extend_from_slice(&[num_alive, game_state.reveal()]); + + for iwc in mpc_am_werewolf_vec.iter() { + inputs.push(iwc.commitment.reveal().x); + inputs.push(iwc.commitment.reveal().y); + } + + assert!(prove_and_verify( + &mpc_index_pk, + &index_vk, + mpc_judgment_circuit.clone(), + inputs + )); + } + pub fn werewolf_attack(&mut self, target_id: MFr) -> Vec { let mut events = Vec::new(); diff --git a/examples/werewolf_cli/main.rs b/examples/werewolf_cli/main.rs index f1b78f8..4a22736 100644 --- a/examples/werewolf_cli/main.rs +++ b/examples/werewolf_cli/main.rs @@ -53,7 +53,7 @@ fn main() -> Result<(), Box> { let mut game = Game::new(register_players(), game_rule); - game.role_assignment(false); + game.role_assignment(true); println!("{:?}", game.state.players); @@ -61,13 +61,21 @@ fn main() -> Result<(), Box> { loop { night_phase(&mut game); + if game.state.day > 1 { + if let Some(winner) = game.check_victory_condition(true) { + println!("Game is over! {} wins!", winner); + break; + } + } morning_phase(&mut game); discussion_phase(&game); voting_phase(&mut game); - if let Some(winner) = game.check_victory_condition() { - println!("ゲーム終了!{}の勝利です!", winner); + if let Some(winner) = game.check_victory_condition(true) { + println!("Game is over! {} wins!", winner); break; + } else { + println!("Despite the execution, a terrifying night is coming."); } game.next_phase(); diff --git a/mpc-algebra/src/wire/field.rs b/mpc-algebra/src/wire/field.rs index 235623c..c626b54 100644 --- a/mpc-algebra/src/wire/field.rs +++ b/mpc-algebra/src/wire/field.rs @@ -261,6 +261,7 @@ impl> LessThan for MpcField Self::Output { let timer = start_timer!(|| "LessThan"); // [z]=[other−self

p/2] diff --git a/src/marlin.rs b/src/marlin.rs index eb26f90..eae2671 100644 --- a/src/marlin.rs +++ b/src/marlin.rs @@ -39,7 +39,7 @@ pub fn setup_and_index>( IndexVerifierKey, ) { let rng = &mut test_rng(); - let srs = LocalMarlin::universal_setup(30000, 500, 1000, rng).unwrap(); + let srs = LocalMarlin::universal_setup(60000, 500, 1000, rng).unwrap(); let (index_pk, index_vk) = LocalMarlin::index(&srs, circuit).unwrap(); let mpc_index_pk = IndexProverKey::from_public(index_pk); (mpc_index_pk, index_vk)