diff --git a/Cargo.toml b/Cargo.toml index 3d281fd..c98d7a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "shuffle", "matchmaking", "c-uzkge", + "wasm", ] resolver = "2" diff --git a/shuffle/wasm/src/card_maps.rs b/shuffle/wasm/src/card_maps.rs deleted file mode 100644 index 6404a58..0000000 --- a/shuffle/wasm/src/card_maps.rs +++ /dev/null @@ -1,56 +0,0 @@ -pub const CARD_MAPS: [&'static str; 54] = [ - "0x0e7e20b3cb30785b64cd6972e2ddf919db64d03d6cf01456243c5ef2fb766a65", - "0x2d7690deeaa77c9d89b0ceb3c25f7bb09c44f40b4b8cf5d6fcb512c7be8fcba9", - "0x13a50334ef174fd8160bb22e5f150b0ce7656c5c4a19b0ad6bc8f93fdf5fab7c", - "0x02acd55fbf59ea2b7a4733ccb5568681e6445d2cba2a4ee0707c1c1d3bc27fea", - "0x17fd6b5a880d0570dad7bd4da582c2ba03717615764e3955a8bf2a1b546abfa2", - "0x10b37010cd0d430a2bc91ee19f30d1a3d5984605dc299953fdd1ef2fff2f1a95", - "0x2a6a6ec33c00e9d9073ce5e48f45afd40cb29303bbc0367606c6f2963ec057c9", - "0x27bfe4a93f3e0802f37732ef692a7ff681ce6baaacb6e1cc73e972374e58cec2", - "0x2627f2b312c0f1f30b638a1ccc76c7025e94d99cc6006229432fa431044cf7aa", - "0x0eb99c13f783f3416210d34a8e5fa766ae239c4c00cb9d3e81f14dc975a7a957", - "0x1245109a40dc41351a708f1b7c6fb8bcf809c656b366fb1d0fa7a46991d2b977", - "0x000f90cf5f6433978210b9098c0e0865d44f6bc4ab9a7c3cfa63ed7e586f8fa7", - "0x2c957cd805d207f518047f6117ecd42fa98b78734efe4cb588cd409ff25aa0b8", - "0x2d4b20b261ace4d99d8d80a0998133b0f5c49bad68a4a9a92e9fe2084c8dcde8", - "0x23f5c25e039914df2928a715bf68c41ba91b51103d1b1aeaba9323b677b9ea8d", - "0x04578915cb17f8fd142120c1bd5c0a26da6668cd746aad9ce707ccfd4464533f", - "0x18d33bc856f163194090c1c6419aedbedfaf6dcfb23588ce7002d7deb6ea7623", - "0x1db8329a5d644ab56185ebb02724b836c5b1d22d29a57965a0e3a43067e06a08", - "0x17a87862cbcee70b0cd0c442d36e26ed763385bb2e948d8f00469d908aa07e72", - "0x13fa0efab13db7078ee0aa83cf8fd476614c779e530da57c2101177e69cd68e3", - "0x16d52c3e7be3ab38454acdfa2cd7a3cb7a321092f41f038a3ae4f1947bad724e", - "0x14157ff39b00904e49f284a3ae75e225b995e3b123887c2ddea019e791fcf88d", - "0x0967dd7bac9eb504b37cf33860d77e8ed747f54864aabb63b2487c3f249dd2d2", - "0x0047239fd59b5ce078d0fa8a1f0c667b2355fb331bfcfe5fe58754cdade49f2b", - "0x0f220815394d328c3a819ca5dc13219b422b8443eca0b8e6911d2b0078d1bb68", - "0x04c1f519b090dac2ebff9282ca66592f8b9b6c8c2e38705740daa1230fe2b6cc", - "0x169a776c4976ebb48f3c2f3eb6214f26ac70557acd6a28c95044653dee7c7306", - "0x17859495fda1f3ac4d240997cfa7d61d9624006410ddc97c7060a24e9fc1053a", - "0x250f584b0539ef28cb0b7a136b26a2b796fbbde5a0df8236b4775c0e713ef8c8", - "0x025761ba480df2787230ecd283209f959b80a16ff631b751e2213a431a0be30c", - "0x0ac3e3209fa174e4981b53a69ce6c5cbca1e217262a27826621553d15fce1317", - "0x1daa7bc5da2abf17ed3a43a4a3ddec8e0ed6cc3f2a729b6bfab7f4f252f47197", - "0x17e97bb5c68c80f4c0f38eebf4106b0c8ec02c6d9d678588be5f4a71b43c86fe", - "0x1dcedb86bb03fa3b404afd3edaa59ceaf8122b2e9dc35c1cdc9f4c65ac6df154", - "0x2f2ce3a1cddb1e92541481d30b7c43af5d0350266672632ad06728818b6affdb", - "0x2c9fb046ab1f36b104b456598d00e3211fb31b0ef357d7c7de55c4a122257dbe", - "0x078d7b6afe9372d90a9b9e2e5f40dc97c06bed7821c0870c8f19847cb4d6d5ce", - "0x0548073474086bb9f2f2eda49f8625572f2be9d6b71bb293388e3ff9ad8fb7aa", - "0x012b6918773feaa8a22ac16c2e243f2c371c98dbf13801ad0bb9f4cee4575c8d", - "0x1abcecb5d562b19da37897d7db6f6227be857493300e1f38d234b43d36037b5d", - "0x2fb979bcc2cc562386634c502b9425003d9c0876250b28e21996de4babe104cc", - "0x173e80227d906db5ba7289d3611dae189797aa8e3e235949e76d2ce97f6f3c73", - "0x022a95649ff5d46713821806b85466cf709ad85171567cf1c0692940793dd30f", - "0x00fbc18c6483aef1404ac3e81cae370bb7c9548b5d76124017d522043fc19a6c", - "0x1d65fcc3af60454fcb4b6a5fd74eb5c3305757a8a47ff7d07cd92e74cb2a1fbb", - "0x227532d0e59b89a139600b60e96a3a8950a93dfa61e40ae623bd16f5529c0687", - "0x10f119e93c8adb81acde0c8876e199a30fa0e5f96345a14ab5e6aee59ad80e12", - "0x1785b53f50e8bb17af2e5394c3c12bcf8349c13b45a0f0aff2da29070e2109b2", - "0x0e928ce03f8f6d07a6c818b295bbc453034e07c55f43eb85b576b22739eb4a51", - "0x0d55d8fae5d67f985fe733eaf647f53f42490c2226e54bb7058031fc5e4ef58e", - "0x0759e62cf2464671501c16a8534d28bc2e5721a1de966ff2ef9e924424765f41", - "0x25bebd6ecfef4f2613efc455e4038489febf84079c88c787977fee2e07629b4b", - "0x1464429b0e93a259cec0b660c0bb6df28cb408706eee28f4e77a5e61c931f6f5", - "0x142fb87f6d0974097206facac23ea38ffa01e3e1e45003e3ec238b6516eb0b2e", -]; diff --git a/shuffle/wasm/src/lib.rs b/shuffle/wasm/src/lib.rs deleted file mode 100644 index 14beb4c..0000000 --- a/shuffle/wasm/src/lib.rs +++ /dev/null @@ -1,494 +0,0 @@ -mod card_maps; -mod utils; - -mod poker; -use ark_ec::AffineRepr; -pub use poker::*; - -use ark_ed_on_bn254::{EdwardsAffine, EdwardsProjective, Fq, Fr}; -use ark_ff::{BigInteger, One, PrimeField}; -use once_cell::sync::Lazy; -use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, sync::Mutex}; -use uzkge::{ - chaum_pedersen::dl::ChaumPedersenDLProof, - gen_params::{ProverParams, VerifierParams}, -}; -use wasm_bindgen::prelude::*; -use zshuffle::{ - build_cs::{prove_shuffle, verify_shuffle}, - gen_params::{ - gen_shuffle_prover_params, load_groth16_pk, params::refresh_prover_params_public_key, - }, - keygen::{aggregate_keys as core_aggregate_keys, Keypair as CoreKeypair}, - mask::*, - reveal::*, - reveal_with_snark::RevealCircuit, - Groth16, MaskedCard as Masked, ProvingKey, SNARK, -}; - -use card_maps::CARD_MAPS; -use utils::{ - default_prng, error_to_jsvalue, hex_to_point, hex_to_scalar, point_to_hex, point_to_uncompress, - scalar_to_hex, shuffle_proof_from_hex, shuffle_proof_to_hex, uncompress_to_point, -}; - -// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global -// allocator. -#[cfg(feature = "wee_alloc")] -#[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; - -static PARAMS: Lazy>> = Lazy::new(|| { - let m = HashMap::new(); - Mutex::new(m) -}); - -const GROTH16_N: usize = 52; - -static GROTH16_PARAMS: Lazy>>> = - Lazy::new(|| { - let m = HashMap::new(); - Mutex::new(m) - }); - -#[derive(Serialize, Deserialize)] -pub struct Keypair { - /// 0xHex (U256) - pub sk: String, - /// 0xHex (U256) - pub pk: String, - /// public key uncompress x, y - pub pkxy: (String, String), -} - -/// e2.0, e2.1, e1.0, e1.1 -#[derive(Serialize, Deserialize, Clone)] -pub struct MaskedCard(pub String, pub String, pub String, pub String); - -#[derive(Serialize, Deserialize)] -pub struct MaskedCardWithProof { - /// MaskedCard - pub card: MaskedCard, - /// hex string - pub proof: String, -} - -#[derive(Serialize, Deserialize)] -pub struct RevealedCardWithProof { - /// MaskedCard - pub card: (String, String), - /// hex string - pub proof: String, -} - -#[derive(Serialize, Deserialize)] -pub struct RevealedCardWithSnarkProof { - pub card: (String, String), - pub snark_proof: Vec, -} - -#[derive(Serialize, Deserialize)] -pub struct ShuffledCardsWithProof { - /// MaskedCard - pub cards: Vec, - /// hex string - pub proof: String, -} - -/// uncompress public key to x, y -#[wasm_bindgen] -pub fn public_uncompress(pk_s: String) -> Result { - let pk = hex_to_point::(&pk_s)?; - let pkxy = point_to_uncompress(&pk, true); - Ok(serde_wasm_bindgen::to_value(&pkxy)?) -} - -/// comporess (public_x, public_y) to public -#[wasm_bindgen] -pub fn public_compress(publics: JsValue) -> Result { - let publicxy: (String, String) = serde_wasm_bindgen::from_value(publics)?; - let pk = uncompress_to_point(&publicxy.0, &publicxy.1)?; - Ok(point_to_hex(&pk, true)) -} - -/// generate keypair -#[wasm_bindgen] -pub fn generate_key() -> Result { - let mut prng = default_prng(); - let keypair = CoreKeypair::generate(&mut prng); - let pkxy = point_to_uncompress(&keypair.public, true); - - let ret = Keypair { - sk: scalar_to_hex(&keypair.secret, true), - pk: point_to_hex(&keypair.public, true), - pkxy, - }; - - Ok(serde_wasm_bindgen::to_value(&ret)?) -} - -/// aggregate all pk to joint pk -#[wasm_bindgen] -pub fn aggregate_keys(publics: JsValue) -> Result { - let publics: Vec = serde_wasm_bindgen::from_value(publics)?; - let mut pks = vec![]; - for bytes in publics { - pks.push(hex_to_point(&bytes)?); - } - let pk = core_aggregate_keys(&pks).map_err(error_to_jsvalue)?; - Ok(point_to_hex(&pk, true)) -} - -/// mask the card, return the masked card and masked proof -#[wasm_bindgen] -pub fn init_masked_cards(joint: String, num: i32) -> Result { - if CARD_MAPS.len() < num as usize { - return Err(error_to_jsvalue("The number of cards exceeds the maximum")); - } - - let mut prng = default_prng(); - let joint_pk = hex_to_point(&joint)?; - - let mut deck = vec![]; - for n in 0..num { - let point = index_to_point(n); - - let (masked_card, masked_proof) = - mask(&mut prng, &joint_pk, &point, &Fr::one()).map_err(error_to_jsvalue)?; - - deck.push(MaskedCardWithProof { - card: masked_card_serialize(&masked_card), - proof: format!( - "0x{}", - hex::encode(&bincode::serialize(&masked_proof).map_err(error_to_jsvalue)?) - ), - }); - } - - Ok(serde_wasm_bindgen::to_value(&deck)?) -} - -/// mask the card, return the masked card and masked proof -#[wasm_bindgen] -pub fn mask_card(joint: String, index: i32) -> Result { - let mut prng = default_prng(); - let joint_pk = hex_to_point(&joint)?; - let point = index_to_point(index); - let (masked_card, masked_proof) = - mask(&mut prng, &joint_pk, &point, &Fr::one()).map_err(error_to_jsvalue)?; - - let ret = MaskedCardWithProof { - card: masked_card_serialize(&masked_card), - proof: format!( - "0x{}", - hex::encode(&bincode::serialize(&masked_proof).map_err(error_to_jsvalue)?) - ), - }; - - Ok(serde_wasm_bindgen::to_value(&ret)?) -} - -/// verify masked card with the proof -#[wasm_bindgen] -pub fn verify_masked_card( - joint: String, - index: i32, - masked: JsValue, - proof: String, -) -> Result { - let masked: MaskedCard = serde_wasm_bindgen::from_value(masked)?; - - let joint_pk = hex_to_point(&joint)?; - let point = index_to_point(index); - let masked = masked_card_deserialize(&masked)?; - - let hex = proof.trim_start_matches("0x"); - let masked_proof = bincode::deserialize(&hex::decode(hex).map_err(error_to_jsvalue)?) - .map_err(error_to_jsvalue)?; - - Ok(verify_mask(&joint_pk, &point, &masked, &masked_proof).is_ok()) -} - -/// Initialize the prover key -#[wasm_bindgen] -pub fn init_prover_key(num: i32) { - let n = num as usize; - - let mut params = PARAMS.lock().unwrap(); - if params.get(&n).is_none() { - let pp = gen_shuffle_prover_params(n) - .map_err(error_to_jsvalue) - .unwrap(); - params.insert(n, pp); - } - drop(params); -} - - -/// Initialize the reveal key -#[wasm_bindgen] -pub fn init_reveal_key() { - let mut params = GROTH16_PARAMS.lock().unwrap(); - if params.get(&GROTH16_N).is_none() { - let pp = load_groth16_pk(GROTH16_N).map_err(error_to_jsvalue).unwrap(); - params.insert(GROTH16_N, pp); - } - drop(params); -} - -/// refresh joint public key when it changed. -#[wasm_bindgen] -pub fn refresh_joint_key(joint: String, num: i32) -> Result, JsValue> { - let joint_pk = hex_to_point(&joint)?; - let n = num as usize; - - let mut params = PARAMS.lock().unwrap(); - let prover_params = if let Some(param) = params.get_mut(&n) { - param - } else { - let pp = gen_shuffle_prover_params(n) - .map_err(error_to_jsvalue) - .unwrap(); - params.insert(n, pp); - params.get_mut(&n).unwrap() - }; - - let pkc = - refresh_prover_params_public_key(prover_params, &joint_pk).map_err(error_to_jsvalue)?; - drop(params); - - let mut pkc_string: Vec<_> = vec![]; - for p in pkc { - let (x, y) = point_to_uncompress(&p, true); - pkc_string.push(x); - pkc_string.push(y); - } - - Ok(pkc_string) -} - -/// shuffle the cards and shuffled proof -#[wasm_bindgen] -pub fn shuffle_cards(joint: String, deck: JsValue) -> Result { - let deck: Vec = serde_wasm_bindgen::from_value(deck)?; - let n = deck.len(); - - let mut prng = default_prng(); - let joint_pk = hex_to_point(&joint)?; - - let mut masked_deck = vec![]; - for card in deck { - masked_deck.push(masked_card_deserialize(&card)?); - } - - let params = PARAMS.lock().unwrap(); - let prover_params = params - .get(&n) - .expect("Missing PARAMS, need init & refresh pk"); - - let (shuffled_proof, new_deck) = - prove_shuffle(&mut prng, &joint_pk, &masked_deck, &prover_params) - .map_err(error_to_jsvalue)?; - drop(params); - - let masked_cards: Vec<_> = new_deck - .iter() - .map(|card| masked_card_serialize(&card)) - .collect(); - - let ret = ShuffledCardsWithProof { - cards: masked_cards, - proof: shuffle_proof_to_hex(&shuffled_proof), - }; - - Ok(serde_wasm_bindgen::to_value(&ret)?) -} - -/// verify the shuffled cards -#[wasm_bindgen] -pub fn verify_shuffled_cards( - deck1: JsValue, - deck2: JsValue, - proof: String, -) -> Result { - let deck1: Vec = serde_wasm_bindgen::from_value(deck1)?; - let deck2: Vec = serde_wasm_bindgen::from_value(deck2)?; - - let n = deck1.len(); - let mut masked_deck1 = vec![]; - for card in deck1 { - masked_deck1.push(masked_card_deserialize(&card)?); - } - let mut masked_deck2 = vec![]; - for card in deck2 { - masked_deck2.push(masked_card_deserialize(&card)?); - } - let shuffled_proof = shuffle_proof_from_hex(&proof)?; - - let params = PARAMS.lock().unwrap(); - let prover_params = params - .get(&n) - .expect("Missing PARAMS, need init & refresh pk"); - let verifier_params = VerifierParams::from(prover_params); - - Ok(verify_shuffle( - &verifier_params, - &masked_deck1, - &masked_deck2, - &shuffled_proof, - ) - .is_ok()) -} - -/// compute masked to revealed card and the revealed proof -#[wasm_bindgen] -pub fn reveal_card(sk: String, card: JsValue) -> Result { - let card: MaskedCard = serde_wasm_bindgen::from_value(card)?; - - let mut prng = default_prng(); - let keypair = CoreKeypair::from_secret(hex_to_scalar(&sk)?); - let masked = masked_card_deserialize(&card)?; - - let (reveal_card, reveal_proof) = - reveal(&mut prng, &keypair, &masked).map_err(error_to_jsvalue)?; - - let ret = RevealedCardWithProof { - card: point_to_uncompress(&reveal_card, true), - proof: format!("0x{}", hex::encode(&reveal_proof.to_uncompress())), - }; - - Ok(serde_wasm_bindgen::to_value(&ret)?) -} - -/// compute masked to revealed card with a snark proof -#[wasm_bindgen] -pub fn reveal_card_with_snark(sk: String, card: JsValue) -> Result { - let card: MaskedCard = serde_wasm_bindgen::from_value(card)?; - - let mut prng = default_prng(); - let keypair = CoreKeypair::from_secret(hex_to_scalar(&sk)?); - let masked = masked_card_deserialize(&card)?; - - let reveal_card = masked.e1 * keypair.secret; - - let params = GROTH16_PARAMS.lock().unwrap(); - let prover_params = params - .get(&GROTH16_N) - .expect("Missing PARAMS, need init & refresh pk"); - - let circuit = RevealCircuit::new(&keypair.secret, &masked, &reveal_card); - let proof = Groth16::::prove(&prover_params, circuit, &mut prng).unwrap(); - drop(params); - - let a = proof.a.xy().unwrap(); - let b = proof.b.xy().unwrap(); - let c = proof.c.xy().unwrap(); - - let snark_proof = vec![ - scalar_to_hex(&a.0, true), - scalar_to_hex(&a.1, true), - scalar_to_hex(&b.0.c1, true), - scalar_to_hex(&b.0.c0, true), - scalar_to_hex(&b.1.c1, true), - scalar_to_hex(&b.1.c0, true), - scalar_to_hex(&c.0, true), - scalar_to_hex(&c.1, true), - ]; - - let ret = RevealedCardWithSnarkProof { - card: point_to_uncompress(&reveal_card, true), - snark_proof, - }; - - Ok(serde_wasm_bindgen::to_value(&ret)?) -} - -/// verify reveal point -#[wasm_bindgen] -pub fn verify_revealed_card(pk: String, card: JsValue, reveal: JsValue) -> Result { - let card: MaskedCard = serde_wasm_bindgen::from_value(card)?; - let reveal: RevealedCardWithProof = serde_wasm_bindgen::from_value(reveal)?; - - let pk = hex_to_point(&pk)?; - let masked = masked_card_deserialize(&card)?; - - let reveal_card = uncompress_to_point(&reveal.card.0, &reveal.card.1)?; - let hex = reveal.proof.trim_start_matches("0x"); - let reveal_proof = - ChaumPedersenDLProof::from_uncompress(&hex::decode(hex).map_err(error_to_jsvalue)?) - .map_err(error_to_jsvalue)?; - - Ok(verify_reveal(&pk, &masked, &reveal_card, &reveal_proof).is_ok()) -} - -/// unmask the card use others' reveals -#[wasm_bindgen] -pub fn unmask_card(sk: String, card: JsValue, reveals: JsValue) -> Result { - let card: MaskedCard = serde_wasm_bindgen::from_value(card)?; - let reveals: Vec<(String, String)> = serde_wasm_bindgen::from_value(reveals)?; - - let mut prng = default_prng(); - let keypair = CoreKeypair::from_secret(hex_to_scalar(&sk)?); - let masked = masked_card_deserialize(&card)?; - - let mut reveal_cards = vec![]; - for reveal in reveals { - reveal_cards.push(uncompress_to_point(&reveal.0, &reveal.1)?); - } - - let (reveal_card, _proof) = reveal(&mut prng, &keypair, &masked).map_err(error_to_jsvalue)?; - reveal_cards.push(reveal_card); - - let unmasked_card = unmask(&masked, &reveal_cards).map_err(error_to_jsvalue)?; - point_to_index(unmasked_card) -} - -/// decode masked to card use all reveals -#[wasm_bindgen] -pub fn decode_point(card: JsValue, reveals: JsValue) -> Result { - let card: MaskedCard = serde_wasm_bindgen::from_value(card)?; - let reveals: Vec<(String, String)> = serde_wasm_bindgen::from_value(reveals)?; - - let masked = masked_card_deserialize(&card)?; - let mut reveal_cards = vec![]; - for reveal in reveals { - reveal_cards.push(uncompress_to_point(&reveal.0, &reveal.1)?); - } - - let unmasked_card = unmask(&masked, &reveal_cards).map_err(error_to_jsvalue)?; - point_to_index(unmasked_card) -} - -fn index_to_point(index: i32) -> EdwardsProjective { - let y_hex = CARD_MAPS[index as usize].trim_start_matches("0x"); - let y_bytes = hex::decode(y_hex).unwrap(); - let y = Fq::from_be_bytes_mod_order(&y_bytes); - - let affine = EdwardsAffine::get_point_from_y_unchecked(y, true).unwrap(); - affine.into() -} - -fn point_to_index(point: EdwardsProjective) -> Result { - let affine = EdwardsAffine::from(point); - let y_bytes = affine.y.into_bigint().to_bytes_be(); - let bytes = format!("0x{}", hex::encode(&y_bytes)); - - if let Some(pos) = CARD_MAPS.iter().position(|y| y == &bytes) { - Ok(pos as i32) - } else { - Err(error_to_jsvalue("Point not map to a card")) - } -} - -fn masked_card_serialize(masked: &Masked) -> MaskedCard { - let (e1_x, e1_y) = point_to_uncompress(&masked.e1, true); - let (e2_x, e2_y) = point_to_uncompress(&masked.e2, true); - MaskedCard(e2_x, e2_y, e1_x, e1_y) -} - -fn masked_card_deserialize(masked: &MaskedCard) -> Result { - let e2 = uncompress_to_point(&masked.0, &masked.1)?; - let e1 = uncompress_to_point(&masked.2, &masked.3)?; - Ok(Masked { e1, e2 }) -} diff --git a/shuffle/wasm/src/poker.rs b/shuffle/wasm/src/poker.rs deleted file mode 100644 index df483bb..0000000 --- a/shuffle/wasm/src/poker.rs +++ /dev/null @@ -1,48 +0,0 @@ -use serde::{Deserialize, Serialize}; -use wasm_bindgen::prelude::*; - -use crate::utils::error_to_jsvalue; - -/// suite from 1..4 -/// value from 1..13 -/// if suite is 0, it will be joker, value is 53, 54 -#[derive(Serialize, Deserialize)] -pub struct PokerCard { - pub suite: i32, - pub value: i32, -} - -#[wasm_bindgen] -pub fn card_to_index(value: JsValue) -> Result { - let card: PokerCard = serde_wasm_bindgen::from_value(value)?; - if card.value > 52 { - Ok(card.value - 1) - } else { - Ok((card.suite - 1) * 13 + (card.value - 1)) - } -} - -#[wasm_bindgen] -pub fn index_to_card(index: i32) -> Result { - if index > 52 { - return Err(error_to_jsvalue("Index not map to a card")); - } - - let card = if index == 52 { - PokerCard { - suite: 0, - value: 53, - } - } else if index == 53 { - PokerCard { - suite: 0, - value: 53, - } - } else { - let suite = index / 13 + 1; - let value = index % 13 + 1; - PokerCard { suite, value } - }; - - Ok(serde_wasm_bindgen::to_value(&card)?) -} diff --git a/shuffle/wasm/src/utils.rs b/shuffle/wasm/src/utils.rs deleted file mode 100644 index 667d157..0000000 --- a/shuffle/wasm/src/utils.rs +++ /dev/null @@ -1,114 +0,0 @@ -use ark_bn254::Fr; -use ark_ec::{AffineRepr, CurveGroup}; -use ark_ed_on_bn254::{EdwardsAffine, EdwardsProjective, Fq}; -use ark_ff::{BigInteger, PrimeField}; -use ark_serialize::{Compress, Validate}; -use rand_chacha::{ - rand_core::{CryptoRng, RngCore, SeedableRng}, - ChaChaRng, -}; -use serde::{Deserialize, Serialize}; -use std::fmt::Display; -use uzkge::{ - plonk::{constraint_system::TurboCS, indexer::PlonkProof}, - poly_commit::kzg_poly_commitment::KZGCommitmentSchemeBN254, -}; -use wasm_bindgen::prelude::*; - -#[inline(always)] -pub(crate) fn error_to_jsvalue(e: T) -> JsValue { - JsValue::from_str(&e.to_string()) -} - -pub fn default_prng() -> impl RngCore + CryptoRng { - ChaChaRng::from_entropy() -} - -#[allow(non_snake_case)] -#[derive(Serialize, Deserialize)] -pub struct BigNumber { - _isBigNumber: bool, - _hex: String, -} - -pub fn hex_to_scalar(hex: &str) -> Result { - let hex = hex.trim_start_matches("0x"); - let bytes = hex::decode(hex).map_err(error_to_jsvalue)?; - if bytes.len() != 32 { - return Err(error_to_jsvalue("Bytes length not 32")); - } - Ok(F::from_be_bytes_mod_order(&bytes)) -} - -pub fn scalar_to_hex(scalar: &F, with_start: bool) -> String { - let bytes = scalar.into_bigint().to_bytes_be(); - let s = hex::encode(&bytes); - if with_start { - format!("0x{}", s) - } else { - s - } -} - -pub fn hex_to_point(hex: &str) -> Result { - let hex = hex.trim_start_matches("0x"); - let bytes = hex::decode(hex).map_err(error_to_jsvalue)?; - G::deserialize_with_mode(bytes.as_slice(), Compress::Yes, Validate::Yes) - .map_err(error_to_jsvalue) -} - -pub fn point_to_hex(point: &G, with_start: bool) -> String { - let mut bytes = Vec::new(); - point - .serialize_with_mode(&mut bytes, Compress::Yes) - .unwrap(); - let s = hex::encode(&bytes); - if with_start { - format!("0x{}", s) - } else { - s - } -} - -pub fn point_to_uncompress>( - point: &G, - with_start: bool, -) -> (String, String) { - let affine = G::Affine::from(*point); - let (x, y) = affine.xy().unwrap(); - let x_bytes = x.into_bigint().to_bytes_be(); - let y_bytes = y.into_bigint().to_bytes_be(); - let x = hex::encode(&x_bytes); - let y = hex::encode(&y_bytes); - - if with_start { - (format!("0x{}", x), format!("0x{}", y)) - } else { - (x, y) - } -} - -pub fn uncompress_to_point(x_str: &str, y_str: &str) -> Result { - let x_hex = x_str.trim_start_matches("0x"); - let y_hex = y_str.trim_start_matches("0x"); - let x_bytes = hex::decode(x_hex).map_err(error_to_jsvalue)?; - let y_bytes = hex::decode(y_hex).map_err(error_to_jsvalue)?; - - let x = Fq::from_be_bytes_mod_order(&x_bytes); - let y = Fq::from_be_bytes_mod_order(&y_bytes); - let affine = EdwardsAffine::new(x, y); - - Ok(affine.into()) -} - -pub fn shuffle_proof_from_hex(s: &str) -> Result, JsValue> { - let hex = s.trim_start_matches("0x"); - let bytes = hex::decode(hex).map_err(error_to_jsvalue)?; - PlonkProof::::from_bytes_be::>(&bytes) - .map_err(error_to_jsvalue) -} - -pub fn shuffle_proof_to_hex(proof: &PlonkProof) -> String { - let bytes = proof.to_bytes_be(); - format!("0x{}", hex::encode(bytes)) -} diff --git a/shuffle/wasm/.appveyor.yml b/wasm/.appveyor.yml similarity index 100% rename from shuffle/wasm/.appveyor.yml rename to wasm/.appveyor.yml diff --git a/shuffle/wasm/.gitignore b/wasm/.gitignore similarity index 100% rename from shuffle/wasm/.gitignore rename to wasm/.gitignore diff --git a/shuffle/wasm/.travis.yml b/wasm/.travis.yml similarity index 100% rename from shuffle/wasm/.travis.yml rename to wasm/.travis.yml diff --git a/shuffle/wasm/Cargo.toml b/wasm/Cargo.toml similarity index 93% rename from shuffle/wasm/Cargo.toml rename to wasm/Cargo.toml index 232d241..13bff5d 100644 --- a/shuffle/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -11,8 +11,9 @@ crate-type = ["cdylib", "rlib"] default = ["console_error_panic_hook"] [dependencies] -zshuffle = { path = "../" } -uzkge = { path = "../../uzkge" } +zshuffle = { path = "../shuffle" } +zmatchmaking = { path = "../matchmaking" } +uzkge = { path = "../uzkge" } ark-ec = { version= "0.4", default-features = false } ark-ff = { version= "0.4", default-features = false } ark-serialize = { version = "0.4", default-features = false } diff --git a/shuffle/wasm/README.md b/wasm/README.md similarity index 100% rename from shuffle/wasm/README.md rename to wasm/README.md diff --git a/wasm/src/anemoi.rs b/wasm/src/anemoi.rs new file mode 100644 index 0000000..130ded5 --- /dev/null +++ b/wasm/src/anemoi.rs @@ -0,0 +1,19 @@ +use alloc::{string::String, vec::Vec}; +use ark_bn254::Fr; +use ark_ff::{BigInteger, PrimeField}; +use uzkge::anemoi::{AnemoiJive, AnemoiJive254}; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub fn anemoi_hash(datas: Vec) -> Vec { + let mut inputs: Vec = Vec::new(); + for data in datas { + let input = hex::decode(data).expect("hex decode data error"); + let input = Fr::from_be_bytes_mod_order(&input); + inputs.push(input); + } + + let res = AnemoiJive254::eval_variable_length_hash(&inputs); + + res.into_bigint().to_bytes_be() +} diff --git a/wasm/src/ed_on_bn254.rs b/wasm/src/ed_on_bn254.rs new file mode 100644 index 0000000..e124329 --- /dev/null +++ b/wasm/src/ed_on_bn254.rs @@ -0,0 +1,56 @@ +use alloc::{string::String, vec::Vec}; +use ark_ec::{AffineRepr, CurveGroup}; +use ark_ed_on_bn254::{EdwardsAffine, Fq, Fr}; +use ark_ff::{BigInteger, PrimeField}; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub fn point_add(x1: String, x2: String, y1: String, y2: String) -> Vec { + let x1 = hex::decode(x1).expect("hex decode x1 error"); + let x_1 = Fq::from_be_bytes_mod_order(&x1); + + let x2 = hex::decode(x2).expect("hex decode x2 error"); + let x_2 = Fq::from_be_bytes_mod_order(&x2); + + let y1 = hex::decode(y1).expect("hex decode y1 error"); + let y_1 = Fq::from_be_bytes_mod_order(&y1); + + let y2 = hex::decode(y2).expect("hex decode y2 error"); + let y_2 = Fq::from_be_bytes_mod_order(&y2); + + let mut ret = [0u8; 64]; + let p1 = EdwardsAffine::new(x_1, y_1); + let p2 = EdwardsAffine::new(x_2, y_2); + let p3 = p1 + p2; + + if let Some((r_x, r_y)) = p3.into_affine().xy() { + ret[0..32].copy_from_slice(&r_x.into_bigint().to_bytes_be()); + ret[32..64].copy_from_slice(&r_y.into_bigint().to_bytes_be()); + } + ret.to_vec() +} + +#[wasm_bindgen] +pub fn scalar_mul(s: String, x: String, y: String) -> i32 { + let s = hex::decode(s).expect("hex decode s error"); + let s = Fr::from_be_bytes_mod_order(&s); + + let x = hex::decode(x).expect("hex decode s error"); + let x = Fq::from_be_bytes_mod_order(&x); + + let y = hex::decode(y).expect("hex decode s error"); + let y = Fq::from_be_bytes_mod_order(&y); + + let mut ret = [0u8; 64]; + let p = EdwardsAffine::new(x, y); + let p2 = p * s; + + match p2.into_affine().xy() { + Some((r_x, r_y)) => { + ret[0..32].copy_from_slice(&r_x.into_bigint().to_bytes_be()); + ret[32..64].copy_from_slice(&r_y.into_bigint().to_bytes_be()); + ret.len() as i32 + } + None => -1, + } +} diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs new file mode 100644 index 0000000..bab373d --- /dev/null +++ b/wasm/src/lib.rs @@ -0,0 +1,10 @@ +#![no_std] +#![deny(warnings)] + +extern crate alloc; + +pub mod ed_on_bn254; + +pub mod anemoi; + +pub mod plonk; diff --git a/wasm/src/plonk.rs b/wasm/src/plonk.rs new file mode 100644 index 0000000..388239f --- /dev/null +++ b/wasm/src/plonk.rs @@ -0,0 +1,125 @@ +use alloc::{format, string::String, vec::Vec}; +use ark_bn254::Fr; +use ark_ed_on_bn254::{EdwardsAffine, EdwardsProjective, Fq}; +use ark_ff::PrimeField; +use uzkge::gen_params::VerifierParams; +use zmatchmaking::build_cs::{verify_matchmaking, Proof}; +use zshuffle::{build_cs::verify_shuffle, MaskedCard}; + +pub fn plonk_verify_matchmaking( + verifier_params: String, + inputs: Vec, + outputs: Vec, + commitment: String, + random_number: String, + proof: String, +) -> bool { + let verifier_params: VerifierParams = { + let data = hex::decode(verifier_params).expect("hex decode verifier_params error"); + bincode::deserialize(&data).expect("bincode deserialize verifier_params error") + }; + + let mut input_param = Vec::new(); + for (index, input) in inputs.iter().enumerate() { + let data = hex::decode(input).expect(&format!("hex decode {} input error", index)); + let input = Fr::from_be_bytes_mod_order(&data); + input_param.push(input) + } + + let mut output_param = Vec::new(); + for (index, output) in outputs.iter().enumerate() { + let data = hex::decode(output).expect(&format!("hex decode {} output error", index)); + let output = Fr::from_be_bytes_mod_order(&data); + output_param.push(output) + } + + let commitment = { + let data = hex::decode(commitment).expect("hex decode commitment error"); + Fr::from_be_bytes_mod_order(&data) + }; + + let random_number = { + let data = hex::decode(random_number).expect("hex decode random_number error"); + Fr::from_be_bytes_mod_order(&data) + }; + + let proof: Proof = { + let data = hex::decode(proof).expect("hex decode proof error"); + bincode::deserialize(&data).expect("bincode deserialize proof error") + }; + + match verify_matchmaking( + &verifier_params, + &input_param, + &output_param, + &commitment, + &random_number, + &proof, + ) { + Ok(_) => true, + Err(_e) => false, + } +} + +fn bytes_2_masked_card(cards: &[Vec]) -> Option { + let e1: EdwardsProjective = { + let x = Fq::from_be_bytes_mod_order(cards.first()?); + let y = Fq::from_be_bytes_mod_order(cards.get(1)?); + let affine = EdwardsAffine::new(x, y); + affine.into() + }; + + let e2: EdwardsProjective = { + let x = Fq::from_be_bytes_mod_order(cards.get(2)?); + let y = Fq::from_be_bytes_mod_order(cards.get(3)?); + let affine = EdwardsAffine::new(x, y); + affine.into() + }; + Some(MaskedCard { e1, e2 }) +} + +pub fn plonk_verify_shuffle( + verifier_params: String, + inputs: Vec>, + outputs: Vec>, + proof: String, +) -> bool { + let verifier_params: VerifierParams = { + let data = hex::decode(verifier_params).expect("hex decode verifier_params error"); + bincode::deserialize(&data).expect("bincode deserialize verifier_params error") + }; + + let mut input_param = Vec::new(); + for (i, cards) in inputs.iter().enumerate() { + let mut card_param = Vec::new(); + for (j, card) in cards.iter().enumerate() { + let data = hex::decode(card).expect(&format!("hex decode {} {} input error", i, j)); + card_param.push(data) + } + let input = + bytes_2_masked_card(&card_param).expect(&format!("hex decode {} input error", i)); + input_param.push(input) + } + + let mut output_param = Vec::new(); + for (i, cards) in outputs.iter().enumerate() { + let mut card_param = Vec::new(); + for (j, card) in cards.iter().enumerate() { + let data = hex::decode(card).expect(&format!("hex decode {} {} output error", i, j)); + card_param.push(data) + } + let output = + bytes_2_masked_card(&card_param).expect(&format!("hex decode {} output error", i)); + output_param.push(output) + } + + let proof: Proof = { + let data = hex::decode(proof).expect("hex decode proof error"); + bincode::deserialize(&data).expect("bincode deserialize proof error") + }; + + match verify_shuffle(&verifier_params, &input_param, &output_param, &proof) { + Ok(_) => true, + Err(_e) => false, + } +} diff --git a/shuffle/wasm/tests/web.rs b/wasm/tests/web.rs similarity index 100% rename from shuffle/wasm/tests/web.rs rename to wasm/tests/web.rs