feat(rln): expose set_metadata and get_metadata public and ffi apis (#178)

This commit is contained in:
Aaryamann Challani 2023-06-15 20:35:49 +05:30 committed by GitHub
parent 0d35571215
commit 2793fe0e24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 157 additions and 4 deletions

2
Cargo.lock generated
View File

@ -2387,7 +2387,7 @@ dependencies = [
[[package]]
name = "pmtree"
version = "1.0.0"
source = "git+https://github.com/Rate-Limiting-Nullifier/pmtree?rev=bf27d4273b34a7f4ec3c77cdf67fb17a5602504a#bf27d4273b34a7f4ec3c77cdf67fb17a5602504a"
source = "git+https://github.com/vacp2p/pmtree?rev=8b005bb44a4c51b56638ad6057b8bc90629fca59#8b005bb44a4c51b56638ad6057b8bc90629fca59"
dependencies = [
"rayon",
]

View File

@ -385,6 +385,22 @@ pub extern "C" fn recover_id_secret(
)
}
////////////////////////////////////////////////////////
// Persistent metadata APIs
////////////////////////////////////////////////////////
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn set_metadata(ctx: *mut RLN, input_buffer: *const Buffer) -> bool {
call!(ctx, set_metadata, input_buffer)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn get_metadata(ctx: *const RLN, output_buffer: *mut Buffer) -> bool {
call_with_output_arg!(ctx, get_metadata, output_buffer)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn hash(input_buffer: *const Buffer, output_buffer: *mut Buffer) -> bool {

View File

@ -7,11 +7,15 @@ use std::collections::HashSet;
use std::fmt::Debug;
use std::path::PathBuf;
use std::str::FromStr;
use utils::pmtree::Hasher;
use utils::pmtree::{Database, Hasher};
use utils::*;
const METADATA_KEY: [u8; 8] = *b"metadata";
pub struct PmTree {
tree: pmtree::MerkleTree<SledDB, PoseidonHash>,
// metadata that an application may use to store additional information
metadata: Vec<u8>,
}
pub struct PmTreeProof {
@ -135,7 +139,10 @@ impl ZerokitMerkleTree for PmTree {
Err(_) => pmtree::MerkleTree::new(depth, config.0)?,
};
Ok(PmTree { tree })
Ok(PmTree {
tree,
metadata: Vec::new(),
})
}
fn depth(&self) -> usize {
@ -238,6 +245,25 @@ impl ZerokitMerkleTree for PmTree {
fn compute_root(&mut self) -> Result<FrOf<Self::Hasher>> {
Ok(self.tree.root())
}
fn set_metadata(&mut self, metadata: &[u8]) -> Result<()> {
self.tree.db.put(METADATA_KEY, metadata.to_vec())?;
self.metadata = metadata.to_vec();
Ok(())
}
fn metadata(&self) -> Result<Vec<u8>> {
if !self.metadata.is_empty() {
return Ok(self.metadata.clone());
}
// if empty, try searching the db
let data = self.tree.db.get(METADATA_KEY)?;
if data.is_none() {
return Err(Report::msg("metadata does not exist"));
}
Ok(data.unwrap())
}
}
impl ZerokitMerkleProof for PmTreeProof {

View File

@ -437,6 +437,43 @@ impl RLN<'_> {
Ok(())
}
/// Sets some metadata that a consuming application may want to store in the RLN object.
/// This metadata is not used by the RLN module.
///
/// Input values are:
/// - `metadata`: a byte vector containing the metadata
///
/// Example
///
/// ```
/// let metadata = b"some metadata";
/// rln.set_metadata(metadata).unwrap();
/// ```
pub fn set_metadata(&mut self, metadata: &[u8]) -> Result<()> {
self.tree.set_metadata(metadata)?;
Ok(())
}
/// Returns the metadata stored in the RLN object.
///
/// Output values are:
/// - `output_data`: a writer receiving the serialization of the metadata
///
/// Example
///
/// ```
/// use std::io::Cursor;
///
/// let mut buffer = Cursor::new(Vec::<u8>::new());
/// rln.get_metadata(&mut buffer).unwrap();
/// let metadata = buffer.into_inner();
/// ```
pub fn get_metadata<W: Write>(&self, mut output_data: W) -> Result<()> {
let metadata = self.tree.metadata()?;
output_data.write_all(&metadata)?;
Ok(())
}
/// Returns the Merkle tree root
///
/// Output values are:
@ -1882,4 +1919,22 @@ mod test {
let (received_leaf, _) = bytes_le_to_fr(output_buffer.into_inner().as_ref());
assert_eq!(received_leaf, leaf);
}
#[test]
fn test_metadata() {
let tree_height = TEST_TREE_HEIGHT;
let input_buffer =
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";
rln.set_metadata(arbitrary_metadata).unwrap();
let mut buffer = Cursor::new(Vec::<u8>::new());
rln.get_metadata(&mut buffer).unwrap();
let received_metadata = buffer.into_inner();
assert_eq!(arbitrary_metadata, received_metadata);
}
}

View File

@ -1201,4 +1201,32 @@ mod test {
// We check that the received id_commitment is the same as the one we inserted
assert_eq!(received_id_commitment, id_commitment);
}
#[test]
fn test_metadata() {
// We create a RLN instance
let tree_height = TEST_TREE_HEIGHT;
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
let input_config = json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string();
let input_buffer = &Buffer::from(input_config.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() };
let seed_bytes: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let input_buffer = &Buffer::from(seed_bytes);
let success = set_metadata(rln_pointer, input_buffer);
assert!(success, "set_metadata call failed");
let mut output_buffer = MaybeUninit::<Buffer>::uninit();
let success = get_metadata(rln_pointer, output_buffer.as_mut_ptr());
assert!(success, "get_metadata call failed");
let output_buffer = unsafe { output_buffer.assume_init() };
let result_data = <&[u8]>::from(&output_buffer).to_vec();
assert_eq!(result_data, seed_bytes.to_vec());
}
}

View File

@ -11,7 +11,7 @@ bench = false
ark-ff = { version = "=0.4.1", default-features = false, features = ["asm"] }
num-bigint = { version = "=0.4.3", default-features = false, features = ["rand"] }
color-eyre = "=0.6.2"
pmtree = { git = "https://github.com/Rate-Limiting-Nullifier/pmtree", rev = "bf27d4273b34a7f4ec3c77cdf67fb17a5602504a", optional = true}
pmtree = { git = "https://github.com/vacp2p/pmtree", rev = "8b005bb44a4c51b56638ad6057b8bc90629fca59", optional = true}
sled = "=0.34.7"
serde = "1.0.44"

View File

@ -29,6 +29,9 @@ pub struct FullMerkleTree<H: Hasher> {
// The next available (i.e., never used) tree index. Equivalently, the number of leaves added to the tree
// (deletions leave next_index unchanged)
next_index: usize,
// metadata that an application may use to store additional information
metadata: Vec<u8>,
}
/// Element of a Merkle proof
@ -94,6 +97,7 @@ where
cached_nodes,
nodes,
next_index,
metadata: Vec::new(),
})
}
@ -234,6 +238,15 @@ where
fn compute_root(&mut self) -> Result<FrOf<Self::Hasher>> {
Ok(self.root())
}
fn set_metadata(&mut self, metadata: &[u8]) -> Result<()> {
self.metadata = metadata.to_vec();
Ok(())
}
fn metadata(&self) -> Result<Vec<u8>> {
Ok(self.metadata.to_vec())
}
}
impl<H: Hasher> FullMerkleTree<H>

