mirror of https://github.com/vacp2p/zerokit.git
feat(rln): ability to set leaves from a given index (#63)
* feat(rln): ability to set leaves from a given index
* style(rln): fmt
* fix(rln): bubble the error
* revert: "fix(rln): bubble the error"
This reverts commit 40265082ba
.
* fix(rln): replace ark::std::Zero with default
* fix(rln): ordering of ffi api
* fix(rln): use PoseidonHash::default_leaf
* chore(rln): add ffi test for batching
* docs(rln): add entry to changelog
* fix(rln): address reviews
* fix(changelog): fmt
* fix(rln): safe conversion
* fix(rln): reset tree with init func, add comments
* chore(rln): add comment about init_tree_with_leaves
* fix(rln): comment
This commit is contained in:
parent
afa4a09bba
commit
490206aa44
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -1,8 +1,24 @@
|
||||||
|
## Upcoming release
|
||||||
|
|
||||||
|
Release highlights:
|
||||||
|
- Allows consumers of zerokit RLN to set leaves to the Merkle Tree from an arbitrary index. Useful for batching updates to the Merkle Tree.
|
||||||
|
|
||||||
|
The full list of changes is below.
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Creation of `set_leaves_from`, which allows consumers to add leaves to a tree from a given starting index. `init_tree_with_leaves` internally uses `set_leaves_from`, with index 0.
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Renaming of `set_leaves` to `init_tree_with_leaves`, which is a more accurate representation of the function's utility.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- None
|
||||||
|
|
||||||
## 2022-09-19 v0.1
|
## 2022-09-19 v0.1
|
||||||
|
|
||||||
Initial beta release.
|
Initial beta release.
|
||||||
|
|
||||||
This release contain:
|
This release contains:
|
||||||
|
|
||||||
- RLN Module with API to manage, compute and verify [RLN](https://rfc.vac.dev/spec/32/) zkSNARK proofs and RLN primitives.
|
- RLN Module with API to manage, compute and verify [RLN](https://rfc.vac.dev/spec/32/) zkSNARK proofs and RLN primitives.
|
||||||
- This can be consumed either as a Rust API or as a C FFI. The latter means it can be easily consumed through other environments, such as [Go](https://github.com/status-im/go-zerokit-rln/blob/master/rln/librln.h) or [Nim](https://github.com/status-im/nwaku/blob/4745c7872c69b5fd5c6ddab36df9c5c3d55f57c3/waku/v2/protocol/waku_rln_relay/waku_rln_relay_types.nim).
|
- This can be consumed either as a Rust API or as a C FFI. The latter means it can be easily consumed through other environments, such as [Go](https://github.com/status-im/go-zerokit-rln/blob/master/rln/librln.h) or [Nim](https://github.com/status-im/nwaku/blob/4745c7872c69b5fd5c6ddab36df9c5c3d55f57c3/waku/v2/protocol/waku_rln_relay/waku_rln_relay_types.nim).
|
||||||
|
|
111
rln/src/ffi.rs
111
rln/src/ffi.rs
|
@ -104,10 +104,22 @@ pub extern "C" fn set_next_leaf(ctx: *mut RLN, input_buffer: *const Buffer) -> b
|
||||||
|
|
||||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn set_leaves(ctx: *mut RLN, input_buffer: *const Buffer) -> bool {
|
pub extern "C" fn set_leaves_from(
|
||||||
|
ctx: *mut RLN,
|
||||||
|
index: usize,
|
||||||
|
input_buffer: *const Buffer,
|
||||||
|
) -> bool {
|
||||||
let rln = unsafe { &mut *ctx };
|
let rln = unsafe { &mut *ctx };
|
||||||
let input_data = <&[u8]>::from(unsafe { &*input_buffer });
|
let input_data = <&[u8]>::from(unsafe { &*input_buffer });
|
||||||
rln.set_leaves(input_data).is_ok()
|
rln.set_leaves_from(index, input_data).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn init_tree_with_leaves(ctx: *mut RLN, input_buffer: *const Buffer) -> bool {
|
||||||
|
let rln = unsafe { &mut *ctx };
|
||||||
|
let input_data = <&[u8]>::from(unsafe { &*input_buffer });
|
||||||
|
rln.init_tree_with_leaves(input_data).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
@ -387,7 +399,7 @@ mod test {
|
||||||
// We add leaves in a batch into the tree
|
// We add leaves in a batch into the tree
|
||||||
let leaves_ser = vec_fr_to_bytes_le(&leaves);
|
let leaves_ser = vec_fr_to_bytes_le(&leaves);
|
||||||
let input_buffer = &Buffer::from(leaves_ser.as_ref());
|
let input_buffer = &Buffer::from(leaves_ser.as_ref());
|
||||||
let success = set_leaves(rln_pointer, input_buffer);
|
let success = init_tree_with_leaves(rln_pointer, input_buffer);
|
||||||
assert!(success, "set leaves call failed");
|
assert!(success, "set leaves call failed");
|
||||||
|
|
||||||
// We get the root of the tree obtained adding leaves in batch
|
// We get the root of the tree obtained adding leaves in batch
|
||||||
|
@ -433,6 +445,95 @@ mod test {
|
||||||
assert_eq!(root_delete, root_empty);
|
assert_eq!(root_delete, root_empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// This test is similar to the one in public.rs but it uses the RLN object as a pointer
|
||||||
|
// Uses `set_leaves_from` to set leaves in a batch
|
||||||
|
fn test_leaf_setting_with_index_ffi() {
|
||||||
|
// We create a new tree
|
||||||
|
let tree_height = TEST_TREE_HEIGHT;
|
||||||
|
let no_of_leaves = 256;
|
||||||
|
|
||||||
|
// We create a RLN instance
|
||||||
|
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
|
||||||
|
let input_buffer = &Buffer::from(TEST_RESOURCES_FOLDER.as_bytes());
|
||||||
|
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
|
||||||
|
assert!(success, "RLN object creation failed");
|
||||||
|
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
leaves.push(Fr::rand(&mut rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_index is the index from which we start setting leaves
|
||||||
|
// random number between 0..no_of_leaves
|
||||||
|
let set_index = rng.gen_range(0..no_of_leaves) as usize;
|
||||||
|
|
||||||
|
// We add leaves in a batch into the tree
|
||||||
|
let leaves_ser = vec_fr_to_bytes_le(&leaves);
|
||||||
|
let input_buffer = &Buffer::from(leaves_ser.as_ref());
|
||||||
|
let success = init_tree_with_leaves(rln_pointer, input_buffer);
|
||||||
|
assert!(success, "init tree with leaves call failed");
|
||||||
|
|
||||||
|
// We get the root of the tree obtained adding leaves in batch
|
||||||
|
let mut output_buffer = MaybeUninit::<Buffer>::uninit();
|
||||||
|
let success = get_root(rln_pointer, output_buffer.as_mut_ptr());
|
||||||
|
assert!(success, "get root call failed");
|
||||||
|
|
||||||
|
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||||
|
let result_data = <&[u8]>::from(&output_buffer).to_vec();
|
||||||
|
let (root_batch_with_init, _) = bytes_le_to_fr(&result_data);
|
||||||
|
|
||||||
|
// `init_tree_with_leaves` resets the tree to the height it was initialized with, using `set_tree`
|
||||||
|
|
||||||
|
// We add leaves in a batch starting from index 0..set_index
|
||||||
|
let leaves_m = vec_fr_to_bytes_le(&leaves[0..set_index]);
|
||||||
|
let buffer = &Buffer::from(leaves_m.as_ref());
|
||||||
|
let success = init_tree_with_leaves(rln_pointer, buffer);
|
||||||
|
assert!(success, "init tree with leaves call failed");
|
||||||
|
|
||||||
|
// We add the remaining n leaves in a batch starting from index set_index
|
||||||
|
let leaves_n = vec_fr_to_bytes_le(&leaves[set_index..]);
|
||||||
|
let buffer = &Buffer::from(leaves_n.as_ref());
|
||||||
|
let success = set_leaves_from(rln_pointer, set_index, buffer);
|
||||||
|
assert!(success, "set leaves from call failed");
|
||||||
|
|
||||||
|
// We get the root of the tree obtained adding leaves in batch
|
||||||
|
let mut output_buffer = MaybeUninit::<Buffer>::uninit();
|
||||||
|
let success = get_root(rln_pointer, output_buffer.as_mut_ptr());
|
||||||
|
assert!(success, "get root call failed");
|
||||||
|
|
||||||
|
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||||
|
let result_data = <&[u8]>::from(&output_buffer).to_vec();
|
||||||
|
let (root_batch_with_custom_index, _) = bytes_le_to_fr(&result_data);
|
||||||
|
|
||||||
|
assert_eq!(root_batch_with_init, root_batch_with_custom_index);
|
||||||
|
|
||||||
|
// We reset the tree to default
|
||||||
|
let success = set_tree(rln_pointer, tree_height);
|
||||||
|
assert!(success, "set tree call failed");
|
||||||
|
|
||||||
|
// We add leaves one by one using the internal index (new leaves goes in next available position)
|
||||||
|
for leaf in &leaves {
|
||||||
|
let leaf_ser = fr_to_bytes_le(&leaf);
|
||||||
|
let input_buffer = &Buffer::from(leaf_ser.as_ref());
|
||||||
|
let success = set_next_leaf(rln_pointer, input_buffer);
|
||||||
|
assert!(success, "set next leaf call failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// We get the root of the tree obtained adding leaves using the internal index
|
||||||
|
let mut output_buffer = MaybeUninit::<Buffer>::uninit();
|
||||||
|
let success = get_root(rln_pointer, output_buffer.as_mut_ptr());
|
||||||
|
assert!(success, "get root call failed");
|
||||||
|
|
||||||
|
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||||
|
let result_data = <&[u8]>::from(&output_buffer).to_vec();
|
||||||
|
let (root_single_additions, _) = bytes_le_to_fr(&result_data);
|
||||||
|
|
||||||
|
assert_eq!(root_batch_with_init, root_single_additions);
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
// This test is similar to the one in lib, but uses only public C API
|
// This test is similar to the one in lib, but uses only public C API
|
||||||
fn test_merkle_proof_ffi() {
|
fn test_merkle_proof_ffi() {
|
||||||
|
@ -739,7 +840,7 @@ mod test {
|
||||||
// We add leaves in a batch into the tree
|
// We add leaves in a batch into the tree
|
||||||
let leaves_ser = vec_fr_to_bytes_le(&leaves);
|
let leaves_ser = vec_fr_to_bytes_le(&leaves);
|
||||||
let input_buffer = &Buffer::from(leaves_ser.as_ref());
|
let input_buffer = &Buffer::from(leaves_ser.as_ref());
|
||||||
let success = set_leaves(rln_pointer, input_buffer);
|
let success = init_tree_with_leaves(rln_pointer, input_buffer);
|
||||||
assert!(success, "set leaves call failed");
|
assert!(success, "set leaves call failed");
|
||||||
|
|
||||||
// We generate a new identity pair
|
// We generate a new identity pair
|
||||||
|
@ -824,7 +925,7 @@ mod test {
|
||||||
// We add leaves in a batch into the tree
|
// We add leaves in a batch into the tree
|
||||||
let leaves_ser = vec_fr_to_bytes_le(&leaves);
|
let leaves_ser = vec_fr_to_bytes_le(&leaves);
|
||||||
let input_buffer = &Buffer::from(leaves_ser.as_ref());
|
let input_buffer = &Buffer::from(leaves_ser.as_ref());
|
||||||
let success = set_leaves(rln_pointer, input_buffer);
|
let success = init_tree_with_leaves(rln_pointer, input_buffer);
|
||||||
assert!(success, "set leaves call failed");
|
assert!(success, "set leaves call failed");
|
||||||
|
|
||||||
// We generate a new identity pair
|
// We generate a new identity pair
|
||||||
|
|
|
@ -118,8 +118,7 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: change to set_leaves_from(index, input_data)
|
pub fn set_leaves_from<R: Read>(&mut self, index: usize, mut input_data: R) -> io::Result<()> {
|
||||||
pub fn set_leaves<R: Read>(&mut self, 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();
|
||||||
input_data.read_to_end(&mut leaves_byte)?;
|
input_data.read_to_end(&mut leaves_byte)?;
|
||||||
|
@ -128,12 +127,20 @@ impl RLN<'_> {
|
||||||
|
|
||||||
// We set the leaves
|
// We set the leaves
|
||||||
for (i, leaf) in leaves.iter().enumerate() {
|
for (i, leaf) in leaves.iter().enumerate() {
|
||||||
self.tree.set(i, *leaf)?;
|
self.tree.set(i + index, *leaf)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init_tree_with_leaves<R: Read>(&mut self, input_data: R) -> io::Result<()> {
|
||||||
|
// reset the tree
|
||||||
|
// NOTE: this requires the tree to be initialized with the correct height initially
|
||||||
|
// TODO: accept tree_height as a parameter and initialize the tree with that height
|
||||||
|
self.set_tree(self.tree.depth())?;
|
||||||
|
return self.set_leaves_from(0, input_data);
|
||||||
|
}
|
||||||
|
|
||||||
// Set input leaf to the next available index
|
// Set input leaf to the next available index
|
||||||
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
|
||||||
|
@ -515,7 +522,7 @@ mod test {
|
||||||
|
|
||||||
// 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));
|
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves));
|
||||||
rln.set_leaves(&mut buffer).unwrap();
|
rln.init_tree_with_leaves(&mut buffer).unwrap();
|
||||||
|
|
||||||
// We check if number of leaves set is consistent
|
// We check if number of leaves set is consistent
|
||||||
assert_eq!(rln.tree.leaves_set(), no_of_leaves);
|
assert_eq!(rln.tree.leaves_set(), no_of_leaves);
|
||||||
|
@ -550,6 +557,80 @@ mod test {
|
||||||
assert_eq!(root_delete, root_empty);
|
assert_eq!(root_delete, root_empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// We test leaf setting with a custom index, to enable batch updates to the root
|
||||||
|
// Uses `set_leaves_from` to set leaves in a batch, from index `start_index`
|
||||||
|
fn test_leaf_setting_with_index() {
|
||||||
|
let tree_height = TEST_TREE_HEIGHT;
|
||||||
|
let no_of_leaves = 256;
|
||||||
|
|
||||||
|
// We generate a vector of random leaves
|
||||||
|
let mut leaves: Vec<Fr> = Vec::new();
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
for _ in 0..no_of_leaves {
|
||||||
|
leaves.push(Fr::rand(&mut rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_index is the index from which we start setting leaves
|
||||||
|
// random number between 0..no_of_leaves
|
||||||
|
let set_index = rng.gen_range(0..no_of_leaves) as usize;
|
||||||
|
|
||||||
|
// We create a new tree
|
||||||
|
let input_buffer = Cursor::new(TEST_RESOURCES_FOLDER);
|
||||||
|
let mut rln = RLN::new(tree_height, input_buffer);
|
||||||
|
|
||||||
|
// We add leaves in a batch into the tree
|
||||||
|
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves));
|
||||||
|
rln.init_tree_with_leaves(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
// We check if number of leaves set is consistent
|
||||||
|
assert_eq!(rln.tree.leaves_set(), no_of_leaves);
|
||||||
|
|
||||||
|
// We get the root of the tree obtained adding leaves in batch
|
||||||
|
let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
rln.get_root(&mut buffer).unwrap();
|
||||||
|
let (root_batch_with_init, _) = bytes_le_to_fr(&buffer.into_inner());
|
||||||
|
|
||||||
|
// `init_tree_with_leaves` resets the tree to the height it was initialized with, using `set_tree`
|
||||||
|
|
||||||
|
// We add leaves in a batch starting from index 0..set_index
|
||||||
|
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves[0..set_index]));
|
||||||
|
rln.init_tree_with_leaves(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
// We add the remaining n leaves in a batch starting from index m
|
||||||
|
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves[set_index..]));
|
||||||
|
rln.set_leaves_from(set_index, &mut buffer).unwrap();
|
||||||
|
|
||||||
|
// We check if number of leaves set is consistent
|
||||||
|
assert_eq!(rln.tree.leaves_set(), no_of_leaves);
|
||||||
|
|
||||||
|
// We get the root of the tree obtained adding leaves in batch
|
||||||
|
let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
rln.get_root(&mut buffer).unwrap();
|
||||||
|
let (root_batch_with_custom_index, _) = bytes_le_to_fr(&buffer.into_inner());
|
||||||
|
|
||||||
|
assert_eq!(root_batch_with_init, root_batch_with_custom_index);
|
||||||
|
|
||||||
|
// We reset the tree to default
|
||||||
|
rln.set_tree(tree_height).unwrap();
|
||||||
|
|
||||||
|
// We add leaves one by one using the internal index (new leaves goes in next available position)
|
||||||
|
for leaf in &leaves {
|
||||||
|
let mut buffer = Cursor::new(fr_to_bytes_le(&leaf));
|
||||||
|
rln.set_next_leaf(&mut buffer).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We check if numbers of leaves set is consistent
|
||||||
|
assert_eq!(rln.tree.leaves_set(), no_of_leaves);
|
||||||
|
|
||||||
|
// We get the root of the tree obtained adding leaves using the internal index
|
||||||
|
let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
rln.get_root(&mut buffer).unwrap();
|
||||||
|
let (root_single_additions, _) = bytes_le_to_fr(&buffer.into_inner());
|
||||||
|
|
||||||
|
assert_eq!(root_batch_with_init, root_single_additions);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// This test is similar to the one in lib, but uses only public API
|
// This test is similar to the one in lib, but uses only public API
|
||||||
fn test_merkle_proof() {
|
fn test_merkle_proof() {
|
||||||
|
@ -772,7 +853,7 @@ mod test {
|
||||||
|
|
||||||
// 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));
|
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves));
|
||||||
rln.set_leaves(&mut buffer).unwrap();
|
rln.init_tree_with_leaves(&mut buffer).unwrap();
|
||||||
|
|
||||||
// Generate identity pair
|
// Generate identity pair
|
||||||
let (identity_secret, id_commitment) = keygen();
|
let (identity_secret, id_commitment) = keygen();
|
||||||
|
@ -837,7 +918,7 @@ mod test {
|
||||||
|
|
||||||
// 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));
|
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves));
|
||||||
rln.set_leaves(&mut buffer).unwrap();
|
rln.init_tree_with_leaves(&mut buffer).unwrap();
|
||||||
|
|
||||||
// Generate identity pair
|
// Generate identity pair
|
||||||
let (identity_secret, id_commitment) = keygen();
|
let (identity_secret, id_commitment) = keygen();
|
||||||
|
@ -982,7 +1063,7 @@ mod test {
|
||||||
|
|
||||||
// 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));
|
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves));
|
||||||
rln.set_leaves(&mut buffer).unwrap();
|
rln.init_tree_with_leaves(&mut buffer).unwrap();
|
||||||
|
|
||||||
// Generate identity pair
|
// Generate identity pair
|
||||||
let (identity_secret, id_commitment) = keygen();
|
let (identity_secret, id_commitment) = keygen();
|
||||||
|
|
Loading…
Reference in New Issue