mirror of https://github.com/status-im/rln.git
add new circuit gen endpoint
add verifier key export endpoint
This commit is contained in:
parent
cbc8e7579a
commit
097f512237
|
@ -18,7 +18,13 @@ cargo run --release --example export_test_keys
|
||||||
|
|
||||||
## Wasm Support
|
## Wasm Support
|
||||||
|
|
||||||
## Test
|
### Build
|
||||||
|
|
||||||
|
```
|
||||||
|
wasm-pack build --release --target=nodejs --out-name=$PACKAGE --out-dir=$PACKAGE_DIR -- --features wasm
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test
|
||||||
|
|
||||||
With wasm-pack:
|
With wasm-pack:
|
||||||
|
|
||||||
|
|
220
src/wasm/wasm.rs
220
src/wasm/wasm.rs
|
@ -1,21 +1,61 @@
|
||||||
use super::utils::set_panic_hook;
|
use super::utils::set_panic_hook;
|
||||||
use crate::circuit::poseidon::PoseidonCircuit;
|
use crate::circuit::poseidon::PoseidonCircuit;
|
||||||
use crate::circuit::rln::{RLNCircuit, RLNInputs};
|
use crate::circuit::rln::{RLNCircuit, RLNInputs};
|
||||||
|
use crate::merkle::MerkleTree;
|
||||||
use crate::poseidon::{Poseidon as PoseidonHasher, PoseidonParams};
|
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_proof, prepare_verifying_key, verify_proof};
|
||||||
use bellman::groth16::{create_random_proof, Parameters, Proof};
|
use bellman::groth16::{create_random_proof, Parameters, Proof};
|
||||||
use bellman::pairing::bn256::{Bn256, Fr};
|
use bellman::pairing::bn256::{Bn256, Fr};
|
||||||
|
use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr};
|
||||||
|
use bellman::pairing::CurveAffine;
|
||||||
use bellman::pairing::Engine;
|
use bellman::pairing::Engine;
|
||||||
use bellman::{Circuit, ConstraintSystem, SynthesisError};
|
use bellman::{Circuit, ConstraintSystem, SynthesisError};
|
||||||
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
use std::io::{self, Error, ErrorKind, Read, Write};
|
use std::io::{self, Error, ErrorKind, Read, Write};
|
||||||
use wasm_bindgen::prelude::*;
|
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;
|
pub fn g1_to_hex(point: G1Affine) -> G1Hex {
|
||||||
use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr};
|
let mut buf_x: Vec<u8> = vec![];
|
||||||
use bellman::pairing::CurveAffine;
|
let mut buf_y: Vec<u8> = vec![];
|
||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
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<u8> = vec![];
|
||||||
|
let mut buf_x_c1: Vec<u8> = vec![];
|
||||||
|
let mut buf_y_c0: Vec<u8> = vec![];
|
||||||
|
let mut buf_y_c1: Vec<u8> = 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]
|
#[wasm_bindgen]
|
||||||
pub struct RLNWasm {
|
pub struct RLNWasm {
|
||||||
|
@ -24,6 +64,15 @@ pub struct RLNWasm {
|
||||||
merkle_depth: usize,
|
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]
|
#[wasm_bindgen]
|
||||||
pub struct G1Hex {
|
pub struct G1Hex {
|
||||||
x: String,
|
x: String,
|
||||||
|
@ -38,6 +87,23 @@ pub struct G2Hex {
|
||||||
y_c1: String,
|
y_c1: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VerifierKey {
|
||||||
|
pub fn new(circuit_parameters: Parameters<Bn256>) -> 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 {
|
impl G1Hex {
|
||||||
pub fn x(&self) -> String {
|
pub fn x(&self) -> String {
|
||||||
self.x.clone()
|
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<Bn256>) -> 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<u8> = vec![];
|
|
||||||
let mut buf_y: Vec<u8> = 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<u8> = vec![];
|
|
||||||
let mut buf_x_c1: Vec<u8> = vec![];
|
|
||||||
let mut buf_y_c0: Vec<u8> = vec![];
|
|
||||||
let mut buf_y_c1: Vec<u8> = 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]
|
#[wasm_bindgen]
|
||||||
impl RLNWasm {
|
impl RLNWasm {
|
||||||
#[wasm_bindgen]
|
fn default_poseidon_params() -> PoseidonParams<Bn256> {
|
||||||
pub fn new(merkle_depth: usize, raw_circuit_parameters: &[u8]) -> RLNWasm {
|
PoseidonParams::<Bn256>::new(8, 55, 3, None, None, None)
|
||||||
set_panic_hook();
|
}
|
||||||
let circuit_parameters = Parameters::<Bn256>::read(raw_circuit_parameters, true).unwrap();
|
|
||||||
let poseidon_params = PoseidonParams::<Bn256>::new(8, 55, 3, None, None, None);
|
fn new_circuit(merkle_depth: usize) -> Parameters<Bn256> {
|
||||||
|
let mut rng = XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
let poseidon_params = Self::default_poseidon_params();
|
||||||
|
let inputs = RLNInputs::<Bn256>::empty(merkle_depth);
|
||||||
|
let circuit = RLNCircuit::<Bn256> {
|
||||||
|
inputs,
|
||||||
|
hasher: PoseidonCircuit::new(poseidon_params.clone()),
|
||||||
|
};
|
||||||
|
generate_random_parameters(circuit, &mut rng).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_params(merkle_depth: usize, circuit_parameters: Parameters<Bn256>) -> RLNWasm {
|
||||||
|
let poseidon_params = Self::default_poseidon_params();
|
||||||
let circuit_hasher = PoseidonCircuit::new(poseidon_params.clone());
|
let circuit_hasher = PoseidonCircuit::new(poseidon_params.clone());
|
||||||
RLNWasm {
|
RLNWasm {
|
||||||
circuit_parameters,
|
circuit_parameters,
|
||||||
|
@ -158,8 +159,18 @@ impl RLNWasm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn export_verifier_key(&self) -> VerifierKey {
|
#[wasm_bindgen]
|
||||||
VerifierKey::new(self.circuit_parameters.clone())
|
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::<Bn256>::read(raw_circuit_parameters, true).unwrap();
|
||||||
|
Self::new_with_params(merkle_depth, circuit_parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
@ -190,6 +201,11 @@ impl RLNWasm {
|
||||||
verify_proof(&verifing_key, &proof, &public_inputs).expect("failed to verify proof");
|
verify_proof(&verifing_key, &proof, &public_inputs).expect("failed to verify proof");
|
||||||
success
|
success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn verifier_key(&self) -> VerifierKey {
|
||||||
|
VerifierKey::new(self.circuit_parameters.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -206,20 +222,6 @@ mod test {
|
||||||
use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr};
|
use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr};
|
||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
fn gen_circuit_parameters(merkle_depth: usize) -> Vec<u8> {
|
|
||||||
let mut rng = XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
|
||||||
let poseidon_params = PoseidonParams::<Bn256>::new(8, 55, 3, None, None, None);
|
|
||||||
let inputs = RLNInputs::<Bn256>::empty(merkle_depth);
|
|
||||||
let circuit = RLNCircuit::<Bn256> {
|
|
||||||
inputs,
|
|
||||||
hasher: PoseidonCircuit::new(poseidon_params.clone()),
|
|
||||||
};
|
|
||||||
let parameters = generate_random_parameters(circuit, &mut rng).unwrap();
|
|
||||||
let mut writer: Vec<u8> = Vec::new();
|
|
||||||
parameters.write(&mut writer);
|
|
||||||
writer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_valid_inputs(merkle_depth: usize) -> RLNInputs<Bn256> {
|
fn gen_valid_inputs(merkle_depth: usize) -> RLNInputs<Bn256> {
|
||||||
let mut rng = XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
let poseidon_params = PoseidonParams::<Bn256>::new(8, 55, 3, None, None, None);
|
let poseidon_params = PoseidonParams::<Bn256>::new(8, 55, 3, None, None, None);
|
||||||
|
@ -267,16 +269,18 @@ mod test {
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn test_rln_wasm() {
|
fn test_rln_wasm() {
|
||||||
let merkle_depth = 32usize;
|
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 inputs = gen_valid_inputs(merkle_depth);
|
||||||
let mut raw_inputs: Vec<u8> = Vec::new();
|
let mut raw_inputs: Vec<u8> = Vec::new();
|
||||||
inputs.write(&mut raw_inputs);
|
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()).unwrap();
|
||||||
let proof = rln_wasm.generate_proof(raw_inputs.as_slice());
|
|
||||||
let mut public_inputs: Vec<u8> = Vec::new();
|
let mut public_inputs: Vec<u8> = Vec::new();
|
||||||
inputs.write_public_inputs(&mut public_inputs);
|
inputs.write_public_inputs(&mut public_inputs);
|
||||||
let proof = proof.unwrap();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
rln_wasm.verify(proof.as_slice(), public_inputs.as_slice()),
|
rln_wasm.verify(proof.as_slice(), public_inputs.as_slice()),
|
||||||
true
|
true
|
||||||
|
|
Loading…
Reference in New Issue