chore(rln): add ark-zkey support (#242)

* Add Submodule

* Add arkzkey

* make arkzkey support as feature

* update submodule url

* add abstract around feature

* new bench file

* update ci
This commit is contained in:
Ekaterina Broslavskaya 2024-05-06 18:09:22 +07:00 committed by GitHub
parent 5937a67ee6
commit 8581ac0b78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 842 additions and 39 deletions

View File

@ -123,6 +123,8 @@ jobs:
steps:
- name: Checkout sources
uses: actions/checkout@v3
with:
submodules: true
- uses: Swatinem/rust-cache@v2
- uses: boa-dev/criterion-compare-action@v3
with:

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "mopro"]
path = mopro
url = https://github.com/zkmopro/mopro.git

788
Cargo.lock generated

File diff suppressed because it is too large Load Diff

1
mopro Submodule

@ -0,0 +1 @@
Subproject commit 3c8d73433632ff497dff238e87e37b152251eece

View File

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

View File

@ -32,6 +32,7 @@ ark-serialize = { version = "=0.4.1", default-features = false }
ark-circom = { version = "=0.1.0", default-features = false, features = [
"circom-2",
] }
ark-zkey = { path = "../mopro/ark-zkey", optional = true, default-features = false }
# WASM
wasmer = { version = "=2.3.0", default-features = false }
@ -74,6 +75,7 @@ parallel = [
]
wasm = ["wasmer/js", "wasmer/std"]
fullmerkletree = ["default"]
arkzkey = ["ark-zkey"]
# Note: pmtree feature is still experimental
pmtree-ft = ["utils/pmtree-ft"]
@ -81,3 +83,7 @@ pmtree-ft = ["utils/pmtree-ft"]
[[bench]]
name = "pmtree_benchmark"
harness = false
[[bench]]
name = "circuit_loading_benchmark"
harness = false

View File

@ -0,0 +1,15 @@
use criterion::{criterion_group, criterion_main, Criterion};
use rln::circuit::TEST_RESOURCES_FOLDER;
// Depending on the key type (enabled by the `--features arkzkey` flag)
// the upload speed from the `rln_final.zkey` or `rln_final.arkzkey` file is calculated
pub fn key_load_benchmark(c: &mut Criterion) {
c.bench_function("zkey::upload_from_folder", |b| {
b.iter(|| {
let _ = rln::circuit::zkey_from_folder(TEST_RESOURCES_FOLDER);
})
});
}
criterion_group!(benches, key_load_benchmark);
criterion_main!(benches);

View File

