#[cfg(test)] #[cfg(not(feature = "stateless"))] mod test { use ark_std::{rand::thread_rng, UniformRand}; use rand::Rng; use rln::circuit::{Fr, TEST_TREE_DEPTH}; use rln::ffi::{ffi_rln::*, ffi_tree::*, ffi_utils::*}; use rln::hashers::{hash_to_field_le, poseidon_hash as utils_poseidon_hash}; use rln::protocol::*; use rln::utils::*; use safer_ffi::prelude::repr_c; use serde_json::json; use std::fs::File; use std::io::Read; use zeroize::Zeroize; const NO_OF_LEAVES: usize = 256; fn create_rln_instance() -> repr_c::Box { let input_config = json!({}).to_string(); let c_str = std::ffi::CString::new(input_config).unwrap(); match ffi_rln_new(TEST_TREE_DEPTH, c_str.as_c_str().into()) { CResult { ok: Some(rln), err: None, } => rln, CResult { ok: None, err: Some(err), } => panic!("RLN object creation failed: {}", err), _ => unreachable!(), } } fn set_leaves_init(ffi_rln_instance: &mut repr_c::Box, leaves: &[Fr]) { let leaves_vec: repr_c::Vec = leaves .iter() .map(|fr| CFr::from(*fr)) .collect::>() .into(); ffi_init_tree_with_leaves(ffi_rln_instance, &leaves_vec); } fn get_random_leaves() -> Vec { let mut rng = thread_rng(); (0..NO_OF_LEAVES).map(|_| Fr::rand(&mut rng)).collect() } fn get_tree_root(ffi_rln_instance: &repr_c::Box) -> Fr { let root_cfr = ffi_get_root(ffi_rln_instance); **root_cfr } fn identity_pair_gen() -> (IdSecret, Fr) { let key_gen = ffi_key_gen(); let mut id_secret_fr = *key_gen[0]; let id_secret_hash = IdSecret::from(&mut id_secret_fr); let id_commitment = *key_gen[1]; (id_secret_hash, id_commitment) } fn rln_proof_gen( ffi_rln_instance: &repr_c::Box, identity_secret: &CFr, user_message_limit: &CFr, message_id: &CFr, x: &CFr, external_nullifier: &CFr, leaf_index: usize, ) -> repr_c::Box { match ffi_generate_rln_proof( ffi_rln_instance, identity_secret, user_message_limit, message_id, x, external_nullifier, leaf_index, ) { CResult { ok: Some(proof), err: None, } => proof, CResult { ok: None, err: Some(err), } => panic!("generate rln proof call failed: {}", err), _ => unreachable!(), } } #[test] // We test merkle batch Merkle tree additions fn test_merkle_operations_ffi() { // We generate a vector of random leaves let leaves = get_random_leaves(); // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); // We first add leaves one by one specifying the index for (i, leaf) in leaves.iter().enumerate() { // We prepare the rate_commitment and we set the leaf at provided index let result = ffi_set_leaf(&mut ffi_rln_instance, i, &CFr::from(*leaf).into()); if !result.ok { panic!("set leaf call failed: {:?}", result.err); } } // We get the root of the tree obtained adding one leaf per time let root_single = get_tree_root(&ffi_rln_instance); // We reset the tree to default let result = ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH); if !result.ok { panic!("set tree call failed: {:?}", result.err); } // We add leaves one by one using the internal index (new leaves goes in next available position) for leaf in &leaves { let result = ffi_set_next_leaf(&mut ffi_rln_instance, &CFr::from(*leaf).into()); if !result.ok { panic!("set next leaf call failed: {:?}", result.err); } } // We get the root of the tree obtained adding leaves using the internal index let root_next = get_tree_root(&ffi_rln_instance); // We check if roots are the same assert_eq!(root_single, root_next); // We reset the tree to default let result = ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH); if !result.ok { panic!("set tree call failed: {:?}", result.err); } // We add leaves in a batch into the tree set_leaves_init(&mut ffi_rln_instance, &leaves); // We get the root of the tree obtained adding leaves in batch let root_batch = get_tree_root(&ffi_rln_instance); // We check if roots are the same assert_eq!(root_single, root_batch); // We now delete all leaves set and check if the root corresponds to the empty tree root // delete calls over indexes higher than no_of_leaves are ignored and will not increase self.tree.next_index for i in 0..NO_OF_LEAVES { let result = ffi_delete_leaf(&mut ffi_rln_instance, i); if !result.ok { panic!("delete leaf call failed: {:?}", result.err); } } // We get the root of the tree obtained deleting all leaves let root_delete = get_tree_root(&ffi_rln_instance); // We reset the tree to default let result = ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH); if !result.ok { panic!("set tree call failed: {:?}", result.err); } // We get the root of the empty tree let root_empty = get_tree_root(&ffi_rln_instance); // We check if roots are the same assert_eq!(root_delete, root_empty); } #[test] // This test is similar to the one in public.rs but it uses the RLN object as a pointer // Uses `set_leaves_from` to set leaves in a batch fn test_leaf_setting_with_index_ffi() { // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); assert_eq!(ffi_leaves_set(&ffi_rln_instance), 0); // We generate a vector of random leaves let leaves = get_random_leaves(); // set_index is the index from which we start setting leaves // random number between 0..no_of_leaves let mut rng = thread_rng(); let set_index = rng.gen_range(0..NO_OF_LEAVES) as usize; println!("set_index: {set_index}"); // We add leaves in a batch into the tree set_leaves_init(&mut ffi_rln_instance, &leaves); // We get the root of the tree obtained adding leaves in batch let root_batch_with_init = get_tree_root(&ffi_rln_instance); // `init_tree_with_leaves` resets the tree to the depth it was initialized with, using `set_tree` // We add leaves in a batch starting from index 0..set_index set_leaves_init(&mut ffi_rln_instance, &leaves[0..set_index]); // We add the remaining n leaves in a batch starting from index set_index let leaves_vec: repr_c::Vec = leaves[set_index..] .iter() .map(|fr| CFr::from(*fr)) .collect::>() .into(); let result = ffi_set_leaves_from(&mut ffi_rln_instance, set_index, &leaves_vec); if !result.ok { panic!("set leaves from call failed: {:?}", result.err); } // We get the root of the tree obtained adding leaves in batch let root_batch_with_custom_index = get_tree_root(&ffi_rln_instance); assert_eq!( root_batch_with_init, root_batch_with_custom_index, "root batch !=" ); // We reset the tree to default let result = ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH); if !result.ok { panic!("set tree call failed: {:?}", result.err); } // We add leaves one by one using the internal index (new leaves goes in next available position) for leaf in &leaves { let result = ffi_set_next_leaf(&mut ffi_rln_instance, &CFr::from(*leaf).into()); if !result.ok { panic!("set next leaf call failed: {:?}", result.err); } } // We get the root of the tree obtained adding leaves using the internal index let root_single_additions = get_tree_root(&ffi_rln_instance); assert_eq!( root_batch_with_init, root_single_additions, "root single additions !=" ); } #[test] // This test is similar to the one in public.rs but it uses the RLN object as a pointer fn test_atomic_operation_ffi() { // We generate a vector of random leaves let leaves = get_random_leaves(); // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); // We add leaves in a batch into the tree set_leaves_init(&mut ffi_rln_instance, &leaves); // We get the root of the tree obtained adding leaves in batch let root_after_insertion = get_tree_root(&ffi_rln_instance); let last_leaf = leaves.last().unwrap(); let last_leaf_index = NO_OF_LEAVES - 1; let indices: repr_c::Vec = vec![last_leaf_index].into(); let last_leaf_vec: repr_c::Vec = vec![CFr::from(*last_leaf)].into(); let result = ffi_atomic_operation( &mut ffi_rln_instance, last_leaf_index, &last_leaf_vec, &indices, ); if !result.ok { panic!("atomic operation call failed: {:?}", result.err); } // We get the root of the tree obtained after a no-op let root_after_noop = get_tree_root(&ffi_rln_instance); assert_eq!(root_after_insertion, root_after_noop); } #[test] // This test is similar to the one in public.rs but it uses the RLN object as a pointer fn test_set_leaves_bad_index_ffi() { // We generate a vector of random leaves let leaves = get_random_leaves(); // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); let mut rng = thread_rng(); let bad_index = (1 << TEST_TREE_DEPTH) - rng.gen_range(0..NO_OF_LEAVES) as usize; // Get root of empty tree let root_empty = get_tree_root(&ffi_rln_instance); // We add leaves in a batch into the tree let leaves_vec: repr_c::Vec = leaves .iter() .map(|fr| CFr::from(*fr)) .collect::>() .into(); ffi_set_leaves_from(&mut ffi_rln_instance, bad_index, &leaves_vec); // Get root of tree after attempted set let root_after_bad_set = get_tree_root(&ffi_rln_instance); assert_eq!(root_empty, root_after_bad_set); } #[test] // This test is similar to the one in lib, but uses only public C API fn test_merkle_proof_ffi() { let leaf_index = 3; // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); // generate identity let mut identity_secret_hash_ = hash_to_field_le(b"test-merkle-proof"); let identity_secret_hash = IdSecret::from(&mut identity_secret_hash_); let mut to_hash = [*identity_secret_hash.clone()]; let id_commitment = utils_poseidon_hash(&to_hash); to_hash[0].zeroize(); let user_message_limit = Fr::from(100); let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); // We prepare id_commitment and we set the leaf at provided index let result = ffi_set_leaf( &mut ffi_rln_instance, leaf_index, &CFr::from(rate_commitment).into(), ); if !result.ok { panic!("set leaf call failed: {:?}", result.err); } // We obtain the Merkle tree root let root = get_tree_root(&ffi_rln_instance); use ark_ff::BigInt; assert_eq!( root, BigInt([ 4939322235247991215, 5110804094006647505, 4427606543677101242, 910933464535675827 ]) .into() ); // We obtain the Merkle proof let proof = match ffi_get_proof(&ffi_rln_instance, leaf_index) { CResult { ok: Some(proof), err: None, } => proof, CResult { ok: None, err: Some(err), } => panic!("get merkle proof call failed: {}", err), _ => unreachable!(), }; let path_elements: Vec = proof.path_elements.iter().map(|cfr| **cfr).collect(); let identity_path_index: Vec = proof.path_index.iter().copied().collect(); // We check correct computation of the path and indexes let expected_path_elements: Vec = [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864", "0x1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1", "0x18f43331537ee2af2e3d758d50f72106467c6eea50371dd528d57eb2b856d238", "0x07f9d837cb17b0d36320ffe93ba52345f1b728571a568265caac97559dbc952a", "0x2b94cf5e8746b3f5c9631f4c5df32907a699c58c94b2ad4d7b5cec1639183f55", "0x2dee93c5a666459646ea7d22cca9e1bcfed71e6951b953611d11dda32ea09d78", "0x078295e5a22b84e982cf601eb639597b8b0515a88cb5ac7fa8a4aabe3c87349d", "0x2fa5e5f18f6027a6501bec864564472a616b2e274a41211a444cbe3a99f3cc61", "0x0e884376d0d8fd21ecb780389e941f66e45e7acce3e228ab3e2156a614fcd747", "0x1b7201da72494f1e28717ad1a52eb469f95892f957713533de6175e5da190af2", "0x1f8d8822725e36385200c0b201249819a6e6e1e4650808b5bebc6bface7d7636", "0x2c5d82f66c914bafb9701589ba8cfcfb6162b0a12acf88a8d0879a0471b5f85a", "0x14c54148a0940bb820957f5adf3fa1134ef5c4aaa113f4646458f270e0bfbfd0", "0x190d33b12f986f961e10c0ee44d8b9af11be25588cad89d416118e4bf4ebe80c", "0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92", "0x2a7c7c9b6ce5880b9f6f228d72bf6a575a526f29c66ecceef8b753d38bba7323", "0x2e8186e558698ec1c67af9c14d463ffc470043c9c2988b954d75dd643f36b992", "0x0f57c5571e9a4eab49e2c8cf050dae948aef6ead647392273546249d1c1ff10f", "0x1830ee67b5fb554ad5f63d4388800e1cfe78e310697d46e43c9ce36134f72cca", ] .map(|e| str_to_fr(e, 16).unwrap()) .to_vec(); let expected_identity_path_index: Vec = vec![1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; assert_eq!(path_elements, expected_path_elements); assert_eq!(identity_path_index, expected_identity_path_index); // We double check that the proof computed from public API is correct let root_from_proof = compute_tree_root( &identity_secret_hash, &user_message_limit, &path_elements, &identity_path_index, ); assert_eq!(root, root_from_proof); } #[test] // Creating a RLN with raw data should generate same results as using a path to resources fn test_rln_raw_ffi() { // We create a RLN instance let ffi_rln_instance = create_rln_instance(); // We obtain the root from the RLN instance let root_rln_folder = get_tree_root(&ffi_rln_instance); let zkey_path = "./resources/tree_depth_20/rln_final.arkzkey"; let mut zkey_file = File::open(zkey_path).expect("no file found"); let metadata = std::fs::metadata(zkey_path).expect("unable to read metadata"); let mut zkey_buffer = vec![0; metadata.len() as usize]; zkey_file .read_exact(&mut zkey_buffer) .expect("buffer overflow"); let graph_data = "./resources/tree_depth_20/graph.bin"; let mut graph_file = File::open(graph_data).expect("no file found"); let metadata = std::fs::metadata(graph_data).expect("unable to read metadata"); let mut graph_buffer = vec![0; metadata.len() as usize]; graph_file .read_exact(&mut graph_buffer) .expect("buffer overflow"); // Creating a RLN instance passing the raw data let tree_config = "".to_string(); let c_str = std::ffi::CString::new(tree_config).unwrap(); let ffi_rln_instance2 = match ffi_rln_new_with_params( TEST_TREE_DEPTH, &zkey_buffer.into(), &graph_buffer.into(), c_str.as_c_str().into(), ) { CResult { ok: Some(rln), err: None, } => rln, CResult { ok: None, err: Some(err), } => panic!("RLN object creation failed: {}", err), _ => unreachable!(), }; // We obtain the root from the RLN instance containing raw data // And compare that the same root was generated let root_rln_raw = get_tree_root(&ffi_rln_instance2); assert_eq!(root_rln_folder, root_rln_raw); } #[test] // Computes and verifies an RLN ZK proof using FFI APIs fn test_rln_proof_ffi() { let user_message_limit = Fr::from(100); // We generate a vector of random leaves let mut rng = thread_rng(); let leaves: Vec = (0..NO_OF_LEAVES) .map(|_| utils_poseidon_hash(&[Fr::rand(&mut rng), Fr::from(100)])) .collect(); // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); // We add leaves in a batch into the tree set_leaves_init(&mut ffi_rln_instance, &leaves); // We generate a new identity pair let (identity_secret_hash, id_commitment) = identity_pair_gen(); let identity_index: usize = NO_OF_LEAVES; // We generate a random signal let mut rng = rand::thread_rng(); let signal: [u8; 32] = rng.gen(); // We generate a random epoch let epoch = hash_to_field_le(b"test-epoch"); // We generate a random rln_identifier let rln_identifier = hash_to_field_le(b"test-rln-identifier"); // We generate a external nullifier let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]); // We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT let message_id = Fr::from(1); let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); // We set as leaf rate_commitment, its index would be equal to no_of_leaves let result = ffi_set_next_leaf(&mut ffi_rln_instance, &CFr::from(rate_commitment).into()); if !result.ok { panic!("set next leaf call failed: {:?}", result.err); } // Get the merkle proof for the identity let _merkle_proof = match ffi_get_proof(&ffi_rln_instance, identity_index) { CResult { ok: Some(proof), err: None, } => proof, CResult { ok: None, err: Some(err), } => panic!("get merkle proof call failed: {}", err), _ => unreachable!(), }; // Hash the signal to get x let x = hash_to_field_le(&signal); // path_elements and identity_path_index are not needed in non-stateless mode let rln_proof = rln_proof_gen( &ffi_rln_instance, &CFr::from(*identity_secret_hash), &CFr::from(user_message_limit), &CFr::from(message_id), &CFr::from(x), &CFr::from(external_nullifier), identity_index, ); assert!(ffi_verify_rln_proof(&ffi_rln_instance, &rln_proof, &CFr::from(x)).ok); } #[test] // Computes and verifies an RLN ZK proof by checking proof's root against an input roots buffer fn test_verify_with_roots_ffi() { let user_message_limit = Fr::from(100); // We generate a vector of random leaves let leaves = get_random_leaves(); // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); // We add leaves in a batch into the tree set_leaves_init(&mut ffi_rln_instance, &leaves); // We generate a new identity pair let (identity_secret_hash, id_commitment) = identity_pair_gen(); let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); let identity_index: usize = NO_OF_LEAVES; // We generate a random signal let mut rng = rand::thread_rng(); let signal: [u8; 32] = rng.gen(); // We generate a random epoch let epoch = hash_to_field_le(b"test-epoch"); // We generate a random rln_identifier let rln_identifier = hash_to_field_le(b"test-rln-identifier"); // We generate a external nullifier let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]); // We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT let message_id = Fr::from(1); // We set as leaf rate_commitment, its index would be equal to no_of_leaves let result = ffi_set_next_leaf(&mut ffi_rln_instance, &CFr::from(rate_commitment).into()); if !result.ok { panic!("set next leaf call failed: {:?}", result.err); } // Get the merkle proof for the identity let _merkle_proof = match ffi_get_proof(&ffi_rln_instance, identity_index) { CResult { ok: Some(proof), err: None, } => proof, CResult { ok: None, err: Some(err), } => panic!("get merkle proof call failed: {}", err), _ => unreachable!(), }; // Hash the signal to get x let x = hash_to_field_le(&signal); // path_elements and identity_path_index are not needed in non-stateless mode // witness input is now passed directly as parameters let rln_proof = rln_proof_gen( &ffi_rln_instance, &CFr::from(*identity_secret_hash), &CFr::from(user_message_limit), &CFr::from(message_id), &CFr::from(x), &CFr::from(external_nullifier), identity_index, ); // We test verify_with_roots // We first try to verify against an empty buffer of roots. // In this case, since no root is provided, proof's root check is skipped and proof is verified if other proof values are valid let roots_empty: repr_c::Vec = vec![].into(); assert!( ffi_verify_with_roots(&ffi_rln_instance, &rln_proof, &roots_empty, &CFr::from(x)).ok ); // We then try to verify against some random values not containing the correct one. let mut roots_random: Vec = Vec::new(); for _ in 0..5 { roots_random.push(CFr::from(Fr::rand(&mut rng))); } let roots_random_vec: repr_c::Vec = roots_random.into(); assert!( !ffi_verify_with_roots( &ffi_rln_instance, &rln_proof, &roots_random_vec, &CFr::from(x), ) .ok ); // We finally include the correct root // We get the root of the tree obtained adding one leaf per time let root = get_tree_root(&ffi_rln_instance); // We include the root and verify the proof let mut roots_with_correct: Vec = Vec::new(); for _ in 0..5 { roots_with_correct.push(CFr::from(Fr::rand(&mut rng))); } roots_with_correct.push(CFr::from(root)); let roots_correct_vec: repr_c::Vec = roots_with_correct.into(); assert!( ffi_verify_with_roots( &ffi_rln_instance, &rln_proof, &roots_correct_vec, &CFr::from(x), ) .ok ); } #[test] // Computes and verifies an RLN ZK proof using FFI APIs and recovers identity secret fn test_recover_id_secret_ffi() { // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); // We generate a new identity pair let (identity_secret_hash, id_commitment) = identity_pair_gen(); let user_message_limit = Fr::from(100); let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); // We set as leaf rate_commitment, its index would be equal to 0 since tree is empty let result = ffi_set_next_leaf(&mut ffi_rln_instance, &CFr::from(rate_commitment).into()); if !result.ok { panic!("set next leaf call failed: {:?}", result.err); } let identity_index: usize = 0; // We generate two proofs using same epoch but different signals. // We generate two random signals let mut rng = rand::thread_rng(); let signal1: [u8; 32] = rng.gen(); let signal2: [u8; 32] = rng.gen(); // We generate a random epoch let epoch = hash_to_field_le(b"test-epoch"); // We generate a random rln_identifier let rln_identifier = hash_to_field_le(b"test-rln-identifier"); // We generate a external nullifier let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]); // We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT let message_id = Fr::from(1); // Get the merkle proof for the identity let _merkle_proof = match ffi_get_proof(&ffi_rln_instance, identity_index) { CResult { ok: Some(proof), err: None, } => proof, CResult { ok: None, err: Some(err), } => panic!("get merkle proof call failed: {}", err), _ => unreachable!(), }; // Hash the signals to get x let x1 = hash_to_field_le(&signal1); let x2 = hash_to_field_le(&signal2); // path_elements and identity_path_index are not needed in non-stateless mode // witness input is now passed directly as parameters // We call generate_rln_proof for first proof values let rln_proof1 = rln_proof_gen( &ffi_rln_instance, &CFr::from(*identity_secret_hash.clone()), &CFr::from(user_message_limit), &CFr::from(message_id), &CFr::from(x1), &CFr::from(external_nullifier), identity_index, ); // We call generate_rln_proof for second proof values let rln_proof2 = rln_proof_gen( &ffi_rln_instance, &CFr::from(*identity_secret_hash.clone()), &CFr::from(user_message_limit), &CFr::from(message_id), &CFr::from(x2), &CFr::from(external_nullifier), identity_index, ); let recovered_id_secret_cfr = match ffi_recover_id_secret(&rln_proof1, &rln_proof2) { CResult { ok: Some(secret), err: None, } => secret, CResult { ok: None, err: Some(err), } => panic!("recover id secret call failed: {}", err), _ => unreachable!(), }; // We check if the recovered identity secret hash corresponds to the original one let recovered_identity_secret_hash = *recovered_id_secret_cfr; assert_eq!(recovered_identity_secret_hash, *identity_secret_hash); // We now test that computing identity_secret_hash is unsuccessful if shares computed from two different identity secret hashes but within same epoch are passed // We generate a new identity pair let (identity_secret_hash_new, id_commitment_new) = identity_pair_gen(); let rate_commitment_new = utils_poseidon_hash(&[id_commitment_new, user_message_limit]); // We set as leaf id_commitment, its index would be equal to 1 since at 0 there is id_commitment let result = ffi_set_next_leaf( &mut ffi_rln_instance, &CFr::from(rate_commitment_new).into(), ); if !result.ok { panic!("set next leaf call failed: {:?}", result.err); } let identity_index_new: usize = 1; // We generate a random signal let signal3: [u8; 32] = rng.gen(); let x3 = hash_to_field_le(&signal3); // Get the merkle proof for the new identity let _merkle_proof_new = match ffi_get_proof(&ffi_rln_instance, identity_index_new) { CResult { ok: Some(proof), err: None, } => proof, CResult { ok: None, err: Some(err), } => panic!("get merkle proof call failed: {}", err), _ => unreachable!(), }; // path_elements_new and identity_path_index_new are not needed in non-stateless mode // witness input is now passed directly as parameters // We call generate_rln_proof let rln_proof3 = rln_proof_gen( &ffi_rln_instance, &CFr::from(*identity_secret_hash_new.clone()), &CFr::from(user_message_limit), &CFr::from(message_id), &CFr::from(x3), &CFr::from(external_nullifier), identity_index_new, ); // We attempt to recover the secret using share1 (coming from identity_secret_hash) and share3 (coming from identity_secret_hash_new) let recovered_id_secret_new_cfr = match ffi_recover_id_secret(&rln_proof1, &rln_proof3) { CResult { ok: Some(secret), err: None, } => secret, CResult { ok: None, err: Some(err), } => panic!("recover id secret call failed: {}", err), _ => unreachable!(), }; let recovered_identity_secret_hash_new = recovered_id_secret_new_cfr; // ensure that the recovered secret does not match with either of the // used secrets in proof generation assert_ne!( *recovered_identity_secret_hash_new, *identity_secret_hash_new ); } #[test] fn test_get_leaf_ffi() { // We create a RLN instance let no_of_leaves = 1 << TEST_TREE_DEPTH; // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); // We generate a new identity tuple from an input seed let seed_bytes: Vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let key_gen = ffi_seeded_extended_key_gen(&seed_bytes.into()); assert_eq!(key_gen.len(), 4, "seeded extended key gen call failed"); let id_commitment = *key_gen[3]; // We insert the id_commitment into the tree at a random index let mut rng = thread_rng(); let index = rng.gen_range(0..no_of_leaves) as usize; let result = ffi_set_leaf( &mut ffi_rln_instance, index, &CFr::from(id_commitment).into(), ); if !result.ok { panic!("set leaf call failed: {:?}", result.err); } // We get the leaf at the same index let received_id_commitment_cfr = match ffi_get_leaf(&ffi_rln_instance, index) { CResult { ok: Some(leaf), err: None, } => leaf, CResult { ok: None, err: Some(err), } => panic!("get leaf call failed: {}", err), _ => unreachable!(), }; let received_id_commitment = *received_id_commitment_cfr; // We check that the received id_commitment is the same as the one we inserted assert_eq!(received_id_commitment, id_commitment); } #[test] fn test_valid_metadata_ffi() { // We create a RLN instance let mut ffi_rln_instance = create_rln_instance(); let seed_bytes: Vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let result = ffi_set_metadata(&mut ffi_rln_instance, &seed_bytes.clone().into()); if !result.ok { panic!("set_metadata call failed: {:?}", result.err); } let metadata = match ffi_get_metadata(&ffi_rln_instance) { CResult { ok: Some(data), err: None, } => data, CResult { ok: None, err: Some(err), } => panic!("get_metadata call failed: {}", err), _ => unreachable!(), }; assert_eq!(metadata.iter().copied().collect::>(), seed_bytes); } #[test] fn test_empty_metadata_ffi() { // We create a RLN instance let ffi_rln_instance = create_rln_instance(); let metadata = match ffi_get_metadata(&ffi_rln_instance) { CResult { ok: Some(data), err: None, } => data, CResult { ok: None, err: Some(err), } => panic!("get_metadata call failed: {}", err), _ => unreachable!(), }; assert_eq!(metadata.len(), 0); } }