add wasm support

This commit is contained in:
kilic 2020-06-07 18:36:18 +03:00
parent 600775f069
commit b7e2954a69
3 changed files with 120 additions and 79 deletions

View File

@ -7,11 +7,18 @@ edition = "2018"
[lib] [lib]
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[features]
default = ["sapling_multicore"]
wasm = ["sapling_wasm"]
bellman_wasm = ["bellman/wasm", "bellman/nolog"]
sapling_wasm = ["sapling-crypto/wasm"]
sapling_multicore = ["sapling-crypto/multicore"]
[dependencies] [dependencies]
rand = "0.4" rand = "0.4"
blake2 = "0.8.1" blake2 = "0.8.1"
sapling-crypto = { package = "sapling-crypto_ce", version = "0.1.2" } sapling-crypto = { package = "sapling-crypto_ce", version = "0.1.3", default-features = false }
hex = "0.4.2" bellman = { package = "bellman_ce", version = "0.3.4", default-features = false }
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = { version = "0.1.1" } console_error_panic_hook = { version = "0.1.1" }

View File

@ -89,26 +89,7 @@ where
let root = E::Fr::from_repr(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; let root = E::Fr::from_repr(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
buf.read_le(&mut reader)?; buf.read_le(&mut reader)?;
let id_key = E::Fr::from_repr(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; let id_key = E::Fr::from_repr(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let mut byte_buf = vec![0u8; 1]; let auth_path = Self::decode_auth_path(&mut reader)?;
let mut auth_path: Vec<Option<(E::Fr, bool)>> = vec![];
loop {
match reader.read_exact(&mut byte_buf) {
Ok(_) => match byte_buf[0] {
0u8 => auth_path.push(Some((E::Fr::zero(), false))),
1u8 => auth_path.push(Some((E::Fr::one(), true))),
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"auth path element should be 1 or 0",
))
}
},
Err(ref err) if err.kind() == io::ErrorKind::UnexpectedEof => {
break;
}
Err(err) => return Err(err),
};
}
Ok(RLNInputs { Ok(RLNInputs {
share_x: Some(share_x), share_x: Some(share_x),
share_y: Some(share_y), share_y: Some(share_y),
@ -120,6 +101,17 @@ where
}) })
} }
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
self.share_x.unwrap().into_repr().write_le(&mut writer).unwrap();
self.share_y.unwrap().into_repr().write_le(&mut writer).unwrap();
self.epoch.unwrap().into_repr().write_le(&mut writer).unwrap();
self.nullifier.unwrap().into_repr().write_le(&mut writer).unwrap();
self.root.unwrap().into_repr().write_le(&mut writer).unwrap();
self.id_key.unwrap().into_repr().write_le(&mut writer).unwrap();
Self::encode_auth_path(&mut writer, self.auth_path.clone()).unwrap();
Ok(())
}
pub fn read_public_inputs<R: Read>(mut reader: R) -> io::Result<Vec<E::Fr>> { pub fn read_public_inputs<R: Read>(mut reader: R) -> io::Result<Vec<E::Fr>> {
let mut buf = <E::Fr as PrimeField>::Repr::default(); let mut buf = <E::Fr as PrimeField>::Repr::default();
buf.read_le(&mut reader)?; buf.read_le(&mut reader)?;
@ -134,6 +126,53 @@ where
let nullifier = E::Fr::from_repr(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; let nullifier = E::Fr::from_repr(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Ok(vec![root, epoch, share_x, share_y, nullifier]) Ok(vec![root, epoch, share_x, share_y, nullifier])
} }
pub fn write_public_inputs<W: Write>(&self, mut writer: W) -> io::Result<()> {
self.root.unwrap().into_repr().write_le(&mut writer)?;
self.epoch.unwrap().into_repr().write_le(&mut writer)?;
self.share_x.unwrap().into_repr().write_le(&mut writer)?;
self.share_y.unwrap().into_repr().write_le(&mut writer)?;
self.nullifier.unwrap().into_repr().write_le(&mut writer)?;
Ok(())
}
pub fn encode_auth_path<W: Write>(mut writer: W, auth_path: Vec<Option<(E::Fr, bool)>>) -> io::Result<()> {
let path_len = auth_path.len() as u8;
writer.write(&[path_len])?;
for el in auth_path.iter() {
let c = el.unwrap();
if c.1 {
writer.write(&[1])?;
} else {
writer.write(&[0])?;
}
c.0.into_repr().write_le(&mut writer).unwrap();
}
Ok(())
}
pub fn decode_auth_path<R: Read>(mut reader: R) -> io::Result<Vec<Option<(E::Fr, bool)>>> {
let mut byte_buf = vec![0u8; 1];
let mut el_buf = <E::Fr as PrimeField>::Repr::default();
let mut auth_path: Vec<Option<(E::Fr, bool)>> = vec![];
reader.read_exact(&mut byte_buf)?;
let path_len = byte_buf[0];
if path_len < 2 {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid path length"));
}
for _ in 0..path_len {
reader.read_exact(&mut byte_buf)?;
let path_dir = match byte_buf[0] {
0u8 => false,
1u8 => true,
_ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid path direction")),
};
el_buf.read_le(&mut reader)?;
let node = E::Fr::from_repr(el_buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
auth_path.push(Some((node, path_dir)));
}
Ok(auth_path)
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -471,24 +510,31 @@ mod test {
let nullifier = Fr::from_str("4").unwrap(); let nullifier = Fr::from_str("4").unwrap();
let root = Fr::from_str("5").unwrap(); let root = Fr::from_str("5").unwrap();
let id_key = Fr::from_str("6").unwrap(); let id_key = Fr::from_str("6").unwrap();
let mut writer: Vec<u8> = Vec::new(); let auth_path = vec![
share_x.into_repr().write_le(&mut writer).unwrap(); Some((Fr::from_str("20").unwrap(), false)),
share_y.into_repr().write_le(&mut writer).unwrap(); Some((Fr::from_str("21").unwrap(), true)),
epoch.into_repr().write_le(&mut writer).unwrap(); Some((Fr::from_str("22").unwrap(), true)),
nullifier.into_repr().write_le(&mut writer).unwrap(); Some((Fr::from_str("23").unwrap(), false)),
root.into_repr().write_le(&mut writer).unwrap(); ];
id_key.into_repr().write_le(&mut writer).unwrap(); let input0 = RLNInputs::<Bn256> {
writer.push(1u8); share_x: Some(share_x),
writer.push(1u8); share_y: Some(share_y),
writer.push(1u8); epoch: Some(epoch),
writer.push(1u8); nullifier: Some(nullifier),
let inputs = RLNInputs::<Bn256>::read(writer.as_slice()).unwrap(); root: Some(root),
assert_eq!(inputs.share_x.unwrap().eq(&share_x), true); id_key: Some(id_key),
assert_eq!(inputs.share_y.unwrap().eq(&share_y), true); auth_path,
assert_eq!(inputs.epoch.unwrap().eq(&epoch), true); };
assert_eq!(inputs.nullifier.unwrap().eq(&nullifier), true); let mut raw_inputs: Vec<u8> = Vec::new();
assert_eq!(inputs.root.unwrap().eq(&root), true); input0.write(&mut raw_inputs).unwrap();
assert_eq!(inputs.id_key.unwrap().eq(&id_key), true); let mut reader = raw_inputs.as_slice();
assert_eq!(4, inputs.merkle_depth()); let input1 = RLNInputs::<Bn256>::read(&mut reader).unwrap();
assert_eq!(input0.share_x, input1.share_x);
assert_eq!(input0.share_y, input1.share_y);
assert_eq!(input0.epoch, input1.epoch);
assert_eq!(input0.nullifier, input1.nullifier);
assert_eq!(input0.root, input1.root);
assert_eq!(input0.id_key, input1.id_key);
assert_eq!(input0.auth_path, input1.auth_path);
} }
} }

View File

@ -91,75 +91,63 @@ mod test {
writer writer
} }
#[wasm_bindgen_test] fn gen_valid_inputs(merkle_depth: usize) -> RLNInputs<Bn256> {
fn test_rln_wasm() {
let merkle_depth = 32usize;
let circuit_parameters = gen_circuit_parameters(merkle_depth);
//
// prepare inputs
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>::default(); let poseidon_params = PoseidonParams::<Bn256>::default();
let mut hasher = PoseidonHasher::new(poseidon_params.clone()); let mut hasher = PoseidonHasher::new(poseidon_params.clone());
let mut membership_tree = MerkleTree::empty(hasher.clone(), merkle_depth); let mut membership_tree = MerkleTree::empty(hasher.clone(), merkle_depth);
// A. setup an identity
let id_key = Fr::rand(&mut rng); let id_key = Fr::rand(&mut rng);
let id_comm = hasher.hash(vec![id_key.clone()]); let id_comm = hasher.hash(vec![id_key.clone()]);
// B. insert to the membership tree let id_index = 6;
let id_index = 6; // any number below 2^depth will work
membership_tree.update(id_index, id_comm); membership_tree.update(id_index, id_comm);
// C.1 get membership witness
let auth_path = membership_tree.witness(id_index); let auth_path = membership_tree.witness(id_index);
assert!(membership_tree.check_inclusion(auth_path.clone(), id_index, id_key.clone())); assert!(membership_tree.check_inclusion(auth_path.clone(), id_index, id_key.clone()));
// C.2 prepare sss
// get current epoch
let epoch = Fr::rand(&mut rng); let epoch = Fr::rand(&mut rng);
let signal_hash = Fr::rand(&mut rng); let signal_hash = Fr::rand(&mut rng);
// evaluation point is the signal_hash
let share_x = signal_hash.clone(); let share_x = signal_hash.clone();
// calculate current line equation
let a_0 = id_key.clone(); let a_0 = id_key.clone();
let a_1 = hasher.hash(vec![a_0, epoch]); let a_1 = hasher.hash(vec![a_0, epoch]);
// evaluate line equation
let mut share_y = a_1.clone(); let mut share_y = a_1.clone();
share_y.mul_assign(&share_x); share_y.mul_assign(&share_x);
share_y.add_assign(&a_0); share_y.add_assign(&a_0);
// calculate nullfier
let nullifier = hasher.hash(vec![a_1]); let nullifier = hasher.hash(vec![a_1]);
let root = membership_tree.root(); let root = membership_tree.root();
// let inputs = RLNInputs::<Bn256> {
// serialize input share_x: Some(share_x),
share_y: Some(share_y),
epoch: Some(epoch),
nullifier: Some(nullifier),
root: Some(membership_tree.root()),
id_key: Some(id_key),
auth_path: auth_path.into_iter().map(|w| Some(w)).collect(),
};
let mut writer: Vec<u8> = Vec::new(); inputs
share_x.into_repr().write_le(&mut writer).unwrap();
share_y.into_repr().write_le(&mut writer).unwrap();
epoch.into_repr().write_le(&mut writer).unwrap();
nullifier.into_repr().write_le(&mut writer).unwrap();
root.into_repr().write_le(&mut writer).unwrap();
id_key.into_repr().write_le(&mut writer).unwrap();
for (e, _) in auth_path.iter() {
e.into_repr().write_le(&mut writer).unwrap();
} }
let raw_circuit_parameters = writer.as_slice();
//
// call wasm
#[wasm_bindgen_test]
fn test_rln_wasm() {
let merkle_depth = 32usize;
let raw_circuit_parameters = gen_circuit_parameters(merkle_depth);
let inputs = gen_valid_inputs(merkle_depth);
let mut raw_inputs: Vec<u8> = Vec::new();
inputs.write(&mut raw_inputs);
use super::RLNWasm; use super::RLNWasm;
// let rlnWasm = RLNWasm::new(merkle_depth, raw_circuit_parameters); let rln_wasm = RLNWasm::new(merkle_depth, raw_circuit_parameters.as_slice());
let proof = rln_wasm.generate_proof(raw_inputs.as_slice());
let mut public_inputs: Vec<u8> = 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);
} }
} }