Compare commits

...

22 Commits

Author SHA1 Message Date
Arseniy Klempner
0c9fc07cfe add debug statements that appear in js console 2024-03-29 11:58:51 -07:00
rymnc
7dd019b0a5 chore: Release 2024-03-07 01:41:06 +05:30
Aaryamann Challani
78bec51fba feat(rln-v1): return empty metadata if it doesnt exist (#231) 2024-03-07 01:37:01 +05:30
rymnc
b0be32943e chore: Release 2024-01-23 09:30:38 -04:00
Richard Ramos
09da5304c1 fix: add support to aarch64-linux-android 2024-01-23 09:30:38 -04:00
Alvaro Revuelta
d5e09524d7 Expose generate proof with witness ffi (#227)
* Expose generate proof with witness ffi

* Force run CI

* Update ci.yml

* Fix wasm with_witness

* Remove forced CI run
2024-01-23 16:49:54 +05:30
Aaryamann Challani
b903d8d740 chore(rln): release v0.3.4 2023-09-14 14:39:19 +05:30
Aaryamann Challani
f73c83b571 fix(rln): if only a single insertion, dont use batch_insert (#215)
* fix(rln): if only a single insertion, dont use batch_insert

* fix: more optimizations
2023-09-14 14:10:53 +05:30
Aaryamann Challani
a86b859b75 chore: Release (#214) 2023-09-12 15:27:08 +05:30
Aaryamann Challani
f8fc455d08 chore(rln): expose leaves_set api (#213) 2023-09-12 14:44:33 +05:30
rymnc
b51896c3a7 chore: Release 2023-08-25 05:37:09 +05:30
Aaryamann Challani
0c5ef6abcf fix(rln): use config.open instead of sled::open (#209)
fix: include tries & exp backoff to catch WouldBlock errors
2023-08-25 05:34:20 +05:30
tyshko-rostyslav
a1c292cb2e add new path arg (#207) 2023-08-24 23:35:14 +05:30
Aaryamann Challani
c6c1bfde91 chore(rln): expose seq_atomic_operation api (#206) 2023-08-21 12:07:57 +05:30
Aaryamann Challani
bf3d1d3309 chore: use pmtree instead of vacp2p_pmtree (#203) 2023-08-16 16:01:39 +05:30
Aaryamann Challani
7110e00674 fix: building in ci (#201) 2023-08-09 14:35:47 +05:30
richΛrd
99966d1a6e feat: print to stderr any error obtained while executing functions via FFI (#200) 2023-08-09 14:35:33 +05:30
Richard Ramos
7d63912ace chore: accept tree_config in new_with_params 2023-08-07 08:48:41 -04:00
Aaryamann Challani
ef1da42d94 v0.3.1 (#198)
* fix(rln): missing fields from cargo.toml

* fix(utils): missing fields from cargo.toml

* chore: Release
2023-08-05 10:42:21 +05:30
Aaryamann Challani
ecb4d9307f chore: docs cleanup (#196) 2023-08-01 22:33:08 +05:30
Aaryamann Challani
d1414a44c5 fix(rln): atomic operation edge case (#195)
* fix(rln): atomic operation edge case

* fmt

* fix: bug

* test: new batching mechanism

* Revert "test: new batching mechanism"

This reverts commit 396c2ec342.

* fix: end should be max index + 1

* fix: optimization

* fix: apply cleanup

* fix: idiomatic leaf setting

* fix: abstract out logic

* fix: type aliasing for verbose types

* fix: remove_indices_and_set_leaves fn
2023-08-01 18:06:52 +05:30
Aaryamann Challani
6d58320077 fix(crates): version tags (#194)
* fix(crates): version tags

* fix commit

---------

Co-authored-by: Rostyslav Tyshko <tyshko.rostyslav@gmail.com>
2023-07-31 09:22:23 +02:00
21 changed files with 549 additions and 178 deletions

View File

@@ -134,4 +134,4 @@ jobs:
- uses: boa-dev/criterion-compare-action@v3
with:
branchName: ${{ github.base_ref }}
cwd: ${{ matrix.crate }}
cwd: ${{ matrix.crate }}

62
Cargo.lock generated
View File

@@ -1919,9 +1919,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "js-sys"
version = "0.3.62"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5"
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
dependencies = [
"wasm-bindgen",
]
@@ -2081,7 +2081,7 @@ checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389"
[[package]]
name = "multiplier"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"ark-bn254 0.3.0",
"ark-circom 0.1.0 (git+https://github.com/gakonst/ark-circom?rev=35ce5a9)",
@@ -2412,6 +2412,15 @@ dependencies = [
"plotters-backend",
]
[[package]]
name = "pmtree"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e054322ee96d2ccd86cd47b87797166682e45f5d67571c48eaa864668d26f510"
dependencies = [
"rayon",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@@ -2434,7 +2443,7 @@ dependencies = [
[[package]]
name = "private-settlement"
version = "0.1.0"
version = "0.3.0"
[[package]]
name = "proc-macro-crate"
@@ -2686,7 +2695,7 @@ dependencies = [
[[package]]
name = "rln"
version = "0.1.0"
version = "0.3.6"
dependencies = [
"ark-bn254 0.4.0",
"ark-circom 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2698,6 +2707,7 @@ dependencies = [
"ark-std 0.4.0",
"cfg-if",
"color-eyre 0.6.2",
"console_error_panic_hook",
"criterion 0.4.0",
"include_dir",
"num-bigint",
@@ -2711,12 +2721,13 @@ dependencies = [
"thiserror",
"tiny-keccak",
"wasmer",
"web-sys",
"zerokit_utils",
]
[[package]]
name = "rln-cli"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"clap 4.2.7",
"clap_derive",
@@ -2945,7 +2956,7 @@ dependencies = [
[[package]]
name = "semaphore-wrapper"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"ark-bn254 0.3.0",
"ark-circom 0.1.0 (git+https://github.com/gakonst/ark-circom?rev=35ce5a9)",
@@ -3504,15 +3515,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2"
[[package]]
name = "vacp2p_pmtree"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee78790de52d6774ea318eb747a488fd5d96055bfe75ec2e7f605b15e21c664"
dependencies = [
"rayon",
]
[[package]]
name = "valuable"
version = "0.1.0"
@@ -3543,9 +3545,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.85"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4"
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -3553,9 +3555,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.85"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822"
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
dependencies = [
"bumpalo",
"log",
@@ -3580,9 +3582,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.85"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434"
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -3590,9 +3592,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.85"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869"
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
@@ -3603,9 +3605,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.85"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "wasm-bindgen-test"
@@ -3995,9 +3997,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.62"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721"
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -4260,7 +4262,7 @@ dependencies = [
[[package]]
name = "zerokit_utils"
version = "0.1.0"
version = "0.3.2"
dependencies = [
"ark-bn254 0.4.0",
"ark-ff 0.4.1",
@@ -4269,8 +4271,8 @@ dependencies = [
"hex-literal",
"num-bigint",
"num-traits",
"pmtree",
"serde",
"sled",
"tiny-keccak",
"vacp2p_pmtree",
]

View File

@@ -8,6 +8,7 @@ members = [
"rln-wasm",
"utils",
]
resolver = "2"
# Compilation profile for any non-workspace member.
# Dependencies are optimized, even in a dev build. This improves dev performance
@@ -18,6 +19,7 @@ opt-level = 3
[profile.release.package."rln-wasm"]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
debug = true
[profile.release.package."semaphore"]
codegen-units = 1
codegen-units = 1

View File

@@ -29,4 +29,7 @@ image = "ghcr.io/cross-rs/mips64-unknown-linux-gnuabi64:latest"
image = "ghcr.io/cross-rs/mips64el-unknown-linux-gnuabi64:latest"
[target.mipsel-unknown-linux-gnu]
image = "ghcr.io/cross-rs/mipsel-unknown-linux-gnu:latest"
image = "ghcr.io/cross-rs/mipsel-unknown-linux-gnu:latest"
[target.aarch64-linux-android]
image = "ghcr.io/cross-rs/aarch64-linux-android:edge"

View File

@@ -1,6 +1,6 @@
[package]
name = "multiplier"
version = "0.1.0"
version = "0.3.0"
edition = "2018"
license = "MIT OR Apache-2.0"

View File

@@ -1,6 +1,6 @@
[package]
name = "private-settlement"
version = "0.1.0"
version = "0.3.0"
edition = "2021"
license = "MIT OR Apache-2.0"

View File

@@ -1,6 +1,6 @@
[package]
name = "rln-cli"
version = "0.1.0"
version = "0.3.0"
edition = "2021"
[dependencies]

View File

@@ -15,6 +15,8 @@ pub(crate) enum Commands {
/// Sets a custom config file
#[arg(short, long)]
config: PathBuf,
#[arg(short, long)]
tree_config_input: PathBuf,
},
SetTree {
tree_height: usize,

View File

@@ -34,6 +34,7 @@ fn main() -> Result<()> {
Some(Commands::NewWithParams {
tree_height,
config,
tree_config_input,
}) => {
let mut resources: Vec<Vec<u8>> = Vec::new();
for filename in ["rln.wasm", "rln_final.zkey", "verification_key.json"] {
@@ -44,11 +45,13 @@ fn main() -> Result<()> {
file.read_exact(&mut buffer)?;
resources.push(buffer);
}
let tree_config_input_file = File::open(&tree_config_input)?;
state.rln = Some(RLN::new_with_params(
*tree_height,
resources[0].clone(),
resources[1].clone(),
resources[2].clone(),
tree_config_input_file,
)?);
Ok(())
}

View File

@@ -2,7 +2,7 @@ use color_eyre::Result;
use rln::public::RLN;
use std::fs::File;
use crate::config::{InnerConfig, Config};
use crate::config::{Config, InnerConfig};
#[derive(Default)]
pub(crate) struct State<'a> {

View File

@@ -250,11 +250,7 @@ pub fn wasm_set_metadata(ctx: *mut RLNWrapper, input: Uint8Array) -> Result<(),
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[wasm_bindgen(js_name = getMetadata)]
pub fn wasm_get_metadata(ctx: *mut RLNWrapper) -> Result<Uint8Array, String> {
call_with_output_and_error_msg!(
ctx,
get_metadata,
"could not get metadata".to_string()
)
call_with_output_and_error_msg!(ctx, get_metadata, "could not get metadata".to_string())
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]

View File

@@ -1,9 +1,12 @@
[package]
name = "rln"
version = "0.1.0"
version = "0.3.6"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "APIs to manage, compute and verify zkSNARK proofs and RLN primitives"
documentation = "https://github.com/vacp2p/zerokit"
homepage = "https://vac.dev"
repository = "https://github.com/vacp2p/zerokit"
[lib]
crate-type = ["rlib", "staticlib"]
@@ -39,13 +42,16 @@ once_cell = "=1.17.1"
rand = "=0.8.5"
rand_chacha = "=0.3.1"
tiny-keccak = { version = "=2.0.2", features = ["keccak"] }
utils = { package = "zerokit_utils", version = "=0.1.0", path = "../utils/", default-features = false }
utils = { package = "zerokit_utils", version = "=0.3.2", path = "../utils/", default-features = false }
# serialization
serde_json = "=1.0.96"
serde = { version = "=1.0.163", features = ["derive"] }
include_dir = "=0.7.3"
console_error_panic_hook = "0.1.7"
web-sys = { version = "0.3.69", features = ["console"] }
[dev-dependencies]
sled = "=0.34.7"

View File

@@ -12,7 +12,15 @@ macro_rules! call {
($instance:expr, $method:ident $(, $arg:expr)*) => {
{
let new_instance: &mut RLN = $instance.process();
new_instance.$method($($arg.process()),*).is_ok()
match new_instance.$method($($arg.process()),*) {
Ok(()) => {
true
}
Err(err) => {
eprintln!("execution error: {err}");
false
}
}
}
}
}
@@ -30,13 +38,17 @@ macro_rules! call_with_output_arg {
{
let mut output_data: Vec<u8> = Vec::new();
let new_instance = $instance.process();
if new_instance.$method(&mut output_data).is_ok() {
unsafe { *$output_arg = Buffer::from(&output_data[..]) };
std::mem::forget(output_data);
true
} else {
std::mem::forget(output_data);
false
match new_instance.$method(&mut output_data) {
Ok(()) => {
unsafe { *$output_arg = Buffer::from(&output_data[..]) };
std::mem::forget(output_data);
true
}
Err(err) => {
std::mem::forget(output_data);
eprintln!("execution error: {err}");
false
}
}
}
};
@@ -44,13 +56,17 @@ macro_rules! call_with_output_arg {
{
let mut output_data: Vec<u8> = Vec::new();
let new_instance = $instance.process();
if new_instance.$method($($arg.process()),*, &mut output_data).is_ok() {
unsafe { *$output_arg = Buffer::from(&output_data[..]) };
std::mem::forget(output_data);
true
} else {
std::mem::forget(output_data);
false
match new_instance.$method($($arg.process()),*, &mut output_data) {
Ok(()) => {
unsafe { *$output_arg = Buffer::from(&output_data[..]) };
std::mem::forget(output_data);
true
}
Err(err) => {
std::mem::forget(output_data);
eprintln!("execution error: {err}");
false
}
}
}
};
@@ -66,13 +82,17 @@ macro_rules! no_ctx_call_with_output_arg {
($method:ident, $output_arg:expr, $( $arg:expr ),* ) => {
{
let mut output_data: Vec<u8> = Vec::new();
if $method($($arg.process()),*, &mut output_data).is_ok() {
unsafe { *$output_arg = Buffer::from(&output_data[..]) };
std::mem::forget(output_data);
true
} else {
std::mem::forget(output_data);
false
match $method($($arg.process()),*, &mut output_data) {
Ok(()) => {
unsafe { *$output_arg = Buffer::from(&output_data[..]) };
std::mem::forget(output_data);
true
}
Err(err) => {
std::mem::forget(output_data);
eprintln!("execution error: {err}");
false
}
}
}
}
@@ -89,8 +109,11 @@ macro_rules! call_with_bool_arg {
{
let new_instance = $instance.process();
if match new_instance.$method($($arg.process()),*,) {
Ok(verified) => verified,
Err(_) => return false,
Ok(result) => result,
Err(err) => {
eprintln!("execution error: {err}");
return false
},
} {
unsafe { *$bool_arg = true };
} else {
@@ -171,11 +194,15 @@ impl<'a> From<&Buffer> for &'a [u8] {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn new(tree_height: usize, input_buffer: *const Buffer, ctx: *mut *mut RLN) -> bool {
if let Ok(rln) = RLN::new(tree_height, input_buffer.process()) {
unsafe { *ctx = Box::into_raw(Box::new(rln)) };
true
} else {
false
match RLN::new(tree_height, input_buffer.process()) {
Ok(rln) => {
unsafe { *ctx = Box::into_raw(Box::new(rln)) };
true
}
Err(err) => {
eprintln!("could not instantiate rln: {err}");
false
}
}
}
@@ -186,18 +213,24 @@ pub extern "C" fn new_with_params(
circom_buffer: *const Buffer,
zkey_buffer: *const Buffer,
vk_buffer: *const Buffer,
tree_config: *const Buffer,
ctx: *mut *mut RLN,
) -> bool {
if let Ok(rln) = RLN::new_with_params(
match RLN::new_with_params(
tree_height,
circom_buffer.process().to_vec(),
zkey_buffer.process().to_vec(),
vk_buffer.process().to_vec(),
tree_config.process(),
) {
unsafe { *ctx = Box::into_raw(Box::new(rln)) };
true
} else {
false
Ok(rln) => {
unsafe { *ctx = Box::into_raw(Box::new(rln)) };
true
}
Err(err) => {
eprintln!("could not instantiate rln: {err}");
false
}
}
}
@@ -228,6 +261,12 @@ pub extern "C" fn get_leaf(ctx: *mut RLN, index: usize, output_buffer: *mut Buff
call_with_output_arg!(ctx, get_leaf, output_buffer, index)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn leaves_set(ctx: *mut RLN) -> usize {
ctx.process().leaves_set()
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn set_next_leaf(ctx: *mut RLN, input_buffer: *const Buffer) -> bool {
@@ -261,6 +300,22 @@ pub extern "C" fn atomic_operation(
call!(ctx, atomic_operation, index, leaves_buffer, indices_buffer)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn seq_atomic_operation(
ctx: *mut RLN,
leaves_buffer: *const Buffer,
indices_buffer: *const Buffer,
) -> bool {
call!(
ctx,
atomic_operation,
ctx.process().leaves_set(),
leaves_buffer,
indices_buffer
)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn get_root(ctx: *const RLN, output_buffer: *mut Buffer) -> bool {
@@ -306,6 +361,21 @@ pub extern "C" fn generate_rln_proof(
call_with_output_arg!(ctx, generate_rln_proof, output_buffer, input_buffer)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn generate_rln_proof_with_witness(
ctx: *mut RLN,
input_buffer: *const Buffer,
output_buffer: *mut Buffer,
) -> bool {
call_with_output_arg!(
ctx,
generate_rln_proof_with_witness,
output_buffer,
input_buffer
)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn verify_rln_proof(

View File

@@ -1,13 +1,12 @@
// This crate instantiate the Poseidon hash algorithm
/// This crate instantiates the Poseidon hash algorithm.
use crate::{circuit::Fr, utils::bytes_le_to_fr};
use once_cell::sync::Lazy;
use tiny_keccak::{Hasher, Keccak};
use utils::poseidon::Poseidon;
// These indexed constants hardcodes the supported round parameters tuples (t, RF, RN, SKIP_MATRICES) for the Bn254 scalar field
// SKIP_MATRICES is the index of the randomly generated secure MDS matrix. See security note in the zerokit_utils::poseidon::poseidon_constants crate on this.
// TODO: generate these parameters
/// These indexed constants hardcode the supported round parameters tuples (t, RF, RN, SKIP_MATRICES) for the Bn254 scalar field.
/// SKIP_MATRICES is the index of the randomly generated secure MDS matrix.
/// TODO: generate these parameters
pub const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
(2, 8, 56, 0),
(3, 8, 57, 0),
@@ -19,7 +18,7 @@ pub const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
(9, 8, 63, 0),
];
// Poseidon Hash wrapper over above implementation. Adapted from semaphore-rs poseidon hash wrapper.
/// Poseidon Hash wrapper over above implementation.
static POSEIDON: Lazy<Poseidon<Fr>> = Lazy::new(|| Poseidon::<Fr>::from(&ROUND_PARAMS));
pub fn poseidon_hash(input: &[Fr]) -> Fr {
@@ -28,11 +27,11 @@ pub fn poseidon_hash(input: &[Fr]) -> Fr {
.expect("hash with fixed input size can't fail")
}
// The zerokit RLN Merkle tree Hasher
/// The zerokit RLN Merkle tree Hasher.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct PoseidonHash;
// The default Hasher trait used by Merkle tree implementation in utils
/// The default Hasher trait used by Merkle tree implementation in utils.
impl utils::merkle_tree::Hasher for PoseidonHash {
type Fr = Fr;
@@ -45,10 +44,9 @@ impl utils::merkle_tree::Hasher for PoseidonHash {
}
}
// Hashes arbitrary signal to the underlying prime field
/// Hashes arbitrary signal to the underlying prime field.
pub fn hash_to_field(signal: &[u8]) -> Fr {
// We hash the input signal using Keccak256
// (note that a bigger curve order might require a bigger hash blocksize)
let mut hash = [0; 32];
let mut hasher = Keccak::v256();
hasher.update(signal);

View File

@@ -1,15 +1,17 @@
use crate::circuit::Fr;
use crate::hashers::{poseidon_hash, PoseidonHash};
use crate::utils::{bytes_le_to_fr, fr_to_bytes_le};
use color_eyre::{Report, Result};
use serde_json::Value;
use std::collections::HashSet;
use std::fmt::Debug;
use std::path::PathBuf;
use std::str::FromStr;
use color_eyre::{Report, Result};
use serde_json::Value;
use utils::pmtree::{Database, Hasher};
use utils::*;
use crate::circuit::Fr;
use crate::hashers::{poseidon_hash, PoseidonHash};
use crate::utils::{bytes_le_to_fr, fr_to_bytes_le};
const METADATA_KEY: [u8; 8] = *b"metadata";
pub struct PmTree {
@@ -25,13 +27,9 @@ pub struct PmTreeProof {
pub type FrOf<H> = <H as Hasher>::Fr;
// The pmtree Hasher trait used by pmtree Merkle tree
impl pmtree::Hasher for PoseidonHash {
impl Hasher for PoseidonHash {
type Fr = Fr;
fn default_leaf() -> Self::Fr {
Fr::from(0)
}
fn serialize(value: Self::Fr) -> pmtree::Value {
fr_to_bytes_le(&value)
}
@@ -41,12 +39,16 @@ impl pmtree::Hasher for PoseidonHash {
fr
}
fn default_leaf() -> Self::Fr {
Fr::from(0)
}
fn hash(inputs: &[Self::Fr]) -> Self::Fr {
poseidon_hash(inputs)
}
}
fn get_tmp_path() -> std::path::PathBuf {
fn get_tmp_path() -> PathBuf {
std::env::temp_dir().join(format!("pmtree-{}", rand::random::<u64>()))
}
@@ -54,7 +56,7 @@ fn get_tmp() -> bool {
true
}
pub struct PmtreeConfig(pm_tree::Config);
pub struct PmtreeConfig(Config);
impl FromStr for PmtreeConfig {
type Err = Report;
@@ -85,7 +87,7 @@ impl FromStr for PmtreeConfig {
)));
}
let config = pm_tree::Config::new()
let config = Config::new()
.temporary(temporary.unwrap_or(get_tmp()))
.path(path.unwrap_or(get_tmp_path()))
.cache_capacity(cache_capacity.unwrap_or(1024 * 1024 * 1024))
@@ -100,7 +102,7 @@ impl Default for PmtreeConfig {
fn default() -> Self {
let tmp_path = get_tmp_path();
PmtreeConfig(
pm_tree::Config::new()
Config::new()
.temporary(true)
.path(tmp_path)
.cache_capacity(150_000)
@@ -145,10 +147,6 @@ impl ZerokitMerkleTree for PmTree {
})
}
fn close_db_connection(&mut self) -> Result<()> {
self.tree.db.close().map_err(|e| Report::msg(e.to_string()))
}
fn depth(&self) -> usize {
self.tree.depth()
}
@@ -165,16 +163,16 @@ impl ZerokitMerkleTree for PmTree {
self.tree.root()
}
fn compute_root(&mut self) -> Result<FrOf<Self::Hasher>> {
Ok(self.tree.root())
}
fn set(&mut self, index: usize, leaf: FrOf<Self::Hasher>) -> Result<()> {
self.tree
.set(index, leaf)
.map_err(|e| Report::msg(e.to_string()))
}
fn get(&self, index: usize) -> Result<FrOf<Self::Hasher>> {
self.tree.get(index).map_err(|e| Report::msg(e.to_string()))
}
fn set_range<I: IntoIterator<Item = FrOf<Self::Hasher>>>(
&mut self,
start: usize,
@@ -185,6 +183,10 @@ impl ZerokitMerkleTree for PmTree {
.map_err(|e| Report::msg(e.to_string()))
}
fn get(&self, index: usize) -> Result<FrOf<Self::Hasher>> {
self.tree.get(index).map_err(|e| Report::msg(e.to_string()))
}
fn override_range<I: IntoIterator<Item = FrOf<Self::Hasher>>, J: IntoIterator<Item = usize>>(
&mut self,
start: usize,
@@ -192,33 +194,17 @@ impl ZerokitMerkleTree for PmTree {
indices: J,
) -> Result<()> {
let leaves = leaves.into_iter().collect::<Vec<_>>();
let indices = indices.into_iter().collect::<HashSet<_>>();
let end = start + leaves.len();
let mut indices = indices.into_iter().collect::<Vec<_>>();
indices.sort();
if leaves.len() + start - indices.len() > self.capacity() {
return Err(Report::msg("index out of bounds"));
match (leaves.len(), indices.len()) {
(0, 0) => Err(Report::msg("no leaves or indices to be removed")),
(1, 0) => self.set(start, leaves[0]),
(0, 1) => self.delete(indices[0]),
(_, 0) => self.set_range_with_leaves(start, leaves),
(0, _) => self.remove_indices(&indices),
(_, _) => self.remove_indices_and_set_leaves(start, leaves, &indices),
}
// extend the range to include indices to be removed
let min_index = indices.iter().min().unwrap_or(&start);
let max_index = indices.iter().max().unwrap_or(&end);
let mut new_leaves = Vec::new();
// insert leaves into new_leaves
for i in *min_index..*max_index {
if indices.contains(&i) {
// insert 0
new_leaves.push(Self::Hasher::default_leaf());
} else {
// insert leaf
new_leaves.push(leaves[i - start]);
}
}
self.tree
.set_range(start, new_leaves)
.map_err(|e| Report::msg(e.to_string()))
}
fn update_next(&mut self, leaf: FrOf<Self::Hasher>) -> Result<()> {
@@ -246,10 +232,6 @@ 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();
@@ -264,10 +246,64 @@ impl ZerokitMerkleTree for PmTree {
let data = self.tree.db.get(METADATA_KEY)?;
if data.is_none() {
return Err(Report::msg("metadata does not exist"));
// send empty Metadata
return Ok(Vec::new());
}
Ok(data.unwrap())
}
fn close_db_connection(&mut self) -> Result<()> {
self.tree.db.close().map_err(|e| Report::msg(e.to_string()))
}
}
type PmTreeHasher = <PmTree as ZerokitMerkleTree>::Hasher;
type FrOfPmTreeHasher = FrOf<PmTreeHasher>;
impl PmTree {
fn set_range_with_leaves(&mut self, start: usize, leaves: Vec<FrOfPmTreeHasher>) -> Result<()> {
self.tree
.set_range(start, leaves)
.map_err(|e| Report::msg(e.to_string()))
}
fn remove_indices(&mut self, indices: &[usize]) -> Result<()> {
let start = indices[0];
let end = indices.last().unwrap() + 1;
let new_leaves = (start..end).map(|_| PmTreeHasher::default_leaf());
self.tree
.set_range(start, new_leaves)
.map_err(|e| Report::msg(e.to_string()))
}
fn remove_indices_and_set_leaves(
&mut self,
start: usize,
leaves: Vec<FrOfPmTreeHasher>,
indices: &[usize],
) -> Result<()> {
let min_index = *indices.first().unwrap();
let max_index = start + leaves.len();
let mut set_values = vec![PmTreeHasher::default_leaf(); max_index - min_index];
for i in min_index..start {
if !indices.contains(&i) {
let value = self.tree.get(i)?;
set_values[i - min_index] = value;
}
}
for (i, &leaf) in leaves.iter().enumerate() {
set_values[start - min_index + i] = leaf;
}
self.tree
.set_range(min_index, set_values)
.map_err(|e| Report::msg(e.to_string()))
}
}
impl ZerokitMerkleProof for PmTreeProof {

View File

@@ -103,29 +103,50 @@ pub fn serialize_witness(rln_witness: &RLNWitnessInput) -> Result<Vec<u8>> {
Ok(serialized)
}
extern crate web_sys;
pub fn deserialize_witness(serialized: &[u8]) -> Result<(RLNWitnessInput, usize)> {
let mut all_read: usize = 0;
let (identity_secret, read) = bytes_le_to_fr(&serialized[all_read..]);
all_read += read;
web_sys::console::log_1(&"Read identity secret".into());
web_sys::console::log_1(&identity_secret.to_string().into());
web_sys::console::log_1(&all_read.to_string().into());
let (path_elements, read) = bytes_le_to_vec_fr(&serialized[all_read..])?;
all_read += read;
web_sys::console::log_1(&"Read path elements".into());
web_sys::console::log_1(&format!("{:?}", path_elements).into());
web_sys::console::log_1(&all_read.to_string().into());
let (identity_path_index, read) = bytes_le_to_vec_u8(&serialized[all_read..])?;
all_read += read;
web_sys::console::log_1(&"Read identity path index".into());
web_sys::console::log_1(&format!("{:?}", identity_path_index).into());
web_sys::console::log_1(&all_read.to_string().into());
let (x, read) = bytes_le_to_fr(&serialized[all_read..]);
all_read += read;
web_sys::console::log_1(&"Read x".into());
web_sys::console::log_1(&x.to_string().into());
web_sys::console::log_1(&all_read.to_string().into());
let (epoch, read) = bytes_le_to_fr(&serialized[all_read..]);
all_read += read;
web_sys::console::log_1(&"Read epoch".into());
web_sys::console::log_1(&epoch.to_string().into());
web_sys::console::log_1(&all_read.to_string().into());
let (rln_identifier, read) = bytes_le_to_fr(&serialized[all_read..]);
all_read += read;
web_sys::console::log_1(&"Read rln identifier".into());
web_sys::console::log_1(&rln_identifier.to_string().into());
web_sys::console::log_1(&all_read.to_string().into());
// TODO: check rln_identifier against public::RLN_IDENTIFIER
if serialized.len() != all_read {
web_sys::console::log_1(&"serialized length is not equal to all_read".into());
return Err(Report::msg("serialized length is not equal to all_read"));
}

View File

@@ -14,6 +14,9 @@ use color_eyre::{Report, Result};
use num_bigint::BigInt;
use std::io::Cursor;
use utils::{ZerokitMerkleProof, ZerokitMerkleTree};
extern crate console_error_panic_hook;
use std::panic;
cfg_if! {
if #[cfg(not(target_arch = "wasm32"))] {
@@ -117,6 +120,7 @@ impl RLN<'_> {
/// - `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
/// - `tree_config`: a reader for a string containing a json with the merkle tree configuration
///
/// Example:
/// ```
@@ -134,6 +138,8 @@ impl RLN<'_> {
/// let mut buffer = vec![0; metadata.len() as usize];
/// file.read_exact(&mut buffer).expect("buffer overflow");
/// resources.push(buffer);
/// let tree_config = "{}".to_string();
/// let tree_config_buffer = &Buffer::from(tree_config.as_bytes());
/// }
///
/// let mut rln = RLN::new_with_params(
@@ -141,11 +147,51 @@ impl RLN<'_> {
/// resources[0].clone(),
/// resources[1].clone(),
/// resources[2].clone(),
/// tree_config_buffer,
/// );
/// ```
#[cfg(not(target_arch = "wasm32"))]
pub fn new_with_params<R: Read>(
tree_height: usize,
circom_vec: Vec<u8>,
zkey_vec: Vec<u8>,
vk_vec: Vec<u8>,
mut tree_config_input: R,
) -> Result<RLN<'static>> {
#[cfg(not(target_arch = "wasm32"))]
let witness_calculator = circom_from_raw(circom_vec)?;
let proving_key = zkey_from_raw(&zkey_vec)?;
let verification_key = vk_from_raw(&vk_vec, &zkey_vec)?;
let mut tree_config_vec: Vec<u8> = Vec::new();
tree_config_input.read_to_end(&mut tree_config_vec)?;
let tree_config_str = String::from_utf8(tree_config_vec)?;
let tree_config: <PoseidonTree as ZerokitMerkleTree>::Config = if tree_config_str.is_empty()
{
<PoseidonTree as ZerokitMerkleTree>::Config::default()
} else {
<PoseidonTree as ZerokitMerkleTree>::Config::from_str(&tree_config_str)?
};
// We compute a default empty tree
let tree = PoseidonTree::new(
tree_height,
<PoseidonTree as ZerokitMerkleTree>::Hasher::default_leaf(),
tree_config,
)?;
Ok(RLN {
witness_calculator,
proving_key,
verification_key,
tree,
})
}
#[cfg(target_arch = "wasm32")]
pub fn new_with_params(
tree_height: usize,
#[cfg(not(target_arch = "wasm32"))] circom_vec: Vec<u8>,
zkey_vec: Vec<u8>,
vk_vec: Vec<u8>,
) -> Result<RLN<'static>> {
@@ -159,12 +205,9 @@ impl RLN<'_> {
let tree = PoseidonTree::default(tree_height)?;
Ok(RLN {
#[cfg(not(target_arch = "wasm32"))]
witness_calculator,
proving_key,
verification_key,
tree,
#[cfg(target_arch = "wasm32")]
_marker: PhantomData,
})
}
@@ -362,10 +405,14 @@ impl RLN<'_> {
// We set the leaves
self.tree
.override_range(index, leaves, indices)
.map_err(|_| Report::msg("Could not perform the batch operation"))?;
.map_err(|e| Report::msg(format!("Could not perform the batch operation: {e}")))?;
Ok(())
}
pub fn leaves_set(&mut self) -> usize {
self.tree.leaves_set()
}
/// 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`.
@@ -676,9 +723,9 @@ impl RLN<'_> {
mut output_data: W,
) -> Result<()> {
// We read input RLN witness and we serialize_compressed it
let mut witness_byte: Vec<u8> = Vec::new();
input_data.read_to_end(&mut witness_byte)?;
let (rln_witness, _) = proof_inputs_to_rln_witness(&mut self.tree, &witness_byte)?;
let mut input_byte: Vec<u8> = Vec::new();
input_data.read_to_end(&mut input_byte)?;
let (rln_witness, _) = proof_inputs_to_rln_witness(&mut self.tree, &input_byte)?;
let proof_values = proof_values_from_witness(&rln_witness);
let proof = generate_proof(self.witness_calculator, &self.proving_key, &rln_witness)?;
@@ -691,12 +738,33 @@ impl RLN<'_> {
Ok(())
}
// 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> ]
// we skip it from documentation for now
#[doc(hidden)]
#[cfg(not(target_arch = "wasm32"))]
pub fn generate_rln_proof_with_witness<R: Read, W: Write>(
&mut self,
mut input_data: R,
mut output_data: W,
) -> Result<()> {
let mut witness_byte: Vec<u8> = Vec::new();
input_data.read_to_end(&mut witness_byte)?;
let (rln_witness, _) = deserialize_witness(&witness_byte)?;
let proof_values = proof_values_from_witness(&rln_witness);
let proof = generate_proof(self.witness_calculator, &self.proving_key, &rln_witness)?;
// Note: we export a serialization of ark-groth16::Proof not semaphore::Proof
// This proof is compressed, i.e. 128 bytes long
proof.serialize_compressed(&mut output_data)?;
output_data.write_all(&serialize_proof_values(&proof_values))?;
Ok(())
}
// Different in wasm since witness_calculator is not available
// See: https://github.com/vacp2p/zerokit/blob/b903d8d740e0b8b82057bcc5377ddce05ae5676b/rln/src/public.rs#L47-L49
#[cfg(target_arch = "wasm32")]
pub fn generate_rln_proof_with_witness<W: Write>(
&mut self,
calculated_witness: Vec<BigInt>,
@@ -1126,6 +1194,7 @@ impl RLN<'_> {
///
/// 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]) -> Result<serde_json::Value> {
panic::set_hook(Box::new(console_error_panic_hook::hook));
let (rln_witness, _) = deserialize_witness(serialized_witness)?;
get_json_inputs(&rln_witness)
}
@@ -1387,7 +1456,7 @@ mod test {
assert_eq!(root_batch_with_init, root_single_additions);
rln.flush();
rln.flush().unwrap();
}
#[test]
@@ -1430,7 +1499,7 @@ mod test {
let indices_buffer = Cursor::new(vec_u8_to_bytes_le(&indices).unwrap());
let leaves_buffer = Cursor::new(vec_fr_to_bytes_le(&last_leaf).unwrap());
rln.atomic_operation(no_of_leaves, leaves_buffer, indices_buffer)
rln.atomic_operation(last_leaf_index, leaves_buffer, indices_buffer)
.unwrap();
// We get the root of the tree obtained after a no-op
@@ -1441,6 +1510,105 @@ mod test {
assert_eq!(root_after_insertion, root_after_noop);
}
#[test]
fn test_atomic_operation_zero_indexed() {
// Test duplicated from https://github.com/waku-org/go-zerokit-rln/pull/12/files
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));
}
// We create a new tree
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
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_after_insertion, _) = bytes_le_to_fr(&buffer.into_inner());
let zero_index = 0;
let indices = vec![zero_index as u8];
let zero_leaf: Vec<Fr> = vec![];
let indices_buffer = Cursor::new(vec_u8_to_bytes_le(&indices).unwrap());
let leaves_buffer = Cursor::new(vec_fr_to_bytes_le(&zero_leaf).unwrap());
rln.atomic_operation(0, leaves_buffer, indices_buffer)
.unwrap();
// We get the root of the tree obtained after a deletion
let mut buffer = Cursor::new(Vec::<u8>::new());
rln.get_root(&mut buffer).unwrap();
let (root_after_deletion, _) = bytes_le_to_fr(&buffer.into_inner());
assert_ne!(root_after_insertion, root_after_deletion);
}
#[test]
fn test_atomic_operation_consistency() {
// Test duplicated from https://github.com/waku-org/go-zerokit-rln/pull/12/files
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));
}
// We create a new tree
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let mut rln = RLN::new(tree_height, input_buffer).unwrap();
// We add leaves in a batch into the tree
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves).unwrap());
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_after_insertion, _) = bytes_le_to_fr(&buffer.into_inner());
let set_index = rng.gen_range(0..no_of_leaves) as usize;
let indices = vec![set_index as u8];
let zero_leaf: Vec<Fr> = vec![];
let indices_buffer = Cursor::new(vec_u8_to_bytes_le(&indices).unwrap());
let leaves_buffer = Cursor::new(vec_fr_to_bytes_le(&zero_leaf).unwrap());
rln.atomic_operation(0, leaves_buffer, indices_buffer)
.unwrap();
// We get the root of the tree obtained after a deletion
let mut buffer = Cursor::new(Vec::<u8>::new());
rln.get_root(&mut buffer).unwrap();
let (root_after_deletion, _) = bytes_le_to_fr(&buffer.into_inner());
assert_ne!(root_after_insertion, root_after_deletion);
// We get the leaf
let mut output_buffer = Cursor::new(Vec::<u8>::new());
rln.get_leaf(set_index, &mut output_buffer).unwrap();
let (received_leaf, _) = bytes_le_to_fr(output_buffer.into_inner().as_ref());
assert_eq!(received_leaf, Fr::from(0));
}
#[allow(unused_must_use)]
#[test]
// This test checks if `set_leaves_from` throws an error when the index is out of bounds
@@ -1657,13 +1825,10 @@ mod test {
.collect();
// Generating the proof
let mut input_buffer = Cursor::new(serialized_witness);
let mut output_buffer = Cursor::new(Vec::<u8>::new());
rln.generate_rln_proof_with_witness(
calculated_witness_vec,
serialized_witness,
&mut output_buffer,
)
.unwrap();
rln.generate_rln_proof_with_witness(&mut input_buffer, &mut output_buffer)
.unwrap();
// output_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();
@@ -1947,4 +2112,19 @@ mod test {
assert_eq!(arbitrary_metadata, received_metadata);
}
#[test]
fn test_empty_metadata() {
let tree_height = TEST_TREE_HEIGHT;
let input_buffer =
Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string());
let rln = RLN::new(tree_height, input_buffer).unwrap();
let mut buffer = Cursor::new(Vec::<u8>::new());
rln.get_metadata(&mut buffer).unwrap();
let received_metadata = buffer.into_inner();
assert_eq!(received_metadata.len(), 0);
}
}

View File

@@ -143,6 +143,8 @@ mod test {
assert!(success, "RLN object creation failed");
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
assert_eq!(rln_pointer.leaves_set(), 0);
// We generate a vector of random leaves
let mut leaves: Vec<Fr> = Vec::new();
let mut rng = thread_rng();
@@ -159,6 +161,7 @@ mod test {
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");
assert_eq!(rln_pointer.leaves_set(), no_of_leaves);
// We get the root of the tree obtained adding leaves in batch
let mut output_buffer = MaybeUninit::<Buffer>::uninit();
@@ -265,7 +268,7 @@ mod test {
let success = atomic_operation(
rln_pointer,
no_of_leaves as usize,
last_leaf_index as usize,
leaves_buffer,
indices_buffer,
);
@@ -617,11 +620,14 @@ mod test {
// Creating a RLN instance passing the raw data
let mut rln_pointer_raw_bytes = MaybeUninit::<*mut RLN>::uninit();
let tree_config = "".to_string();
let tree_config_buffer = &Buffer::from(tree_config.as_bytes());
let success = new_with_params(
tree_height,
circom_data,
zkey_data,
vk_data,
tree_config_buffer,
rln_pointer_raw_bytes.as_mut_ptr(),
);
assert!(success, "RLN object creation failed");
@@ -1203,7 +1209,7 @@ mod test {
}
#[test]
fn test_metadata() {
fn test_valid_metadata() {
// We create a RLN instance
let tree_height = TEST_TREE_HEIGHT;
@@ -1229,4 +1235,25 @@ mod test {
assert_eq!(result_data, seed_bytes.to_vec());
}
#[test]
fn test_empty_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 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() };
assert_eq!(output_buffer.len, 0);
}
}

View File

@@ -1,6 +1,6 @@
[package]
name = "semaphore-wrapper"
version = "0.1.0"
version = "0.3.0"
edition = "2021"
license = "MIT OR Apache-2.0"
@@ -47,4 +47,4 @@ opt-level = 3
# Dependencies are optimized, even in a dev build. This improves dev performance
# while having neglible impact on incremental build times.
[profile.dev.package."*"]
opt-level = 3
opt-level = 3

View File

@@ -1,9 +1,12 @@
[package]
name = "zerokit_utils"
version = "0.1.0"
version = "0.3.2"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Various utilities for Zerokit"
documentation = "https://github.com/vacp2p/zerokit"
homepage = "https://vac.dev"
repository = "https://github.com/vacp2p/zerokit"
[lib]
bench = false
@@ -12,7 +15,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 = { package = "vacp2p_pmtree", version = "=1.0.0", optional = true}
pmtree = { package = "pmtree", version = "=2.0.0", optional = true}
sled = "=0.34.7"
serde = "=1.0.163"

View File

@@ -2,29 +2,51 @@ use pmtree::*;
use sled::Db as Sled;
use std::collections::HashMap;
use std::thread;
use std::time::Duration;
pub struct SledDB(Sled);
impl SledDB {
fn new_with_tries(config: <SledDB as Database>::Config, tries: u32) -> PmtreeResult<Self> {
// If we've tried more than 10 times, we give up and return an error.
if tries >= 10 {
return Err(PmtreeErrorKind::DatabaseError(
DatabaseErrorKind::CustomError(format!(
"Cannot create database: exceeded maximum retry attempts. {config:#?}"
)),
));
}
match config.open() {
Ok(db) => Ok(SledDB(db)),
Err(e) if e.to_string().contains("WouldBlock") => {
// try till the fd is freed
// sleep for 10^tries milliseconds, then recursively try again
thread::sleep(Duration::from_millis(10u64.pow(tries)));
Self::new_with_tries(config, tries + 1)
}
Err(e) => {
// On any other error, we return immediately.
Err(PmtreeErrorKind::DatabaseError(
DatabaseErrorKind::CustomError(format!(
"Cannot create database: {e} {config:#?}"
)),
))
}
}
}
}
impl Database for SledDB {
type Config = sled::Config;
fn new(config: Self::Config) -> PmtreeResult<Self> {
let db: Sled = match config.open() {
Ok(db) => db,
Err(e) => {
return Err(PmtreeErrorKind::DatabaseError(
DatabaseErrorKind::CustomError(format!(
"Cannot create database: {e} {config:#?}",
)),
))
}
};
Ok(SledDB(db))
let db = Self::new_with_tries(config, 0)?;
Ok(db)
}
fn load(config: Self::Config) -> PmtreeResult<Self> {
let db: Sled = match sled::open(&config.path) {
let db = match config.open() {
Ok(db) => db,
Err(e) => {
return Err(PmtreeErrorKind::DatabaseError(