Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix json serialization and update corresponding test #253

Merged
merged 1 commit into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 45 additions & 77 deletions rln/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use ark_circom::{CircomReduction, WitnessCalculator};
use ark_groth16::{prepare_verifying_key, Groth16, Proof as ArkProof, ProvingKey, VerifyingKey};
use ark_relations::r1cs::ConstraintMatrices;
use ark_relations::r1cs::SynthesisError;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{rand::thread_rng, UniformRand};
use color_eyre::{Report, Result};
use num_bigint::BigInt;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha20Rng;
use serde::{Deserialize, Serialize};
#[cfg(not(target_arch = "wasm32"))]
use std::sync::Mutex;
#[cfg(debug_assertions)]
Expand All @@ -29,14 +31,20 @@ use utils::{ZerokitMerkleProof, ZerokitMerkleTree};
// RLN Witness data structure and utility functions
///////////////////////////////////////////////////////

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct RLNWitnessInput {
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
identity_secret: Fr,
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
user_message_limit: Fr,
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
message_id: Fr,
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
path_elements: Vec<Fr>,
identity_path_index: Vec<u8>,
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
x: Fr,
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
external_nullifier: Fr,
}

Expand Down Expand Up @@ -214,55 +222,6 @@ pub fn proof_inputs_to_rln_witness(
))
}

/// Returns `RLNWitnessInput` given a file with JSON serialized values.
///
/// # Errors
///
/// Returns an error if `message_id` is not within `user_message_limit`.
pub fn rln_witness_from_json(input_json_str: &str) -> Result<RLNWitnessInput> {
let input_json: serde_json::Value =
serde_json::from_str(input_json_str).expect("JSON was not well-formatted");

let user_message_limit = str_to_fr(&input_json["userMessageLimit"].to_string(), 10)?;

let message_id = str_to_fr(&input_json["messageId"].to_string(), 10)?;

message_id_range_check(&message_id, &user_message_limit)?;

let identity_secret = str_to_fr(&input_json["identitySecret"].to_string(), 10)?;

let path_elements = input_json["pathElements"]
.as_array()
.ok_or(Report::msg("not an array"))?
.iter()
.map(|v| str_to_fr(&v.to_string(), 10))
.collect::<Result<_>>()?;

let identity_path_index_array = input_json["identityPathIndex"]
.as_array()
.ok_or(Report::msg("not an array"))?;

let mut identity_path_index: Vec<u8> = vec![];

for v in identity_path_index_array {
identity_path_index.push(v.as_u64().ok_or(Report::msg("not a u64 value"))? as u8);
}

let x = str_to_fr(&input_json["x"].to_string(), 10)?;

let external_nullifier = str_to_fr(&input_json["externalNullifier"].to_string(), 10)?;

Ok(RLNWitnessInput {
identity_secret,
path_elements,
identity_path_index,
x,
external_nullifier,
user_message_limit,
message_id,
})
}

/// Creates `RLNWitnessInput` from it's fields.
///
/// # Errors
Expand Down Expand Up @@ -759,40 +718,49 @@ pub fn verify_proof(
Ok(verified)
}

/// Get CIRCOM JSON inputs
///
/// Returns a JSON object containing the inputs necessary to calculate
/// the witness with CIRCOM on javascript
// auxiliary function for serialisation Fr to json using ark serilize
fn ark_se<S, A: CanonicalSerialize>(a: &A, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut bytes = vec![];
a.serialize_compressed(&mut bytes)
.map_err(serde::ser::Error::custom)?;
s.serialize_bytes(&bytes)
}

// auxiliary function for deserialisation Fr to json using ark serilize
fn ark_de<'de, D, A: CanonicalDeserialize>(data: D) -> Result<A, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let s: Vec<u8> = serde::de::Deserialize::deserialize(data)?;
let a = A::deserialize_compressed_unchecked(s.as_slice());
a.map_err(serde::de::Error::custom)
}

