Skip to content

Commit

Permalink
Some Type simplifications (#297)
Browse files Browse the repository at this point in the history
* refactor: Reorder generic parameters across all SNARK methods and structs

TL;DR: This is deinterleaving, i.e. E1, E2, C1, C2 .. becomes E1, C1, .. E2, C2, ...

- Reorganized order of generic parameters across various rust function calls and implementations, affecting structures such as `PublicParams`, `RecursiveSNARK`, and `CompressedSNARK`, among others.
- Updated all relevant unit tests to align with the new ordering of parameters.

* feat: Implement CurveCycleEquipped for various engines

- Introduced a new convenience trait to pair engines with fields in a curve cycle relationship, extending mod.rs traits.
- Added CurveCycleEquipped to the provider mod.rs traits list.
- Implemented CurveCycleEquipped to Bn256Engine, Bn256EngineKZG, Bn256EngineZM, Secp256k1Engine, and PallasEngine, setting respective secondary types accordingly.
- Expanded functionality for multiple engine systems with the addition of a secondary engine of 'Self'.

* refactor: Refactor SNARK parameters and update related functions

- Refactored the bench, examples, and source files to simplify `PublicParams`, `CompressedSNARK`, and `RecursiveSNARK` setup by removing the redundant secondary engine type and circuit parameters.
- Modified all functions, methods, and type definitions that depend on the `PublicParams`, `CompressedSNARK`, and `RecursiveSNARK` setup to reflect these changes.
- Removed all (default) instances of `TrivialCircuit` parameters from the codebase, simplifying the setup process.
- Renamed `SecEngine` to `SecEng`,
- Adjustments were made to functions to reflect the updated parameters without changing the functionality or behavior of the code.

* chore: remove type boilerplate

* refactor: Refactor supernova for single engine parameters and simplified testing

TL;DR : use CurveCycle and remove Phantom parameters

- Altered and simplified generic parameter restrictions for `NonUniformBench` and `NonUniformCircuit`.
- Refactored import statements in `benches/common/supernova/mod.rs` for a cleaner and simplified codebase.
- Refactored the use of `TrivialTestCircuit` from the `benches/common/supernova/bench.rs` file.
- Revised the `RecursiveSNARK` type in `bench.rs`,
- Refactored and simplified function signatures in `test.rs`,
- Made significant changes to the `TestROM` structure and adjusted related function implementations within `src/supernova/test.rs`.
- Overall, improved the use of generics.

* refactor: Refactor engine parameterization in circuit tests

- Simplified engine parameterization by replacing dual `E1` and `E2` variables with a single `E1` in relevant function definitions.
- Enhanced code readability by changing type constraints to `CurveCycleEquipped` and implementing the `SecEng` projection across multiple function modules.
- Updated calls and variable assignments to align with the new engine parameterization.
- Retained original functionalities of the affected functions even with the considerable code modifications and simplifications.

* chore: rename SecEng -> Dual

* docs: Improve code readability and testing robustness

- Improved readability of CurveCycleEquipped function comment in traits module by adding backticks around function name.
  • Loading branch information
huitseeker authored Feb 5, 2024
1 parent d2479f2 commit 788e878
Show file tree
Hide file tree
Showing 16 changed files with 651 additions and 917 deletions.
16 changes: 7 additions & 9 deletions benches/common/supernova/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::common::{noise_threshold_env, BenchParams};
use arecibo::{
provider::{PallasEngine, VestaEngine},
supernova::NonUniformCircuit,
supernova::TrivialTestCircuit,
supernova::{snark::CompressedSNARK, PublicParams, RecursiveSNARK},
traits::{
snark::RelaxedR1CSSNARKTrait,
Expand All @@ -33,10 +32,9 @@ pub fn bench_snark_internal_with_arity<
num_cons: usize,
snark_type: SnarkType,
) {
let bench: NonUniformBench<E1, E2, TrivialTestCircuit<<E2 as Engine>::Scalar>> = match snark_type
{
SnarkType::Recursive => NonUniformBench::new(2, num_cons),
SnarkType::Compressed => NonUniformBench::new(num_augmented_circuits, num_cons),
let bench: NonUniformBench<E1> = match snark_type {
SnarkType::Recursive => NonUniformBench::<E1>::new(2, num_cons),
SnarkType::Compressed => NonUniformBench::<E1>::new(num_augmented_circuits, num_cons),
};
let pp = match snark_type {
SnarkType::Recursive => PublicParams::setup(&bench, &*default_ck_hint(), &*default_ck_hint()),
Expand All @@ -50,7 +48,7 @@ pub fn bench_snark_internal_with_arity<
};
let z0_primary = vec![<E1 as Engine>::Scalar::from(2u64)];
let z0_secondary = vec![<E2 as Engine>::Scalar::from(2u64)];
let mut recursive_snark_option: Option<RecursiveSNARK<E1, E2>> = None;
let mut recursive_snark_option: Option<RecursiveSNARK<E1>> = None;
let mut selected_augmented_circuit = 0;

for _ in 0..num_warmup_steps {
Expand Down Expand Up @@ -97,11 +95,11 @@ pub fn bench_snark_internal_with_arity<

match snark_type {
SnarkType::Compressed => {
let (prover_key, verifier_key) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp).unwrap();
let (prover_key, verifier_key) = CompressedSNARK::<_, S1, S2>::setup(&pp).unwrap();
// Benchmark the prove time
group.bench_function(bench_params.bench_id("Prove"), |b| {
b.iter(|| {
assert!(CompressedSNARK::<_, _, _, _, S1, S2>::prove(
assert!(CompressedSNARK::<_, S1, S2>::prove(
black_box(&pp),
black_box(&prover_key),
black_box(&recursive_snark)
Expand All @@ -110,7 +108,7 @@ pub fn bench_snark_internal_with_arity<
})
});

let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &prover_key, &recursive_snark);
let res = CompressedSNARK::<_, S1, S2>::prove(&pp, &prover_key, &recursive_snark);
assert!(res.is_ok());
let compressed_snark = res.unwrap();
// Benchmark the verification time
Expand Down
36 changes: 15 additions & 21 deletions benches/common/supernova/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ pub mod targets;

use anyhow::anyhow;
use arecibo::{
supernova::NonUniformCircuit,
supernova::{StepCircuit, TrivialTestCircuit},
traits::Engine,
supernova::{NonUniformCircuit, StepCircuit, TrivialTestCircuit},
traits::{CurveCycleEquipped, Dual, Engine},
};
use bellpepper_core::{num::AllocatedNum, ConstraintSystem, SynthesisError};
use core::marker::PhantomData;
Expand Down Expand Up @@ -68,45 +67,40 @@ fn num_cons_env() -> anyhow::Result<Vec<usize>> {
})
}

pub struct NonUniformBench<E1, E2, S>
pub struct NonUniformBench<E1>
where
E1: Engine<Base = <E2 as Engine>::Scalar>,
E2: Engine<Base = <E1 as Engine>::Scalar>,
S: StepCircuit<E2::Scalar> + Default,
E1: CurveCycleEquipped,
{
num_circuits: usize,
num_cons: usize,
_p: PhantomData<(E1, E2, S)>,
_p: PhantomData<E1>,
}

impl<E1, E2, S> NonUniformBench<E1, E2, S>
impl<E1> NonUniformBench<E1>
where
E1: Engine<Base = <E2 as Engine>::Scalar>,
E2: Engine<Base = <E1 as Engine>::Scalar>,
S: StepCircuit<E2::Scalar> + Default,
E1: CurveCycleEquipped,
{
fn new(num_circuits: usize, num_cons: usize) -> Self {
Self {
num_circuits,
num_cons,
_p: Default::default(),
_p: PhantomData,
}
}
}

impl<E1, E2, S>
NonUniformCircuit<E1, E2, NonTrivialTestCircuit<E1::Scalar>, TrivialTestCircuit<E2::Scalar>>
for NonUniformBench<E1, E2, S>
impl<E1> NonUniformCircuit<E1> for NonUniformBench<E1>
where
E1: Engine<Base = <E2 as Engine>::Scalar>,
E2: Engine<Base = <E1 as Engine>::Scalar>,
S: StepCircuit<E2::Scalar> + Default,
E1: CurveCycleEquipped,
{
type C1 = NonTrivialTestCircuit<E1::Scalar>;
type C2 = TrivialTestCircuit<<Dual<E1> as Engine>::Scalar>;

fn num_circuits(&self) -> usize {
self.num_circuits
}

fn primary_circuit(&self, circuit_index: usize) -> NonTrivialTestCircuit<E1::Scalar> {
fn primary_circuit(&self, circuit_index: usize) -> Self::C1 {
assert!(
circuit_index < self.num_circuits,
"Circuit index out of bounds: asked for {circuit_index}, but there are only {} circuits.",
Expand All @@ -116,7 +110,7 @@ where
NonTrivialTestCircuit::new(self.num_cons)
}

fn secondary_circuit(&self) -> TrivialTestCircuit<E2::Scalar> {
fn secondary_circuit(&self) -> Self::C2 {
Default::default()
}
}
Expand Down
17 changes: 5 additions & 12 deletions benches/compressed-snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ type S2 = arecibo::spartan::snark::RelaxedR1CSSNARK<E2, EE2>;
// SNARKs with computation commitmnets
type SS1 = arecibo::spartan::ppsnark::RelaxedR1CSSNARK<E1, EE1>;
type SS2 = arecibo::spartan::ppsnark::RelaxedR1CSSNARK<E2, EE2>;
type C1 = NonTrivialCircuit<<E1 as Engine>::Scalar>;
type C2 = TrivialCircuit<<E2 as Engine>::Scalar>;

// To run these benchmarks, first download `criterion` with `cargo install cargo-criterion`.
// Then `cargo criterion --bench compressed-snark`. The results are located in `target/criterion/data/<name-of-benchmark>`.
Expand Down Expand Up @@ -69,19 +67,14 @@ fn bench_compressed_snark_internal<S1: RelaxedR1CSSNARKTrait<E1>, S2: RelaxedR1C
let c_secondary = TrivialCircuit::default();

// Produce public parameters
let pp = PublicParams::<E1, E2, C1, C2>::setup(
&c_primary,
&c_secondary,
&*S1::ck_floor(),
&*S2::ck_floor(),
);
let pp = PublicParams::<E1>::setup(&c_primary, &c_secondary, &*S1::ck_floor(), &*S2::ck_floor());

// Produce prover and verifier keys for CompressedSNARK
let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp).unwrap();
let (pk, vk) = CompressedSNARK::<_, S1, S2>::setup(&pp).unwrap();

// produce a recursive SNARK
let num_steps = 3;
let mut recursive_snark: RecursiveSNARK<E1, E2, C1, C2> = RecursiveSNARK::new(
let mut recursive_snark: RecursiveSNARK<E1> = RecursiveSNARK::new(
&pp,
&c_primary,
&c_secondary,
Expand Down Expand Up @@ -113,15 +106,15 @@ fn bench_compressed_snark_internal<S1: RelaxedR1CSSNARKTrait<E1>, S2: RelaxedR1C
// Bench time to produce a compressed SNARK
group.bench_function(bench_params.bench_id("Prove"), |b| {
b.iter(|| {
assert!(CompressedSNARK::<_, _, _, _, S1, S2>::prove(
assert!(CompressedSNARK::<_, S1, S2>::prove(
black_box(&pp),
black_box(&pk),
black_box(&recursive_snark)
)
.is_ok());
})
});
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
let res = CompressedSNARK::<_, S1, S2>::prove(&pp, &pk, &recursive_snark);
assert!(res.is_ok());
let compressed_snark = res.unwrap();

Expand Down
2 changes: 1 addition & 1 deletion benches/compute-digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ criterion_main!(compute_digest);
fn bench_compute_digest(c: &mut Criterion) {
c.bench_function("compute_digest", |b| {
b.iter(|| {
PublicParams::<E1, E2, C1, C2>::setup(
PublicParams::<E1>::setup(
black_box(&C1::new(10)),
black_box(&C2::default()),
black_box(&*default_ck_hint()),
Expand Down
6 changes: 2 additions & 4 deletions benches/recursive-snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ use common::{noise_threshold_env, BenchParams};

type E1 = PallasEngine;
type E2 = VestaEngine;
type C1 = NonTrivialCircuit<<E1 as Engine>::Scalar>;
type C2 = TrivialCircuit<<E2 as Engine>::Scalar>;

// To run these benchmarks, first download `criterion` with `cargo install cargo-criterion`.
// Then `cargo criterion --bench recursive-snark`. The results are located in `target/criterion/data/<name-of-benchmark>`.
Expand Down Expand Up @@ -73,7 +71,7 @@ fn bench_recursive_snark(c: &mut Criterion) {
let c_secondary = TrivialCircuit::default();

// Produce public parameters
let pp = PublicParams::<E1, E2, C1, C2>::setup(
let pp = PublicParams::<E1>::setup(
&c_primary,
&c_secondary,
&*default_ck_hint(),
Expand All @@ -85,7 +83,7 @@ fn bench_recursive_snark(c: &mut Criterion) {
// the first step is cheaper than other steps owing to the presence of
// a lot of zeros in the satisfying assignment
let num_warmup_steps = 10;
let mut recursive_snark: RecursiveSNARK<E1, E2, C1, C2> = RecursiveSNARK::new(
let mut recursive_snark: RecursiveSNARK<E1> = RecursiveSNARK::new(
&pp,
&c_primary,
&c_secondary,
Expand Down
5 changes: 1 addition & 4 deletions benches/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,6 @@ impl<Scalar: PrimeField + PrimeFieldBits> StepCircuit<Scalar> for Sha256Circuit<
}
}

type C1 = Sha256Circuit<<E1 as Engine>::Scalar>;
type C2 = TrivialCircuit<<E2 as Engine>::Scalar>;

criterion_group! {
name = recursive_snark;
config = Criterion::default().warm_up_time(Duration::from_millis(3000));
Expand Down Expand Up @@ -158,7 +155,7 @@ fn bench_recursive_snark(c: &mut Criterion) {

// Produce public parameters
let ttc = TrivialCircuit::default();
let pp = PublicParams::<E1, E2, C1, C2>::setup(
let pp = PublicParams::<E1>::setup(
&circuit_primary,
&ttc,
&*default_ck_hint(),
Expand Down
40 changes: 17 additions & 23 deletions examples/and.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,14 @@ fn main() {
println!("Nova-based 64-bit bitwise AND example");
println!("=========================================================");

type C1 = AndCircuit<<E1 as Engine>::GE>;
type C2 = TrivialCircuit<<E2 as Engine>::Scalar>;

let num_steps = 32;
for num_ops_per_step in [1024, 2048, 4096, 8192, 16384, 32768, 65536] {
// number of instances of AND per Nova's recursive step
let circuit_primary = AndCircuit::new(num_ops_per_step);
let circuit_secondary = TrivialCircuit::default();
let circuit_primary = C1::new(num_ops_per_step);
let circuit_secondary = C2::default();

println!(
"Proving {} AND ops ({num_ops_per_step} instances per step and {num_steps} steps)",
Expand All @@ -222,12 +225,7 @@ fn main() {
// produce public parameters
let start = Instant::now();
println!("Producing public parameters...");
let pp = PublicParams::<
E1,
E2,
AndCircuit<<E1 as Engine>::GE>,
TrivialCircuit<<E2 as Engine>::Scalar>,
>::setup(
let pp = PublicParams::<E1>::setup(
&circuit_primary,
&circuit_secondary,
&*S1::ck_floor(),
Expand Down Expand Up @@ -255,23 +253,19 @@ fn main() {

// produce non-deterministic advice
let circuits = (0..num_steps)
.map(|_| AndCircuit::new(num_ops_per_step))
.map(|_| C1::new(num_ops_per_step))
.collect::<Vec<_>>();

type C1 = AndCircuit<<E1 as Engine>::GE>;
type C2 = TrivialCircuit<<E2 as Engine>::Scalar>;

// produce a recursive SNARK
println!("Generating a RecursiveSNARK...");
let mut recursive_snark: RecursiveSNARK<E1, E2, C1, C2> =
RecursiveSNARK::<E1, E2, C1, C2>::new(
&pp,
&circuits[0],
&circuit_secondary,
&[<E1 as Engine>::Scalar::zero()],
&[<E2 as Engine>::Scalar::zero()],
)
.unwrap();
let mut recursive_snark: RecursiveSNARK<E1> = RecursiveSNARK::<E1>::new(
&pp,
&circuits[0],
&circuit_secondary,
&[<E1 as Engine>::Scalar::zero()],
&[<E2 as Engine>::Scalar::zero()],
)
.unwrap();

let start = Instant::now();
for circuit_primary in circuits.iter() {
Expand All @@ -297,11 +291,11 @@ fn main() {

// produce a compressed SNARK
println!("Generating a CompressedSNARK using Spartan with multilinear KZG...");
let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp).unwrap();
let (pk, vk) = CompressedSNARK::<_, S1, S2>::setup(&pp).unwrap();

let start = Instant::now();

let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
let res = CompressedSNARK::<_, S1, S2>::prove(&pp, &pk, &recursive_snark);
println!(
"CompressedSNARK::prove: {:?}, took {:?}",
res.is_ok(),
Expand Down
Loading

1 comment on commit 788e878

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Table of Contents

Overview

This benchmark report shows the Arecibo GPU benchmarks.
NVIDIA L4
Intel(R) Xeon(R) CPU @ 2.20GHz
32 vCPUs
125 GB RAM
Workflow run: https://github.com/lurk-lab/arecibo/actions/runs/7790392895

Benchmark Results

RecursiveSNARK-NIVC-2

ref=d2479f2 ref=788e878
Prove-NumCons-6540 52.95 ms (✅ 1.00x) 53.42 ms (✅ 1.01x slower)
Verify-NumCons-6540 32.93 ms (✅ 1.00x) 33.32 ms (✅ 1.01x slower)
Prove-NumCons-1028888 342.75 ms (✅ 1.00x) 347.36 ms (✅ 1.01x slower)
Verify-NumCons-1028888 256.39 ms (✅ 1.00x) 259.05 ms (✅ 1.01x slower)

CompressedSNARK-NIVC-Commitments-2

ref=d2479f2 ref=788e878
Prove-NumCons-6540 14.08 s (✅ 1.00x) 14.14 s (✅ 1.00x slower)
Verify-NumCons-6540 77.91 ms (✅ 1.00x) 79.16 ms (✅ 1.02x slower)
Prove-NumCons-1028888 110.65 s (✅ 1.00x) 110.67 s (✅ 1.00x slower)
Verify-NumCons-1028888 774.38 ms (✅ 1.00x) 772.48 ms (✅ 1.00x faster)

Made with criterion-table

Please sign in to comment.