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

perf: optimize Pedersen and IPA commitments gadgets #201

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ jobs:
curl -sSfL https://github.com/ethereum/solidity/releases/download/v0.8.4/solc-static-linux -o /usr/local/bin/solc
chmod +x /usr/local/bin/solc
- name: Execute compile.sh to generate .r1cs and .wasm from .circom
run: ./frontends/src/circom/test_folder/compile.sh
run: ./experimental-frontends/src/circom/test_folder/compile.sh
- name: Execute compile.sh to generate .json from noir
run: ./frontends/src/noir/test_folder/compile.sh
run: ./experimental-frontends/src/noir/test_folder/compile.sh
- name: Run tests
uses: actions-rs/cargo@v1
with:
Expand Down Expand Up @@ -95,11 +95,11 @@ jobs:
default: true
- name: Add target
run: rustup target add ${{ matrix.target }}
- name: Wasm-compat frontends build
- name: Wasm-compat experimental-frontends build
uses: actions-rs/cargo@v1
with:
command: build
args: -p frontends --no-default-features --target ${{ matrix.target }} --features "wasm, parallel"
args: -p experimental-frontends --no-default-features --target ${{ matrix.target }} --features "wasm, parallel"
- name: Wasm-compat folding-schemes build
uses: actions-rs/cargo@v1
with:
Expand Down Expand Up @@ -132,14 +132,30 @@ jobs:
curl -sSfL https://github.com/ethereum/solidity/releases/download/v0.8.4/solc-static-linux -o /usr/local/bin/solc
chmod +x /usr/local/bin/solc
- name: Execute compile.sh to generate .r1cs and .wasm from .circom
run: ./frontends/src/circom/test_folder/compile.sh
run: ./experimental-frontends/src/circom/test_folder/compile.sh
- name: Execute compile.sh to generate .json from noir
run: ./frontends/src/noir/test_folder/compile.sh
run: ./experimental-frontends/src/noir/test_folder/compile.sh
- name: Run examples tests
run: cargo test --examples
- name: Run examples
run: cargo run --release --example 2>&1 | grep -E '^ ' | xargs -n1 cargo run --release --example

# run the benchmarks with the flag `--no-run` to ensure that they compile,
# but without executing them.
bench:
if: github.event.pull_request.draft == false
name: Bench compile
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- uses: Swatinem/rust-cache@v2
- uses: actions-rs/cargo@v1
with:
command: bench
args: -p folding-schemes --no-run

fmt:
if: github.event.pull_request.draft == false
name: Rustfmt
Expand All @@ -164,10 +180,10 @@ jobs:
feature_set: [basic, wasm]
include:
- feature_set: basic
features: --features default,light-test
# We only want to test `frontends` package with `wasm` feature.
features: --features default
# We only want to test `experimental-frontends` package with `wasm` feature.
- feature_set: wasm
features: -p frontends --features wasm,parallel --target wasm32-unknown-unknown
features: -p experimental-frontends --features wasm,parallel --target wasm32-unknown-unknown
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
Cargo.lock

