diff --git a/Cargo.toml b/Cargo.toml index 60e0d1064..525de7843 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "src/components/finutils", "src/components/abciapp", "src/components/config", + "src/components/zkcards_wasm", "src/components/wasm", "src/components/wallet_mobile", "src/components/contracts/baseapp", diff --git a/src/components/zkcards_wasm/Cargo.toml b/src/components/zkcards_wasm/Cargo.toml new file mode 100644 index 000000000..47cde0742 --- /dev/null +++ b/src/components/zkcards_wasm/Cargo.toml @@ -0,0 +1,69 @@ +[package] +name = "zkcards-wasm" +version = "0.1.0" +authors = ["simonjiaoh@gmail.com"] +build = "build.rs" +edition = "2021" + +description = "" +repository = "" +license = "" + +# wasm-opt has a segfaulting issue. Disabling for now +[package.metadata.wasm-pack.profile.release] +wasm-opt = false + +[dependencies] +base64 = "0.12" +hex = "0.4.2" +js-sys = "0.3.27" +rand_chacha = "0.2" +rand_core = { version = "0.5", default-features = false, features = ["alloc"] } +rand = { version = "0.7", features = ["wasm-bindgen"] } +serde = { version = "1.0.124", features = ["derive"] } +serde_json = "1.0" +wasm-bindgen = { version = "=0.2.84", features = ["serde-serialize"] } + +ring = "0.16.19" +aes-gcm = "0.9.0" +bech32 = "0.7.2" + +# Must enable the "js"-feature, +# OR the compiling will fail. +getrandom = { version = "0.2", features = ["js"] } + +zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } + +ark-ff = "0.3.0" +ark-std = { version = "0.3.0", features = ["std"] } +ark-serialize = { version = "0.3.0", features = ["derive"] } +proof-essentials = { git = "https://github.com/FindoraNetwork/proof-toolbox.git", branch = "findora" } +starknet-curve = { git = "https://github.com/FindoraNetwork/proof-toolbox.git", branch = "findora" } +barnett = { git = "https://github.com/simonjiao/mental-poker.git", branch = "develop", package = "barnett-smart-card-protocol" } + +[lib] +crate-type = ["cdylib", "rlib"] +path = "src/wasm.rs" + +[dependencies.web-sys] +version = "0.3.4" +features = [ + 'Headers', + 'Request', + 'RequestInit', + 'RequestMode', + 'Response', + 'Window', + 'console', +] + +[build-dependencies] +serde = "1.0.124" +serde_json = "1.0.41" +vergen = "=3.1.0" +wasm-bindgen = { version = "=0.2.84", features = ["serde-serialize"] } + +[dev-dependencies] +# Must enable the "js"-feature, +# OR the compiling will fail. +getrandom = { version = "0.2", features = ["js"] } diff --git a/src/components/zkcards_wasm/build.rs b/src/components/zkcards_wasm/build.rs new file mode 100644 index 000000000..01d913101 --- /dev/null +++ b/src/components/zkcards_wasm/build.rs @@ -0,0 +1,11 @@ +use vergen::{generate_cargo_keys, ConstantsFlags}; + +fn main() { + let mut flags = ConstantsFlags::all(); + // Tell vergen to use the semver from cargo and not `git describe` + flags.set(ConstantsFlags::SEMVER, false); + flags.set(ConstantsFlags::SEMVER_FROM_CARGO_PKG, true); + + // Generate the 'cargo:' key output + generate_cargo_keys(flags).expect("Unable to generate the cargo keys!"); +} diff --git a/src/components/zkcards_wasm/conf.json b/src/components/zkcards_wasm/conf.json new file mode 100644 index 000000000..97d025f9e --- /dev/null +++ b/src/components/zkcards_wasm/conf.json @@ -0,0 +1,3 @@ +{ + "plugins": ["plugins/markdown"] +} diff --git a/src/components/zkcards_wasm/demo.js b/src/components/zkcards_wasm/demo.js new file mode 100644 index 000000000..7e0244aa1 --- /dev/null +++ b/src/components/zkcards_wasm/demo.js @@ -0,0 +1,71 @@ +// Call 'wasm-pack build --target nodejs' to build from this directory for this command to work +const wasm = require('./pkg/wasm.js'); +const axios = require('axios'); +const HOST = "localhost"; +const SUBMISSION_PORT = "8669"; +const QUERY_PORT= "8668"; + +// Create some keypairs +let kp_alice = wasm.new_keypair(); +let kp_bob = wasm.new_keypair(); +let kp_charlie = wasm.new_keypair(); +let kp_auditor = wasm.new_keypair(); + +console.log(wasm.public_key_to_base64(kp_bob.get_pk())); + +// And a separate tracking key for the auditor +let tracking_kp_auditor = wasm.generate_elgamal_keys(); + +// Alice will define an asset +let token_code = wasm.random_asset_type(); +let memo = "test memo"; +let definition_transaction = wasm.WasmTransactionBuilder.new().add_operation_create_asset(kp_alice, memo, token_code).transaction(); + +let route = 'http://' + HOST + ':' + SUBMISSION_PORT; +let ledger = 'http://' + HOST + ':' + QUERY_PORT; + +axios.post(route + '/submit_transaction', JSON.parse(definition_transaction)) + .then(function(response) { + console.log("Successfully defined asset."); + }) + .catch(function(e) { + console.log("Error defining asset. Perhaps the asset has already been created?"); + console.log(e); + }); + +// At this point, transaction would be submitted to the ledger +// Once the definition transaction succeeds, Alice can issue and transfer 1000 units to herself +// Sometimes, it is necessary to have a handle on the issuance output for complicated operations like issuances + transfers. +// Here is an example: + +// Manually construct issuance output +let conf_amount = false; +let conf_type = false; +let blind_asset_record = wasm.create_blind_asset_record(1000n, token_code, kp_alice.get_pk(), conf_amount, conf_type); + +// Construct transfer operation first +let transfer_op = wasm.WasmTransferOperationBuilder.new() + .add_input(wasm.create_relative_txo_ref(0n), + wasm.open_blind_asset_record(blind_asset_record, kp_alice), + 1000n) + .add_output(1000n, kp_bob.get_pk(), token_code) + .create(wasm.standard_transfer_type()) + .sign(kp_alice) + .transaction(); + +// Txn with issuance and transfer operation +let issue_and_transfer_txn = wasm.WasmTransactionBuilder.new() + .add_operation_issue_asset(kp_alice, token_code, 1n, blind_asset_record) + .add_operation(transfer_op) + .transaction(); + +axios.post(route + '/submit_transaction', JSON.parse(issue_and_transfer_txn)) + .then(function(response) { + console.log("Issued and transferred asset."); + + }) + .catch(function(_) { + console.log("Error issuing and transferring asset"); + }); + + diff --git a/src/components/zkcards_wasm/input.json b/src/components/zkcards_wasm/input.json new file mode 100644 index 000000000..03b058fd6 --- /dev/null +++ b/src/components/zkcards_wasm/input.json @@ -0,0 +1,28 @@ +{ + "wasm-funcs": [ + { "name": "create_asset", + "result": "Result", + "args": [ [ "key_pair", "KeyPair" ], + [ "token_code", "String" ], + [ "updatable", "bool" ], + [ "traceable", "bool" ] + ] + }, + { "name": "issue_asset", + "result": "Result", + "args": [ [ "key_pair", "KeyPair" ], + [ "token_code", "String" ], + [ "seq_num", "u64" ], + [ "amount", "u64" ] + ] + }, + { "name": "transfer_asset", + "result": "Result", + "args": [ [ "key_pair", "KeyPair" ], + [ "txo_sid", "u64" ], + [ "amount", "u64" ], + [ "blind_asset_record_str", "String" ] + ] + } + ] +} diff --git a/src/components/zkcards_wasm/src/wasm.rs b/src/components/zkcards_wasm/src/wasm.rs new file mode 100644 index 000000000..eda903f4d --- /dev/null +++ b/src/components/zkcards_wasm/src/wasm.rs @@ -0,0 +1,15 @@ +//! +//! Interface for issuing transactions that can be compiled to Wasm. +//! +//! Allows web clients to issue transactions from a browser contexts. +//! +//! For now, forwards transactions to a ledger hosted locally. +//! +//! To compile wasm package, run wasm-pack build in the wasm directory. +//! + +#![allow(warnings)] +#![deny(missing_docs)] +#![allow(clippy::needless_borrow)] + +mod zkcards; diff --git a/src/components/zkcards_wasm/src/zkcards/error.rs b/src/components/zkcards_wasm/src/zkcards/error.rs new file mode 100644 index 000000000..23aacd8f1 --- /dev/null +++ b/src/components/zkcards_wasm/src/zkcards/error.rs @@ -0,0 +1,38 @@ +use barnett::error::CardProtocolError; +use proof_essentials::error::CryptoError; +use std::fmt::{Display, Formatter}; + +pub type Result = std::result::Result; + +#[derive(Debug, PartialEq)] +pub enum GameErrors { + InvalidParameters, + CardNotFound, + InvalidCard, + NotReady, + AllShuffled, + ProtocolError(CardProtocolError), + CryptoError(CryptoError), + NotEnoughRevealedTokens(u32), +} + +impl Display for GameErrors { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidParameters => write!(f, "Invalid config parameters"), + Self::CardNotFound => write!(f, "No such card in hand"), + Self::InvalidCard => write!(f, "Invalid card"), + Self::NotReady => write!(f, "Game not Ready"), + Self::AllShuffled => write!(f, "All players have been shuffled"), + Self::ProtocolError(e) => write!(f, "Protocol Error: {}", e.to_string()), + Self::CryptoError(e) => write!(f, "Crypto Error: {}", e.to_string()), + Self::NotEnoughRevealedTokens(_) => write!(f, "No enough revealed tokens"), + } + } +} + +impl From for GameErrors { + fn from(value: CardProtocolError) -> Self { + Self::ProtocolError(value) + } +} diff --git a/src/components/zkcards_wasm/src/zkcards/mod.rs b/src/components/zkcards_wasm/src/zkcards/mod.rs new file mode 100644 index 000000000..21ff72f8b --- /dev/null +++ b/src/components/zkcards_wasm/src/zkcards/mod.rs @@ -0,0 +1,203 @@ +mod error; +mod player; +mod user_card; + +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use barnett::discrete_log_cards; +use proof_essentials::{ + homomorphic_encryption::el_gamal::ElGamal, + vector_commitment::pedersen::PedersenCommitment, + zkp::{ + arguments::shuffle, + proofs::{chaum_pedersen_dl_equality, schnorr_identification}, + }, +}; +use serde::{Deserialize, Serialize}; + +// Choose elliptic curve setting +// And instantiate concrete type for our card protocol +type Curve = starknet_curve::Projective; +type Scalar = starknet_curve::Fr; + +type CardProtocol<'a> = discrete_log_cards::DLCards<'a, Curve>; +type Enc = ElGamal; +type Comm = PedersenCommitment; + +#[derive(Deserialize, Serialize)] +pub struct CardParameters( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + discrete_log_cards::Parameters, +); +impl CardParameters { + pub fn card_nums(&self) -> (usize, usize) { + self.0.card_nums() + } +} +impl From> for CardParameters { + fn from(value: discrete_log_cards::Parameters) -> Self { + Self(value) + } +} +impl From for discrete_log_cards::Parameters { + fn from(value: CardParameters) -> Self { + value.0 + } +} +impl<'a> From<&'a CardParameters> for &'a discrete_log_cards::Parameters { + fn from(value: &'a CardParameters) -> Self { + &value.0 + } +} + +pub type PlayerPublicKey = discrete_log_cards::PublicKey; +pub type PlayerSecretKey = discrete_log_cards::PlayerSecretKey; +pub type AggregatePublicKey = discrete_log_cards::PublicKey; + +#[derive(Clone, Copy, Eq, Hash, PartialEq, Debug, Serialize, Deserialize)] +pub struct Card( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + discrete_log_cards::Card, +); +impl From> for Card { + fn from(value: discrete_log_cards::Card) -> Self { + Self(value) + } +} +impl From for discrete_log_cards::Card { + fn from(value: Card) -> Self { + value.0 + } +} + +#[derive(Clone, Copy, Eq, Hash, PartialEq, Debug, Serialize, Deserialize)] +pub struct MaskedCard( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + discrete_log_cards::MaskedCard, +); +impl From> for MaskedCard { + fn from(value: discrete_log_cards::MaskedCard) -> Self { + Self(value) + } +} +impl From for discrete_log_cards::MaskedCard { + fn from(value: MaskedCard) -> Self { + value.0 + } +} +impl<'a> From<&'a MaskedCard> for &'a discrete_log_cards::MaskedCard { + fn from(value: &'a MaskedCard) -> Self { + &value.0 + } +} + +#[derive(Clone, Copy, Eq, Hash, PartialEq, Debug, Serialize, Deserialize)] +pub struct RevealToken( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + discrete_log_cards::RevealToken, +); +impl From> for RevealToken { + fn from(value: discrete_log_cards::RevealToken) -> Self { + Self(value) + } +} +impl From for discrete_log_cards::RevealToken { + fn from(value: RevealToken) -> Self { + value.0 + } +} + +#[derive(Copy, Clone, Deserialize, Serialize)] +pub struct ProofKeyOwnership( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + schnorr_identification::proof::Proof, +); +impl From> for ProofKeyOwnership { + fn from(value: schnorr_identification::proof::Proof) -> Self { + Self(value) + } +} +impl From for schnorr_identification::proof::Proof { + fn from(value: ProofKeyOwnership) -> Self { + value.0 + } +} + +#[derive(Clone, Copy, Eq, Hash, PartialEq, Debug, Deserialize, Serialize)] +pub struct ProofReveal( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + chaum_pedersen_dl_equality::proof::Proof, +); +impl From> for ProofReveal { + fn from(value: chaum_pedersen_dl_equality::proof::Proof) -> Self { + Self(value) + } +} +impl From for chaum_pedersen_dl_equality::proof::Proof { + fn from(value: ProofReveal) -> Self { + value.0 + } +} + +#[derive(Deserialize, Serialize)] +pub struct ProofShuffle( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + shuffle::proof::Proof, +); +impl From> for ProofShuffle { + fn from(value: shuffle::proof::Proof) -> Self { + Self(value) + } +} +impl From for shuffle::proof::Proof { + fn from(value: ProofShuffle) -> Self { + value.0 + } +} +impl<'a> From<&'a ProofShuffle> for &'a shuffle::proof::Proof { + fn from(value: &'a ProofShuffle) -> Self { + &value.0 + } +} + +//pub struct ProofMasking(chaum_pedersen_dl_equality::proof::Proof); +#[derive(Clone, Copy, Eq, Hash, PartialEq, Debug, Deserialize, Serialize)] +pub struct ProofRemasking( + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + chaum_pedersen_dl_equality::proof::Proof, +); +impl From> for ProofRemasking { + fn from(value: chaum_pedersen_dl_equality::proof::Proof) -> Self { + Self(value) + } +} +impl From for chaum_pedersen_dl_equality::proof::Proof { + fn from(value: ProofRemasking) -> Self { + value.0 + } +} + +#[derive(Serialize, Deserialize)] +pub struct RevealedToken { + pub token: RevealToken, + pub proof: ProofReveal, + #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")] + pub player: PlayerPublicKey, +} + +fn ark_se(a: &A, s: S) -> Result +where + S: serde::Serializer, +{ + let mut bytes = vec![]; + a.serialize(&mut bytes).map_err(serde::ser::Error::custom)?; + s.serialize_bytes(&bytes) +} + +fn ark_de<'de, D, A: CanonicalDeserialize>(data: D) -> Result +where + D: serde::de::Deserializer<'de>, +{ + let s: Vec = serde::de::Deserialize::deserialize(data)?; + let a = A::deserialize(s.as_slice()); + a.map_err(serde::de::Error::custom) +} diff --git a/src/components/zkcards_wasm/src/zkcards/player.rs b/src/components/zkcards_wasm/src/zkcards/player.rs new file mode 100644 index 000000000..7bb04a341 --- /dev/null +++ b/src/components/zkcards_wasm/src/zkcards/player.rs @@ -0,0 +1,201 @@ +use super::{ + ark_de, ark_se, + error::{GameErrors, Result}, + user_card::ClassicPlayingCard, + AggregatePublicKey, Card, CardParameters, CardProtocol, MaskedCard, PlayerPublicKey, + PlayerSecretKey, ProofKeyOwnership, ProofReveal, ProofShuffle, RevealToken, + RevealedToken, Scalar, +}; +use ark_std::rand::Rng; +use barnett::BarnettSmartProtocol; +use proof_essentials::utils::{permutation::Permutation, rand::sample_vector}; +use rand::thread_rng; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Clone)] +pub struct Player { + name: Vec, + sk: PlayerSecretKey, + pk: PlayerPublicKey, + proof_key: ProofKeyOwnership, + cards: Vec, + opened_cards: Vec>, +} + +#[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, +} + +impl Surrogate { + pub fn verify(&self, pp: &CardParameters) -> bool { + CardProtocol::verify_key_ownership( + pp.into(), + &self.pk, + &self.name, + &self.proof_key.into(), + ) + .is_ok() + } +} + +impl Player { + pub fn new( + rng: &mut R, + pp: &CardParameters, + 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![], + }) + } + + pub fn new_surrogate(&self, pp: &CardParameters) -> Surrogate { + let rng = &mut thread_rng(); + let proof_key = CardProtocol::prove_key_ownership( + rng, + pp.into(), + &self.pk, + &self.sk, + &self.name, + ) + .unwrap(); + + Surrogate { + name: self.name.clone(), + pk: self.pk, + proof_key: proof_key.into(), + } + } + + pub fn surrogate(&self) -> Surrogate { + Surrogate { + name: self.name.clone(), + pk: self.pk, + proof_key: self.proof_key, + } + } + + pub fn shuffle( + &self, + parameters: &CardParameters, + deck: &Vec, + joint_pk: &AggregatePublicKey, + nums_of_cards: usize, + ) -> Result<(Vec, ProofShuffle)> { + let mut rng = thread_rng(); + let permutation = Permutation::new(&mut rng, nums_of_cards); + let masking_factors: Vec = sample_vector(&mut rng, nums_of_cards); + + let deck = deck.iter().map(|c| c.clone().into()).collect::>(); + let (shuffled_deck, shuffle_proof) = CardProtocol::shuffle_and_remask( + &mut rng, + parameters.into(), + joint_pk, + &deck, + &masking_factors, + &permutation, + )?; + + let shuffled_deck = shuffled_deck + .into_iter() + .map(|c| c.into()) + .collect::>(); + + Ok((shuffled_deck, shuffle_proof.into())) + } + + pub fn verify_shuffle( + &self, + parameters: &CardParameters, + joint_pk: &AggregatePublicKey, + original_deck: &Vec, + shuffled_deck: &Vec, + proof_shuffle: &ProofShuffle, + ) -> Result<()> { + let original_deck = original_deck + .iter() + .map(|e| e.clone().into()) + .collect::>(); + let shuffled_deck = shuffled_deck + .iter() + .map(|e| e.clone().into()) + .collect::>(); + CardProtocol::verify_shuffle( + parameters.into(), + joint_pk, + &original_deck, + &shuffled_deck, + proof_shuffle.into(), + ) + .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, + 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, + }); + + let raw_reveal_tokens = reveal_tokens + .iter() + .map(|t| (t.token.into(), t.proof.into(), t.player)) + .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)?; + + self.opened_cards[i] = Some(serde_json::from_slice(opened_card).unwrap()); + Ok(()) + } + + pub fn compute_reveal_token( + &self, + rng: &mut R, + pp: &CardParameters, + card: &MaskedCard, + ) -> Result<(RevealToken, ProofReveal, PlayerPublicKey)> { + let (reveal_token, reveal_proof) = CardProtocol::compute_reveal_token( + rng, + pp.into(), + &self.sk, + &self.pk, + card.into(), + )?; + + Ok((reveal_token.into(), reveal_proof.into(), self.pk)) + } +} diff --git a/src/components/zkcards_wasm/src/zkcards/user_card.rs b/src/components/zkcards_wasm/src/zkcards/user_card.rs new file mode 100644 index 000000000..96dc7e9f5 --- /dev/null +++ b/src/components/zkcards_wasm/src/zkcards/user_card.rs @@ -0,0 +1,117 @@ +use super::Card; +use ark_ff::UniformRand; +use ark_std::rand::Rng; +use barnett::discrete_log_cards; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(PartialEq, Clone, Copy, Eq, Serialize, Deserialize)] +pub enum Suite { + Club, + Diamond, + Heart, + Spade, +} + +impl Suite { + pub(crate) const VALUES: [Self; 4] = + [Self::Club, Self::Diamond, Self::Heart, Self::Spade]; +} + +#[derive(PartialEq, PartialOrd, Clone, Copy, Eq, Serialize, Deserialize)] +pub enum Value { + Two, + Three, + Four, + Five, + Six, + Seven, + Eight, + Nine, + Ten, + Jack, + Queen, + King, + Ace, +} + +impl Value { + pub(crate) const VALUES: [Self; 13] = [ + Self::Two, + Self::Three, + Self::Four, + Self::Five, + Self::Six, + Self::Seven, + Self::Eight, + Self::Nine, + Self::Ten, + Self::Jack, + Self::Queen, + Self::King, + Self::Ace, + ]; +} + +#[derive(PartialEq, Clone, Eq, Copy, Serialize, Deserialize)] +pub struct ClassicPlayingCard { + value: Value, + suite: Suite, +} + +impl ClassicPlayingCard { + pub fn new(value: Value, suite: Suite) -> Self { + Self { value, suite } + } +} + +impl std::fmt::Debug for ClassicPlayingCard { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let suite = match self.suite { + Suite::Club => "♣", + Suite::Diamond => "♦", + Suite::Heart => "♥", + Suite::Spade => "♠", + }; + + let val = match self.value { + Value::Two => "2", + Value::Three => "3", + Value::Four => "4", + Value::Five => "5", + Value::Six => "6", + Value::Seven => "7", + Value::Eight => "8", + Value::Nine => "9", + Value::Ten => "10", + Value::Jack => "J", + Value::Queen => "Q", + Value::King => "K", + Value::Ace => "A", + }; + + write!(f, "{}{}", val, suite) + } +} + +pub(crate) fn encode_cards( + rng: &mut R, + num_of_cards: usize, +) -> HashMap> { + let mut map = HashMap::new(); + let plaintexts = (0..num_of_cards) + .map(|_| discrete_log_cards::Card::rand(rng).into()) + .collect::>(); + + let mut i = 0; + for value in Value::VALUES.iter().copied() { + for suite in Suite::VALUES.iter().copied() { + let current_card = ClassicPlayingCard::new(value, suite); + let raw_card = serde_json::to_vec(¤t_card).unwrap(); + map.insert(plaintexts[i], raw_card); + i += 1; + } + } + + map +} diff --git a/src/components/zkcards_wasm/test.js b/src/components/zkcards_wasm/test.js new file mode 100644 index 000000000..3c6b6fca7 --- /dev/null +++ b/src/components/zkcards_wasm/test.js @@ -0,0 +1,42 @@ + +// Call 'wasm-pack build --target nodejs' to build from this directory for this command to work +const wasm = require('./pkg/wasm.js'); +const axios = require('axios'); +const HOST = "localhost"; +const SUBMISSION_PORT = "8669"; + +// Create some keypairs +let kp_alice = wasm.new_keypair(); + +let define = function() { +let memo = "test asset"; +let asset_type = wasm.random_asset_type(); +let definition_transaction = wasm.WasmTransactionBuilder.new().add_operation_create_asset(kp_alice, memo, asset_type).transaction(); + +// define an asset +let route = 'http://' + HOST + ':' + SUBMISSION_PORT; + +axios.post(route + '/submit_transaction', JSON.parse(definition_transaction)) + .then(function(response) { + console.log("Successfully defined asset."); + }) + .catch(function(e) { + console.log("Error defining asset. Perhaps the asset has already been created?"); + console.log(e); + }); + +let issuance_transaction = wasm.WasmTransactionBuilder.new() + .add_basic_issue_asset(kp_alice, "", asset_type, 0n, 1000n) + .transaction(); + +axios.post(route + '/submit_transaction', JSON.parse(issuance_transaction)) + .then(function(response) { + console.log("Successfully issued asset."); + }) + .catch(function(e) { + console.log("Error issuing asset."); + console.log(e); + }); +} + +setInterval(define, 1000);