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`.
The frontend interface allows to define the circuit to be folded. The currently 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`.
# The `FCircuit` trait
@ -14,14 +14,14 @@ To be folded with sonobe, a circuit needs to implement the [`FCircuit` trait](ht
pub trait FCircuit<F:PrimeField>: Clone + Debug {
type Params: Debug;
/// returns a new FCircuit instance
/// Returns a new FCircuit instance
fn new(params: Self::Params) -> Self;
/// returns the number of elements in the state of the FCircuit, which corresponds to the
/// Returns the number of elements in the state of the FCircuit, which corresponds to the
/// FCircuit inputs.
fn state_len(&self) -> usize;
/// computes the next state values in place, assigning z_{i+1} into z_i, and computing the new
/// Computes the next state values in place, assigning z_{i+1} into z_i, and computing the new
/// z_{i+1}
fn step_native(
// this method uses self, so that each FCircuit implementation (and different frontends)
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.
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.
## Folding a simple circuit
@ -90,7 +90,7 @@ impl FCircuit for MultiInputsFCircuit {
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
/// Generates R1CS constraints for the step of F for the given z_i
fn generate_step_constraints(
&self,
cs: ConstraintSystemRef<F>,
@ -110,18 +110,21 @@ impl FCircuit for MultiInputsFCircuit {
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.
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.
Note that the logic here is also very similar to the previous example: write a struct that will hold the circuit, implement the `FCircuit` trait for the struct, ensure that the length of the state is correct, and implement the `step_native` and `generate_step_constraints` methods.
```rust
// Define a struct that will be our circuit. This struct will implement the FCircuit trait.
#[derive(Clone, Copy, Debug)]
pub struct Sha256FCircuit<F:PrimeField> {
_f: PhantomData<F>,
}
impl<F:PrimeField> FCircuit<F> for Sha256FCircuit<F> {
type Params = ();
@ -132,7 +135,7 @@ impl FCircuit for Sha256FCircuit {
1
}
/// computes the next state values in place, assigning z_{i+1} into z_i, and computing the new
/// Computes the next state values in place, assigning z_{i+1} into z_i, and computing the new
let out_bytes = Sha256::evaluate(&(), z_i[0].into_bigint().to_bytes_le()).unwrap();
@ -141,7 +144,7 @@ impl FCircuit for Sha256FCircuit {
Ok(vec![out[0]])
}
/// generates the constraints for the step of F for the given z_i
/// Generates the constraints for the step of F for the given z_i
fn generate_step_constraints(
&self,
_cs: ConstraintSystemRef<F>,
@ -156,4 +159,64 @@ impl FCircuit for Sha256FCircuit {
}
```
## Folding a circuit with public and private inputs
## Folding a circuit with public and private inputs
Sometimes, the circuit to be folded will have private inputs. Let's see how we can setup such a circuit to be folded with sonobe. Again, the logic here is also very similar to our previous examples. The main difference is that the `struct` which will hold the circuit also holds a `Vec` of private inputs.