fix(rln): resolve memory leak in calc_witness and improve FFI memory deallocation pattern (#354)

This commit is contained in:
Vinh Trịnh
2025-11-20 17:27:52 +07:00
committed by GitHub
parent a52cf84f46
commit c74ab11c82
11 changed files with 677 additions and 828 deletions

View File

@@ -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"

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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,
}
}

View File

@@ -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()),
},
}

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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
);
}
}

View File

@@ -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];