arnaucube
arnaucube/sonobe-docsPublic Self-hosted repository
sonobe-docs/src/usage/frontend-arkworks.md
src/usage/frontend-arkworks.mdRaw
  1# Arkworks frontend
  2
  3Let'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.
  4
  5You 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.
  6
  7## Cubic circuit example
  8This first example implements the `FCircuit` trait for the R1CS example circuit from [Vitalik's post](https://www.vitalik.ca/general/2016/12/10/qap.html), which checks $x^3 + x + 5 == y$.
  9
 10$z_i$ is used as $x$, and $z_{i+1}$ is used as $y$, and at the next step, $z_{i+1}$ will be assigned to $z_i$, and a new $z_{i+1}$ will be computted.
 11
 12```rust
 13#[derive(Clone, Copy, Debug)]
 14pub struct CubicFCircuit<F: PrimeField> {
 15    _f: PhantomData<F>,
 16}
 17impl<F: PrimeField> FCircuit<F> for CubicFCircuit<F> {
 18    type Params = ();
 19    fn new(_params: Self::Params) -> Result<Self, Error> {
 20        Ok(Self { _f: PhantomData })
 21    }
 22    fn state_len(&self) -> usize {
 23        1
 24    }
 25    fn external_inputs_len(&self) -> usize {
 26        0
 27    }
 28    fn step_native(
 29        &self,
 30        _i: usize,
 31        z_i: Vec<F>,
 32        _external_inputs: Vec<F>,
 33    ) -> Result<Vec<F>, Error> {
 34        Ok(vec![z_i[0] * z_i[0] * z_i[0] + z_i[0] + F::from(5_u32)])
 35    }
 36    fn generate_step_constraints(
 37        &self,
 38        cs: ConstraintSystemRef<F>,
 39        _i: usize,
 40        z_i: Vec<FpVar<F>>,
 41        _external_inputs: Vec<FpVar<F>>,
 42    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 43        let five = FpVar::<F>::new_constant(cs.clone(), F::from(5u32))?;
 44        let z_i = z_i[0].clone();
 45
 46        Ok(vec![&z_i * &z_i * &z_i + &z_i + &five])
 47    }
 48}
 49```
 50
 51
 52## Multiple inputs circuit example
 53
 54The following example has a state of 5 public elements. At each step, we will want the circuit to compute the next state by:
 55
 561. adding 4 to the first element
 572. adding 40 to the second element
 583. multiplying the third element by 4
 594. multiplying the fourth element by 40
 605. adding 100 to the fifth element
 61
 62
 63```rust
 64// Define a struct that will be our circuit. This struct will implement the FCircuit trait.
 65#[derive(Clone, Copy, Debug)]
 66pub struct MultiInputsFCircuit<F: PrimeField> {
 67    _f: PhantomData<F>,
 68}
 69impl<F: PrimeField> FCircuit<F> for MultiInputsFCircuit<F> {
 70    type Params = ();
 71
 72    fn new(_params: Self::Params) -> Result<Self, Error> {
 73        Ok(Self { _f: PhantomData })
 74    }
 75    fn state_len(&self) -> usize {
 76        5 // since the circuit has 5 inputs
 77    }
 78    fn external_inputs_len(&self) -> usize {
 79        0
 80    }
 81
 82    /// computes the next state values in place, assigning z_{i+1} into z_i, and computing the new
 83    /// z_{i+1}
 84    fn step_native(
 85        &self,
 86        _i: usize,
 87        z_i: Vec<F>,
 88        _external_inputs: Vec<F>,
 89    ) -> Result<Vec<F>, Error> {
 90        let a = z_i[0] + F::from(4_u32);
 91        let b = z_i[1] + F::from(40_u32);
 92        let c = z_i[2] * F::from(4_u32);
 93        let d = z_i[3] * F::from(40_u32);
 94        let e = z_i[4] + F::from(100_u32);
 95
 96        Ok(vec![a, b, c, d, e])
 97    }
 98
 99    /// generates the constraints for the step of F for the given z_i
100    fn generate_step_constraints(
101        &self,
102        cs: ConstraintSystemRef<F>,
103        _i: usize,
104        z_i: Vec<FpVar<F>>,
105        _external_inputs: Vec<FpVar<F>>,
106    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
107        let four = FpVar::<F>::new_constant(cs.clone(), F::from(4u32))?;
108        let forty = FpVar::<F>::new_constant(cs.clone(), F::from(40u32))?;
109        let onehundred = FpVar::<F>::new_constant(cs.clone(), F::from(100u32))?;
110        let a = z_i[0].clone() + four.clone();
111        let b = z_i[1].clone() + forty.clone();
112        let c = z_i[2].clone() * four;
113        let d = z_i[3].clone() * forty;
114        let e = z_i[4].clone() + onehundred;
115
116        Ok(vec![a, b, c, d, e])
117    }
118}
119```
120
121
122## Using external inputs
123
124In this example we set the state to be the previous state together with an external input, and the new state is an array which contains the new state and a zero which will be ignored.
125
126This is useful for example if we want to fold multiple verifications of signatures, where the circuit F checks the signature and is folded for each of the signatures and public keys. To keep things simpler, the following example does not verify signatures but does a similar approach with a chain of hashes, where each iteration hashes the previous step output ($z_i$) together with an external input ($w_i$).
127
128```
129       w_1     w_2     w_3     w_4     
130       │       │       │       │      
131       ▼       ▼       ▼       ▼      
132      ┌─┐     ┌─┐     ┌─┐     ┌─┐     
133─────►│F├────►│F├────►│F├────►│F├────►
134 z_1  └─┘ z_2 └─┘ z_3 └─┘ z_4 └─┘ z_5
135
136
137where each F is:
138  w_i                                        
139   │     ┌────────────────────┐              
140   │     │FCircuit            │              
141   │     │                    │              
142   └────►│ h =Hash(z_i[0],w_i)│              
143────────►│ │                  ├───────►      
144 z_i     │ └──►z_{i+1}=[h]    │  z_{i+1}
145         │                    │              
146         └────────────────────┘
147```
148
149where each $w_i$ value is set at the `external_inputs` array.
150
151The last state $z_i$ is used together with the external input w_i as inputs to compute the new state $z_{i+1}$.
152
153```rust
154use ark_crypto_primitives::{
155    crh::{
156        poseidon::constraints::{CRHGadget, CRHParametersVar},
157        poseidon::CRH,
158        CRHScheme, CRHSchemeGadget,
159    },
160    sponge::{poseidon::PoseidonConfig, Absorb},
161};
162
163#[derive(Clone, Debug)]
164pub struct ExternalInputsCircuits<F: PrimeField>
165where
166    F: Absorb,
167{
168    _f: PhantomData<F>,
169    poseidon_config: PoseidonConfig<F>,
170}
171impl<F: PrimeField> FCircuit<F> for ExternalInputsCircuit<F>
172where
173    F: Absorb,
174{
175    type Params = PoseidonConfig<F>;
176
177    fn new(params: Self::Params) -> Result<Self, Error> {
178        Ok(Self {
179            _f: PhantomData,
180            poseidon_config: params,
181        })
182    }
183    fn state_len(&self) -> usize {
184        1
185    }
186    fn external_inputs_len(&self) -> usize {
187        1
188    }
189
190    /// computes the next state value for the step of F for the given z_i and external_inputs
191    /// z_{i+1}
192    fn step_native(
193        &self,
194        _i: usize,
195        z_i: Vec<F>,
196        external_inputs: Vec<F>,
197    ) -> Result<Vec<F>, Error> {
198        let hash_input: [F; 2] = [z_i[0], external_inputs[0]];
199        let h = CRH::<F>::evaluate(&self.poseidon_config, hash_input).unwrap();
200        Ok(vec![h])
201    }
202
203    /// generates the constraints and returns the next state value for the step of F for the given
204    /// z_i and external_inputs
205    fn generate_step_constraints(
206        &self,
207        cs: ConstraintSystemRef<F>,
208        _i: usize,
209        z_i: Vec<FpVar<F>>,
210        external_inputs: Vec<FpVar<F>>,
211    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
212        let crh_params =
213            CRHParametersVar::<F>::new_constant(cs.clone(), self.poseidon_config.clone())?;
214        let hash_input: [FpVar<F>; 2] = [z_i[0].clone(), external_inputs[0].clone()];
215        let h = CRHGadget::<F>::evaluate(&crh_params, &hash_input)?;
216        Ok(vec![h])
217    }
218}
219```
220
221<br><br>
222
223# Complete examples
224You can find the complete examples with all the imports at [sonobe/examples](https://github.com/privacy-scaling-explorations/sonobe/tree/main/examples).