Skip to content

Commit

Permalink
migrate tests to use ? instead of unwrap & `experimental-frontend…
Browse files Browse the repository at this point in the history
…s` renaming (#176)

* rename frontends to experimental-frontends to make it explicit, as discussed in the last meeting

* rename upper_bound_ccs to compute_concrete_ccs to describe better the method logic

* migrate tests to use result instead of unwrap

motivation: in this way tests are like in-library code and there is no
differenciation between test code and library code in terms of style,
where errors are returned with `?` instead of `unwrap`. Same for
examples. This was already done partially like this in some of the
ProtoGalaxy tests, now on almost all the folding-schemes tests.

* update CI to work with the new dir name

* apply PR review suggestions
  • Loading branch information
arnaucube authored Dec 5, 2024
1 parent fa8f821 commit 83d1383
Show file tree
Hide file tree
Showing 83 changed files with 1,303 additions and 1,358 deletions.
20 changes: 10 additions & 10 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,9 +132,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 examples tests
run: cargo test --examples
- name: Run examples
Expand All @@ -154,7 +154,7 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: bench
args: --no-run
args: -p folding-schemes --no-run

fmt:
if: github.event.pull_request.draft == false
Expand All @@ -180,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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ members = [
"folding-schemes",
"solidity-verifiers",
"cli",
"frontends"
"experimental-frontends"
]
resolver = "2"
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
6 changes: 4 additions & 2 deletions benches/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ where
));
group.significance_level(0.1).sample_size(10);
group.bench_function("prove_step", |b| {
b.iter(|| black_box(fs.clone()).prove_step(rng, vec![], None).unwrap())
b.iter(|| -> Result<_, _> { black_box(fs.clone()).prove_step(rng, vec![], None) })
});

// verify the IVCProof
let ivc_proof = fs.ivc_proof();
group.bench_function("verify", |b| {
b.iter(|| FS::verify(black_box(fs_params.1.clone()), black_box(ivc_proof.clone())).unwrap())
b.iter(|| -> Result<_, _> {
FS::verify(black_box(fs_params.1.clone()), black_box(ivc_proof.clone()))
})
});
group.finish();
Ok(())
Expand Down
40 changes: 18 additions & 22 deletions examples/circom_full_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2};
use std::path::PathBuf;
use std::time::Instant;

use experimental_frontends::circom::CircomFCircuit;
use folding_schemes::{
commitment::{kzg::KZG, pedersen::Pedersen},
folding::{
Expand All @@ -28,17 +29,16 @@ use folding_schemes::{
},
frontend::FCircuit,
transcript::poseidon::poseidon_canonical_config,
Decider, FoldingScheme,
Decider, Error, FoldingScheme,
};
use frontends::circom::CircomFCircuit;
use solidity_verifiers::{
evm::{compile_solidity, Evm},
utils::get_function_selector_for_nova_cyclefold_verifier,
verifiers::nova_cyclefold::get_decider_template_for_cyclefold_decider,
NovaCycleFoldVerifierKey,
};

fn main() {
fn main() -> Result<(), Error> {
// set the initial state
let z_0 = vec![Fr::from(3_u32)];

Expand All @@ -58,13 +58,14 @@ fn main() {
];

// initialize the Circom circuit
let r1cs_path = PathBuf::from("./frontends/src/circom/test_folder/with_external_inputs.r1cs");
let r1cs_path =
PathBuf::from("./experimental-frontends/src/circom/test_folder/with_external_inputs.r1cs");
let wasm_path = PathBuf::from(
"./frontends/src/circom/test_folder/with_external_inputs_js/with_external_inputs.wasm",
"./experimental-frontends/src/circom/test_folder/with_external_inputs_js/with_external_inputs.wasm",
);

let f_circuit_params = (r1cs_path.into(), wasm_path.into(), 1, 2);
let f_circuit = CircomFCircuit::<Fr>::new(f_circuit_params).unwrap();
let f_circuit = CircomFCircuit::<Fr>::new(f_circuit_params)?;

pub type N =
Nova<G1, GVar, G2, GVar2, CircomFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>, false>;
Expand All @@ -85,20 +86,18 @@ fn main() {

// prepare the Nova prover & verifier params
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, f_circuit.clone());
let nova_params = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
let nova_params = N::preprocess(&mut rng, &nova_preprocess_params)?;

// initialize the folding scheme engine, in our case we use Nova
let mut nova = N::init(&nova_params, f_circuit.clone(), z_0).unwrap();
let mut nova = N::init(&nova_params, f_circuit.clone(), z_0)?;

// prepare the Decider prover & verifier params
let (decider_pp, decider_vp) =
D::preprocess(&mut rng, nova_params.clone(), nova.clone()).unwrap();
let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params.clone(), nova.clone())?;

// run n steps of the folding iteration
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
let start = Instant::now();
nova.prove_step(rng, external_inputs_at_step.clone(), None)
.unwrap();
nova.prove_step(rng, external_inputs_at_step.clone(), None)?;
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
}

Expand All @@ -107,11 +106,10 @@ fn main() {
N::verify(
nova_params.1, // Nova's verifier params
ivc_proof,
)
.unwrap();
)?;

let start = Instant::now();
let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
let proof = D::prove(rng, decider_pp, nova.clone())?;
println!("generated Decider proof: {:?}", start.elapsed());

let verified = D::verify(
Expand All @@ -122,8 +120,7 @@ fn main() {
&nova.U_i.get_commitments(),
&nova.u_i.get_commitments(),
&proof,
)
.unwrap();
)?;
assert!(verified);
println!("Decider proof verification: {}", verified);

Expand All @@ -139,8 +136,7 @@ fn main() {
&nova.U_i,
&nova.u_i,
proof,
)
.unwrap();
)?;

