mirror of
https://github.com/vacp2p/zerokit.git
synced 2026-01-09 14:38:01 -05:00
fix(rln): review and refine utility functions in rln (#287)
This commit is contained in:
@@ -8,9 +8,9 @@ use color_eyre::{eyre::eyre, Result};
|
||||
use rln::{
|
||||
circuit::{Fr, TEST_TREE_HEIGHT},
|
||||
hashers::{hash_to_field, poseidon_hash},
|
||||
protocol::{deserialize_field_element, keygen, prepare_verify_input},
|
||||
protocol::{keygen, prepare_prove_input, prepare_verify_input},
|
||||
public::RLN,
|
||||
utils::{bytes_le_to_fr, fr_to_bytes_le, generate_input_buffer, normalize_usize},
|
||||
utils::{bytes_le_to_fr, fr_to_bytes_le, generate_input_buffer},
|
||||
};
|
||||
|
||||
const MESSAGE_LIMIT: u32 = 1;
|
||||
@@ -118,26 +118,14 @@ impl RLNSystem {
|
||||
None => return Err(eyre!("user index {user_index} not found")),
|
||||
};
|
||||
|
||||
let mut input_buffer = Cursor::new(Vec::new());
|
||||
self.rln.get_leaf(user_index, &mut input_buffer)?;
|
||||
let stored_rate_commitment = deserialize_field_element(input_buffer.into_inner());
|
||||
|
||||
let expected_rate_commitment =
|
||||
poseidon_hash(&[identity.id_commitment, Fr::from(MESSAGE_LIMIT)]);
|
||||
|
||||
if stored_rate_commitment != expected_rate_commitment {
|
||||
return Err(eyre!("user mismatch in merkle tree"));
|
||||
}
|
||||
|
||||
let mut serialized = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity.identity_secret_hash));
|
||||
serialized.append(&mut normalize_usize(user_index));
|
||||
serialized.append(&mut fr_to_bytes_le(&Fr::from(MESSAGE_LIMIT)));
|
||||
serialized.append(&mut fr_to_bytes_le(&Fr::from(message_id)));
|
||||
serialized.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
serialized.append(&mut normalize_usize(signal.len()));
|
||||
serialized.append(&mut signal.as_bytes().to_vec());
|
||||
|
||||
let serialized = prepare_prove_input(
|
||||
identity.identity_secret_hash,
|
||||
user_index,
|
||||
Fr::from(MESSAGE_LIMIT),
|
||||
Fr::from(message_id),
|
||||
external_nullifier,
|
||||
signal.as_bytes(),
|
||||
);
|
||||
let mut input_buffer = Cursor::new(serialized);
|
||||
let mut output_buffer = Cursor::new(Vec::new());
|
||||
self.rln
|
||||
|
||||
@@ -100,18 +100,26 @@ pub fn deserialize_identity_tuple(serialized: Vec<u8>) -> (Fr, Fr, Fr, Fr) {
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if `rln_witness.message_id` is not within `rln_witness.user_message_limit`.
|
||||
/// input data is [ identity_secret<32> | user_message_limit<32> | message_id<32> | path_elements[<32>] | identity_path_index<8> | x<32> | external_nullifier<32> ]
|
||||
pub fn serialize_witness(rln_witness: &RLNWitnessInput) -> Result<Vec<u8>> {
|
||||
// Check if message_id is within user_message_limit
|
||||
message_id_range_check(&rln_witness.message_id, &rln_witness.user_message_limit)?;
|
||||
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_witness.identity_secret));
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_witness.user_message_limit));
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_witness.message_id));
|
||||
serialized.append(&mut vec_fr_to_bytes_le(&rln_witness.path_elements)?);
|
||||
serialized.append(&mut vec_u8_to_bytes_le(&rln_witness.identity_path_index)?);
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_witness.x));
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_witness.external_nullifier));
|
||||
// Calculate capacity for Vec:
|
||||
// - 5 fixed field elements: identity_secret, user_message_limit, message_id, x, external_nullifier
|
||||
// - variable number of path elements
|
||||
// - identity_path_index (variable size)
|
||||
let mut serialized: Vec<u8> = Vec::with_capacity(
|
||||
fr_byte_size() * (5 + rln_witness.path_elements.len())
|
||||
+ rln_witness.identity_path_index.len(),
|
||||
);
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_witness.identity_secret));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_witness.user_message_limit));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_witness.message_id));
|
||||
serialized.extend_from_slice(&vec_fr_to_bytes_le(&rln_witness.path_elements)?);
|
||||
serialized.extend_from_slice(&vec_u8_to_bytes_le(&rln_witness.identity_path_index)?);
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_witness.x));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_witness.external_nullifier));
|
||||
|
||||
Ok(serialized)
|
||||
}
|
||||
@@ -306,14 +314,17 @@ pub fn proof_values_from_witness(rln_witness: &RLNWitnessInput) -> Result<RLNPro
|
||||
})
|
||||
}
|
||||
|
||||
/// input_data is [ root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
pub fn serialize_proof_values(rln_proof_values: &RLNProofValues) -> Vec<u8> {
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
// Calculate capacity for Vec:
|
||||
// 5 field elements: root, external_nullifier, x, y, nullifier
|
||||
let mut serialized = Vec::with_capacity(fr_byte_size() * 5);
|
||||
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_proof_values.root));
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_proof_values.external_nullifier));
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_proof_values.x));
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_proof_values.y));
|
||||
serialized.append(&mut fr_to_bytes_le(&rln_proof_values.nullifier));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_proof_values.root));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_proof_values.external_nullifier));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_proof_values.x));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_proof_values.y));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&rln_proof_values.nullifier));
|
||||
|
||||
serialized
|
||||
}
|
||||
@@ -350,30 +361,43 @@ pub fn deserialize_proof_values(serialized: &[u8]) -> (RLNProofValues, usize) {
|
||||
)
|
||||
}
|
||||
|
||||
// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
pub fn prepare_prove_input(
|
||||
identity_secret: Fr,
|
||||
id_index: usize,
|
||||
user_message_limit: Fr,
|
||||
message_id: Fr,
|
||||
external_nullifier: Fr,
|
||||
signal: &[u8],
|
||||
) -> Vec<u8> {
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
// Calculate capacity for Vec:
|
||||
// - 4 field elements: identity_secret, user_message_limit, message_id, external_nullifier
|
||||
// - 16 bytes for two normalized usize values (id_index<8> + signal_len<8>)
|
||||
// - variable length signal data
|
||||
let mut serialized = Vec::with_capacity(fr_byte_size() * 4 + 16 + signal.len()); // length of 4 fr elements + 16 bytes (id_index + len) + signal length
|
||||
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret));
|
||||
serialized.append(&mut normalize_usize(id_index));
|
||||
serialized.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
serialized.append(&mut normalize_usize(signal.len()));
|
||||
serialized.append(&mut signal.to_vec());
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&identity_secret));
|
||||
serialized.extend_from_slice(&normalize_usize(id_index));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&user_message_limit));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&message_id));
|
||||
serialized.extend_from_slice(&fr_to_bytes_le(&external_nullifier));
|
||||
serialized.extend_from_slice(&normalize_usize(signal.len()));
|
||||
serialized.extend_from_slice(signal);
|
||||
|
||||
serialized
|
||||
}
|
||||
|
||||
#[allow(clippy::redundant_clone)]
|
||||
// input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
pub fn prepare_verify_input(proof_data: Vec<u8>, signal: &[u8]) -> Vec<u8> {
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
// Calculate capacity for Vec:
|
||||
// - proof_data contains the proof and proof values (proof<128> + root<32> + external_nullifier<32> + x<32> + y<32> + nullifier<32>)
|
||||
// - 8 bytes for normalized signal length value (signal_len<8>)
|
||||
// - variable length signal data
|
||||
let mut serialized = Vec::with_capacity(proof_data.len() + 8 + signal.len());
|
||||
|
||||
serialized.append(&mut proof_data.clone());
|
||||
serialized.append(&mut normalize_usize(signal.len()));
|
||||
serialized.append(&mut signal.to_vec());
|
||||
serialized.extend(proof_data);
|
||||
serialized.extend_from_slice(&normalize_usize(signal.len()));
|
||||
serialized.extend_from_slice(signal);
|
||||
|
||||
serialized
|
||||
}
|
||||
|
||||
@@ -793,26 +793,25 @@ impl RLN {
|
||||
/// let mut buffer = Cursor::new(fr_to_bytes_le(&rate_commitment));
|
||||
/// rln.set_leaf(identity_index, &mut buffer).unwrap();
|
||||
///
|
||||
/// // We generate a random signal
|
||||
/// let mut rng = rand::thread_rng();
|
||||
/// let signal: [u8; 32] = rng.gen();
|
||||
///
|
||||
/// // We generate a random epoch
|
||||
/// let epoch = hash_to_field(b"test-epoch");
|
||||
/// // We generate a random rln_identifier
|
||||
/// let rln_identifier = hash_to_field(b"test-rln-identifier");
|
||||
/// let external_nullifier = poseidon_hash(&[epoch, rln_identifier]);
|
||||
/// // We generate a external nullifier
|
||||
/// let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
|
||||
/// // We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT
|
||||
/// let message_id = Fr::from(1);
|
||||
///
|
||||
/// // We prepare input for generate_rln_proof API
|
||||
/// // input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
/// let mut serialized: Vec<u8> = Vec::new();
|
||||
/// serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
/// serialized.append(&mut normalize_usize(identity_index));
|
||||
/// serialized.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
/// serialized.append(&mut fr_to_bytes_le(&Fr::from(1))); // message_id
|
||||
/// serialized.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
/// serialized.append(&mut normalize_usize(signal_len).resize(8,0));
|
||||
/// serialized.append(&mut signal.to_vec());
|
||||
/// let prove_input = prepare_prove_input(
|
||||
/// identity_secret_hash,
|
||||
/// identity_index,
|
||||
/// user_message_limit,
|
||||
/// message_id,
|
||||
/// external_nullifier,
|
||||
/// &signal,
|
||||
/// );
|
||||
///
|
||||
/// let mut input_buffer = Cursor::new(serialized);
|
||||
/// let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
@@ -887,10 +886,9 @@ impl RLN {
|
||||
/// // We prepare input for verify_rln_proof API
|
||||
/// // input_data is `[ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var>]`
|
||||
/// // that is [ proof_data || signal_len<8> | signal<var> ]
|
||||
/// proof_data.append(&mut normalize_usize(signal_len));
|
||||
/// proof_data.append(&mut signal.to_vec());
|
||||
/// let verify_input = prepare_verify_input(proof_data, &signal);
|
||||
///
|
||||
/// let mut input_buffer = Cursor::new(proof_data);
|
||||
/// let mut input_buffer = Cursor::new(verify_input);
|
||||
/// let verified = rln.verify_rln_proof(&mut input_buffer).unwrap();
|
||||
///
|
||||
/// assert!(verified);
|
||||
@@ -966,7 +964,7 @@ impl RLN {
|
||||
/// roots_serialized.append(&mut fr_to_bytes_le(&root));
|
||||
/// roots_buffer = Cursor::new(roots_serialized.clone());
|
||||
/// let verified = rln
|
||||
/// .verify_with_roots(&mut input_buffer.clone(), &mut roots_buffer)
|
||||
/// .verify_with_roots(&mut input_buffer, &mut roots_buffer)
|
||||
/// .unwrap();
|
||||
///
|
||||
/// assert!(verified);
|
||||
|
||||
@@ -9,28 +9,28 @@ use std::str::FromStr;
|
||||
|
||||
use serde_json::{json, Value};
|
||||
|
||||
fn fq_from_str(s: String) -> ark_bn254::Fq {
|
||||
fn fq_from_str(s: &str) -> ark_bn254::Fq {
|
||||
ark_bn254::Fq::from_str(&s).unwrap()
|
||||
}
|
||||
|
||||
fn g1_from_str(g1: &[String]) -> ark_bn254::G1Affine {
|
||||
let x = fq_from_str(g1[0].clone());
|
||||
let y = fq_from_str(g1[1].clone());
|
||||
let z = fq_from_str(g1[2].clone());
|
||||
let x = fq_from_str(&g1[0]);
|
||||
let y = fq_from_str(&g1[1]);
|
||||
let z = fq_from_str(&g1[2]);
|
||||
ark_bn254::G1Affine::from(ark_bn254::G1Projective::new(x, y, z))
|
||||
}
|
||||
|
||||
fn g2_from_str(g2: &[Vec<String>]) -> ark_bn254::G2Affine {
|
||||
let c0 = fq_from_str(g2[0][0].clone());
|
||||
let c1 = fq_from_str(g2[0][1].clone());
|
||||
let c0 = fq_from_str(&g2[0][0]);
|
||||
let c1 = fq_from_str(&g2[0][1]);
|
||||
let x = ark_bn254::Fq2::new(c0, c1);
|
||||
|
||||
let c0 = fq_from_str(g2[1][0].clone());
|
||||
let c1 = fq_from_str(g2[1][1].clone());
|
||||
let c0 = fq_from_str(&g2[1][0]);
|
||||
let c1 = fq_from_str(&g2[1][1]);
|
||||
let y = ark_bn254::Fq2::new(c0, c1);
|
||||
|
||||
let c0 = fq_from_str(g2[2][0].clone());
|
||||
let c1 = fq_from_str(g2[2][1].clone());
|
||||
let c0 = fq_from_str(&g2[2][0]);
|
||||
let c1 = fq_from_str(&g2[2][1]);
|
||||
let z = ark_bn254::Fq2::new(c0, c1);
|
||||
|
||||
ark_bn254::G2Affine::from(ark_bn254::G2Projective::new(x, y, z))
|
||||
@@ -619,35 +619,36 @@ mod tree_test {
|
||||
let epoch = hash_to_field(b"test-epoch");
|
||||
// We generate a random rln_identifier
|
||||
let rln_identifier = hash_to_field(b"test-rln-identifier");
|
||||
// We generate a external nullifier
|
||||
let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
|
||||
// We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT
|
||||
let message_id = Fr::from(1);
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized.append(&mut normalize_usize(identity_index));
|
||||
serialized.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
serialized.append(&mut fr_to_bytes_le(&Fr::from(1)));
|
||||
serialized.append(&mut fr_to_bytes_le(&utils_poseidon_hash(&[
|
||||
epoch,
|
||||
rln_identifier,
|
||||
])));
|
||||
serialized.append(&mut normalize_usize(signal.len()));
|
||||
serialized.append(&mut signal.to_vec());
|
||||
// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
let prove_input = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal,
|
||||
);
|
||||
|
||||
let mut input_buffer = Cursor::new(serialized);
|
||||
let mut input_buffer = Cursor::new(prove_input);
|
||||
let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.generate_rln_proof(&mut input_buffer, &mut output_buffer)
|
||||
.unwrap();
|
||||
|
||||
// output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let mut proof_data = output_buffer.into_inner();
|
||||
let proof_data = output_buffer.into_inner();
|
||||
|
||||
// We prepare input for verify_rln_proof API
|
||||
// input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// that is [ proof_data || signal_len<8> | signal<var> ]
|
||||
proof_data.append(&mut normalize_usize(signal.len()));
|
||||
proof_data.append(&mut signal.to_vec());
|
||||
let verify_input = prepare_verify_input(proof_data, &signal);
|
||||
|
||||
let mut input_buffer = Cursor::new(proof_data);
|
||||
let mut input_buffer = Cursor::new(verify_input);
|
||||
let verified = rln.verify_rln_proof(&mut input_buffer).unwrap();
|
||||
|
||||
assert!(verified);
|
||||
@@ -690,22 +691,23 @@ mod tree_test {
|
||||
let epoch = hash_to_field(b"test-epoch");
|
||||
// We generate a random rln_identifier
|
||||
let rln_identifier = hash_to_field(b"test-rln-identifier");
|
||||
// We generate a external nullifier
|
||||
let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
|
||||
// We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT
|
||||
let message_id = Fr::from(1);
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// 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_hash));
|
||||
serialized.append(&mut normalize_usize(identity_index));
|
||||
serialized.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
serialized.append(&mut fr_to_bytes_le(&Fr::from(1)));
|
||||
serialized.append(&mut fr_to_bytes_le(&utils_poseidon_hash(&[
|
||||
epoch,
|
||||
rln_identifier,
|
||||
])));
|
||||
serialized.append(&mut normalize_usize(signal.len()));
|
||||
serialized.append(&mut signal.to_vec());
|
||||
// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
let prove_input = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal,
|
||||
);
|
||||
|
||||
let mut input_buffer = Cursor::new(serialized);
|
||||
let mut input_buffer = Cursor::new(prove_input);
|
||||
|
||||
// We read input RLN witness and we serialize_compressed it
|
||||
let mut witness_byte: Vec<u8> = Vec::new();
|
||||
@@ -720,16 +722,15 @@ mod tree_test {
|
||||
rln.generate_rln_proof_with_witness(&mut input_buffer, &mut output_buffer)
|
||||
.unwrap();
|
||||
|
||||
// output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let mut proof_data = output_buffer.into_inner();
|
||||
// output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let proof_data = output_buffer.into_inner();
|
||||
|
||||
// We prepare input for verify_rln_proof API
|
||||
// input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// that is [ proof_data || signal_len<8> | signal<var> ]
|
||||
proof_data.append(&mut normalize_usize(signal.len()));
|
||||
proof_data.append(&mut signal.to_vec());
|
||||
let verify_input = prepare_verify_input(proof_data, &signal);
|
||||
|
||||
let mut input_buffer = Cursor::new(proof_data);
|
||||
let mut input_buffer = Cursor::new(verify_input);
|
||||
let verified = rln.verify_rln_proof(&mut input_buffer).unwrap();
|
||||
|
||||
assert!(verified);
|
||||
@@ -773,33 +774,35 @@ mod tree_test {
|
||||
let epoch = hash_to_field(b"test-epoch");
|
||||
// We generate a random rln_identifier
|
||||
let rln_identifier = hash_to_field(b"test-rln-identifier");
|
||||
// We generate a external nullifier
|
||||
let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
|
||||
// We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT
|
||||
let message_id = Fr::from(1);
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ identity_secret<32> | id_index<8> | external_nullifier<32> | user_message_limit<32> | message_id<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized.append(&mut normalize_usize(identity_index));
|
||||
serialized.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
serialized.append(&mut fr_to_bytes_le(&Fr::from(1)));
|
||||
serialized.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
serialized.append(&mut normalize_usize(signal.len()));
|
||||
serialized.append(&mut signal.to_vec());
|
||||
// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
let prove_input = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal,
|
||||
);
|
||||
|
||||
let mut input_buffer = Cursor::new(serialized);
|
||||
let mut input_buffer = Cursor::new(prove_input);
|
||||
let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.generate_rln_proof(&mut input_buffer, &mut output_buffer)
|
||||
.unwrap();
|
||||
|
||||
// output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let mut proof_data = output_buffer.into_inner();
|
||||
// output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let proof_data = output_buffer.into_inner();
|
||||
|
||||
// We prepare input for verify_rln_proof API
|
||||
// input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ proof<128> |// We prepare input for verify_rln_proof API root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// that is [ proof_data || signal_len<8> | signal<var> ]
|
||||
proof_data.append(&mut normalize_usize(signal.len()));
|
||||
proof_data.append(&mut signal.to_vec());
|
||||
let input_buffer = Cursor::new(proof_data);
|
||||
let verify_input = prepare_verify_input(proof_data, &signal);
|
||||
|
||||
let mut input_buffer = Cursor::new(verify_input);
|
||||
|
||||
// If no roots is provided, proof validation is skipped and if the remaining proof values are valid, the proof will be correctly verified
|
||||
let mut roots_serialized: Vec<u8> = Vec::new();
|
||||
@@ -828,9 +831,9 @@ mod tree_test {
|
||||
|
||||
// We add the real root and we check if now the proof is verified
|
||||
roots_serialized.append(&mut fr_to_bytes_le(&root));
|
||||
roots_buffer = Cursor::new(roots_serialized.clone());
|
||||
roots_buffer = Cursor::new(roots_serialized);
|
||||
let verified = rln
|
||||
.verify_with_roots(&mut input_buffer.clone(), &mut roots_buffer)
|
||||
.verify_with_roots(&mut input_buffer, &mut roots_buffer)
|
||||
.unwrap();
|
||||
|
||||
assert!(verified);
|
||||
@@ -846,7 +849,6 @@ mod tree_test {
|
||||
// Generate identity pair
|
||||
let (identity_secret_hash, id_commitment) = keygen();
|
||||
let user_message_limit = Fr::from(100);
|
||||
let message_id = Fr::from(0);
|
||||
let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]);
|
||||
|
||||
// We set as leaf id_commitment after storing its index
|
||||
@@ -864,41 +866,49 @@ mod tree_test {
|
||||
let epoch = hash_to_field(b"test-epoch");
|
||||
// We generate a random rln_identifier
|
||||
let rln_identifier = hash_to_field(b"test-rln-identifier");
|
||||
// We generate a external nullifier
|
||||
let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
|
||||
// We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT
|
||||
let message_id = Fr::from(1);
|
||||
|
||||
// We generate two proofs using same epoch but different signals.
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
let mut serialized1: Vec<u8> = Vec::new();
|
||||
serialized1.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized1.append(&mut normalize_usize(identity_index));
|
||||
serialized1.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
serialized1.append(&mut fr_to_bytes_le(&message_id));
|
||||
serialized1.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
let prove_input1 = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal1,
|
||||
);
|
||||
|
||||
// The first part is the same for both proof input, so we clone
|
||||
let mut serialized2 = serialized1.clone();
|
||||
|
||||
// We attach the first signal to the first proof input
|
||||
serialized1.append(&mut normalize_usize(signal1.len()));
|
||||
serialized1.append(&mut signal1.to_vec());
|
||||
|
||||
// We attach the second signal to the second proof input
|
||||
serialized2.append(&mut normalize_usize(signal2.len()));
|
||||
serialized2.append(&mut signal2.to_vec());
|
||||
let prove_input2 = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal2,
|
||||
);
|
||||
|
||||
// We generate the first proof
|
||||
let mut input_buffer = Cursor::new(serialized1);
|
||||
let mut input_buffer = Cursor::new(prove_input1);
|
||||
let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.generate_rln_proof(&mut input_buffer, &mut output_buffer)
|
||||
.unwrap();
|
||||
|
||||
// output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let proof_data_1 = output_buffer.into_inner();
|
||||
|
||||
// We generate the second proof
|
||||
let mut input_buffer = Cursor::new(serialized2);
|
||||
let mut input_buffer = Cursor::new(prove_input2);
|
||||
let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.generate_rln_proof(&mut input_buffer, &mut output_buffer)
|
||||
.unwrap();
|
||||
|
||||
// output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let proof_data_2 = output_buffer.into_inner();
|
||||
|
||||
let mut input_proof_data_1 = Cursor::new(proof_data_1.clone());
|
||||
@@ -935,25 +945,24 @@ mod tree_test {
|
||||
let signal3: [u8; 32] = rng.gen();
|
||||
|
||||
// We prepare proof input. Note that epoch is the same as before
|
||||
let mut serialized3: Vec<u8> = Vec::new();
|
||||
serialized3.append(&mut fr_to_bytes_le(&identity_secret_hash_new));
|
||||
serialized3.append(&mut normalize_usize(identity_index_new));
|
||||
serialized3.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
serialized3.append(&mut fr_to_bytes_le(&message_id));
|
||||
serialized3.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
serialized3.append(&mut normalize_usize(signal3.len()));
|
||||
serialized3.append(&mut signal3.to_vec());
|
||||
let prove_input3 = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index_new,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal3,
|
||||
);
|
||||
|
||||
// We generate the proof
|
||||
let mut input_buffer = Cursor::new(serialized3);
|
||||
let mut input_buffer = Cursor::new(prove_input3);
|
||||
let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.generate_rln_proof(&mut input_buffer, &mut output_buffer)
|
||||
.unwrap();
|
||||
let proof_data_3 = output_buffer.into_inner();
|
||||
|
||||
// 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_1 = Cursor::new(proof_data_1);
|
||||
let mut input_proof_data_3 = Cursor::new(proof_data_3);
|
||||
let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.recover_id_secret(
|
||||
@@ -1022,7 +1031,7 @@ mod stateless_test {
|
||||
let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ identity_secret<32> | id_index<8> | external_nullifier<32> | user_message_limit<32> | message_id<32> | signal_len<8> | signal<var> ]
|
||||
// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
|
||||
let x = hash_to_field(&signal);
|
||||
let merkle_proof = tree.proof(identity_index).expect("proof should exist");
|
||||
@@ -1043,15 +1052,15 @@ mod stateless_test {
|
||||
rln.generate_rln_proof_with_witness(&mut input_buffer, &mut output_buffer)
|
||||
.unwrap();
|
||||
|
||||
// output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let mut proof_data = output_buffer.into_inner();
|
||||
// output_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let proof_data = output_buffer.into_inner();
|
||||
|
||||
// We prepare input for verify_rln_proof API
|
||||
// input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// that is [ proof_data || signal_len<8> | signal<var> ]
|
||||
proof_data.append(&mut normalize_usize(signal.len()));
|
||||
proof_data.append(&mut signal.to_vec());
|
||||
let input_buffer = Cursor::new(proof_data);
|
||||
let verify_input = prepare_verify_input(proof_data, &signal);
|
||||
|
||||
let mut input_buffer = Cursor::new(verify_input);
|
||||
|
||||
// If no roots is provided, proof validation is skipped and if the remaining proof values are valid, the proof will be correctly verified
|
||||
let mut roots_serialized: Vec<u8> = Vec::new();
|
||||
@@ -1078,9 +1087,9 @@ mod stateless_test {
|
||||
|
||||
// We add the real root and we check if now the proof is verified
|
||||
roots_serialized.append(&mut fr_to_bytes_le(&root));
|
||||
roots_buffer = Cursor::new(roots_serialized.clone());
|
||||
roots_buffer = Cursor::new(roots_serialized);
|
||||
let verified = rln
|
||||
.verify_with_roots(&mut input_buffer.clone(), &mut roots_buffer)
|
||||
.verify_with_roots(&mut input_buffer, &mut roots_buffer)
|
||||
.unwrap();
|
||||
|
||||
assert!(verified);
|
||||
@@ -1205,7 +1214,7 @@ mod stateless_test {
|
||||
.unwrap();
|
||||
let proof_data_3 = output_buffer.into_inner();
|
||||
|
||||
let mut input_proof_data_1 = Cursor::new(proof_data_1.clone());
|
||||
let mut input_proof_data_1 = Cursor::new(proof_data_1);
|
||||
let mut input_proof_data_3 = Cursor::new(proof_data_3);
|
||||
let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.recover_id_secret(
|
||||
|
||||
262
rln/src/utils.rs
262
rln/src/utils.rs
@@ -7,18 +7,19 @@ use num_bigint::{BigInt, BigUint};
|
||||
use num_traits::Num;
|
||||
use serde_json::json;
|
||||
use std::io::Cursor;
|
||||
use std::iter::Extend;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn to_bigint(el: &Fr) -> Result<BigInt> {
|
||||
let res: BigUint = (*el).into();
|
||||
Ok(res.into())
|
||||
Ok(BigUint::from(*el).into())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn fr_byte_size() -> usize {
|
||||
let mbs = <Fr as PrimeField>::MODULUS_BIT_SIZE;
|
||||
((mbs + 64 - (mbs % 64)) / 8) as usize
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn str_to_fr(input: &str, radix: u32) -> Result<Fr> {
|
||||
if !(radix == 10 || radix == 16) {
|
||||
return Err(Report::msg("wrong radix"));
|
||||
@@ -37,6 +38,7 @@ pub fn str_to_fr(input: &str, radix: u32) -> Result<Fr> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn bytes_le_to_fr(input: &[u8]) -> (Fr, usize) {
|
||||
let el_size = fr_byte_size();
|
||||
(
|
||||
@@ -45,77 +47,50 @@ pub fn bytes_le_to_fr(input: &[u8]) -> (Fr, usize) {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn bytes_be_to_fr(input: &[u8]) -> (Fr, usize) {
|
||||
let el_size = fr_byte_size();
|
||||
(
|
||||
Fr::from(BigUint::from_bytes_be(&input[0..el_size])),
|
||||
el_size,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn fr_to_bytes_le(input: &Fr) -> Vec<u8> {
|
||||
let input_biguint: BigUint = (*input).into();
|
||||
let mut res = input_biguint.to_bytes_le();
|
||||
//BigUint conversion ignores most significant zero bytes. We restore them otherwise serialization will fail (length % 8 != 0)
|
||||
while res.len() != fr_byte_size() {
|
||||
res.push(0);
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub fn fr_to_bytes_be(input: &Fr) -> Vec<u8> {
|
||||
let input_biguint: BigUint = (*input).into();
|
||||
let mut res = input_biguint.to_bytes_be();
|
||||
// BigUint conversion ignores most significant zero bytes. We restore them otherwise serialization might fail
|
||||
// Fr elements are stored using 64 bits nimbs
|
||||
while res.len() != fr_byte_size() {
|
||||
res.insert(0, 0);
|
||||
}
|
||||
res.resize(fr_byte_size(), 0);
|
||||
res
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn vec_fr_to_bytes_le(input: &[Fr]) -> Result<Vec<u8>> {
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
//We store the vector length
|
||||
bytes.extend(u64::try_from(input.len())?.to_le_bytes().to_vec());
|
||||
// Calculate capacity for Vec:
|
||||
// - 8 bytes for normalized vector length (usize)
|
||||
// - each Fr element requires fr_byte_size() bytes (typically 32 bytes)
|
||||
let mut bytes = Vec::with_capacity(8 + input.len() * fr_byte_size());
|
||||
|
||||
// We store the vector length
|
||||
bytes.extend_from_slice(&normalize_usize(input.len()));
|
||||
|
||||
// We store each element
|
||||
input.iter().for_each(|el| bytes.extend(fr_to_bytes_le(el)));
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
pub fn vec_fr_to_bytes_be(input: &[Fr]) -> Result<Vec<u8>> {
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
//We store the vector length
|
||||
bytes.extend(u64::try_from(input.len())?.to_be_bytes().to_vec());
|
||||
|
||||
// We store each element
|
||||
input.iter().for_each(|el| bytes.extend(fr_to_bytes_be(el)));
|
||||
for el in input {
|
||||
bytes.extend_from_slice(&fr_to_bytes_le(el));
|
||||
}
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn vec_u8_to_bytes_le(input: &[u8]) -> Result<Vec<u8>> {
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
//We store the vector length
|
||||
bytes.extend(u64::try_from(input.len())?.to_le_bytes().to_vec());
|
||||
// Calculate capacity for Vec:
|
||||
// - 8 bytes for normalized vector length (usize)
|
||||
// - variable length input data
|
||||
let mut bytes = Vec::with_capacity(8 + input.len());
|
||||
|
||||
bytes.extend(input);
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
pub fn vec_u8_to_bytes_be(input: Vec<u8>) -> Result<Vec<u8>> {
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
//We store the vector length
|
||||
bytes.extend(u64::try_from(input.len())?.to_be_bytes().to_vec());
|
||||
|
||||
bytes.extend(input);
|
||||
// We store the vector length
|
||||
bytes.extend_from_slice(&normalize_usize(input.len()));
|
||||
|
||||
// We store the input
|
||||
bytes.extend_from_slice(input);
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn bytes_le_to_vec_u8(input: &[u8]) -> Result<(Vec<u8>, usize)> {
|
||||
let mut read: usize = 0;
|
||||
|
||||
@@ -128,19 +103,7 @@ pub fn bytes_le_to_vec_u8(input: &[u8]) -> Result<(Vec<u8>, usize)> {
|
||||
Ok((res, read))
|
||||
}
|
||||
|
||||
pub fn bytes_be_to_vec_u8(input: &[u8]) -> Result<(Vec<u8>, usize)> {
|
||||
let mut read: usize = 0;
|
||||
|
||||
let len = usize::try_from(u64::from_be_bytes(input[0..8].try_into()?))?;
|
||||
read += 8;
|
||||
|
||||
let res = input[8..8 + len].to_vec();
|
||||
|
||||
read += res.len();
|
||||
|
||||
Ok((res, read))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn bytes_le_to_vec_fr(input: &[u8]) -> Result<(Vec<Fr>, usize)> {
|
||||
let mut read: usize = 0;
|
||||
let mut res: Vec<Fr> = Vec::new();
|
||||
@@ -158,29 +121,7 @@ pub fn bytes_le_to_vec_fr(input: &[u8]) -> Result<(Vec<Fr>, usize)> {
|
||||
Ok((res, read))
|
||||
}
|
||||
|
||||
pub fn bytes_be_to_vec_fr(input: &[u8]) -> Result<(Vec<Fr>, usize)> {
|
||||
let mut read: usize = 0;
|
||||
let mut res: Vec<Fr> = Vec::new();
|
||||
|
||||
let len = usize::try_from(u64::from_be_bytes(input[0..8].try_into()?))?;
|
||||
read += 8;
|
||||
|
||||
let el_size = fr_byte_size();
|
||||
for i in 0..len {
|
||||
let (curr_el, _) = bytes_be_to_fr(&input[8 + el_size * i..8 + el_size * (i + 1)]);
|
||||
res.push(curr_el);
|
||||
read += el_size;
|
||||
}
|
||||
|
||||
Ok((res, read))
|
||||
}
|
||||
|
||||
pub fn normalize_usize(input: usize) -> Vec<u8> {
|
||||
let mut normalized_usize = input.to_le_bytes().to_vec();
|
||||
normalized_usize.resize(8, 0);
|
||||
normalized_usize
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn bytes_le_to_vec_usize(input: &[u8]) -> Result<Vec<usize>> {
|
||||
let nof_elem = usize::try_from(u64::from_le_bytes(input[0..8].try_into()?))?;
|
||||
if nof_elem == 0 {
|
||||
@@ -194,141 +135,12 @@ pub fn bytes_le_to_vec_usize(input: &[u8]) -> Result<Vec<usize>> {
|
||||
}
|
||||
}
|
||||
|
||||
// using for test
|
||||
#[inline(always)]
|
||||
pub fn normalize_usize(input: usize) -> [u8; 8] {
|
||||
input.to_le_bytes()
|
||||
}
|
||||
|
||||
#[inline(always)] // using for test
|
||||
pub fn generate_input_buffer() -> Cursor<String> {
|
||||
Cursor::new(json!({}).to_string())
|
||||
}
|
||||
|
||||
/* Old conversion utilities between different libraries data types
|
||||
|
||||
// Conversion Utilities between poseidon-rs Field and arkworks Fr (in order to call directly poseidon-rs' poseidon_hash)
|
||||
|
||||
use ff::{PrimeField as _, PrimeFieldRepr as _};
|
||||
use poseidon_rs::Fr as PosFr;
|
||||
|
||||
pub fn fr_to_posfr(value: Fr) -> PosFr {
|
||||
let mut bytes = [0_u8; 32];
|
||||
let byte_vec = value.into_repr().to_bytes_be();
|
||||
bytes.copy_from_slice(&byte_vec[..]);
|
||||
let mut repr = <PosFr as ff::PrimeField>::Repr::default();
|
||||
repr.read_be(&bytes[..])
|
||||
.expect("read from correctly sized slice always succeeds");
|
||||
PosFr::from_repr(repr).expect("value is always in range")
|
||||
}
|
||||
|
||||
pub fn posfr_to_fr(value: PosFr) -> Fr {
|
||||
let mut bytes = [0u8; 32];
|
||||
value
|
||||
.into_repr()
|
||||
.write_be(&mut bytes[..])
|
||||
.expect("write to correctly sized slice always succeeds");
|
||||
Fr::from_be_bytes_mod_order(&bytes)
|
||||
}
|
||||
|
||||
|
||||
// Conversion Utilities between semaphore-rs Field and arkworks Fr
|
||||
|
||||
use semaphore::Field;
|
||||
|
||||
pub fn to_fr(el: &Field) -> Fr {
|
||||
Fr::try_from(*el).unwrap()
|
||||
}
|
||||
|
||||
pub fn to_field(el: &Fr) -> Field {
|
||||
(*el).try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn vec_to_fr(v: &[Field]) -> Vec<Fr> {
|
||||
v.iter().map(|el| to_fr(el)).collect()
|
||||
}
|
||||
|
||||
pub fn vec_to_field(v: &[Fr]) -> Vec<Field> {
|
||||
v.iter().map(|el| to_field(el)).collect()
|
||||
}
|
||||
|
||||
pub fn vec_fr_to_field(input: &[Fr]) -> Vec<Field> {
|
||||
input.iter().map(|el| to_field(el)).collect()
|
||||
}
|
||||
|
||||
pub fn vec_field_to_fr(input: &[Field]) -> Vec<Fr> {
|
||||
input.iter().map(|el| to_fr(el)).collect()
|
||||
}
|
||||
|
||||
pub fn str_to_field(input: String, radix: i32) -> Field {
|
||||
assert!((radix == 10) || (radix == 16));
|
||||
|
||||
// We remove any quote present and we trim
|
||||
let single_quote: char = '\"';
|
||||
let input_clean = input.replace(single_quote, "");
|
||||
let input_clean = input_clean.trim();
|
||||
|
||||
if radix == 10 {
|
||||
Field::from_str(&format!(
|
||||
"{:01$x}",
|
||||
BigUint::from_str(input_clean).unwrap(),
|
||||
64
|
||||
))
|
||||
.unwrap()
|
||||
} else {
|
||||
let input_clean = input_clean.replace("0x", "");
|
||||
Field::from_str(&format!("{:0>64}", &input_clean)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytes_le_to_field(input: &[u8]) -> (Field, usize) {
|
||||
let (fr_el, read) = bytes_le_to_fr(input);
|
||||
(to_field(&fr_el), read)
|
||||
}
|
||||
|
||||
pub fn bytes_be_to_field(input: &[u8]) -> (Field, usize) {
|
||||
let (fr_el, read) = bytes_be_to_fr(input);
|
||||
(to_field(&fr_el), read)
|
||||
}
|
||||
|
||||
|
||||
pub fn field_to_bytes_le(input: &Field) -> Vec<u8> {
|
||||
fr_to_bytes_le(&to_fr(input))
|
||||
}
|
||||
|
||||
pub fn field_to_bytes_be(input: &Field) -> Vec<u8> {
|
||||
fr_to_bytes_be(&to_fr(input))
|
||||
}
|
||||
|
||||
|
||||
pub fn vec_field_to_bytes_le(input: &[Field]) -> Vec<u8> {
|
||||
vec_fr_to_bytes_le(&vec_field_to_fr(input))
|
||||
}
|
||||
|
||||
pub fn vec_field_to_bytes_be(input: &[Field]) -> Vec<u8> {
|
||||
vec_fr_to_bytes_be(&vec_field_to_fr(input))
|
||||
}
|
||||
|
||||
|
||||
pub fn bytes_le_to_vec_field(input: &[u8]) -> (Vec<Field>, usize) {
|
||||
let (vec_fr, read) = bytes_le_to_vec_fr(input);
|
||||
(vec_fr_to_field(&vec_fr), read)
|
||||
}
|
||||
|
||||
pub fn bytes_be_to_vec_field(input: &[u8]) -> (Vec<Field>, usize) {
|
||||
let (vec_fr, read) = bytes_be_to_vec_fr(input);
|
||||
(vec_fr_to_field(&vec_fr), read)
|
||||
}
|
||||
|
||||
// Arithmetic over Field elements (wrapped over arkworks algebra crate)
|
||||
|
||||
pub fn add(a: &Field, b: &Field) -> Field {
|
||||
to_field(&(to_fr(a) + to_fr(b)))
|
||||
}
|
||||
|
||||
pub fn mul(a: &Field, b: &Field) -> Field {
|
||||
to_field(&(to_fr(a) * to_fr(b)))
|
||||
}
|
||||
|
||||
pub fn div(a: &Field, b: &Field) -> Field {
|
||||
to_field(&(to_fr(a) / to_fr(b)))
|
||||
}
|
||||
|
||||
pub fn inv(a: &Field) -> Field {
|
||||
to_field(&(Fr::from(1) / to_fr(a)))
|
||||
}
|
||||
*/
|
||||
|
||||
139
rln/tests/ffi.rs
139
rln/tests/ffi.rs
@@ -486,10 +486,13 @@ mod test {
|
||||
|
||||
// We generate a random epoch
|
||||
let epoch = hash_to_field(b"test-epoch");
|
||||
// We generate a random rln_identifier
|
||||
let rln_identifier = hash_to_field(b"test-rln-identifier");
|
||||
// We generate a external nullifier
|
||||
let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
|
||||
// We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT
|
||||
let message_id = Fr::from(1);
|
||||
|
||||
let message_id = Fr::from(0);
|
||||
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
|
||||
@@ -500,27 +503,25 @@ mod test {
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized.append(&mut normalize_usize(identity_index));
|
||||
serialized.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
serialized.append(&mut fr_to_bytes_le(&message_id));
|
||||
serialized.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
serialized.append(&mut normalize_usize(signal.len()));
|
||||
serialized.append(&mut signal.to_vec());
|
||||
|
||||
let prove_input = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal,
|
||||
);
|
||||
// We call generate_rln_proof
|
||||
// result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let mut proof_data = rln_proof_gen(rln_pointer, serialized.as_ref());
|
||||
let proof_data = rln_proof_gen(rln_pointer, prove_input.as_ref());
|
||||
|
||||
// We prepare input for verify_rln_proof API
|
||||
// input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// that is [ proof_data | signal_len<8> | signal<var> ]
|
||||
proof_data.append(&mut normalize_usize(signal.len()));
|
||||
proof_data.append(&mut signal.to_vec());
|
||||
// that is [ proof_data || signal_len<8> | signal<var> ]
|
||||
let verify_input = prepare_verify_input(proof_data, &signal);
|
||||
|
||||
// We call verify_rln_proof
|
||||
let input_buffer = &Buffer::from(proof_data.as_ref());
|
||||
let input_buffer = &Buffer::from(verify_input.as_ref());
|
||||
let mut proof_is_valid: bool = false;
|
||||
let proof_is_valid_ptr = &mut proof_is_valid as *mut bool;
|
||||
let success = verify_rln_proof(rln_pointer, input_buffer, proof_is_valid_ptr);
|
||||
@@ -553,11 +554,12 @@ mod test {
|
||||
|
||||
// We generate a random epoch
|
||||
let epoch = hash_to_field(b"test-epoch");
|
||||
// We generate a random rln_identifier
|
||||
let rln_identifier = hash_to_field(b"test-rln-identifier");
|
||||
// We generate a external nullifier
|
||||
let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
|
||||
|
||||
let user_message_limit = Fr::from(100);
|
||||
let message_id = Fr::from(0);
|
||||
// We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT
|
||||
let message_id = Fr::from(1);
|
||||
|
||||
// We set as leaf rate_commitment, its index would be equal to no_of_leaves
|
||||
let leaf_ser = fr_to_bytes_le(&rate_commitment);
|
||||
@@ -567,24 +569,23 @@ mod test {
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
let mut serialized: Vec<u8> = Vec::new();
|
||||
serialized.append(&mut fr_to_bytes_le(&identity_secret_hash));
|
||||
serialized.append(&mut normalize_usize(identity_index));
|
||||
serialized.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
serialized.append(&mut fr_to_bytes_le(&message_id));
|
||||
serialized.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
serialized.append(&mut normalize_usize(signal.len()));
|
||||
serialized.append(&mut signal.to_vec());
|
||||
let prove_input = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal,
|
||||
);
|
||||
|
||||
// We call generate_rln_proof
|
||||
// result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let mut proof_data = rln_proof_gen(rln_pointer, serialized.as_ref());
|
||||
let proof_data = rln_proof_gen(rln_pointer, prove_input.as_ref());
|
||||
|
||||
// We prepare input for verify_rln_proof API
|
||||
// input_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// that is [ proof_data | signal_len<8> | signal<var> ]
|
||||
proof_data.append(&mut normalize_usize(signal.len()));
|
||||
proof_data.append(&mut signal.to_vec());
|
||||
// that is [ proof_data || signal_len<8> | signal<var> ]
|
||||
let verify_input = prepare_verify_input(proof_data.clone(), &signal);
|
||||
|
||||
// We test verify_with_roots
|
||||
|
||||
@@ -592,7 +593,7 @@ 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 mut roots_data: Vec<u8> = Vec::new();
|
||||
|
||||
let input_buffer = &Buffer::from(proof_data.as_ref());
|
||||
let input_buffer = &Buffer::from(verify_input.as_ref());
|
||||
let roots_buffer = &Buffer::from(roots_data.as_ref());
|
||||
let mut proof_is_valid: bool = false;
|
||||
let proof_is_valid_ptr = &mut proof_is_valid as *mut bool;
|
||||
@@ -606,7 +607,7 @@ mod test {
|
||||
for _ in 0..5 {
|
||||
roots_data.append(&mut fr_to_bytes_le(&Fr::rand(&mut rng)));
|
||||
}
|
||||
let input_buffer = &Buffer::from(proof_data.as_ref());
|
||||
let input_buffer = &Buffer::from(verify_input.as_ref());
|
||||
let roots_buffer = &Buffer::from(roots_data.as_ref());
|
||||
let mut proof_is_valid: bool = false;
|
||||
let proof_is_valid_ptr = &mut proof_is_valid as *mut bool;
|
||||
@@ -622,7 +623,7 @@ mod test {
|
||||
|
||||
// We include the root and verify the proof
|
||||
roots_data.append(&mut fr_to_bytes_le(&root));
|
||||
let input_buffer = &Buffer::from(proof_data.as_ref());
|
||||
let input_buffer = &Buffer::from(verify_input.as_ref());
|
||||
let roots_buffer = &Buffer::from(roots_data.as_ref());
|
||||
let mut proof_is_valid: bool = false;
|
||||
let proof_is_valid_ptr = &mut proof_is_valid as *mut bool;
|
||||
@@ -643,7 +644,6 @@ mod test {
|
||||
let (identity_secret_hash, id_commitment) = identity_pair_gen(rln_pointer);
|
||||
|
||||
let user_message_limit = Fr::from(100);
|
||||
let message_id = Fr::from(0);
|
||||
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
|
||||
@@ -665,36 +665,40 @@ mod test {
|
||||
|
||||
// We generate a random epoch
|
||||
let epoch = hash_to_field(b"test-epoch");
|
||||
// We generate a random rln_identifier
|
||||
let rln_identifier = hash_to_field(b"test-rln-identifier");
|
||||
// We generate a external nullifier
|
||||
let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]);
|
||||
// We choose a message_id satisfy 0 <= message_id < MESSAGE_LIMIT
|
||||
let message_id = Fr::from(1);
|
||||
|
||||
// We prepare input for generate_rln_proof API
|
||||
// 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_hash));
|
||||
serialized1.append(&mut normalize_usize(identity_index));
|
||||
serialized1.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
serialized1.append(&mut fr_to_bytes_le(&message_id));
|
||||
serialized1.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
let prove_input1 = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal1,
|
||||
);
|
||||
|
||||
// The first part is the same for both proof input, so we clone
|
||||
let mut serialized2 = serialized1.clone();
|
||||
|
||||
// We attach the first signal to the first proof input
|
||||
serialized1.append(&mut normalize_usize(signal1.len()));
|
||||
serialized1.append(&mut signal1.to_vec());
|
||||
|
||||
// We attach the second signal to the first proof input
|
||||
serialized2.append(&mut normalize_usize(signal2.len()));
|
||||
serialized2.append(&mut signal2.to_vec());
|
||||
let prove_input2 = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal2,
|
||||
);
|
||||
|
||||
// We call generate_rln_proof for first proof values
|
||||
// result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let proof_data_1 = rln_proof_gen(rln_pointer, serialized1.as_ref());
|
||||
let proof_data_1 = rln_proof_gen(rln_pointer, prove_input1.as_ref());
|
||||
|
||||
// We call generate_rln_proof
|
||||
// result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let proof_data_2 = rln_proof_gen(rln_pointer, serialized2.as_ref());
|
||||
let proof_data_2 = rln_proof_gen(rln_pointer, prove_input2.as_ref());
|
||||
|
||||
let input_proof_buffer_1 = &Buffer::from(proof_data_1.as_ref());
|
||||
let input_proof_buffer_2 = &Buffer::from(proof_data_2.as_ref());
|
||||
@@ -737,18 +741,18 @@ mod test {
|
||||
// We prepare input for generate_rln_proof API
|
||||
// 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_hash_new));
|
||||
serialized.append(&mut normalize_usize(identity_index_new));
|
||||
serialized.append(&mut fr_to_bytes_le(&user_message_limit));
|
||||
serialized.append(&mut fr_to_bytes_le(&message_id));
|
||||
serialized.append(&mut fr_to_bytes_le(&external_nullifier));
|
||||
serialized.append(&mut normalize_usize(signal3.len()));
|
||||
serialized.append(&mut signal3.to_vec());
|
||||
let prove_input3 = prepare_prove_input(
|
||||
identity_secret_hash,
|
||||
identity_index_new,
|
||||
user_message_limit,
|
||||
message_id,
|
||||
external_nullifier,
|
||||
&signal3,
|
||||
);
|
||||
|
||||
// We call generate_rln_proof
|
||||
// result_data is [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> ]
|
||||
let proof_data_3 = rln_proof_gen(rln_pointer, serialized.as_ref());
|
||||
let proof_data_3 = rln_proof_gen(rln_pointer, prove_input3.as_ref());
|
||||
|
||||
// We attempt to recover the secret using share1 (coming from identity_secret_hash) and share3 (coming from identity_secret_hash_new)
|
||||
|
||||
@@ -1211,15 +1215,14 @@ mod stateless_test {
|
||||
.unwrap();
|
||||
|
||||
let serialized = serialize_witness(&rln_witness).unwrap();
|
||||
let mut proof_data = rln_proof_gen_with_witness(rln_pointer, serialized.as_ref());
|
||||
let proof_data = rln_proof_gen_with_witness(rln_pointer, serialized.as_ref());
|
||||
|
||||
proof_data.append(&mut normalize_usize(signal.len()));
|
||||
proof_data.append(&mut signal.to_vec());
|
||||
let verify_input = prepare_verify_input(proof_data.clone(), &signal);
|
||||
|
||||
// If no roots is provided, proof validation is skipped and if the remaining proof values are valid, the proof will be correctly verified
|
||||
let mut roots_data: Vec<u8> = Vec::new();
|
||||
|
||||
let input_buffer = &Buffer::from(proof_data.as_ref());
|
||||
let input_buffer = &Buffer::from(verify_input.as_ref());
|
||||
let roots_buffer = &Buffer::from(roots_data.as_ref());
|
||||
let mut proof_is_valid: bool = false;
|
||||
let proof_is_valid_ptr = &mut proof_is_valid as *mut bool;
|
||||
@@ -1233,7 +1236,7 @@ mod stateless_test {
|
||||
for _ in 0..5 {
|
||||
roots_data.append(&mut fr_to_bytes_le(&Fr::rand(&mut rng)));
|
||||
}
|
||||
let input_buffer = &Buffer::from(proof_data.as_ref());
|
||||
let input_buffer = &Buffer::from(verify_input.as_ref());
|
||||
let roots_buffer = &Buffer::from(roots_data.as_ref());
|
||||
let mut proof_is_valid: bool = false;
|
||||
let proof_is_valid_ptr = &mut proof_is_valid as *mut bool;
|
||||
@@ -1248,7 +1251,7 @@ mod stateless_test {
|
||||
|
||||
// We add the real root and we check if now the proof is verified
|
||||
roots_data.append(&mut fr_to_bytes_le(&root));
|
||||
let input_buffer = &Buffer::from(proof_data.as_ref());
|
||||
let input_buffer = &Buffer::from(verify_input.as_ref());
|
||||
let roots_buffer = &Buffer::from(roots_data.as_ref());
|
||||
let mut proof_is_valid: bool = false;
|
||||
let proof_is_valid_ptr = &mut proof_is_valid as *mut bool;
|
||||
|
||||
Reference in New Issue
Block a user