Compare commits

..

1 Commits

Author SHA1 Message Date
rymnc
b5e5be47db chore(rln): onchain tree poc 2023-11-30 12:25:33 +05:30
16 changed files with 677 additions and 292 deletions

12
Cargo.lock generated
View File

@@ -3758,9 +3758,9 @@ dependencies = [
[[package]]
name = "wasm-encoder"
version = "0.32.0"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7"
checksum = "d05d0b6fcd0aeb98adf16e7975331b3c17222aa815148f5b976370ce589d80ef"
dependencies = [
"leb128",
]
@@ -4099,9 +4099,9 @@ dependencies = [
[[package]]
name = "wast"
version = "64.0.0"
version = "57.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a259b226fd6910225aa7baeba82f9d9933b6d00f2ce1b49b80fa4214328237cc"
checksum = "6eb0f5ed17ac4421193c7477da05892c2edafd67f9639e3c11a82086416662dc"
dependencies = [
"leb128",
"memchr",
@@ -4111,9 +4111,9 @@ dependencies = [
[[package]]
name = "wat"
version = "1.0.71"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53253d920ab413fca1c7dc2161d601c79b4fdf631d0ba51dd4343bf9b556c3f6"
checksum = "ab9ab0d87337c3be2bb6fc5cd331c4ba9fd6bcb4ee85048a0dd59ed9ecf92e53"
dependencies = [
"wast",
]

View File

@@ -7,7 +7,6 @@ use std::vec::Vec;
use js_sys::{BigInt as JsBigInt, Object, Uint8Array};
use num_bigint::BigInt;
use rln::circuit::{default_vk, default_zkey};
use rln::public::{hash, poseidon_hash, RLN};
use wasm_bindgen::prelude::*;
@@ -182,10 +181,13 @@ impl<'a> ProcessArg for &'a [u8] {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = newRLN)]
pub fn wasm_new() -> Result<*mut RLNWrapper, String> {
let zkey = default_zkey().map_err(|err| format!("{:#?}", err))?;
let vk = default_vk().map_err(|err| format!("{:#?}", err))?;
let instance = RLN::new_with_params(zkey, vk).map_err(|err| format!("{:#?}", err))?;
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())
.map_err(|err| format!("{:#?}", err))?;
let wrapper = RLNWrapper { instance };
Ok(Box::into_raw(Box::new(wrapper)))
}
@@ -274,12 +276,6 @@ pub fn rln_witness_to_json(
Object::from_entries(&js_value).map_err(|err| format!("{:#?}", err))
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = generateMembershipKey)]
pub fn wasm_key_gen(ctx: *const RLNWrapper) -> Result<Uint8Array, String> {
call_with_output_and_error_msg!(ctx, key_gen, "could not generate membership keys")
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen]
pub fn generate_rln_proof_with_witness(
@@ -309,6 +305,12 @@ pub fn generate_rln_proof_with_witness(
)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = generateMembershipKey)]
pub fn wasm_key_gen(ctx: *const RLNWrapper) -> Result<Uint8Array, String> {
call_with_output_and_error_msg!(ctx, key_gen, "could not generate membership keys")
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = generateExtendedMembershipKey)]
pub fn wasm_extended_key_gen(ctx: *const RLNWrapper) -> Result<Uint8Array, String> {

View File

@@ -3,7 +3,7 @@
#[cfg(test)]
mod tests {
use js_sys::{BigInt as JsBigInt, Object, Uint8Array};
use rln::circuit::Fr;
use rln::circuit::{Fr, TEST_TREE_HEIGHT};
use rln::hashers::{hash_to_field, poseidon_hash};
use rln::utils::{bytes_le_to_fr, fr_to_bytes_le, normalize_usize};
use rln_wasm::*;
@@ -21,9 +21,16 @@ mod tests {
#[wasm_bindgen_test]
pub async fn test_basic_flow() {
let tree_height = TEST_TREE_HEIGHT;
let circom_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/rln.wasm");
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.json");
let zkey = read_file(&zkey_path).unwrap();
let vk = read_file(&vk_path).unwrap();
// Creating an instance of RLN
let circom_path = format!("../rln/resources/tree_height_20/rln.wasm");
let rln_instance = wasm_new().unwrap();
let rln_instance = wasm_new(tree_height, zkey, vk).unwrap();
// Creating membership key
let mem_keys = wasm_key_gen(rln_instance).unwrap();
@@ -116,10 +123,18 @@ mod tests {
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.json");
let zkey = read_file(&zkey_path).unwrap();
let vk = read_file(&vk_path).unwrap();
// Creating an instance of RLN
let rln_instance = wasm_new().unwrap();
let rln_instance = wasm_new(tree_height, zkey, vk).unwrap();
let test_metadata = Uint8Array::new(&JsValue::from_str("test"));
// Inserting random metadata

View File

@@ -56,7 +56,7 @@ sled = "=0.34.7"
criterion = { version = "=0.4.0", features = ["html_reports"] }
[features]
default = ["parallel", "wasmer/sys-default", "pmtree-ft"]
default = ["parallel", "wasmer/sys-default"]
parallel = ["ark-ec/parallel", "ark-ff/parallel", "ark-std/parallel", "ark-groth16/parallel", "utils/parallel"]
wasm = ["wasmer/js", "wasmer/std"]
fullmerkletree = ["default"]

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,114 @@
{
"protocol": "groth16",
"curve": "bn128",
"nPublic": 5,
"vk_alpha_1": [
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
"1"
],
"vk_beta_2": [
[
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
],
[
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
],
[
"1",
"0"
]
],
"vk_gamma_2": [
[
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
],
[
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
],
[
"1",
"0"
]
],
"vk_delta_2": [
[
"3689226096868373144622340732612563195789744807442014147637039988348252818659",
"18947459102520510468597269280688700807407684209892273827108603062925288762423"
],
[
"5816405977664254142436796931495067997250259145480168934320978750042633353708",
"14555486789839131710516067578112557185806110684461247253491378577062852578892"
],
[
"1",
"0"
]
],
"vk_alphabeta_12": [
[
[
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
],
[
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
],
[
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
]
],
[
[
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
],
[
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
],
[
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
]
]
],
"IC": [
[
"5412646265162057015134786739992128493053406364679846617542694915593022919217",
"9665511386935901867415947590751330959748921059696950821222365265700369811120",
"1"
],
[
"4294362651275803035824711662252687124584574009834787359330648404293309808795",
"1861758671717754835450145961645465880215655915164196594175485865489885224285",
"1"
],
[
"1911114017568107170522785254288953144010421698038439931935418407428234018676",
"13761363892532562822351086117281964648116890138564516558345965908415019790129",
"1"
],
[
"16312980235585837964428386585067529342038135099260965575497230302984635878053",
"20286500347141875536561618770383759234192052027362539966911091298688849002783",
"1"
],
[
"21038649368092225315431823433752123495654049075935052064397443455654061176031",
"6976971039866104284556300526186000690370678593992968176463280189048347216392",
"1"
],
[
"971745799362951123575710699973701411260115357326598060711339429906895409324",
"12959821343398475313407440786226277845673045139874184400082186049649123071798",
"1"
]
]
}

View File

@@ -5,31 +5,39 @@ use ark_bn254::{
G1Projective as ArkG1Projective, G2Affine as ArkG2Affine, G2Projective as ArkG2Projective,
};
use ark_circom::read_zkey;
use ark_circom::WitnessCalculator;
use ark_groth16::{ProvingKey, VerifyingKey};
use ark_relations::r1cs::ConstraintMatrices;
use cfg_if::cfg_if;
use color_eyre::{Report, Result};
use num_bigint::BigUint;
use serde_json::Value;
use std::io::Cursor;
use std::str::FromStr;
use wasmer::{Module, Store};
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(not(target_arch = "wasm32"))] {
use ark_circom::{WitnessCalculator};
use once_cell::sync::OnceCell;
use std::sync::Mutex;
use wasmer::{Module, Store};
use include_dir::{include_dir, Dir};
use std::path::Path;
}
}
const ZKEY_FILENAME: &str = "rln_final.zkey";
const VK_FILENAME: &str = "verification_key.json";
const WASM_FILENAME: &str = "rln.wasm";
// These parameters are used for tests
const ZKEY_BYTES: &[u8] = include_bytes!("../resources/tree_height_20/rln_final.zkey");
// Note that the circuit and keys in TEST_RESOURCES_FOLDER are compiled for Merkle trees of height 20 & 32
// Changing these parameters to other values than these defaults will cause zkSNARK proof verification to fail
pub const TEST_PARAMETERS_INDEX: usize = 0;
pub const TEST_TREE_HEIGHT: usize = [20, 32][TEST_PARAMETERS_INDEX];
pub const TEST_RESOURCES_FOLDER: &str = ["tree_height_20", "tree_height_32"][TEST_PARAMETERS_INDEX];
const VK_BYTES: &[u8] = include_bytes!("../resources/tree_height_20/verification_key.json");
pub const WASM_BYTES: &[u8] = include_bytes!("../resources/tree_height_20/rln.wasm");
#[cfg(not(target_arch = "wasm32"))]
static RESOURCES_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/resources");
// The following types define the pairing friendly elliptic curve, the underlying finite fields and groups default to this module
// Note that proofs are serialized assuming Fr to be 4x8 = 32 bytes in size. Hence, changing to a curve with different encoding will make proof verification to fail
@@ -54,10 +62,18 @@ pub fn zkey_from_raw(zkey_data: &Vec<u8>) -> Result<(ProvingKey<Curve>, Constrai
}
// Loads the proving key
pub fn default_zkey() -> Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)> {
let mut c = Cursor::new(ZKEY_BYTES);
let proving_key_and_matrices = read_zkey(&mut c)?;
Ok(proving_key_and_matrices)
#[cfg(not(target_arch = "wasm32"))]
pub fn zkey_from_folder(
resources_folder: &str,
) -> Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)> {
let zkey = RESOURCES_DIR.get_file(Path::new(resources_folder).join(ZKEY_FILENAME));
if let Some(zkey) = zkey {
let mut c = Cursor::new(zkey.contents());
let proving_key_and_matrices = read_zkey(&mut c)?;
Ok(proving_key_and_matrices)
} else {
Err(Report::msg("No proving key found!"))
}
}
// Loads the verification key from a bytes vector
@@ -77,8 +93,24 @@ pub fn vk_from_raw(vk_data: &Vec<u8>, zkey_data: &Vec<u8>) -> Result<VerifyingKe
}
// Loads the verification key
pub fn default_vk() -> Result<VerifyingKey<Curve>> {
vk_from_vector(VK_BYTES)
#[cfg(not(target_arch = "wasm32"))]
pub fn vk_from_folder(resources_folder: &str) -> Result<VerifyingKey<Curve>> {
let vk = RESOURCES_DIR.get_file(Path::new(resources_folder).join(VK_FILENAME));
let zkey = RESOURCES_DIR.get_file(Path::new(resources_folder).join(ZKEY_FILENAME));
let verifying_key: VerifyingKey<Curve>;
if let Some(vk) = vk {
verifying_key = vk_from_json(vk.contents_utf8().ok_or(Report::msg(
"Could not read verification key from JSON file!",
))?)?;
Ok(verifying_key)
} else if let Some(_zkey) = zkey {
let (proving_key, _matrices) = zkey_from_folder(resources_folder)?;
verifying_key = proving_key.vk;
Ok(verifying_key)
} else {
Err(Report::msg("No proving/verification key found!"))
}
}
#[cfg(not(target_arch = "wasm32"))]
@@ -95,25 +127,18 @@ pub fn circom_from_raw(wasm_buffer: Vec<u8>) -> Result<&'static Mutex<WitnessCal
})
}
#[cfg(target_arch = "wasm32")]
pub fn circom_from_raw(wasm_buffer: Vec<u8>) -> Result<WitnessCalculator> {
let store = Store::default();
let module = Module::new(&store, wasm_buffer)?;
let witness_calculator = WitnessCalculator::from_module(module)?;
Ok(witness_calculator)
}
// Initializes the witness calculator
#[cfg(not(target_arch = "wasm32"))]
pub fn default_circom() -> Result<&'static Mutex<WitnessCalculator>> {
pub fn circom_from_folder(resources_folder: &str) -> Result<&'static Mutex<WitnessCalculator>> {
// We read the wasm file
circom_from_raw(WASM_BYTES.into())
}
let wasm = RESOURCES_DIR.get_file(Path::new(resources_folder).join(WASM_FILENAME));
#[cfg(target_arch = "wasm32")]
pub fn default_circom() -> Result<WitnessCalculator> {
// We read the wasm file
circom_from_raw(WASM_BYTES.into())
if let Some(wasm) = wasm {
let wasm_buffer = wasm.contents();
circom_from_raw(wasm_buffer.to_vec())
} else {
Err(Report::msg("No wasm file found!"))
}
}
// The following function implementations are taken/adapted from https://github.com/gakonst/ark-circom/blob/1732e15d6313fe176b0b1abb858ac9e095d0dbd7/src/zkey.rs
@@ -228,8 +253,12 @@ fn vk_from_vector(vk: &[u8]) -> Result<VerifyingKey<Curve>> {
}
// Checks verification key to be correct with respect to proving key
pub fn check_vk_from_zkey(verifying_key: VerifyingKey<Curve>) -> Result<()> {
let (proving_key, _matrices) = default_zkey()?;
#[cfg(not(target_arch = "wasm32"))]
pub fn check_vk_from_zkey(
resources_folder: &str,
verifying_key: VerifyingKey<Curve>,
) -> Result<()> {
let (proving_key, _matrices) = zkey_from_folder(resources_folder)?;
if proving_key.vk == verifying_key {
Ok(())
} else {

View File

@@ -193,8 +193,8 @@ impl<'a> From<&Buffer> for &'a [u8] {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn new(input_buffer: *const Buffer, ctx: *mut *mut RLN) -> bool {
match RLN::new(input_buffer.process()) {
pub extern "C" fn new(tree_height: usize, input_buffer: *const Buffer, ctx: *mut *mut RLN) -> bool {
match RLN::new(tree_height, input_buffer.process()) {
Ok(rln) => {
unsafe { *ctx = Box::into_raw(Box::new(rln)) };
true

View File

@@ -1,9 +1,8 @@
use crate::circuit::{Curve, Fr};
use crate::circuit::{vk_from_raw, zkey_from_raw, Curve, Fr};
use crate::hashers::{hash_to_field, poseidon_hash as utils_poseidon_hash};
use crate::poseidon_tree::PoseidonTree;
use crate::protocol::*;
use crate::utils::*;
use ark_circom::WitnessCalculator;
/// This is the main public API for RLN module. It is used by the FFI, and should be
/// used by tests etc as well
use ark_groth16::Proof as ArkProof;
@@ -14,14 +13,14 @@ use cfg_if::cfg_if;
use color_eyre::{Report, Result};
use num_bigint::BigInt;
use std::io::Cursor;
use utils::{ZerokitMerkleProof, ZerokitMerkleTree};
cfg_if! {
if #[cfg(not(target_arch = "wasm32"))] {
use std::default::Default;
use std::sync::Mutex;
use crate::circuit::{zkey_from_raw, circom_from_raw, vk_from_raw, default_zkey, default_vk, default_circom};
use crate::circuit::{circom_from_folder, vk_from_folder, circom_from_raw, zkey_from_folder, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT};
use ark_circom::WitnessCalculator;
use serde_json::{json, Value};
use utils::{Hasher};
use std::str::FromStr;
@@ -72,18 +71,21 @@ impl RLN<'_> {
/// let mut rln = RLN::new(tree_height, resources);
/// ```
#[cfg(not(target_arch = "wasm32"))]
pub fn new<R: Read>(mut input_data: R) -> Result<RLN<'static>> {
pub fn new<R: Read>(tree_height: usize, mut input_data: R) -> Result<RLN<'static>> {
// We read input
let mut input: Vec<u8> = Vec::new();
input_data.read_to_end(&mut input)?;
let rln_config: Value = serde_json::from_str(&String::from_utf8(input)?)?;
let resources_folder = rln_config["resources_folder"]
.as_str()
.unwrap_or(TEST_RESOURCES_FOLDER);
let tree_config = rln_config["tree_config"].to_string();
let witness_calculator = default_circom()?;
let witness_calculator = circom_from_folder(resources_folder)?;
let proving_key = default_zkey()?;
let verification_key = default_vk()?;
let proving_key = zkey_from_folder(resources_folder)?;
let verification_key = vk_from_folder(resources_folder)?;
let tree_config: <PoseidonTree as ZerokitMerkleTree>::Config = if tree_config.is_empty() {
<PoseidonTree as ZerokitMerkleTree>::Config::default()
@@ -93,7 +95,7 @@ impl RLN<'_> {
// We compute a default empty tree
let tree = PoseidonTree::new(
20,
tree_height,
<PoseidonTree as ZerokitMerkleTree>::Hasher::default_leaf(),
tree_config,
)?;
@@ -186,15 +188,22 @@ impl RLN<'_> {
#[cfg(target_arch = "wasm32")]
pub fn new_with_params(
zkey: (ProvingKey<Curve>, ConstraintMatrices<Fr>),
vk: VerifyingKey<Curve>,
tree_height: usize,
zkey_vec: Vec<u8>,
vk_vec: Vec<u8>,
) -> Result<RLN<'static>> {
#[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(20)?;
let tree = PoseidonTree::default(tree_height)?;
Ok(RLN {
proving_key: zkey,
verification_key: vk,
proving_key,
verification_key,
tree,
_marker: PhantomData,
})
@@ -734,29 +743,6 @@ impl RLN<'_> {
Ok(())
}
#[cfg(target_arch = "wasm32")]
pub fn generate_rln_proof<R: Read, W: Write>(
&mut self,
witness_calculator: &mut WitnessCalculator,
mut input_data: R,
mut output_data: W,
) -> Result<()> {
// We read input RLN witness and we serialize_compressed it
let mut witness_byte: Vec<u8> = Vec::new();
input_data.read_to_end(&mut witness_byte)?;
let (rln_witness, _) = proof_inputs_to_rln_witness(&mut self.tree, &witness_byte)?;
let proof_values = proof_values_from_witness(&rln_witness)?;
let proof = generate_proof(witness_calculator, &self.proving_key, &rln_witness)?;
// Note: we export a serialization of ark-groth16::Proof not semaphore::Proof
// This proof is compressed, i.e. 128 bytes long
proof.serialize_compressed(&mut output_data)?;
output_data.write_all(&serialize_proof_values(&proof_values))?;
Ok(())
}
// TODO: this function seems to use redundant witness (as bigint and serialized) and should be refactored
// Generate RLN Proof using a witness calculated from outside zerokit
//
@@ -1202,8 +1188,9 @@ impl RLN<'_> {
#[cfg(not(target_arch = "wasm32"))]
impl Default for RLN<'_> {
fn default() -> Self {
let buffer = Cursor::new(json!({}).to_string());
Self::new(buffer).unwrap()
let tree_height = TEST_TREE_HEIGHT;
let buffer = Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
Self::new(tree_height, buffer).unwrap()
}
}

View File

@@ -1,4 +1,4 @@
use crate::circuit::{Curve, Fr};
use crate::circuit::{Curve, Fr, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT};
use crate::hashers::{hash_to_field, poseidon_hash as utils_poseidon_hash};
use crate::protocol::*;
use crate::public::RLN;
@@ -14,11 +14,10 @@ use ark_std::{rand::thread_rng, UniformRand};
use rand::Rng;
use serde_json::{json, Value};
const tree_height: usize = 20;
#[test]
// We test merkle batch Merkle tree additions
fn test_merkle_operations() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -29,8 +28,9 @@ fn test_merkle_operations() {
}
// We create a new tree
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We first add leaves one by one specifying the index
for (i, leaf) in leaves.iter().enumerate() {
@@ -109,6 +109,7 @@ fn test_merkle_operations() {
// We test leaf setting with a custom index, to enable batch updates to the root
// Uses `set_leaves_from` to set leaves in a batch, from index `start_index`
fn test_leaf_setting_with_index() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -123,8 +124,9 @@ fn test_leaf_setting_with_index() {
let set_index = rng.gen_range(0..no_of_leaves) as usize;
// We create a new tree
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@@ -183,6 +185,7 @@ fn test_leaf_setting_with_index() {
#[test]
// Tests the atomic_operation fn, which set_leaves_from uses internally
fn test_atomic_operation() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -193,8 +196,9 @@ fn test_atomic_operation() {
}
// We create a new tree
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@@ -232,6 +236,7 @@ fn test_atomic_operation() {
#[test]
fn test_atomic_operation_zero_indexed() {
// Test duplicated from https://github.com/waku-org/go-zerokit-rln/pull/12/files
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -242,8 +247,9 @@ fn test_atomic_operation_zero_indexed() {
}
// We create a new tree
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@@ -276,6 +282,7 @@ fn test_atomic_operation_zero_indexed() {
#[test]
fn test_atomic_operation_consistency() {
// Test duplicated from https://github.com/waku-org/go-zerokit-rln/pull/12/files
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -286,8 +293,9 @@ fn test_atomic_operation_consistency() {
}
// We create a new tree
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@@ -328,6 +336,7 @@ fn test_atomic_operation_consistency() {
#[test]
// This test checks if `set_leaves_from` throws an error when the index is out of bounds
fn test_set_leaves_bad_index() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -339,8 +348,9 @@ fn test_set_leaves_bad_index() {
let bad_index = (1 << tree_height) - rng.gen_range(0..no_of_leaves) as usize;
// We create a new tree
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// Get root of empty tree
let mut buffer = Cursor::new(Vec::<u8>::new());
@@ -401,8 +411,11 @@ fn value_to_string_vec(value: &Value) -> Vec<String> {
#[test]
fn test_groth16_proof_hardcoded() {
let input_buffer = Cursor::new(json!({}).to_string());
let rln = RLN::new(input_buffer).unwrap();
let tree_height = TEST_TREE_HEIGHT;
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let rln = RLN::new(tree_height, input_buffer).unwrap();
let valid_snarkjs_proof = json!({
"pi_a": [
@@ -480,11 +493,14 @@ fn test_groth16_proof_hardcoded() {
#[test]
// This test is similar to the one in lib, but uses only public API
fn test_groth16_proof() {
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let tree_height = TEST_TREE_HEIGHT;
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// Note: we only test Groth16 proof generation, so we ignore setting the tree in the RLN object
let rln_witness = random_rln_witness(tree_height.into());
let rln_witness = random_rln_witness(tree_height);
let proof_values = proof_values_from_witness(&rln_witness).unwrap();
// We compute a Groth16 proof
@@ -514,6 +530,7 @@ fn test_groth16_proof() {
#[test]
fn test_rln_proof() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -526,8 +543,9 @@ fn test_rln_proof() {
}
// We create a new RLN instance
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@@ -587,6 +605,7 @@ fn test_rln_proof() {
#[test]
fn test_rln_with_witness() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -597,8 +616,9 @@ fn test_rln_with_witness() {
}
// We create a new RLN instance
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@@ -691,6 +711,7 @@ fn test_rln_with_witness() {
#[test]
fn proof_verification_with_roots() {
// The first part is similar to test_rln_with_witness
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -701,8 +722,9 @@ fn proof_verification_with_roots() {
}
// We create a new RLN instance
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@@ -791,9 +813,12 @@ fn proof_verification_with_roots() {
#[test]
fn test_recover_id_secret() {
let tree_height = TEST_TREE_HEIGHT;
// We create a new RLN instance
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// Generate identity pair
let (identity_secret_hash, id_commitment) = keygen();
@@ -926,9 +951,11 @@ fn test_recover_id_secret() {
#[test]
fn test_get_leaf() {
// We generate a random tree
let tree_height = 10;
let mut rng = thread_rng();
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We generate a random leaf
let leaf = Fr::rand(&mut rng);
@@ -951,8 +978,11 @@ fn test_get_leaf() {
#[test]
fn test_metadata() {
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let tree_height = TEST_TREE_HEIGHT;
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
let arbitrary_metadata: &[u8] = b"block_number:200000";
rln.set_metadata(arbitrary_metadata).unwrap();

View File

@@ -1,7 +1,5 @@
#[cfg(test)]
mod test {
const tree_height: usize = 20;
use ark_std::{rand::thread_rng, UniformRand};
use rand::Rng;
use rln::circuit::*;
@@ -19,6 +17,7 @@ mod test {
#[test]
// We test merkle batch Merkle tree additions
fn test_merkle_operations_ffi() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -30,9 +29,9 @@ mod test {
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resource_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -133,13 +132,14 @@ mod test {
// Uses `set_leaves_from` to set leaves in a batch
fn test_leaf_setting_with_index_ffi() {
// We create a new tree
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -224,13 +224,14 @@ mod test {
#[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() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -288,6 +289,7 @@ mod test {
#[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() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
// We generate a vector of random leaves
@@ -301,9 +303,9 @@ mod test {
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -337,14 +339,15 @@ mod test {
#[test]
// This test is similar to the one in lib, but uses only public C API
fn test_merkle_proof_ffi() {
let tree_height = TEST_TREE_HEIGHT;
let leaf_index = 3;
let user_message_limit = 1;
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -370,16 +373,18 @@ mod test {
use ark_ff::BigInt;
assert_eq!(
root,
BigInt([
4939322235247991215,
5110804094006647505,
4427606543677101242,
910933464535675827
])
.into()
);
if TEST_TREE_HEIGHT == 20 || TEST_TREE_HEIGHT == 32 {
assert_eq!(
root,
BigInt([
4939322235247991215,
5110804094006647505,
4427606543677101242,
910933464535675827
])
.into()
);
}
// We obtain the Merkle tree root
let mut output_buffer = MaybeUninit::<Buffer>::uninit();
@@ -473,36 +478,40 @@ mod test {
let mut expected_identity_path_index: Vec<u8> =
vec![1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
expected_path_elements.append(&mut vec![
str_to_fr(
"0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92",
16,
)
.unwrap(),
str_to_fr(
"0x2a7c7c9b6ce5880b9f6f228d72bf6a575a526f29c66ecceef8b753d38bba7323",
16,
)
.unwrap(),
str_to_fr(
"0x2e8186e558698ec1c67af9c14d463ffc470043c9c2988b954d75dd643f36b992",
16,
)
.unwrap(),
str_to_fr(
"0x0f57c5571e9a4eab49e2c8cf050dae948aef6ead647392273546249d1c1ff10f",
16,
)
.unwrap(),
]);
expected_identity_path_index.append(&mut vec![0, 0, 0, 0]);
if TEST_TREE_HEIGHT == 20 {
expected_path_elements.append(&mut vec![
str_to_fr(
"0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92",
16,
)
.unwrap(),
str_to_fr(
"0x2a7c7c9b6ce5880b9f6f228d72bf6a575a526f29c66ecceef8b753d38bba7323",
16,
)
.unwrap(),
str_to_fr(
"0x2e8186e558698ec1c67af9c14d463ffc470043c9c2988b954d75dd643f36b992",
16,
)
.unwrap(),
str_to_fr(
"0x0f57c5571e9a4eab49e2c8cf050dae948aef6ead647392273546249d1c1ff10f",
16,
)
.unwrap(),
]);
expected_identity_path_index.append(&mut vec![0, 0, 0, 0]);
}
expected_path_elements.append(&mut vec![str_to_fr(
"0x1830ee67b5fb554ad5f63d4388800e1cfe78e310697d46e43c9ce36134f72cca",
16,
)
.unwrap()]);
expected_identity_path_index.append(&mut vec![0]);
if TEST_TREE_HEIGHT == 20 {
expected_path_elements.append(&mut vec![str_to_fr(
"0x1830ee67b5fb554ad5f63d4388800e1cfe78e310697d46e43c9ce36134f72cca",
16,
)
.unwrap()]);
expected_identity_path_index.append(&mut vec![0]);
}
assert_eq!(path_elements, expected_path_elements);
assert_eq!(identity_path_index, expected_identity_path_index);
@@ -521,11 +530,13 @@ mod test {
#[test]
// Benchmarks proof generation and verification
fn test_groth16_proofs_performance_ffi() {
let tree_height = TEST_TREE_HEIGHT;
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -582,11 +593,13 @@ mod test {
#[test]
// Creating a RLN with raw data should generate same results as using a path to resources
fn test_rln_raw_ffi() {
let tree_height = TEST_TREE_HEIGHT;
// We create a RLN instance using a resource folder path
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -599,7 +612,7 @@ mod test {
let (root_rln_folder, _) = bytes_le_to_fr(&result_data);
// Reading the raw data from the files required for instantiating a RLN instance using raw data
let circom_path = format!("./resources/tree_height_20/rln.wasm");
let circom_path = format!("./resources/tree_height_{TEST_TREE_HEIGHT}/rln.wasm");
let mut circom_file = File::open(&circom_path).expect("no file found");
let metadata = std::fs::metadata(&circom_path).expect("unable to read metadata");
let mut circom_buffer = vec![0; metadata.len() as usize];
@@ -607,7 +620,7 @@ mod test {
.read_exact(&mut circom_buffer)
.expect("buffer overflow");
let zkey_path = format!("./resources/tree_height_20/rln_final.zkey");
let zkey_path = format!("./resources/tree_height_{TEST_TREE_HEIGHT}/rln_final.zkey");
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];
@@ -615,7 +628,7 @@ mod test {
.read_exact(&mut zkey_buffer)
.expect("buffer overflow");
let vk_path = format!("./resources/tree_height_20/verification_key.json");
let vk_path = format!("./resources/tree_height_{TEST_TREE_HEIGHT}/verification_key.json");
let mut vk_file = File::open(&vk_path).expect("no file found");
let metadata = std::fs::metadata(&vk_path).expect("unable to read metadata");
@@ -656,6 +669,7 @@ mod test {
#[test]
// Computes and verifies an RLN ZK proof using FFI APIs
fn test_rln_proof_ffi() {
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
let user_message_limit = Fr::from(65535);
@@ -670,9 +684,9 @@ mod test {
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -755,6 +769,7 @@ mod test {
// Computes and verifies an RLN ZK proof by checking proof's root against an input roots buffer
fn test_verify_with_roots() {
// First part similar to test_rln_proof_ffi
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 256;
let user_message_limit = Fr::from(100);
@@ -767,9 +782,9 @@ mod test {
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -891,11 +906,13 @@ mod test {
#[test]
// Computes and verifies an RLN ZK proof using FFI APIs
fn test_recover_id_secret_ffi() {
let tree_height = TEST_TREE_HEIGHT;
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -1062,11 +1079,13 @@ mod test {
#[test]
// Tests hash to field using FFI APIs
fn test_seeded_keygen_ffi() {
let tree_height = TEST_TREE_HEIGHT;
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -1101,11 +1120,12 @@ mod test {
#[test]
// Tests hash to field using FFI APIs
fn test_seeded_extended_keygen_ffi() {
let tree_height = TEST_TREE_HEIGHT;
// We create a RLN instance
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -1205,12 +1225,13 @@ mod test {
#[test]
fn test_get_leaf() {
// We create a RLN instance
let no_of_leaves = 1 << tree_height;
let tree_height = TEST_TREE_HEIGHT;
let no_of_leaves = 1 << TEST_TREE_HEIGHT;
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
@@ -1249,11 +1270,12 @@ mod test {
#[test]
fn test_metadata() {
// We create a RLN instance
let tree_height = TEST_TREE_HEIGHT;
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({}).to_string();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(input_buffer, rln_pointer.as_mut_ptr());
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };

View File

@@ -1,7 +1,10 @@
#[cfg(test)]
mod test {
use ark_ff::BigInt;
use rln::circuit::{default_circom, default_vk, default_zkey, Fr};
use rln::circuit::{
circom_from_folder, vk_from_folder, zkey_from_folder, Fr, TEST_RESOURCES_FOLDER,
TEST_TREE_HEIGHT,
};
use rln::hashers::{hash_to_field, poseidon_hash};
use rln::poseidon_tree::PoseidonTree;
use rln::protocol::*;
@@ -68,6 +71,7 @@ mod test {
#[test]
// We test Merkle tree generation, proofs and verification
fn test_merkle_proof() {
let tree_height = TEST_TREE_HEIGHT;
let leaf_index = 3;
// generate identity
@@ -77,29 +81,38 @@ mod test {
// generate merkle tree
let default_leaf = Fr::from(0);
let mut tree =
PoseidonTree::new(20, default_leaf, ConfigOf::<PoseidonTree>::default()).unwrap();
let mut tree = PoseidonTree::new(
tree_height,
default_leaf,
ConfigOf::<PoseidonTree>::default(),
)
.unwrap();
tree.set(leaf_index, rate_commitment.into()).unwrap();
// We check correct computation of the root
let root = tree.root();
assert_eq!(
root,
BigInt([
4939322235247991215,
5110804094006647505,
4427606543677101242,
910933464535675827
])
.into()
);
if TEST_TREE_HEIGHT == 20 || TEST_TREE_HEIGHT == 32 {
assert_eq!(
root,
BigInt([
4939322235247991215,
5110804094006647505,
4427606543677101242,
910933464535675827
])
.into()
);
}
let merkle_proof = tree.proof(leaf_index).expect("proof should exist");
let path_elements = merkle_proof.get_path_elements();
dbg!(&path_elements);
dbg!(poseidon_hash(&[rate_commitment, Fr::from(0)]));
let identity_path_index = merkle_proof.get_path_index();
// We check correct computation of the path and indexes
// These values refers to TEST_TREE_HEIGHT == 16
let mut expected_path_elements = vec![
str_to_fr(
"0x0000000000000000000000000000000000000000000000000000000000000000",
@@ -182,36 +195,40 @@ mod test {
vec![1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
// We add the remaining elements for the case TEST_TREE_HEIGHT = 20
expected_path_elements.append(&mut vec![
str_to_fr(
"0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92",
16,
)
.unwrap(),
str_to_fr(
"0x2a7c7c9b6ce5880b9f6f228d72bf6a575a526f29c66ecceef8b753d38bba7323",
16,
)
.unwrap(),
str_to_fr(
"0x2e8186e558698ec1c67af9c14d463ffc470043c9c2988b954d75dd643f36b992",
16,
)
.unwrap(),
str_to_fr(
"0x0f57c5571e9a4eab49e2c8cf050dae948aef6ead647392273546249d1c1ff10f",
16,
)
.unwrap(),
]);
expected_identity_path_index.append(&mut vec![0, 0, 0, 0]);
if TEST_TREE_HEIGHT == 20 {
expected_path_elements.append(&mut vec![
str_to_fr(
"0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92",
16,
)
.unwrap(),
str_to_fr(
"0x2a7c7c9b6ce5880b9f6f228d72bf6a575a526f29c66ecceef8b753d38bba7323",
16,
)
.unwrap(),
str_to_fr(
"0x2e8186e558698ec1c67af9c14d463ffc470043c9c2988b954d75dd643f36b992",
16,
)
.unwrap(),
str_to_fr(
"0x0f57c5571e9a4eab49e2c8cf050dae948aef6ead647392273546249d1c1ff10f",
16,
)
.unwrap(),
]);
expected_identity_path_index.append(&mut vec![0, 0, 0, 0]);
}
expected_path_elements.append(&mut vec![str_to_fr(
"0x1830ee67b5fb554ad5f63d4388800e1cfe78e310697d46e43c9ce36134f72cca",
16,
)
.unwrap()]);
expected_identity_path_index.append(&mut vec![0]);
if TEST_TREE_HEIGHT == 20 {
expected_path_elements.append(&mut vec![str_to_fr(
"0x1830ee67b5fb554ad5f63d4388800e1cfe78e310697d46e43c9ce36134f72cca",
16,
)
.unwrap()]);
expected_identity_path_index.append(&mut vec![0]);
}
assert_eq!(path_elements, expected_path_elements);
assert_eq!(identity_path_index, expected_identity_path_index);
@@ -224,9 +241,9 @@ mod test {
// We test a RLN proof generation and verification
fn test_witness_from_json() {
// We generate all relevant keys
let proving_key = default_zkey().unwrap();
let verification_key = default_vk().unwrap();
let builder = default_circom().unwrap();
let proving_key = zkey_from_folder(TEST_RESOURCES_FOLDER).unwrap();
let verification_key = vk_from_folder(TEST_RESOURCES_FOLDER).unwrap();
let builder = circom_from_folder(TEST_RESOURCES_FOLDER).unwrap();
// We compute witness from the json input example
let witness_json = WITNESS_JSON_20;
@@ -242,9 +259,122 @@ mod test {
assert!(verified.unwrap());
}
#[test]
fn test_compute_root_single_insertion() {
let tree_height = TEST_TREE_HEIGHT;
let leaf_index = 0;
let rate_commitment = str_to_fr(
"0x2A09A9FD93C590C26B91EFFBB2499F07E8F7AA12E2B4940A3AED2411CB65E11C",
16,
)
.unwrap();
let default_leaf = Fr::from(0);
let mut tree = PoseidonTree::new(
tree_height,
default_leaf,
ConfigOf::<PoseidonTree>::default(),
)
.unwrap();
tree.set(leaf_index, rate_commitment.into()).unwrap();
assert_eq!(
tree.root().to_string(),
"7919895337495550471953660523154055129542864206434083474237224229170626792564"
);
}
#[test]
fn test_compute_root_multiple_insertions() {
let tree_height = TEST_TREE_HEIGHT;
let start_index = 0;
let rate_commitments: Vec<Fr> = [
BigInt([
6344960399222479404,
8873735028955887118,
7344916015079734877,
3049769223023031486,
]),
BigInt([
5712098114927176582,
8940737845291386850,
13760702216785496874,
2705829225787818087,
]),
BigInt([
11095489423361569757,
3600059334404558726,
2596276295120316067,
1747990648971046346,
]),
BigInt([
6042348329893423557,
18258910608249868782,
15808282831752017379,
431669247253051424,
]),
BigInt([
10095207707778447201,
5682738389371124904,
13211310082780638286,
1315201582035914269,
]),
BigInt([
17025532269492512967,
1150892318682047614,
9382150527271933425,
3232654496558305327,
]),
BigInt([
12575250814731208081,
3588033008530583836,
14988210865591309718,
1882695786084137797,
]),
BigInt([
2907978739955320703,
8716018548752635030,
10462674785957232325,
2943370953425792650,
]),
BigInt([
5234706529109067247,
11231622334196983240,
1886386083208828393,
1690607978854820878,
]),
BigInt([
12359804935986041669,
10294673542421867784,
11783956311711833641,
2759017549080634703,
]),
]
.into_iter()
.map(|x| Fr::from(x))
.collect();
let default_leaf = Fr::from(0);
let mut tree = PoseidonTree::new(
tree_height,
default_leaf,
ConfigOf::<PoseidonTree>::default(),
)
.unwrap();
tree.set_range(start_index, rate_commitments).unwrap();
assert_eq!(
tree.root().to_string(),
"5210724218081541877101688952118136930297124697603087561558225712176057209122"
);
}
#[test]
// We test a RLN proof generation and verification
fn test_end_to_end() {
let tree_height = TEST_TREE_HEIGHT;
let leaf_index = 3;
// Generate identity pair
@@ -254,8 +384,12 @@ mod test {
//// generate merkle tree
let default_leaf = Fr::from(0);
let mut tree =
PoseidonTree::new(20, default_leaf, ConfigOf::<PoseidonTree>::default()).unwrap();
let mut tree = PoseidonTree::new(
tree_height,
default_leaf,
ConfigOf::<PoseidonTree>::default(),
)
.unwrap();
tree.set(leaf_index, rate_commitment.into()).unwrap();
let merkle_proof = tree.proof(leaf_index).expect("proof should exist");
@@ -279,9 +413,9 @@ mod test {
.unwrap();
// We generate all relevant keys
let proving_key = default_zkey().unwrap();
let verification_key = default_vk().unwrap();
let builder = default_circom().unwrap();
let proving_key = zkey_from_folder(TEST_RESOURCES_FOLDER).unwrap();
let verification_key = vk_from_folder(TEST_RESOURCES_FOLDER).unwrap();
let builder = circom_from_folder(TEST_RESOURCES_FOLDER).unwrap();
// Let's generate a zkSNARK proof
let proof = generate_proof(builder, &proving_key, &rln_witness).unwrap();
@@ -312,6 +446,24 @@ mod test {
assert_eq!(proof_values, deser);
}
#[test]
fn test_poseidon_hash() {
let inputs = &[
str_to_fr(
"0x2A09A9FD93C590C26B91EFFBB2499F07E8F7AA12E2B4940A3AED2411CB65E11C",
16,
)
.unwrap(),
Fr::from(0),
];
let hash = poseidon_hash(inputs);
assert_eq!(
hash.to_string(),
"13164376930590487041313497514223288845711140604177161029957349518915056324115"
);
}
#[test]
// Tests seeded keygen
// Note that hardcoded values are only valid for Bn254

View File

@@ -3,7 +3,7 @@ mod test {
use ark_ff::BigInt;
use ark_std::{rand::thread_rng, UniformRand};
use rand::Rng;
use rln::circuit::Fr;
use rln::circuit::{Fr, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT};
use rln::hashers::{hash_to_field, poseidon_hash as utils_poseidon_hash, ROUND_PARAMS};
use rln::protocol::{compute_tree_root, deserialize_identity_tuple};
use rln::public::{hash as public_hash, poseidon_hash as public_poseidon_hash, RLN};
@@ -14,11 +14,13 @@ mod test {
#[test]
// This test is similar to the one in lib, but uses only public API
fn test_merkle_proof() {
let tree_height = TEST_TREE_HEIGHT;
let leaf_index = 3;
let user_message_limit = 1;
let input_buffer = Cursor::new(json!({}).to_string());
let mut rln = RLN::new(input_buffer).unwrap();
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// generate identity
let identity_secret_hash = hash_to_field(b"test-merkle-proof");
@@ -34,15 +36,26 @@ mod test {
rln.get_root(&mut buffer).unwrap();
let (root, _) = bytes_le_to_fr(&buffer.into_inner());
assert_eq!(
root,
Fr::from(BigInt([
17110646155607829651,
5040045984242729823,
6965416728592533086,
2328960363755461975
]))
);
if TEST_TREE_HEIGHT == 20 {
assert_eq!(
root,
Fr::from(BigInt([
17110646155607829651,
5040045984242729823,
6965416728592533086,
2328960363755461975
]))
);
} else if TEST_TREE_HEIGHT == 32 {
assert_eq!(
root,
str_to_fr(
"0x21947ffd0bce0c385f876e7c97d6a42eec5b1fe935aab2f01c1f8a8cbcc356d2",
16
)
.unwrap()
);
}
// We check correct computation of merkle proof
let mut buffer = Cursor::new(Vec::<u8>::new());
@@ -135,36 +148,40 @@ mod test {
vec![1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
// We add the remaining elements for the case TEST_TREE_HEIGHT = 20
expected_path_elements.append(&mut vec![
str_to_fr(
"0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92",
16,
)
.unwrap(),
str_to_fr(
"0x2a7c7c9b6ce5880b9f6f228d72bf6a575a526f29c66ecceef8b753d38bba7323",
16,
)
.unwrap(),
str_to_fr(
"0x2e8186e558698ec1c67af9c14d463ffc470043c9c2988b954d75dd643f36b992",
16,
)
.unwrap(),
str_to_fr(
"0x0f57c5571e9a4eab49e2c8cf050dae948aef6ead647392273546249d1c1ff10f",
16,
)
.unwrap(),
]);
expected_identity_path_index.append(&mut vec![0, 0, 0, 0]);
if TEST_TREE_HEIGHT == 20 || TEST_TREE_HEIGHT == 32 {
expected_path_elements.append(&mut vec![
str_to_fr(
"0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92",
16,
)
.unwrap(),
str_to_fr(
"0x2a7c7c9b6ce5880b9f6f228d72bf6a575a526f29c66ecceef8b753d38bba7323",
16,
)
.unwrap(),
str_to_fr(
"0x2e8186e558698ec1c67af9c14d463ffc470043c9c2988b954d75dd643f36b992",
16,
)
.unwrap(),
str_to_fr(
"0x0f57c5571e9a4eab49e2c8cf050dae948aef6ead647392273546249d1c1ff10f",
16,
)
.unwrap(),
]);
expected_identity_path_index.append(&mut vec![0, 0, 0, 0]);
}
expected_path_elements.append(&mut vec![str_to_fr(
"0x1830ee67b5fb554ad5f63d4388800e1cfe78e310697d46e43c9ce36134f72cca",
16,
)
.unwrap()]);
expected_identity_path_index.append(&mut vec![0]);
if TEST_TREE_HEIGHT == 20 {
expected_path_elements.append(&mut vec![str_to_fr(
"0x1830ee67b5fb554ad5f63d4388800e1cfe78e310697d46e43c9ce36134f72cca",
16,
)
.unwrap()]);
expected_identity_path_index.append(&mut vec![0]);
}
assert_eq!(path_elements, expected_path_elements);
assert_eq!(identity_path_index, expected_identity_path_index);

View File

@@ -13,6 +13,7 @@
//! * Disk based storage backend (using mmaped files should be easy)
//! * Implement serialization for tree and Merkle proof
use std::fmt::Debug;
use std::str::FromStr;
use color_eyre::Result;
@@ -21,7 +22,7 @@ use color_eyre::Result;
/// and the hash function used to initialize a Merkle Tree implementation
pub trait Hasher {
/// Type of the leaf and tree node
type Fr: Clone + Copy + Eq;
type Fr: Clone + Copy + Eq + Debug + ToString;
/// Returns the default tree leaf
fn default_leaf() -> Self::Fr;

View File

@@ -113,6 +113,8 @@ where
if index >= self.capacity() {
return Err(Report::msg("index exceeds set size"));
}
let log = format!("inserting {} at {}[{index}]", leaf.to_string(), self.depth);
dbg!(log);
self.nodes.insert((self.depth, index), leaf);
self.recalculate_from(index)?;
self.next_index = max(self.next_index, index + 1);
@@ -192,6 +194,7 @@ where
if index >= self.capacity() {
return Err(Report::msg("index exceeds set size"));
}
dbg!("yomama");
let mut witness = Vec::<(H::Fr, u8)>::with_capacity(self.depth);
let mut i = index;
let mut depth = self.depth;
@@ -246,6 +249,13 @@ where
.nodes
.get(&(depth, index))
.unwrap_or_else(|| &self.cached_nodes[depth]);
let log = format!(
"depth: {}, index: {}, node at depth[index]: {}",
depth,
index,
&node.to_string()
);
dbg!(log);
node
}
@@ -255,10 +265,14 @@ where
fn hash_couple(&mut self, depth: usize, index: usize) -> H::Fr {
let b = index & !1;
H::hash(&[self.get_node(depth, b), self.get_node(depth, b + 1)])
let l = self.get_node(depth, b);
let r = self.get_node(depth, b + 1);
dbg!(l.to_string(), r.to_string());
H::hash(&[l, r])
}
fn recalculate_from(&mut self, index: usize) -> Result<()> {
dbg!("running recalc from");
let mut i = index;
let mut depth = self.depth;
loop {
@@ -266,6 +280,8 @@ where
i >>= 1;
depth -= 1;
self.nodes.insert((depth, i), h);
let log = format!("inserting {} at {depth}[{i}]", h.to_string());
dbg!(log);
if depth == 0 {
break;
}