Browse Source

chore: start updating doc on frontend

main
dmpierre 1 year ago
parent
commit
aa47ac1d54
4 changed files with 136 additions and 15 deletions
  1. +1
    -0
      src/SUMMARY.md
  2. +15
    -12
      src/folding-and-sonobe.md
  3. +118
    -2
      src/usage/frontend.md
  4. +2
    -1
      src/usage/overview.md

+ 1
- 0
src/SUMMARY.md

@ -1,4 +1,5 @@
# sonobe docs
- [Introduction](README.md)
- [Folding Schemes and Sonobe](folding-and-sonobe.md)

+ 15
- 12
src/folding-and-sonobe.md

@ -4,7 +4,9 @@
Folding schemes are a family of SNARKs for iterative computations, allowing to prove that a function $F$ applied $n$ times to an initial input $z_0$ results in $z_n$.
<img src="imgs/folding-main-idea-diagram.png" style="width:70%;" />
<p align="center">
<img src="imgs/folding-main-idea-diagram.png" style="width:70%;" />
</p>
Where $w_i$ are the external witnesses used at each iterative step.
@ -12,25 +14,26 @@ In other words, it allows to prove efficiently that $z_n = F(...~F(F(F(F(z_0, w_
<br>
The next 3 videos provide a good overview on the folding shcmes ideas:
The next 3 videos provide a good overview of folding schemes:
- 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 build with them.
- In [this presentation](https://www.youtube.com/watch?v=SwonTtOQzAk) (1h) Justin Drake explains the folding schemes and Nova concepts.
- 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.
## Sonobe overview
Sonobe is a folding schemes modular library to fold R1CS instances in an Incremental Verifiable computation (IVC) style. It also provides the tools required to generate a zkSNARK out of an IVC proof and to verify it on Ethereum's EVM.
Sonobe is a modular folding schemes library. It allows developers to fold R1CS instances in an Incremental Verifiable computation (IVC) style. It also provides tools required to generate a zkSNARK out of an IVC proof. Developers can configure sonobe so that those proofs can also be verified on Ethereum's EVM.
The development flow using Sonobe looks like:
1. Define a circuit to be folded
2. Set which folding scheme to be used (eg. Nova)
3. Set a final decider to generate the final proof (eg. Spartan over Pasta curves)
4. Generate the the decider verifier
1. Define a circuit to be folded. This is done using a frontend such as [`circom`](https://github.com/iden3/circom) or [arkworks](https://github.com/arkworks-rs/r1cs-std).
2. Set which folding scheme to be used (eg. Nova).
3. Set a final decider to generate the final proof (eg. Spartan over Pasta curves).
4. Generate the decider verifier.
![](imgs/sonobe-lib-pipeline.png)
<p align="center">
<img src="imgs/sonobe-lib-pipeline.png" style="width:70%;" />
</p>
The folding scheme and decider used can be swapped respectively with a few lines of code (eg. switching from a Decider that uses two Spartan proofs over a cycle of curves, to a Decider that uses a single Groth16 proof over the BN254 to be verified in an Ethereum smart contract).
Complete examples can be found at [sonobe/folding-schemes/examples](https://github.com/privacy-scaling-explorations/sonobe/tree/main/folding-schemes/examples)
Complete examples can be found at [sonobe/folding-schemes/examples](https://github.com/privacy-scaling-explorations/sonobe/tree/main/folding-schemes/examples).

+ 118
- 2
src/usage/frontend.md

@ -1,8 +1,10 @@
# Frontend
The frontend interface allows to define the circuit to be folded. The available frontends are arkworks are Circom.
The frontend interface allows to define the circuit to be folded. The available frontends are [`circom`](https://github.com/iden3/circom) or [arkworks](https://github.com/arkworks-rs/r1cs-std). We will show here how to define a circuit using `arkworks`.
We just need to fulfill the [`FCircuit` trait](https://github.com/privacy-scaling-explorations/sonobe/blob/main/sonobe/src/frontend/mod.rs):
# The `FCircuit` trait
To be folded with sonobe, a circuit needs to implement the [`FCircuit` trait](https://github.com/privacy-scaling-explorations/sonobe/blob/main/sonobe/src/frontend/mod.rs). This trait defines the methods that sonobe expects from the circuit to be folded. It corresponds to the $F$ function that is being folded. The trait has the following methods:
```rust
/// FCircuit defines the trait of the circuit of the F function, which is the one being folded (ie.
@ -41,3 +43,117 @@ pub trait FCircuit: Clone + Debug {
}
```
# Example
Let's walk through different simple examples implementing the `FCircuit` trait. By the end, you will hopefully be familiar with how to integrate an `arkworks` circuit into sonobe.
## Folding a simple circuit
The circuit we will fold has a state of 5 public elements. At each step, we will want the circuit to compute the next state by:
1. adding 4 to the first element
2. adding 40 to the second element
3. multiplying the third element by 4
4. multiplying the fourth element by 40
5. adding 100 to the fifth element
Let's implement this now:
```rust
// Define a struct that will be our circuit. This struct will implement the FCircuit trait.
#[derive(Clone, Copy, Debug)]
pub struct MultiInputsFCircuit<F: PrimeField> {
_f: PhantomData<F>,
}
// Implement the FCircuit trait for the struct
impl<F: PrimeField> FCircuit<F> for MultiInputsFCircuit<F> {
type Params = ();
fn new(_params: Self::Params) -> Self {
Self { _f: PhantomData }
}
fn state_len(&self) -> usize {
5 // This circuit has 5 inputs
}
// Computes the next state values in place, assigning z_{i+1} into z_i, and computing the new z_{i+1}
// We want the `step_native` method to implement the same logic as the `generate_step_constraints` method
fn step_native(&self, _i: usize, z_i: Vec<F>) -> Result<Vec<F>, Error> {
let a = z_i[0] + F::from(4_u32);
let b = z_i[1] + F::from(40_u32);
let c = z_i[2] * F::from(4_u32);
let d = z_i[3] * F::from(40_u32);
let e = z_i[4] + F::from(100_u32);
Ok(vec![a, b, c, d, e]) // The length of the returned vector should match `state_len`
}
/// generates R1CS constraints for the step of F for the given z_i
fn generate_step_constraints(
&self,
cs: ConstraintSystemRef<F>,
_i: usize,
z_i: Vec<FpVar<F>>,
) -> Result<Vec<FpVar<F>>, SynthesisError> {
// Implementing the circuit constraints
let four = FpVar::<F>::new_constant(cs.clone(), F::from(4u32))?;
let forty = FpVar::<F>::new_constant(cs.clone(), F::from(40u32))?;
let onehundred = FpVar::<F>::new_constant(cs.clone(), F::from(100u32))?;
let a = z_i[0].clone() + four.clone();
let b = z_i[1].clone() + forty.clone();
let c = z_i[2].clone() * four;
let d = z_i[3].clone() * forty;
let e = z_i[4].clone() + onehundred;
Ok(vec![a, b, c, d, e]) // The length of the returned vector should match `state_len`
}
}
```
## Folding a `Sha256` circuit
We will fold a simple `Sha256` circuit. The circuit has a state of 1 public element. At each step, we will want the circuit to compute the next state by applying the `Sha256` function to the current state.
```rust
#[derive(Clone, Copy, Debug)]
pub struct Sha256FCircuit<F: PrimeField> {
_f: PhantomData<F>,
}
impl<F: PrimeField> FCircuit<F> for Sha256FCircuit<F> {
type Params = ();
fn new(_params: Self::Params) -> Self {
Self { _f: PhantomData }
}
fn state_len(&self) -> usize {
1
}
/// computes the next state values in place, assigning z_{i+1} into z_i, and computing the new
/// z_{i+1}
fn step_native(&self, _i: usize, z_i: Vec<F>) -> Result<Vec<F>, Error> {
let out_bytes = Sha256::evaluate(&(), z_i[0].into_bigint().to_bytes_le()).unwrap();
let out: Vec<F> = out_bytes.to_field_elements().unwrap();
Ok(vec![out[0]])
}
/// generates the constraints for the step of F for the given z_i
fn generate_step_constraints(
&self,
_cs: ConstraintSystemRef<F>,
_i: usize,
z_i: Vec<FpVar<F>>,
) -> Result<Vec<FpVar<F>>, SynthesisError> {
let unit_var = UnitVar::default();
let out_bytes = Sha256Gadget::evaluate(&unit_var, &z_i[0].to_bytes()?)?;
let out = out_bytes.0.to_constraint_field()?;
Ok(vec![out[0].clone()])
}
}
```
## Folding a circuit with public and private inputs

+ 2
- 1
src/usage/overview.md

@ -1,6 +1,7 @@
# Usage
This section showcases how to use the Sonobe library to:
- Define a circuit to be folded using the Frontend
- Define a circuit to be folded using a frontend such as [`circom`](https://github.com/iden3/circom) or [arkworks](https://github.com/arkworks-rs/r1cs-std).
- Fold the circuit using one of the folding schemes
- Generate a final Decider proof
- Verify the Decider proof, and in Ethereum case, generate a Solidity verifier

Loading…
Cancel
Save