2022-08-07 14:51:03 +00:00
# Zerokit RLN Module
2022-03-11 09:55:46 +00:00
2022-08-07 14:51:03 +00:00
This module provides APIs to manage, compute and verify [RLN ](https://rfc.vac.dev/spec/32/ ) zkSNARK proofs and RLN primitives.
2022-03-11 09:55:46 +00:00
2022-11-25 09:54:17 +00:00
## Pre-requisites
2024-05-10 11:13:00 +00:00
2023-02-24 06:20:51 +00:00
### Install dependencies and clone repo
2022-03-11 09:55:46 +00:00
2022-11-25 09:54:17 +00:00
```sh
2023-02-24 06:20:51 +00:00
make installdeps
2022-11-25 09:54:17 +00:00
git clone https://github.com/vacp2p/zerokit.git
cd zerokit/rln
```
2022-03-11 09:55:46 +00:00
2023-02-24 06:20:51 +00:00
### Build and Test
To build and test, run the following commands within the module folder
2024-05-10 11:13:00 +00:00
2023-02-24 06:20:51 +00:00
```bash
cargo make build
cargo make test
```
2022-05-24 11:14:02 +00:00
2022-11-25 09:54:17 +00:00
### Compile ZK circuits
2024-05-10 11:13:00 +00:00
The `rln` (https://github.com/rate-limiting-nullifier/circom-rln) repository, which contains the RLN circuit implementation is a submodule of zerokit RLN.
2022-05-24 11:14:02 +00:00
2022-11-25 09:54:17 +00:00
To compile the RLN circuit
2022-05-24 11:14:02 +00:00
2024-05-10 11:13:00 +00:00
```sh
2022-05-24 11:14:02 +00:00
# Update submodules
git submodule update --init --recursive
# Install rln dependencies
cd vendor/rln/ & & npm install
# Build circuits
./scripts/build-circuits.sh rln
# Copy over assets
2022-08-07 14:51:03 +00:00
cp build/zkeyFiles/rln-final.zkey ../../resources/tree_height_15
cp build/zkeyFiles/rln.wasm ../../resources/tree_height_15
```
2022-11-25 09:54:17 +00:00
Note that the above code snippet will compile a RLN circuit with a Merkle tree of height equal `15` based on the default value set in `vendor/rln/circuit/rln.circom` .
2022-08-07 14:51:03 +00:00
2022-11-25 09:54:17 +00:00
In order to compile a RLN circuit with Merkle tree height `N` , it suffices to change `vendor/rln/circuit/rln.circom` to
2022-08-07 14:51:03 +00:00
2022-05-24 11:14:02 +00:00
```
2022-08-07 14:51:03 +00:00
pragma circom 2.0.0;
include "./rln-base.circom";
component main {public [x, epoch, rln_identifier ]} = RLN(N);
```
2024-05-10 11:13:00 +00:00
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` .
2022-11-25 09:54:17 +00:00
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.
2023-10-03 15:58:21 +00:00
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.
2022-11-25 09:54:17 +00:00
## Getting started
### Add RLN as dependency
We start by adding zerokit RLN to our `Cargo.toml`
```toml
[dependencies]
rln = { git = "https://github.com/vacp2p/zerokit" }
```
### Create a RLN object
First, we need to create a RLN object for a chosen input Merkle tree size.
2024-06-14 05:33:55 +00:00
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.arkvkey`, optional) are found.
2022-11-25 09:54:17 +00:00
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.
```rust
use rln::protocol::*;
use rln::public::*;
use std::io::Cursor;
2024-05-10 11:13:00 +00:00
// We set the RLN parameters:
2022-11-25 09:54:17 +00:00
// - the tree height;
2024-05-10 11:13:00 +00:00
// - the tree config, if it is not defined, the default value will be set
2022-11-25 09:54:17 +00:00
let tree_height = 20;
2024-05-10 11:13:00 +00:00
let input = Cursor::new(json!({}).to_string());
2022-11-25 09:54:17 +00:00
// We create a new RLN instance
2024-05-10 11:13:00 +00:00
let mut rln = RLN::new(tree_height, input);
2022-11-25 09:54:17 +00:00
```
### Generate an identity keypair
We generate an identity keypair
```rust
// We generate an identity pair
let mut buffer = Cursor::new(Vec::< u8 > ::new());
rln.key_gen(& mut buffer).unwrap();
// We deserialize the keygen output to obtain
2023-10-03 15:58:21 +00:00
// the identity_secret and id_commitment
2022-12-11 23:48:22 +00:00
let (identity_secret_hash, id_commitment) = deserialize_identity_pair(buffer.into_inner());
2022-11-25 09:54:17 +00:00
```
2023-10-03 15:58:21 +00:00
### Add Rate commitment to the RLN Merkle tree
2022-11-25 09:54:17 +00:00
```rust
// We define the tree index where id_commitment will be added
let id_index = 10;
2023-10-03 15:58:21 +00:00
let user_message_limit = 10;
2022-11-25 09:54:17 +00:00
// We serialize id_commitment and pass it to set_leaf
2023-10-03 15:58:21 +00:00
let rate_commitment = poseidon_hash(& [id_commitment, user_message_limit]);
let mut buffer = Cursor::new(serialize_field_element(rate_commitment));
2022-11-25 09:54:17 +00:00
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).
2024-05-10 11:13:00 +00:00
### Set external nullifier
2022-11-25 09:54:17 +00:00
2024-05-10 11:13:00 +00:00
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.
2022-11-25 09:54:17 +00:00
```rust
// 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(b"Today at noon, this year");
2024-05-10 11:13:00 +00:00
// 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]);
2022-11-25 09:54:17 +00:00
```
2024-05-10 11:13:00 +00:00
2022-11-25 09:54:17 +00:00
### Set signal
The signal is the message for which we are computing a RLN proof.
```rust
2024-05-10 11:13:00 +00:00
// We set our signal
2022-11-25 09:54:17 +00:00
let signal = b"RLN is awesome";
```
### Generate a RLN proof
2024-05-10 11:13:00 +00:00
We prepare the input to the proof generation routine.
2022-11-25 09:54:17 +00:00
2024-05-10 11:13:00 +00:00
Input buffer is serialized as `[ identity_key | id_index | external_nullifier | user_message_limit | message_id | signal_len | signal ]` .
2022-11-25 09:54:17 +00:00
```rust
// We prepare input to the proof generation routine
2024-05-10 11:13:00 +00:00
let proof_input = prepare_prove_input(identity_secret_hash, id_index, external_nullifier, signal);
2022-11-25 09:54:17 +00:00
```
We are now ready to generate a RLN ZK proof along with the _public outputs_ of the ZK circuit evaluation.
```rust
// We generate a RLN proof for proof_input
let mut in_buffer = Cursor::new(proof_input);
let mut out_buffer = Cursor::new(Vec::< u8 > ::new());
rln.generate_rln_proof(& mut in_buffer, & mut out_buffer)
.unwrap();
// We get the public outputs returned by the circuit evaluation
let proof_data = out_buffer.into_inner();
```
2024-05-10 11:13:00 +00:00
The byte vector `proof_data` is serialized as `[ zk-proof | tree_root | external_nullifier | share_x | share_y | nullifier ]` .
2022-11-25 09:54:17 +00:00
### Verify a RLN proof
2024-05-10 11:13:00 +00:00
We prepare the input to the proof verification routine.
2022-11-25 09:54:17 +00:00
Input buffer is serialized as `[proof_data | signal_len | signal ]` , where `proof_data` is (computed as) the output obtained by `generate_rln_proof` .
```rust
// We prepare input to the proof verification routine
let verify_data = prepare_verify_input(proof_data, signal);
// We verify the zk-proof against the provided proof values
let mut in_buffer = Cursor::new(verify_data);
let verified = rln.verify(& mut in_buffer).unwrap();
```
2024-05-10 11:13:00 +00:00
We check if the proof verification was successful:
2022-11-25 09:54:17 +00:00
```rust
// We ensure the proof is valid
assert!(verified);
```
## Get involved!
2024-05-10 11:13:00 +00:00
2022-11-25 09:54:17 +00:00
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
2024-05-10 11:13:00 +00:00
2022-11-25 09:54:17 +00:00
```rust
cargo doc --no-deps
```
2024-05-10 11:13:00 +00:00
and look at unit tests to have an hint on how to interface and use them.