1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use crate::uint256::Uint256;

pub struct Hasher {
    p: Uint256,
    n_rounds: u8,
    c: Vec<Uint256>
}

impl Default for Hasher {
    fn default() -> Self {
        Hasher {
            p: Uint256::from("21888242871839275222246405745257275088548364400416034343698204186575808495617"),
            n_rounds: 10,
            c: vec![
                Uint256::from("0"),
                Uint256::from("25823191961023811529686723375255045606187170120624741056268890390838310270028"),
                Uint256::from("71153255768872006974285801937521995907343848376936063113800887806988124358800"),
                Uint256::from("51253176922899201987938365653129780755804051536550826601168630951148399005246"),
                Uint256::from("66651710483985382365580181188706173532487386392003341306307921015066514594406"),
                Uint256::from("45887003413921204775397977044284378920236104620216194900669591190628189327887"),
                Uint256::from("14399999722617037892747232478295923748665564430258345135947757381904956977453"),
                Uint256::from("29376176727758177809204424209125257629638239807319618360680345079470240949145"),
                Uint256::from("13768859312518298840937540532277016512087005174650120937309279832230513110846"),
                Uint256::from("54749662990362840569021981534456448557155682756506853240029023635346061661615"),
                Uint256::from("25161436470718351277017231215227846535148280460947816286575563945185127975034"),
                Uint256::from("90370030464179443930112165274275271350651484239155016554738639197417116558730"),
                Uint256::from("92014788260850167582827910417652439562305280453223492851660096740204889381255"),
                Uint256::from("40376490640073034398204558905403523738912091909516510156577526370637723469243"),
                Uint256::from("903792244391531377123276432892896247924738784402045372115602887103675299839"),
                Uint256::from("112203415202699791888928570309186854585561656615192232544262649073999791317171"),
                Uint256::from("114801681136748880679062548782792743842998635558909635247841799223004802934045"),
                Uint256::from("111440818948676816539978930514468038603327388809824089593328295503672011604028"),
                Uint256::from("64965960071752809090438003157362764845283225351402746675238539375404528707397"),
                Uint256::from("98428510787134995495896453413714864789970336245473413374424598985988309743097")
            ]    
        }
    }
}

impl Hasher {
    fn mimc_feistel(il: &Uint256, ir: &Uint256, k: &Uint256) -> (Uint256, Uint256) {
        let hasher = Hasher::default();
        let mut last_l = il.clone();
        let mut last_r = ir.clone();

        for i in 0..hasher.n_rounds {
            let mask = last_r.add_mod(&k, &hasher.p);
            let mask = mask.add_mod(&hasher.c[i as usize], &hasher.p);
            let mask2 = mask.mul_mod(&mask, &hasher.p);
            let mask4 = mask2.mul_mod(&mask2, &hasher.p);
            let mask = mask4.mul_mod(&mask, &hasher.p);
    
            let temp = last_r;
            last_r = last_l.add_mod(&mask, &hasher.p);
            last_l = temp;
        }
    
        (last_l, last_r)
    }

    pub fn mimc_sponge(left: &Uint256, right: &Uint256, k: &Uint256) -> Uint256 {
        let mut last_r = left.clone();
        let mut last_l = right.clone();
    
        for _ in 0..Hasher::default().n_rounds {
            let (new_last_r, new_last_l) = Hasher::mimc_feistel(&last_r, &last_l, &k);
    
            last_r = new_last_r.add_mod(&Uint256::new(1), &Hasher::default().p);
            last_l = new_last_l.clone();
        }
    
        last_r
    }
}