/// Converts a [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) object to the corresponding JSON serialization.
///
/// # Errors
///
/// Returns an error if `rln_witness.message_id` is not within `rln_witness.user_message_limit`.
pub fn get_json_inputs(rln_witness: &RLNWitnessInput) -> Result<serde_json::Value> {
/// Returns an error if `message_id` is not within `user_message_limit`.
pub fn rln_witness_from_json(input_json: serde_json::Value) -> Result<RLNWitnessInput> {
let rln_witness: RLNWitnessInput = serde_json::from_value(input_json).unwrap();
message_id_range_check(&rln_witness.message_id, &rln_witness.user_message_limit)?;

let mut path_elements = Vec::new();
Ok(rln_witness)
}

for v in rln_witness.path_elements.iter() {
path_elements.push(to_bigint(v)?.to_str_radix(10));
}
/// Converts a JSON value into [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) object.
///
/// # Errors
///
/// Returns an error if `rln_witness.message_id` is not within `rln_witness.user_message_limit`.
pub fn rln_witness_to_json(rln_witness: &RLNWitnessInput) -> Result<serde_json::Value> {
message_id_range_check(&rln_witness.message_id, &rln_witness.user_message_limit)?;

let mut identity_path_index = Vec::new();
rln_witness
.identity_path_index
.iter()
.for_each(|v| identity_path_index.push(BigInt::from(*v).to_str_radix(10)));

let inputs = serde_json::json!({
"identitySecret": to_bigint(&rln_witness.identity_secret)?.to_str_radix(10),
"userMessageLimit": to_bigint(&rln_witness.user_message_limit)?.to_str_radix(10),
"messageId": to_bigint(&rln_witness.message_id)?.to_str_radix(10),
"pathElements": path_elements,
"identityPathIndex": identity_path_index,
"x": to_bigint(&rln_witness.x)?.to_str_radix(10),
"externalNullifier": to_bigint(&rln_witness.external_nullifier)?.to_str_radix(10),
});

Ok(inputs)
let rln_witness_json = serde_json::to_value(rln_witness)?;
Ok(rln_witness_json)
}

pub fn message_id_range_check(message_id: &Fr, user_message_limit: &Fr) -> Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion rln/src/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1248,7 +1248,7 @@ impl RLN<'_> {
/// The function returns the corresponding JSON encoding of the input [`RLNWitnessInput`](crate::protocol::RLNWitnessInput) object.
pub fn get_rln_witness_json(&mut self, serialized_witness: &[u8]) -> Result<serde_json::Value> {
let (rln_witness, _) = deserialize_witness(serialized_witness)?;
get_json_inputs(&rln_witness)
rln_witness_to_json(&rln_witness)
}

/// Closes the connection to the Merkle tree database.
Expand Down
133 changes: 44 additions & 89 deletions rln/tests/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,6 @@ mod test {

type ConfigOf<T> = <T as ZerokitMerkleTree>::Config;

// Input generated with https://github.com/oskarth/zk-kit/commit/b6a872f7160c7c14e10a0ea40acab99cbb23c9a8
const WITNESS_JSON_20: &str = r#"
{
"externalNullifier": "21074405743803627666274838159589343934394162804826017440941339048886754734203",
"identityPathIndex": [
1,
1,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
0,
0,
0,
0,
1,
1,
1,
0
],
"identitySecret": "2301650865650889795878889082892690584512243988708213561328369865554257051708",
"messageId": "1",
"pathElements": [
"14082964758224722211945379872337797638951236517417253447686770846170014042825",
"6628418579821163687428454604867534487917867918886059133241840211975892987309",
"12745863228198753394445659605634840709296716381893463421165313830643281758511",
"56118267389743063830320351452083247040583061493621478539311100137113963555",
"3648731943306935051357703221473866306053186513730785325303257057776816073765",
"10548621390442503192989374711060717107954536293658152583621924810330521179016",
"11741160669079729961275351458682156164905457324981803454515784688429276743441",
"17165464309215350864730477596846156251863702878546777829650812432906796008534",
"18947162586829418653666557598416458949428989734998924978331450666032720066913",
"8809427088917589399897132358419395928548406347152047718919154153577297139202",
"6261460226929242970747566981077801929281729646713842579109271945192964422300",
"13871468675790284383809887052382100311103716176061564908030808887079542722597",
"10413964486611723004584705484327518190402370933255450052832412709168190985805",
"3978387560092078849178760154060822400741873818692524912249877867958842934383",
"14014915591348694328771517896715085647041518432952027841088176673715002508448",
"17680675606519345547327984724173632294904524423937145835611954334756161077843",
"17107175244885276119916848057745382329169223109661217238296871427531065458152",
"18326186549441826262593357123467931475982067066825042001499291800252145875109",
"7043961192177345916232559778383741091053414803377017307095275172896944935996",
"2807630271073553218355393059254209097448243975722083008310815929736065268921"
],
"userMessageLimit": "100",
"x": "20645213238265527935869146898028115621427162613172918400241870500502509785943"
}
"#;

#[test]
// We test Merkle tree generation, proofs and verification
fn test_merkle_proof() {
Expand Down Expand Up @@ -140,33 +85,8 @@ mod test {
assert!(tree.verify(&rate_commitment, &merkle_proof).unwrap());
}

#[test]
// We test a RLN proof generation and verification
fn test_witness_from_json() {
// We generate all relevant keys
let proving_key = zkey_from_folder().unwrap();
let verification_key = vk_from_folder().unwrap();
let builder = circom_from_folder().unwrap();

// We compute witness from the json input example
let witness_json = WITNESS_JSON_20;
let rln_witness = rln_witness_from_json(witness_json).unwrap();

// Let's generate a zkSNARK proof
let proof = generate_proof(builder, &proving_key, &rln_witness).unwrap();
let proof_values = proof_values_from_witness(&rln_witness).unwrap();

// Let's verify the proof
let verified = verify_proof(&verification_key, &proof, &proof_values);

assert!(verified.unwrap());
}

#[test]
// We test a RLN proof generation and verification
fn test_end_to_end() {
fn get_test_witness() -> RLNWitnessInput {
let leaf_index = 3;

// Generate identity pair
let (identity_secret_hash, id_commitment) = keygen();
let user_message_limit = Fr::from(100);
Expand All @@ -192,25 +112,58 @@ mod test {
let rln_identifier = hash_to_field(b"test-rln-identifier");
let external_nullifier = poseidon_hash(&[epoch, rln_identifier]);

let rln_witness: RLNWitnessInput = rln_witness_from_values(
rln_witness_from_values(
identity_secret_hash,
&merkle_proof,
x,
external_nullifier,
user_message_limit,
Fr::from(1),
)
.unwrap();
.unwrap()
}

#[test]
// We test a RLN proof generation and verification
fn test_witness_from_json() {
// We generate all relevant keys
let proving_key = zkey_from_folder().unwrap();
let verification_key = vk_from_folder().unwrap();
let builder = circom_from_folder().unwrap();

// We compute witness from the json input
let rln_witness = get_test_witness();
let rln_witness_json = rln_witness_to_json(&rln_witness).unwrap();
let rln_witness_deser = rln_witness_from_json(rln_witness_json).unwrap();
assert_eq!(rln_witness_deser, rln_witness);

// Let's generate a zkSNARK proof
let proof = generate_proof(builder, &proving_key, &rln_witness).unwrap();
let proof = generate_proof(builder, &proving_key, &rln_witness_deser).unwrap();
let proof_values = proof_values_from_witness(&rln_witness_deser).unwrap();

let proof_values = proof_values_from_witness(&rln_witness).unwrap();
// Let's verify the proof
let verified = verify_proof(&verification_key, &proof, &proof_values);

assert!(verified.unwrap());
}

#[test]
// We test a RLN proof generation and verification
fn test_end_to_end() {
let rln_witness = get_test_witness();
let rln_witness_json = rln_witness_to_json(&rln_witness).unwrap();
let rln_witness_deser = rln_witness_from_json(rln_witness_json).unwrap();
assert_eq!(rln_witness_deser, rln_witness);

// We generate all relevant keys
let proving_key = zkey_from_folder().unwrap();
let verification_key = vk_from_folder().unwrap();
let builder = circom_from_folder().unwrap();

// Let's generate a zkSNARK proof
let proof = generate_proof(builder, &proving_key, &rln_witness_deser).unwrap();

let proof_values = proof_values_from_witness(&rln_witness_deser).unwrap();

// Let's verify the proof
let success = verify_proof(&verification_key, &proof, &proof_values).unwrap();
Expand All @@ -220,11 +173,13 @@ mod test {

#[test]
fn test_witness_serialization() {
// We test witness serialization
let witness_json: &str = WITNESS_JSON_20;

let rln_witness = rln_witness_from_json(witness_json).unwrap();
// We test witness JSON serialization
let rln_witness = get_test_witness();
let rln_witness_json = rln_witness_to_json(&rln_witness).unwrap();
let rln_witness_deser = rln_witness_from_json(rln_witness_json).unwrap();
assert_eq!(rln_witness_deser, rln_witness);

// We test witness serialization
let ser = serialize_witness(&rln_witness).unwrap();
let (deser, _) = deserialize_witness(&ser).unwrap();
assert_eq!(rln_witness, deser);
Expand Down
Loading