mirror of https://github.com/vacp2p/zerokit.git
feat(rln): add example usage tutorial and expand documentation for RLN (WIP) (#74)
* feat(rln): expand documentation with minimal public API usage example * refactor(rln): ease RLN interaction with new APIs * feat(rln): expand API docs * fix(rln): disable doctest for rln
This commit is contained in:
parent
3427729f7e
commit
284e51483c
|
@ -6,6 +6,9 @@ edition = "2021"
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "rlib", "staticlib"]
|
crate-type = ["cdylib", "rlib", "staticlib"]
|
||||||
|
|
||||||
|
# This flag disable cargo doctests, i.e. testing example code-snippets in documentation
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
|
157
rln/README.md
157
rln/README.md
|
@ -2,15 +2,22 @@
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
Currently, this module comes with three [pre-compiled](https://github.com/vacp2p/zerokit/tree/master/rln/resources) RLN circuits having Merkle tree of height `15`, `19` and `20`, respectively.
|
## Pre-requisites
|
||||||
|
### Install
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/vacp2p/zerokit.git
|
||||||
|
cd zerokit/rln
|
||||||
|
```
|
||||||
Implemented tests can be executed by running within the module folder
|
Implemented tests can be executed by running within the module folder
|
||||||
|
|
||||||
`cargo test --release`
|
`cargo test --release`
|
||||||
|
|
||||||
## Compiling circuits
|
### Compile ZK circuits
|
||||||
|
|
||||||
`rln` (https://github.com/privacy-scaling-explorations/rln) repo with Circuits is contained as a submodule.
|
The `rln` (https://github.com/privacy-scaling-explorations/rln) repository, which contains the RLN circuit implementation is a submodule of zerokit RLN.
|
||||||
|
|
||||||
|
To compile the RLN circuit
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
# Update submodules
|
# Update submodules
|
||||||
|
@ -27,9 +34,9 @@ cp build/zkeyFiles/rln-final.zkey ../../resources/tree_height_15
|
||||||
cp build/zkeyFiles/rln.wasm ../../resources/tree_height_15
|
cp build/zkeyFiles/rln.wasm ../../resources/tree_height_15
|
||||||
```
|
```
|
||||||
|
|
||||||
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 `rln/circuit/rln.circom`.
|
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`.
|
||||||
|
|
||||||
To compile a RLN circuit with Merkle tree height `N`, it suffices to change `rln/circuit/rln.circom` to
|
In order to compile a RLN circuit with Merkle tree height `N`, it suffices to change `vendor/rln/circuit/rln.circom` to
|
||||||
|
|
||||||
```
|
```
|
||||||
pragma circom 2.0.0;
|
pragma circom 2.0.0;
|
||||||
|
@ -41,3 +48,143 @@ 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 three [pre-compiled](https://github.com/vacp2p/zerokit/tree/master/rln/resources) RLN circuits having Merkle tree of height `15`, `19` and `20`, respectively.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// We set the RLN parameters:
|
||||||
|
// - the tree height;
|
||||||
|
// - the circuit resource folder (requires a trailing "/").
|
||||||
|
let tree_height = 20;
|
||||||
|
let resources = Cursor::new("../zerokit/rln/resources/tree_height_20/");
|
||||||
|
|
||||||
|
// We create a new RLN instance
|
||||||
|
let mut rln = RLN::new(tree_height, resources);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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
|
||||||
|
// the identiy_secret and id_commitment
|
||||||
|
let (identity_secret, id_commitment) = deserialize_identity_pair(buffer.into_inner());
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add ID commitment to the RLN Merkle tree
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// We define the tree index where id_commitment will be added
|
||||||
|
let id_index = 10;
|
||||||
|
|
||||||
|
// We serialize id_commitment and pass it to set_leaf
|
||||||
|
let mut buffer = Cursor::new(serialize_field_element(id_commitment));
|
||||||
|
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).
|
||||||
|
|
||||||
|
### Set epoch
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
```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");
|
||||||
|
```
|
||||||
|
### Set signal
|
||||||
|
|
||||||
|
The signal is the message for which we are computing a RLN proof.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// We set our signal
|
||||||
|
let signal = b"RLN is awesome";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate a RLN proof
|
||||||
|
|
||||||
|
We prepare the input to the proof generation routine.
|
||||||
|
|
||||||
|
Input buffer is serialized as `[ identity_key | id_index | epoch | signal_len | signal ]`.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// We prepare input to the proof generation routine
|
||||||
|
let proof_input = prepare_prove_input(identity_secret, id_index, epoch, signal);
|
||||||
|
```
|
||||||
|
|
||||||
|
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();
|
||||||
|
```
|
||||||
|
|
||||||
|
The byte vector `proof_data` is serialized as `[ zk-proof | tree_root | epoch | share_x | share_y | nullifier | rln_identifier ]`.
|
||||||
|
|
||||||
|
|
||||||
|
### Verify a RLN proof
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|
```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();
|
||||||
|
```
|
||||||
|
|
||||||
|
We check if the proof verification was successful:
|
||||||
|
```rust
|
||||||
|
// We ensure the proof is valid
|
||||||
|
assert!(verified);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get involved!
|
||||||
|
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
|
||||||
|
```rust
|
||||||
|
cargo doc --no-deps
|
||||||
|
```
|
||||||
|
and look at unit tests to have an hint on how to interface and use them.
|
|
@ -5,9 +5,9 @@ use std::slice;
|
||||||
use crate::public::RLN;
|
use crate::public::RLN;
|
||||||
|
|
||||||
/// Buffer struct is taken from
|
/// Buffer struct is taken from
|
||||||
/// https://github.com/celo-org/celo-threshold-bls-rs/blob/master/crates/threshold-bls-ffi/src/ffi.rs
|
/// <https://github.com/celo-org/celo-threshold-bls-rs/blob/master/crates/threshold-bls-ffi/src/ffi.rs>
|
||||||
///
|
///
|
||||||
/// Also heavily inspired by https://github.com/kilic/rln/blob/master/src/ffi.rs
|
/// Also heavily inspired by <https://github.com/kilic/rln/blob/master/src/ffi.rs>
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
|
|
@ -24,11 +24,16 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Application specific RLN identifier
|
/// The application-specific RLN identifier.
|
||||||
|
///
|
||||||
|
/// Prevents a RLN ZK proof generated for one application to be re-used in another one.
|
||||||
pub const RLN_IDENTIFIER: &[u8] = b"zerokit/rln/010203040506070809";
|
pub const RLN_IDENTIFIER: &[u8] = b"zerokit/rln/010203040506070809";
|
||||||
|
|
||||||
// TODO Add Engine here? i.e. <E: Engine> not <Curve>
|
/// The RLN object.
|
||||||
// TODO Assuming we want to use IncrementalMerkleTree, figure out type/trait conversions
|
///
|
||||||
|
/// It implements the methods required to update the internal Merkle Tree, generate and verify RLN ZK proofs.
|
||||||
|
///
|
||||||
|
/// I/O is mostly done using writers and readers implementing `std::io::Write` and `std::io::Read`, respectively.
|
||||||
pub struct RLN<'a> {
|
pub struct RLN<'a> {
|
||||||
proving_key: Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)>,
|
proving_key: Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)>,
|
||||||
verification_key: Result<VerifyingKey<Curve>>,
|
verification_key: Result<VerifyingKey<Curve>>,
|
||||||
|
@ -44,6 +49,22 @@ pub struct RLN<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RLN<'_> {
|
impl RLN<'_> {
|
||||||
|
/// Creates a new RLN object by loading circuit resources from a folder.
|
||||||
|
///
|
||||||
|
/// Input parameters are
|
||||||
|
/// - `tree_height`: the height of the internal Merkle tree
|
||||||
|
/// - `input_data`: a reader for the string path of the resource folder containing the ZK circuit (`rln.wasm`), the proving key (`rln_final.zkey`) and the verification key (`verification_key.json`).
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```
|
||||||
|
/// use std::io::Cursor;
|
||||||
|
///
|
||||||
|
/// let tree_height = 20;
|
||||||
|
/// let resources = Cursor::new("./resources/tree_height_20/");
|
||||||
|
///
|
||||||
|
/// // We create a new RLN instance
|
||||||
|
/// let mut rln = RLN::new(tree_height, resources);
|
||||||
|
/// ```
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn new<R: Read>(tree_height: usize, mut input_data: R) -> RLN<'static> {
|
pub fn new<R: Read>(tree_height: usize, mut input_data: R) -> RLN<'static> {
|
||||||
// We read input
|
// We read input
|
||||||
|
@ -70,6 +91,39 @@ impl RLN<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new RLN object by passing circuit resources as byte vectors.
|
||||||
|
///
|
||||||
|
/// Input parameters are
|
||||||
|
/// - `tree_height`: the height of the internal Merkle tree
|
||||||
|
/// - `circom_vec`: a byte vector containing the ZK circuit (`rln.wasm`) as binary file
|
||||||
|
/// - `zkey_vec`: a byte vector containing to the proving key (`rln_final.zkey`) as binary file
|
||||||
|
/// - `vk_vec`: a byte vector containing to the verification key (`verification_key.json`) as binary file
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```
|
||||||
|
/// use std::fs::File;
|
||||||
|
/// use std::io::Read;
|
||||||
|
///
|
||||||
|
/// let tree_height = 20;
|
||||||
|
/// let resources_folder = "./resources/tree_height_20/";
|
||||||
|
///
|
||||||
|
/// let mut resources: Vec<Vec<u8>> = Vec::new();
|
||||||
|
/// for filename in ["rln.wasm", "rln_final.zkey", "verification_key.json"] {
|
||||||
|
/// let fullpath = format!("{resources_folder}{filename}");
|
||||||
|
/// let mut file = File::open(&fullpath).expect("no file found");
|
||||||
|
/// let metadata = std::fs::metadata(&fullpath).expect("unable to read metadata");
|
||||||
|
/// let mut buffer = vec![0; metadata.len() as usize];
|
||||||
|
/// file.read_exact(&mut buffer).expect("buffer overflow");
|
||||||
|
/// resources.push(buffer);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let mut rln = RLN::new_with_params(
|
||||||
|
/// tree_height,
|
||||||
|
/// resources[0].clone(),
|
||||||
|
/// resources[1].clone(),
|
||||||
|
/// resources[2].clone(),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
pub fn new_with_params(
|
pub fn new_with_params(
|
||||||
tree_height: usize,
|
tree_height: usize,
|
||||||
#[cfg(not(target_arch = "wasm32"))] circom_vec: Vec<u8>,
|
#[cfg(not(target_arch = "wasm32"))] circom_vec: Vec<u8>,
|
||||||
|
@ -99,6 +153,12 @@ impl RLN<'_> {
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
// Merkle-tree APIs
|
// Merkle-tree APIs
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
/// Initializes the internal Merkle tree.
|
||||||
|
///
|
||||||
|
/// Leaves are set to the default value implemented in PoseidonTree implementation.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `tree_height`: the height of the Merkle tree.
|
||||||
pub fn set_tree(&mut self, tree_height: usize) -> io::Result<()> {
|
pub fn set_tree(&mut self, tree_height: usize) -> io::Result<()> {
|
||||||
// We compute a default empty tree of desired height
|
// We compute a default empty tree of desired height
|
||||||
self.tree = PoseidonTree::default(tree_height);
|
self.tree = PoseidonTree::default(tree_height);
|
||||||
|
@ -106,6 +166,26 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets a leaf value at position index in the internal Merkle tree.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `index`: the index of the leaf
|
||||||
|
/// - `input_data`: a reader for the serialization of the leaf value (serialization done with [`rln::utils::fr_to_bytes_le`](crate::utils::fr_to_bytes_le))
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```
|
||||||
|
/// use crate::protocol::*;
|
||||||
|
///
|
||||||
|
/// // We generate a random id secret and commitment pair
|
||||||
|
/// let (identity_secret, id_commitment) = keygen();
|
||||||
|
///
|
||||||
|
/// // We define the tree index where id_commitment will be added
|
||||||
|
/// let id_index = 10;
|
||||||
|
///
|
||||||
|
/// // We serialize id_commitment and pass it to set_leaf
|
||||||
|
/// let mut buffer = Cursor::new(serialize_field_element(id_commitment));
|
||||||
|
/// rln.set_leaf(id_index, &mut buffer).unwrap();
|
||||||
|
/// ```
|
||||||
pub fn set_leaf<R: Read>(&mut self, index: usize, mut input_data: R) -> io::Result<()> {
|
pub fn set_leaf<R: Read>(&mut self, index: usize, mut input_data: R) -> io::Result<()> {
|
||||||
// We read input
|
// We read input
|
||||||
let mut leaf_byte: Vec<u8> = Vec::new();
|
let mut leaf_byte: Vec<u8> = Vec::new();
|
||||||
|
@ -118,6 +198,36 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets multiple leaves starting from position index in the internal Merkle tree.
|
||||||
|
///
|
||||||
|
/// If n leaves are passed as input, these will be set at positions `index`, `index+1`, ..., `index+n-1` respectively.
|
||||||
|
///
|
||||||
|
/// This function updates the internal Merkle tree `next_index value indicating the next available index corresponding to a never-set leaf as `next_index = max(next_index, index + n)`.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `index`: the index of the first leaf to be set
|
||||||
|
/// - `input_data`: a reader for the serialization of multiple leaf values (serialization done with [`rln::utils::vec_fr_to_bytes_le`](crate::utils::vec_fr_to_bytes_le))
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```
|
||||||
|
/// use rln::circuit::Fr;
|
||||||
|
/// use rln::utils::*;
|
||||||
|
///
|
||||||
|
/// let start_index = 10;
|
||||||
|
/// let no_of_leaves = 256;
|
||||||
|
///
|
||||||
|
/// // We generate a vector of random leaves
|
||||||
|
/// let mut leaves: Vec<Fr> = Vec::new();
|
||||||
|
/// let mut rng = thread_rng();
|
||||||
|
/// for _ in 0..no_of_leaves {
|
||||||
|
/// let (_, id_commitment) = keygen();
|
||||||
|
/// leaves.push(id_commitment);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // We add leaves in a batch into the tree
|
||||||
|
/// let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves));
|
||||||
|
/// rln.set_leaves_from(index, &mut buffer).unwrap();
|
||||||
|
/// ```
|
||||||
pub fn set_leaves_from<R: Read>(&mut self, index: usize, mut input_data: R) -> io::Result<()> {
|
pub fn set_leaves_from<R: Read>(&mut self, index: usize, mut input_data: R) -> io::Result<()> {
|
||||||
// We read input
|
// We read input
|
||||||
let mut leaves_byte: Vec<u8> = Vec::new();
|
let mut leaves_byte: Vec<u8> = Vec::new();
|
||||||
|
@ -129,6 +239,12 @@ impl RLN<'_> {
|
||||||
return self.tree.set_range(index, leaves);
|
return self.tree.set_range(index, leaves);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resets the tree state to default and sets multiple leaves starting from index 0.
|
||||||
|
///
|
||||||
|
/// In contrast to [`set_leaves_from`](crate::public::RLN::set_leaves_from), this function resets to 0 the internal `next_index` value, before setting the input leaves values.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `input_data`: a reader for the serialization of multiple leaf values (serialization done with [`rln::utils::vec_fr_to_bytes_le`](crate::utils::vec_fr_to_bytes_le))
|
||||||
pub fn init_tree_with_leaves<R: Read>(&mut self, input_data: R) -> io::Result<()> {
|
pub fn init_tree_with_leaves<R: Read>(&mut self, input_data: R) -> io::Result<()> {
|
||||||
// reset the tree
|
// reset the tree
|
||||||
// NOTE: this requires the tree to be initialized with the correct height initially
|
// NOTE: this requires the tree to be initialized with the correct height initially
|
||||||
|
@ -137,7 +253,47 @@ impl RLN<'_> {
|
||||||
return self.set_leaves_from(0, input_data);
|
return self.set_leaves_from(0, input_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set input leaf to the next available index
|
/// Sets a leaf value at the next available never-set leaf index.
|
||||||
|
///
|
||||||
|
/// This function updates the internal Merkle tree `next_index` value indicating the next available index corresponding to a never-set leaf as `next_index = next_index + 1`.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `input_data`: a reader for the serialization of multiple leaf values (serialization done with [`rln::utils::vec_fr_to_bytes_le`](crate::utils::vec_fr_to_bytes_le))
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```
|
||||||
|
/// use rln::circuit::Fr;
|
||||||
|
/// use rln::utils::*;
|
||||||
|
///
|
||||||
|
/// let tree_height = 20;
|
||||||
|
/// let start_index = 10;
|
||||||
|
/// let no_of_leaves = 256;
|
||||||
|
///
|
||||||
|
/// // We reset the tree
|
||||||
|
/// rln.set_tree(tree_height).unwrap();
|
||||||
|
///
|
||||||
|
/// // Internal Merkle tree next_index value is now 0
|
||||||
|
///
|
||||||
|
/// // We generate a vector of random leaves
|
||||||
|
/// let mut leaves: Vec<Fr> = Vec::new();
|
||||||
|
/// let mut rng = thread_rng();
|
||||||
|
/// for _ in 0..no_of_leaves {
|
||||||
|
/// let (_, id_commitment) = keygen();
|
||||||
|
/// leaves.push(id_commitment);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // We add leaves in a batch into the tree
|
||||||
|
/// let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves));
|
||||||
|
/// rln.set_leaves_from(index, &mut buffer).unwrap();
|
||||||
|
///
|
||||||
|
/// // We set 256 leaves starting from index 10: next_index value is now max(0, 256+10) = 266
|
||||||
|
///
|
||||||
|
/// // We set a leaf on next available index
|
||||||
|
/// // id_commitment will be set at index 266
|
||||||
|
/// let (_, id_commitment) = keygen();
|
||||||
|
/// let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment));
|
||||||
|
/// rln.set_next_leaf(&mut buffer).unwrap();
|
||||||
|
/// ```
|
||||||
pub fn set_next_leaf<R: Read>(&mut self, mut input_data: R) -> io::Result<()> {
|
pub fn set_next_leaf<R: Read>(&mut self, mut input_data: R) -> io::Result<()> {
|
||||||
// We read input
|
// We read input
|
||||||
let mut leaf_byte: Vec<u8> = Vec::new();
|
let mut leaf_byte: Vec<u8> = Vec::new();
|
||||||
|
@ -150,14 +306,37 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deleting a leaf corresponds to set its value to the default 0 leaf
|
/// Sets the value of the leaf at position index to the harcoded default value.
|
||||||
|
///
|
||||||
|
/// This function does not change the internal Merkle tree `next_index` value.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `index`: the index of the leaf whose value will be reset
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// let index = 10;
|
||||||
|
/// rln.delete_leaf(index).unwrap();
|
||||||
|
/// ```
|
||||||
pub fn delete_leaf(&mut self, index: usize) -> io::Result<()> {
|
pub fn delete_leaf(&mut self, index: usize) -> io::Result<()> {
|
||||||
self.tree.delete(index)?;
|
self.tree.delete(index)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns current membership root
|
/// Returns the Merkle tree root
|
||||||
/// * `root` is a scalar field element in 32 bytes
|
///
|
||||||
|
/// Output values are:
|
||||||
|
/// - `output_data`: a writer receiving the serialization of the root value (serialization done with [`rln::utils::fr_to_bytes_le`](crate::utils::fr_to_bytes_le))
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```
|
||||||
|
/// use rln::utils::*;
|
||||||
|
///
|
||||||
|
/// let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
/// rln.get_root(&mut buffer).unwrap();
|
||||||
|
/// let (root, _) = bytes_le_to_fr(&buffer.into_inner());
|
||||||
|
/// ```
|
||||||
pub fn get_root<W: Write>(&self, mut output_data: W) -> io::Result<()> {
|
pub fn get_root<W: Write>(&self, mut output_data: W) -> io::Result<()> {
|
||||||
let root = self.tree.root();
|
let root = self.tree.root();
|
||||||
output_data.write_all(&fr_to_bytes_le(&root))?;
|
output_data.write_all(&fr_to_bytes_le(&root))?;
|
||||||
|
@ -165,8 +344,27 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns current membership root
|
/// Returns the Merkle proof of the leaf at position index
|
||||||
/// * `root` is a scalar field element in 32 bytes
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `index`: the index of the leaf
|
||||||
|
///
|
||||||
|
/// Output values are:
|
||||||
|
/// - `output_data`: a writer receiving the serialization of the path elements and path indexes (serialization done with [`rln::utils::vec_fr_to_bytes_le`](crate::utils::vec_fr_to_bytes_le) and [`rln::utils::vec_u8_to_bytes_le`](crate::utils::vec_u8_to_bytes_le), respectively)
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```
|
||||||
|
/// use rln::utils::*;
|
||||||
|
///
|
||||||
|
/// let index = 10;
|
||||||
|
///
|
||||||
|
/// let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
/// rln.get_proof(index, &mut buffer).unwrap();
|
||||||
|
///
|
||||||
|
/// let buffer_inner = buffer.into_inner();
|
||||||
|
/// let (path_elements, read) = bytes_le_to_vec_fr(&buffer_inner);
|
||||||
|
/// let (identity_path_index, _) = bytes_le_to_vec_u8(&buffer_inner[read..].to_vec());
|
||||||
|
/// ```
|
||||||
pub fn get_proof<W: Write>(&self, index: usize, mut output_data: W) -> io::Result<()> {
|
pub fn get_proof<W: Write>(&self, index: usize, mut output_data: W) -> io::Result<()> {
|
||||||
let merkle_proof = self.tree.proof(index).expect("proof should exist");
|
let merkle_proof = self.tree.proof(index).expect("proof should exist");
|
||||||
let path_elements = merkle_proof.get_path_elements();
|
let path_elements = merkle_proof.get_path_elements();
|
||||||
|
@ -181,6 +379,27 @@ impl RLN<'_> {
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
// zkSNARK APIs
|
// zkSNARK APIs
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
/// Computes a zkSNARK RLN proof using a [`RLNWitnessInput`](crate::protocol::RLNWitnessInput).
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `input_data`: a reader for the serialization of a [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) object, containing the public and private inputs to the ZK circuits (serialization done using [`rln::protocol::serialize_witness`](crate::protocol::serialize_witness))
|
||||||
|
///
|
||||||
|
/// Output values are:
|
||||||
|
/// - `output_data`: a writer receiving the serialization of the zkSNARK proof
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```
|
||||||
|
/// use rln::protocol::*;
|
||||||
|
///
|
||||||
|
/// let rln_witness = random_rln_witness(tree_height);
|
||||||
|
/// let proof_values = proof_values_from_witness(&rln_witness);
|
||||||
|
///
|
||||||
|
/// // We compute a Groth16 proof
|
||||||
|
/// let mut input_buffer = Cursor::new(serialize_witness(&rln_witness));
|
||||||
|
/// let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
/// rln.prove(&mut input_buffer, &mut output_buffer).unwrap();
|
||||||
|
/// let zk_proof = output_buffer.into_inner();
|
||||||
|
/// ```
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn prove<R: Read, W: Write>(
|
pub fn prove<R: Read, W: Write>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -211,6 +430,41 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verifies a zkSNARK RLN proof.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `input_data`: a reader for the serialization of the RLN zkSNARK proof concatenated with a serialization of the circuit output values, i.e. `[ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]`, where <_> indicates the byte length.
|
||||||
|
///
|
||||||
|
/// The function returns true if the zkSNARK proof is valid with respect to the provided circuit output values, false otherwise.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```
|
||||||
|
/// use rln::protocol::*;
|
||||||
|
///
|
||||||
|
/// let rln_witness = random_rln_witness(tree_height);
|
||||||
|
///
|
||||||
|
/// // We compute a Groth16 proof
|
||||||
|
/// let mut input_buffer = Cursor::new(serialize_witness(&rln_witness));
|
||||||
|
/// let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
/// rln.prove(&mut input_buffer, &mut output_buffer).unwrap();
|
||||||
|
/// let zk_proof = output_buffer.into_inner();
|
||||||
|
///
|
||||||
|
/// // We prepare the input to prove API, consisting of zk_proof (compressed, 4*32 bytes) || proof_values (6*32 bytes)
|
||||||
|
/// // In this example, we compute proof values directly from witness using the utility proof_values_from_witness
|
||||||
|
/// let proof_values = proof_values_from_witness(&rln_witness);
|
||||||
|
/// let serialized_proof_values = serialize_proof_values(&proof_values);
|
||||||
|
///
|
||||||
|
/// // We build the input to the verify method
|
||||||
|
/// let mut verify_data = Vec::<u8>::new();
|
||||||
|
/// verify_data.extend(&zk_proof);
|
||||||
|
/// verify_data.extend(&proof_values);
|
||||||
|
/// let mut input_buffer = Cursor::new(verify_data);
|
||||||
|
///
|
||||||
|
/// // We verify the Groth16 proof against the provided zk-proof and proof values
|
||||||
|
/// let verified = rln.verify(&mut input_buffer).unwrap();
|
||||||
|
///
|
||||||
|
/// assert!(verified);
|
||||||
|
/// ```
|
||||||
pub fn verify<R: Read>(&self, mut input_data: R) -> io::Result<bool> {
|
pub fn verify<R: Read>(&self, mut input_data: R) -> io::Result<bool> {
|
||||||
// Input data is serialized for Curve as:
|
// Input data is serialized for Curve as:
|
||||||
// serialized_proof (compressed, 4*32 bytes) || serialized_proof_values (6*32 bytes), i.e.
|
// serialized_proof (compressed, 4*32 bytes) || serialized_proof_values (6*32 bytes), i.e.
|
||||||
|
@ -231,28 +485,52 @@ impl RLN<'_> {
|
||||||
Ok(verified)
|
Ok(verified)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the serialized rln_witness for some input
|
/// Computes a zkSNARK RLN proof from the identity secret, the Merkle tree index, the epoch and signal.
|
||||||
pub fn get_serialized_rln_witness<R: Read>(&mut self, mut input_data: R) -> Vec<u8> {
|
///
|
||||||
// We read input RLN witness and we deserialize it
|
/// Input values are:
|
||||||
let mut witness_byte: Vec<u8> = Vec::new();
|
/// - `input_data`: a reader for the serialization of `[ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]`
|
||||||
input_data.read_to_end(&mut witness_byte).unwrap();
|
///
|
||||||
let (rln_witness, _) = proof_inputs_to_rln_witness(&mut self.tree, &witness_byte);
|
/// Output values are:
|
||||||
|
/// - `output_data`: a writer receiving the serialization of the zkSNARK proof and the circuit evaluations outputs, i.e. `[ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]`
|
||||||
serialize_witness(&rln_witness)
|
///
|
||||||
}
|
/// Example
|
||||||
|
/// ```
|
||||||
/// Get JSON inputs for serialized RLN witness
|
/// use rln::protocol::*:
|
||||||
pub fn get_rln_witness_json(
|
/// use rln::utils::*;
|
||||||
&mut self,
|
///
|
||||||
serialized_witness: &[u8],
|
/// // Generate identity pair
|
||||||
) -> io::Result<serde_json::Value> {
|
/// let (identity_secret, id_commitment) = keygen();
|
||||||
let (rln_witness, _) = deserialize_witness(serialized_witness);
|
///
|
||||||
Ok(get_json_inputs(&rln_witness))
|
/// // We set as leaf id_commitment after storing its index
|
||||||
}
|
/// let identity_index = 10;
|
||||||
|
/// let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment));
|
||||||
// This API keeps partial compatibility with kilic's rln public API https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L148
|
/// rln.set_leaf(identity_index, &mut buffer).unwrap();
|
||||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
///
|
||||||
// output_data is [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]
|
/// // We generate a random signal
|
||||||
|
/// let mut rng = rand::thread_rng();
|
||||||
|
/// let signal: [u8; 32] = rng.gen();
|
||||||
|
/// let signal_len = u64::try_from(signal.len()).unwrap();
|
||||||
|
///
|
||||||
|
/// // We generate a random epoch
|
||||||
|
/// let epoch = hash_to_field(b"test-epoch");
|
||||||
|
///
|
||||||
|
/// // We prepare input for generate_rln_proof API
|
||||||
|
/// // input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||||
|
/// let mut serialized: Vec<u8> = Vec::new();
|
||||||
|
/// serialized.append(&mut fr_to_bytes_le(&identity_secret));
|
||||||
|
/// serialized.append(&mut identity_index.to_le_bytes().to_vec());
|
||||||
|
/// serialized.append(&mut fr_to_bytes_le(&epoch));
|
||||||
|
/// serialized.append(&mut signal_len.to_le_bytes().to_vec());
|
||||||
|
/// serialized.append(&mut signal.to_vec());
|
||||||
|
///
|
||||||
|
/// let mut input_buffer = Cursor::new(serialized);
|
||||||
|
/// let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
/// rln.generate_rln_proof(&mut input_buffer, &mut output_buffer)
|
||||||
|
/// .unwrap();
|
||||||
|
///
|
||||||
|
/// // proof_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ]
|
||||||
|
/// let mut proof_data = output_buffer.into_inner();
|
||||||
|
/// ```
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn generate_rln_proof<R: Read, W: Write>(
|
pub fn generate_rln_proof<R: Read, W: Write>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -280,9 +558,12 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate RLN Proof using a witness calculated from outside zerokit
|
// 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
|
||||||
/// output_data is [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]
|
//
|
||||||
|
// output_data is [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]
|
||||||
|
// we skip it from documentation for now
|
||||||
|
#[doc(hidden)]
|
||||||
pub fn generate_rln_proof_with_witness<W: Write>(
|
pub fn generate_rln_proof_with_witness<W: Write>(
|
||||||
&mut self,
|
&mut self,
|
||||||
calculated_witness: Vec<BigInt>,
|
calculated_witness: Vec<BigInt>,
|
||||||
|
@ -303,9 +584,33 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input data is serialized for Curve as:
|
/// Verifies a zkSNARK RLN proof against the provided proof values and the state of the internal Merkle tree.
|
||||||
// [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
|
///
|
||||||
// Note that in contrast to verify, this function takes as input the signal and further verifies: the tree root, the X coordinate, the RLN identifier
|
/// Input values are:
|
||||||
|
/// - `input_data`: a reader for the serialization of the RLN zkSNARK proof concatenated with a serialization of the circuit output values and the signal information, i.e. `[ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ]`
|
||||||
|
///
|
||||||
|
/// The function returns true if the zkSNARK proof is valid with respect to the provided circuit output values and signal. Returns false otherwise.
|
||||||
|
///
|
||||||
|
/// Note that contrary to [`verify`](crate::public::RLN::verify), this function takes additionaly as input the signal and further verifies if
|
||||||
|
/// - the Merkle tree root corresponds to the root provided as input;
|
||||||
|
/// - the input signal corresponds to the Shamir's x coordinate provided as input
|
||||||
|
/// - the hardcoded application [RLN identifier](crate::public::RLN_IDENTIFIER) corresponds to the RLN identifier provided as input
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```
|
||||||
|
/// // proof_data is computed as in the example code snippet provided for rln::public::RLN::generate_rln_proof
|
||||||
|
///
|
||||||
|
/// // 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> ]
|
||||||
|
/// // that is [ proof_data || signal_len<8> | signal<var> ]
|
||||||
|
/// proof_data.append(&mut signal_len.to_le_bytes().to_vec());
|
||||||
|
/// proof_data.append(&mut signal.to_vec());
|
||||||
|
///
|
||||||
|
/// let mut input_buffer = Cursor::new(proof_data);
|
||||||
|
/// let verified = rln.verify_rln_proof(&mut input_buffer).unwrap();
|
||||||
|
///
|
||||||
|
/// assert!(verified);
|
||||||
|
/// ```
|
||||||
pub fn verify_rln_proof<R: Read>(&self, mut input_data: R) -> io::Result<bool> {
|
pub fn verify_rln_proof<R: Read>(&self, mut input_data: R) -> io::Result<bool> {
|
||||||
let mut serialized: Vec<u8> = Vec::new();
|
let mut serialized: Vec<u8> = Vec::new();
|
||||||
input_data.read_to_end(&mut serialized)?;
|
input_data.read_to_end(&mut serialized)?;
|
||||||
|
@ -336,10 +641,57 @@ impl RLN<'_> {
|
||||||
&& (proof_values.rln_identifier == hash_to_field(RLN_IDENTIFIER)))
|
&& (proof_values.rln_identifier == hash_to_field(RLN_IDENTIFIER)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function verifies a proof against a sequence of input valid roots to allow external validation of the tree state.
|
/// Verifies a zkSNARK RLN proof against the provided proof values and a set of allowed Merkle tree roots.
|
||||||
// Input data is serialized for Curve as:
|
///
|
||||||
// [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
|
/// Input values are:
|
||||||
// roots_data is serialized as (arbitrary long, even empty) sequence of Fr elements serialized in little endian (32 bytes each for Bn254)
|
/// - `input_data`: a reader for the serialization of the RLN zkSNARK proof concatenated with a serialization of the circuit output values and the signal information, i.e. `[ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ]`
|
||||||
|
/// - `roots_data`: a reader for the serialization of a vector of roots, i.e. `[ number_of_roots<8> | root_1<32> | ... | root_n<32> ]` (number_of_roots is a uint64 in little-endian, roots are serialized using `rln::utils::fr_to_bytes_le`))
|
||||||
|
///
|
||||||
|
/// The function returns true if the zkSNARK proof is valid with respect to the provided circuit output values, signal and roots. Returns false otherwise.
|
||||||
|
///
|
||||||
|
/// Note that contrary to [`verify_rln_proof`](crate::public::RLN::verify_rln_proof), this function does not check if the internal Merkle tree root corresponds to the root provided as input, but rather checks if the root provided as input in `input_data` corresponds to one of the roots serialized in `roots_data`.
|
||||||
|
///
|
||||||
|
/// If `roots_data` contains no root (is empty), root validation is skipped and the proof will be correctly verified only if the other proof values results valid (i.e., zk-proof, signal, x-coordinate, RLN identifier)
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```
|
||||||
|
/// // proof_data is computed as in the example code snippet provided for rln::public::RLN::generate_rln_proof
|
||||||
|
///
|
||||||
|
/// // If no roots is provided, proof validation is skipped and if the remaining proof values are valid, the proof will be correctly verified
|
||||||
|
/// let mut input_buffer = Cursor::new(proof_data);
|
||||||
|
/// let mut roots_serialized: Vec<u8> = Vec::new();
|
||||||
|
/// let mut roots_buffer = Cursor::new(roots_serialized.clone());
|
||||||
|
/// let verified = rln
|
||||||
|
/// .verify_with_roots(&mut input_buffer.clone(), &mut roots_buffer)
|
||||||
|
/// .unwrap();
|
||||||
|
///
|
||||||
|
/// assert!(verified);
|
||||||
|
///
|
||||||
|
/// // We serialize in the roots buffer some random values and we check that the proof is not verified since doesn't contain the correct root the proof refers to
|
||||||
|
/// for _ in 0..5 {
|
||||||
|
/// roots_serialized.append(&mut fr_to_bytes_le(&Fr::rand(&mut rng)));
|
||||||
|
/// }
|
||||||
|
/// roots_buffer = Cursor::new(roots_serialized.clone());
|
||||||
|
/// let verified = rln
|
||||||
|
/// .verify_with_roots(&mut input_buffer.clone(), &mut roots_buffer)
|
||||||
|
/// .unwrap();
|
||||||
|
///
|
||||||
|
/// assert!(verified == false);
|
||||||
|
///
|
||||||
|
/// // We get the root of the tree obtained adding one leaf per time
|
||||||
|
/// let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
/// rln.get_root(&mut buffer).unwrap();
|
||||||
|
/// let (root, _) = bytes_le_to_fr(&buffer.into_inner());
|
||||||
|
///
|
||||||
|
/// // We add the real root and we check if now the proof is verified
|
||||||
|
/// roots_serialized.append(&mut fr_to_bytes_le(&root));
|
||||||
|
/// roots_buffer = Cursor::new(roots_serialized.clone());
|
||||||
|
/// let verified = rln
|
||||||
|
/// .verify_with_roots(&mut input_buffer.clone(), &mut roots_buffer)
|
||||||
|
/// .unwrap();
|
||||||
|
///
|
||||||
|
/// assert!(verified);
|
||||||
|
/// ```
|
||||||
pub fn verify_with_roots<R: Read>(
|
pub fn verify_with_roots<R: Read>(
|
||||||
&self,
|
&self,
|
||||||
mut input_data: R,
|
mut input_data: R,
|
||||||
|
@ -413,6 +765,24 @@ impl RLN<'_> {
|
||||||
// Utils
|
// Utils
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Returns an identity secret and identity commitment pair.
|
||||||
|
///
|
||||||
|
/// The identity commitment is the Poseidon hash of the identity secret.
|
||||||
|
///
|
||||||
|
/// Output values are:
|
||||||
|
/// - `output_data`: a writer receiving the serialization of the identity secret and identity commitment (serialization done with `rln::utils::fr_to_bytes_le`)
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```
|
||||||
|
/// use rln::protocol::*;
|
||||||
|
///
|
||||||
|
/// // We generate an identity pair
|
||||||
|
/// let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
/// rln.key_gen(&mut buffer).unwrap();
|
||||||
|
///
|
||||||
|
/// // We deserialize the keygen output
|
||||||
|
/// let (identity_secret, id_commitment) = deserialize_identity_pair(buffer.into_inner());
|
||||||
|
/// ```
|
||||||
pub fn key_gen<W: Write>(&self, mut output_data: W) -> io::Result<()> {
|
pub fn key_gen<W: Write>(&self, mut output_data: W) -> io::Result<()> {
|
||||||
let (id_key, id_commitment_key) = keygen();
|
let (id_key, id_commitment_key) = keygen();
|
||||||
output_data.write_all(&fr_to_bytes_le(&id_key))?;
|
output_data.write_all(&fr_to_bytes_le(&id_key))?;
|
||||||
|
@ -421,6 +791,30 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an identity secret and identity commitment pair generated using a seed.
|
||||||
|
///
|
||||||
|
/// The identity commitment is the Poseidon hash of the identity secret.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `input_data`: a reader for the byte vector containing the seed
|
||||||
|
///
|
||||||
|
/// Output values are:
|
||||||
|
/// - `output_data`: a writer receiving the serialization of the identity secret and identity commitment (serialization done with [`rln::utils::fr_to_bytes_le`](crate::utils::fr_to_bytes_le))
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```
|
||||||
|
/// use rln::protocol::*;
|
||||||
|
///
|
||||||
|
/// let seed_bytes: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
///
|
||||||
|
/// let mut input_buffer = Cursor::new(&seed_bytes);
|
||||||
|
/// let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
/// rln.seeded_key_gen(&mut input_buffer, &mut output_buffer)
|
||||||
|
/// .unwrap();
|
||||||
|
///
|
||||||
|
/// // We deserialize the keygen output
|
||||||
|
/// let (identity_secret, id_commitment) = deserialize_identity_pair(output_buffer.into_inner());
|
||||||
|
/// ```
|
||||||
pub fn seeded_key_gen<R: Read, W: Write>(
|
pub fn seeded_key_gen<R: Read, W: Write>(
|
||||||
&self,
|
&self,
|
||||||
mut input_data: R,
|
mut input_data: R,
|
||||||
|
@ -436,6 +830,28 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hashes an input signal to an element in the working prime field.
|
||||||
|
///
|
||||||
|
/// The result is computed as the Keccak256 of the input signal modulo the prime field characteristic.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `input_data`: a reader for the byte vector containing the input signal.
|
||||||
|
///
|
||||||
|
/// Output values are:
|
||||||
|
/// - `output_data`: a writer receiving the serialization of the resulting field element (serialization done with [`rln::utils::fr_to_bytes_le`](crate::utils::fr_to_bytes_le))
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```
|
||||||
|
/// let signal: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
///
|
||||||
|
/// let mut input_buffer = Cursor::new(&signal);
|
||||||
|
/// let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
/// rln.hash(&mut input_buffer, &mut output_buffer)
|
||||||
|
/// .unwrap();
|
||||||
|
///
|
||||||
|
/// // We deserialize the keygen output
|
||||||
|
/// let field_element = deserialize_field_element(output_buffer.into_inner());
|
||||||
|
/// ```
|
||||||
pub fn hash<R: Read, W: Write>(&self, mut input_data: R, mut output_data: W) -> io::Result<()> {
|
pub fn hash<R: Read, W: Write>(&self, mut input_data: R, mut output_data: W) -> io::Result<()> {
|
||||||
let mut serialized: Vec<u8> = Vec::new();
|
let mut serialized: Vec<u8> = Vec::new();
|
||||||
input_data.read_to_end(&mut serialized)?;
|
input_data.read_to_end(&mut serialized)?;
|
||||||
|
@ -445,6 +861,35 @@ impl RLN<'_> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the serialization of a [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) populated from the identity secret, the Merkle tree index, the epoch and signal.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `input_data`: a reader for the serialization of `[ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]`
|
||||||
|
///
|
||||||
|
/// The function returns the corresponding [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) object serialized using [`rln::protocol::serialize_witness`](crate::protocol::serialize_witness)).
|
||||||
|
pub fn get_serialized_rln_witness<R: Read>(&mut self, mut input_data: R) -> Vec<u8> {
|
||||||
|
// We read input RLN witness and we deserialize it
|
||||||
|
let mut witness_byte: Vec<u8> = Vec::new();
|
||||||
|
input_data.read_to_end(&mut witness_byte).unwrap();
|
||||||
|
let (rln_witness, _) = proof_inputs_to_rln_witness(&mut self.tree, &witness_byte);
|
||||||
|
|
||||||
|
serialize_witness(&rln_witness)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a byte serialization of a [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) object to the corresponding JSON serialization.
|
||||||
|
///
|
||||||
|
/// Input values are:
|
||||||
|
/// - `serialized_witness`: the byte serialization of a [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) object (serialization done with [`rln::protocol::serialize_witness`](crate::protocol::serialize_witness)).
|
||||||
|
///
|
||||||
|
/// The function returns the corresponding JSON encoding of the input [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) object.
|
||||||
|
pub fn get_rln_witness_json(
|
||||||
|
&mut self,
|
||||||
|
serialized_witness: &[u8],
|
||||||
|
) -> io::Result<serde_json::Value> {
|
||||||
|
let (rln_witness, _) = deserialize_witness(serialized_witness);
|
||||||
|
Ok(get_json_inputs(&rln_witness))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
|
Loading…
Reference in New Issue