arkworks_mimc/
lib.rs

1use std::marker::PhantomData;
2
3use ark_ff::PrimeField;
4
5#[cfg(feature = "r1cs")]
6pub mod constraints;
7pub mod params;
8pub mod utils;
9
10#[cfg(feature = "paramgen")]
11pub mod paramgen;
12
13pub use traits::*;
14mod traits;
15
16pub trait MiMCParameters: Clone + Default {
17    const ROUNDS: usize;
18    const EXPONENT: usize;
19}
20
21#[derive(Default, Clone)]
22pub struct MiMC<F: PrimeField, P: MiMCParameters> {
23    pub num_outputs: usize,
24    pub k: F,
25    pub round_keys: Vec<F>,
26    params: PhantomData<P>,
27}
28
29impl<F: PrimeField, P: MiMCParameters> MiMC<F, P> {
30    pub fn new(num_outputs: usize, k: F, round_keys: Vec<F>) -> Self {
31        assert_eq!(round_keys.len(), P::ROUNDS, "Invalid round keys length");
32        Self {
33            num_outputs,
34            params: PhantomData,
35            k,
36            round_keys,
37        }
38    }
39}
40
41impl<F: PrimeField, P: MiMCParameters> MiMC<F, P> {
42    /// MiMC 2n/n x^exp permute
43    pub fn permute_feistel(&self, state: Vec<F>) -> Vec<F> {
44        let mut r = F::zero();
45        let mut c = F::zero();
46        for s in state.into_iter() {
47            r += s;
48            (r, c) = self.feistel(r, c);
49        }
50        let mut outputs = vec![r];
51        match self.num_outputs {
52            0 | 1 => outputs,
53            _ => {
54                for _ in 1..self.num_outputs {
55                    (r, c) = self.feistel(r, c);
56                    outputs.push(r);
57                }
58                outputs
59            }
60        }
61    }
62
63    fn feistel(&self, left: F, right: F) -> (F, F) {
64        let mut x_l = left;
65        let mut x_r = right;
66        for i in 0..P::ROUNDS {
67            let t = match i == 0 {
68                true => self.k + x_l,
69                false => self.k + x_l + self.round_keys[i],
70            };
71            let mut tn = F::one();
72            (0..P::EXPONENT).for_each(|_| tn *= t);
73            (x_l, x_r) = match i < P::ROUNDS - 1 {
74                true => (x_r + tn, x_l),
75                false => (x_l, x_r + tn),
76            };
77        }
78        (x_l, x_r)
79    }
80
81    /// MiMC n/n x^exp permute
82    pub fn permute_non_feistel(&self, state: Vec<F>) -> Vec<F> {
83        let mut r = self.k;
84        for s in state.into_iter() {
85            r += s + self.non_feistel(s, r);
86        }
87        let mut outputs = vec![r];
88        match self.num_outputs {
89            0 | 1 => outputs,
90            _ => {
91                for _ in 1..self.num_outputs {
92                    r += self.non_feistel(r, r);
93                    outputs.push(r);
94                }
95                outputs
96            }
97        }
98    }
99
100    fn non_feistel(&self, x: F, k: F) -> F {
101        let mut r = F::zero();
102        for i in 0..P::ROUNDS {
103            let t = match i == 0 {
104                true => k + x,
105                false => k + r + self.round_keys[i],
106            };
107            let mut tn = F::one();
108            (0..P::EXPONENT).for_each(|_| tn *= t);
109            r = tn;
110        }
111        r + k
112    }
113}