From 097f51223715764460cc6a59351f631ad6931ae7 Mon Sep 17 00:00:00 2001 From: kilic Date: Mon, 2 Nov 2020 13:23:42 +0300 Subject: [PATCH] add new circuit gen endpoint add verifier key export endpoint --- README.md | 8 +- src/wasm/wasm.rs | 220 ++++++++++++++++++++++++----------------------- 2 files changed, 119 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index de790b6..a2a61f2 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,13 @@ cargo run --release --example export_test_keys ## Wasm Support -## Test +### Build + +``` +wasm-pack build --release --target=nodejs --out-name=$PACKAGE --out-dir=$PACKAGE_DIR -- --features wasm +``` + +### Test With wasm-pack: diff --git a/src/wasm/wasm.rs b/src/wasm/wasm.rs index 5fae648..d7cb97f 100644 --- a/src/wasm/wasm.rs +++ b/src/wasm/wasm.rs @@ -1,21 +1,61 @@ use super::utils::set_panic_hook; use crate::circuit::poseidon::PoseidonCircuit; use crate::circuit::rln::{RLNCircuit, RLNInputs}; +use crate::merkle::MerkleTree; use crate::poseidon::{Poseidon as PoseidonHasher, PoseidonParams}; +use bellman::groth16::generate_random_parameters; use bellman::groth16::{create_proof, prepare_verifying_key, verify_proof}; use bellman::groth16::{create_random_proof, Parameters, Proof}; use bellman::pairing::bn256::{Bn256, Fr}; +use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr}; +use bellman::pairing::CurveAffine; use bellman::pairing::Engine; use bellman::{Circuit, ConstraintSystem, SynthesisError}; +use rand::{Rand, SeedableRng, XorShiftRng}; use std::io::{self, Error, ErrorKind, Read, Write}; use wasm_bindgen::prelude::*; -use crate::merkle::MerkleTree; +use js_sys::Array; +use sapling_crypto::bellman::pairing::bn256::{G1Affine, G2Affine}; -use bellman::groth16::generate_random_parameters; -use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr}; -use bellman::pairing::CurveAffine; -use rand::{Rand, SeedableRng, XorShiftRng}; +pub fn g1_to_hex(point: G1Affine) -> G1Hex { + let mut buf_x: Vec = vec![]; + let mut buf_y: Vec = vec![]; + let point_xy = point.into_xy_unchecked(); + point_xy.0.into_repr().write_be(&mut buf_x).unwrap(); + let x = hex::encode(buf_x); + point_xy.1.into_repr().write_be(&mut buf_y).unwrap(); + let y = hex::encode(buf_y); + G1Hex { x, y } +} + +pub fn g2_to_hex(point: G2Affine) -> G2Hex { + let mut buf_x_c0: Vec = vec![]; + let mut buf_x_c1: Vec = vec![]; + let mut buf_y_c0: Vec = vec![]; + let mut buf_y_c1: Vec = vec![]; + + let point_xy = point.into_xy_unchecked(); + + point_xy.0.c0.into_repr().write_be(&mut buf_x_c0).unwrap(); + let x_c0 = hex::encode(buf_x_c0); + + point_xy.0.c1.into_repr().write_be(&mut buf_x_c1).unwrap(); + let x_c1 = hex::encode(buf_x_c1); + + point_xy.1.c0.into_repr().write_be(&mut buf_y_c0).unwrap(); + let y_c0 = hex::encode(buf_y_c0); + + point_xy.1.c1.into_repr().write_be(&mut buf_y_c1).unwrap(); + let y_c1 = hex::encode(buf_y_c1); + + G2Hex { + x_c0, + x_c1, + y_c0, + y_c1, + } +} #[wasm_bindgen] pub struct RLNWasm { @@ -24,6 +64,15 @@ pub struct RLNWasm { merkle_depth: usize, } +#[wasm_bindgen] +pub struct VerifierKey { + alpha_1: G1Hex, + beta_2: G2Hex, + gamma_2: G2Hex, + delta_2: G2Hex, + ic_array: Array, +} + #[wasm_bindgen] pub struct G1Hex { x: String, @@ -38,6 +87,23 @@ pub struct G2Hex { y_c1: String, } +impl VerifierKey { + pub fn new(circuit_parameters: Parameters) -> VerifierKey { + let vk = circuit_parameters.vk; + let ic_array: Array = Array::new(); + for e_ic in vk.ic.iter() { + ic_array.push(&wasm_bindgen::JsValue::from(g1_to_hex(e_ic.clone()))); + } + VerifierKey { + alpha_1: g1_to_hex(vk.alpha_g1), + beta_2: g2_to_hex(vk.beta_g2), + gamma_2: g2_to_hex(vk.gamma_g2), + delta_2: g2_to_hex(vk.delta_g2), + ic_array, + } + } +} + impl G1Hex { pub fn x(&self) -> String { self.x.clone() @@ -66,90 +132,25 @@ impl G2Hex { } } -#[wasm_bindgen] -pub struct VerifierKey { - alpha_1: G1Hex, - beta_2: G2Hex, - gamma_2: G2Hex, - delta_2: G2Hex, - ic_array: Array, -} - -use sapling_crypto::bellman::pairing::bn256::{G1Affine, G2Affine}; - -use js_sys::Array; - -impl VerifierKey { - pub fn some() -> Array { - let js_array: Array = Array::new(); - - js_array.push(&wasm_bindgen::JsValue::from(String::from("xxx"))); - js_array.push(&wasm_bindgen::JsValue::from(String::from("yyy"))); - js_array - } - - pub fn new(circuit_parameters: Parameters) -> VerifierKey { - let vk = circuit_parameters.vk; - let ic_array: Array = Array::new(); - for e_ic in vk.ic.iter() { - ic_array.push(&wasm_bindgen::JsValue::from(Self::g1_to_js(e_ic.clone()))); - } - VerifierKey { - alpha_1: Self::g1_to_js(vk.alpha_g1), - beta_2: Self::g2_to_js(vk.beta_g2), - gamma_2: Self::g2_to_js(vk.gamma_g2), - delta_2: Self::g2_to_js(vk.delta_g2), - ic_array, - } - } - - fn g1_to_js(point: G1Affine) -> G1Hex { - let mut buf_x: Vec = vec![]; - let mut buf_y: Vec = vec![]; - let point_xy = point.into_xy_unchecked(); - point_xy.0.into_repr().write_be(&mut buf_x).unwrap(); - let x = hex::encode(buf_x); - point_xy.1.into_repr().write_be(&mut buf_y).unwrap(); - let y = hex::encode(buf_y); - G1Hex { x, y } - } - - fn g2_to_js(point: G2Affine) -> G2Hex { - let mut buf_x_c0: Vec = vec![]; - let mut buf_x_c1: Vec = vec![]; - let mut buf_y_c0: Vec = vec![]; - let mut buf_y_c1: Vec = vec![]; - - let point_xy = point.into_xy_unchecked(); - - point_xy.0.c0.into_repr().write_be(&mut buf_x_c0).unwrap(); - let x_c0 = hex::encode(buf_x_c0); - - point_xy.0.c1.into_repr().write_be(&mut buf_x_c1).unwrap(); - let x_c1 = hex::encode(buf_x_c1); - - point_xy.1.c0.into_repr().write_be(&mut buf_y_c0).unwrap(); - let y_c0 = hex::encode(buf_y_c0); - - point_xy.1.c1.into_repr().write_be(&mut buf_y_c1).unwrap(); - let y_c1 = hex::encode(buf_y_c1); - - G2Hex { - x_c0, - x_c1, - y_c0, - y_c1, - } - } -} - #[wasm_bindgen] impl RLNWasm { - #[wasm_bindgen] - pub fn new(merkle_depth: usize, raw_circuit_parameters: &[u8]) -> RLNWasm { - set_panic_hook(); - let circuit_parameters = Parameters::::read(raw_circuit_parameters, true).unwrap(); - let poseidon_params = PoseidonParams::::new(8, 55, 3, None, None, None); + fn default_poseidon_params() -> PoseidonParams { + PoseidonParams::::new(8, 55, 3, None, None, None) + } + + fn new_circuit(merkle_depth: usize) -> Parameters { + let mut rng = XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let poseidon_params = Self::default_poseidon_params(); + let inputs = RLNInputs::::empty(merkle_depth); + let circuit = RLNCircuit:: { + inputs, + hasher: PoseidonCircuit::new(poseidon_params.clone()), + }; + generate_random_parameters(circuit, &mut rng).unwrap() + } + + fn new_with_params(merkle_depth: usize, circuit_parameters: Parameters) -> RLNWasm { + let poseidon_params = Self::default_poseidon_params(); let circuit_hasher = PoseidonCircuit::new(poseidon_params.clone()); RLNWasm { circuit_parameters, @@ -158,8 +159,18 @@ impl RLNWasm { } } - pub fn export_verifier_key(&self) -> VerifierKey { - VerifierKey::new(self.circuit_parameters.clone()) + #[wasm_bindgen] + pub fn new(merkle_depth: usize) -> RLNWasm { + set_panic_hook(); + let circuit_parameters = Self::new_circuit(merkle_depth); + Self::new_with_params(merkle_depth, circuit_parameters) + } + + #[wasm_bindgen] + pub fn new_with_raw_params(merkle_depth: usize, raw_circuit_parameters: &[u8]) -> RLNWasm { + set_panic_hook(); + let circuit_parameters = Parameters::::read(raw_circuit_parameters, true).unwrap(); + Self::new_with_params(merkle_depth, circuit_parameters) } #[wasm_bindgen] @@ -190,6 +201,11 @@ impl RLNWasm { verify_proof(&verifing_key, &proof, &public_inputs).expect("failed to verify proof"); success } + + #[wasm_bindgen] + pub fn verifier_key(&self) -> VerifierKey { + VerifierKey::new(self.circuit_parameters.clone()) + } } #[cfg(test)] @@ -206,20 +222,6 @@ mod test { use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr}; use rand::{Rand, SeedableRng, XorShiftRng}; - fn gen_circuit_parameters(merkle_depth: usize) -> Vec { - let mut rng = XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let poseidon_params = PoseidonParams::::new(8, 55, 3, None, None, None); - let inputs = RLNInputs::::empty(merkle_depth); - let circuit = RLNCircuit:: { - inputs, - hasher: PoseidonCircuit::new(poseidon_params.clone()), - }; - let parameters = generate_random_parameters(circuit, &mut rng).unwrap(); - let mut writer: Vec = Vec::new(); - parameters.write(&mut writer); - writer - } - fn gen_valid_inputs(merkle_depth: usize) -> RLNInputs { let mut rng = XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]); let poseidon_params = PoseidonParams::::new(8, 55, 3, None, None, None); @@ -267,16 +269,18 @@ mod test { #[wasm_bindgen_test] fn test_rln_wasm() { let merkle_depth = 32usize; - let raw_circuit_parameters = gen_circuit_parameters(merkle_depth); + + let rln_wasm = super::RLNWasm::new(merkle_depth); + let inputs = gen_valid_inputs(merkle_depth); let mut raw_inputs: Vec = Vec::new(); inputs.write(&mut raw_inputs); - use super::RLNWasm; - let rln_wasm = RLNWasm::new(merkle_depth, raw_circuit_parameters.as_slice()); - let proof = rln_wasm.generate_proof(raw_inputs.as_slice()); + + let proof = rln_wasm.generate_proof(raw_inputs.as_slice()).unwrap(); + let mut public_inputs: Vec = Vec::new(); inputs.write_public_inputs(&mut public_inputs); - let proof = proof.unwrap(); + assert_eq!( rln_wasm.verify(proof.as_slice(), public_inputs.as_slice()), true