Skip to content

Commit

Permalink
fix json serialization (#253)
Browse files Browse the repository at this point in the history
  • Loading branch information
seemenkina committed May 21, 2024
1 parent fe2b224 commit 820240d
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 167 deletions.
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

0 comments on commit 820240d

Please sign in to comment.