| Crates.io | rln |
| lib.rs | rln |
| version | 1.0.0 |
| created_at | 2023-07-28 10:42:56.038383+00 |
| updated_at | 2025-12-19 08:59:16.416224+00 |
| description | APIs to manage, compute and verify zkSNARK proofs and RLN primitives |
| homepage | https://vac.dev |
| repository | https://github.com/vacp2p/zerokit |
| max_upload_size | |
| id | 928418 |
| size | 6,509,534 |
The Zerokit RLN Module provides a Rust implementation for working with Rate-Limiting Nullifier RLN zkSNARK proofs and primitives. This module allows you to:
[!IMPORTANT] Version 0.7.0 is the only version that does not support WASM and x32 architecture. WASM support is available in version 0.8.0 and above.
We start by adding zerokit RLN to our Cargo.toml
[dependencies]
rln = "1.0.0"
The RLN object constructor requires the following files:
rln_final.arkzkey: The proving key in arkzkey format.graph.bin: The graph file built for the input tree sizeAdditionally, rln.wasm is used for testing in the rln-wasm module.
use rln::prelude::{keygen, poseidon_hash, hash_to_field_le, RLN, RLNWitnessInput, Fr, IdSecret};
fn main() {
// 1. Initialize RLN with parameters:
// - the tree depth;
// - the tree config, if it is not defined, the default value will be set
let tree_depth = 20;
let mut rln = RLN::new(tree_depth, "").unwrap();
// 2. Generate an identity keypair
let (identity_secret, id_commitment) = keygen();
// 3. Add a rate commitment to the Merkle tree
let leaf_index = 10;
let user_message_limit = Fr::from(10);
let rate_commitment = poseidon_hash(&[id_commitment, user_message_limit]);
rln.set_leaf(leaf_index, rate_commitment).unwrap();
// 4. Get the Merkle proof for the added commitment
let (path_elements, identity_path_index) = rln.get_merkle_proof(leaf_index).unwrap();
// 5. Set up external nullifier (epoch + app identifier)
// We generate epoch from a date seed and we ensure is
// mapped to a field element by hashing-to-field its content
let epoch = hash_to_field_le(b"Today at noon, this year");
// We generate rln_identifier from an application identifier and
// we ensure is mapped to a field element by hashing-to-field its content
let rln_identifier = hash_to_field_le(b"test-rln-identifier");
// We generate a external nullifier
let external_nullifier = poseidon_hash(&[epoch, rln_identifier]);
// We choose a message_id satisfy 0 <= message_id < user_message_limit
let message_id = Fr::from(1);
// 6. Define the message signal
let signal = b"RLN is awesome";
// 7. Compute x from the signal
let x = hash_to_field_le(signal);
// 8. Create witness input for RLN proof generation
let witness = RLNWitnessInput::new(
identity_secret,
user_message_limit,
message_id,
path_elements,
identity_path_index,
x,
external_nullifier,
)
.unwrap();
// 9. Generate a RLN proof
// We generate proof and proof values from the witness
let (proof, proof_values) = rln.generate_rln_proof(&witness).unwrap();
// 10. Verify the RLN proof
// We verify the proof using the proof and proof values and the hashed signal x
let verified = rln.verify_rln_proof(&proof, &proof_values, &x).unwrap();
assert!(verified);
}
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.
fullmerkletree feature).optimalmerkletree feature).pmtree-ft feature).git clone https://github.com/vacp2p/zerokit.git
make installdeps
cd zerokit/rln
# Build with default features
cargo make build
# Test with default features
cargo make test
# Test with stateless features
cargo make test_stateless
The circom-rln (https://github.com/rate-limiting-nullifier/circom-rln) repository,
which contains the RLN circuit implementation used for pre-compiled RLN circuit for zerokit RLN.
If you want to compile your own RLN circuit, you can follow the instructions below.
This script actually generates not only the zkey file for the RLN circuit,
but also the execution wasm file used for witness calculation.
However, the wasm file is not needed for the rln module,
because current implementation uses the iden3 graph file for witness calculation.
This graph file is generated by the circom-witnesscalc tool in step 2.
To customize the circuit parameters, modify circom-rln/circuits/rln.circom:
pragma circom 2.1.0;
include "./rln.circom";
component main { public [x, externalNullifier] } = RLN(N, M);
Where:
N: Merkle tree depth, determining the maximum membership capacity (2^N members).
M: Bit size for range checks, setting an upper bound for the number of messages per epoch (2^M messages).
[!NOTE] However, if
Nis too big, this might require a larger Powers of Tau ceremony than the one hardcoded in./scripts/build-circuits.sh, which is2^14. In such case, we refer to the official Circom documentation for instructions on how to run an appropriate Powers of Tau ceremony and Phase 2 in order to compile the desired circuit.
Additionally, whileMsets an upper bound on the number of messages per epoch (2^M), you can configure lower message limit for your use case, as long as it satisfiesuser_message_limit ≤ 2^M.
Currently, therlnmodule comes with a pre-compiled RLN circuit with a Merkle tree of depth20and a bit size of16, allowing up to2^20registered members and a2^16message limit per epoch.
You can follow the instructions below or refer to the
installing Circom guide for more details.
Make sure to use the specific version v2.1.0.
# Clone the circom repository
git clone https://github.com/iden3/circom.git
# Checkout the specific version
cd circom && git checkout v2.1.0
# Build the circom compiler
cargo build --release
# Install the circom binary globally
cargo install --path circom
# Check the circom version to ensure it's v2.1.0
circom --version
# Clone the circom-rln repository
git clone https://github.com/rate-limiting-nullifier/circom-rln
# Install dependencies
cd circom-rln && npm install
# Build circuits
./scripts/build-circuits.sh rln
# Use the generated zkey file in subsequent steps
cp zkeyFiles/rln/final.zkey <path_to_rln_final.zkey>
The execution graph file used for witness calculation can be compiled following instructions
in the circom-witnesscalc repository.
As mentioned in step 1, we should use rln.circom file from circom-rln repository.
# Clone the circom-witnesscalc repository
git clone https://github.com/iden3/circom-witnesscalc
# Load the submodules
cd circom-witnesscalc && git submodule update --init --recursive
# Build the circom-witnesscalc tool
cargo build
# Generate the witness calculation graph
cargo run --package circom_witnesscalc --bin build-circuit ../circom-rln/circuits/rln.circom <path_to_graph.bin>
The rln module comes with pre-compiled
execution graph files for the RLN circuit.
For faster loading, compile the zkey file into the arkzkey format using ark-zkey. This is fork of the original repository with the uncompressed arkzkey support.
# Clone the ark-zkey repository
git clone https://github.com/seemenkina/ark-zkey.git
# Build the ark-zkey tool
cd ark-zkey && cargo build
# Generate the arkzkey representation for the zkey file
cargo run --bin arkzkey-util <path_to_rln_final.zkey>
This will generate the rln_final.arkzkey file, which is used by the rln module.
Currently, the rln module comes with
pre-compiled arkzkey keys for the RLN circuit.
[!NOTE] You can use this convert_zkey.sh script to automate the process of generating the arkzkey file from any zkey file
Run the script as follows:
chmod +x ./convert_zkey.sh
./convert_zkey.sh <path_to_rln_final.zkey>
RLN provides C-compatible bindings for integration with C, C++, Nim, and other languages through safer_ffi.
The FFI layer is organized into several modules:
ffi_rln.rs – Implements core RLN functionality, including initialization functions, proof generation, and proof verification.ffi_tree.rs – Provides all tree-related operations and helper functions for Merkle tree management.ffi_utils.rs – Contains all utility functions and structure definitions used across the FFI layer.Working examples demonstrating proof generation, proof verification and slashing in C and Nim:
_free functions.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
cargo doc --no-deps
and look at unit tests to have an hint on how to interface and use them.