diff --git a/src/components/zkcards_wasm/Cargo.toml b/src/components/zkcards_wasm/Cargo.toml index 5b79f244e..469485e27 100644 --- a/src/components/zkcards_wasm/Cargo.toml +++ b/src/components/zkcards_wasm/Cargo.toml @@ -23,6 +23,7 @@ rand = "0.8" serde = { version = "1", features = ["derive"] } serde_json = "1.0" wasm-bindgen = { version = "0.2.84", features = ["serde-serialize"] } +serde-wasm-bindgen = "0.5.0" # Must enable the "js"-feature, # OR the compiling will fail. diff --git a/src/components/zkcards_wasm/src/wasm.rs b/src/components/zkcards_wasm/src/wasm.rs index eda903f4d..d7ee776b4 100644 --- a/src/components/zkcards_wasm/src/wasm.rs +++ b/src/components/zkcards_wasm/src/wasm.rs @@ -12,4 +12,127 @@ #![deny(missing_docs)] #![allow(clippy::needless_borrow)] +//todo: remove `unwrap` +//todo: more comments + mod zkcards; + +use crate::zkcards::{ + AggregatePublicKey, Card, CardParameters, MaskedCard, Player, ProofShuffle, + RevealToken, RevealedToken, ShuffleResult, Surrogate, +}; +use rand::thread_rng; +use std::collections::HashMap; +use std::hash::Hash; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +/// create a new player with `name` and `card parameters` received from contract +pub fn new_player(pp: CardParameters, name: Vec) -> Player { + let rng = &mut thread_rng(); + Player::new(rng, &pp, &name).unwrap() +} + +#[wasm_bindgen] +/// generate a `surrogate` with `ProofKeyOwnerShip` as this player's behave +pub fn new_surrogate(player: &Player, pp: &CardParameters) -> Surrogate { + player.new_surrogate(pp) +} + +#[wasm_bindgen] +/// verify a player +pub fn verify_proof_pk(player: Surrogate, pp: &CardParameters) -> bool { + player.verify(&pp) +} + +#[wasm_bindgen] +/// Perform a shuffle operation +pub fn shuffle( + player: &Player, + pp: &CardParameters, + deck: JsValue, + joint_pk: &AggregatePublicKey, + nums_of_cards: usize, +) -> JsValue { + let raw_deck: Vec> = serde_wasm_bindgen::from_value(deck).unwrap(); + let deck = raw_deck + .into_iter() + .map(|c| serde_json::from_slice(c.as_slice()).unwrap()) + .collect::>(); + let (tokens, proof) = player.shuffle(pp, &deck, joint_pk, nums_of_cards).unwrap(); + let res = ShuffleResult { tokens, proof }; + + serde_wasm_bindgen::to_value(&res).unwrap() +} + +#[wasm_bindgen] +/// verify shuffled deck from another player +pub fn verify_shuffle( + parameters: &CardParameters, + joint_pk: &AggregatePublicKey, + original_deck: JsValue, + shuffled_deck: JsValue, + proof_shuffle: &ProofShuffle, +) -> bool { + let raw_original_deck: Vec> = + serde_wasm_bindgen::from_value(original_deck).unwrap(); + let original_deck = raw_original_deck + .into_iter() + .map(|c| serde_json::from_slice(c.as_slice()).unwrap()) + .collect::>(); + let raw_shuffled_deck: Vec> = + serde_wasm_bindgen::from_value(shuffled_deck).unwrap(); + let shuffled_deck = raw_shuffled_deck + .into_iter() + .map(|c| serde_json::from_slice(c.as_slice()).unwrap()) + .collect::>(); + + Player::verify_shuffle( + parameters, + joint_pk, + &original_deck, + &shuffled_deck, + proof_shuffle, + ) + .is_ok() +} + +#[wasm_bindgen] +/// reveal a card +pub fn compute_reveal_token( + player: &Player, + card: &MaskedCard, + pp: &CardParameters, +) -> RevealedToken { + let rng = &mut thread_rng(); + player.compute_reveal_token(rng, pp, card).unwrap() +} + +#[wasm_bindgen] +/// open a card +pub fn open_card( + parameters: &CardParameters, + reveal_tokens: JsValue, + card_mappings: JsValue, + card: &MaskedCard, + cards: JsValue, +) -> JsValue { + let raw_reveal_tokens: Vec> = + serde_wasm_bindgen::from_value(reveal_tokens).unwrap(); + let reveal_tokens = raw_reveal_tokens + .into_iter() + .map(|c| serde_json::from_slice(c.as_slice()).unwrap()) + .collect::>(); + let card_mappings: HashMap> = + serde_wasm_bindgen::from_value(card_mappings).unwrap(); + let raw_cards: Vec> = serde_wasm_bindgen::from_value(cards).unwrap(); + let cards = raw_cards + .into_iter() + .map(|c| serde_json::from_slice(c.as_slice()).unwrap()) + .collect::>(); + + let play_card = + Player::peek_at_card(parameters, &reveal_tokens, &card_mappings, card, &cards) + .unwrap(); + serde_wasm_bindgen::to_value(&play_card).unwrap() +} diff --git a/src/components/zkcards_wasm/src/zkcards/mod.rs b/src/components/zkcards_wasm/src/zkcards/mod.rs index 38822f8db..44db7f357 100644 --- a/src/components/zkcards_wasm/src/zkcards/mod.rs +++ b/src/components/zkcards_wasm/src/zkcards/mod.rs @@ -2,6 +2,9 @@ mod error; mod player; mod user_card; +pub use player::*; +pub use user_card::*; + use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use barnett::discrete_log_cards; use proof_essentials::{ @@ -51,9 +54,20 @@ impl<'a> From<&'a CardParameters> for &'a discrete_log_cards::Parameters } } -pub type PlayerPublicKey = discrete_log_cards::PublicKey; -pub type PlayerSecretKey = discrete_log_cards::PlayerSecretKey; -pub type AggregatePublicKey = discrete_log_cards::PublicKey; +type PlayerSecretKey = discrete_log_cards::PlayerSecretKey; + +#[wasm_bindgen] +#[derive(Clone, Copy, Serialize, Deserialize)] +pub struct PlayerPublicKey( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + pub(crate) discrete_log_cards::PublicKey, +); +#[wasm_bindgen] +#[derive(Clone, Serialize, Deserialize)] +pub struct AggregatePublicKey( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + pub(crate) discrete_log_cards::PublicKey, +); #[wasm_bindgen] #[derive(Clone, Copy, Eq, Hash, PartialEq, Debug, Serialize, Deserialize)] @@ -72,6 +86,11 @@ impl From for discrete_log_cards::Card { } } +#[wasm_bindgen] +pub struct MaskedCards { + inner: Vec, +} + #[wasm_bindgen] #[derive(Clone, Copy, Eq, Hash, PartialEq, Debug, Serialize, Deserialize)] pub struct MaskedCard( @@ -167,7 +186,6 @@ impl<'a> From<&'a ProofShuffle> for &'a shuffle::proof::Proof } } -#[wasm_bindgen] //pub struct ProofMasking(chaum_pedersen_dl_equality::proof::Proof); #[derive(Clone, Copy, Eq, Hash, PartialEq, Debug, Deserialize, Serialize)] pub struct ProofRemasking( @@ -185,13 +203,24 @@ impl From for chaum_pedersen_dl_equality::proof::Proof { } } -//#[wasm_bindgen] +#[derive(Serialize, Deserialize)] +pub struct ShuffleResult { + pub tokens: Vec, + pub proof: ProofShuffle, +} + +impl ShuffleResult { + pub fn new(tokens: Vec, proof: ProofShuffle) -> Self { + Self { tokens, proof } + } +} + +#[wasm_bindgen] #[derive(Serialize, Deserialize)] pub struct RevealedToken { - pub token: RevealToken, - pub proof: ProofReveal, - #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] - pub player: PlayerPublicKey, + pub(crate) token: RevealToken, + pub(crate) proof: ProofReveal, + pub(crate) player: PlayerPublicKey, } fn ark_se(a: &A, s: S) -> Result diff --git a/src/components/zkcards_wasm/src/zkcards/player.rs b/src/components/zkcards_wasm/src/zkcards/player.rs index 7bb04a341..cac39ebea 100644 --- a/src/components/zkcards_wasm/src/zkcards/player.rs +++ b/src/components/zkcards_wasm/src/zkcards/player.rs @@ -7,35 +7,34 @@ use super::{ RevealedToken, Scalar, }; use ark_std::rand::Rng; -use barnett::BarnettSmartProtocol; +use barnett::{BarnettSmartProtocol, Mask}; use proof_essentials::utils::{permutation::Permutation, rand::sample_vector}; use rand::thread_rng; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use wasm_bindgen::prelude::*; +#[wasm_bindgen] #[derive(Clone)] pub struct Player { name: Vec, sk: PlayerSecretKey, pk: PlayerPublicKey, - proof_key: ProofKeyOwnership, - cards: Vec, - opened_cards: Vec>, } +#[wasm_bindgen] #[derive(Serialize, Deserialize)] pub struct Surrogate { - pub name: Vec, - #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] - pub pk: PlayerPublicKey, - pub proof_key: ProofKeyOwnership, + pub(crate) name: Vec, + pub(crate) pk: PlayerPublicKey, + pub(crate) proof_key: ProofKeyOwnership, } impl Surrogate { pub fn verify(&self, pp: &CardParameters) -> bool { CardProtocol::verify_key_ownership( pp.into(), - &self.pk, + &self.pk.0, &self.name, &self.proof_key.into(), ) @@ -50,15 +49,10 @@ impl Player { name: &Vec, ) -> Result { let (pk, sk) = CardProtocol::player_keygen(rng, pp.into())?; - let proof_key = - CardProtocol::prove_key_ownership(rng, pp.into(), &pk, &sk, name)?; Ok(Self { name: name.clone(), sk, - pk, - proof_key: proof_key.into(), - cards: vec![], - opened_cards: vec![], + pk: PlayerPublicKey(pk), }) } @@ -67,7 +61,7 @@ impl Player { let proof_key = CardProtocol::prove_key_ownership( rng, pp.into(), - &self.pk, + &self.pk.0, &self.sk, &self.name, ) @@ -80,14 +74,6 @@ impl Player { } } - pub fn surrogate(&self) -> Surrogate { - Surrogate { - name: self.name.clone(), - pk: self.pk, - proof_key: self.proof_key, - } - } - pub fn shuffle( &self, parameters: &CardParameters, @@ -103,7 +89,7 @@ impl Player { let (shuffled_deck, shuffle_proof) = CardProtocol::shuffle_and_remask( &mut rng, parameters.into(), - joint_pk, + &joint_pk.0, &deck, &masking_factors, &permutation, @@ -118,7 +104,6 @@ impl Player { } pub fn verify_shuffle( - &self, parameters: &CardParameters, joint_pk: &AggregatePublicKey, original_deck: &Vec, @@ -135,7 +120,7 @@ impl Player { .collect::>(); CardProtocol::verify_shuffle( parameters.into(), - joint_pk, + &joint_pk.0, &original_deck, &shuffled_deck, proof_shuffle.into(), @@ -143,43 +128,30 @@ impl Player { .map_err(|e| GameErrors::CryptoError(e)) } - pub fn receive_card(&mut self, card: MaskedCard) { - self.cards.push(card); - self.opened_cards.push(None); - } - pub fn peek_at_card( - &mut self, parameters: &CardParameters, - reveal_tokens: &mut Vec, + reveal_tokens: &Vec, card_mappings: &HashMap>, card: &MaskedCard, - ) -> Result<()> { - let i = self.cards.iter().position(|&x| x == *card); - - let i = i.ok_or(GameErrors::CardNotFound)?; - - //TODO add function to create that without the proof - let rng = &mut thread_rng(); - let own_reveal_token = self.compute_reveal_token(rng, parameters, card)?; - reveal_tokens.push(RevealedToken { - token: own_reveal_token.0, - proof: own_reveal_token.1, - player: own_reveal_token.2, - }); + cards: &Vec, + ) -> Result> { + let _ = cards + .iter() + .position(|&x| x == *card) + .ok_or(GameErrors::CardNotFound)?; let raw_reveal_tokens = reveal_tokens .iter() - .map(|t| (t.token.into(), t.proof.into(), t.player)) + .map(|t| (t.token.into(), t.proof.into(), t.player.0)) .collect::>(); let unmasked_card = CardProtocol::unmask(parameters.into(), &raw_reveal_tokens, card.into())?; - let opened_card = card_mappings.get(&unmasked_card.into()); - let opened_card = opened_card.ok_or(GameErrors::InvalidCard)?; + let opened_card = card_mappings + .get(&unmasked_card.into()) + .ok_or(GameErrors::InvalidCard)?; - self.opened_cards[i] = Some(serde_json::from_slice(opened_card).unwrap()); - Ok(()) + Ok(opened_card.to_owned()) } pub fn compute_reveal_token( @@ -187,15 +159,19 @@ impl Player { rng: &mut R, pp: &CardParameters, card: &MaskedCard, - ) -> Result<(RevealToken, ProofReveal, PlayerPublicKey)> { + ) -> Result { let (reveal_token, reveal_proof) = CardProtocol::compute_reveal_token( rng, pp.into(), &self.sk, - &self.pk, + &self.pk.0, card.into(), )?; - Ok((reveal_token.into(), reveal_proof.into(), self.pk)) + Ok(RevealedToken { + token: reveal_token.into(), + proof: reveal_proof.into(), + player: self.pk, + }) } }