# Circom generated files
frontends/src/circom/test_folder/*_js/
experimental-frontends/src/circom/test_folder/*_js/
*.r1cs
*.sym

# Noir generated files
frontends/src/noir/test_folder/*/target/*
experimental-frontends/src/noir/test_folder/*/target/*

# generated contracts data
solidity-verifiers/generated
Expand Down
16 changes: 2 additions & 14 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,9 @@ members = [
"folding-schemes",
"solidity-verifiers",
"cli",
"frontends"
"experimental-frontends"
]
resolver = "2"

[patch.crates-io]
# The following patch is to use a version of ark-r1cs-std compatible with
# v0.4.0 but that includes two cherry-picked commits from after v0.4.0 which
# fixes the in-circuit scalar multiplication of the zero point and the
# y-coordinate of the zero point. The commits are respectively from
# https://github.com/arkworks-rs/r1cs-std/pull/124 and
# https://github.com/arkworks-rs/r1cs-std/pull/126, without including other
# changes done between v0.4.0 and this fix which would break compatibility.
ark-r1cs-std = { path = "../r1cs-std-tmpfix" }
# patch ark_curves to use a cherry-picked version which contains
# bn254::constraints & grumpkin for v0.4.0 (once arkworks v0.5.0 is released
# this will no longer be needed)
ark-bn254 = { git = "https://github.com/arnaucube/ark-curves-cherry-picked", branch="cherry-pick"}
ark-grumpkin = { git = "https://github.com/arnaucube/ark-curves-cherry-picked", branch="cherry-pick"}
ark-r1cs-std = {git = "https://github.com/yelhousni/r1cs-std", branch="perf/sw"}
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ Folding schemes implemented:
- [Nova: Recursive Zero-Knowledge Arguments from Folding Schemes](https://eprint.iacr.org/2021/370.pdf), Abhiram Kothapalli, Srinath Setty, Ioanna Tzialla. 2021
- [CycleFold: Folding-scheme-based recursive arguments over a cycle of elliptic curves](https://eprint.iacr.org/2023/1192.pdf), Abhiram Kothapalli, Srinath Setty. 2023
- [HyperNova: Recursive arguments for customizable constraint systems](https://eprint.iacr.org/2023/573.pdf), Abhiram Kothapalli, Srinath Setty. 2023

Work in progress:

- [ProtoGalaxy: Efficient ProtoStar-style folding of multiple instances](https://eprint.iacr.org/2023/1106.pdf), Liam Eagen, Ariel Gabizon. 2023


Expand All @@ -34,7 +31,7 @@ Work in progress:
Frontends allow to define the circuit to be folded (ie. `FCircuit`).
The recommended frontend is directly implementing the [`FCircuit` trait](https://github.com/privacy-scaling-explorations/sonobe/blob/main/folding-schemes/src/frontend/mod.rs#L16) with the Arkworks constraint system.

Alternatively, experimental frontends for [Circom](https://github.com/iden3/circom), [Noir](https://github.com/noir-lang/noir) and [Noname](https://github.com/zksecurity/noname) can be found at the [sonobe/frontends](https://github.com/privacy-scaling-explorations/sonobe/tree/main/frontends) directory, which have some computational (and time) overhead.
Alternatively, experimental frontends for [Circom](https://github.com/iden3/circom), [Noir](https://github.com/noir-lang/noir) and [Noname](https://github.com/zksecurity/noname) can be found at the [sonobe/experimental-frontends](https://github.com/privacy-scaling-explorations/sonobe/tree/main/experimental-frontends) directory, which have some computational (and time) overhead.

More details about the frontend interface and the experimental frontends can be found at the [sonobe-docs/frontend](https://privacy-scaling-explorations.github.io/sonobe-docs/usage/frontend.html) page.

Expand All @@ -49,7 +46,7 @@ folding-schemes = { git = "https://github.com/privacy-scaling-explorations/sonob
Available packages:
- `folding-schemes`: main crate, contains the different scheme implementations, together with commitment schemes, frontend trait, arithmetization, transcript, etc.
- `solidity-verifiers`: contains the templating logic to output the verifier contracts for the DeciderEth proofs. Currently only supports Nova+CycleFold DeciderEth proofs.
- `frontends`: contains the experimental frontends other than the arkworks frontend. More details at the [sonobe/frontends](https://github.com/privacy-scaling-explorations/sonobe/tree/main/frontends) directory.
- `experimental-frontends`: contains the experimental frontends other than the arkworks frontend. More details at the [sonobe/experimental-frontends](https://github.com/privacy-scaling-explorations/sonobe/tree/main/experimental-frontends) directory.

Available features:
- `parallel` enables some parallelization optimizations available in the crate. It is enabled by default.
Expand Down Expand Up @@ -105,7 +102,7 @@ Sonobe is [MIT Licensed](https://github.com/privacy-scaling-explorations/sonobe/

## Acknowledgments

This project builds on top of multiple [arkworks](https://github.com/arkworks-rs) libraries. It uses Espresso system's [virtual polynomial](https://github.com/EspressoSystems/hyperplonk/blob/main/arithmetic/src/virtual_polynomial.rs) abstraction and its [SumCheck](https://github.com/EspressoSystems/hyperplonk/tree/main/subroutines/src/poly_iop/sum_check) implementation.
This project builds on top of multiple [arkworks](https://github.com/arkworks-rs) libraries. It uses Espresso System's [virtual polynomial](https://github.com/EspressoSystems/hyperplonk/blob/main/arithmetic/src/virtual_polynomial.rs) abstraction and its [SumCheck](https://github.com/EspressoSystems/hyperplonk/tree/main/subroutines/src/poly_iop/sum_check) implementation.

The Solidity templates used in `nova_cyclefold_verifier.sol`, use [iden3](https://github.com/iden3/snarkjs/blob/master/templates/verifier_groth16.sol.ejs)'s Groth16 implementation and a KZG10 Solidity template adapted from [weijiekoh/libkzg](https://github.com/weijiekoh/libkzg).

Expand Down
10 changes: 10 additions & 0 deletions benches/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# benchmarks
*Note: we're starting to benchmark & profile Sonobe, current results are pre-optimizations.*

- Benchmark
- Run: `cargo bench`
- To run a specific benchmark, for example Nova's benchmark, run: `cargo bench --bench=nova`
- Profiling
- eg. `cargo bench --bench=nova -- --profile-time 3`


53 changes: 53 additions & 0 deletions benches/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use criterion::*;

use folding_schemes::{
frontend::{utils::CustomFCircuit, FCircuit},
Curve, Error, FoldingScheme,
};

pub(crate) fn bench_ivc_opt<
C1: Curve<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
C2: Curve,
FS: FoldingScheme<C1, C2, CustomFCircuit<C1::ScalarField>>,
>(
c: &mut Criterion,
name: String,
n: usize,
prep_param: FS::PreprocessorParam,
) -> Result<(), Error> {
let fcircuit_size = 1 << n; // 2^n

let f_circuit = CustomFCircuit::<C1::ScalarField>::new(fcircuit_size)?;

let mut rng = rand::rngs::OsRng;

// prepare the FS prover & verifier params
let fs_params = FS::preprocess(&mut rng, &prep_param)?;

let z_0 = vec![C1::ScalarField::from(3_u32)];
let mut fs = FS::init(&fs_params, f_circuit, z_0)?;

// warmup steps
for _ in 0..5 {
fs.prove_step(rng, (), None)?;
}

let mut group = c.benchmark_group(format!(
"{} - FCircuit: {} (2^{}) constraints",
name, fcircuit_size, n
));
group.significance_level(0.1).sample_size(10);
group.bench_function("prove_step", |b| {
b.iter(|| -> Result<_, _> { black_box(fs.clone()).prove_step(rng, (), None) })
});

// verify the IVCProof
let ivc_proof = fs.ivc_proof();
group.bench_function("verify", |b| {
b.iter(|| -> Result<_, _> {
FS::verify(black_box(fs_params.1.clone()), black_box(ivc_proof.clone()))
})
});
group.finish();
Ok(())
}
84 changes: 84 additions & 0 deletions benches/hypernova.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use criterion::*;
use pprof::criterion::{Output, PProfProfiler};

use ark_bn254::{Fr as bn_Fr, G1Projective as bn_G};
use ark_grumpkin::Projective as grumpkin_G;
use ark_pallas::{Fr as pallas_Fr, Projective as pallas_G};
use ark_vesta::Projective as vesta_G;

use folding_schemes::{
commitment::pedersen::Pedersen,
folding::{hypernova::HyperNova, nova::PreprocessorParam},
frontend::{utils::CustomFCircuit, FCircuit},
transcript::poseidon::poseidon_canonical_config,
};

mod common;
use common::bench_ivc_opt;

fn bench_hypernova_ivc(c: &mut Criterion) {
let poseidon_config = poseidon_canonical_config::<pallas_Fr>();

// iterate over the powers of n
for n in [0_usize, 14, 16, 18, 19, 20, 21, 22].iter() {
let fcircuit_size = 1 << n; // 2^n
let fcircuit = CustomFCircuit::<pallas_Fr>::new(fcircuit_size).unwrap();
let prep_param = PreprocessorParam::new(poseidon_config.clone(), fcircuit);

bench_ivc_opt::<
pallas_G,
vesta_G,
HyperNova<
pallas_G,
vesta_G,
CustomFCircuit<pallas_Fr>,
Pedersen<pallas_G>,
Pedersen<vesta_G>,
1,
1,
false,
>,
>(
c,
"HyperNova - Pallas-Vesta curves".to_string(),
*n,
prep_param,
)
.unwrap();
}

let poseidon_config = poseidon_canonical_config::<bn_Fr>();
for n in [0_usize, 14, 16, 18, 19, 20, 21, 22].iter() {
let fcircuit_size = 1 << n; // 2^n
let fcircuit = CustomFCircuit::<bn_Fr>::new(fcircuit_size).unwrap();
let prep_param = PreprocessorParam::new(poseidon_config.clone(), fcircuit);

bench_ivc_opt::<
bn_G,
grumpkin_G,
HyperNova<
bn_G,
grumpkin_G,
CustomFCircuit<bn_Fr>,
Pedersen<bn_G>,
Pedersen<grumpkin_G>,
1,
1,
false,
>,
>(
c,
"HyperNova - BN254-Grumpkin curves".to_string(),
*n,
prep_param,
)
.unwrap();
}
}

criterion_group! {
name = benches;
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
targets = bench_hypernova_ivc
}
criterion_main!(benches);
75 changes: 75 additions & 0 deletions benches/nova.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use criterion::*;
use pprof::criterion::{Output, PProfProfiler};

use ark_bn254::{Fr as bn_Fr, G1Projective as bn_G};
use ark_grumpkin::Projective as grumpkin_G;
use ark_pallas::{Fr as pallas_Fr, Projective as pallas_G};
use ark_vesta::Projective as vesta_G;

use folding_schemes::{
commitment::pedersen::Pedersen,
folding::nova::{Nova, PreprocessorParam},
frontend::{utils::CustomFCircuit, FCircuit},
transcript::poseidon::poseidon_canonical_config,
};

mod common;
use common::bench_ivc_opt;

fn bench_nova_ivc(c: &mut Criterion) {
let poseidon_config = poseidon_canonical_config::<pallas_Fr>();

// iterate over the powers of n
for n in [0_usize, 14, 16, 18, 19, 20, 21, 22].iter() {
let fcircuit_size = 1 << n; // 2^n
let fcircuit = CustomFCircuit::<pallas_Fr>::new(fcircuit_size).unwrap();
let prep_param = PreprocessorParam::new(poseidon_config.clone(), fcircuit);

bench_ivc_opt::<
pallas_G,
vesta_G,
Nova<
pallas_G,
vesta_G,
CustomFCircuit<pallas_Fr>,
Pedersen<pallas_G>,
Pedersen<vesta_G>,
false,
>,
>(c, "Nova - Pallas-Vesta curves".to_string(), *n, prep_param)
.unwrap();
}

let poseidon_config = poseidon_canonical_config::<bn_Fr>();
for n in [0_usize, 14, 16, 18, 19, 20, 21, 22].iter() {
let fcircuit_size = 1 << n; // 2^n
let fcircuit = CustomFCircuit::<bn_Fr>::new(fcircuit_size).unwrap();
let prep_param = PreprocessorParam::new(poseidon_config.clone(), fcircuit);

bench_ivc_opt::<
bn_G,
grumpkin_G,
Nova<
bn_G,
grumpkin_G,
CustomFCircuit<bn_Fr>,
Pedersen<bn_G>,
Pedersen<grumpkin_G>,
false,
>,
>(
c,
"Nova - BN254-Grumpkin curves".to_string(),
*n,
prep_param,
)
.unwrap();
}
}

criterion_group! {
name = benches;
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
targets = bench_nova_ivc
}
criterion_main!(benches);
Loading
Loading