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

Benchmark ark-works for circom with wasm-bindgen #290

Open
vivianjeng opened this issue Jan 8, 2025 · 3 comments
Open

Benchmark ark-works for circom with wasm-bindgen #290

vivianjeng opened this issue Jan 8, 2025 · 3 comments
Assignees

Comments

@vivianjeng
Copy link
Collaborator

Problem

We have explored this before: #202 (comment)
But looking carefully into the waku implementation, it doesn't enable rayon in their wasm-bindgen
(and the ark-groth16 has the feature parallel to enable rayon)
with current mopro implementation, we support wasm-bindgen-rayon
so we can try to benchmark circom groth16 prover for circuits

The result with parallel and without

keccak256 (debug mode) with parallel without parallel
time 10.98826125s 27.5738135s

Details

Try to use mopro build for web (by default it supports rayon)
and record the time it executes when generating a groth16 proof
(NOTE: without witness generation time, I think it is not possible to generate wasm bindings with current rust witness generator)
You can also refer to waku implementation: https://github.com/vacp2p/zerokit/blob/master/rln-wasm/src/lib.rs

Or you can load the wtns, zkey as bytes before generate the function
e.g.

const WTNS_BYTES: &[u8] = include_bytes!("./keccak256.wtns");
const ZKEY_BYTES: &[u8] = include_bytes!("./keccak256.zkey");

#[wasm_bindgen]
pub fn arkworks_prover() -> Result<JsValue, JsValue> {
    prove(...)
}

Acceptance criteria

Benchmark the execution time for the following circuits in the browser

ark-works with rayon snarkjs
sha256 - ms - ms
keccak256 - ms - ms
RSA - ms - ms
semaphore-32 - ms - ms
Anon Aadhaar - ms - ms

Please check the circuit input, wasm, zkey here
https://github.com/zkmopro/android-benchmark-app/tree/main/ios/MoproApp

Next steps (optional)

Update documentation for https://zkmopro.org/docs/performance/

@sifnoc sifnoc self-assigned this Jan 8, 2025
@sifnoc
Copy link
Collaborator

sifnoc commented Jan 15, 2025

Successfully compiled ark-groth16 with wasm-pack in here: https://github.com/sifnoc/ark-groth16-wasm
However, I encountered a compilation error when attempting to use rust-witness in mopro-ffi. To proceed, I plan to use a pre-generated witness and zkey.

Could you provide guidance on obtaining the wtns file mentioned in this issue? Should I explore rust_witness for generating it, or is there another recommended approach?

@vivianjeng
Copy link
Collaborator Author

I think you can save the witness output to a file
and read the witness from the file (in wasm environment)
similar to the usage of srs in halo2 circuit
e.g. (from chatGPT)

use num_bigint::BigUint;
use std::fs::File;
use std::io::{self, Read, Write};

fn save_biguint_vec_to_file(vec: &[BigUint], file_path: &str) -> io::Result<()> {
    let mut file = File::create(file_path)?;
    for biguint in vec {
        let bytes = biguint.to_bytes_be();
        let length = bytes.len() as u64;
        // Write the length of the bytes
        file.write_all(&length.to_be_bytes())?;
        // Write the actual bytes
        file.write_all(&bytes)?;
    }
    Ok(())
}

fn load_biguint_vec_from_file(file_path: &str) -> io::Result<Vec<BigUint>> {
    let mut file = File::open(file_path)?;
    let mut buf = Vec::new();
    file.read_to_end(&mut buf)?;

    let mut biguint_vec = Vec::new();
    let mut cursor = 0;

    while cursor < buf.len() {
        // Read the length of the bytes (u64 is 8 bytes)
        let mut length_bytes = [0u8; 8];
        length_bytes.copy_from_slice(&buf[cursor..cursor + 8]);
        cursor += 8;
        let length = u64::from_be_bytes(length_bytes) as usize;

        // Read the actual bytes
        let bytes = &buf[cursor..cursor + length];
        cursor += length;

        // Convert bytes back to BigUint
        biguint_vec.push(BigUint::from_bytes_be(bytes));
    }

    Ok(biguint_vec)
}

and wtns is a file generated from snarkjs (you don't need to use it. Just an example)
https://github.com/iden3/snarkjs?tab=readme-ov-file#14-calculate-the-witness
To generate a wtns is by executing

snarkjs wtns calculate circuit_js/circuit.wasm input.json witness.wtns

The disadvantage of the wtns file is that the type might be different from the inputs in ark-works

@KimiWu123 KimiWu123 moved this to Current Milestone in Mopro Kanban Jan 17, 2025
@vivianjeng vivianjeng moved this from Current Milestone to In progress in Mopro Kanban Jan 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In progress
Development

No branches or pull requests

2 participants