Skip to content

Commit

Permalink
make rln-wasm stateless
Browse files Browse the repository at this point in the history
  • Loading branch information
seemenkina committed Sep 11, 2024
1 parent fc823e7 commit c7a171c
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 191 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion rln-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ crate-type = ["cdylib", "rlib"]
default = ["console_error_panic_hook"]

[dependencies]
rln = { path = "../rln", default-features = false, features = ["wasm"] }
rln = { path = "../rln", default-features = false, features = [
"wasm",
"stateless",
] }
num-bigint = { version = "0.4", default-features = false, features = [
"rand",
"serde",
Expand All @@ -29,6 +32,7 @@ serde_json = "1.0.85"
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.7", optional = true }
zerokit_utils = { version = "0.5.1", path = "../utils" }

[dev-dependencies]
wasm-bindgen-test = "0.3.13"
Expand Down
92 changes: 1 addition & 91 deletions rln-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,88 +182,15 @@ impl<'a> ProcessArg for &'a [u8] {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = newRLN)]
pub fn wasm_new(
tree_height: usize,
zkey: Uint8Array,
vk: Uint8Array,
) -> Result<*mut RLNWrapper, String> {
let instance = RLN::new_with_params(tree_height, zkey.to_vec(), vk.to_vec())
let instance = RLN::new_with_params(zkey.to_vec(), vk.to_vec())
.map_err(|err| format!("{:#?}", err))?;
let wrapper = RLNWrapper { instance };
Ok(Box::into_raw(Box::new(wrapper)))
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = getSerializedRLNWitness)]
pub fn wasm_get_serialized_rln_witness(
ctx: *mut RLNWrapper,
input: Uint8Array,
) -> Result<Uint8Array, String> {
let rln_witness = call!(ctx, get_serialized_rln_witness, &input.to_vec()[..])
.map_err(|err| format!("{:#?}", err))?;
Ok(Uint8Array::from(&rln_witness[..]))
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = insertMember)]
pub fn wasm_set_next_leaf(ctx: *mut RLNWrapper, input: Uint8Array) -> Result<(), String> {
call_with_error_msg!(
ctx,
set_next_leaf,
"could not insert member into merkle tree".to_string(),
&input.to_vec()[..]
)
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = setLeavesFrom)]
pub fn wasm_set_leaves_from(
ctx: *mut RLNWrapper,
index: usize,
input: Uint8Array,
) -> Result<(), String> {
call_with_error_msg!(
ctx,
set_leaves_from,
"could not set multiple leaves".to_string(),
index,
&*input.to_vec()
)
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = deleteLeaf)]
pub fn wasm_delete_leaf(ctx: *mut RLNWrapper, index: usize) -> Result<(), String> {
call_with_error_msg!(ctx, delete_leaf, "could not delete leaf".to_string(), index)
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = setMetadata)]
pub fn wasm_set_metadata(ctx: *mut RLNWrapper, input: Uint8Array) -> Result<(), String> {
call_with_error_msg!(
ctx,
set_metadata,
"could not set metadata".to_string(),
&*input.to_vec()
)
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = getMetadata)]
pub fn wasm_get_metadata(ctx: *mut RLNWrapper) -> Result<Uint8Array, String> {
call_with_output_and_error_msg!(ctx, get_metadata, "could not get metadata".to_string())
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = initTreeWithLeaves)]
pub fn wasm_init_tree_with_leaves(ctx: *mut RLNWrapper, input: Uint8Array) -> Result<(), String> {
call_with_error_msg!(
ctx,
init_tree_with_leaves,
"could not init merkle tree".to_string(),
&*input.to_vec()
)
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = RLNWitnessToJson)]
pub fn rln_witness_to_json(
Expand Down Expand Up @@ -362,17 +289,6 @@ pub fn wasm_recover_id_secret(
)
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = verifyRLNProof)]
pub fn wasm_verify_rln_proof(ctx: *const RLNWrapper, proof: Uint8Array) -> Result<bool, String> {
call_bool_method_with_error_msg!(
ctx,
verify_rln_proof,
"error while verifying rln proof".to_string(),
&proof.to_vec()[..]
)
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = verifyWithRoots)]
pub fn wasm_verify_with_roots(
Expand All @@ -389,12 +305,6 @@ pub fn wasm_verify_with_roots(
)
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = getRoot)]
pub fn wasm_get_root(ctx: *const RLNWrapper) -> Result<Uint8Array, String> {
call_with_output_and_error_msg!(ctx, get_root, "could not obtain root")
}