View File

@ -63,6 +63,8 @@ pub trait ZerokitMerkleTree {
fn delete(&mut self, index: usize) -> Result<()>;
fn proof(&self, index: usize) -> Result<Self::Proof>;
fn verify(&self, leaf: &FrOf<Self::Hasher>, witness: &Self::Proof) -> Result<bool>;
fn set_metadata(&mut self, metadata: &[u8]) -> Result<()>;
fn metadata(&self) -> Result<Vec<u8>>;
}
pub trait ZerokitMerkleProof {

View File

@ -30,6 +30,9 @@ where
// The next available (i.e., never used) tree index. Equivalently, the number of leaves added to the tree
// (deletions leave next_index unchanged)
next_index: usize,
// metadata that an application may use to store additional information
metadata: Vec<u8>,
}
/// The Merkle proof
@ -76,6 +79,7 @@ where
depth,
nodes: HashMap::new(),
next_index: 0,
metadata: Vec::new(),
})
}
@ -216,6 +220,15 @@ where
self.recalculate_from(0)?;
Ok(self.root())
}
fn set_metadata(&mut self, metadata: &[u8]) -> Result<()> {
self.metadata = metadata.to_vec();
Ok(())
}
fn metadata(&self) -> Result<Vec<u8>> {
Ok(self.metadata.to_vec())
}
}
impl<H: Hasher> OptimalMerkleTree<H>