mirror of https://github.com/vacp2p/zerokit.git
feat(rln): expose set_metadata and get_metadata public and ffi apis (#178)
This commit is contained in:
parent
0d35571215
commit
2793fe0e24
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue