chore(rln): use ark serialized verification key for faster serde (#259)

* chore(rln): use ark serialized verification key for faster serde

* fix: unused imports

* fix: rm verification_key.json

* fix: s/vk_from_slice/vk_from_ark_serialized/g
This commit is contained in:
Aaryamann Challani 2024-06-14 11:03:55 +05:30 committed by GitHub
parent dd5edd6818
commit c6493bd10f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 21 additions and 264 deletions

View File

@ -38,9 +38,9 @@ fn main() -> Result<()> {
}) => {
let mut resources: Vec<Vec<u8>> = Vec::new();
#[cfg(feature = "arkzkey")]
let filenames = ["rln.wasm", "rln_final.arkzkey", "verification_key.json"];
let filenames = ["rln.wasm", "rln_final.arkzkey", "verification_key.arkvkey"];
#[cfg(not(feature = "arkzkey"))]
let filenames = ["rln.wasm", "rln_final.zkey", "verification_key.json"];
let filenames = ["rln.wasm", "rln_final.zkey", "verification_key.arkvkey"];
for filename in filenames {
let fullpath = config.join(Path::new(filename));
let mut file = File::open(&fullpath)?;

View File

@ -25,7 +25,7 @@ mod tests {
let circom_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/rln.wasm");
let zkey_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/rln_final.zkey");
let vk_path =
format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/verification_key.json");
format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/verification_key.arkvkey");
let zkey = read_file(&zkey_path).unwrap();
let vk = read_file(&vk_path).unwrap();
@ -129,7 +129,7 @@ mod tests {
let tree_height = TEST_TREE_HEIGHT;
let zkey_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/rln_final.zkey");
let vk_path =
format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/verification_key.json");
format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/verification_key.arkvkey");
let zkey = read_file(&zkey_path).unwrap();
let vk = read_file(&vk_path).unwrap();

View File

@ -74,7 +74,7 @@ rln = { git = "https://github.com/vacp2p/zerokit" }
First, we need to create a RLN object for a chosen input Merkle tree size.
Note that we need to pass to RLN object constructor the path where the circuit (`rln.wasm`, built for the input tree size), the corresponding proving key (`rln_final.zkey`) or (`rln_final.arkzkey`) and verification key (`verification_key.json`, optional) are found.
Note that we need to pass to RLN object constructor the path where the circuit (`rln.wasm`, built for the input tree size), the corresponding proving key (`rln_final.zkey`) or (`rln_final.arkzkey`) and verification key (`verification_key.arkvkey`, optional) are found.
In the following we will use [cursors](https://doc.rust-lang.org/std/io/struct.Cursor.html) as readers/writers for interfacing with RLN public APIs.

View File

@ -1,6 +1,5 @@
use criterion::{criterion_group, criterion_main, Criterion};
use rln::circuit::{to_verifying_key, RESOURCES_DIR, VK_FILENAME};
use serde_json::Value;
use rln::circuit::{vk_from_ark_serialized, RESOURCES_DIR, VK_FILENAME};
use std::path::Path;
// Here we benchmark how long the deserialization of the
@ -8,12 +7,11 @@ use std::path::Path;
// and skipping conversion from bytes => string => serde_json::Value
pub fn vk_deserialize_benchmark(c: &mut Criterion) {
let vk = RESOURCES_DIR.get_file(Path::new(VK_FILENAME)).unwrap();
let vk = vk.contents_utf8().unwrap();
let json: Value = serde_json::from_str(vk).unwrap();
let vk = vk.contents();
c.bench_function("circuit::to_verifying_key", |b| {
b.iter(|| {
let _ = to_verifying_key(&json);
let _ = vk_from_ark_serialized(&vk);
})
});
}

Binary file not shown.

View File

@ -1,114 +0,0 @@
{
"protocol": "groth16",
"curve": "bn128",
"nPublic": 5,
"vk_alpha_1": [
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
"1"
],
"vk_beta_2": [
[
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
],
[
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
],
[
"1",
"0"
]
],
"vk_gamma_2": [
[
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
],
[
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
],
[
"1",
"0"
]
],
"vk_delta_2": [
[
"17077735495685170943380938230836408503627170115414840315502244846025577589191",
"14030085636943255545683322474441991939484590437387381169642530788494152024614"
],
[
"11568745146423307387256571230823432454624378106569286849514884592874522611163",
"1838524899938769516485895655063198583192139511330418290063560641219523306282"
],
[
"1",
"0"
]
],
"vk_alphabeta_12": [
[
[
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
],
[
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
],
[
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
]
],
[
[
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
],
[
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
],
[
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
]
]
],
"IC": [
[
"4920513730204767532050733107749276406754520419375654722016092399980613788208",
"10950491564509418434657706642388934308456795265036074733953533582377584967294",
"1"
],
[
"6815064660695497986531118446154820702646540722664044216580897159556261271171",
"17838140936832571103329556013529166877877534025488014783346458943575275015438",
"1"
],
[
"16364982450206976302246609763791333525052810246590359380676749324389440643932",
"17092624338100676284548565502349491320314889021833923882585524649862570629227",
"1"
],
[
"3679639231485547795420532910726924727560917141402837495597760107842698404034",
"16213191511474848247596810551723578773353083440353745908057321946068926848382",
"1"
],
[
"9215428431027260354679105025212521481930206886203677270216204485256690813172",
"934602510541226149881779979217731465262250233587980565969044391353665291792",
"1"
],
[
"8935861545794299876685457331391349387048184820319250771243971382360441890897",
"4993459033694759724715904486381952906869986989682015547152342336961693234616",
"1"
]
]
}

View File

@ -6,11 +6,9 @@ use ark_bn254::{
};
use ark_groth16::{ProvingKey, VerifyingKey};
use ark_relations::r1cs::ConstraintMatrices;
use ark_serialize::CanonicalDeserialize;
use cfg_if::cfg_if;
use color_eyre::{Report, Result};
use num_bigint::BigUint;
use serde_json::Value;
use std::str::FromStr;
cfg_if! {
if #[cfg(not(target_arch = "wasm32"))] {
@ -35,7 +33,7 @@ cfg_if! {
}
const ZKEY_FILENAME: &str = "tree_height_20/rln_final.zkey";
pub const VK_FILENAME: &str = "tree_height_20/verification_key.json";
pub const VK_FILENAME: &str = "tree_height_20/verification_key.arkvkey";
const WASM_FILENAME: &str = "tree_height_20/rln.wasm";
pub const TEST_TREE_HEIGHT: usize = 20;
@ -101,7 +99,7 @@ pub fn vk_from_raw(vk_data: &[u8], zkey_data: &Vec<u8>) -> Result<VerifyingKey<C
let verifying_key: VerifyingKey<Curve>;
if !vk_data.is_empty() {
verifying_key = vk_from_vector(vk_data)?;
verifying_key = vk_from_ark_serialized(vk_data)?;
Ok(verifying_key)
} else if !zkey_data.is_empty() {
let (proving_key, _matrices) = zkey_from_raw(zkey_data)?;
@ -120,9 +118,7 @@ pub fn vk_from_folder() -> Result<VerifyingKey<Curve>> {
let verifying_key: VerifyingKey<Curve>;
if let Some(vk) = vk {
verifying_key = vk_from_json(vk.contents_utf8().ok_or(Report::msg(
"Could not read verification key from JSON file!",
))?)?;
verifying_key = vk_from_ark_serialized(vk.contents())?;
Ok(verifying_key)
} else if let Some(_zkey) = zkey {
let (proving_key, _matrices) = zkey_from_folder()?;
@ -161,115 +157,11 @@ pub fn circom_from_folder() -> Result<&'static Mutex<WitnessCalculator>> {
}
}
// The following function implementations are taken/adapted from https://github.com/gakonst/ark-circom/blob/1732e15d6313fe176b0b1abb858ac9e095d0dbd7/src/zkey.rs
// Utilities to convert a json verification key in a groth16::VerificationKey
fn fq_from_str(s: &str) -> Result<Fq> {
Ok(Fq::from(BigUint::from_str(s)?))
}
// Extracts the element in G1 corresponding to its JSON serialization
fn json_to_g1(json: &Value, key: &str) -> Result<G1Affine> {
let els: Vec<String> = json
.get(key)
.ok_or(Report::msg("no json value"))?
.as_array()
.ok_or(Report::msg("value not an array"))?
.iter()
.map(|i| i.as_str().ok_or(Report::msg("element is not a string")))
.map(|x| x.map(|v| v.to_owned()))
.collect::<Result<Vec<String>>>()?;
Ok(G1Affine::from(G1Projective::new(
fq_from_str(&els[0])?,
fq_from_str(&els[1])?,
fq_from_str(&els[2])?,
)))
}
// Extracts the vector of G1 elements corresponding to its JSON serialization
fn json_to_g1_vec(json: &Value, key: &str) -> Result<Vec<G1Affine>> {
let els: Vec<Vec<String>> = json
.get(key)
.ok_or(Report::msg("no json value"))?
.as_array()
.ok_or(Report::msg("value not an array"))?
.iter()
.map(|i| {
i.as_array()
.ok_or(Report::msg("element is not an array"))
.and_then(|array| {
array
.iter()
.map(|x| x.as_str().ok_or(Report::msg("element is not a string")))
.map(|x| x.map(|v| v.to_owned()))
.collect::<Result<Vec<String>>>()
})
})
.collect::<Result<Vec<Vec<String>>>>()?;
let mut res = vec![];
for coords in els {
res.push(G1Affine::from(G1Projective::new(
fq_from_str(&coords[0])?,
fq_from_str(&coords[1])?,
fq_from_str(&coords[2])?,
)))
}
Ok(res)
}
// Extracts the element in G2 corresponding to its JSON serialization
fn json_to_g2(json: &Value, key: &str) -> Result<G2Affine> {
let els: Vec<Vec<String>> = json
.get(key)
.ok_or(Report::msg("no json value"))?
.as_array()
.ok_or(Report::msg("value not an array"))?
.iter()
.map(|i| {
i.as_array()
.ok_or(Report::msg("element is not an array"))
.and_then(|array| {
array
.iter()
.map(|x| x.as_str().ok_or(Report::msg("element is not a string")))
.map(|x| x.map(|v| v.to_owned()))
.collect::<Result<Vec<String>>>()
})
})
.collect::<Result<Vec<Vec<String>>>>()?;
let x = Fq2::new(fq_from_str(&els[0][0])?, fq_from_str(&els[0][1])?);
let y = Fq2::new(fq_from_str(&els[1][0])?, fq_from_str(&els[1][1])?);
let z = Fq2::new(fq_from_str(&els[2][0])?, fq_from_str(&els[2][1])?);
Ok(G2Affine::from(G2Projective::new(x, y, z)))
}
// Converts JSON to a VerifyingKey
pub fn to_verifying_key(json: &serde_json::Value) -> Result<VerifyingKey<Curve>> {
Ok(VerifyingKey {
alpha_g1: json_to_g1(json, "vk_alpha_1")?,
beta_g2: json_to_g2(json, "vk_beta_2")?,
gamma_g2: json_to_g2(json, "vk_gamma_2")?,
delta_g2: json_to_g2(json, "vk_delta_2")?,
gamma_abc_g1: json_to_g1_vec(json, "IC")?,
})
}
// Computes the verification key from its JSON serialization
fn vk_from_json(vk: &str) -> Result<VerifyingKey<Curve>> {
let json: Value = serde_json::from_str(vk)?;
to_verifying_key(&json)
}
// Computes the verification key from a bytes vector containing its JSON serialization
fn vk_from_vector(vk: &[u8]) -> Result<VerifyingKey<Curve>> {
let json = String::from_utf8(vk.to_vec())?;
let json: Value = serde_json::from_str(&json)?;
to_verifying_key(&json)
// Computes the verification key from a bytes vector containing pre-processed ark-serialized verification key
// uncompressed, unchecked
pub fn vk_from_ark_serialized(data: &[u8]) -> Result<VerifyingKey<Curve>> {
let vk = VerifyingKey::<Curve>::deserialize_uncompressed_unchecked(data)?;
Ok(vk)
}
// Checks verification key to be correct with respect to proving key

View File

@ -112,7 +112,7 @@ impl RLN<'_> {
/// - `tree_height`: the height of the internal Merkle tree
/// - `circom_vec`: a byte vector containing the ZK circuit (`rln.wasm`) as binary file
/// - `zkey_vec`: a byte vector containing to the proving key (`rln_final.zkey`) or (`rln_final.arkzkey`) as binary file
/// - `vk_vec`: a byte vector containing to the verification key (`verification_key.json`) as binary file
/// - `vk_vec`: a byte vector containing to the verification key (`verification_key.arkvkey`) as binary file
/// - `tree_config_input`: a reader for a string containing a json with the merkle tree configuration
///
/// Example:
@ -124,7 +124,7 @@ impl RLN<'_> {
/// let resources_folder = "./resources/tree_height_20/";
///
/// let mut resources: Vec<Vec<u8>> = Vec::new();
/// for filename in ["rln.wasm", "rln_final.zkey", "verification_key.json"] {
/// for filename in ["rln.wasm", "rln_final.zkey", "verification_key.arkvkey"] {
/// let fullpath = format!("{resources_folder}{filename}");
/// let mut file = File::open(&fullpath).expect("no file found");
/// let metadata = std::fs::metadata(&fullpath).expect("unable to read metadata");

View File

@ -1,11 +1,10 @@
use crate::circuit::{Curve, Fr, TEST_TREE_HEIGHT};
use crate::circuit::{Fr, TEST_TREE_HEIGHT};
use crate::hashers::{hash_to_field, poseidon_hash as utils_poseidon_hash};
use crate::protocol::*;
use crate::public::RLN;
use crate::utils::*;
use ark_groth16::Proof as ArkProof;
use ark_serialize::{CanonicalDeserialize, Read};
use num_bigint::BigInt;
use std::io::Cursor;
use std::str::FromStr;
use utils::ZerokitMerkleTree;
@ -646,24 +645,6 @@ fn test_rln_with_witness() {
let serialized_witness = serialize_witness(&rln_witness).unwrap();
// Calculate witness outside zerokit (simulating what JS is doing)
let inputs = inputs_for_witness_calculation(&rln_witness)
.unwrap()
.into_iter()
.map(|(name, values)| (name.to_string(), values));
let calculated_witness = rln
.witness_calculator
.lock()
.expect("witness_calculator mutex should not get poisoned")
.calculate_witness_element::<Curve, _>(inputs, false)
.map_err(ProofError::WitnessError)
.unwrap();
let calculated_witness_vec: Vec<BigInt> = calculated_witness
.into_iter()
.map(|v| to_bigint(&v).unwrap())
.collect();
// Generating the proof
let mut input_buffer = Cursor::new(serialized_witness);
let mut output_buffer = Cursor::new(Vec::<u8>::new());

View File

@ -427,7 +427,7 @@ mod test {
.read_exact(&mut zkey_buffer)
.expect("buffer overflow");
let vk_path = "./resources/tree_height_20/verification_key.json";
let vk_path = "./resources/tree_height_20/verification_key.arkvkey";
let mut vk_file = File::open(&vk_path).expect("no file found");
let metadata = std::fs::metadata(&vk_path).expect("unable to read metadata");
let mut vk_buffer = vec![0; metadata.len() as usize];