- [Circom](https://github.com/iden3/circom), iden3, 0Kims Association. Experimental frontend using [arkworks/circom-compat](https://github.com/arkworks-rs/circom-compat).
### Frontends
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/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.
- [sonobe-btc](https://github.com/dmpierre/sonobe-btc): implementation of an on-chain Bitcoin light client leveraging Sonobe: uses nova to verify bitcoin's proof of work over 100k blocks and groth16 to land the zkSNARK IVC proof on chain.
- [sonobe-btc](https://github.com/dmpierre/sonobe-btc): implementation of an on-chain Bitcoin light client leveraging Sonobe: uses nova to verify bitcoin's proof of work over 100k blocks and groth16 to land the zkSNARK IVC proof on chain.
- [hash-chain-sonobe](https://github.com/arnaucube/hash-chain-sonobe): example using Sonobe & Circom circuits, proving chains of Sha256 and Keccak256 hashes.
- [hash-chain-sonobe](https://github.com/arnaucube/hash-chain-sonobe): example using Sonobe & Circom circuits, proving chains of Sha256 and Keccak256 hashes.
- [ethdos-fold](https://github.com/arnaucube/ethdos-fold): implementation of [ETHdos](https://ethdos.xyz/blog) using folding schemes.
## Papers
## Related papers
- [Mova: Nova folding without committing to error terms](https://eprint.iacr.org/2024/1220): a folding scheme for R1CS instances that does not require committing to error or cross terms. It is implemented on top of Sonobe code base, and used for benchmarks, see their repo [here](https://github.com/NethermindEth/sonobe/tree/paper).
- [Mova: Nova folding without committing to error terms](https://eprint.iacr.org/2024/1220): a folding scheme for R1CS instances that does not require committing to error or cross terms. It is implemented on top of Sonobe code base, and used for benchmarks, see their repo [here](https://github.com/NethermindEth/sonobe/tree/paper).
- [Eva: Efficient IVC-Based Authentication of Lossy-Encoded Videos](https://eprint.iacr.org/2024/1436): cryptographic protocol for authenticating lossy-encoded videos. Is implemented on top of Sonobe code base.
- [Eva: Efficient IVC-Based Authentication of Lossy-Encoded Videos](https://eprint.iacr.org/2024/1436): cryptographic protocol for authenticating lossy-encoded videos. Is implemented on top of Sonobe code base.
@ -15,10 +15,11 @@ In other words, it allows to prove efficiently that $z_n = F(...~F(F(F(F(z_0, w_
<br>
<br>
The next 3 videos provide a good overview of folding schemes:
The next 3 videos provide an overview of the main ideas in folding schemes (sorted from more high level to deepest into the concepts):
- In [this presentation](https://www.youtube.com/watch?v=Jj19k2AXH2k) (5 min) Abhiram Kothapalli explains the main idea of Nova folding scheme.
- In [this presentation](https://www.youtube.com/watch?v=Jj19k2AXH2k) (5 min) Abhiram Kothapalli explains the main idea of Nova folding scheme.
- In [this presentation](https://youtu.be/IzLTpKWt-yg?t=6367) (20 min) Carlos Pérez overviews the features of folding schemes and what can be built with them.
- In [this presentation](https://youtu.be/IzLTpKWt-yg?t=6367) (20 min) Carlos Pérez overviews the features of folding schemes and what can be built with them.
- In [this presentation](https://www.youtube.com/watch?v=SwonTtOQzAk) (1h) Justin Drake explains what a folding scheme is and Nova-related concepts.
- In [this presentation](https://www.youtube.com/watch?v=z3FH9I8klDk) (30min) arnaucube overivews the main building blocks on folding schemes and showcases the usage of Sonobe.
- In [this presentation](https://www.youtube.com/watch?v=4alOna5X3ro) (1h) Albert Garreta dives into the math behind folding schemes.
In the Ethereum Decider case, we can generate a Solidity smart contract that verifies the proofs onchain. More details in the [next section](solidity-verifier.md).
@ -17,14 +19,12 @@ Generating the final proof (decider), to be able to verify it in Ethereum's EVM:
```rust
```rust
type DECIDER = Decider<
type DECIDER = Decider<
Projective,
Projective,
GVar,
Projective2,
Projective2,
GVar2,
CubicFCircuit<Fr>,
CubicFCircuit<Fr>,
KZG<'static, Bn254>,
KZG<'static, Bn254>,
Pedersen<Projective2>,
Pedersen<Projective2>,
Groth16<Bn254>, // here we define the Snark to use in the decider
Groth16<Bn254>, // here we define the Snark to use in the decider
NOVA, // here we define the FoldingScheme to use
NOVA, // here we define the FoldingScheme to use
>;
>;
let mut rng = rand::rngs::OsRng;
let mut rng = rand::rngs::OsRng;
@ -38,3 +38,27 @@ let proof = DECIDER::prove(rng, decider_pp, nova.clone()).unwrap();
```
```
As in the previous sections, you can find a full examples with all the code at [sonobe/examples](https://github.com/privacy-scaling-explorations/sonobe/tree/main/examples).
As in the previous sections, you can find a full examples with all the code at [sonobe/examples](https://github.com/privacy-scaling-explorations/sonobe/tree/main/examples).
## Decider verify
We can now verify the Decider proof
```rust
// this is the same that we defined for the prover
In the Ethereum Decider case, we can generate a Solidity smart contract that verifies the proofs onchain. More details in the [next section](solidity-verifier.md).
> Warning: the following frontends are experimental and some computational and time overhead is expected when using them compared to directly using the [arkworks frontend](frontend-arkworks.md).
This section overviews how to use the various experimental frontends:
- [implementing new frontends](#implementing-new-frontends)
- [Circom frontend](#circom-frontend)
- [Noname frontend](#noname-frontend)
- [Noir frontend](#noir-frontend)
## Implementing new frontends
Support for new frontends can be added (even from outside this repo) by implementing the [`FCircuit` trait](https://github.com/privacy-scaling-explorations/sonobe/blob/main/folding-schemes/src/frontend/mod.rs).
## Circom frontend
> **Note**: Circom frontend will be significantly slower than the Arkworks frontend. We explain below how to implement a custom `step_native` function with your circom circuits to speed things up!
> **Note**: Circom frontend will be significantly slower than the Arkworks frontend. We explain below how to implement a custom `step_native` function with your circom circuits to speed things up!
Experimental frontend using [arkworks/circom-compat](https://github.com/arkworks-rs/circom-compat).
Experimental frontend using [arkworks/circom-compat](https://github.com/arkworks-rs/circom-compat).
@ -107,3 +123,21 @@ for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
```
```
You can find a full example using Nova to fold a Circom circuit at [sonobe/examples/circom_full_flow.rs](https://github.com/privacy-scaling-explorations/sonobe/blob/main/examples/circom_full_flow.rs).
You can find a full example using Nova to fold a Circom circuit at [sonobe/examples/circom_full_flow.rs](https://github.com/privacy-scaling-explorations/sonobe/blob/main/examples/circom_full_flow.rs).
## Noname frontend
Experimental [Noname](https://github.com/zksecurity/noname/). Under the hood, we [bridge](https://github.com/dmpierre/ark-noname/tree/feat/sonobe-integration) compiled Noname circuits to arkworks R1CS. Our Noname integration does not support Noname's standard library for now.
Using Noname with sonobe is similar to using any other frontend. Sonobe expects that the length of your public and private (external) inputs match what the Noname circuit expects. Note that sonobe does not expect your public inputs to follow some specific naming convention when using Noname: it will assume that whatever public input variable you have is the IVC state.
This [example](https://github.com/privacy-scaling-explorations/sonobe/blob/main/examples/noname_full_flow.rs) shows how to fold a simple Noname circuit having both public and external, private inputs.
## Noir frontend
Experimental [Noir](https://noir-lang.org/) frontend. Under the hood, we [bridge](https://github.com/dmpierre/arkworks_backend) compiled Noir circuits to arkworks R1CS. Beware that sonobe assumes that the compiled Noir circuit that is being folded does not use any other opcode than an arithmetic gate: you can not fold circuits calling [oracles](https://noir-lang.org/docs/noir/concepts/oracles) or using [unconstrained](https://noir-lang.org/docs/noir/concepts/unconstrained/) functions. You should be able to use Noir's standard library though.
Using Noir with sonobe is similar to using any other frontend. Sonobe expects that the length of your public and private (external) inputs match what the Noir circuit expects. Note that sonobe does not expect your public inputs to follow some specific naming convention when using Noir: it will assume that whatever public input variable you have is the IVC state.
This [example](https://github.com/privacy-scaling-explorations/sonobe/blob/main/examples/noir_full_flow.rs) shows how to fold a poseidon circuit from the Noir standard library.
Let's walk through different simple examples implementing the `FCircuit` trait. By the end of this section, you will hopefully be familiar with how to integrate an `arkworks` circuit into sonobe.
Let's walk through different simple examples implementing the `FCircuit` trait. By the end of this section, you will hopefully be familiar with how to integrate an `arkworks` circuit into Sonobe.
You can find most of the following examples with the rest of code to run them at the [`examples`](https://github.com/privacy-scaling-explorations/sonobe/tree/main/examples) directory of the Sonobe repo.
You can find most of the following examples with the rest of code to run them at the [`examples`](https://github.com/privacy-scaling-explorations/sonobe/tree/main/examples) directory of the Sonobe repo.
@ -16,29 +16,21 @@ pub struct CubicFCircuit {
}
}
impl<F:PrimeField> FCircuit<F> for CubicFCircuit<F> {
impl<F:PrimeField> FCircuit<F> for CubicFCircuit<F> {
Experimental frontend using [arkworks_backend](https://github.com/dmpierre/arkworks_backend).
If you write your R1CS circuits using [Noir](https://noir-lang.org/), you can also use [sonobe](https://github.com/privacy-scaling-explorations/sonobe/) to fold your circuits. Under the hood, we bridge compiled Noir circuits to arkworks R1CS. Beware that sonobe assumes that the compiled Noir circuit that is being folded does not use any other opcode than an arithmetic gate: you can not fold circuits calling [oracles](https://noir-lang.org/docs/noir/concepts/oracles) or using [unconstrained](https://noir-lang.org/docs/noir/concepts/unconstrained/) functions. You should be able to use Noir's standard library though.
Using Noir with sonobe is similar to using any other frontend. Sonobe expects that the length of your public and private (external) inputs match what the Noir circuit expects. Note that sonobe does not expect your public inputs to follow some specific naming convention when using Noir: it will assume that whatever public input variable you have is the IVC state.
This [example](https://github.com/privacy-scaling-explorations/sonobe/blob/main/examples/noir_full_flow.rs) shows how to fold a poseidon circuit from the Noir standard library.
Experimental frontend using [ark-noname](https://github.com/dmpierre/ark-noname/tree/feat/sonobe-integration).
If you write your R1CS circuits using [Noname](), you can also use [sonobe](https://github.com/privacy-scaling-explorations/sonobe/) to fold your circuits. Under the hood, we bridge compiled Noname circuits to arkworks R1CS. Our Noname integration does not support Noname's standard library for now.
Using Noname with sonobe is similar to using any other frontend. Sonobe expects that the length of your public and private (external) inputs match what the Noname circuit expects. Note that sonobe does not expect your public inputs to follow some specific naming convention when using Noname: it will assume that whatever public input variable you have is the IVC state.
This [example](https://github.com/privacy-scaling-explorations/sonobe/blob/main/examples/noname_full_flow.rs) shows how to fold a simple Noname circuit having both public and external, private inputs.
The frontend interface allows to define the circuit to be folded.
The frontend interface allows to define the circuit to be folded.
The recommended frontend is to directly use [arkworks](https://github.com/arkworks-rs) to define the FCircuit, just following the [`FCircuit` trait](https://github.com/privacy-scaling-explorations/sonobe/blob/main/folding-schemes/src/frontend/mod.rs).
The recommended frontend is to directly use [arkworks](https://github.com/arkworks-rs) to define the FCircuit, just following the [`FCircuit` trait](https://github.com/privacy-scaling-explorations/sonobe/blob/main/folding-schemes/src/frontend/mod.rs).
Alternatively, experimental frontends for [Circom](https://github.com/iden3/circom), [Noir](https://noir-lang.org/), and [Noname](https://github.com/zksecurity/noname) can be found at [sonobe/frontends](https://github.com/privacy-scaling-explorations/sonobe/tree/main/frontends), which have some computational (and time) overhead.
Alternatively, experimental frontends for [Circom](https://github.com/iden3/circom), [Noir](https://noir-lang.org/), and [Noname](https://github.com/zksecurity/noname) can be found at [sonobe/experimental-frontends](https://github.com/privacy-scaling-explorations/sonobe/tree/main/experimental-frontends), which have some computational (and time) overhead.
Defining a circuit to be folded is as simple as fulfilling the `FCircuit` trait interface. Henceforth, integrating a new zk circuits language into Sonobe, can be done by building a wrapper on top of it that satisfies the `FCircuit` trait.
Defining a circuit to be folded is as simple as fulfilling the `FCircuit` trait interface. Henceforth, integrating a new zk circuits language into Sonobe, can be done by building a wrapper on top of it that satisfies the `FCircuit` trait.
@ -17,8 +17,14 @@ To be folded with sonobe, a circuit needs to implement the [`FCircuit` trait](ht
/// inside the agmented F' function).
/// inside the agmented F' function).
/// The parameter z_i denotes the current state, and z_{i+1} denotes the next state after applying
/// The parameter z_i denotes the current state, and z_{i+1} denotes the next state after applying
/// the step.
/// the step.
/// Note that the external inputs for the specific circuit are defined at the implementation of
/// both `FCircuit::ExternalInputs` and `FCircuit::ExternalInputsVar`, where the `Default` trait
/// implementation. For example if the external inputs are just an array of field elements, their
/// `Default` trait implementation must return an array of the expected size.
pub trait FCircuit<F:PrimeField>: Clone + Debug {
pub trait FCircuit<F:PrimeField>: Clone + Debug {
type Params: Debug;
type Params: Debug;
type ExternalInputs: Clone + Default + Debug;
type ExternalInputsVar: Clone + Default + Debug + AllocVar<Self::ExternalInputs,F>;
external_inputs: Vec<FpVar<F>>, // inputs that are not part of the state
external_inputs: Self::ExternalInputsVar, // inputs that are not part of the state
) -> Result<Vec<FpVar<F>>, SynthesisError>;
) -> Result<Vec<FpVar<F>>, SynthesisError>;
}
}
```
```
# Side note: adhoc frontend dependencies for the experimental frontends
> Note: this affects only to the experimental frontends in the [sonobe/frontends](https://github.com/privacy-scaling-explorations/sonobe/tree/main/frontends) directory.
## Side note: adhoc frontend dependencies for the experimental frontends
> Note: this affects only to the experimental frontends in the [sonobe/experimental-frontends](https://github.com/privacy-scaling-explorations/sonobe/tree/main/experimental-frontends) directory.
There are many ad hoc dependencies for each of the frontends integrated with Sonobe. Here are a few reasons why this is the case.
There are many ad hoc dependencies for each of the frontends integrated with Sonobe. Here are a few reasons why this is the case.
Thanks to the modularity of arkworks, we can swap between curves and proving systems.
Thanks to the modularity of arkworks, we can swap between curves and proving systems.
Suppose that for the final proof (decider), instead of using Groth16 over the BN254 curve, we want to use Marlin+IPA over the Pasta curves, so we can enjoy of not needing a trusted setup.
Suppose that for the final proof (decider), instead of using Groth16 over the BN254 curve, we want to use Marlin+IPA over the Pasta curves, so we can enjoy of not needing a trusted setup.
It just requires few line changes on our previous code [...]
It just requires few line changes on our previous code, for example, imagine we're using the Nova folding scheme (where `FC` is the `FCircuit` that we want to fold):
```rust
type FS = Nova<G1,G2,FC,Pedersen<G1>, Pedersen<G2>, false>;
```
to switch the folding scheme to use HyperNova, is as simple as updating the previous line to:
```rust
type FS = HyperNova<G1,G2,FC,Pedersen<G1>, Pedersen<G2>, 1, 1, false>;
```
similarly for using ProtoGalaxy folding scheme:
```rust
type FS = ProtoGalaxy<G1,G2,FC,Pedersen<G1>, Pedersen<G2>>;
```
We can use any cycle of curves available in arkworks for the `G1` and `G2`, and the rest of the code can be kept the same.
@ -10,11 +10,11 @@ Nova's zk-IVC proof generation is quite efficient, as it simply involves blindin
We identify 3 main interesting places to use the nova zk-layer: one before all the folding pipeline (Use-case-1), one at the end of the folding pipeline right before the final Decider SNARK proof (Use-case-2), and a third one for cases where compressed SNARK proofs are not needed, and just IVC proofs (bigger than SNARK proofs) suffice (Use-case-3):
We identify 3 main interesting places to use the nova zk-layer: one before all the folding pipeline (Use-case-1), one at the end of the folding pipeline right before the final Decider SNARK proof (Use-case-2), and a third one for cases where compressed SNARK proofs are not needed, and just IVC proofs (bigger than SNARK proofs) suffice (Use-case-3):
- Use-case-1: at the beginning of the folding pipeline, right when the user has their original instance prior to be folded into the running instance, the user can fold it with the random-satisfying-instance to then have a blinded instance that can be sent to a server that will fold it with the running instance.
- **Use-case-1**: at the beginning of the folding pipeline, right when the user has their original instance prior to be folded into the running instance, the user can fold it with the random-satisfying-instance to then have a blinded instance that can be sent to a server that will fold it with the running instance.
- In this one, the user could externalize all the IVC folding and also the Decider final proof generation to a server.
- In this one, the user could externalize all the IVC folding and also the Decider final proof generation to a server.
- Use-case-2: at the end of all the IVC folding steps (after n iterations of nova.prove_step), to 'blind' the IVC proof so then it can be sent to a server that will generate the final Decider SNARK proof.
- **Use-case-2**: at the end of all the IVC folding steps (after n iterations of nova.prove_step), to 'blind' the IVC proof so then it can be sent to a server that will generate the final Decider SNARK proof.
- In this one, the user could externalize the Decider final proof generation to a server.
- In this one, the user could externalize the Decider final proof generation to a server.
- Use-case-3: the user does not care about the Decider (final compressed SNARK proof), and wants to generate a zk-proof of the last IVC state to an IVC verifier (without any SNARK proof involved). In this use-case, the zk is only added at the last IVCProof. Note that this proof will be much bigger and expensive to verify than a Decider SNARK proof.
- **Use-case-3**: the user does not need the Decider (final compressed SNARK proof), and wants to generate a zk-proof of the last IVC state to an IVC verifier (without any SNARK proof involved, and without continuing folding after this last proof). In this use-case, the zk is only added at the last IVCProof. Note that this proof will be much bigger and expensive to verify than a Decider SNARK proof.
The current implementation available in Sonobe covers the Use-case-3.
The current implementation available in Sonobe covers the Use-case-3.
Use-case-1 can be achieved directly by a simpler version of the zk IVC scheme skipping steps and implemented directly at the app level by folding the original instance with a randomized instance (steps 2,3,4 from section D.4 of the [HyperNova](https://eprint.iacr.org/2023/573.pdf)
Use-case-1 can be achieved directly by a simpler version of the zk IVC scheme skipping steps and implemented directly at the app level by folding the original instance with a randomized instance (steps 2,3,4 from section D.4 of the [HyperNova](https://eprint.iacr.org/2023/573.pdf)