// prepare the setup params for the solidity verifier
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((decider_vp, f_circuit.state_len()));
Expand All @@ -161,9 +157,9 @@ fn main() {
fs::write(
"./examples/nova-verifier.sol",
decider_solidity_code.clone(),
)
.unwrap();
fs::write("./examples/solidity-calldata.calldata", calldata.clone()).unwrap();
)?;
fs::write("./examples/solidity-calldata.calldata", calldata.clone())?;
let s = solidity_verifiers::utils::get_formatted_calldata(calldata.clone());
fs::write("./examples/solidity-calldata.inputs", s.join(",\n")).expect("");
Ok(())
}
37 changes: 16 additions & 21 deletions examples/external_inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,32 +128,29 @@ pub mod tests {

// test to check that the ExternalInputsCircuit computes the same values inside and outside the circuit
#[test]
fn test_f_circuit() {
fn test_f_circuit() -> Result<(), Error> {
let poseidon_config = poseidon_canonical_config::<Fr>();

let cs = ConstraintSystem::<Fr>::new_ref();

let circuit = ExternalInputsCircuit::<Fr>::new(poseidon_config).unwrap();
let circuit = ExternalInputsCircuit::<Fr>::new(poseidon_config)?;
let z_i = vec![Fr::from(1_u32)];
let external_inputs = vec![Fr::from(3_u32)];

let z_i1 = circuit
.step_native(0, z_i.clone(), external_inputs.clone())
.unwrap();
let z_i1 = circuit.step_native(0, z_i.clone(), external_inputs.clone())?;

let z_iVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_i)).unwrap();
let external_inputsVar =
Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(external_inputs)).unwrap();
let z_iVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_i))?;
let external_inputsVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(external_inputs))?;

let computed_z_i1Var = circuit
.generate_step_constraints(cs.clone(), 0, z_iVar, external_inputsVar)
.unwrap();
assert_eq!(computed_z_i1Var.value().unwrap(), z_i1);
let computed_z_i1Var =
circuit.generate_step_constraints(cs.clone(), 0, z_iVar, external_inputsVar)?;
assert_eq!(computed_z_i1Var.value()?, z_i1);
Ok(())
}
}

/// cargo run --release --example external_inputs
fn main() {
fn main() -> Result<(), Error> {
let num_steps = 5;
let initial_state = vec![Fr::from(1_u32)];

Expand All @@ -168,7 +165,7 @@ fn main() {
assert_eq!(external_inputs.len(), num_steps);

let poseidon_config = poseidon_canonical_config::<Fr>();
let F_circuit = ExternalInputsCircuit::<Fr>::new(poseidon_config.clone()).unwrap();
let F_circuit = ExternalInputsCircuit::<Fr>::new(poseidon_config.clone())?;

/// The idea here is that eventually we could replace the next line chunk that defines the
/// `type N = Nova<...>` by using another folding scheme that fulfills the `FoldingScheme`
Expand All @@ -188,17 +185,15 @@ fn main() {

println!("Prepare Nova's ProverParams & VerifierParams");
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit.clone());
let nova_params = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
let nova_params = N::preprocess(&mut rng, &nova_preprocess_params)?;

println!("Initialize FoldingScheme");
let mut folding_scheme = N::init(&nova_params, F_circuit, initial_state.clone()).unwrap();
let mut folding_scheme = N::init(&nova_params, F_circuit, initial_state.clone())?;

// compute a step of the IVC
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
let start = Instant::now();
folding_scheme
.prove_step(rng, external_inputs_at_step.clone(), None)
.unwrap();
folding_scheme.prove_step(rng, external_inputs_at_step.clone(), None)?;
println!("Nova::prove_step {}: {:?}", i, start.elapsed());
}
println!(
Expand All @@ -212,6 +207,6 @@ fn main() {
N::verify(
nova_params.1, // Nova's verifier params
ivc_proof,
)
.unwrap();
)?;
Ok(())
}
Loading

0 comments on commit 83d1383

Please sign in to comment.