mirror of
https://github.com/vacp2p/zerokit.git
synced 2026-01-09 05:38:06 -05:00
fix(rln): resolve memory leak in calc_witness and improve FFI memory deallocation pattern (#354)
This commit is contained in:
@@ -39,15 +39,18 @@ once_cell = "1.21.3"
|
||||
lazy_static = "1.5.0"
|
||||
rand = "0.8.5"
|
||||
rand_chacha = "0.3.1"
|
||||
ruint = { version = "1.17.0", default-features = false, features = ["rand", "serde", "ark-ff-05"] }
|
||||
ruint = { version = "1.17.0", default-features = false, features = [
|
||||
"rand",
|
||||
"serde",
|
||||
"ark-ff-05",
|
||||
] }
|
||||
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
|
||||
zeroize = "1.8"
|
||||
zeroize = "1.8.2"
|
||||
tempfile = "3.21.0"
|
||||
utils = { package = "zerokit_utils", version = "0.7.0", path = "../utils", default-features = false }
|
||||
|
||||
# FFI
|
||||
safer-ffi.version = "0.1"
|
||||
safer-ffi.features = [] # you may add some later on.
|
||||
|
||||
# serialization
|
||||
prost = "0.14.1"
|
||||
|
||||
@@ -323,7 +323,7 @@ Working examples demonstrating proof generation, proof verification and slashing
|
||||
|
||||
### Memory Management
|
||||
|
||||
All heap-allocated objects must be explicitly freed using their corresponding `_free` functions to prevent memory leaks.
|
||||
- All **heap-allocated** objects returned from Rust FFI **must** be freed using their corresponding FFI `_free` functions.
|
||||
|
||||
## Get involved
|
||||
|
||||
|
||||
@@ -4,65 +4,67 @@
|
||||
|
||||
#include "rln.h"
|
||||
|
||||
int main (int argc, char const * const argv[])
|
||||
int main(int argc, char const *const argv[])
|
||||
{
|
||||
printf("Creating RLN instance\n");
|
||||
|
||||
#ifdef STATELESS
|
||||
CResult_FFI_RLN_ptr_Vec_uint8_t ffi_new_result = ffi_new();
|
||||
CResult_FFI_RLN_ptr_Vec_uint8_t ffi_rln_new_result = ffi_rln_new();
|
||||
#else
|
||||
const char* config_path = "../resources/tree_depth_20/config.json";
|
||||
CResult_FFI_RLN_ptr_Vec_uint8_t ffi_new_result = ffi_new(20, config_path);
|
||||
const char *config_path = "../resources/tree_depth_20/config.json";
|
||||
CResult_FFI_RLN_ptr_Vec_uint8_t ffi_rln_new_result = ffi_rln_new(20, config_path);
|
||||
#endif
|
||||
|
||||
if (!ffi_new_result.ok) {
|
||||
fprintf(stderr, "%s", ffi_new_result.err.ptr);
|
||||
if (!ffi_rln_new_result.ok)
|
||||
{
|
||||
fprintf(stderr, "Initial RLN instance creation error: %s\n", ffi_rln_new_result.err.ptr);
|
||||
c_string_free(ffi_rln_new_result.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
FFI_RLN_t* rln = ffi_new_result.ok;
|
||||
FFI_RLN_t *rln = ffi_rln_new_result.ok;
|
||||
printf("RLN instance created successfully\n");
|
||||
|
||||
printf("\nGenerating identity keys\n");
|
||||
Vec_CFr_t keys = ffi_key_gen();
|
||||
CFr_t* identity_secret = (CFr_t*)vec_cfr_get(&keys, 0);
|
||||
CFr_t* id_commitment = (CFr_t*)vec_cfr_get(&keys, 1);
|
||||
const CFr_t *identity_secret = vec_cfr_get(&keys, 0);
|
||||
const CFr_t *id_commitment = vec_cfr_get(&keys, 1);
|
||||
printf("Identity generated\n");
|
||||
|
||||
Vec_uint8_t debug = cfr_debug(identity_secret);
|
||||
printf(" - identity_secret = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
debug = cfr_debug(id_commitment);
|
||||
printf(" - id_commitment = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nCreating message limit\n");
|
||||
CFr_t* user_message_limit = uint_to_cfr(1);
|
||||
CFr_t *user_message_limit = uint_to_cfr(1);
|
||||
|
||||
debug = cfr_debug(user_message_limit);
|
||||
printf(" - user_message_limit = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nComputing rate commitment\n");
|
||||
CFr_t* rate_commitment = ffi_poseidon_hash_pair(id_commitment, user_message_limit);
|
||||
CFr_t *rate_commitment = ffi_poseidon_hash_pair(id_commitment, user_message_limit);
|
||||
|
||||
debug = cfr_debug(rate_commitment);
|
||||
printf(" - rate_commitment = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nCFr serialization: CFr <-> bytes\n");
|
||||
Vec_uint8_t ser_rate_commitment = cfr_to_bytes_le(rate_commitment);
|
||||
|
||||
debug = vec_u8_debug(&ser_rate_commitment);
|
||||
printf(" - serialized rate_commitment = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
CFr_t* deser_rate_commitment = bytes_le_to_cfr(&ser_rate_commitment);
|
||||
CFr_t *deser_rate_commitment = bytes_le_to_cfr(&ser_rate_commitment);
|
||||
|
||||
debug = cfr_debug(deser_rate_commitment);
|
||||
printf(" - deserialized rate_commitment = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
vec_u8_free(ser_rate_commitment);
|
||||
cfr_free(deser_rate_commitment);
|
||||
@@ -72,109 +74,120 @@ int main (int argc, char const * const argv[])
|
||||
|
||||
debug = vec_u8_debug(&ser_keys);
|
||||
printf(" - serialized keys = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
CResult_Vec_CFr_ptr_Vec_uint8_t deser_keys_result = bytes_le_to_vec_cfr(&ser_keys);
|
||||
if (!deser_keys_result.ok) {
|
||||
fprintf(stderr, "%s", deser_keys_result.err.ptr);
|
||||
CResult_Vec_CFr_Vec_uint8_t deser_keys_result = bytes_le_to_vec_cfr(&ser_keys);
|
||||
if (deser_keys_result.err.ptr)
|
||||
{
|
||||
fprintf(stderr, "Keys deserialization error: %s\n", deser_keys_result.err.ptr);
|
||||
c_string_free(deser_keys_result.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
debug = vec_cfr_debug(deser_keys_result.ok);
|
||||
debug = vec_cfr_debug(&deser_keys_result.ok);
|
||||
printf(" - deserialized identity_secret = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
Vec_CFr_t deser_keys = deser_keys_result.ok;
|
||||
vec_cfr_free(deser_keys);
|
||||
|
||||
vec_u8_free(ser_keys);
|
||||
vec_cfr_free(*deser_keys_result.ok);
|
||||
|
||||
#ifdef STATELESS
|
||||
const size_t TREE_DEPTH = 20;
|
||||
const size_t CFR_SIZE = 32;
|
||||
#define TREE_DEPTH 20
|
||||
#define CFR_SIZE 32
|
||||
|
||||
printf("\nBuilding Merkle path for stateless mode\n");
|
||||
CFr_t* default_leaf = cfr_zero();
|
||||
CFr_t *default_leaf = cfr_zero();
|
||||
|
||||
CFr_t* default_hashes[TREE_DEPTH - 1];
|
||||
CFr_t *default_hashes[TREE_DEPTH - 1];
|
||||
default_hashes[0] = ffi_poseidon_hash_pair(default_leaf, default_leaf);
|
||||
for (size_t i = 1; i < TREE_DEPTH - 1; i++) {
|
||||
default_hashes[i] = ffi_poseidon_hash_pair(default_hashes[i-1], default_hashes[i-1]);
|
||||
for (size_t i = 1; i < TREE_DEPTH - 1; i++)
|
||||
{
|
||||
default_hashes[i] = ffi_poseidon_hash_pair(default_hashes[i - 1], default_hashes[i - 1]);
|
||||
}
|
||||
|
||||
void* path_elements_buffer = malloc(CFR_SIZE * TREE_DEPTH);
|
||||
memcpy(path_elements_buffer, default_leaf, CFR_SIZE);
|
||||
for (size_t i = 1; i < TREE_DEPTH; i++) {
|
||||
memcpy((char*)path_elements_buffer + (i * CFR_SIZE), default_hashes[i-1], CFR_SIZE);
|
||||
Vec_CFr_t path_elements = vec_cfr_new(TREE_DEPTH);
|
||||
vec_cfr_push(&path_elements, default_leaf);
|
||||
for (size_t i = 0; i < TREE_DEPTH - 1; i++)
|
||||
{
|
||||
vec_cfr_push(&path_elements, default_hashes[i]);
|
||||
}
|
||||
Vec_CFr_t path_elements = {
|
||||
.ptr = (CFr_t*)path_elements_buffer,
|
||||
.len = TREE_DEPTH,
|
||||
.cap = TREE_DEPTH
|
||||
};
|
||||
|
||||
printf("\nVec<CFr> serialization: Vec<CFr> <-> bytes\n");
|
||||
Vec_uint8_t ser_path_elements = vec_cfr_to_bytes_le(&path_elements);
|
||||
|
||||
debug = vec_u8_debug(&ser_path_elements);
|
||||
printf(" - serialized path_elements = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
CResult_Vec_CFr_ptr_Vec_uint8_t deser_path_elements = bytes_le_to_vec_cfr(&ser_path_elements);
|
||||
if (!deser_path_elements.ok) {
|
||||
fprintf(stderr, "%s", deser_path_elements.err.ptr);
|
||||
CResult_Vec_CFr_Vec_uint8_t deser_path_elements_result = bytes_le_to_vec_cfr(&ser_path_elements);
|
||||
if (deser_path_elements_result.err.ptr)
|
||||
{
|
||||
fprintf(stderr, "Path elements deserialization error: %s\n", deser_path_elements_result.err.ptr);
|
||||
c_string_free(deser_path_elements_result.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
debug = vec_cfr_debug(deser_path_elements.ok);
|
||||
debug = vec_cfr_debug(&deser_path_elements_result.ok);
|
||||
printf(" - deserialized path_elements = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
Vec_CFr_t deser_path_elements = deser_path_elements_result.ok;
|
||||
vec_cfr_free(deser_path_elements);
|
||||
|
||||
vec_cfr_free(*deser_path_elements.ok);
|
||||
vec_u8_free(ser_path_elements);
|
||||
|
||||
uint8_t* path_index_arr = calloc(TREE_DEPTH, sizeof(uint8_t));
|
||||
uint8_t path_index_arr[TREE_DEPTH] = {0};
|
||||
Vec_uint8_t identity_path_index = {
|
||||
.ptr = path_index_arr,
|
||||
.len = TREE_DEPTH,
|
||||
.cap = TREE_DEPTH
|
||||
};
|
||||
.cap = TREE_DEPTH};
|
||||
|
||||
printf("\nVec<uint8> serialization: Vec<uint8> <-> bytes\n");
|
||||
Vec_uint8_t ser_path_index = vec_u8_to_bytes_le(&identity_path_index);
|
||||
|
||||
debug = vec_u8_debug(&ser_path_index);
|
||||
printf(" - serialized path_index = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
CResult_Vec_uint8_ptr_Vec_uint8_t deser_path_index = bytes_le_to_vec_u8(&ser_path_index);
|
||||
if (!deser_path_index.ok) {
|
||||
fprintf(stderr, "%s", deser_path_index.err.ptr);
|
||||
CResult_Vec_uint8_Vec_uint8_t deser_path_index_result = bytes_le_to_vec_u8(&ser_path_index);
|
||||
if (deser_path_index_result.err.ptr)
|
||||
{
|
||||
fprintf(stderr, "Path index deserialization error: %s\n", deser_path_index_result.err.ptr);
|
||||
c_string_free(deser_path_index_result.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
debug = vec_u8_debug(deser_path_index.ok);
|
||||
debug = vec_u8_debug(&deser_path_index_result.ok);
|
||||
printf(" - deserialized path_index = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
Vec_uint8_t deser_path_index = deser_path_index_result.ok;
|
||||
vec_u8_free(deser_path_index);
|
||||
|
||||
vec_u8_free(*deser_path_index.ok);
|
||||
vec_u8_free(ser_path_index);
|
||||
|
||||
printf("\nComputing Merkle root for stateless mode\n");
|
||||
printf(" - computing root for index 0 with rate_commitment\n");
|
||||
CFr_t* computed_root = ffi_poseidon_hash_pair(rate_commitment, default_leaf);
|
||||
for (size_t i = 1; i < TREE_DEPTH; i++) {
|
||||
CFr_t* next_root = ffi_poseidon_hash_pair(computed_root, default_hashes[i-1]);
|
||||
CFr_t *computed_root = ffi_poseidon_hash_pair(rate_commitment, default_leaf);
|
||||
for (size_t i = 1; i < TREE_DEPTH; i++)
|
||||
{
|
||||
CFr_t *next_root = ffi_poseidon_hash_pair(computed_root, default_hashes[i - 1]);
|
||||
cfr_free(computed_root);
|
||||
computed_root = next_root;
|
||||
}
|
||||
|
||||
debug = cfr_debug(computed_root);
|
||||
printf(" - computed_root = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
#else
|
||||
printf("\nAdding rate_commitment to tree\n");
|
||||
CResult_bool_ptr_Vec_uint8_t set_result = ffi_set_next_leaf(&rln, &rate_commitment);
|
||||
if (!set_result.ok) {
|
||||
fprintf(stderr, "%s", set_result.err.ptr);
|
||||
CBoolResult_t set_err = ffi_set_next_leaf(&rln, &rate_commitment);
|
||||
if (!set_err.ok)
|
||||
{
|
||||
fprintf(stderr, "Set next leaf error: %s\n", set_err.err.ptr);
|
||||
c_string_free(set_err.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -183,54 +196,56 @@ int main (int argc, char const * const argv[])
|
||||
|
||||
printf("\nGetting Merkle proof\n");
|
||||
CResult_FFI_MerkleProof_ptr_Vec_uint8_t proof_result = ffi_get_proof(&rln, leaf_index);
|
||||
if (!proof_result.ok) {
|
||||
fprintf(stderr, "%s", proof_result.err.ptr);
|
||||
if (!proof_result.ok)
|
||||
{
|
||||
fprintf(stderr, "Get proof error: %s\n", proof_result.err.ptr);
|
||||
c_string_free(proof_result.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
FFI_MerkleProof_t* merkle_proof = proof_result.ok;
|
||||
FFI_MerkleProof_t *merkle_proof = proof_result.ok;
|
||||
printf(" - proof obtained (depth: %zu)\n", merkle_proof->path_elements.len);
|
||||
#endif
|
||||
|
||||
printf("\nHashing signal\n");
|
||||
uint8_t signal[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
Vec_uint8_t signal_vec = {signal, 32, 32};
|
||||
CFr_t* x = ffi_hash_to_field_le(&signal_vec);
|
||||
CFr_t *x = ffi_hash_to_field_le(&signal_vec);
|
||||
|
||||
debug = cfr_debug(x);
|
||||
printf(" - x = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nHashing epoch\n");
|
||||
const char* epoch_str = "test-epoch";
|
||||
Vec_uint8_t epoch_vec = {(uint8_t*)epoch_str, strlen(epoch_str), strlen(epoch_str)};
|
||||
CFr_t* epoch = ffi_hash_to_field_le(&epoch_vec);
|
||||
const char *epoch_str = "test-epoch";
|
||||
Vec_uint8_t epoch_vec = {(uint8_t *)epoch_str, strlen(epoch_str), strlen(epoch_str)};
|
||||
CFr_t *epoch = ffi_hash_to_field_le(&epoch_vec);
|
||||
|
||||
debug = cfr_debug(epoch);
|
||||
printf(" - epoch = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nHashing RLN identifier\n");
|
||||
const char* rln_id_str = "test-rln-identifier";
|
||||
Vec_uint8_t rln_id_vec = {(uint8_t*)rln_id_str, strlen(rln_id_str), strlen(rln_id_str)};
|
||||
CFr_t* rln_identifier = ffi_hash_to_field_le(&rln_id_vec);
|
||||
const char *rln_id_str = "test-rln-identifier";
|
||||
Vec_uint8_t rln_id_vec = {(uint8_t *)rln_id_str, strlen(rln_id_str), strlen(rln_id_str)};
|
||||
CFr_t *rln_identifier = ffi_hash_to_field_le(&rln_id_vec);
|
||||
|
||||
debug = cfr_debug(rln_identifier);
|
||||
printf(" - rln_identifier = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nComputing Poseidon hash for external nullifier\n");
|
||||
CFr_t* external_nullifier = ffi_poseidon_hash_pair(epoch, rln_identifier);
|
||||
CFr_t *external_nullifier = ffi_poseidon_hash_pair(epoch, rln_identifier);
|
||||
|
||||
debug = cfr_debug(external_nullifier);
|
||||
printf(" - external_nullifier = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nCreating message_id\n");
|
||||
CFr_t* message_id = uint_to_cfr(0);
|
||||
CFr_t *message_id = uint_to_cfr(0);
|
||||
|
||||
debug = cfr_debug(message_id);
|
||||
printf(" - message_id = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nGenerating RLN Proof\n");
|
||||
#ifdef STATELESS
|
||||
@@ -242,8 +257,7 @@ int main (int argc, char const * const argv[])
|
||||
&path_elements,
|
||||
&identity_path_index,
|
||||
x,
|
||||
external_nullifier
|
||||
);
|
||||
external_nullifier);
|
||||
#else
|
||||
CResult_FFI_RLNProof_ptr_Vec_uint8_t proof_gen_result = ffi_generate_rln_proof(
|
||||
&rln,
|
||||
@@ -252,142 +266,135 @@ int main (int argc, char const * const argv[])
|
||||
message_id,
|
||||
x,
|
||||
external_nullifier,
|
||||
leaf_index
|
||||
);
|
||||
leaf_index);
|
||||
#endif
|
||||
FFI_RLNProof_t* rln_proof = NULL;
|
||||
|
||||
if (!proof_gen_result.ok) {
|
||||
fprintf(stderr, "Proof generation failed: %s\n", proof_gen_result.err.ptr);
|
||||
if (!proof_gen_result.ok)
|
||||
{
|
||||
fprintf(stderr, "Proof generation error: %s\n", proof_gen_result.err.ptr);
|
||||
c_string_free(proof_gen_result.err);
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
rln_proof = proof_gen_result.ok;
|
||||
printf("Proof generated successfully\n");
|
||||
|
||||
printf("\nVerifying Proof\n");
|
||||
#ifdef STATELESS
|
||||
Vec_CFr_t roots = {
|
||||
.ptr = computed_root,
|
||||
.len = 1,
|
||||
.cap = 1
|
||||
};
|
||||
CResult_bool_ptr_Vec_uint8_t verify_result = ffi_verify_with_roots(&rln, &rln_proof, &roots, x);
|
||||
#else
|
||||
CResult_bool_ptr_Vec_uint8_t verify_result = ffi_verify_rln_proof(&rln, &rln_proof, x);
|
||||
#endif
|
||||
if (!verify_result.ok) {
|
||||
fprintf(stderr, "Proof verification error: %s\n", verify_result.err.ptr);
|
||||
return EXIT_FAILURE;
|
||||
} else if (*verify_result.ok) {
|
||||
printf("Proof verified successfully\n");
|
||||
} else {
|
||||
printf("Proof verification failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("\nSimulating double-signaling attack (same epoch, different message)\n");
|
||||
|
||||
printf("\nHashing second signal\n");
|
||||
uint8_t signal2[32] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
|
||||
Vec_uint8_t signal2_vec = {signal2, 32, 32};
|
||||
CFr_t* x2 = ffi_hash_to_field_le(&signal2_vec);
|
||||
|
||||
debug = cfr_debug(x2);
|
||||
printf(" - x2 = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
|
||||
printf("\nCreating second message with the same id\n");
|
||||
CFr_t* message_id2 = uint_to_cfr(0);
|
||||
|
||||
debug = cfr_debug(message_id2);
|
||||
printf(" - message_id2 = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
|
||||
printf("\nGenerating second RLN Proof\n");
|
||||
#ifdef STATELESS
|
||||
CResult_FFI_RLNProof_ptr_Vec_uint8_t proof_gen_result2 = ffi_generate_rln_proof_stateless(
|
||||
&rln,
|
||||
identity_secret,
|
||||
user_message_limit,
|
||||
message_id2,
|
||||
&path_elements,
|
||||
&identity_path_index,
|
||||
x2,
|
||||
external_nullifier
|
||||
);
|
||||
#else
|
||||
CResult_FFI_RLNProof_ptr_Vec_uint8_t proof_gen_result2 = ffi_generate_rln_proof(
|
||||
&rln,
|
||||
identity_secret,
|
||||
user_message_limit,
|
||||
message_id2,
|
||||
x2,
|
||||
external_nullifier,
|
||||
leaf_index
|
||||
);
|
||||
#endif
|
||||
FFI_RLNProof_t* rln_proof2 = NULL;
|
||||
|
||||
if (!proof_gen_result2.ok) {
|
||||
fprintf(stderr, "Second proof generation failed: %s\n", proof_gen_result2.err.ptr);
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
rln_proof2 = proof_gen_result2.ok;
|
||||
printf("Second proof generated successfully\n");
|
||||
|
||||
printf("\nVerifying second proof\n");
|
||||
#ifdef STATELESS
|
||||
CResult_bool_ptr_Vec_uint8_t verify_result2 = ffi_verify_with_roots(&rln, &rln_proof2, &roots, x2);
|
||||
#else
|
||||
CResult_bool_ptr_Vec_uint8_t verify_result2 = ffi_verify_rln_proof(&rln, &rln_proof2, x2);
|
||||
#endif
|
||||
if (!verify_result2.ok) {
|
||||
fprintf(stderr, "Second proof verification error: %s\n", verify_result2.err.ptr);
|
||||
return EXIT_FAILURE;
|
||||
} else if (*verify_result2.ok) {
|
||||
printf("Second proof verified successfully\n");
|
||||
|
||||
printf("\nRecovering identity secret\n");
|
||||
CResult_CFr_ptr_Vec_uint8_t recover_result = ffi_recover_id_secret(&rln_proof, &rln_proof2);
|
||||
if (!recover_result.ok) {
|
||||
fprintf(stderr, "Identity recovery error: %s\n", recover_result.err.ptr);
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
CFr_t* recovered_secret = recover_result.ok;
|
||||
|
||||
debug = cfr_debug(recovered_secret);
|
||||
printf(" - recovered_secret = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
|
||||
debug = cfr_debug(identity_secret);
|
||||
printf(" - original_secret = %s\n", debug.ptr);
|
||||
vec_u8_free(debug);
|
||||
|
||||
printf("Slashing successful: Identity is recovered!\n");
|
||||
|
||||
cfr_free(recovered_secret);
|
||||
}
|
||||
} else {
|
||||
printf("Second proof verification failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (rln_proof2) {
|
||||
ffi_rln_proof_free(rln_proof2);
|
||||
}
|
||||
cfr_free(x2);
|
||||
cfr_free(message_id2);
|
||||
}
|
||||
|
||||
if (rln_proof) {
|
||||
ffi_rln_proof_free(rln_proof);
|
||||
FFI_RLNProof_t *rln_proof = proof_gen_result.ok;
|
||||
printf("Proof generated successfully\n");
|
||||
|
||||
printf("\nVerifying Proof\n");
|
||||
#ifdef STATELESS
|
||||
Vec_CFr_t roots = vec_cfr_from_cfr(computed_root);
|
||||
CBoolResult_t verify_err = ffi_verify_with_roots(&rln, &rln_proof, &roots, x);
|
||||
#else
|
||||
CBoolResult_t verify_err = ffi_verify_rln_proof(&rln, &rln_proof, x);
|
||||
#endif
|
||||
|
||||
if (!verify_err.ok)
|
||||
{
|
||||
fprintf(stderr, "Proof verification error: %s\n", verify_err.err.ptr);
|
||||
c_string_free(verify_err.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("Proof verified successfully\n");
|
||||
|
||||
printf("\nSimulating double-signaling attack (same epoch, different message)\n");
|
||||
|
||||
printf("\nHashing second signal\n");
|
||||
uint8_t signal2[32] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
|
||||
Vec_uint8_t signal2_vec = {signal2, 32, 32};
|
||||
CFr_t *x2 = ffi_hash_to_field_le(&signal2_vec);
|
||||
|
||||
debug = cfr_debug(x2);
|
||||
printf(" - x2 = %s\n", debug.ptr);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nCreating second message with the same id\n");
|
||||
CFr_t *message_id2 = uint_to_cfr(0);
|
||||
|
||||
debug = cfr_debug(message_id2);
|
||||
printf(" - message_id2 = %s\n", debug.ptr);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("\nGenerating second RLN Proof\n");
|
||||
#ifdef STATELESS
|
||||
free(path_index_arr);
|
||||
free(path_elements_buffer);
|
||||
for (size_t i = 0; i < TREE_DEPTH - 1; i++) {
|
||||
CResult_FFI_RLNProof_ptr_Vec_uint8_t proof_gen_result2 = ffi_generate_rln_proof_stateless(
|
||||
&rln,
|
||||
identity_secret,
|
||||
user_message_limit,
|
||||
message_id2,
|
||||
&path_elements,
|
||||
&identity_path_index,
|
||||
x2,
|
||||
external_nullifier);
|
||||
#else
|
||||
CResult_FFI_RLNProof_ptr_Vec_uint8_t proof_gen_result2 = ffi_generate_rln_proof(
|
||||
&rln,
|
||||
identity_secret,
|
||||
user_message_limit,
|
||||
message_id2,
|
||||
x2,
|
||||
external_nullifier,
|
||||
leaf_index);
|
||||
#endif
|
||||
|
||||
if (!proof_gen_result2.ok)
|
||||
{
|
||||
fprintf(stderr, "Second proof generation error: %s\n", proof_gen_result2.err.ptr);
|
||||
c_string_free(proof_gen_result2.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
FFI_RLNProof_t *rln_proof2 = proof_gen_result2.ok;
|
||||
printf("Second proof generated successfully\n");
|
||||
|
||||
printf("\nVerifying second proof\n");
|
||||
#ifdef STATELESS
|
||||
CBoolResult_t verify_err2 = ffi_verify_with_roots(&rln, &rln_proof2, &roots, x2);
|
||||
#else
|
||||
CBoolResult_t verify_err2 = ffi_verify_rln_proof(&rln, &rln_proof2, x2);
|
||||
#endif
|
||||
|
||||
if (!verify_err2.ok)
|
||||
{
|
||||
fprintf(stderr, "Proof verification error: %s\n", verify_err2.err.ptr);
|
||||
c_string_free(verify_err2.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("Second proof verified successfully\n");
|
||||
|
||||
printf("\nRecovering identity secret\n");
|
||||
CResult_CFr_ptr_Vec_uint8_t recover_result = ffi_recover_id_secret(&rln_proof, &rln_proof2);
|
||||
if (!recover_result.ok)
|
||||
{
|
||||
fprintf(stderr, "Identity recovery error: %s\n", recover_result.err.ptr);
|
||||
c_string_free(recover_result.err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CFr_t *recovered_secret = recover_result.ok;
|
||||
|
||||
debug = cfr_debug(recovered_secret);
|
||||
printf(" - recovered_secret = %s\n", debug.ptr);
|
||||
c_string_free(debug);
|
||||
|
||||
debug = cfr_debug(identity_secret);
|
||||
printf(" - original_secret = %s\n", debug.ptr);
|
||||
c_string_free(debug);
|
||||
|
||||
printf("Slashing successful: Identity is recovered!\n");
|
||||
|
||||
cfr_free(recovered_secret);
|
||||
|
||||
ffi_rln_proof_free(rln_proof2);
|
||||
cfr_free(x2);
|
||||
cfr_free(message_id2);
|
||||
ffi_rln_proof_free(rln_proof);
|
||||
|
||||
#ifdef STATELESS
|
||||
vec_cfr_free(roots);
|
||||
vec_cfr_free(path_elements);
|
||||
for (size_t i = 0; i < TREE_DEPTH - 1; i++)
|
||||
{
|
||||
cfr_free(default_hashes[i]);
|
||||
}
|
||||
cfr_free(default_leaf);
|
||||
@@ -405,5 +412,6 @@ int main (int argc, char const * const argv[])
|
||||
cfr_free(message_id);
|
||||
vec_cfr_free(keys);
|
||||
ffi_rln_free(rln);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -39,10 +39,6 @@ type
|
||||
path_elements*: Vec_CFr
|
||||
path_index*: Vec_uint8
|
||||
|
||||
CResultBoolPtrVecU8* = object
|
||||
ok*: ptr bool
|
||||
err*: Vec_uint8
|
||||
|
||||
CResultRLNPtrVecU8* = object
|
||||
ok*: ptr FFI_RLN
|
||||
err*: Vec_uint8
|
||||
@@ -59,12 +55,16 @@ type
|
||||
ok*: ptr FFI_MerkleProof
|
||||
err*: Vec_uint8
|
||||
|
||||
CResultVecCFrPtrVecU8* = object
|
||||
ok*: ptr Vec_CFr
|
||||
CResultVecCFrVecU8* = object
|
||||
ok*: Vec_CFr
|
||||
err*: Vec_uint8
|
||||
|
||||
CResultVecU8PtrVecU8* = object
|
||||
ok*: ptr Vec_uint8
|
||||
CResultVecU8VecU8* = object
|
||||
ok*: Vec_uint8
|
||||
err*: Vec_uint8
|
||||
|
||||
CBoolResult* = object
|
||||
ok*: bool
|
||||
err*: Vec_uint8
|
||||
|
||||
# CFr functions
|
||||
@@ -84,15 +84,23 @@ proc bytes_be_to_cfr*(bytes: ptr Vec_uint8): ptr CFr {.importc: "bytes_be_to_cfr
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
|
||||
# Vec<CFr> functions
|
||||
proc vec_cfr_new*(capacity: CSize): Vec_CFr {.importc: "vec_cfr_new", cdecl,
|
||||
dynlib: RLN_LIB.}
|
||||
proc vec_cfr_from_cfr*(cfr: ptr CFr): Vec_CFr {.importc: "vec_cfr_from_cfr",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc vec_cfr_push*(v: ptr Vec_CFr, cfr: ptr CFr) {.importc: "vec_cfr_push",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc vec_cfr_len*(v: ptr Vec_CFr): CSize {.importc: "vec_cfr_len", cdecl,
|
||||
dynlib: RLN_LIB.}
|
||||
proc vec_cfr_get*(v: ptr Vec_CFr, i: CSize): ptr CFr {.importc: "vec_cfr_get",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc vec_cfr_to_bytes_le*(v: ptr Vec_CFr): Vec_uint8 {.importc: "vec_cfr_to_bytes_le",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc vec_cfr_to_bytes_be*(v: ptr Vec_CFr): Vec_uint8 {.importc: "vec_cfr_to_bytes_be",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc bytes_le_to_vec_cfr*(bytes: ptr Vec_uint8): CResultVecCFrPtrVecU8 {.importc: "bytes_le_to_vec_cfr",
|
||||
proc bytes_le_to_vec_cfr*(bytes: ptr Vec_uint8): CResultVecCFrVecU8 {.importc: "bytes_le_to_vec_cfr",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc bytes_be_to_vec_cfr*(bytes: ptr Vec_uint8): CResultVecCFrPtrVecU8 {.importc: "bytes_be_to_vec_cfr",
|
||||
proc bytes_be_to_vec_cfr*(bytes: ptr Vec_uint8): CResultVecCFrVecU8 {.importc: "bytes_be_to_vec_cfr",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc vec_cfr_debug*(v: ptr Vec_CFr): Vec_uint8 {.importc: "vec_cfr_debug",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
@@ -104,9 +112,9 @@ proc vec_u8_to_bytes_le*(v: ptr Vec_uint8): Vec_uint8 {.importc: "vec_u8_to_byte
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc vec_u8_to_bytes_be*(v: ptr Vec_uint8): Vec_uint8 {.importc: "vec_u8_to_bytes_be",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc bytes_le_to_vec_u8*(bytes: ptr Vec_uint8): CResultVecU8PtrVecU8 {.importc: "bytes_le_to_vec_u8",
|
||||
proc bytes_le_to_vec_u8*(bytes: ptr Vec_uint8): CResultVecU8VecU8 {.importc: "bytes_le_to_vec_u8",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc bytes_be_to_vec_u8*(bytes: ptr Vec_uint8): CResultVecU8PtrVecU8 {.importc: "bytes_be_to_vec_u8",
|
||||
proc bytes_be_to_vec_u8*(bytes: ptr Vec_uint8): CResultVecU8VecU8 {.importc: "bytes_be_to_vec_u8",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc vec_u8_debug*(v: ptr Vec_uint8): Vec_uint8 {.importc: "vec_u8_debug",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
@@ -128,10 +136,10 @@ proc ffi_key_gen*(): Vec_CFr {.importc: "ffi_key_gen", cdecl,
|
||||
|
||||
# RLN instance functions
|
||||
when defined(ffiStateless):
|
||||
proc ffi_new*(): CResultRLNPtrVecU8 {.importc: "ffi_new", cdecl,
|
||||
proc ffi_rln_new*(): CResultRLNPtrVecU8 {.importc: "ffi_rln_new", cdecl,
|
||||
dynlib: RLN_LIB.}
|
||||
else:
|
||||
proc ffi_new*(treeDepth: CSize, config: cstring): CResultRLNPtrVecU8 {.importc: "ffi_new",
|
||||
proc ffi_rln_new*(treeDepth: CSize, config: cstring): CResultRLNPtrVecU8 {.importc: "ffi_rln_new",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
|
||||
proc ffi_rln_free*(rln: ptr FFI_RLN) {.importc: "ffi_rln_free", cdecl,
|
||||
@@ -168,14 +176,14 @@ when defined(ffiStateless):
|
||||
proof: ptr ptr FFI_RLNProof,
|
||||
roots: ptr Vec_CFr,
|
||||
x: ptr CFr
|
||||
): CResultBoolPtrVecU8 {.importc: "ffi_verify_with_roots", cdecl,
|
||||
): CBoolResult {.importc: "ffi_verify_with_roots", cdecl,
|
||||
dynlib: RLN_LIB.}
|
||||
else:
|
||||
proc ffi_verify_rln_proof*(
|
||||
rln: ptr ptr FFI_RLN,
|
||||
proof: ptr ptr FFI_RLNProof,
|
||||
x: ptr CFr
|
||||
): CResultBoolPtrVecU8 {.importc: "ffi_verify_rln_proof", cdecl,
|
||||
): CBoolResult {.importc: "ffi_verify_rln_proof", cdecl,
|
||||
dynlib: RLN_LIB.}
|
||||
|
||||
proc ffi_rln_proof_free*(p: ptr FFI_RLNProof) {.importc: "ffi_rln_proof_free",
|
||||
@@ -184,7 +192,7 @@ proc ffi_rln_proof_free*(p: ptr FFI_RLNProof) {.importc: "ffi_rln_proof_free",
|
||||
# Merkle tree operations (non-stateless mode)
|
||||
when not defined(ffiStateless):
|
||||
proc ffi_set_next_leaf*(rln: ptr ptr FFI_RLN,
|
||||
value: ptr ptr CFr): CResultBoolPtrVecU8 {.importc: "ffi_set_next_leaf",
|
||||
leaf: ptr ptr CFr): CBoolResult {.importc: "ffi_set_next_leaf",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
proc ffi_leaves_set*(rln: ptr ptr FFI_RLN): CSize {.importc: "ffi_leaves_set",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
@@ -199,7 +207,7 @@ proc ffi_recover_id_secret*(proof1: ptr ptr FFI_RLNProof,
|
||||
proof2: ptr ptr FFI_RLNProof): CResultCFrPtrVecU8 {.importc: "ffi_recover_id_secret",
|
||||
cdecl, dynlib: RLN_LIB.}
|
||||
|
||||
# Helpers
|
||||
# Helpers functions
|
||||
proc asVecU8*(buf: var seq[uint8]): Vec_uint8 =
|
||||
result.dataPtr = if buf.len == 0: nil else: addr buf[0]
|
||||
result.len = CSize(buf.len)
|
||||
@@ -210,18 +218,22 @@ proc asString*(v: Vec_uint8): string =
|
||||
result = newString(v.len.int)
|
||||
copyMem(addr result[0], v.dataPtr, v.len.int)
|
||||
|
||||
proc c_string_free*(s: Vec_uint8) {.importc: "c_string_free", cdecl,
|
||||
dynlib: RLN_LIB.}
|
||||
|
||||
when isMainModule:
|
||||
echo "Creating RLN instance"
|
||||
|
||||
var rlnRes: CResultRLNPtrVecU8
|
||||
when defined(ffiStateless):
|
||||
rlnRes = ffi_new()
|
||||
rlnRes = ffi_rln_new()
|
||||
else:
|
||||
let config_path = """../resources/tree_depth_20/config.json""".cstring
|
||||
rlnRes = ffi_new(CSize(20), config_path)
|
||||
rlnRes = ffi_rln_new(CSize(20), config_path)
|
||||
|
||||
if rlnRes.ok.isNil:
|
||||
stderr.writeLine "ffi_new error: ", asString(rlnRes.err)
|
||||
stderr.writeLine "Initial RLN instance creation error: ", asString(rlnRes.err)
|
||||
c_string_free(rlnRes.err)
|
||||
quit 1
|
||||
|
||||
var rln = rlnRes.ok
|
||||
@@ -236,12 +248,12 @@ when isMainModule:
|
||||
block:
|
||||
let debug = cfr_debug(identitySecret)
|
||||
echo " - identity_secret = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(idCommitment)
|
||||
echo " - id_commitment = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nCreating message limit"
|
||||
let userMessageLimit = uint_to_cfr(1'u32)
|
||||
@@ -249,7 +261,7 @@ when isMainModule:
|
||||
block:
|
||||
let debug = cfr_debug(userMessageLimit)
|
||||
echo " - user_message_limit = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nComputing rate commitment"
|
||||
let rateCommitment = ffi_poseidon_hash_pair(idCommitment, userMessageLimit)
|
||||
@@ -257,7 +269,7 @@ when isMainModule:
|
||||
block:
|
||||
let debug = cfr_debug(rateCommitment)
|
||||
echo " - rate_commitment = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nCFr serialization: CFr <-> bytes"
|
||||
var serRateCommitment = cfr_to_bytes_be(rateCommitment)
|
||||
@@ -265,14 +277,14 @@ when isMainModule:
|
||||
block:
|
||||
let debug = vec_u8_debug(addr serRateCommitment)
|
||||
echo " - serialized rate_commitment = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
let deserRateCommitment = bytes_be_to_cfr(addr serRateCommitment)
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(deserRateCommitment)
|
||||
echo " - deserialized rate_commitment = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
vec_u8_free(serRateCommitment)
|
||||
cfr_free(deserRateCommitment)
|
||||
@@ -283,21 +295,23 @@ when isMainModule:
|
||||
block:
|
||||
let debug = vec_u8_debug(addr serKeys)
|
||||
echo " - serialized keys = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
let deserKeysResult = bytes_be_to_vec_cfr(addr serKeys)
|
||||
if deserKeysResult.ok.isNil:
|
||||
stderr.writeLine "bytes_be_to_vec_cfr error: ", asString(
|
||||
if deserKeysResult.err.dataPtr != nil:
|
||||
stderr.writeLine "Keys deserialization error: ", asString(
|
||||
deserKeysResult.err)
|
||||
c_string_free(deserKeysResult.err)
|
||||
quit 1
|
||||
|
||||
block:
|
||||
let debug = vec_cfr_debug(deserKeysResult.ok)
|
||||
var okKeys = deserKeysResult.ok
|
||||
let debug = vec_cfr_debug(addr okKeys)
|
||||
echo " - deserialized identity_secret = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
vec_cfr_free(deserKeysResult.ok)
|
||||
vec_u8_free(serKeys)
|
||||
vec_cfr_free(deserKeysResult.ok[])
|
||||
|
||||
when defined(ffiStateless):
|
||||
const treeDepth = 20
|
||||
@@ -312,16 +326,10 @@ when isMainModule:
|
||||
defaultHashes[i] = ffi_poseidon_hash_pair(defaultHashes[i-1],
|
||||
defaultHashes[i-1])
|
||||
|
||||
var pathElemsBuffer = alloc(CFR_SIZE * treeDepth)
|
||||
copyMem(pathElemsBuffer, defaultLeaf, CFR_SIZE)
|
||||
for i in 1..treeDepth-1:
|
||||
copyMem(cast[pointer](cast[int](pathElemsBuffer) + i * CFR_SIZE),
|
||||
defaultHashes[i-1], CFR_SIZE)
|
||||
|
||||
var pathElements: Vec_CFr
|
||||
pathElements.dataPtr = cast[ptr CFr](pathElemsBuffer)
|
||||
pathElements.len = CSize(treeDepth)
|
||||
pathElements.cap = CSize(treeDepth)
|
||||
var pathElements = vec_cfr_new(CSize(treeDepth))
|
||||
vec_cfr_push(addr pathElements, defaultLeaf)
|
||||
for i in 0..treeDepth-2:
|
||||
vec_cfr_push(addr pathElements, defaultHashes[i])
|
||||
|
||||
echo "\nVec<CFr> serialization: Vec<CFr> <-> bytes"
|
||||
var serPathElements = vec_cfr_to_bytes_be(addr pathElements)
|
||||
@@ -329,20 +337,22 @@ when isMainModule:
|
||||
block:
|
||||
let debug = vec_u8_debug(addr serPathElements)
|
||||
echo " - serialized path_elements = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
let deserPathElements = bytes_be_to_vec_cfr(addr serPathElements)
|
||||
if deserPathElements.ok.isNil:
|
||||
stderr.writeLine "bytes_be_to_vec_cfr error: ", asString(
|
||||
if deserPathElements.err.dataPtr != nil:
|
||||
stderr.writeLine "Path elements deserialization error: ", asString(
|
||||
deserPathElements.err)
|
||||
c_string_free(deserPathElements.err)
|
||||
quit 1
|
||||
|
||||
block:
|
||||
let debug = vec_cfr_debug(deserPathElements.ok)
|
||||
var okPathElems = deserPathElements.ok
|
||||
let debug = vec_cfr_debug(addr okPathElems)
|
||||
echo " - deserialized path_elements = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
vec_cfr_free(deserPathElements.ok[])
|
||||
vec_cfr_free(deserPathElements.ok)
|
||||
vec_u8_free(serPathElements)
|
||||
|
||||
var pathIndexSeq = newSeq[uint8](treeDepth)
|
||||
@@ -354,20 +364,22 @@ when isMainModule:
|
||||
block:
|
||||
let debug = vec_u8_debug(addr serPathIndex)
|
||||
echo " - serialized path_index = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
let deserPathIndex = bytes_be_to_vec_u8(addr serPathIndex)
|
||||
if deserPathIndex.ok.isNil:
|
||||
stderr.writeLine "bytes_be_to_vec_u8 error: ", asString(
|
||||
if deserPathIndex.err.dataPtr != nil:
|
||||
stderr.writeLine "Path index deserialization error: ", asString(
|
||||
deserPathIndex.err)
|
||||
c_string_free(deserPathIndex.err)
|
||||
quit 1
|
||||
|
||||
block:
|
||||
let debug = vec_u8_debug(deserPathIndex.ok)
|
||||
var okPathIdx = deserPathIndex.ok
|
||||
let debug = vec_u8_debug(addr okPathIdx)
|
||||
echo " - deserialized path_index = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
vec_u8_free(deserPathIndex.ok[])
|
||||
vec_u8_free(deserPathIndex.ok)
|
||||
vec_u8_free(serPathIndex)
|
||||
|
||||
echo "\nComputing Merkle root for stateless mode"
|
||||
@@ -381,15 +393,14 @@ when isMainModule:
|
||||
block:
|
||||
let debug = cfr_debug(computedRoot)
|
||||
echo " - computed_root = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
else:
|
||||
echo "\nAdding rate_commitment to tree"
|
||||
var rcPtr = rateCommitment
|
||||
let setRes = ffi_set_next_leaf(addr rln, addr rcPtr)
|
||||
if setRes.ok.isNil or not setRes.ok[]:
|
||||
stderr.writeLine "set_next_leaf error: ", asString(setRes.err)
|
||||
vec_cfr_free(keys)
|
||||
ffi_rln_free(rln)
|
||||
let setErr = ffi_set_next_leaf(addr rln, addr rcPtr)
|
||||
if not setErr.ok:
|
||||
stderr.writeLine "Set next leaf error: ", asString(setErr.err)
|
||||
c_string_free(setErr.err)
|
||||
quit 1
|
||||
|
||||
let leafIndex = ffi_leaves_set(addr rln) - 1
|
||||
@@ -398,9 +409,8 @@ when isMainModule:
|
||||
echo "\nGetting Merkle proof"
|
||||
let proofResult = ffi_get_proof(addr rln, leafIndex)
|
||||
if proofResult.ok.isNil:
|
||||
stderr.writeLine "get_proof error: ", asString(proofResult.err)
|
||||
vec_cfr_free(keys)
|
||||
ffi_rln_free(rln)
|
||||
stderr.writeLine "Get proof error: ", asString(proofResult.err)
|
||||
c_string_free(proofResult.err)
|
||||
quit 1
|
||||
let merkleProof = proofResult.ok
|
||||
echo " - proof obtained (depth: ", merkleProof.path_elements.len, ")"
|
||||
@@ -410,36 +420,36 @@ when isMainModule:
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
var signalVec = Vec_uint8(dataPtr: cast[ptr uint8](addr signal[0]),
|
||||
len: CSize(signal.len), cap: CSize(signal.len))
|
||||
let x = ffi_hash_to_field_le(addr signalVec)
|
||||
let x = ffi_hash_to_field_be(addr signalVec)
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(x)
|
||||
echo " - x = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nHashing epoch"
|
||||
let epochStr = "test-epoch"
|
||||
var epochBytes = newSeq[uint8](epochStr.len)
|
||||
for i in 0..<epochStr.len: epochBytes[i] = uint8(epochStr[i])
|
||||
var epochVec = asVecU8(epochBytes)
|
||||
let epoch = ffi_hash_to_field_le(addr epochVec)
|
||||
let epoch = ffi_hash_to_field_be(addr epochVec)
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(epoch)
|
||||
echo " - epoch = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nHashing RLN identifier"
|
||||
let rlnIdStr = "test-rln-identifier"
|
||||
var rlnIdBytes = newSeq[uint8](rlnIdStr.len)
|
||||
for i in 0..<rlnIdStr.len: rlnIdBytes[i] = uint8(rlnIdStr[i])
|
||||
var rlnIdVec = asVecU8(rlnIdBytes)
|
||||
let rlnIdentifier = ffi_hash_to_field_le(addr rlnIdVec)
|
||||
let rlnIdentifier = ffi_hash_to_field_be(addr rlnIdVec)
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(rlnIdentifier)
|
||||
echo " - rln_identifier = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nComputing Poseidon hash for external nullifier"
|
||||
let externalNullifier = ffi_poseidon_hash_pair(epoch, rlnIdentifier)
|
||||
@@ -447,7 +457,7 @@ when isMainModule:
|
||||
block:
|
||||
let debug = cfr_debug(externalNullifier)
|
||||
echo " - external_nullifier = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nCreating message_id"
|
||||
let messageId = uint_to_cfr(0'u32)
|
||||
@@ -455,7 +465,7 @@ when isMainModule:
|
||||
block:
|
||||
let debug = cfr_debug(messageId)
|
||||
echo " - message_id = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nGenerating RLN Proof"
|
||||
var proofRes: CResultProofPtrVecU8
|
||||
@@ -468,7 +478,8 @@ when isMainModule:
|
||||
userMessageLimit, messageId, x, externalNullifier, leafIndex)
|
||||
|
||||
if proofRes.ok.isNil:
|
||||
stderr.writeLine "Proof generation failed: ", asString(proofRes.err)
|
||||
stderr.writeLine "Proof generation error: ", asString(proofRes.err)
|
||||
c_string_free(proofRes.err)
|
||||
quit 1
|
||||
|
||||
var proof = proofRes.ok
|
||||
@@ -476,23 +487,18 @@ when isMainModule:
|
||||
|
||||
echo "\nVerifying Proof"
|
||||
when defined(ffiStateless):
|
||||
var roots: Vec_CFr
|
||||
roots.dataPtr = computedRoot
|
||||
roots.len = CSize(1)
|
||||
roots.cap = CSize(1)
|
||||
let verifyRes = ffi_verify_with_roots(addr rln, addr proof, addr roots, x)
|
||||
var roots = vec_cfr_from_cfr(computedRoot)
|
||||
let verifyErr = ffi_verify_with_roots(addr rln, addr proof, addr roots, x)
|
||||
else:
|
||||
let verifyRes = ffi_verify_rln_proof(addr rln, addr proof, x)
|
||||
let verifyErr = ffi_verify_rln_proof(addr rln, addr proof, x)
|
||||
|
||||
if verifyRes.ok.isNil:
|
||||
stderr.writeLine "Proof verification error: ", asString(verifyRes.err)
|
||||
quit 1
|
||||
elif verifyRes.ok[]:
|
||||
echo "Proof verified successfully"
|
||||
else:
|
||||
echo "Proof verification failed"
|
||||
if not verifyErr.ok:
|
||||
stderr.writeLine "Proof verification error: ", asString(verifyErr.err)
|
||||
c_string_free(verifyErr.err)
|
||||
quit 1
|
||||
|
||||
echo "Proof verified successfully"
|
||||
|
||||
echo "\nSimulating double-signaling attack (same epoch, different message)"
|
||||
|
||||
echo "\nHashing second signal"
|
||||
@@ -500,12 +506,12 @@ when isMainModule:
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
var signal2Vec = Vec_uint8(dataPtr: cast[ptr uint8](addr signal2[0]),
|
||||
len: CSize(signal2.len), cap: CSize(signal2.len))
|
||||
let x2 = ffi_hash_to_field_le(addr signal2Vec)
|
||||
let x2 = ffi_hash_to_field_be(addr signal2Vec)
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(x2)
|
||||
echo " - x2 = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nCreating second message with the same id"
|
||||
let messageId2 = uint_to_cfr(0'u32)
|
||||
@@ -513,7 +519,7 @@ when isMainModule:
|
||||
block:
|
||||
let debug = cfr_debug(messageId2)
|
||||
echo " - message_id2 = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "\nGenerating second RLN Proof"
|
||||
var proofRes2: CResultProofPtrVecU8
|
||||
@@ -526,7 +532,8 @@ when isMainModule:
|
||||
userMessageLimit, messageId2, x2, externalNullifier, leafIndex)
|
||||
|
||||
if proofRes2.ok.isNil:
|
||||
stderr.writeLine "Second proof generation failed: ", asString(proofRes2.err)
|
||||
stderr.writeLine "Second proof generation error: ", asString(proofRes2.err)
|
||||
c_string_free(proofRes2.err)
|
||||
quit 1
|
||||
|
||||
var proof2 = proofRes2.ok
|
||||
@@ -534,50 +541,52 @@ when isMainModule:
|
||||
|
||||
echo "\nVerifying second proof"
|
||||
when defined(ffiStateless):
|
||||
let verifyRes2 = ffi_verify_with_roots(addr rln, addr proof2, addr roots, x2)
|
||||
let verifyErr2 = ffi_verify_with_roots(addr rln, addr proof2, addr roots, x2)
|
||||
else:
|
||||
let verifyRes2 = ffi_verify_rln_proof(addr rln, addr proof2, x2)
|
||||
let verifyErr2 = ffi_verify_rln_proof(addr rln, addr proof2, x2)
|
||||
|
||||
if verifyRes2.ok.isNil:
|
||||
stderr.writeLine "Second proof verification error: ", asString(verifyRes2.err)
|
||||
if not verifyErr2.ok:
|
||||
stderr.writeLine "Second proof verification error: ", asString(
|
||||
verifyErr2.err)
|
||||
c_string_free(verifyErr2.err)
|
||||
quit 1
|
||||
elif verifyRes2.ok[]:
|
||||
echo "Second proof verified successfully"
|
||||
|
||||
echo "\nRecovering identity secret"
|
||||
let recoverRes = ffi_recover_id_secret(addr proof, addr proof2)
|
||||
if recoverRes.ok.isNil:
|
||||
stderr.writeLine "Identity recovery error: ", asString(recoverRes.err)
|
||||
quit 1
|
||||
else:
|
||||
let recoveredSecret = recoverRes.ok
|
||||
echo "Second proof verified successfully"
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(recoveredSecret)
|
||||
echo " - recovered_secret = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(identitySecret)
|
||||
echo " - original_secret = ", asString(debug)
|
||||
vec_u8_free(debug)
|
||||
|
||||
echo "Slashing successful: Identity is recovered!"
|
||||
cfr_free(recoveredSecret)
|
||||
else:
|
||||
echo "Second proof verification failed"
|
||||
echo "\nRecovering identity secret"
|
||||
let recoverRes = ffi_recover_id_secret(addr proof, addr proof2)
|
||||
if recoverRes.ok.isNil:
|
||||
stderr.writeLine "Identity recovery error: ", asString(recoverRes.err)
|
||||
c_string_free(recoverRes.err)
|
||||
quit 1
|
||||
|
||||
let recoveredSecret = recoverRes.ok
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(recoveredSecret)
|
||||
echo " - recovered_secret = ", asString(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
block:
|
||||
let debug = cfr_debug(identitySecret)
|
||||
echo " - original_secret = ", asString(debug)
|
||||
c_string_free(debug)
|
||||
|
||||
echo "Slashing successful: Identity is recovered!"
|
||||
cfr_free(recoveredSecret)
|
||||
|
||||
ffi_rln_proof_free(proof2)
|
||||
cfr_free(x2)
|
||||
cfr_free(messageId2)
|
||||
ffi_rln_proof_free(proof)
|
||||
|
||||
when defined(ffiStateless):
|
||||
cfr_free(computedRoot)
|
||||
vec_cfr_free(roots)
|
||||
vec_cfr_free(pathElements)
|
||||
for i in 0..treeDepth-2:
|
||||
cfr_free(defaultHashes[i])
|
||||
cfr_free(defaultLeaf)
|
||||
for i in 0..treeDepth-2: cfr_free(defaultHashes[i])
|
||||
dealloc(pathElemsBuffer)
|
||||
cfr_free(computedRoot)
|
||||
else:
|
||||
ffi_merkle_proof_free(merkleProof)
|
||||
|
||||
|
||||
@@ -41,15 +41,23 @@ pub fn calc_witness<I: IntoIterator<Item = (String, Vec<FrOrSecret>)>>(
|
||||
deserialize_witnesscalc_graph(std::io::Cursor::new(graph_data)).unwrap();
|
||||
|
||||
let mut inputs_buffer = get_inputs_buffer(get_inputs_size(&nodes));
|
||||
|
||||
populate_inputs(&inputs, &input_mapping, &mut inputs_buffer);
|
||||
|
||||
if let Some(v) = inputs.get_mut("identitySecret") {
|
||||
// ~== v[0] = U256::ZERO;
|
||||
unsafe { zeroize_flat_type(v) };
|
||||
// DO NOT USE: unsafe { zeroize_flat_type(v) } only clears the Vec pointer, not the data—can cause memory leaks
|
||||
|
||||
for val in v.iter_mut() {
|
||||
unsafe { zeroize_flat_type(val) };
|
||||
}
|
||||
}
|
||||
|
||||
let res = graph::evaluate(&nodes, inputs_buffer.as_slice(), &signals);
|
||||
inputs_buffer.iter_mut().for_each(|i| {
|
||||
unsafe { zeroize_flat_type(i) };
|
||||
});
|
||||
|
||||
for val in inputs_buffer.iter_mut() {
|
||||
unsafe { zeroize_flat_type(val) };
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use super::ffi_utils::{CFr, CResult};
|
||||
use super::ffi_utils::{CBoolResult, CFr, CResult};
|
||||
use crate::{
|
||||
circuit::{graph_from_folder, zkey_from_folder, zkey_from_raw, Curve},
|
||||
protocol::{
|
||||
@@ -38,7 +38,7 @@ pub struct FFI_RLN {
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_new(
|
||||
pub fn ffi_rln_new(
|
||||
tree_depth: usize,
|
||||
config_path: char_p::Ref<'_>,
|
||||
) -> CResult<repr_c::Box<FFI_RLN>, repr_c::String> {
|
||||
@@ -94,7 +94,7 @@ pub fn ffi_new(
|
||||
|
||||
#[cfg(feature = "stateless")]
|
||||
#[ffi_export]
|
||||
pub fn ffi_new() -> CResult<repr_c::Box<FFI_RLN>, repr_c::String> {
|
||||
pub fn ffi_rln_new() -> CResult<repr_c::Box<FFI_RLN>, repr_c::String> {
|
||||
let proving_key = zkey_from_folder().to_owned();
|
||||
let graph_data = graph_from_folder().to_owned();
|
||||
|
||||
@@ -111,7 +111,7 @@ pub fn ffi_new() -> CResult<repr_c::Box<FFI_RLN>, repr_c::String> {
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_new_with_params(
|
||||
pub fn ffi_rln_new_with_params(
|
||||
tree_depth: usize,
|
||||
zkey_buffer: &repr_c::Vec<u8>,
|
||||
graph_data: &repr_c::Vec<u8>,
|
||||
@@ -202,7 +202,7 @@ pub fn ffi_new_with_params(
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn ffi_rln_free(rln: Option<repr_c::Box<FFI_RLN>>) {
|
||||
pub fn ffi_rln_free(rln: repr_c::Box<FFI_RLN>) {
|
||||
drop(rln);
|
||||
}
|
||||
|
||||
@@ -216,8 +216,8 @@ pub struct FFI_RLNProof {
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn ffi_rln_proof_free(rln: Option<repr_c::Box<FFI_RLNProof>>) {
|
||||
drop(rln);
|
||||
pub fn ffi_rln_proof_free(rln_proof: repr_c::Box<FFI_RLNProof>) {
|
||||
drop(rln_proof);
|
||||
}
|
||||
|
||||
// Proof generation APIs
|
||||
@@ -364,24 +364,45 @@ pub fn ffi_verify_rln_proof(
|
||||
rln: &repr_c::Box<FFI_RLN>,
|
||||
proof: &repr_c::Box<FFI_RLNProof>,
|
||||
x: &CFr,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
) -> CBoolResult {
|
||||
// Verify the root
|
||||
if rln.tree.root() != proof.proof_values.root {
|
||||
return CBoolResult {
|
||||
ok: false,
|
||||
err: Some("Invalid root".to_string().into()),
|
||||
};
|
||||
}
|
||||
|
||||
// Verify the signal
|
||||
if *x != proof.proof_values.x {
|
||||
return CBoolResult {
|
||||
ok: false,
|
||||
err: Some("Invalid signal".to_string().into()),
|
||||
};
|
||||
}
|
||||
|
||||
// Verify the proof
|
||||
match verify_proof(&rln.proving_key.0.vk, &proof.proof, &proof.proof_values) {
|
||||
Ok(proof_verified) => {
|
||||
// Verify the root and signal
|
||||
let roots_verified = rln.tree.root() == proof.proof_values.root;
|
||||
let signal_verified = *x == proof.proof_values.x;
|
||||
CResult {
|
||||
ok: Some(Box_::new(
|
||||
proof_verified && roots_verified && signal_verified,
|
||||
)),
|
||||
err: None,
|
||||
if !proof_verified {
|
||||
return CBoolResult {
|
||||
ok: false,
|
||||
err: Some("Invalid proof".to_string().into()),
|
||||
};
|
||||
}
|
||||
}
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
Err(err) => {
|
||||
return CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// All verifications passed
|
||||
CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,43 +412,44 @@ pub fn ffi_verify_with_roots(
|
||||
proof: &repr_c::Box<FFI_RLNProof>,
|
||||
roots: &repr_c::Vec<CFr>,
|
||||
x: &CFr,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
// Verify the proof
|
||||
let proof_verified =
|
||||
match verify_proof(&rln.proving_key.0.vk, &proof.proof, &proof.proof_values) {
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
return CResult {
|
||||
ok: None,
|
||||
err: Some(err.to_string().into()),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// If proof verification failed, return early
|
||||
if !proof_verified {
|
||||
return CResult {
|
||||
ok: Some(Box_::new(false)),
|
||||
err: None,
|
||||
) -> CBoolResult {
|
||||
// Verify the root
|
||||
if !roots.is_empty() && !roots.iter().any(|root| root.0 == proof.proof_values.root) {
|
||||
return CBoolResult {
|
||||
ok: false,
|
||||
err: Some("Invalid root".to_string().into()),
|
||||
};
|
||||
}
|
||||
|
||||
// Verify the root
|
||||
let roots_verified: bool = if roots.is_empty() {
|
||||
// If no root is passed in roots_buffer, we skip proof's root check
|
||||
true
|
||||
} else {
|
||||
// We check if the proof's root is in roots
|
||||
roots.iter().any(|root| root.0 == proof.proof_values.root)
|
||||
// Verify the signal
|
||||
if *x != proof.proof_values.x {
|
||||
return CBoolResult {
|
||||
ok: false,
|
||||
err: Some("Invalid signal".to_string().into()),
|
||||
};
|
||||
}
|
||||
|
||||
// Verify the proof
|
||||
match verify_proof(&rln.proving_key.0.vk, &proof.proof, &proof.proof_values) {
|
||||
Ok(proof_verified) => {
|
||||
if !proof_verified {
|
||||
return CBoolResult {
|
||||
ok: false,
|
||||
err: Some("Invalid proof".to_string().into()),
|
||||
};
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
return CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Verify the signal
|
||||
let signal_verified = *x == proof.proof_values.x;
|
||||
|
||||
CResult {
|
||||
ok: Some(Box_::new(
|
||||
proof_verified && roots_verified && signal_verified,
|
||||
)),
|
||||
// All verifications passed
|
||||
CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![cfg(not(feature = "stateless"))]
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
use {
|
||||
super::ffi_rln::FFI_RLN,
|
||||
super::ffi_utils::{CFr, CResult},
|
||||
super::ffi_utils::{CBoolResult, CFr, CResult},
|
||||
crate::poseidon_tree::PoseidonTree,
|
||||
safer_ffi::{boxed::Box_, derive_ReprC, ffi_export, prelude::repr_c},
|
||||
utils::{ZerokitMerkleProof, ZerokitMerkleTree},
|
||||
@@ -11,7 +11,6 @@ use {
|
||||
|
||||
// MerkleProof
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[derive_ReprC]
|
||||
#[repr(C)]
|
||||
pub struct FFI_MerkleProof {
|
||||
@@ -19,31 +18,26 @@ pub struct FFI_MerkleProof {
|
||||
pub path_index: repr_c::Vec<u8>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_merkle_proof_free(proof: Option<repr_c::Box<FFI_MerkleProof>>) {
|
||||
drop(proof);
|
||||
pub fn ffi_merkle_proof_free(merkle_proof: repr_c::Box<FFI_MerkleProof>) {
|
||||
drop(merkle_proof);
|
||||
}
|
||||
|
||||
// Merkle tree management APIs
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_set_tree(
|
||||
rln: &mut repr_c::Box<FFI_RLN>,
|
||||
tree_depth: usize,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
pub fn ffi_set_tree(rln: &mut repr_c::Box<FFI_RLN>, tree_depth: usize) -> CBoolResult {
|
||||
// We compute a default empty tree of desired depth
|
||||
match PoseidonTree::default(tree_depth) {
|
||||
Ok(tree) => {
|
||||
rln.tree = tree;
|
||||
CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
}
|
||||
}
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
@@ -51,44 +45,38 @@ pub fn ffi_set_tree(
|
||||
|
||||
// Merkle tree leaf operations
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_delete_leaf(
|
||||
rln: &mut repr_c::Box<FFI_RLN>,
|
||||
index: usize,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
pub fn ffi_delete_leaf(rln: &mut repr_c::Box<FFI_RLN>, index: usize) -> CBoolResult {
|
||||
match rln.tree.delete(index) {
|
||||
Ok(_) => CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
Ok(_) => CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_set_leaf(
|
||||
rln: &mut repr_c::Box<FFI_RLN>,
|
||||
index: usize,
|
||||
value: &repr_c::Box<CFr>,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
match rln.tree.set(index, value.0) {
|
||||
Ok(_) => CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
leaf: &repr_c::Box<CFr>,
|
||||
) -> CBoolResult {
|
||||
match rln.tree.set(index, leaf.0) {
|
||||
Ok(_) => CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_get_leaf(
|
||||
rln: &repr_c::Box<FFI_RLN>,
|
||||
@@ -106,82 +94,70 @@ pub fn ffi_get_leaf(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_leaves_set(rln: &repr_c::Box<FFI_RLN>) -> usize {
|
||||
rln.tree.leaves_set()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_set_next_leaf(
|
||||
rln: &mut repr_c::Box<FFI_RLN>,
|
||||
value: &repr_c::Box<CFr>,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
match rln.tree.update_next(value.0) {
|
||||
Ok(_) => CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
pub fn ffi_set_next_leaf(rln: &mut repr_c::Box<FFI_RLN>, leaf: &repr_c::Box<CFr>) -> CBoolResult {
|
||||
match rln.tree.update_next(leaf.0) {
|
||||
Ok(_) => CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_set_leaves_from(
|
||||
rln: &mut repr_c::Box<FFI_RLN>,
|
||||
index: usize,
|
||||
leaves: &repr_c::Vec<CFr>,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
) -> CBoolResult {
|
||||
match rln
|
||||
.tree
|
||||
.override_range(index, leaves.iter().map(|cfr| cfr.0), [].into_iter())
|
||||
{
|
||||
Ok(_) => CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
Ok(_) => CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_init_tree_with_leaves(
|
||||
rln: &mut repr_c::Box<FFI_RLN>,
|
||||
leaves: &repr_c::Vec<CFr>,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
) -> CBoolResult {
|
||||
// Reset tree to default
|
||||
let tree_depth = rln.tree.depth();
|
||||
match PoseidonTree::default(tree_depth) {
|
||||
Ok(tree) => {
|
||||
rln.tree = tree;
|
||||
}
|
||||
Err(err) => {
|
||||
return CResult {
|
||||
ok: None,
|
||||
err: Some(err.to_string().into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Err(err) = PoseidonTree::default(tree_depth) {
|
||||
return CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
};
|
||||
};
|
||||
|
||||
match rln
|
||||
.tree
|
||||
.override_range(0, leaves.iter().map(|cfr| cfr.0), [].into_iter())
|
||||
{
|
||||
Ok(_) => CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
Ok(_) => CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
@@ -189,49 +165,47 @@ pub fn ffi_init_tree_with_leaves(
|
||||
|
||||
// Atomic operations
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_atomic_operation(
|
||||
rln: &mut repr_c::Box<FFI_RLN>,
|
||||
index: usize,
|
||||
leaves: &repr_c::Vec<CFr>,
|
||||
indices: &repr_c::Vec<usize>,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
) -> CBoolResult {
|
||||
match rln.tree.override_range(
|
||||
index,
|
||||
leaves.iter().map(|cfr| cfr.0),
|
||||
indices.iter().copied(),
|
||||
) {
|
||||
Ok(_) => CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
Ok(_) => CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_seq_atomic_operation(
|
||||
rln: &mut repr_c::Box<FFI_RLN>,
|
||||
leaves: &repr_c::Vec<CFr>,
|
||||
indices: &repr_c::Vec<u8>,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
) -> CBoolResult {
|
||||
let index = rln.tree.leaves_set();
|
||||
match rln.tree.override_range(
|
||||
index,
|
||||
leaves.iter().map(|cfr| cfr.0),
|
||||
indices.iter().map(|x| *x as usize),
|
||||
) {
|
||||
Ok(_) => CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
Ok(_) => CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
@@ -239,13 +213,11 @@ pub fn ffi_seq_atomic_operation(
|
||||
|
||||
// Root and proof operations
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_get_root(rln: &repr_c::Box<FFI_RLN>) -> repr_c::Box<CFr> {
|
||||
CFr::from(rln.tree.root()).into()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_get_proof(
|
||||
rln: &repr_c::Box<FFI_RLN>,
|
||||
@@ -281,25 +253,20 @@ pub fn ffi_get_proof(
|
||||
|
||||
// Persistent metadata APIs
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_set_metadata(
|
||||
rln: &mut repr_c::Box<FFI_RLN>,
|
||||
metadata: &repr_c::Vec<u8>,
|
||||
) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
pub fn ffi_set_metadata(rln: &mut repr_c::Box<FFI_RLN>, metadata: &repr_c::Vec<u8>) -> CBoolResult {
|
||||
match rln.tree.set_metadata(metadata) {
|
||||
Ok(_) => CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
Ok(_) => CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_get_metadata(rln: &repr_c::Box<FFI_RLN>) -> CResult<repr_c::Vec<u8>, repr_c::String> {
|
||||
match rln.tree.metadata() {
|
||||
@@ -314,16 +281,15 @@ pub fn ffi_get_metadata(rln: &repr_c::Box<FFI_RLN>) -> CResult<repr_c::Vec<u8>,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stateless"))]
|
||||
#[ffi_export]
|
||||
pub fn ffi_flush(rln: &mut repr_c::Box<FFI_RLN>) -> CResult<repr_c::Box<bool>, repr_c::String> {
|
||||
pub fn ffi_flush(rln: &mut repr_c::Box<FFI_RLN>) -> CBoolResult {
|
||||
match rln.tree.close_db_connection() {
|
||||
Ok(_) => CResult {
|
||||
ok: Some(Box_::new(true)),
|
||||
Ok(_) => CBoolResult {
|
||||
ok: true,
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
Err(err) => CBoolResult {
|
||||
ok: false,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -19,6 +19,15 @@ pub struct CResult<T: ReprC, Err: ReprC> {
|
||||
pub err: Option<Err>,
|
||||
}
|
||||
|
||||
// CBoolResult
|
||||
|
||||
#[derive_ReprC]
|
||||
#[repr(C)]
|
||||
pub struct CBoolResult {
|
||||
pub ok: bool,
|
||||
pub err: Option<repr_c::String>,
|
||||
}
|
||||
|
||||
// CFr
|
||||
|
||||
#[derive_ReprC]
|
||||
@@ -96,16 +105,44 @@ pub fn uint_to_cfr(value: u32) -> repr_c::Box<CFr> {
|
||||
|
||||
#[ffi_export]
|
||||
pub fn cfr_debug(cfr: Option<&CFr>) -> repr_c::String {
|
||||
format!("{:?}", cfr.map(|c| c.0.to_string())).into()
|
||||
match cfr {
|
||||
Some(cfr) => format!("{:?}", cfr.0).into(),
|
||||
None => "None".into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn cfr_free(cfr: Option<repr_c::Box<CFr>>) {
|
||||
pub fn cfr_free(cfr: repr_c::Box<CFr>) {
|
||||
drop(cfr);
|
||||
}
|
||||
|
||||
// Vec<CFr>
|
||||
|
||||
#[ffi_export]
|
||||
pub fn vec_cfr_new(capacity: usize) -> repr_c::Vec<CFr> {
|
||||
Vec::with_capacity(capacity).into()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn vec_cfr_from_cfr(cfr: &CFr) -> repr_c::Vec<CFr> {
|
||||
vec![*cfr].into()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn vec_cfr_push(v: &mut safer_ffi::Vec<CFr>, cfr: &CFr) {
|
||||
let mut new: Vec<CFr> = std::mem::replace(v, Vec::new().into()).into();
|
||||
if new.len() == new.capacity() {
|
||||
new.reserve_exact(1);
|
||||
}
|
||||
new.push(*cfr);
|
||||
*v = new.into();
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn vec_cfr_len(v: &repr_c::Vec<CFr>) -> usize {
|
||||
v.len()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn vec_cfr_get(v: &repr_c::Vec<CFr>, i: usize) -> Option<&CFr> {
|
||||
v.get(i)
|
||||
@@ -124,14 +161,12 @@ pub fn vec_cfr_to_bytes_be(vec: &repr_c::Vec<CFr>) -> repr_c::Vec<u8> {
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn bytes_le_to_vec_cfr(
|
||||
bytes: &repr_c::Vec<u8>,
|
||||
) -> CResult<repr_c::Box<repr_c::Vec<CFr>>, repr_c::String> {
|
||||
pub fn bytes_le_to_vec_cfr(bytes: &repr_c::Vec<u8>) -> CResult<repr_c::Vec<CFr>, repr_c::String> {
|
||||
match crate::utils::bytes_le_to_vec_fr(bytes) {
|
||||
Ok((vec_fr, _)) => {
|
||||
let vec_cfr: Vec<CFr> = vec_fr.into_iter().map(CFr).collect();
|
||||
CResult {
|
||||
ok: Some(Box_::new(vec_cfr.into())),
|
||||
ok: Some(vec_cfr.into()),
|
||||
err: None,
|
||||
}
|
||||
}
|
||||
@@ -143,14 +178,12 @@ pub fn bytes_le_to_vec_cfr(
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn bytes_be_to_vec_cfr(
|
||||
bytes: &repr_c::Vec<u8>,
|
||||
) -> CResult<repr_c::Box<repr_c::Vec<CFr>>, repr_c::String> {
|
||||
pub fn bytes_be_to_vec_cfr(bytes: &repr_c::Vec<u8>) -> CResult<repr_c::Vec<CFr>, repr_c::String> {
|
||||
match crate::utils::bytes_be_to_vec_fr(bytes) {
|
||||
Ok((vec_fr, _)) => {
|
||||
let vec_cfr: Vec<CFr> = vec_fr.into_iter().map(CFr).collect();
|
||||
CResult {
|
||||
ok: Some(Box_::new(vec_cfr.into())),
|
||||
ok: Some(vec_cfr.into()),
|
||||
err: None,
|
||||
}
|
||||
}
|
||||
@@ -162,8 +195,14 @@ pub fn bytes_be_to_vec_cfr(
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn vec_cfr_debug(v: &repr_c::Vec<CFr>) -> repr_c::String {
|
||||
format!("{:?}", v.iter().map(|cfr| cfr.0).collect::<Vec<Fr>>()).into()
|
||||
pub fn vec_cfr_debug(v: Option<&repr_c::Vec<CFr>>) -> repr_c::String {
|
||||
match v {
|
||||
Some(v) => {
|
||||
let vec_fr: Vec<Fr> = v.iter().map(|cfr| cfr.0).collect();
|
||||
format!("{:?}", vec_fr).into()
|
||||
}
|
||||
None => "None".into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
@@ -184,12 +223,10 @@ pub fn vec_u8_to_bytes_be(vec: &repr_c::Vec<u8>) -> repr_c::Vec<u8> {
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn bytes_le_to_vec_u8(
|
||||
bytes: &repr_c::Vec<u8>,
|
||||
) -> CResult<repr_c::Box<repr_c::Vec<u8>>, repr_c::String> {
|
||||
pub fn bytes_le_to_vec_u8(bytes: &repr_c::Vec<u8>) -> CResult<repr_c::Vec<u8>, repr_c::String> {
|
||||
match crate::utils::bytes_le_to_vec_u8(bytes) {
|
||||
Ok((vec, _)) => CResult {
|
||||
ok: Some(Box_::new(vec.into())),
|
||||
ok: Some(vec.into()),
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
@@ -200,12 +237,10 @@ pub fn bytes_le_to_vec_u8(
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn bytes_be_to_vec_u8(
|
||||
bytes: &repr_c::Vec<u8>,
|
||||
) -> CResult<repr_c::Box<repr_c::Vec<u8>>, repr_c::String> {
|
||||
pub fn bytes_be_to_vec_u8(bytes: &repr_c::Vec<u8>) -> CResult<repr_c::Vec<u8>, repr_c::String> {
|
||||
match crate::utils::bytes_be_to_vec_u8(bytes) {
|
||||
Ok((vec, _)) => CResult {
|
||||
ok: Some(Box_::new(vec.into())),
|
||||
ok: Some(vec.into()),
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
@@ -216,8 +251,11 @@ pub fn bytes_be_to_vec_u8(
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn vec_u8_debug(v: &repr_c::Vec<u8>) -> repr_c::String {
|
||||
format!("{:?}", v.iter().copied().collect::<Vec<u8>>()).into()
|
||||
pub fn vec_u8_debug(v: Option<&repr_c::Vec<u8>>) -> repr_c::String {
|
||||
match v {
|
||||
Some(v) => format!("{:?}", v.deref()).into(),
|
||||
None => "None".into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
@@ -282,3 +320,8 @@ pub fn ffi_seeded_extended_key_gen(seed: &repr_c::Vec<u8>) -> repr_c::Vec<CFr> {
|
||||
]
|
||||
.into()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn c_string_free(s: repr_c::String) {
|
||||
drop(s);
|
||||
}
|
||||
|
||||
348
rln/tests/ffi.rs
348
rln/tests/ffi.rs
@@ -20,7 +20,7 @@ mod test {
|
||||
fn create_rln_instance() -> repr_c::Box<FFI_RLN> {
|
||||
let input_config = json!({}).to_string();
|
||||
let c_str = std::ffi::CString::new(input_config).unwrap();
|
||||
match ffi_new(TEST_TREE_DEPTH, c_str.as_c_str().into()) {
|
||||
match ffi_rln_new(TEST_TREE_DEPTH, c_str.as_c_str().into()) {
|
||||
CResult {
|
||||
ok: Some(rln),
|
||||
err: None,
|
||||
@@ -39,19 +39,7 @@ mod test {
|
||||
.map(|fr| CFr::from(*fr))
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
match ffi_init_tree_with_leaves(ffi_rln_instance, &leaves_vec) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {
|
||||
assert_eq!(ffi_leaves_set(ffi_rln_instance), leaves.len());
|
||||
}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("init tree with leaves call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
ffi_init_tree_with_leaves(ffi_rln_instance, &leaves_vec);
|
||||
}
|
||||
|
||||
fn get_random_leaves() -> Vec<Fr> {
|
||||
@@ -113,16 +101,9 @@ mod test {
|
||||
// We first add leaves one by one specifying the index
|
||||
for (i, leaf) in leaves.iter().enumerate() {
|
||||
// We prepare the rate_commitment and we set the leaf at provided index
|
||||
match ffi_set_leaf(&mut ffi_rln_instance, i, &Box_::new(CFr::from(*leaf))) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_set_leaf(&mut ffi_rln_instance, i, &Box_::new(CFr::from(*leaf)));
|
||||
if !result.ok {
|
||||
panic!("set leaf call failed: {:?}", result.err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,30 +111,16 @@ mod test {
|
||||
let root_single = get_tree_root(&ffi_rln_instance);
|
||||
|
||||
// We reset the tree to default
|
||||
match ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set tree call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH);
|
||||
if !result.ok {
|
||||
panic!("set tree call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// We add leaves one by one using the internal index (new leaves goes in next available position)
|
||||
for leaf in &leaves {
|
||||
match ffi_set_next_leaf(&mut ffi_rln_instance, &Box_::new(CFr::from(*leaf))) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set next leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_set_next_leaf(&mut ffi_rln_instance, &Box_::new(CFr::from(*leaf)));
|
||||
if !result.ok {
|
||||
panic!("set next leaf call failed: {:?}", result.err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,16 +131,9 @@ mod test {
|
||||
assert_eq!(root_single, root_next);
|
||||
|
||||
// We reset the tree to default
|
||||
match ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set tree call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH);
|
||||
if !result.ok {
|
||||
panic!("set tree call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// We add leaves in a batch into the tree
|
||||
@@ -188,16 +148,9 @@ mod test {
|
||||
// We now delete all leaves set and check if the root corresponds to the empty tree root
|
||||
// delete calls over indexes higher than no_of_leaves are ignored and will not increase self.tree.next_index
|
||||
for i in 0..NO_OF_LEAVES {
|
||||
match ffi_delete_leaf(&mut ffi_rln_instance, i) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("delete leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_delete_leaf(&mut ffi_rln_instance, i);
|
||||
if !result.ok {
|
||||
panic!("delete leaf call failed: {:?}", result.err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,16 +158,9 @@ mod test {
|
||||
let root_delete = get_tree_root(&ffi_rln_instance);
|
||||
|
||||
// We reset the tree to default
|
||||
match ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set tree call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH);
|
||||
if !result.ok {
|
||||
panic!("set tree call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// We get the root of the empty tree
|
||||
@@ -258,16 +204,9 @@ mod test {
|
||||
.map(|fr| CFr::from(*fr))
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
match ffi_set_leaves_from(&mut ffi_rln_instance, set_index, &leaves_vec) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set leaves from call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_set_leaves_from(&mut ffi_rln_instance, set_index, &leaves_vec);
|
||||
if !result.ok {
|
||||
panic!("set leaves from call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// We get the root of the tree obtained adding leaves in batch
|
||||
@@ -278,30 +217,16 @@ mod test {
|
||||
);
|
||||
|
||||
// We reset the tree to default
|
||||
match ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set tree call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_set_tree(&mut ffi_rln_instance, TEST_TREE_DEPTH);
|
||||
if !result.ok {
|
||||
panic!("set tree call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// We add leaves one by one using the internal index (new leaves goes in next available position)
|
||||
for leaf in &leaves {
|
||||
match ffi_set_next_leaf(&mut ffi_rln_instance, &Box_::new(CFr::from(*leaf))) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set next leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_set_next_leaf(&mut ffi_rln_instance, &Box_::new(CFr::from(*leaf)));
|
||||
if !result.ok {
|
||||
panic!("set next leaf call failed: {:?}", result.err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,21 +257,14 @@ mod test {
|
||||
let indices: repr_c::Vec<usize> = vec![last_leaf_index].into();
|
||||
let last_leaf_vec: repr_c::Vec<CFr> = vec![CFr::from(*last_leaf)].into();
|
||||
|
||||
match ffi_atomic_operation(
|
||||
let result = ffi_atomic_operation(
|
||||
&mut ffi_rln_instance,
|
||||
last_leaf_index,
|
||||
&last_leaf_vec,
|
||||
&indices,
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("atomic operation call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
);
|
||||
if !result.ok {
|
||||
panic!("atomic operation call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// We get the root of the tree obtained after a no-op
|
||||
@@ -374,13 +292,7 @@ mod test {
|
||||
.map(|fr| CFr::from(*fr))
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
match ffi_set_leaves_from(&mut ffi_rln_instance, bad_index, &leaves_vec) {
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(_),
|
||||
} => {}
|
||||
_ => panic!("set leaves from call should have failed"),
|
||||
}
|
||||
ffi_set_leaves_from(&mut ffi_rln_instance, bad_index, &leaves_vec);
|
||||
|
||||
// Get root of tree after attempted set
|
||||
let root_after_bad_set = get_tree_root(&ffi_rln_instance);
|
||||
@@ -404,20 +316,13 @@ mod test {
|
||||
let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]);
|
||||
|
||||
// We prepare id_commitment and we set the leaf at provided index
|
||||
match ffi_set_leaf(
|
||||
let result = ffi_set_leaf(
|
||||
&mut ffi_rln_instance,
|
||||
leaf_index,
|
||||
&Box_::new(CFr::from(rate_commitment)),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
);
|
||||
if !result.ok {
|
||||
panic!("set leaf call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// We obtain the Merkle tree root
|
||||
@@ -522,7 +427,7 @@ mod test {
|
||||
// Creating a RLN instance passing the raw data
|
||||
let tree_config = "".to_string();
|
||||
let c_str = std::ffi::CString::new(tree_config).unwrap();
|
||||
let ffi_rln_instance2 = match ffi_new_with_params(
|
||||
let ffi_rln_instance2 = match ffi_rln_new_with_params(
|
||||
TEST_TREE_DEPTH,
|
||||
&zkey_buffer.into(),
|
||||
&graph_buffer.into(),
|
||||
@@ -582,19 +487,12 @@ mod test {
|
||||
let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]);
|
||||
|
||||
// We set as leaf rate_commitment, its index would be equal to no_of_leaves
|
||||
match ffi_set_next_leaf(
|
||||
let result = ffi_set_next_leaf(
|
||||
&mut ffi_rln_instance,
|
||||
&Box_::new(CFr::from(rate_commitment)),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set next leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
);
|
||||
if !result.ok {
|
||||
panic!("set next leaf call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// Get the merkle proof for the identity
|
||||
@@ -624,20 +522,7 @@ mod test {
|
||||
identity_index,
|
||||
);
|
||||
|
||||
let proof_is_valid =
|
||||
match ffi_verify_rln_proof(&ffi_rln_instance, &rln_proof, &CFr::from(x)) {
|
||||
CResult {
|
||||
ok: Some(success),
|
||||
err: None,
|
||||
} => *success,
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("verify rln proof call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
assert!(proof_is_valid);
|
||||
assert!(ffi_verify_rln_proof(&ffi_rln_instance, &rln_proof, &CFr::from(x)).ok);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -672,19 +557,12 @@ mod test {
|
||||
let message_id = Fr::from(1);
|
||||
|
||||
// We set as leaf rate_commitment, its index would be equal to no_of_leaves
|
||||
match ffi_set_next_leaf(
|
||||
let result = ffi_set_next_leaf(
|
||||
&mut ffi_rln_instance,
|
||||
&Box_::new(CFr::from(rate_commitment)),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set next leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
);
|
||||
if !result.ok {
|
||||
panic!("set next leaf call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// Get the merkle proof for the identity
|
||||
@@ -722,21 +600,9 @@ mod test {
|
||||
// In this case, since no root is provided, proof's root check is skipped and proof is verified if other proof values are valid
|
||||
let roots_empty: repr_c::Vec<CFr> = vec![].into();
|
||||
|
||||
let proof_is_valid =
|
||||
match ffi_verify_with_roots(&ffi_rln_instance, &rln_proof, &roots_empty, &CFr::from(x))
|
||||
{
|
||||
CResult {
|
||||
ok: Some(valid),
|
||||
err: None,
|
||||
} => *valid,
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("verify with roots call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Proof should be valid
|
||||
assert!(proof_is_valid);
|
||||
assert!(
|
||||
ffi_verify_with_roots(&ffi_rln_instance, &rln_proof, &roots_empty, &CFr::from(x)).ok
|
||||
);
|
||||
|
||||
// We then try to verify against some random values not containing the correct one.
|
||||
let mut roots_random: Vec<CFr> = Vec::new();
|
||||
@@ -745,24 +611,15 @@ mod test {
|
||||
}
|
||||
let roots_random_vec: repr_c::Vec<CFr> = roots_random.into();
|
||||
|
||||
let proof_is_valid = match ffi_verify_with_roots(
|
||||
&ffi_rln_instance,
|
||||
&rln_proof,
|
||||
&roots_random_vec,
|
||||
&CFr::from(x),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(valid),
|
||||
err: None,
|
||||
} => *valid,
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("verify with roots call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Proof should be invalid.
|
||||
assert!(!proof_is_valid);
|
||||
assert!(
|
||||
!ffi_verify_with_roots(
|
||||
&ffi_rln_instance,
|
||||
&rln_proof,
|
||||
&roots_random_vec,
|
||||
&CFr::from(x),
|
||||
)
|
||||
.ok
|
||||
);
|
||||
|
||||
// We finally include the correct root
|
||||
// We get the root of the tree obtained adding one leaf per time
|
||||
@@ -776,24 +633,15 @@ mod test {
|
||||
roots_with_correct.push(CFr::from(root));
|
||||
let roots_correct_vec: repr_c::Vec<CFr> = roots_with_correct.into();
|
||||
|
||||
let proof_is_valid = match ffi_verify_with_roots(
|
||||
&ffi_rln_instance,
|
||||
&rln_proof,
|
||||
&roots_correct_vec,
|
||||
&CFr::from(x),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(valid),
|
||||
err: None,
|
||||
} => *valid,
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("verify with roots call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Proof should be valid.
|
||||
assert!(proof_is_valid);
|
||||
assert!(
|
||||
ffi_verify_with_roots(
|
||||
&ffi_rln_instance,
|
||||
&rln_proof,
|
||||
&roots_correct_vec,
|
||||
&CFr::from(x),
|
||||
)
|
||||
.ok
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -809,19 +657,12 @@ mod test {
|
||||
let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]);
|
||||
|
||||
// We set as leaf rate_commitment, its index would be equal to 0 since tree is empty
|
||||
match ffi_set_next_leaf(
|
||||
let result = ffi_set_next_leaf(
|
||||
&mut ffi_rln_instance,
|
||||
&Box_::new(CFr::from(rate_commitment)),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set next leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
);
|
||||
if !result.ok {
|
||||
panic!("set next leaf call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
let identity_index: usize = 0;
|
||||
@@ -907,19 +748,12 @@ mod test {
|
||||
let rate_commitment_new = utils_poseidon_hash(&[id_commitment_new, user_message_limit]);
|
||||
|
||||
// We set as leaf id_commitment, its index would be equal to 1 since at 0 there is id_commitment
|
||||
match ffi_set_next_leaf(
|
||||
let result = ffi_set_next_leaf(
|
||||
&mut ffi_rln_instance,
|
||||
&Box_::new(CFr::from(rate_commitment_new)),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set next leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
);
|
||||
if !result.ok {
|
||||
panic!("set next leaf call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
let identity_index_new: usize = 1;
|
||||
@@ -996,20 +830,13 @@ mod test {
|
||||
// We insert the id_commitment into the tree at a random index
|
||||
let mut rng = thread_rng();
|
||||
let index = rng.gen_range(0..no_of_leaves) as usize;
|
||||
match ffi_set_leaf(
|
||||
let result = ffi_set_leaf(
|
||||
&mut ffi_rln_instance,
|
||||
index,
|
||||
&Box_::new(CFr::from(id_commitment)),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set leaf call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
);
|
||||
if !result.ok {
|
||||
panic!("set leaf call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
// We get the leaf at the same index
|
||||
@@ -1037,16 +864,9 @@ mod test {
|
||||
|
||||
let seed_bytes: Vec<u8> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
match ffi_set_metadata(&mut ffi_rln_instance, &seed_bytes.clone().into()) {
|
||||
CResult {
|
||||
ok: Some(_),
|
||||
err: None,
|
||||
} => {}
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("set_metadata call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
let result = ffi_set_metadata(&mut ffi_rln_instance, &seed_bytes.clone().into());
|
||||
if !result.ok {
|
||||
panic!("set_metadata call failed: {:?}", result.err);
|
||||
}
|
||||
|
||||
let metadata = match ffi_get_metadata(&ffi_rln_instance) {
|
||||
|
||||
@@ -13,7 +13,7 @@ mod test {
|
||||
type ConfigOf<T> = <T as ZerokitMerkleTree>::Config;
|
||||
|
||||
fn create_rln_instance() -> repr_c::Box<FFI_RLN> {
|
||||
match ffi_new() {
|
||||
match ffi_rln_new() {
|
||||
CResult {
|
||||
ok: Some(rln),
|
||||
err: None,
|
||||
@@ -274,21 +274,9 @@ mod test {
|
||||
// If no roots is provided, proof validation is skipped and if the remaining proof values are valid, the proof will be correctly verified
|
||||
let roots_empty: repr_c::Vec<CFr> = vec![].into();
|
||||
|
||||
let proof_is_valid =
|
||||
match ffi_verify_with_roots(&ffi_rln_instance, &rln_proof, &roots_empty, &CFr::from(x))
|
||||
{
|
||||
CResult {
|
||||
ok: Some(valid),
|
||||
err: None,
|
||||
} => *valid,
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("verify with roots call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Proof should be valid
|
||||
assert!(proof_is_valid);
|
||||
assert!(
|
||||
ffi_verify_with_roots(&ffi_rln_instance, &rln_proof, &roots_empty, &CFr::from(x)).ok
|
||||
);
|
||||
|
||||
// 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
|
||||
let mut roots_random: Vec<CFr> = Vec::new();
|
||||
@@ -297,24 +285,15 @@ mod test {
|
||||
}
|
||||
let roots_random_vec: repr_c::Vec<CFr> = roots_random.into();
|
||||
|
||||
let proof_is_valid = match ffi_verify_with_roots(
|
||||
&ffi_rln_instance,
|
||||
&rln_proof,
|
||||
&roots_random_vec,
|
||||
&CFr::from(x),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(valid),
|
||||
err: None,
|
||||
} => *valid,
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("verify with roots call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Proof should be invalid.
|
||||
assert!(!proof_is_valid);
|
||||
assert!(
|
||||
!ffi_verify_with_roots(
|
||||
&ffi_rln_instance,
|
||||
&rln_proof,
|
||||
&roots_random_vec,
|
||||
&CFr::from(x),
|
||||
)
|
||||
.ok
|
||||
);
|
||||
|
||||
// We get the root of the tree obtained adding one leaf per time
|
||||
let root = tree.root();
|
||||
@@ -327,23 +306,14 @@ mod test {
|
||||
roots_with_correct.push(CFr::from(root));
|
||||
let roots_correct_vec: repr_c::Vec<CFr> = roots_with_correct.into();
|
||||
|
||||
let proof_is_valid = match ffi_verify_with_roots(
|
||||
&ffi_rln_instance,
|
||||
&rln_proof,
|
||||
&roots_correct_vec,
|
||||
&CFr::from(x),
|
||||
) {
|
||||
CResult {
|
||||
ok: Some(valid),
|
||||
err: None,
|
||||
} => *valid,
|
||||
CResult {
|
||||
ok: None,
|
||||
err: Some(err),
|
||||
} => panic!("verify with roots call failed: {}", err),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Proof should be valid.
|
||||
assert!(proof_is_valid);
|
||||
assert!(
|
||||
ffi_verify_with_roots(
|
||||
&ffi_rln_instance,
|
||||
&rln_proof,
|
||||
&roots_correct_vec,
|
||||
&CFr::from(x)
|
||||
)
|
||||
.ok
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ mod test {
|
||||
assert_eq!(*cfr_int, fr_int);
|
||||
|
||||
let cfr_debug_str = cfr_debug(Some(&cfr_int));
|
||||
assert_eq!(cfr_debug_str.to_string(), "Some(\"42\")");
|
||||
assert_eq!(cfr_debug_str.to_string(), "42");
|
||||
|
||||
let key_gen = ffi_key_gen();
|
||||
let mut id_secret_fr = *key_gen[0];
|
||||
|
||||
Reference in New Issue
Block a user