Skip to content

Commit

Permalink
Some Type simplifications (lurk-lang#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

0 comments on commit 788e878

Please sign in to comment.