From ad6c2d5deec39be98a83af52f22518e5edccd4cf Mon Sep 17 00:00:00 2001 From: sheagrief <3a.mad1earth4@gmail.com> Date: Thu, 31 Oct 2024 15:53:55 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=90=9B=20Modify:=20Change=20a=20playe?= =?UTF-8?q?r=20parameter=20for=20MPC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/werewolf_cli/game.rs | 7 +++++-- examples/werewolf_cli/game/player.rs | 11 ++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/werewolf_cli/game.rs b/examples/werewolf_cli/game.rs index 006b75e..d83c010 100644 --- a/examples/werewolf_cli/game.rs +++ b/examples/werewolf_cli/game.rs @@ -4,8 +4,11 @@ use ark_ff::BigInteger; use ark_ff::PrimeField; use ark_ff::UniformRand; use ark_marlin::IndexProverKey; +use ark_std::One; use mpc_algebra::commitment::CommitmentScheme; +use mpc_algebra::BooleanWire; use mpc_algebra::FromLocal; +use mpc_algebra::MpcBooleanField; use mpc_algebra::Reveal; use nalgebra::DMatrix; use player::Player; @@ -291,10 +294,10 @@ impl Game { let mut events = Vec::new(); for player in &mut self.state.players { - if player.marked_for_death && player.is_alive { + if player.marked_for_death.reveal().is_one() && player.is_alive { player.kill(self.state.day); events.push(format!("{}が無残な姿で発見されました。", player.name)); - player.marked_for_death = false; + player.marked_for_death = MpcBooleanField::pub_false(); } } diff --git a/examples/werewolf_cli/game/player.rs b/examples/werewolf_cli/game/player.rs index c7eb9c6..0abb385 100644 --- a/examples/werewolf_cli/game/player.rs +++ b/examples/werewolf_cli/game/player.rs @@ -1,14 +1,15 @@ -use serde::{Deserialize, Serialize}; +use ark_bls12_377::Fr; +use mpc_algebra::{AdditiveFieldShare, BooleanWire, MpcBooleanField}; use zk_mpc::werewolf::types::Role; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct Player { pub id: usize, pub name: String, pub role: Option, pub is_alive: bool, pub death_day: Option, - pub marked_for_death: bool, + pub marked_for_death: MpcBooleanField>, } impl Player { @@ -19,7 +20,7 @@ impl Player { role, is_alive: true, death_day: None, - marked_for_death: false, + marked_for_death: MpcBooleanField::pub_false(), } } @@ -33,7 +34,7 @@ impl Player { } pub fn mark_for_death(&mut self) { - self.marked_for_death = true; + self.marked_for_death = MpcBooleanField::pub_true(); } } From 725b07ca3b943f9b7dba0b57a0612556daf92f00 Mon Sep 17 00:00:00 2001 From: sheagrief <3a.mad1earth4@gmail.com> Date: Thu, 31 Oct 2024 18:02:08 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=90=9B=20Fix:=20Change=20attack=20&?= =?UTF-8?q?=20divination=20for=20MPC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/werewolf_cli/game.rs | 45 ++++++++++++------- examples/werewolf_cli/main.rs | 83 +++++++++++++++++++++++------------ 2 files changed, 83 insertions(+), 45 deletions(-) diff --git a/examples/werewolf_cli/game.rs b/examples/werewolf_cli/game.rs index d83c010..45f3444 100644 --- a/examples/werewolf_cli/game.rs +++ b/examples/werewolf_cli/game.rs @@ -10,6 +10,7 @@ use mpc_algebra::BooleanWire; use mpc_algebra::FromLocal; use mpc_algebra::MpcBooleanField; use mpc_algebra::Reveal; +use mpc_net::{MpcMultiNet as Net, MpcNet}; use nalgebra::DMatrix; use player::Player; use rand::Rng; @@ -233,24 +234,27 @@ impl Game { } } - pub fn werewolf_attack(&mut self, target_id: usize) -> Vec { + pub fn werewolf_attack(&mut self, target_id: MFr) -> Vec { let mut events = Vec::new(); - if let Some(_werewolf) = self + let am_werewolf = self .state .players .iter() - .find(|p| p.is_werewolf() && p.is_alive) - { - if let Some(target) = self - .state - .players - .iter_mut() - .find(|p| p.id == target_id && p.is_alive && !p.is_werewolf()) + .any(|p| p.id == Net::party_id() && p.role == Some(Role::Werewolf) && p.is_alive); + + // calc + if let Some(target) = + self.state.players.iter_mut().find(|p| { + Fr::from(p.id as i32) == target_id.reveal() && p.is_alive && !p.is_werewolf() + }) { target.mark_for_death(); + if am_werewolf { events.push(format!("人狼が{}を襲撃対象に選びました。", target.name)); + } } else { + if am_werewolf { events.push("無効な襲撃対象が選択されました。".to_string()); } } @@ -258,35 +262,42 @@ impl Game { events } - pub fn seer_divination(&self, target_id: usize) -> Vec { + pub fn seer_divination(&self, target_id: MFr) -> Vec { let mut events = Vec::new(); + // get FortuneTeller + let am_fortune_teller = + self.state.players.iter().any(|p| { + p.id == Net::party_id() && p.role == Some(Role::FortuneTeller) && p.is_alive + }); + + // calc if let Some(seer) = self .state .players .iter() .find(|p| p.role == Some(Role::FortuneTeller) && p.is_alive) { - if let Some(target) = self - .state - .players - .iter() - .find(|p| p.id == target_id && p.is_alive && p.id != seer.id) - { + if let Some(target) = self.state.players.iter().find(|p| { + Fr::from(p.id as i32) == target_id.reveal() && p.is_alive && p.id != seer.id + }) { let role_name = if target.is_werewolf() { "人狼" } else { "人狼ではない" }; + if am_fortune_teller { events.push(format!( "占い師が{}を占いました。結果:{}", target.name, role_name )); + } } else { + if am_fortune_teller { events.push("無効な占い対象が選択されました。".to_string()); } } - + } events } diff --git a/examples/werewolf_cli/main.rs b/examples/werewolf_cli/main.rs index a8b266c..00ceb77 100644 --- a/examples/werewolf_cli/main.rs +++ b/examples/werewolf_cli/main.rs @@ -1,9 +1,12 @@ +use ark_bls12_377::Fr; use game::{player::Player, Game, GameRules}; use mpc_algebra::channel::MpcSerNet; +use mpc_algebra::Reveal; use mpc_net::{MpcMultiNet as Net, MpcNet}; use std::io::{self, Write}; use std::path::PathBuf; use structopt::StructOpt; +use zk_mpc::marlin::MFr; use zk_mpc::werewolf::types::{GroupingParameter, Role}; pub mod game; @@ -99,34 +102,37 @@ fn register_players() -> Vec { fn night_phase(game: &mut Game) { println!("\n--- 夜のフェーズ ---"); let players = game.state.players.clone(); - for player in &players { - if player.is_alive { - let mut events = Vec::new(); + + let player = players.iter().find(|p| p.id == Net::party_id()).unwrap(); + + let mut events = Vec::new(); + match player.role { + Some(Role::Villager) => { + println!("You are a villager. Please wait until everyone has finished their actions."); + } Some(Role::Werewolf) => { - let werewolf_target = get_werewolf_target(game, player); - events.extend(game.werewolf_attack(werewolf_target)); + println!("You are a werewolf."); } Some(Role::FortuneTeller) => { + println!("You are a fortune Teller. Please wait until other roles actions."); + } + None => todo!(), + } + + let attack_target = get_werewolf_target(game, player); + events.extend(game.werewolf_attack(attack_target)); + let seer_target = get_seer_target(game, player); events.extend(game.seer_divination(seer_target)); - } - Some(Role::Villager) => { - println!( - "{}さん、あなたは村人です。次の人に渡してください。", - player.name - ); - } - None => unreachable!(), - } + for event in events { println!("{}", event); } wait_for_enter(); - // 各プレイヤーのフェーズ後にCLIをフラッシュ + println!("Waiting for all players to finish their actions."); + wait_for_everyone(); clear_screen(); - } - } } fn wait_for_enter() { @@ -135,15 +141,23 @@ fn wait_for_enter() { io::stdin().read_line(&mut input).unwrap(); } +fn wait_for_everyone() { + let dummy = 0_u32; + Net::broadcast(&dummy); +} + fn clear_screen() { print!("\x1B[2J\x1B[1;1H"); // ANSI escape code for clearing the screen io::stdout().flush().unwrap(); } -fn get_werewolf_target(game: &Game, werewolf: &Player) -> usize { +fn get_werewolf_target(game: &Game, player: &Player) -> MFr { + let mut target_id = Fr::default(); + + if player.role.unwrap().is_werewolf() { println!( "{}さん、あなたは人狼です。襲撃する対象を選んでください:", - werewolf.name + player.name ); game.state .players @@ -157,30 +171,38 @@ fn get_werewolf_target(game: &Game, werewolf: &Player) -> usize { let mut input = String::new(); io::stdin().read_line(&mut input).unwrap(); - let target_id: usize = input.trim().parse().unwrap_or(0); + target_id = Fr::from(input.trim().parse().unwrap_or(0) as i32); if game .state .players .iter() - .any(|p| p.id == target_id && p.is_alive && !p.is_werewolf()) + .any(|p| Fr::from(p.id as i32) == target_id && p.is_alive && !p.is_werewolf()) { - return target_id; + break; } else { println!("無効な選択です。もう一度選んでください。"); } } + } else { + target_id = Fr::default(); + } + + return MFr::from_add_shared(target_id); } -fn get_seer_target(game: &Game, seer: &Player) -> usize { +fn get_seer_target(game: &Game, player: &Player) -> MFr { + let mut target_id = Fr::default(); + + if player.role.unwrap() == Role::FortuneTeller { println!( "{}さん、あなたは占い師です。占う対象を選んでください:", - seer.name + player.name ); game.state .players .iter() - .filter(|p| p.is_alive && p.id != seer.id) + .filter(|p| p.is_alive && p.id != player.id) .for_each(|p| println!("{}: {}", p.id, p.name)); loop { @@ -189,19 +211,24 @@ fn get_seer_target(game: &Game, seer: &Player) -> usize { let mut input = String::new(); io::stdin().read_line(&mut input).unwrap(); - let target_id: usize = input.trim().parse().unwrap_or(0); + target_id = Fr::from(input.trim().parse().unwrap_or(0) as i32); if game .state .players .iter() - .any(|p| p.id == target_id && p.is_alive && p.id != seer.id) + .any(|p| Fr::from(p.id as i32) == target_id && p.is_alive && p.id != player.id) { - return target_id; + break; } else { println!("無効な選択です。もう一度選んでください。"); } } + } else { + target_id = Fr::default(); + } + + return MFr::from_add_shared(target_id); } fn morning_phase(game: &mut Game) { From 5e00a37c4196391826695c2c6a47f253034133b5 Mon Sep 17 00:00:00 2001 From: sheagrief <3a.mad1earth4@gmail.com> Date: Tue, 5 Nov 2024 16:48:25 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20formatter=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/werewolf_cli/game.rs | 18 +++--- examples/werewolf_cli/main.rs | 104 +++++++++++++++++----------------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/examples/werewolf_cli/game.rs b/examples/werewolf_cli/game.rs index 464363c..3b9dfb1 100644 --- a/examples/werewolf_cli/game.rs +++ b/examples/werewolf_cli/game.rs @@ -250,12 +250,12 @@ impl Game { self.state.players.iter_mut().find(|p| { Fr::from(p.id as i32) == target_id.reveal() && p.is_alive && !p.is_werewolf() }) - { - target.mark_for_death(); + { + target.mark_for_death(); if am_werewolf { events.push(format!("人狼が{}を襲撃対象に選びました。", target.name)); } - } else { + } else { if am_werewolf { events.push("無効な襲撃対象が選択されました。".to_string()); } @@ -289,17 +289,17 @@ impl Game { "人狼ではない" }; if am_fortune_teller { - events.push(format!( - "占い師が{}を占いました。結果:{}", - target.name, role_name - )); + events.push(format!( + "占い師が{}を占いました。結果:{}", + target.name, role_name + )); } } else { if am_fortune_teller { - events.push("無効な占い対象が選択されました。".to_string()); + events.push("無効な占い対象が選択されました。".to_string()); + } } } - } events } diff --git a/examples/werewolf_cli/main.rs b/examples/werewolf_cli/main.rs index e565ed7..8999b16 100644 --- a/examples/werewolf_cli/main.rs +++ b/examples/werewolf_cli/main.rs @@ -107,14 +107,14 @@ fn night_phase(game: &mut Game) { let mut events = Vec::new(); - match player.role { + match player.role { Some(Role::Villager) => { println!("You are a villager. Please wait until everyone has finished their actions."); } - Some(Role::Werewolf) => { + Some(Role::Werewolf) => { println!("You are a werewolf."); - } - Some(Role::FortuneTeller) => { + } + Some(Role::FortuneTeller) => { println!("You are a fortune Teller. Please wait until other roles actions."); } None => todo!(), @@ -123,16 +123,16 @@ fn night_phase(game: &mut Game) { let attack_target = get_werewolf_target(game, player); events.extend(game.werewolf_attack(attack_target)); - let seer_target = get_seer_target(game, player); - events.extend(game.seer_divination(seer_target)); + let seer_target = get_seer_target(game, player); + events.extend(game.seer_divination(seer_target)); - for event in events { - println!("{}", event); - } - wait_for_enter(); + for event in events { + println!("{}", event); + } + wait_for_enter(); println!("Waiting for all players to finish their actions."); wait_for_everyone(); - clear_screen(); + clear_screen(); } fn wait_for_enter() { @@ -155,35 +155,35 @@ fn get_werewolf_target(game: &Game, player: &Player) -> MFr { let mut target_id = Fr::default(); if player.role.unwrap().is_werewolf() { - println!( - "{}さん、あなたは人狼です。襲撃する対象を選んでください:", + println!( + "{}さん、あなたは人狼です。襲撃する対象を選んでください:", player.name - ); - game.state - .players - .iter() - .filter(|p| p.is_alive && !p.is_werewolf()) - .for_each(|p| println!("{}: {}", p.id, p.name)); + ); + game.state + .players + .iter() + .filter(|p| p.is_alive && !p.is_werewolf()) + .for_each(|p| println!("{}: {}", p.id, p.name)); - loop { - print!("対象のIDを入力してください: "); - io::stdout().flush().unwrap(); + loop { + print!("対象のIDを入力してください: "); + io::stdout().flush().unwrap(); - let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); target_id = Fr::from(input.trim().parse().unwrap_or(0) as i32); - if game - .state - .players - .iter() + if game + .state + .players + .iter() .any(|p| Fr::from(p.id as i32) == target_id && p.is_alive && !p.is_werewolf()) - { + { break; - } else { - println!("無効な選択です。もう一度選んでください。"); + } else { + println!("無効な選択です。もう一度選んでください。"); + } } - } } else { target_id = Fr::default(); } @@ -195,35 +195,35 @@ fn get_seer_target(game: &Game, player: &Player) -> MFr { let mut target_id = Fr::default(); if player.role.unwrap() == Role::FortuneTeller { - println!( - "{}さん、あなたは占い師です。占う対象を選んでください:", + println!( + "{}さん、あなたは占い師です。占う対象を選んでください:", player.name - ); - game.state - .players - .iter() + ); + game.state + .players + .iter() .filter(|p| p.is_alive && p.id != player.id) - .for_each(|p| println!("{}: {}", p.id, p.name)); + .for_each(|p| println!("{}: {}", p.id, p.name)); - loop { - print!("対象のIDを入力してください: "); - io::stdout().flush().unwrap(); + loop { + print!("対象のIDを入力してください: "); + io::stdout().flush().unwrap(); - let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); target_id = Fr::from(input.trim().parse().unwrap_or(0) as i32); - if game - .state - .players - .iter() + if game + .state + .players + .iter() .any(|p| Fr::from(p.id as i32) == target_id && p.is_alive && p.id != player.id) - { + { break; - } else { - println!("無効な選択です。もう一度選んでください。"); + } else { + println!("無効な選択です。もう一度選んでください。"); + } } - } } else { target_id = Fr::default(); }