mirror of https://github.com/vacp2p/zerokit.git
feat(rln): add extended keygen APIs for Semaphore-compatible credentials (#85)
* refactor(rln): update APIs based on updated rln circuit design * chore(rln): update rln vendor submodule * fix(ci): update ci to not ignore rln resources changes * feat(rln): add extended keygen APIs * refactor(rln): rename id_secret/id_key to identity_secret_hash as per RFC * fix(rln): cargo fmt
This commit is contained in:
parent
e69f6a67d8
commit
32f3202e9d
|
@ -97,7 +97,7 @@ rln.key_gen(&mut buffer).unwrap();
|
|||
|
||||
// We deserialize the keygen output to obtain
|
||||
// the identiy_secret and id_commitment
|
||||
let (identity_secret, id_commitment) = deserialize_identity_pair(buffer.into_inner());
|
||||
let (identity_secret_hash, id_commitment) = deserialize_identity_pair(buffer.into_inner());
|
||||
```
|
||||
|
||||
### Add ID commitment to the RLN Merkle tree
|
||||
|
@ -139,7 +139,7 @@ Input buffer is serialized as `[ identity_key | id_index | epoch | signal_len |
|
|||
|
||||
```rust
|
||||
// We prepare input to the proof generation routine
|
||||
let proof_input = prepare_prove_input(identity_secret, id_index, epoch, signal);
|
||||
let proof_input = prepare_prove_input(identity_secret_hash, id_index, epoch, signal);
|
||||
```
|
||||
|
||||
We are now ready to generate a RLN ZK proof along with the _public outputs_ of the ZK circuit evaluation.
|
||||
|
|
148
rln/src/ffi.rs
148
rln/src/ffi.rs
|
@ -297,6 +297,44 @@ pub extern "C" fn seeded_key_gen(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn extended_key_gen(ctx: *const RLN, output_buffer: *mut Buffer) -> bool {
|
||||
let rln = unsafe { &*ctx };
|
||||
let mut output_data: Vec<u8> = Vec::new();
|
||||
if rln.extended_key_gen(&mut output_data).is_ok() {
|
||||
unsafe { *output_buffer = Buffer::from(&output_data[..]) };
|
||||
std::mem::forget(output_data);
|
||||
true
|
||||
} else {
|
||||
std::mem::forget(output_data);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn seeded_extended_key_gen(
|
||||
ctx: *const RLN,
|
||||
input_buffer: *const Buffer,
|
||||
output_buffer: *mut Buffer,
|
||||
) -> bool {
|
||||
let rln = unsafe { &*ctx };
|
||||
let input_data = <&[u8]>::from(unsafe { &*input_buffer });
|
||||
let mut output_data: Vec<u8> = Vec::new();
|
||||
if rln
|
||||
.seeded_extended_key_gen(input_data, &mut output_data)
|
||||
.is_ok()
|
||||
{
|
||||
unsafe { *output_buffer = Buffer::from(&output_data[..]) };
|
||||
std::mem::forget(output_data);
|
||||
true
|
||||
} else {
|
||||
std::mem::forget(output_data);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn recover_id_secret(
|
||||
|
@ -623,8 +661,8 @@ mod test {
|
|||
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
|
||||
|
||||
// generate identity
|
||||
let identity_secret = hash_to_field(b"test-merkle-proof");
|
||||
let id_commitment = poseidon_hash(&vec![identity_secret]);
|
||||
let identity_secret_hash = hash_to_field(b"test-merkle-proof");
|
||||
let id_commitment = poseidon_hash(&vec![identity_secret_hash]);
|
||||
|
||||
// We prepare id_commitment and we set the leaf at provided index
|
||||
let leaf_ser = fr_to_bytes_le(&id_commitment);
|
||||
|
@ -924,7 +962,7 @@ mod test {
|
|||
assert!(success, "key gen call failed");
|
||||
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||
let result_data = <&[u8]>::from(&output_buffer).to_vec();
|
||||
let (identity_secret, read) = bytes_le_to_fr(&result_data);
|
||||
let (identity_secret_hash, read) = bytes_le_to_fr(&result_data);
|
||||
let (id_commitment, _) = bytes_le_to_fr(&result_data[read..].to_vec());
|
||||
|
||||
// We set as leaf id_commitment, its index would be equal to no_of_leaves
|
||||
|
@ -944,9 +982,9 @@ mod test {
|
|||
let epoch = hash_to_field(b"test-epoch");
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret));
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized.append(&mut identity_index.to_le_bytes().to_vec());
|
||||
serialized.append(&mut fr_to_bytes_le(&epoch));
|
||||
serialized.append(&mut signal_len.to_le_bytes().to_vec());
|
||||
|
@ -1009,7 +1047,7 @@ mod test {
|
|||
assert!(success, "key gen call failed");
|
||||
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||
let result_data = <&[u8]>::from(&output_buffer).to_vec();
|
||||
let (identity_secret, read) = bytes_le_to_fr(&result_data);
|
||||
let (identity_secret_hash, read) = bytes_le_to_fr(&result_data);
|
||||
let (id_commitment, _) = bytes_le_to_fr(&result_data[read..].to_vec());
|
||||
|
||||
// We set as leaf id_commitment, its index would be equal to no_of_leaves
|
||||
|
@ -1029,9 +1067,9 @@ mod test {
|
|||
let epoch = hash_to_field(b"test-epoch");
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret));
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized.append(&mut identity_index.to_le_bytes().to_vec());
|
||||
serialized.append(&mut fr_to_bytes_le(&epoch));
|
||||
serialized.append(&mut signal_len.to_le_bytes().to_vec());
|
||||
|
@ -1122,7 +1160,7 @@ mod test {
|
|||
assert!(success, "key gen call failed");
|
||||
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||
let result_data = <&[u8]>::from(&output_buffer).to_vec();
|
||||
let (identity_secret, read) = bytes_le_to_fr(&result_data);
|
||||
let (identity_secret_hash, read) = bytes_le_to_fr(&result_data);
|
||||
let (id_commitment, _) = bytes_le_to_fr(&result_data[read..].to_vec());
|
||||
|
||||
// We set as leaf id_commitment, its index would be equal to 0 since tree is empty
|
||||
|
@ -1148,9 +1186,9 @@ mod test {
|
|||
let epoch = hash_to_field(b"test-epoch");
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized1: Vec<u8> = Vec::new();
|
||||
serialized1.append(&mut fr_to_bytes_le(&identity_secret));
|
||||
serialized1.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized1.append(&mut identity_index.to_le_bytes().to_vec());
|
||||
serialized1.append(&mut fr_to_bytes_le(&epoch));
|
||||
|
||||
|
@ -1194,17 +1232,17 @@ mod test {
|
|||
);
|
||||
assert!(success, "recover id secret call failed");
|
||||
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||
let serialized_id_secret = <&[u8]>::from(&output_buffer).to_vec();
|
||||
let serialized_identity_secret_hash = <&[u8]>::from(&output_buffer).to_vec();
|
||||
|
||||
// We passed two shares for the same secret, so recovery should be successful
|
||||
// To check it, we ensure that recovered_id_secret is non-empty
|
||||
assert!(!serialized_id_secret.is_empty());
|
||||
// To check it, we ensure that recovered identity secret hash is empty
|
||||
assert!(!serialized_identity_secret_hash.is_empty());
|
||||
|
||||
// We check if the recovered id secret corresponds to the original one
|
||||
let (recovered_id_secret, _) = bytes_le_to_fr(&serialized_id_secret);
|
||||
assert_eq!(recovered_id_secret, identity_secret);
|
||||
// We check if the recovered identity secret hash corresponds to the original one
|
||||
let (recovered_identity_secret_hash, _) = bytes_le_to_fr(&serialized_identity_secret_hash);
|
||||
assert_eq!(recovered_identity_secret_hash, identity_secret_hash);
|
||||
|
||||
// We now test that computing_id_secret is unsuccessful if shares computed from two different id secrets but within same epoch are passed
|
||||
// We now test that computing identity_secret_hash is unsuccessful if shares computed from two different identity secret hashes but within same epoch are passed
|
||||
|
||||
// We generate a new identity pair
|
||||
let mut output_buffer = MaybeUninit::<Buffer>::uninit();
|
||||
|
@ -1212,7 +1250,7 @@ mod test {
|
|||
assert!(success, "key gen call failed");
|
||||
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||
let result_data = <&[u8]>::from(&output_buffer).to_vec();
|
||||
let (identity_secret_new, read) = bytes_le_to_fr(&result_data);
|
||||
let (identity_secret_hash_new, read) = bytes_le_to_fr(&result_data);
|
||||
let (id_commitment_new, _) = bytes_le_to_fr(&result_data[read..].to_vec());
|
||||
|
||||
// We set as leaf id_commitment, its index would be equal to 1 since at 0 there is id_commitment
|
||||
|
@ -1228,10 +1266,10 @@ mod test {
|
|||
let signal3_len = u64::try_from(signal3.len()).unwrap();
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// Note that epoch is the same as before
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_new));
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash_new));
|
||||
serialized.append(&mut identity_index_new.to_le_bytes().to_vec());
|
||||
serialized.append(&mut fr_to_bytes_le(&epoch));
|
||||
serialized.append(&mut signal3_len.to_le_bytes().to_vec());
|
||||
|
@ -1246,7 +1284,7 @@ mod test {
|
|||
// result_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ]
|
||||
let proof_data_3 = <&[u8]>::from(&output_buffer).to_vec();
|
||||
|
||||
// We attempt to recover the secret using share1 (coming from identity_secret) and share3 (coming from identity_secret_new)
|
||||
// We attempt to recover the secret using share1 (coming from identity_secret_hash) and share3 (coming from identity_secret_hash_new)
|
||||
|
||||
let input_proof_buffer_1 = &Buffer::from(proof_data_1.as_ref());
|
||||
let input_proof_buffer_3 = &Buffer::from(proof_data_3.as_ref());
|
||||
|
@ -1259,11 +1297,11 @@ mod test {
|
|||
);
|
||||
assert!(success, "recover id secret call failed");
|
||||
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||
let serialized_id_secret = <&[u8]>::from(&output_buffer).to_vec();
|
||||
let serialized_identity_secret_hash = <&[u8]>::from(&output_buffer).to_vec();
|
||||
|
||||
// We passed two shares for different secrets, so recovery should be not successful
|
||||
// To check it, we ensure that recovered_id_secret is empty
|
||||
assert!(serialized_id_secret.is_empty());
|
||||
// To check it, we ensure that recovered identity secret hash is empty
|
||||
assert!(serialized_identity_secret_hash.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1286,11 +1324,11 @@ mod test {
|
|||
assert!(success, "seeded key gen call failed");
|
||||
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||
let result_data = <&[u8]>::from(&output_buffer).to_vec();
|
||||
let (identity_secret, read) = bytes_le_to_fr(&result_data);
|
||||
let (identity_secret_hash, read) = bytes_le_to_fr(&result_data);
|
||||
let (id_commitment, _) = bytes_le_to_fr(&result_data[read..].to_vec());
|
||||
|
||||
// We check against expected values
|
||||
let expected_identity_secret_seed_bytes = str_to_fr(
|
||||
let expected_identity_secret_hash_seed_bytes = str_to_fr(
|
||||
"0x766ce6c7e7a01bdf5b3f257616f603918c30946fa23480f2859c597817e6716",
|
||||
16,
|
||||
);
|
||||
|
@ -1299,7 +1337,61 @@ mod test {
|
|||
16,
|
||||
);
|
||||
|
||||
assert_eq!(identity_secret, expected_identity_secret_seed_bytes);
|
||||
assert_eq!(
|
||||
identity_secret_hash,
|
||||
expected_identity_secret_hash_seed_bytes
|
||||
);
|
||||
assert_eq!(id_commitment, expected_id_commitment_seed_bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Tests hash to field using FFI APIs
|
||||
fn test_seeded_extended_keygen_ffi() {
|
||||
let tree_height = TEST_TREE_HEIGHT;
|
||||
|
||||
// We create a RLN instance
|
||||
let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit();
|
||||
let input_buffer = &Buffer::from(TEST_RESOURCES_FOLDER.as_bytes());
|
||||
let success = new(tree_height, input_buffer, rln_pointer.as_mut_ptr());
|
||||
assert!(success, "RLN object creation failed");
|
||||
let rln_pointer = unsafe { &mut *rln_pointer.assume_init() };
|
||||
|
||||
// We generate a new identity tuple from an input seed
|
||||
let seed_bytes: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
let input_buffer = &Buffer::from(seed_bytes);
|
||||
let mut output_buffer = MaybeUninit::<Buffer>::uninit();
|
||||
let success =
|
||||
seeded_extended_key_gen(rln_pointer, input_buffer, output_buffer.as_mut_ptr());
|
||||
assert!(success, "seeded key gen call failed");
|
||||
let output_buffer = unsafe { output_buffer.assume_init() };
|
||||
let result_data = <&[u8]>::from(&output_buffer).to_vec();
|
||||
let (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) =
|
||||
deserialize_identity_tuple(result_data);
|
||||
|
||||
// We check against expected values
|
||||
let expected_identity_trapdoor_seed_bytes = str_to_fr(
|
||||
"0x766ce6c7e7a01bdf5b3f257616f603918c30946fa23480f2859c597817e6716",
|
||||
16,
|
||||
);
|
||||
let expected_identity_nullifier_seed_bytes = str_to_fr(
|
||||
"0x1f18714c7bc83b5bca9e89d404cf6f2f585bc4c0f7ed8b53742b7e2b298f50b4",
|
||||
16,
|
||||
);
|
||||
let expected_identity_secret_hash_seed_bytes = str_to_fr(
|
||||
"0x2aca62aaa7abaf3686fff2caf00f55ab9462dc12db5b5d4bcf3994e671f8e521",
|
||||
16,
|
||||
);
|
||||
let expected_id_commitment_seed_bytes = str_to_fr(
|
||||
"0x68b66aa0a8320d2e56842581553285393188714c48f9b17acd198b4f1734c5c",
|
||||
16,
|
||||
);
|
||||
|
||||
assert_eq!(identity_trapdoor, expected_identity_trapdoor_seed_bytes);
|
||||
assert_eq!(identity_nullifier, expected_identity_nullifier_seed_bytes);
|
||||
assert_eq!(
|
||||
identity_secret_hash,
|
||||
expected_identity_secret_hash_seed_bytes
|
||||
);
|
||||
assert_eq!(id_commitment, expected_id_commitment_seed_bytes);
|
||||
}
|
||||
|
||||
|
|
|
@ -179,8 +179,8 @@ mod test {
|
|||
let leaf_index = 3;
|
||||
|
||||
// generate identity
|
||||
let identity_secret = hash_to_field(b"test-merkle-proof");
|
||||
let id_commitment = poseidon_hash(&vec![identity_secret]);
|
||||
let identity_secret_hash = hash_to_field(b"test-merkle-proof");
|
||||
let id_commitment = poseidon_hash(&vec![identity_secret_hash]);
|
||||
|
||||
// generate merkle tree
|
||||
let default_leaf = Fr::from(0);
|
||||
|
@ -365,7 +365,7 @@ mod test {
|
|||
let leaf_index = 3;
|
||||
|
||||
// Generate identity pair
|
||||
let (identity_secret, id_commitment) = keygen();
|
||||
let (identity_secret_hash, id_commitment) = keygen();
|
||||
|
||||
//// generate merkle tree
|
||||
let default_leaf = Fr::from(0);
|
||||
|
@ -382,7 +382,7 @@ mod test {
|
|||
//let rln_identifier = hash_to_field(b"test-rln-identifier");
|
||||
|
||||
let rln_witness: RLNWitnessInput = rln_witness_from_values(
|
||||
identity_secret,
|
||||
identity_secret_hash,
|
||||
&merkle_proof,
|
||||
x,
|
||||
epoch, /*, rln_identifier*/
|
||||
|
@ -436,10 +436,10 @@ mod test {
|
|||
fn test_seeded_keygen() {
|
||||
// Generate identity pair using a seed phrase
|
||||
let seed_phrase: &str = "A seed phrase example";
|
||||
let (identity_secret, id_commitment) = seeded_keygen(seed_phrase.as_bytes());
|
||||
let (identity_secret_hash, id_commitment) = seeded_keygen(seed_phrase.as_bytes());
|
||||
|
||||
// We check against expected values
|
||||
let expected_identity_secret_seed_phrase = str_to_fr(
|
||||
let expected_identity_secret_hash_seed_phrase = str_to_fr(
|
||||
"0x20df38f3f00496f19fe7c6535492543b21798ed7cb91aebe4af8012db884eda3",
|
||||
16,
|
||||
);
|
||||
|
@ -448,15 +448,18 @@ mod test {
|
|||
16,
|
||||
);
|
||||
|
||||
assert_eq!(identity_secret, expected_identity_secret_seed_phrase);
|
||||
assert_eq!(
|
||||
identity_secret_hash,
|
||||
expected_identity_secret_hash_seed_phrase
|
||||
);
|
||||
assert_eq!(id_commitment, expected_id_commitment_seed_phrase);
|
||||
|
||||
// Generate identity pair using an byte array
|
||||
let seed_bytes: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
let (identity_secret, id_commitment) = seeded_keygen(seed_bytes);
|
||||
let (identity_secret_hash, id_commitment) = seeded_keygen(seed_bytes);
|
||||
|
||||
// We check against expected values
|
||||
let expected_identity_secret_seed_bytes = str_to_fr(
|
||||
let expected_identity_secret_hash_seed_bytes = str_to_fr(
|
||||
"0x766ce6c7e7a01bdf5b3f257616f603918c30946fa23480f2859c597817e6716",
|
||||
16,
|
||||
);
|
||||
|
@ -465,13 +468,19 @@ mod test {
|
|||
16,
|
||||
);
|
||||
|
||||
assert_eq!(identity_secret, expected_identity_secret_seed_bytes);
|
||||
assert_eq!(
|
||||
identity_secret_hash,
|
||||
expected_identity_secret_hash_seed_bytes
|
||||
);
|
||||
assert_eq!(id_commitment, expected_id_commitment_seed_bytes);
|
||||
|
||||
// We check again if the identity pair generated with the same seed phrase corresponds to the previously generated one
|
||||
let (identity_secret, id_commitment) = seeded_keygen(seed_phrase.as_bytes());
|
||||
let (identity_secret_hash, id_commitment) = seeded_keygen(seed_phrase.as_bytes());
|
||||
|
||||
assert_eq!(identity_secret, expected_identity_secret_seed_phrase);
|
||||
assert_eq!(
|
||||
identity_secret_hash,
|
||||
expected_identity_secret_hash_seed_phrase
|
||||
);
|
||||
assert_eq!(id_commitment, expected_id_commitment_seed_phrase);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,10 +63,32 @@ pub fn deserialize_field_element(serialized: Vec<u8>) -> Fr {
|
|||
}
|
||||
|
||||
pub fn deserialize_identity_pair(serialized: Vec<u8>) -> (Fr, Fr) {
|
||||
let (identity_secret, read) = bytes_le_to_fr(&serialized);
|
||||
let (identity_secret_hash, read) = bytes_le_to_fr(&serialized);
|
||||
let (id_commitment, _) = bytes_le_to_fr(&serialized[read..].to_vec());
|
||||
|
||||
return (identity_secret, id_commitment);
|
||||
return (identity_secret_hash, id_commitment);
|
||||
}
|
||||
|
||||
pub fn deserialize_identity_tuple(serialized: Vec<u8>) -> (Fr, Fr, Fr, Fr) {
|
||||
let mut all_read = 0;
|
||||
|
||||
let (identity_trapdoor, read) = bytes_le_to_fr(&serialized[all_read..].to_vec());
|
||||
all_read += read;
|
||||
|
||||
let (identity_nullifier, read) = bytes_le_to_fr(&serialized[all_read..].to_vec());
|
||||
all_read += read;
|
||||
|
||||
let (identity_secret_hash, read) = bytes_le_to_fr(&serialized[all_read..].to_vec());
|
||||
all_read += read;
|
||||
|
||||
let (identity_commitment, _) = bytes_le_to_fr(&serialized[all_read..].to_vec());
|
||||
|
||||
return (
|
||||
identity_trapdoor,
|
||||
identity_nullifier,
|
||||
identity_secret_hash,
|
||||
identity_commitment,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn serialize_witness(rln_witness: &RLNWitnessInput) -> Vec<u8> {
|
||||
|
@ -121,7 +143,7 @@ pub fn deserialize_witness(serialized: &[u8]) -> (RLNWitnessInput, usize) {
|
|||
|
||||
// This function deserializes input for kilic's rln generate_proof public API
|
||||
// https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L148
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// return value is a rln witness populated according to this information
|
||||
pub fn proof_inputs_to_rln_witness(
|
||||
tree: &mut PoseidonTree,
|
||||
|
@ -387,18 +409,38 @@ pub fn compute_tree_root(
|
|||
// Protocol utility functions
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
// Generates a tupe (identity_secret, id_commitment) where
|
||||
// identity_secret is random and id_commitment = PoseidonHash(identity_secret)
|
||||
// Generates a tuple (identity_secret_hash, id_commitment) where
|
||||
// identity_secret_hash is random and id_commitment = PoseidonHash(identity_secret_hash)
|
||||
// RNG is instantiated using thread_rng()
|
||||
pub fn keygen() -> (Fr, Fr) {
|
||||
let mut rng = thread_rng();
|
||||
let identity_secret = Fr::rand(&mut rng);
|
||||
let id_commitment = poseidon_hash(&[identity_secret]);
|
||||
(identity_secret, id_commitment)
|
||||
let identity_secret_hash = Fr::rand(&mut rng);
|
||||
let id_commitment = poseidon_hash(&[identity_secret_hash]);
|
||||
(identity_secret_hash, id_commitment)
|
||||
}
|
||||
|
||||
// Generates a tupe (identity_secret, id_commitment) where
|
||||
// identity_secret is random and id_commitment = PoseidonHash(identity_secret)
|
||||
// Generates a tuple (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) where
|
||||
// identity_trapdoor and identity_nullifier are random,
|
||||
// identity_secret_hash = PoseidonHash(identity_trapdoor, identity_nullifier),
|
||||
// id_commitment = PoseidonHash(identity_secret_hash),
|
||||
// RNG is instantiated using thread_rng()
|
||||
// Generated credentials are compatible with Semaphore credentials
|
||||
pub fn extended_keygen() -> (Fr, Fr, Fr, Fr) {
|
||||
let mut rng = thread_rng();
|
||||
let identity_trapdoor = Fr::rand(&mut rng);
|
||||
let identity_nullifier = Fr::rand(&mut rng);
|
||||
let identity_secret_hash = poseidon_hash(&[identity_trapdoor, identity_nullifier]);
|
||||
let id_commitment = poseidon_hash(&[identity_secret_hash]);
|
||||
(
|
||||
identity_trapdoor,
|
||||
identity_nullifier,
|
||||
identity_secret_hash,
|
||||
id_commitment,
|
||||
)
|
||||
}
|
||||
|
||||
// Generates a tuple (identity_secret_hash, id_commitment) where
|
||||
// identity_secret_hash is random and id_commitment = PoseidonHash(identity_secret_hash)
|
||||
// RNG is instantiated using 20 rounds of ChaCha seeded with the hash of the input
|
||||
pub fn seeded_keygen(signal: &[u8]) -> (Fr, Fr) {
|
||||
// ChaCha20 requires a seed of exactly 32 bytes.
|
||||
|
@ -409,9 +451,36 @@ pub fn seeded_keygen(signal: &[u8]) -> (Fr, Fr) {
|
|||
hasher.finalize(&mut seed);
|
||||
|
||||
let mut rng = ChaCha20Rng::from_seed(seed);
|
||||
let identity_secret = Fr::rand(&mut rng);
|
||||
let id_commitment = poseidon_hash(&[identity_secret]);
|
||||
(identity_secret, id_commitment)
|
||||
let identity_secret_hash = Fr::rand(&mut rng);
|
||||
let id_commitment = poseidon_hash(&[identity_secret_hash]);
|
||||
(identity_secret_hash, id_commitment)
|
||||
}
|
||||
|
||||
// Generates a tuple (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) where
|
||||
// identity_trapdoor and identity_nullifier are random,
|
||||
// identity_secret_hash = PoseidonHash(identity_trapdoor, identity_nullifier),
|
||||
// id_commitment = PoseidonHash(identity_secret_hash),
|
||||
// RNG is instantiated using 20 rounds of ChaCha seeded with the hash of the input
|
||||
// Generated credentials are compatible with Semaphore credentials
|
||||
pub fn extended_seeded_keygen(signal: &[u8]) -> (Fr, Fr, Fr, Fr) {
|
||||
// ChaCha20 requires a seed of exactly 32 bytes.
|
||||
// We first hash the input seed signal to a 32 bytes array and pass this as seed to ChaCha20
|
||||
let mut seed = [0; 32];
|
||||
let mut hasher = Keccak::v256();
|
||||
hasher.update(signal);
|
||||
hasher.finalize(&mut seed);
|
||||
|
||||
let mut rng = ChaCha20Rng::from_seed(seed);
|
||||
let identity_trapdoor = Fr::rand(&mut rng);
|
||||
let identity_nullifier = Fr::rand(&mut rng);
|
||||
let identity_secret_hash = poseidon_hash(&[identity_trapdoor, identity_nullifier]);
|
||||
let id_commitment = poseidon_hash(&[identity_secret_hash]);
|
||||
(
|
||||
identity_trapdoor,
|
||||
identity_nullifier,
|
||||
identity_secret_hash,
|
||||
id_commitment,
|
||||
)
|
||||
}
|
||||
|
||||
// Hashes arbitrary signal to the underlying prime field
|
||||
|
@ -452,7 +521,7 @@ pub fn compute_id_secret(
|
|||
// We successfully recovered the identity secret
|
||||
return Ok(a_0);
|
||||
} else {
|
||||
return Err("Cannot recover id_secret from provided shares".into());
|
||||
return Err("Cannot recover identity_secret_hash from provided shares".into());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -177,8 +177,8 @@ impl RLN<'_> {
|
|||
/// ```
|
||||
/// use crate::protocol::*;
|
||||
///
|
||||
/// // We generate a random id secret and commitment pair
|
||||
/// let (identity_secret, id_commitment) = keygen();
|
||||
/// // We generate a random identity secret hash and commitment pair
|
||||
/// let (identity_secret_hash, id_commitment) = keygen();
|
||||
///
|
||||
/// // We define the tree index where id_commitment will be added
|
||||
/// let id_index = 10;
|
||||
|
@ -489,7 +489,7 @@ impl RLN<'_> {
|
|||
/// Computes a zkSNARK RLN proof from the identity secret, the Merkle tree index, the epoch and signal.
|
||||
///
|
||||
/// Input values are:
|
||||
/// - `input_data`: a reader for the serialization of `[ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]`
|
||||
/// - `input_data`: a reader for the serialization of `[ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]`
|
||||
///
|
||||
/// Output values are:
|
||||
/// - `output_data`: a writer receiving the serialization of the zkSNARK proof and the circuit evaluations outputs, i.e. `[ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]`
|
||||
|
@ -500,7 +500,7 @@ impl RLN<'_> {
|
|||
/// use rln::utils::*;
|
||||
///
|
||||
/// // Generate identity pair
|
||||
/// let (identity_secret, id_commitment) = keygen();
|
||||
/// let (identity_secret_hash, id_commitment) = keygen();
|
||||
///
|
||||
/// // We set as leaf id_commitment after storing its index
|
||||
/// let identity_index = 10;
|
||||
|
@ -516,9 +516,9 @@ impl RLN<'_> {
|
|||
/// let epoch = hash_to_field(b"test-epoch");
|
||||
///
|
||||
/// // We prepare input for generate_rln_proof API
|
||||
/// // input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
/// // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
/// let mut serialized: Vec<u8> = Vec::new();
|
||||
/// serialized.append(&mut fr_to_bytes_le(&identity_secret));
|
||||
/// serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
/// serialized.append(&mut identity_index.to_le_bytes().to_vec());
|
||||
/// serialized.append(&mut fr_to_bytes_le(&epoch));
|
||||
/// serialized.append(&mut signal_len.to_le_bytes().to_vec());
|
||||
|
@ -782,12 +782,45 @@ impl RLN<'_> {
|
|||
/// rln.key_gen(&mut buffer).unwrap();
|
||||
///
|
||||
/// // We deserialize the keygen output
|
||||
/// let (identity_secret, id_commitment) = deserialize_identity_pair(buffer.into_inner());
|
||||
/// let (identity_secret_hash, id_commitment) = deserialize_identity_pair(buffer.into_inner());
|
||||
/// ```
|
||||
pub fn key_gen<W: Write>(&self, mut output_data: W) -> io::Result<()> {
|
||||
let (id_key, id_commitment_key) = keygen();
|
||||
output_data.write_all(&fr_to_bytes_le(&id_key))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&id_commitment_key))?;
|
||||
let (identity_secret_hash, id_commitment) = keygen();
|
||||
output_data.write_all(&fr_to_bytes_le(&identity_secret_hash))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&id_commitment))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns an identity trapdoor, nullifier, secret and commitment tuple.
|
||||
///
|
||||
/// The identity secret is the Poseidon hash of the identity trapdoor and identity nullifier.
|
||||
///
|
||||
/// The identity commitment is the Poseidon hash of the identity secret.
|
||||
///
|
||||
/// Generated credentials are compatible with [Semaphore](https://semaphore.appliedzkp.org/docs/guides/identities)'s credentials.
|
||||
///
|
||||
/// Output values are:
|
||||
/// - `output_data`: a writer receiving the serialization of the identity tapdoor, identity nullifier, identity secret and identity commitment (serialization done with `rln::utils::fr_to_bytes_le`)
|
||||
///
|
||||
/// Example
|
||||
/// ```
|
||||
/// use rln::protocol::*;
|
||||
///
|
||||
/// // We generate an identity tuple
|
||||
/// let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||
/// rln.extended_key_gen(&mut buffer).unwrap();
|
||||
///
|
||||
/// // We deserialize the keygen output
|
||||
/// let (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) = deserialize_identity_tuple(buffer.into_inner());
|
||||
/// ```
|
||||
pub fn extended_key_gen<W: Write>(&self, mut output_data: W) -> io::Result<()> {
|
||||
let (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) =
|
||||
extended_keygen();
|
||||
output_data.write_all(&fr_to_bytes_le(&identity_trapdoor))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&identity_nullifier))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&identity_secret_hash))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&id_commitment))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -814,7 +847,7 @@ impl RLN<'_> {
|
|||
/// .unwrap();
|
||||
///
|
||||
/// // We deserialize the keygen output
|
||||
/// let (identity_secret, id_commitment) = deserialize_identity_pair(output_buffer.into_inner());
|
||||
/// let (identity_secret_hash, id_commitment) = deserialize_identity_pair(output_buffer.into_inner());
|
||||
/// ```
|
||||
pub fn seeded_key_gen<R: Read, W: Write>(
|
||||
&self,
|
||||
|
@ -824,9 +857,55 @@ impl RLN<'_> {
|
|||
let mut serialized: Vec<u8> = Vec::new();
|
||||
input_data.read_to_end(&mut serialized)?;
|
||||
|
||||
let (id_key, id_commitment_key) = seeded_keygen(&serialized);
|
||||
output_data.write_all(&fr_to_bytes_le(&id_key))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&id_commitment_key))?;
|
||||
let (identity_secret_hash, id_commitment) = seeded_keygen(&serialized);
|
||||
output_data.write_all(&fr_to_bytes_le(&identity_secret_hash))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&id_commitment))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns an identity trapdoor, nullifier, secret and commitment tuple generated using a seed.
|
||||
///
|
||||
/// The identity secret is the Poseidon hash of the identity trapdoor and identity nullifier.
|
||||
///
|
||||
/// The identity commitment is the Poseidon hash of the identity secret.
|
||||
///
|
||||
/// Generated credentials are compatible with [Semaphore](https://semaphore.appliedzkp.org/docs/guides/identities)'s credentials.
|
||||
///
|
||||
/// Input values are:
|
||||
/// - `input_data`: a reader for the byte vector containing the seed
|
||||
///
|
||||
/// Output values are:
|
||||
/// - `output_data`: a writer receiving the serialization of the identity tapdoor, identity nullifier, identity secret and identity commitment (serialization done with `rln::utils::fr_to_bytes_le`)
|
||||
///
|
||||
/// Example
|
||||
/// ```
|
||||
/// use rln::protocol::*;
|
||||
///
|
||||
/// let seed_bytes: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
///
|
||||
/// let mut input_buffer = Cursor::new(&seed_bytes);
|
||||
/// let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
/// rln.seeded_key_gen(&mut input_buffer, &mut output_buffer)
|
||||
/// .unwrap();
|
||||
///
|
||||
/// // We deserialize the keygen output
|
||||
/// let (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) = deserialize_identity_tuple(buffer.into_inner());
|
||||
/// ```
|
||||
pub fn seeded_extended_key_gen<R: Read, W: Write>(
|
||||
&self,
|
||||
mut input_data: R,
|
||||
mut output_data: W,
|
||||
) -> io::Result<()> {
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
input_data.read_to_end(&mut serialized)?;
|
||||
|
||||
let (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) =
|
||||
extended_seeded_keygen(&serialized);
|
||||
output_data.write_all(&fr_to_bytes_le(&identity_trapdoor))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&identity_nullifier))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&identity_secret_hash))?;
|
||||
output_data.write_all(&fr_to_bytes_le(&id_commitment))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -838,11 +917,11 @@ impl RLN<'_> {
|
|||
/// - `input_proof_data_2`: same as `input_proof_data_1`
|
||||
///
|
||||
/// Output values are:
|
||||
/// - `output_data`: a writer receiving the serialization of the recovered identity secret field element if correctly recovered (serialization done with [`rln::utils::fr_to_bytes_le`](crate::utils::fr_to_bytes_le)), a writer receiving an empty byte vector if not.
|
||||
/// - `output_data`: a writer receiving the serialization of the recovered identity secret hash field element if correctly recovered (serialization done with [`rln::utils::fr_to_bytes_le`](crate::utils::fr_to_bytes_le)), a writer receiving an empty byte vector if not.
|
||||
///
|
||||
/// Example
|
||||
/// ```
|
||||
/// // identity_secret, proof_data_1 and proof_data_2 are computed as in the example code snippet provided for rln::public::RLN::generate_rln_proof using same identity secret and epoch (but not necessarily same signal)
|
||||
/// // identity_secret_hash, proof_data_1 and proof_data_2 are computed as in the example code snippet provided for rln::public::RLN::generate_rln_proof using same identity secret and epoch (but not necessarily same signal)
|
||||
///
|
||||
/// let mut input_proof_data_1 = Cursor::new(proof_data_1);
|
||||
/// let mut input_proof_data_2 = Cursor::new(proof_data_2);
|
||||
|
@ -854,14 +933,14 @@ impl RLN<'_> {
|
|||
/// )
|
||||
/// .unwrap();
|
||||
///
|
||||
/// let serialized_id_secret = output_buffer.into_inner();
|
||||
/// let serialized_identity_secret_hash = output_buffer.into_inner();
|
||||
///
|
||||
/// // We ensure that a non-empty value is written to output_buffer
|
||||
/// assert!(!serialized_id_secret.is_empty());
|
||||
/// assert!(!serialized_identity_secret_hash.is_empty());
|
||||
///
|
||||
/// // We check if the recovered id secret corresponds to the original one
|
||||
/// let (recovered_id_secret, _) = bytes_le_to_fr(&serialized_id_secret);
|
||||
/// assert_eq!(recovered_id_secret, identity_secret);
|
||||
/// // We check if the recovered identity secret hash corresponds to the original one
|
||||
/// let (recovered_identity_secret_hash, _) = bytes_le_to_fr(&serialized_identity_secret_hash);
|
||||
/// assert_eq!(recovered_identity_secret_hash, identity_secret_hash);
|
||||
/// ```
|
||||
pub fn recover_id_secret<R: Read, W: Write>(
|
||||
&self,
|
||||
|
@ -894,12 +973,13 @@ impl RLN<'_> {
|
|||
let share2 = (proof_values_2.x, proof_values_2.y);
|
||||
|
||||
// We recover the secret
|
||||
let recovered_id_secret = compute_id_secret(share1, share2, external_nullifier_1);
|
||||
let recovered_identity_secret_hash =
|
||||
compute_id_secret(share1, share2, external_nullifier_1);
|
||||
|
||||
// If an id secret is recovered, we write it to output_data, otherwise nothing will be written.
|
||||
if recovered_id_secret.is_ok() {
|
||||
let id_secret = recovered_id_secret.unwrap();
|
||||
output_data.write_all(&fr_to_bytes_le(&id_secret))?;
|
||||
// If an identity secret hash is recovered, we write it to output_data, otherwise nothing will be written.
|
||||
if recovered_identity_secret_hash.is_ok() {
|
||||
let identity_secret_hash = recovered_identity_secret_hash.unwrap();
|
||||
output_data.write_all(&fr_to_bytes_le(&identity_secret_hash))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -941,7 +1021,7 @@ impl RLN<'_> {
|
|||
/// Returns the serialization of a [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) populated from the identity secret, the Merkle tree index, the epoch and signal.
|
||||
///
|
||||
/// Input values are:
|
||||
/// - `input_data`: a reader for the serialization of `[ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]`
|
||||
/// - `input_data`: a reader for the serialization of `[ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]`
|
||||
///
|
||||
/// The function returns the corresponding [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) object serialized using [`rln::protocol::serialize_witness`](crate::protocol::serialize_witness)).
|
||||
pub fn get_serialized_rln_witness<R: Read>(&mut self, mut input_data: R) -> Vec<u8> {
|
||||
|
@ -1197,8 +1277,8 @@ mod test {
|
|||
let mut rln = RLN::new(tree_height, input_buffer);
|
||||
|
||||
// generate identity
|
||||
let identity_secret = hash_to_field(b"test-merkle-proof");
|
||||
let id_commitment = poseidon_hash(&vec![identity_secret]);
|
||||
let identity_secret_hash = hash_to_field(b"test-merkle-proof");
|
||||
let id_commitment = poseidon_hash(&vec![identity_secret_hash]);
|
||||
|
||||
// We pass id_commitment as Read buffer to RLN's set_leaf
|
||||
let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment));
|
||||
|
@ -1412,7 +1492,7 @@ mod test {
|
|||
rln.init_tree_with_leaves(&mut buffer).unwrap();
|
||||
|
||||
// Generate identity pair
|
||||
let (identity_secret, id_commitment) = keygen();
|
||||
let (identity_secret_hash, id_commitment) = keygen();
|
||||
|
||||
// We set as leaf id_commitment after storing its index
|
||||
let identity_index = u64::try_from(rln.tree.leaves_set()).unwrap();
|
||||
|
@ -1428,9 +1508,9 @@ mod test {
|
|||
let epoch = hash_to_field(b"test-epoch");
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret));
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized.append(&mut identity_index.to_le_bytes().to_vec());
|
||||
serialized.append(&mut fr_to_bytes_le(&epoch));
|
||||
serialized.append(&mut signal_len.to_le_bytes().to_vec());
|
||||
|
@ -1477,7 +1557,7 @@ mod test {
|
|||
rln.init_tree_with_leaves(&mut buffer).unwrap();
|
||||
|
||||
// Generate identity pair
|
||||
let (identity_secret, id_commitment) = keygen();
|
||||
let (identity_secret_hash, id_commitment) = keygen();
|
||||
|
||||
// We set as leaf id_commitment after storing its index
|
||||
let identity_index = u64::try_from(rln.tree.leaves_set()).unwrap();
|
||||
|
@ -1493,9 +1573,9 @@ mod test {
|
|||
let epoch = hash_to_field(b"test-epoch");
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret));
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized.append(&mut identity_index.to_le_bytes().to_vec());
|
||||
serialized.append(&mut fr_to_bytes_le(&epoch));
|
||||
serialized.append(&mut signal_len.to_le_bytes().to_vec());
|
||||
|
@ -1564,11 +1644,11 @@ mod test {
|
|||
.unwrap();
|
||||
let serialized_output = output_buffer.into_inner();
|
||||
|
||||
let (identity_secret, read) = bytes_le_to_fr(&serialized_output);
|
||||
let (identity_secret_hash, read) = bytes_le_to_fr(&serialized_output);
|
||||
let (id_commitment, _) = bytes_le_to_fr(&serialized_output[read..].to_vec());
|
||||
|
||||
// We check against expected values
|
||||
let expected_identity_secret_seed_bytes = str_to_fr(
|
||||
let expected_identity_secret_hash_seed_bytes = str_to_fr(
|
||||
"0x766ce6c7e7a01bdf5b3f257616f603918c30946fa23480f2859c597817e6716",
|
||||
16,
|
||||
);
|
||||
|
@ -1577,7 +1657,53 @@ mod test {
|
|||
16,
|
||||
);
|
||||
|
||||
assert_eq!(identity_secret, expected_identity_secret_seed_bytes);
|
||||
assert_eq!(
|
||||
identity_secret_hash,
|
||||
expected_identity_secret_hash_seed_bytes
|
||||
);
|
||||
assert_eq!(id_commitment, expected_id_commitment_seed_bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seeded_extended_keygen() {
|
||||
let rln = RLN::default();
|
||||
|
||||
let seed_bytes: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
let mut input_buffer = Cursor::new(&seed_bytes);
|
||||
let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
|
||||
rln.seeded_extended_key_gen(&mut input_buffer, &mut output_buffer)
|
||||
.unwrap();
|
||||
let serialized_output = output_buffer.into_inner();
|
||||
|
||||
let (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) =
|
||||
deserialize_identity_tuple(serialized_output);
|
||||
|
||||
// We check against expected values
|
||||
let expected_identity_trapdoor_seed_bytes = str_to_fr(
|
||||
"0x766ce6c7e7a01bdf5b3f257616f603918c30946fa23480f2859c597817e6716",
|
||||
16,
|
||||
);
|
||||
let expected_identity_nullifier_seed_bytes = str_to_fr(
|
||||
"0x1f18714c7bc83b5bca9e89d404cf6f2f585bc4c0f7ed8b53742b7e2b298f50b4",
|
||||
16,
|
||||
);
|
||||
let expected_identity_secret_hash_seed_bytes = str_to_fr(
|
||||
"0x2aca62aaa7abaf3686fff2caf00f55ab9462dc12db5b5d4bcf3994e671f8e521",
|
||||
16,
|
||||
);
|
||||
let expected_id_commitment_seed_bytes = str_to_fr(
|
||||
"0x68b66aa0a8320d2e56842581553285393188714c48f9b17acd198b4f1734c5c",
|
||||
16,
|
||||
);
|
||||
|
||||
assert_eq!(identity_trapdoor, expected_identity_trapdoor_seed_bytes);
|
||||
assert_eq!(identity_nullifier, expected_identity_nullifier_seed_bytes);
|
||||
assert_eq!(
|
||||
identity_secret_hash,
|
||||
expected_identity_secret_hash_seed_bytes
|
||||
);
|
||||
assert_eq!(id_commitment, expected_id_commitment_seed_bytes);
|
||||
}
|
||||
|
||||
|
@ -1622,7 +1748,7 @@ mod test {
|
|||
rln.init_tree_with_leaves(&mut buffer).unwrap();
|
||||
|
||||
// Generate identity pair
|
||||
let (identity_secret, id_commitment) = keygen();
|
||||
let (identity_secret_hash, id_commitment) = keygen();
|
||||
|
||||
// We set as leaf id_commitment after storing its index
|
||||
let identity_index = u64::try_from(rln.tree.leaves_set()).unwrap();
|
||||
|
@ -1638,9 +1764,9 @@ mod test {
|
|||
let epoch = hash_to_field(b"test-epoch");
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret));
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized.append(&mut identity_index.to_le_bytes().to_vec());
|
||||
serialized.append(&mut fr_to_bytes_le(&epoch));
|
||||
serialized.append(&mut signal_len.to_le_bytes().to_vec());
|
||||
|
@ -1705,7 +1831,7 @@ mod test {
|
|||
let mut rln = RLN::new(tree_height, input_buffer);
|
||||
|
||||
// Generate identity pair
|
||||
let (identity_secret, id_commitment) = keygen();
|
||||
let (identity_secret_hash, id_commitment) = keygen();
|
||||
|
||||
// We set as leaf id_commitment after storing its index
|
||||
let identity_index = u64::try_from(rln.tree.leaves_set()).unwrap();
|
||||
|
@ -1726,9 +1852,9 @@ mod test {
|
|||
// We generate two proofs using same epoch but different signals.
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized1: Vec<u8> = Vec::new();
|
||||
serialized1.append(&mut fr_to_bytes_le(&identity_secret));
|
||||
serialized1.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized1.append(&mut identity_index.to_le_bytes().to_vec());
|
||||
serialized1.append(&mut fr_to_bytes_le(&epoch));
|
||||
|
||||
|
@ -1767,19 +1893,19 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let serialized_id_secret = output_buffer.into_inner();
|
||||
let serialized_identity_secret_hash = output_buffer.into_inner();
|
||||
|
||||
// We ensure that a non-empty value is written to output_buffer
|
||||
assert!(!serialized_id_secret.is_empty());
|
||||
assert!(!serialized_identity_secret_hash.is_empty());
|
||||
|
||||
// We check if the recovered id secret corresponds to the original one
|
||||
let (recovered_id_secret, _) = bytes_le_to_fr(&serialized_id_secret);
|
||||
assert_eq!(recovered_id_secret, identity_secret);
|
||||
// We check if the recovered identity secret hash corresponds to the original one
|
||||
let (recovered_identity_secret_hash, _) = bytes_le_to_fr(&serialized_identity_secret_hash);
|
||||
assert_eq!(recovered_identity_secret_hash, identity_secret_hash);
|
||||
|
||||
// We now test that computing_id_secret is unsuccessful if shares computed from two different id secrets but within same epoch are passed
|
||||
// We now test that computing identity_secret_hash is unsuccessful if shares computed from two different identity secret hashes but within same epoch are passed
|
||||
|
||||
// We generate a new identity pair
|
||||
let (identity_secret_new, id_commitment_new) = keygen();
|
||||
let (identity_secret_hash_new, id_commitment_new) = keygen();
|
||||
|
||||
// We add it to the tree
|
||||
let identity_index_new = u64::try_from(rln.tree.leaves_set()).unwrap();
|
||||
|
@ -1791,9 +1917,9 @@ mod test {
|
|||
let signal3_len = u64::try_from(signal3.len()).unwrap();
|
||||
|
||||
// We prepare proof input. Note that epoch is the same as before
|
||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized3: Vec<u8> = Vec::new();
|
||||
serialized3.append(&mut fr_to_bytes_le(&identity_secret_new));
|
||||
serialized3.append(&mut fr_to_bytes_le(&identity_secret_hash_new));
|
||||
serialized3.append(&mut identity_index_new.to_le_bytes().to_vec());
|
||||
serialized3.append(&mut fr_to_bytes_le(&epoch));
|
||||
serialized3.append(&mut signal3_len.to_le_bytes().to_vec());
|
||||
|
@ -1806,7 +1932,7 @@ mod test {
|
|||
.unwrap();
|
||||
let proof_data_3 = output_buffer.into_inner();
|
||||
|
||||
// We attempt to recover the secret using share1 (coming from identity_secret) and share3 (coming from identity_secret_new)
|
||||
// We attempt to recover the secret using share1 (coming from identity_secret_hash) and share3 (coming from identity_secret_hash_new)
|
||||
|
||||
let mut input_proof_data_1 = Cursor::new(proof_data_1.clone());
|
||||
let mut input_proof_data_3 = Cursor::new(proof_data_3);
|
||||
|
@ -1818,9 +1944,9 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let serialized_id_secret = output_buffer.into_inner();
|
||||
let serialized_identity_secret_hash = output_buffer.into_inner();
|
||||
|
||||
// We ensure that an empty value was written to output_buffer, i.e. no secret is recovered
|
||||
assert!(serialized_id_secret.is_empty());
|
||||
assert!(serialized_identity_secret_hash.is_empty());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue