fix(rln): Remove resources folder, update missed docs (#246)

* remove resources folder, update missed docs

* refactor
This commit is contained in:
Ekaterina Broslavskaya 2024-05-10 18:13:00 +07:00 committed by GitHub
parent 652cc3647e
commit 4931b25237
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 105 additions and 131 deletions

View File

@ -3,6 +3,7 @@
This module provides APIs to manage, compute and verify [RLN](https://rfc.vac.dev/spec/32/) zkSNARK proofs and RLN primitives. This module provides APIs to manage, compute and verify [RLN](https://rfc.vac.dev/spec/32/) zkSNARK proofs and RLN primitives.
## Pre-requisites ## Pre-requisites
### Install dependencies and clone repo ### Install dependencies and clone repo
```sh ```sh
@ -14,6 +15,7 @@ cd zerokit/rln
### Build and Test ### Build and Test
To build and test, run the following commands within the module folder To build and test, run the following commands within the module folder
```bash ```bash
cargo make build cargo make build
cargo make test cargo make test
@ -21,11 +23,11 @@ cargo make test
### Compile ZK circuits ### Compile ZK circuits
The `rln` (https://github.com/privacy-scaling-explorations/rln) repository, which contains the RLN circuit implementation is a submodule of zerokit RLN. The `rln` (https://github.com/rate-limiting-nullifier/circom-rln) repository, which contains the RLN circuit implementation is a submodule of zerokit RLN.
To compile the RLN circuit To compile the RLN circuit
``` sh ```sh
# Update submodules # Update submodules
git submodule update --init --recursive git submodule update --init --recursive
@ -52,10 +54,9 @@ include "./rln-base.circom";
component main {public [x, epoch, rln_identifier ]} = RLN(N); component main {public [x, epoch, rln_identifier ]} = RLN(N);
``` ```
However, if `N` is too big, this might require a bigger Powers of Tau ceremony than the one hardcoded in `./scripts/build-circuits.sh`, which is `2^14`. However, if `N` is too big, this might require a bigger Powers of Tau ceremony than the one hardcoded in `./scripts/build-circuits.sh`, which is `2^14`.
In such case we refer to the official [Circom documentation](https://docs.circom.io/getting-started/proving-circuits/#powers-of-tau) for instructions on how to run an appropriate Powers of Tau ceremony and Phase 2 in order to compile the desired circuit. In such case we refer to the official [Circom documentation](https://docs.circom.io/getting-started/proving-circuits/#powers-of-tau) for instructions on how to run an appropriate Powers of Tau ceremony and Phase 2 in order to compile the desired circuit.
Currently, the `rln` module comes with 2 [pre-compiled](https://github.com/vacp2p/zerokit/tree/master/rln/resources) RLN circuits having Merkle tree of height `20` and `32`, respectively. Currently, the `rln` module comes with 2 [pre-compiled](https://github.com/vacp2p/zerokit/tree/master/rln/resources) RLN circuits having Merkle tree of height `20` and `32`, respectively.
## Getting started ## Getting started
@ -73,7 +74,7 @@ rln = { git = "https://github.com/vacp2p/zerokit" }
First, we need to create a RLN object for a chosen input Merkle tree size. First, we need to create a RLN object for a chosen input Merkle tree size.
Note that we need to pass to RLN object constructor the path where the circuit (`rln.wasm`, built for the input tree size), the corresponding proving key (`rln_final.zkey`) and verification key (`verification_key.json`, optional) are found. Note that we need to pass to RLN object constructor the path where the circuit (`rln.wasm`, built for the input tree size), the corresponding proving key (`rln_final.zkey`) or (`rln_final.arkzkey`) and verification key (`verification_key.json`, optional) are found.
In the following we will use [cursors](https://doc.rust-lang.org/std/io/struct.Cursor.html) as readers/writers for interfacing with RLN public APIs. In the following we will use [cursors](https://doc.rust-lang.org/std/io/struct.Cursor.html) as readers/writers for interfacing with RLN public APIs.
@ -82,14 +83,14 @@ use rln::protocol::*;
use rln::public::*; use rln::public::*;
use std::io::Cursor; use std::io::Cursor;
// We set the RLN parameters: // We set the RLN parameters:
// - the tree height; // - the tree height;
// - the circuit resource folder (requires a trailing "/"). // - the tree config, if it is not defined, the default value will be set
let tree_height = 20; let tree_height = 20;
let resources = Cursor::new("../zerokit/rln/resources/tree_height_20/"); let input = Cursor::new(json!({}).to_string());
// We create a new RLN instance // We create a new RLN instance
let mut rln = RLN::new(tree_height, resources); let mut rln = RLN::new(tree_height, input);
``` ```
### Generate an identity keypair ### Generate an identity keypair
@ -121,33 +122,43 @@ rln.set_leaf(id_index, &mut buffer).unwrap();
Note that when tree leaves are not explicitly set by the user (in this example, all those with index less and greater than `10`), their values is set to an hardcoded default (all-`0` bytes in current implementation). Note that when tree leaves are not explicitly set by the user (in this example, all those with index less and greater than `10`), their values is set to an hardcoded default (all-`0` bytes in current implementation).
### Set epoch ### Set external nullifier
The epoch, sometimes referred to as _external nullifier_, is used to identify messages received in a certain time frame. It usually corresponds to the current UNIX time but can also be set to a random value or generated by a seed, provided that it corresponds to a field element. The `external nullifier` includes two parameters.
The first one is `epoch` and it's used to identify messages received in a certain time frame. It usually corresponds to the current UNIX time but can also be set to a random value or generated by a seed, provided that it corresponds to a field element.
The second one is `rln_identifier` and it's used to prevent a RLN ZK proof generated for one application to be re-used in another one.
```rust ```rust
// We generate epoch from a date seed and we ensure is // We generate epoch from a date seed and we ensure is
// mapped to a field element by hashing-to-field its content // mapped to a field element by hashing-to-field its content
let epoch = hash_to_field(b"Today at noon, this year"); let epoch = hash_to_field(b"Today at noon, this year");
// We generate rln_identifier from a date seed and we ensure is
// mapped to a field element by hashing-to-field its content
let rln_identifier = hash_to_field(b"test-rln-identifier");
let external_nullifier = poseidon_hash(&[epoch, rln_identifier]);
``` ```
### Set signal ### Set signal
The signal is the message for which we are computing a RLN proof. The signal is the message for which we are computing a RLN proof.
```rust ```rust
// We set our signal // We set our signal
let signal = b"RLN is awesome"; let signal = b"RLN is awesome";
``` ```
### Generate a RLN proof ### Generate a RLN proof
We prepare the input to the proof generation routine. We prepare the input to the proof generation routine.
Input buffer is serialized as `[ identity_key | id_index | epoch | rln_identifier | user_message_limit | message_id | signal_len | signal ]`. Input buffer is serialized as `[ identity_key | id_index | external_nullifier | user_message_limit | message_id | signal_len | signal ]`.
```rust ```rust
// We prepare input to the proof generation routine // We prepare input to the proof generation routine
let proof_input = prepare_prove_input(identity_secret_hash, id_index, epoch, rln_identifier, user_message_limit, message_id, signal); let proof_input = prepare_prove_input(identity_secret_hash, id_index, external_nullifier, signal);
``` ```
We are now ready to generate a RLN ZK proof along with the _public outputs_ of the ZK circuit evaluation. We are now ready to generate a RLN ZK proof along with the _public outputs_ of the ZK circuit evaluation.
@ -164,12 +175,11 @@ rln.generate_rln_proof(&mut in_buffer, &mut out_buffer)
let proof_data = out_buffer.into_inner(); let proof_data = out_buffer.into_inner();
``` ```
The byte vector `proof_data` is serialized as `[ zk-proof | tree_root | epoch | share_x | share_y | nullifier | rln_identifier ]`. The byte vector `proof_data` is serialized as `[ zk-proof | tree_root | external_nullifier | share_x | share_y | nullifier ]`.
### Verify a RLN proof ### Verify a RLN proof
We prepare the input to the proof verification routine. We prepare the input to the proof verification routine.
Input buffer is serialized as `[proof_data | signal_len | signal ]`, where `proof_data` is (computed as) the output obtained by `generate_rln_proof`. Input buffer is serialized as `[proof_data | signal_len | signal ]`, where `proof_data` is (computed as) the output obtained by `generate_rln_proof`.
@ -182,17 +192,21 @@ let mut in_buffer = Cursor::new(verify_data);
let verified = rln.verify(&mut in_buffer).unwrap(); let verified = rln.verify(&mut in_buffer).unwrap();
``` ```
We check if the proof verification was successful: We check if the proof verification was successful:
```rust ```rust
// We ensure the proof is valid // We ensure the proof is valid
assert!(verified); assert!(verified);
``` ```
## Get involved! ## Get involved!
Zerokit RLN public and FFI APIs allow interaction with many more features than what briefly showcased above. Zerokit RLN public and FFI APIs allow interaction with many more features than what briefly showcased above.
We invite you to check our API documentation by running We invite you to check our API documentation by running
```rust ```rust
cargo doc --no-deps cargo doc --no-deps
``` ```
and look at unit tests to have an hint on how to interface and use them.
and look at unit tests to have an hint on how to interface and use them.

View File

@ -1,12 +1,11 @@
use criterion::{criterion_group, criterion_main, Criterion}; use criterion::{criterion_group, criterion_main, Criterion};
use rln::circuit::TEST_RESOURCES_FOLDER;
// Depending on the key type (enabled by the `--features arkzkey` flag) // Depending on the key type (enabled by the `--features arkzkey` flag)
// the upload speed from the `rln_final.zkey` or `rln_final.arkzkey` file is calculated // the upload speed from the `rln_final.zkey` or `rln_final.arkzkey` file is calculated
pub fn key_load_benchmark(c: &mut Criterion) { pub fn key_load_benchmark(c: &mut Criterion) {
c.bench_function("zkey::upload_from_folder", |b| { c.bench_function("zkey::upload_from_folder", |b| {
b.iter(|| { b.iter(|| {
let _ = rln::circuit::zkey_from_folder(TEST_RESOURCES_FOLDER); let _ = rln::circuit::zkey_from_folder();
}) })
}); });
} }

View File

@ -26,7 +26,7 @@ cfg_if! {
cfg_if! { cfg_if! {
if #[cfg(feature = "arkzkey")] { if #[cfg(feature = "arkzkey")] {
use ark_zkey::read_arkzkey_from_bytes; use ark_zkey::read_arkzkey_from_bytes;
const ARKZKEY_FILENAME: &str = "rln_final.arkzkey"; const ARKZKEY_FILENAME: &str = "tree_height_20/rln_final.arkzkey";
} else { } else {
use std::io::Cursor; use std::io::Cursor;
@ -34,12 +34,11 @@ cfg_if! {
} }
} }
const ZKEY_FILENAME: &str = "rln_final.zkey"; const ZKEY_FILENAME: &str = "tree_height_20/rln_final.zkey";
const VK_FILENAME: &str = "verification_key.json"; const VK_FILENAME: &str = "tree_height_20/verification_key.json";
const WASM_FILENAME: &str = "rln.wasm"; const WASM_FILENAME: &str = "tree_height_20/rln.wasm";
pub const TEST_TREE_HEIGHT: usize = 20; pub const TEST_TREE_HEIGHT: usize = 20;
pub const TEST_RESOURCES_FOLDER: &str = "tree_height_20";
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
static RESOURCES_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/resources"); static RESOURCES_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/resources");
@ -75,13 +74,11 @@ pub fn zkey_from_raw(zkey_data: &Vec<u8>) -> Result<(ProvingKey<Curve>, Constrai
// Loads the proving key // Loads the proving key
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub fn zkey_from_folder( pub fn zkey_from_folder() -> Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)> {
resources_folder: &str,
) -> Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)> {
#[cfg(feature = "arkzkey")] #[cfg(feature = "arkzkey")]
let zkey = RESOURCES_DIR.get_file(Path::new(resources_folder).join(ARKZKEY_FILENAME)); let zkey = RESOURCES_DIR.get_file(Path::new(ARKZKEY_FILENAME));
#[cfg(not(feature = "arkzkey"))] #[cfg(not(feature = "arkzkey"))]
let zkey = RESOURCES_DIR.get_file(Path::new(resources_folder).join(ZKEY_FILENAME)); let zkey = RESOURCES_DIR.get_file(Path::new(ZKEY_FILENAME));
if let Some(zkey) = zkey { if let Some(zkey) = zkey {
let proving_key_and_matrices = match () { let proving_key_and_matrices = match () {
@ -117,9 +114,9 @@ pub fn vk_from_raw(vk_data: &[u8], zkey_data: &Vec<u8>) -> Result<VerifyingKey<C
// Loads the verification key // Loads the verification key
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub fn vk_from_folder(resources_folder: &str) -> Result<VerifyingKey<Curve>> { pub fn vk_from_folder() -> Result<VerifyingKey<Curve>> {
let vk = RESOURCES_DIR.get_file(Path::new(resources_folder).join(VK_FILENAME)); let vk = RESOURCES_DIR.get_file(Path::new(VK_FILENAME));
let zkey = RESOURCES_DIR.get_file(Path::new(resources_folder).join(ZKEY_FILENAME)); let zkey = RESOURCES_DIR.get_file(Path::new(ZKEY_FILENAME));
let verifying_key: VerifyingKey<Curve>; let verifying_key: VerifyingKey<Curve>;
if let Some(vk) = vk { if let Some(vk) = vk {
@ -128,7 +125,7 @@ pub fn vk_from_folder(resources_folder: &str) -> Result<VerifyingKey<Curve>> {
))?)?; ))?)?;
Ok(verifying_key) Ok(verifying_key)
} else if let Some(_zkey) = zkey { } else if let Some(_zkey) = zkey {
let (proving_key, _matrices) = zkey_from_folder(resources_folder)?; let (proving_key, _matrices) = zkey_from_folder()?;
verifying_key = proving_key.vk; verifying_key = proving_key.vk;
Ok(verifying_key) Ok(verifying_key)
} else { } else {
@ -152,9 +149,9 @@ pub fn circom_from_raw(wasm_buffer: Vec<u8>) -> Result<&'static Mutex<WitnessCal
// Initializes the witness calculator // Initializes the witness calculator
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub fn circom_from_folder(resources_folder: &str) -> Result<&'static Mutex<WitnessCalculator>> { pub fn circom_from_folder() -> Result<&'static Mutex<WitnessCalculator>> {
// We read the wasm file // We read the wasm file
let wasm = RESOURCES_DIR.get_file(Path::new(resources_folder).join(WASM_FILENAME)); let wasm = RESOURCES_DIR.get_file(Path::new(WASM_FILENAME));
if let Some(wasm) = wasm { if let Some(wasm) = wasm {
let wasm_buffer = wasm.contents(); let wasm_buffer = wasm.contents();
@ -277,11 +274,8 @@ fn vk_from_vector(vk: &[u8]) -> Result<VerifyingKey<Curve>> {
// Checks verification key to be correct with respect to proving key // Checks verification key to be correct with respect to proving key
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub fn check_vk_from_zkey( pub fn check_vk_from_zkey(verifying_key: VerifyingKey<Curve>) -> Result<()> {
resources_folder: &str, let (proving_key, _matrices) = zkey_from_folder()?;
verifying_key: VerifyingKey<Curve>,
) -> Result<()> {
let (proving_key, _matrices) = zkey_from_folder(resources_folder)?;
if proving_key.vk == verifying_key { if proving_key.vk == verifying_key {
Ok(()) Ok(())
} else { } else {

View File

@ -19,7 +19,7 @@ cfg_if! {
if #[cfg(not(target_arch = "wasm32"))] { if #[cfg(not(target_arch = "wasm32"))] {
use std::default::Default; use std::default::Default;
use std::sync::Mutex; use std::sync::Mutex;
use crate::circuit::{circom_from_folder, vk_from_folder, circom_from_raw, zkey_from_folder, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT}; use crate::circuit::{circom_from_folder, vk_from_folder, circom_from_raw, zkey_from_folder, TEST_TREE_HEIGHT};
use ark_circom::WitnessCalculator; use ark_circom::WitnessCalculator;
use serde_json::{json, Value}; use serde_json::{json, Value};
use utils::{Hasher}; use utils::{Hasher};
@ -58,18 +58,16 @@ impl RLN<'_> {
/// ///
/// Input parameters are /// Input parameters are
/// - `tree_height`: the height of the internal Merkle tree /// - `tree_height`: the height of the internal Merkle tree
/// - `input_data`: include next parameters /// - `input_data`: include `tree_config` a reader for a string containing a json with the merkle tree configuration
/// - `resources_folder`: a reader for the string path of the resource folder containing the ZK circuit (`rln.wasm`), the proving key (`rln_final.zkey`) or (`rln_final.arkzkey`) and the verification key (`verification_key.json`).
/// - `tree_config`: a reader for a string containing a json with the merkle tree configuration
/// Example: /// Example:
/// ``` /// ```
/// use std::io::Cursor; /// use std::io::Cursor;
/// ///
/// let tree_height = 20; /// let tree_height = 20;
/// let resources = Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());; /// let input = Cursor::new(json!({}).to_string());;
/// ///
/// // We create a new RLN instance /// // We create a new RLN instance
/// let mut rln = RLN::new(tree_height, resources); /// let mut rln = RLN::new(tree_height, input);
/// ``` /// ```
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub fn new<R: Read>(tree_height: usize, mut input_data: R) -> Result<RLN<'static>> { pub fn new<R: Read>(tree_height: usize, mut input_data: R) -> Result<RLN<'static>> {
@ -78,15 +76,12 @@ impl RLN<'_> {
input_data.read_to_end(&mut input)?; input_data.read_to_end(&mut input)?;
let rln_config: Value = serde_json::from_str(&String::from_utf8(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 tree_config = rln_config["tree_config"].to_string();
let witness_calculator = circom_from_folder(resources_folder)?; let witness_calculator = circom_from_folder()?;
let proving_key = zkey_from_folder(resources_folder)?; let proving_key = zkey_from_folder()?;
let verification_key = vk_from_folder(resources_folder)?; let verification_key = vk_from_folder()?;
let tree_config: <PoseidonTree as ZerokitMerkleTree>::Config = if tree_config.is_empty() { let tree_config: <PoseidonTree as ZerokitMerkleTree>::Config = if tree_config.is_empty() {
<PoseidonTree as ZerokitMerkleTree>::Config::default() <PoseidonTree as ZerokitMerkleTree>::Config::default()
@ -1204,7 +1199,7 @@ impl RLN<'_> {
impl Default for RLN<'_> { impl Default for RLN<'_> {
fn default() -> Self { fn default() -> Self {
let tree_height = TEST_TREE_HEIGHT; let tree_height = TEST_TREE_HEIGHT;
let buffer = Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string()); let buffer = Cursor::new(json!({}).to_string());
Self::new(tree_height, buffer).unwrap() Self::new(tree_height, buffer).unwrap()
} }
} }

View File

@ -1,4 +1,4 @@
use crate::circuit::{Curve, Fr, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT}; use crate::circuit::{Curve, Fr, TEST_TREE_HEIGHT};
use crate::hashers::{hash_to_field, poseidon_hash as utils_poseidon_hash}; use crate::hashers::{hash_to_field, poseidon_hash as utils_poseidon_hash};
use crate::protocol::*; use crate::protocol::*;
use crate::public::RLN; use crate::public::RLN;
@ -28,9 +28,7 @@ fn test_merkle_operations() {
} }
// We create a new tree // We create a new tree
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // We first add leaves one by one specifying the index
for (i, leaf) in leaves.iter().enumerate() { for (i, leaf) in leaves.iter().enumerate() {
@ -124,9 +122,7 @@ fn test_leaf_setting_with_index() {
let set_index = rng.gen_range(0..no_of_leaves) as usize; let set_index = rng.gen_range(0..no_of_leaves) as usize;
// We create a new tree // We create a new tree
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap()); let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@ -196,9 +192,7 @@ fn test_atomic_operation() {
} }
// We create a new tree // We create a new tree
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap()); let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@ -247,9 +241,7 @@ fn test_atomic_operation_zero_indexed() {
} }
// We create a new tree // We create a new tree
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap()); let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@ -293,9 +285,7 @@ fn test_atomic_operation_consistency() {
} }
// We create a new tree // We create a new tree
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap()); let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@ -348,9 +338,7 @@ fn test_set_leaves_bad_index() {
let bad_index = (1 << tree_height) - rng.gen_range(0..no_of_leaves) as usize; let bad_index = (1 << tree_height) - rng.gen_range(0..no_of_leaves) as usize;
// We create a new tree // We create a new tree
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // Get root of empty tree
let mut buffer = Cursor::new(Vec::<u8>::new()); let mut buffer = Cursor::new(Vec::<u8>::new());
@ -413,9 +401,7 @@ fn value_to_string_vec(value: &Value) -> Vec<String> {
fn test_groth16_proof_hardcoded() { fn test_groth16_proof_hardcoded() {
let tree_height = TEST_TREE_HEIGHT; let tree_height = TEST_TREE_HEIGHT;
let input_buffer = let rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let rln = RLN::new(tree_height, input_buffer).unwrap();
let valid_snarkjs_proof = json!({ let valid_snarkjs_proof = json!({
"pi_a": [ "pi_a": [
@ -495,9 +481,7 @@ fn test_groth16_proof_hardcoded() {
fn test_groth16_proof() { fn test_groth16_proof() {
let tree_height = TEST_TREE_HEIGHT; let tree_height = TEST_TREE_HEIGHT;
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // 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); let rln_witness = random_rln_witness(tree_height);
@ -543,9 +527,7 @@ fn test_rln_proof() {
} }
// We create a new RLN instance // We create a new RLN instance
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap()); let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@ -588,11 +570,11 @@ fn test_rln_proof() {
rln.generate_rln_proof(&mut input_buffer, &mut output_buffer) rln.generate_rln_proof(&mut input_buffer, &mut output_buffer)
.unwrap(); .unwrap();
// output_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ] // output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
let mut proof_data = output_buffer.into_inner(); let mut proof_data = output_buffer.into_inner();
// We prepare input for verify_rln_proof API // We prepare input for verify_rln_proof API
// input_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> | signal_len<8> | signal<var> ] // input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
// that is [ proof_data || signal_len<8> | signal<var> ] // that is [ proof_data || signal_len<8> | signal<var> ]
proof_data.append(&mut normalize_usize(signal.len())); proof_data.append(&mut normalize_usize(signal.len()));
proof_data.append(&mut signal.to_vec()); proof_data.append(&mut signal.to_vec());
@ -616,9 +598,7 @@ fn test_rln_with_witness() {
} }
// We create a new RLN instance // We create a new RLN instance
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap()); let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@ -693,11 +673,11 @@ fn test_rln_with_witness() {
) )
.unwrap(); .unwrap();
// output_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ] // output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
let mut proof_data = output_buffer.into_inner(); let mut proof_data = output_buffer.into_inner();
// We prepare input for verify_rln_proof API // We prepare input for verify_rln_proof API
// input_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> | signal_len<8> | signal<var> ] // input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
// that is [ proof_data || signal_len<8> | signal<var> ] // that is [ proof_data || signal_len<8> | signal<var> ]
proof_data.append(&mut normalize_usize(signal.len())); proof_data.append(&mut normalize_usize(signal.len()));
proof_data.append(&mut signal.to_vec()); proof_data.append(&mut signal.to_vec());
@ -722,9 +702,7 @@ fn proof_verification_with_roots() {
} }
// We create a new RLN instance // We create a new RLN instance
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap()); let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
@ -751,7 +729,7 @@ fn proof_verification_with_roots() {
let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]); let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
// We prepare input for generate_rln_proof API // We prepare input for generate_rln_proof API
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | rln_identifier<32> | user_message_limit<32> | message_id<32> | signal_len<8> | signal<var> ] // input_data is [ identity_secret<32> | id_index<8> | external_nullifier<32> | user_message_limit<32> | message_id<32> | signal_len<8> | signal<var> ]
let mut serialized: Vec<u8> = Vec::new(); let mut serialized: Vec<u8> = Vec::new();
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash)); serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
serialized.append(&mut normalize_usize(identity_index)); serialized.append(&mut normalize_usize(identity_index));
@ -766,11 +744,11 @@ fn proof_verification_with_roots() {
rln.generate_rln_proof(&mut input_buffer, &mut output_buffer) rln.generate_rln_proof(&mut input_buffer, &mut output_buffer)
.unwrap(); .unwrap();
// output_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ] // output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
let mut proof_data = output_buffer.into_inner(); let mut proof_data = output_buffer.into_inner();
// We prepare input for verify_rln_proof API // We prepare input for verify_rln_proof API
// input_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> | signal_len<8> | signal<var> ] // input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
// that is [ proof_data || signal_len<8> | signal<var> ] // that is [ proof_data || signal_len<8> | signal<var> ]
proof_data.append(&mut normalize_usize(signal.len())); proof_data.append(&mut normalize_usize(signal.len()));
proof_data.append(&mut signal.to_vec()); proof_data.append(&mut signal.to_vec());
@ -816,9 +794,7 @@ fn test_recover_id_secret() {
let tree_height = TEST_TREE_HEIGHT; let tree_height = TEST_TREE_HEIGHT;
// We create a new RLN instance // We create a new RLN instance
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// Generate identity pair // Generate identity pair
let (identity_secret_hash, id_commitment) = keygen(); let (identity_secret_hash, id_commitment) = keygen();
@ -953,9 +929,7 @@ fn test_get_leaf() {
// We generate a random tree // We generate a random tree
let tree_height = 10; let tree_height = 10;
let mut rng = thread_rng(); let mut rng = thread_rng();
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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 // We generate a random leaf
let leaf = Fr::rand(&mut rng); let leaf = Fr::rand(&mut rng);
@ -980,9 +954,7 @@ fn test_get_leaf() {
fn test_valid_metadata() { fn test_valid_metadata() {
let tree_height = TEST_TREE_HEIGHT; let tree_height = TEST_TREE_HEIGHT;
let input_buffer = let mut rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
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"; let arbitrary_metadata: &[u8] = b"block_number:200000";
rln.set_metadata(arbitrary_metadata).unwrap(); rln.set_metadata(arbitrary_metadata).unwrap();
@ -998,9 +970,7 @@ fn test_valid_metadata() {
fn test_empty_metadata() { fn test_empty_metadata() {
let tree_height = TEST_TREE_HEIGHT; let tree_height = TEST_TREE_HEIGHT;
let input_buffer = let rln = RLN::new(tree_height, generate_input_buffer()).unwrap();
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let rln = RLN::new(tree_height, input_buffer).unwrap();
let mut buffer = Cursor::new(Vec::<u8>::new()); let mut buffer = Cursor::new(Vec::<u8>::new());
rln.get_metadata(&mut buffer).unwrap(); rln.get_metadata(&mut buffer).unwrap();

View File

@ -5,6 +5,8 @@ use ark_ff::PrimeField;
use color_eyre::{Report, Result}; use color_eyre::{Report, Result};
use num_bigint::{BigInt, BigUint}; use num_bigint::{BigInt, BigUint};
use num_traits::Num; use num_traits::Num;
use serde_json::json;
use std::io::Cursor;
use std::iter::Extend; use std::iter::Extend;
pub fn to_bigint(el: &Fr) -> Result<BigInt> { pub fn to_bigint(el: &Fr) -> Result<BigInt> {
@ -179,6 +181,11 @@ pub fn normalize_usize(input: usize) -> Vec<u8> {
normalized_usize normalized_usize
} }
// using for test
pub fn generate_input_buffer() -> Cursor<String> {
Cursor::new(json!({}).to_string())
}
/* Old conversion utilities between different libraries data types /* Old conversion utilities between different libraries data types
// Conversion Utilities between poseidon-rs Field and arkworks Fr (in order to call directly poseidon-rs' poseidon_hash) // Conversion Utilities between poseidon-rs Field and arkworks Fr (in order to call directly poseidon-rs' poseidon_hash)

View File

@ -18,7 +18,7 @@ mod test {
fn create_rln_instance() -> &'static mut RLN<'static> { fn create_rln_instance() -> &'static mut RLN<'static> {
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit(); let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string(); let input_config = json!({}).to_string();
let input_buffer = &Buffer::from(input_config.as_bytes()); let input_buffer = &Buffer::from(input_config.as_bytes());
let success = new(TEST_TREE_HEIGHT, input_buffer, rln_pointer.as_mut_ptr()); let success = new(TEST_TREE_HEIGHT, input_buffer, rln_pointer.as_mut_ptr());
assert!(success, "RLN object creation failed"); assert!(success, "RLN object creation failed");
@ -509,11 +509,11 @@ mod test {
serialized.append(&mut signal.to_vec()); serialized.append(&mut signal.to_vec());
// We call generate_rln_proof // We call generate_rln_proof
// result_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ] // result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
let mut proof_data = rln_proof_gen(rln_pointer, serialized.as_ref()); let mut proof_data = rln_proof_gen(rln_pointer, serialized.as_ref());
// We prepare input for verify_rln_proof API // We prepare input for verify_rln_proof API
// input_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> | signal_len<8> | signal<var> ] // input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
// that is [ proof_data | signal_len<8> | signal<var> ] // that is [ proof_data | signal_len<8> | signal<var> ]
proof_data.append(&mut normalize_usize(signal.len())); proof_data.append(&mut normalize_usize(signal.len()));
proof_data.append(&mut signal.to_vec()); proof_data.append(&mut signal.to_vec());
@ -576,11 +576,11 @@ mod test {
serialized.append(&mut signal.to_vec()); serialized.append(&mut signal.to_vec());
// We call generate_rln_proof // We call generate_rln_proof
// result_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ] // result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
let mut proof_data = rln_proof_gen(rln_pointer, serialized.as_ref()); let mut proof_data = rln_proof_gen(rln_pointer, serialized.as_ref());
// We prepare input for verify_rln_proof API // We prepare input for verify_rln_proof API
// input_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> | signal_len<8> | signal<var> ] // input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
// that is [ proof_data | signal_len<8> | signal<var> ] // that is [ proof_data | signal_len<8> | signal<var> ]
proof_data.append(&mut normalize_usize(signal.len())); proof_data.append(&mut normalize_usize(signal.len()));
proof_data.append(&mut signal.to_vec()); proof_data.append(&mut signal.to_vec());
@ -688,11 +688,11 @@ mod test {
serialized2.append(&mut signal2.to_vec()); serialized2.append(&mut signal2.to_vec());
// We call generate_rln_proof for first proof values // We call generate_rln_proof for first proof values
// result_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ] // result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
let proof_data_1 = rln_proof_gen(rln_pointer, serialized1.as_ref()); let proof_data_1 = rln_proof_gen(rln_pointer, serialized1.as_ref());
// We call generate_rln_proof // We call generate_rln_proof
// result_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ] // result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
let proof_data_2 = rln_proof_gen(rln_pointer, serialized2.as_ref()); let proof_data_2 = rln_proof_gen(rln_pointer, serialized2.as_ref());
let input_proof_buffer_1 = &Buffer::from(proof_data_1.as_ref()); let input_proof_buffer_1 = &Buffer::from(proof_data_1.as_ref());
@ -746,7 +746,7 @@ mod test {
serialized.append(&mut signal3.to_vec()); serialized.append(&mut signal3.to_vec());
// We call generate_rln_proof // We call generate_rln_proof
// result_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ] // result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
let proof_data_3 = rln_proof_gen(rln_pointer, serialized.as_ref()); let proof_data_3 = rln_proof_gen(rln_pointer, serialized.as_ref());
// We attempt to recover the secret using share1 (coming from identity_secret_hash) and share3 (coming from identity_secret_hash_new) // We attempt to recover the secret using share1 (coming from identity_secret_hash) and share3 (coming from identity_secret_hash_new)

View File

@ -2,9 +2,7 @@
mod test { mod test {
use ark_ff::BigInt; use ark_ff::BigInt;
use rln::circuit::zkey_from_folder; use rln::circuit::zkey_from_folder;
use rln::circuit::{ use rln::circuit::{circom_from_folder, vk_from_folder, Fr, TEST_TREE_HEIGHT};
circom_from_folder, vk_from_folder, Fr, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT,
};
use rln::hashers::{hash_to_field, poseidon_hash}; use rln::hashers::{hash_to_field, poseidon_hash};
use rln::poseidon_tree::PoseidonTree; use rln::poseidon_tree::PoseidonTree;
use rln::protocol::*; use rln::protocol::*;
@ -146,9 +144,9 @@ mod test {
// We test a RLN proof generation and verification // We test a RLN proof generation and verification
fn test_witness_from_json() { fn test_witness_from_json() {
// We generate all relevant keys // We generate all relevant keys
let proving_key = zkey_from_folder(TEST_RESOURCES_FOLDER).unwrap(); let proving_key = zkey_from_folder().unwrap();
let verification_key = vk_from_folder(TEST_RESOURCES_FOLDER).unwrap(); let verification_key = vk_from_folder().unwrap();
let builder = circom_from_folder(TEST_RESOURCES_FOLDER).unwrap(); let builder = circom_from_folder().unwrap();
// We compute witness from the json input example // We compute witness from the json input example
let witness_json = WITNESS_JSON_20; let witness_json = WITNESS_JSON_20;
@ -205,9 +203,9 @@ mod test {
.unwrap(); .unwrap();
// We generate all relevant keys // We generate all relevant keys
let proving_key = zkey_from_folder(TEST_RESOURCES_FOLDER).unwrap(); let proving_key = zkey_from_folder().unwrap();
let verification_key = vk_from_folder(TEST_RESOURCES_FOLDER).unwrap(); let verification_key = vk_from_folder().unwrap();
let builder = circom_from_folder(TEST_RESOURCES_FOLDER).unwrap(); let builder = circom_from_folder().unwrap();
// Let's generate a zkSNARK proof // Let's generate a zkSNARK proof
let proof = generate_proof(builder, &proving_key, &rln_witness).unwrap(); let proof = generate_proof(builder, &proving_key, &rln_witness).unwrap();

View File

@ -3,12 +3,11 @@ mod test {
use ark_ff::BigInt; use ark_ff::BigInt;
use ark_std::{rand::thread_rng, UniformRand}; use ark_std::{rand::thread_rng, UniformRand};
use rand::Rng; use rand::Rng;
use rln::circuit::{Fr, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT}; use rln::circuit::{Fr, TEST_TREE_HEIGHT};
use rln::hashers::{hash_to_field, poseidon_hash as utils_poseidon_hash, ROUND_PARAMS}; 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::protocol::{compute_tree_root, deserialize_identity_tuple};
use rln::public::{hash as public_hash, poseidon_hash as public_poseidon_hash, RLN}; use rln::public::{hash as public_hash, poseidon_hash as public_poseidon_hash, RLN};
use rln::utils::*; use rln::utils::*;
use serde_json::json;
use std::io::Cursor; use std::io::Cursor;
#[test] #[test]
@ -17,9 +16,7 @@ mod test {
let leaf_index = 3; let leaf_index = 3;
let user_message_limit = 1; let user_message_limit = 1;
let input_buffer = let mut rln = RLN::new(TEST_TREE_HEIGHT, generate_input_buffer()).unwrap();
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(TEST_TREE_HEIGHT, input_buffer).unwrap();
// generate identity // generate identity
let identity_secret_hash = hash_to_field(b"test-merkle-proof"); let identity_secret_hash = hash_to_field(b"test-merkle-proof");