---
# System prepended metadata

title: coding task

---

# coding task

__Implement a circuit for poseidon hash using a vanilla plonk gate.__

The plonk is configured as follows. It uses a custom gate
$$q_a·a + q_b·b + q_c·c + q_{ab}·a·b + constant + instance = 0$$
and use the following struct to store the witnesses and selectors.
``` rust
#[derive(Clone, Copy)]
pub struct StandardPlonkConfig {
    a: Column<Advice>,
    b: Column<Advice>,
    c: Column<Advice>,
    q_a: Column<Fixed>,
    q_b: Column<Fixed>,
    q_c: Column<Fixed>,
    q_ab: Column<Fixed>,
    constant: Column<Fixed>,
    #[allow(dead_code)]
    instance: Column<Instance>,
}
```
Then we enforce the custom gates over the witnesses and selectors via the following configuration.
``` rust
impl<F:Prim> StandardPlonkConfig<F> {
    fn configure(meta: &mut ConstraintSystem<F>) -> Self {
        let [a, b, c] = [(); 3].map(|_| meta.advice_column());
        let [q_a, q_b, q_c, q_ab, constant] = [(); 5].map(|_| meta.fixed_column());
        let instance = meta.instance_column();

        [a, b, c].map(|column| meta.enable_equality(column));

        meta.create_gate(
            "q_a·a + q_b·b + q_c·c + q_ab·a·b + constant + instance = 0",
            |meta| {
                let [a, b, c] = [a, b, c].map(|column| meta.query_advice(column, Rotation::cur()));
                let [q_a, q_b, q_c, q_ab, constant] = [q_a, q_b, q_c, q_ab, constant]
                    .map(|column| meta.query_fixed(column, Rotation::cur()));
                let instance = meta.query_instance(instance, Rotation::cur());
                Some(
                    q_a * a.clone()
                        + q_b * b.clone()
                        + q_c * c
                        + q_ab * a * b
                        + constant
                        + instance,
                )
            },
        );

        StandardPlonkConfig { a, b, c, q_a, q_b, q_c, q_ab, constant, instance }
    }
}
```

The task is to design a circuit for the following subroutine of a 4-to-1 poseidon hash function.
``` rust
struct PoseidonState<F: PrimeField> {
    state: [F; 4],
    index: usize
}
```

You may assume that the state is already initialized. It will go through a `MAX_ITER` number of iterations. `index` is used to track which iteration it is current at. Each iterations is parameterized with an iteration key `k_i: [F; 4]`. The hash function also takes a global parameter M which is a 4-by-4 matrix, i.e. `M: [[F; 4];4]`.

Suppose the current state is $a_{i,1}, a_{i,2}, a_{i,3}, a_{i,4}$, then the next state is defined as


\begin{align*}
\left<a_{i+1,1}, a_{i+1,2}, a_{i+1,3}, a_{i+1,4}\right>&:=\left<a_{i,1}^5, a_{i,2}, a_{i,3}, a_{i,4}\right>\times\begin{pmatrix} M_{1,1}, M_{1,2}, M_{1,3}, M_{1,4}\\M_{2,1}, M_{2,2}, M_{2,3}, M_{2,4}\\M_{3,1}, M_{3,2}, M_{3,3}, M_{3,4}\\M_{4,1}, M_{4,2}, M_{4,3}, M_{4,4} \end{pmatrix} \\ &+ \left<k_{i,1}, k_{i,2}, k_{i,3}, k_{i,4}\right>
\end{align*}

Notice that the first element in the previous state is raised to the power of 5.

# Skelton of the code

``` rust
/// Assume we do a maximum of 5 iterations
const MAX_ITER: usize = 5;
/// Assume the round key is given as an array of size MAX_ITER;
/// each element of the array is the round key for the corresponding iteration
/// You DO NOT need to complete this part.
const ROUND_KEY: [[F;4];MAX_ITER] = ... 
/// Assume the matrix is given as a 4-by-4 2-dimentional array;
/// You DO NOT need to complete this part.
const MDS_MATRIX: [[F;4];4] = ...

/// The state that holds the exsitng 
#[derive(Clone, Default)]
struct PoseidonState([F; 4]);

// 

impl Circuit<Fr> for PoseidonState {
    type Config = StandardPlonkConfig;
    type FloorPlanner = SimpleFloorPlanner;

    fn without_witnesses(&self) -> Self {
        Self::default()
    }

    fn configure(meta: &mut ConstraintSystem<Fr>) -> Self::Config {
        meta.set_minimum_degree(4);
        // configure a chip here
        StandardPlonkConfig::configure(meta)
    }

    fn synthesize(
        &self,
        config: Self::Config,
        mut layouter: impl Layouter<Fr>,
        meta: &mut ConstraintSystem<Fr>
    ) -> Result<(), Error> {
        layouter.assign_region(
            || "",
            |mut region| {
                //
                // BEGIN of SAMPLE code
                //
                region.assign_advice(|| "", config.a, 0, || Value::known(self.0[0]))?;
                region.assign_fixed(|| "", config.q_a, 0, || Value::known(-F::one()))?;
                region.assign_advice(|| "", config.b, 0, || Value::known(self.0[1]))?;
                region.assign_fixed(|| "", config.q_b, 0, || Value::known(F::from(5)))?;
                region.assign_advice(|| "", config.c, 0, || Value::known(self.0[2]))?;                
                region.assign_fixed(|| "", config.q_c, 0, || Value::known(F::one()))?;
                //
                // END of SAMPLE code
                //
                // You may comment out the sample code and write your code here
                
                // meta.create_gate to query the advice and fixed columns
                // return the vector with operations
                // vec![<a> * MDS_MATIX + <k>]
                Ok(())
            },
        )
    }
    
    fn matrix_mul(&self, config: Self::Config, matrix: [[F;4];4], curr_state: [F; 4], meta: &mut ConstraintSystem<Fr>) -> [F; 4]{
        let final_matrix: [F; 4];
    // We will fill in the curr_state array with [a[0], a[1], ...]
        for (let i = 0; i < curr_state.len; i++){
            curr_state[i] = curr_state[i].map(|column| meta.query_advice(column, Rotation::(i)));
        }
        for (let i = 0; i < curr_state.len; i++) {
            for (let j = 0; j < curr_state.len; j++)
            // query curr_state adivce column and multiply by rows in matrix
            final_matrix = curr_state[i] * matrix[i][j];
            }
        }
        Ok(final_matrix)
        
        
    }
}

// Scalar field of bn256 / Scalar
// Chip needs to do multiply and add (perhaps having a lookup table for a^5) a is a field element of a^256
// 

```