#[wasm_bindgen(js_name = hash)]
pub fn wasm_hash(input: Uint8Array) -> Result<Uint8Array, String> {
fn_call_with_output_and_error_msg!(hash, "could not generate hash", &input.to_vec()[..])
Expand Down
71 changes: 23 additions & 48 deletions rln-wasm/tests/rln-wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ mod tests {
use rln::hashers::{hash_to_field, poseidon_hash};
use rln::utils::{bytes_le_to_fr, fr_to_bytes_le, normalize_usize};
use rln_wasm::*;
use rln::poseidon_tree::PoseidonTree;
use rln::utils::vec_fr_to_bytes_le;
use wasm_bindgen::{prelude::*, JsValue};
use wasm_bindgen_test::wasm_bindgen_test;
use zerokit_utils::merkle_tree::merkle_tree::ZerokitMerkleTree;
use zerokit_utils::ZerokitMerkleProof;
use rln::utils::vec_u8_to_bytes_le;

#[wasm_bindgen(module = "src/utils.js")]
extern "C" {
Expand All @@ -30,7 +35,9 @@ mod tests {
let vk = read_file(&vk_path).unwrap();

// Creating an instance of RLN
let rln_instance = wasm_new(tree_height, zkey, vk).unwrap();
let rln_instance = wasm_new(zkey, vk).unwrap();

let mut tree = PoseidonTree::default(TEST_TREE_HEIGHT).unwrap();

// Creating membership key
let mem_keys = wasm_key_gen(rln_instance).unwrap();
Expand All @@ -40,7 +47,7 @@ mod tests {
// Prepare the message
let signal = b"Hello World";

let identity_index: usize = 0;
let identity_index = tree.leaves_set();
// Setting up the epoch and rln_identifier
let epoch = hash_to_field(b"test-epoch");
let rln_identifier = hash_to_field(b"test-rln-identifier");
Expand All @@ -53,31 +60,28 @@ mod tests {

let (id_commitment_fr, _) = bytes_le_to_fr(&id_commitment.to_vec()[..]);
let rate_commitment = poseidon_hash(&[id_commitment_fr, user_message_limit]);
tree.update_next(rate_commitment).unwrap();

let x = hash_to_field(signal);
let merkle_proof = tree.proof(identity_index).expect("proof should exist");
let path_elements = merkle_proof.get_path_elements();
let identity_path_index = merkle_proof.get_path_index();

// Insert PK
wasm_set_next_leaf(
rln_instance,
Uint8Array::from(fr_to_bytes_le(&rate_commitment).as_slice()),
)
.unwrap();

// Serializing the message
let mut serialized_vec: Vec<u8> = Vec::new();
serialized_vec.append(&mut id_key.to_vec());
serialized_vec.append(&mut normalize_usize(identity_index));
serialized_vec.append(&mut fr_to_bytes_le(&user_message_limit).to_vec());
serialized_vec.append(&mut message_id.to_vec());
serialized_vec.append(&mut vec_fr_to_bytes_le(&path_elements).unwrap());
serialized_vec.append(&mut vec_u8_to_bytes_le(&identity_path_index).unwrap());
serialized_vec.append(&mut fr_to_bytes_le(&x));
serialized_vec.append(&mut external_nullifier.to_vec());
serialized_vec.append(&mut normalize_usize(signal.len()));
serialized_vec.append(&mut signal.to_vec());
let serialized_message = Uint8Array::from(&serialized_vec[..]);

let serialized_rln_witness =
wasm_get_serialized_rln_witness(rln_instance, serialized_message).unwrap();

// Obtaining inputs that should be sent to circom witness calculator
let json_inputs =
rln_witness_to_json(rln_instance, serialized_rln_witness.clone()).unwrap();
rln_witness_to_json(rln_instance, serialized_message.clone()).unwrap();

// Calculating witness with JS
// (Using a JSON since wasm_bindgen does not like Result<Vec<JsBigInt>,JsValue>)
Expand All @@ -97,7 +101,7 @@ mod tests {
let proof = generate_rln_proof_with_witness(
rln_instance,
calculated_witness.into(),
serialized_rln_witness,
serialized_message,
)
.unwrap();

Expand All @@ -107,42 +111,13 @@ mod tests {
proof_bytes.append(&mut signal.to_vec());
let proof_with_signal = Uint8Array::from(&proof_bytes[..]);

// Validate Proof
let is_proof_valid = wasm_verify_rln_proof(rln_instance, proof_with_signal);

assert!(
is_proof_valid.unwrap(),
"validating proof generated with wasm failed"
);

// Validating Proof with Roots
let root = wasm_get_root(rln_instance).unwrap();
let roots = Uint8Array::from(&root.to_vec()[..]);
let root = tree.root();
let root_le = fr_to_bytes_le(&root);
let roots = Uint8Array::from(&root_le[..]);
let proof_with_signal = Uint8Array::from(&proof_bytes[..]);

let is_proof_valid = wasm_verify_with_roots(rln_instance, proof_with_signal, roots);
assert!(is_proof_valid.unwrap(), "verifying proof with roots failed");
}

#[wasm_bindgen_test]
fn test_metadata() {
let tree_height = TEST_TREE_HEIGHT;
let zkey_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/rln_final.zkey");
let vk_path =
format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/verification_key.arkvkey");
let zkey = read_file(&zkey_path).unwrap();
let vk = read_file(&vk_path).unwrap();

// Creating an instance of RLN
let rln_instance = wasm_new(tree_height, zkey, vk).unwrap();

let test_metadata = Uint8Array::new(&JsValue::from_str("test"));
// Inserting random metadata
wasm_set_metadata(rln_instance, test_metadata.clone()).unwrap();

// Getting metadata
let metadata = wasm_get_metadata(rln_instance).unwrap();

assert_eq!(metadata.to_vec(), test_metadata.to_vec());
}
}
51 changes: 0 additions & 51 deletions rln/src/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,26 +211,6 @@ impl RLN {
})
}

#[cfg(all(target_arch = "wasm32", not(feature = "stateless")))]
pub fn new_with_params(tree_height: usize, zkey_vec: Vec<u8>, vk_vec: Vec<u8>) -> Result<RLN> {
// TODO: check this lines while update rln-wasm
#[cfg(not(target_arch = "wasm32"))]
let witness_calculator = circom_from_raw(circom_vec)?;

let proving_key = zkey_from_raw(&zkey_vec)?;
let verification_key = vk_from_raw(&vk_vec, &zkey_vec)?;

// We compute a default empty tree
let tree = PoseidonTree::default(tree_height)?;

Ok(RLN {
proving_key,
verification_key,
tree,
_marker: PhantomData,
})
}

/// Creates a new stateless RLN object by passing circuit resources as byte vectors.
///
/// Input parameters are
Expand Down Expand Up @@ -275,39 +255,8 @@ impl RLN {
})
}

/// Creates a new stateless RLN object by passing circuit resources as byte vectors.
///
/// Input parameters are
/// - `zkey_vec`: a byte vector containing to the proving key (`rln_final.zkey`) or (`rln_final.arkzkey`) as binary file
/// - `vk_vec`: a byte vector containing to the verification key (`verification_key.arkvkey`) as binary file
///
/// Example:
/// ```
/// use std::fs::File;
/// use std::io::Read;
///
/// let resources_folder = "./resources/tree_height_20/";
///
/// let mut resources: Vec<Vec<u8>> = Vec::new();
/// for filename in ["rln_final.zkey", "verification_key.arkvkey"] {
/// let fullpath = format!("{resources_folder}{filename}");
/// let mut file = File::open(&fullpath).expect("no file found");
/// let metadata = std::fs::metadata(&fullpath).expect("unable to read metadata");
/// let mut buffer = vec![0; metadata.len() as usize];
/// file.read_exact(&mut buffer).expect("buffer overflow");
/// resources.push(buffer);
/// }
///
/// let mut rln = RLN::new_with_params(
/// resources[0].clone(),
/// resources[1].clone(),
/// );
/// ```
#[cfg(all(target_arch = "wasm32", feature = "stateless"))]
pub fn new_with_params(zkey_vec: Vec<u8>, vk_vec: Vec<u8>) -> Result<RLN> {
#[cfg(not(target_arch = "wasm32"))]
let witness_calculator = circom_from_raw(circom_vec)?;

let proving_key = zkey_from_raw(&zkey_vec)?;
let verification_key = vk_from_raw(&vk_vec, &zkey_vec)?;

Expand Down

0 comments on commit c7a171c

Please sign in to comment.