diff --git a/rln/Cargo.toml b/rln/Cargo.toml index 3ee5ae3..ca9ab3f 100644 --- a/rln/Cargo.toml +++ b/rln/Cargo.toml @@ -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" diff --git a/rln/README.md b/rln/README.md index 8e63e3f..5747fdc 100644 --- a/rln/README.md +++ b/rln/README.md @@ -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 diff --git a/rln/ffi_c_examples/main.c b/rln/ffi_c_examples/main.c index 3823aae..e667127 100644 --- a/rln/ffi_c_examples/main.c +++ b/rln/ffi_c_examples/main.c @@ -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 serialization: Vec <-> 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 serialization: Vec <-> 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; } \ No newline at end of file diff --git a/rln/ffi_nim_examples/main.nim b/rln/ffi_nim_examples/main.nim index 3de589c..36ebff1 100644 --- a/rln/ffi_nim_examples/main.nim +++ b/rln/ffi_nim_examples/main.nim @@ -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 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 serialization: Vec <-> 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..)>>( 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 } diff --git a/rln/src/ffi/ffi_rln.rs b/rln/src/ffi/ffi_rln.rs index 35359ec..2fbeb18 100644 --- a/rln/src/ffi/ffi_rln.rs +++ b/rln/src/ffi/ffi_rln.rs @@ -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::String> { @@ -94,7 +94,7 @@ pub fn ffi_new( #[cfg(feature = "stateless")] #[ffi_export] -pub fn ffi_new() -> CResult, repr_c::String> { +pub fn ffi_rln_new() -> CResult, 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::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, graph_data: &repr_c::Vec, @@ -202,7 +202,7 @@ pub fn ffi_new_with_params( } #[ffi_export] -pub fn ffi_rln_free(rln: Option>) { +pub fn ffi_rln_free(rln: repr_c::Box) { drop(rln); } @@ -216,8 +216,8 @@ pub struct FFI_RLNProof { } #[ffi_export] -pub fn ffi_rln_proof_free(rln: Option>) { - drop(rln); +pub fn ffi_rln_proof_free(rln_proof: repr_c::Box) { + drop(rln_proof); } // Proof generation APIs @@ -364,24 +364,45 @@ pub fn ffi_verify_rln_proof( rln: &repr_c::Box, proof: &repr_c::Box, x: &CFr, -) -> CResult, 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, roots: &repr_c::Vec, x: &CFr, -) -> CResult, 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, } } diff --git a/rln/src/ffi/ffi_tree.rs b/rln/src/ffi/ffi_tree.rs index 0a0aec8..2dc81ae 100644 --- a/rln/src/ffi/ffi_tree.rs +++ b/rln/src/ffi/ffi_tree.rs @@ -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, } -#[cfg(not(feature = "stateless"))] #[ffi_export] -pub fn ffi_merkle_proof_free(proof: Option>) { - drop(proof); +pub fn ffi_merkle_proof_free(merkle_proof: repr_c::Box) { + drop(merkle_proof); } // Merkle tree management APIs -#[cfg(not(feature = "stateless"))] #[ffi_export] -pub fn ffi_set_tree( - rln: &mut repr_c::Box, - tree_depth: usize, -) -> CResult, repr_c::String> { +pub fn ffi_set_tree(rln: &mut repr_c::Box, 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, - index: usize, -) -> CResult, repr_c::String> { +pub fn ffi_delete_leaf(rln: &mut repr_c::Box, 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, index: usize, - value: &repr_c::Box, -) -> CResult, repr_c::String> { - match rln.tree.set(index, value.0) { - Ok(_) => CResult { - ok: Some(Box_::new(true)), + leaf: &repr_c::Box, +) -> 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, @@ -106,82 +94,70 @@ pub fn ffi_get_leaf( } } -#[cfg(not(feature = "stateless"))] #[ffi_export] pub fn ffi_leaves_set(rln: &repr_c::Box) -> usize { rln.tree.leaves_set() } -#[cfg(not(feature = "stateless"))] #[ffi_export] -pub fn ffi_set_next_leaf( - rln: &mut repr_c::Box, - value: &repr_c::Box, -) -> CResult, 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, leaf: &repr_c::Box) -> 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, index: usize, leaves: &repr_c::Vec, -) -> CResult, 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, leaves: &repr_c::Vec, -) -> CResult, 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, index: usize, leaves: &repr_c::Vec, indices: &repr_c::Vec, -) -> CResult, 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, leaves: &repr_c::Vec, indices: &repr_c::Vec, -) -> CResult, 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) -> repr_c::Box { CFr::from(rln.tree.root()).into() } -#[cfg(not(feature = "stateless"))] #[ffi_export] pub fn ffi_get_proof( rln: &repr_c::Box, @@ -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, - metadata: &repr_c::Vec, -) -> CResult, repr_c::String> { +pub fn ffi_set_metadata(rln: &mut repr_c::Box, metadata: &repr_c::Vec) -> 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) -> CResult, repr_c::String> { match rln.tree.metadata() { @@ -314,16 +281,15 @@ pub fn ffi_get_metadata(rln: &repr_c::Box) -> CResult, } } -#[cfg(not(feature = "stateless"))] #[ffi_export] -pub fn ffi_flush(rln: &mut repr_c::Box) -> CResult, repr_c::String> { +pub fn ffi_flush(rln: &mut repr_c::Box) -> 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()), }, } diff --git a/rln/src/ffi/ffi_utils.rs b/rln/src/ffi/ffi_utils.rs index 2f7e23a..35d6727 100644 --- a/rln/src/ffi/ffi_utils.rs +++ b/rln/src/ffi/ffi_utils.rs @@ -19,6 +19,15 @@ pub struct CResult { pub err: Option, } +// CBoolResult + +#[derive_ReprC] +#[repr(C)] +pub struct CBoolResult { + pub ok: bool, + pub err: Option, +} + // CFr #[derive_ReprC] @@ -96,16 +105,44 @@ pub fn uint_to_cfr(value: u32) -> repr_c::Box { #[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>) { +pub fn cfr_free(cfr: repr_c::Box) { drop(cfr); } // Vec +#[ffi_export] +pub fn vec_cfr_new(capacity: usize) -> repr_c::Vec { + Vec::with_capacity(capacity).into() +} + +#[ffi_export] +pub fn vec_cfr_from_cfr(cfr: &CFr) -> repr_c::Vec { + vec![*cfr].into() +} + +#[ffi_export] +pub fn vec_cfr_push(v: &mut safer_ffi::Vec, cfr: &CFr) { + let mut new: Vec = 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) -> usize { + v.len() +} + #[ffi_export] pub fn vec_cfr_get(v: &repr_c::Vec, i: usize) -> Option<&CFr> { v.get(i) @@ -124,14 +161,12 @@ pub fn vec_cfr_to_bytes_be(vec: &repr_c::Vec) -> repr_c::Vec { } #[ffi_export] -pub fn bytes_le_to_vec_cfr( - bytes: &repr_c::Vec, -) -> CResult>, repr_c::String> { +pub fn bytes_le_to_vec_cfr(bytes: &repr_c::Vec) -> CResult, repr_c::String> { match crate::utils::bytes_le_to_vec_fr(bytes) { Ok((vec_fr, _)) => { let vec_cfr: Vec = 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, -) -> CResult>, repr_c::String> { +pub fn bytes_be_to_vec_cfr(bytes: &repr_c::Vec) -> CResult, repr_c::String> { match crate::utils::bytes_be_to_vec_fr(bytes) { Ok((vec_fr, _)) => { let vec_cfr: Vec = 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) -> repr_c::String { - format!("{:?}", v.iter().map(|cfr| cfr.0).collect::>()).into() +pub fn vec_cfr_debug(v: Option<&repr_c::Vec>) -> repr_c::String { + match v { + Some(v) => { + let vec_fr: Vec = 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) -> repr_c::Vec { } #[ffi_export] -pub fn bytes_le_to_vec_u8( - bytes: &repr_c::Vec, -) -> CResult>, repr_c::String> { +pub fn bytes_le_to_vec_u8(bytes: &repr_c::Vec) -> CResult, 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, -) -> CResult>, repr_c::String> { +pub fn bytes_be_to_vec_u8(bytes: &repr_c::Vec) -> CResult, 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) -> repr_c::String { - format!("{:?}", v.iter().copied().collect::>()).into() +pub fn vec_u8_debug(v: Option<&repr_c::Vec>) -> 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) -> repr_c::Vec { ] .into() } + +#[ffi_export] +pub fn c_string_free(s: repr_c::String) { + drop(s); +} diff --git a/rln/tests/ffi.rs b/rln/tests/ffi.rs index edee801..8214345 100644 --- a/rln/tests/ffi.rs +++ b/rln/tests/ffi.rs @@ -20,7 +20,7 @@ mod test { fn create_rln_instance() -> repr_c::Box { 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::>() .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 { @@ -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::>() .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 = vec![last_leaf_index].into(); let last_leaf_vec: repr_c::Vec = 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::>() .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 = 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 = Vec::new(); @@ -745,24 +611,15 @@ mod test { } let roots_random_vec: repr_c::Vec = 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 = 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 = 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) { diff --git a/rln/tests/ffi_stateless.rs b/rln/tests/ffi_stateless.rs index b45095c..df3171f 100644 --- a/rln/tests/ffi_stateless.rs +++ b/rln/tests/ffi_stateless.rs @@ -13,7 +13,7 @@ mod test { type ConfigOf = ::Config; fn create_rln_instance() -> repr_c::Box { - 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 = 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 = Vec::new(); @@ -297,24 +285,15 @@ mod test { } let roots_random_vec: repr_c::Vec = 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 = 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 + ); } } diff --git a/rln/tests/ffi_utils.rs b/rln/tests/ffi_utils.rs index 2b5a3b1..ef8ec5e 100644 --- a/rln/tests/ffi_utils.rs +++ b/rln/tests/ffi_utils.rs @@ -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];