mirror of https://github.com/status-im/rln.git
add wasm support
This commit is contained in:
parent
600775f069
commit
b7e2954a69
11
Cargo.toml
11
Cargo.toml
|
@ -7,11 +7,18 @@ edition = "2018"
|
|||
[lib]
|
||||
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]
|
||||
rand = "0.4"
|
||||
blake2 = "0.8.1"
|
||||
sapling-crypto = { package = "sapling-crypto_ce", version = "0.1.2" }
|
||||
hex = "0.4.2"
|
||||
sapling-crypto = { package = "sapling-crypto_ce", version = "0.1.3", default-features = false }
|
||||
bellman = { package = "bellman_ce", version = "0.3.4", default-features = false }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
console_error_panic_hook = { version = "0.1.1" }
|
||||
|
|
|
@ -89,26 +89,7 @@ where
|
|||
let root = E::Fr::from_repr(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
buf.read_le(&mut reader)?;
|
||||
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 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),
|
||||
};
|
||||
}
|
||||
let auth_path = Self::decode_auth_path(&mut reader)?;
|
||||
Ok(RLNInputs {
|
||||
share_x: Some(share_x),
|
||||
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>> {
|
||||
let mut buf = <E::Fr as PrimeField>::Repr::default();
|
||||
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))?;
|
||||
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)]
|
||||
|
@ -471,24 +510,31 @@ mod test {
|
|||
let nullifier = Fr::from_str("4").unwrap();
|
||||
let root = Fr::from_str("5").unwrap();
|
||||
let id_key = Fr::from_str("6").unwrap();
|
||||
let mut writer: Vec<u8> = Vec::new();
|
||||
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();
|
||||
writer.push(1u8);
|
||||
writer.push(1u8);
|
||||
writer.push(1u8);
|
||||
writer.push(1u8);
|
||||
let inputs = RLNInputs::<Bn256>::read(writer.as_slice()).unwrap();
|
||||
assert_eq!(inputs.share_x.unwrap().eq(&share_x), true);
|
||||
assert_eq!(inputs.share_y.unwrap().eq(&share_y), true);
|
||||
assert_eq!(inputs.epoch.unwrap().eq(&epoch), true);
|
||||
assert_eq!(inputs.nullifier.unwrap().eq(&nullifier), true);
|
||||
assert_eq!(inputs.root.unwrap().eq(&root), true);
|
||||
assert_eq!(inputs.id_key.unwrap().eq(&id_key), true);
|
||||
assert_eq!(4, inputs.merkle_depth());
|
||||
let auth_path = vec![
|
||||
Some((Fr::from_str("20").unwrap(), false)),
|
||||
Some((Fr::from_str("21").unwrap(), true)),
|
||||
Some((Fr::from_str("22").unwrap(), true)),
|
||||
Some((Fr::from_str("23").unwrap(), false)),
|
||||
];
|
||||
let input0 = RLNInputs::<Bn256> {
|
||||
share_x: Some(share_x),
|
||||
share_y: Some(share_y),
|
||||
epoch: Some(epoch),
|
||||
nullifier: Some(nullifier),
|
||||
root: Some(root),
|
||||
id_key: Some(id_key),
|
||||
auth_path,
|
||||
};
|
||||
let mut raw_inputs: Vec<u8> = Vec::new();
|
||||
input0.write(&mut raw_inputs).unwrap();
|
||||
let mut reader = raw_inputs.as_slice();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,75 +91,63 @@ mod test {
|
|||
writer
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_rln_wasm() {
|
||||
let merkle_depth = 32usize;
|
||||
let circuit_parameters = gen_circuit_parameters(merkle_depth);
|
||||
//
|
||||
// prepare inputs
|
||||
|
||||
fn gen_valid_inputs(merkle_depth: usize) -> RLNInputs<Bn256> {
|
||||
let mut rng = XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let poseidon_params = PoseidonParams::<Bn256>::default();
|
||||
let mut hasher = PoseidonHasher::new(poseidon_params.clone());
|
||||
let mut membership_tree = MerkleTree::empty(hasher.clone(), merkle_depth);
|
||||
|
||||
// A. setup an identity
|
||||
|
||||
let id_key = Fr::rand(&mut rng);
|
||||
let id_comm = hasher.hash(vec![id_key.clone()]);
|
||||
|
||||
// B. insert to the membership tree
|
||||
|
||||
let id_index = 6; // any number below 2^depth will work
|
||||
let id_index = 6;
|
||||
membership_tree.update(id_index, id_comm);
|
||||
|
||||
// C.1 get membership witness
|
||||
|
||||
let auth_path = membership_tree.witness(id_index);
|
||||
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 signal_hash = Fr::rand(&mut rng);
|
||||
// evaluation point is the signal_hash
|
||||
let share_x = signal_hash.clone();
|
||||
|
||||
// calculate current line equation
|
||||
let a_0 = id_key.clone();
|
||||
let a_1 = hasher.hash(vec![a_0, epoch]);
|
||||
|
||||
// evaluate line equation
|
||||
let mut share_y = a_1.clone();
|
||||
share_y.mul_assign(&share_x);
|
||||
share_y.add_assign(&a_0);
|
||||
|
||||
// calculate nullfier
|
||||
let nullifier = hasher.hash(vec![a_1]);
|
||||
|
||||
let root = membership_tree.root();
|
||||
|
||||
//
|
||||
// serialize input
|
||||
let inputs = RLNInputs::<Bn256> {
|
||||
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();
|
||||
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
|
||||
inputs
|
||||
}
|
||||
|
||||
#[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;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue