diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a28523f..dff3f82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -135,14 +135,37 @@ jobs: # We skip clippy on rln-wasm, since wasm target is managed by cargo make # Currently not treating warnings as error, too noisy # -- -D warnings - benchmark: + + benchmark-utils: # run only in pull requests if: github.event_name == 'pull_request' strategy: matrix: # we run benchmark tests only on ubuntu platform: [ ubuntu-latest ] - crate: [ rln, utils ] + crate: [ utils ] + runs-on: ${{ matrix.platform }} + timeout-minutes: 60 + + name: benchmark - ${{ matrix.platform }} - ${{ matrix.crate }} + steps: + - name: Checkout sources + uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 + - uses: boa-dev/criterion-compare-action@v3 + with: + branchName: ${{ github.base_ref }} + cwd: ${{ matrix.crate }} + + benchmark-rln: + # run only in pull requests + if: github.event_name == 'pull_request' + strategy: + matrix: + # we run benchmark tests only on ubuntu + platform: [ ubuntu-latest ] + crate: [ rln ] + feature: [ "default", "arkzkey" ] runs-on: ${{ matrix.platform }} timeout-minutes: 60 @@ -155,3 +178,4 @@ jobs: with: branchName: ${{ github.base_ref }} cwd: ${{ matrix.crate }} + features: ${{ matrix.feature }} \ No newline at end of file diff --git a/rln/Cargo.toml b/rln/Cargo.toml index fe72076..c24461f 100644 --- a/rln/Cargo.toml +++ b/rln/Cargo.toml @@ -90,6 +90,11 @@ harness = false name = "circuit_loading_benchmark" harness = false +[[bench]] +name = "circuit_loading_arkzkey_benchmark" +harness = false +required-features = ["arkzkey"] + [[bench]] name = "circuit_deser_benchmark" harness = false diff --git a/rln/benches/circuit_loading_arkzkey_benchmark.rs b/rln/benches/circuit_loading_arkzkey_benchmark.rs new file mode 100644 index 0000000..4e15759 --- /dev/null +++ b/rln/benches/circuit_loading_arkzkey_benchmark.rs @@ -0,0 +1,36 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use rln::circuit::{arkzkey_from_raw_compressed, arkzkey_from_raw_uncompressed, ARKZKEY_BYTES, ARKZKEY_BYTES_UNCOMPR}; + +pub fn uncompressed_bench(c: &mut Criterion) { + let arkzkey = ARKZKEY_BYTES_UNCOMPR.to_vec(); + let size = arkzkey.len() as f32; + println!("Size of uncompressed arkzkey: {:.2?} MB", size / 1024.0 / 1024.0); + + c.bench_function("arkzkey::arkzkey_from_raw_uncompressed", |b| { + b.iter(|| { + let r = arkzkey_from_raw_uncompressed(&arkzkey); + assert_eq!(r.is_ok(), true); + }) + }); +} +pub fn compressed_bench(c: &mut Criterion) { + let arkzkey = ARKZKEY_BYTES.to_vec(); + let size = arkzkey.len() as f32; + println!("Size of compressed arkzkey: {:.2?} MB", size / 1024.0 / 1024.0); + + c.bench_function("arkzkey::arkzkey_from_raw_compressed", |b| { + b.iter(|| { + let r = arkzkey_from_raw_compressed(&arkzkey); + assert_eq!(r.is_ok(), true); + }) + }); +} + + +criterion_group! { + name = benches; + config = Criterion::default().measurement_time(std::time::Duration::from_secs(250)); + targets = uncompressed_bench, compressed_bench +} +criterion_main!(benches); + diff --git a/rln/benches/circuit_loading_benchmark.rs b/rln/benches/circuit_loading_benchmark.rs index 5ef2077..b7b8a7d 100644 --- a/rln/benches/circuit_loading_benchmark.rs +++ b/rln/benches/circuit_loading_benchmark.rs @@ -1,14 +1,17 @@ +use ark_circom::read_zkey; use criterion::{criterion_group, criterion_main, Criterion}; -use rln::circuit::{zkey_from_raw, ZKEY_BYTES}; +use std::io::Cursor; -// 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) { - let zkey = ZKEY_BYTES.to_vec(); +pub fn zkey_load_benchmark(c: &mut Criterion) { + let zkey = rln::circuit::ZKEY_BYTES.to_vec(); + let size = zkey.len() as f32; + println!("Size of zkey: {:.2?} MB", size / 1024.0 / 1024.0); c.bench_function("zkey::zkey_from_raw", |b| { b.iter(|| { - let _ = zkey_from_raw(&zkey); + let mut reader = Cursor::new(zkey.clone()); + let r = read_zkey(&mut reader); + assert_eq!(r.is_ok(), true); }) }); } @@ -16,6 +19,6 @@ pub fn key_load_benchmark(c: &mut Criterion) { criterion_group! { name = benches; config = Criterion::default().measurement_time(std::time::Duration::from_secs(250)); - targets = key_load_benchmark + targets = zkey_load_benchmark } criterion_main!(benches); diff --git a/rln/resources/tree_height_20/rln_final_uncompr.arkzkey b/rln/resources/tree_height_20/rln_final_uncompr.arkzkey new file mode 100644 index 0000000..f5454f6 Binary files /dev/null and b/rln/resources/tree_height_20/rln_final_uncompr.arkzkey differ diff --git a/rln/src/circuit.rs b/rln/src/circuit.rs index 2cb7920..62702e6 100644 --- a/rln/src/circuit.rs +++ b/rln/src/circuit.rs @@ -19,13 +19,18 @@ use { }; #[cfg(feature = "arkzkey")] -use ark_zkey::read_arkzkey_from_bytes; +use { + ark_zkey::{read_arkzkey_from_bytes, SerializableConstraintMatrices, SerializableProvingKey}, + color_eyre::eyre::WrapErr, +}; #[cfg(not(feature = "arkzkey"))] use {ark_circom::read_zkey, std::io::Cursor}; #[cfg(feature = "arkzkey")] -const ARKZKEY_BYTES: &[u8] = include_bytes!("../resources/tree_height_20/rln_final.arkzkey"); +pub const ARKZKEY_BYTES: &[u8] = include_bytes!("../resources/tree_height_20/rln_final.arkzkey"); +#[cfg(feature = "arkzkey")] +pub const ARKZKEY_BYTES_UNCOMPR: &[u8] = include_bytes!("../resources/tree_height_20/rln_final_uncompr.arkzkey"); pub const ZKEY_BYTES: &[u8] = include_bytes!("../resources/tree_height_20/rln_final.zkey"); pub const VK_BYTES: &[u8] = include_bytes!("../resources/tree_height_20/verification_key.arkvkey"); @@ -143,3 +148,76 @@ pub fn check_vk_from_zkey(verifying_key: VerifyingKey) -> Result<()> { Err(Report::msg("verifying_keys are not equal")) } } + + +//////////////////////////////////////////////////////// +// Function from [arkzkey](https://github.com/zkmopro/ark-zkey/blob/main/src/lib.rs#L106) for benchmark +// without print and using compressed and uncompressed data +//////////////////////////////////////////////////////// +#[cfg(feature = "arkzkey")] +pub fn arkzkey_from_raw_uncompressed(arkzkey_data: &[u8], +) -> Result<(ProvingKey, ConstraintMatrices)> { + if arkzkey_data.is_empty() { + return Err(Report::msg("No proving key found!")); + } + + let mut cursor = std::io::Cursor::new(arkzkey_data); + + let serialized_proving_key = + SerializableProvingKey::deserialize_uncompressed_unchecked(&mut cursor) + .wrap_err("Failed to deserialize proving key")?; + + let serialized_constraint_matrices = + SerializableConstraintMatrices::deserialize_uncompressed_unchecked(&mut cursor) + .wrap_err("Failed to deserialize constraint matrices")?; + + // Get on right form for API + let proving_key: ProvingKey = serialized_proving_key.0; + let constraint_matrices: ConstraintMatrices = ConstraintMatrices { + num_instance_variables: serialized_constraint_matrices.num_instance_variables, + num_witness_variables: serialized_constraint_matrices.num_witness_variables, + num_constraints: serialized_constraint_matrices.num_constraints, + a_num_non_zero: serialized_constraint_matrices.a_num_non_zero, + b_num_non_zero: serialized_constraint_matrices.b_num_non_zero, + c_num_non_zero: serialized_constraint_matrices.c_num_non_zero, + a: serialized_constraint_matrices.a.data, + b: serialized_constraint_matrices.b.data, + c: serialized_constraint_matrices.c.data, + }; + + Ok((proving_key, constraint_matrices)) +} + +#[cfg(feature = "arkzkey")] +pub fn arkzkey_from_raw_compressed(arkzkey_data: &[u8], +) -> Result<(ProvingKey, ConstraintMatrices)> { + if arkzkey_data.is_empty() { + return Err(Report::msg("No proving key found!")); + } + + let mut cursor = std::io::Cursor::new(arkzkey_data); + + let serialized_proving_key = + SerializableProvingKey::deserialize_compressed_unchecked(&mut cursor) + .wrap_err("Failed to deserialize proving key")?; + + let serialized_constraint_matrices = + SerializableConstraintMatrices::deserialize_compressed_unchecked(&mut cursor) + .wrap_err("Failed to deserialize constraint matrices")?; + + // Get on right form for API + let proving_key: ProvingKey = serialized_proving_key.0; + let constraint_matrices: ConstraintMatrices = ConstraintMatrices { + num_instance_variables: serialized_constraint_matrices.num_instance_variables, + num_witness_variables: serialized_constraint_matrices.num_witness_variables, + num_constraints: serialized_constraint_matrices.num_constraints, + a_num_non_zero: serialized_constraint_matrices.a_num_non_zero, + b_num_non_zero: serialized_constraint_matrices.b_num_non_zero, + c_num_non_zero: serialized_constraint_matrices.c_num_non_zero, + a: serialized_constraint_matrices.a.data, + b: serialized_constraint_matrices.b.data, + c: serialized_constraint_matrices.c.data, + }; + + Ok((proving_key, constraint_matrices)) +}