@ -1,7 +1,6 @@
use criterion::{criterion_group, criterion_main, Criterion};
use utils::ZerokitMerkleTree;
use rln::{circuit::Fr, pm_tree_adapter::PmTree};
use utils::ZerokitMerkleTree;
pub fn pmtree_benchmark(c: &mut Criterion) {
let mut tree = PmTree::default(2).unwrap();

Binary file not shown.

View File

@ -4,14 +4,12 @@ use ark_bn254::{
Bn254, Fq as ArkFq, Fq2 as ArkFq2, Fr as ArkFr, G1Affine as ArkG1Affine,
G1Projective as ArkG1Projective, G2Affine as ArkG2Affine, G2Projective as ArkG2Projective,
};
use ark_circom::read_zkey;
use ark_groth16::{ProvingKey, VerifyingKey};
use ark_relations::r1cs::ConstraintMatrices;
use cfg_if::cfg_if;
use color_eyre::{Report, Result};
use num_bigint::BigUint;
use serde_json::Value;
use std::io::Cursor;
use std::str::FromStr;
cfg_if! {
@ -25,6 +23,17 @@ cfg_if! {
}
}
cfg_if! {
if #[cfg(feature = "arkzkey")] {
use ark_zkey::read_arkzkey_from_bytes;
const ARKZKEY_FILENAME: &str = "rln_final.arkzkey";
} else {
use std::io::Cursor;
use ark_circom::read_zkey;
}
}
const ZKEY_FILENAME: &str = "rln_final.zkey";
const VK_FILENAME: &str = "verification_key.json";
const WASM_FILENAME: &str = "rln.wasm";
@ -49,8 +58,15 @@ pub type G2Projective = ArkG2Projective;
// Loads the proving key using a bytes vector
pub fn zkey_from_raw(zkey_data: &Vec<u8>) -> Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)> {
if !zkey_data.is_empty() {
let mut c = Cursor::new(zkey_data);
let proving_key_and_matrices = read_zkey(&mut c)?;
let proving_key_and_matrices = match () {
#[cfg(feature = "arkzkey")]
() => read_arkzkey_from_bytes(zkey_data.as_slice())?,
#[cfg(not(feature = "arkzkey"))]
() => {
let mut c = Cursor::new(zkey_data);
read_zkey(&mut c)?
}
};
Ok(proving_key_and_matrices)
} else {
Err(Report::msg("No proving key found!"))
@ -62,10 +78,21 @@ pub fn zkey_from_raw(zkey_data: &Vec<u8>) -> Result<(ProvingKey<Curve>, Constrai
pub fn zkey_from_folder(
resources_folder: &str,
) -> Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)> {
#[cfg(feature = "arkzkey")]
let zkey = RESOURCES_DIR.get_file(Path::new(resources_folder).join(ARKZKEY_FILENAME));
#[cfg(not(feature = "arkzkey"))]
let zkey = RESOURCES_DIR.get_file(Path::new(resources_folder).join(ZKEY_FILENAME));
if let Some(zkey) = zkey {
let mut c = Cursor::new(zkey.contents());
let proving_key_and_matrices = read_zkey(&mut c)?;
let proving_key_and_matrices = match () {
#[cfg(feature = "arkzkey")]
() => read_arkzkey_from_bytes(zkey.contents())?,
#[cfg(not(feature = "arkzkey"))]
() => {
let mut c = Cursor::new(zkey.contents());
read_zkey(&mut c)?
}
};
Ok(proving_key_and_matrices)
} else {
Err(Report::msg("No proving key found!"))

View File

@ -58,7 +58,7 @@ impl RLN<'_> {
///
/// Input parameters are
/// - `tree_height`: the height of the internal Merkle tree
/// - `input_data`: a reader for the string path of the resource folder containing the ZK circuit (`rln.wasm`), the proving key (`rln_final.zkey`) and the verification key (`verification_key.json`).
/// - `input_data`: a reader for the string path of the resource folder containing the ZK circuit (`rln.wasm`), the proving key (`rln_final.zkey`) or (`rln_final.arkzkey`) and the verification key (`verification_key.json`).
///
/// Example:
/// ```
@ -83,8 +83,8 @@ impl RLN<'_> {
let tree_config = rln_config["tree_config"].to_string();
let witness_calculator = circom_from_folder(resources_folder)?;
let proving_key = zkey_from_folder(resources_folder)?;
let verification_key = vk_from_folder(resources_folder)?;
let tree_config: <PoseidonTree as ZerokitMerkleTree>::Config = if tree_config.is_empty() {
@ -115,7 +115,7 @@ impl RLN<'_> {
/// Input parameters are
/// - `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`) 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
/// - `tree_config`: a reader for a string containing a json with the merkle tree configuration
///
@ -684,7 +684,7 @@ impl RLN<'_> {
/// Output values are:
/// - `output_data`: a writer receiving the serialization of the zkSNARK proof and the circuit evaluations outputs, i.e. `[ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]`
///
/// Example
/// Example
/// ```
/// use rln::protocol::*:
/// use rln::utils::*;
@ -829,7 +829,7 @@ impl RLN<'_> {
/// Note that contrary to [`verify_rln_proof`](crate::public::RLN::verify_rln_proof), this function does not check if the internal Merkle tree root corresponds to the root provided as input, but rather checks if the root provided as input in `input_data` corresponds to one of the roots serialized in `roots_data`.
///
/// If `roots_data` contains no root (is empty), root validation is skipped and the proof will be correctly verified only if the other proof values results valid (i.e., zk-proof, signal, x-coordinate, RLN identifier)
///
///
/// Example
/// ```
/// // proof_data is computed as in the example code snippet provided for rln::public::RLN::generate_rln_proof

View File

@ -618,7 +618,9 @@ mod test {
circom_file
.read_exact(&mut circom_buffer)
.expect("buffer overflow");
#[cfg(feature = "arkzkey")]
let zkey_path = format!("./resources/tree_height_{TEST_TREE_HEIGHT}/rln_final.arkzkey");
#[cfg(not(feature = "arkzkey"))]
let zkey_path = format!("./resources/tree_height_{TEST_TREE_HEIGHT}/rln_final.zkey");
let mut zkey_file = File::open(&zkey_path).expect("no file found");
let metadata = std::fs::metadata(&zkey_path).expect("unable to read metadata");

View File

@ -1,9 +1,9 @@
#[cfg(test)]
mod test {
use ark_ff::BigInt;
use rln::circuit::zkey_from_folder;
use rln::circuit::{
circom_from_folder, vk_from_folder, zkey_from_folder, Fr, TEST_RESOURCES_FOLDER,
TEST_TREE_HEIGHT,
circom_from_folder, vk_from_folder, Fr, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT,
};
use rln::hashers::{hash_to_field, poseidon_hash};
use rln::poseidon_tree::PoseidonTree;