arnaucube
arnaucube/mimc-rsPublic Self-hosted repository
mimc-rs/src/lib.rs
src/lib.rsRaw
  1extern crate rand;
  2#[macro_use]
  3extern crate ff;
  4use ff::*;
  5
  6#[derive(PrimeField)]
  7#[PrimeFieldModulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617"]
  8#[PrimeFieldGenerator = "7"]
  9pub struct Fr(FrRepr);
 10
 11extern crate num;
 12extern crate num_bigint;
 13use num_bigint::{BigInt, Sign};
 14use tiny_keccak::Keccak;
 15
 16const SEED: &str = "mimc";
 17
 18pub struct Constants {
 19    n_rounds: usize,
 20    cts: Vec<Fr>,
 21}
 22
 23pub fn generate_constants(n_rounds: usize) -> Constants {
 24    let cts = get_constants(SEED, n_rounds);
 25
 26    Constants {
 27        n_rounds: n_rounds,
 28        cts: cts,
 29    }
 30}
 31
 32pub fn get_constants(seed: &str, n_rounds: usize) -> Vec<Fr> {
 33    let mut cts: Vec<Fr> = Vec::new();
 34    cts.push(Fr::zero());
 35
 36    let mut keccak = Keccak::new_keccak256();
 37    let mut h = [0u8; 32];
 38    keccak.update(seed.as_bytes());
 39    keccak.finalize(&mut h);
 40
 41    let r: BigInt = BigInt::parse_bytes(
 42        b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
 43        10,
 44    )
 45    .unwrap();
 46
 47    let mut c = BigInt::from_bytes_be(Sign::Plus, &h);
 48    for _ in 1..n_rounds {
 49        let (_, c_bytes) = c.to_bytes_be();
 50        let mut c_bytes32: [u8; 32] = [0; 32];
 51        let diff = c_bytes32.len() - c_bytes.len();
 52        c_bytes32[diff..].copy_from_slice(&c_bytes[..]);
 53
 54        let mut keccak = Keccak::new_keccak256();
 55        let mut h = [0u8; 32];
 56        keccak.update(&c_bytes[..]);
 57        keccak.finalize(&mut h);
 58        c = BigInt::from_bytes_be(Sign::Plus, &h);
 59
 60        let n = modulus(&c, &r);
 61        cts.push(Fr::from_str(&n.to_string()).unwrap());
 62    }
 63    cts
 64}
 65
 66pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt {
 67    ((a % m) + m) % m
 68}
 69
 70pub struct Mimc7 {
 71    constants: Constants,
 72}
 73
 74impl Mimc7 {
 75    pub fn new(n_rounds: usize) -> Mimc7 {
 76        Mimc7 {
 77            constants: generate_constants(n_rounds),
 78        }
 79    }
 80
 81    pub fn hash(&self, x_in: &Fr, k: &Fr) -> Fr {
 82        let mut h: Fr = Fr::zero();
 83        for i in 0..self.constants.n_rounds {
 84            let mut t: Fr;
 85            if i == 0 {
 86                t = x_in.clone();
 87                t.add_assign(k);
 88            } else {
 89                t = h.clone();
 90                t.add_assign(&k);
 91                t.add_assign(&self.constants.cts[i]);
 92            }
 93            let mut t2 = t.clone();
 94            t2.square();
 95            let mut t7 = t2.clone();
 96            t7.square();
 97            t7.mul_assign(&t2);
 98            t7.mul_assign(&t);
 99            h = t7.clone();
100        }
101        h.add_assign(&k);
102        h
103    }
104
105    pub fn multi_hash(&self, arr: Vec<Fr>, key: &Fr) -> Fr {
106        let mut r = key.clone();
107        for i in 0..arr.len() {
108            let h = self.hash(&arr[i], &r);
109            r.add_assign(&arr[i]);
110            r.add_assign(&h);
111        }
112        r
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_generate_constants() {
122        let constants = generate_constants(91);
123        assert_eq!(
124            "Fr(0x2e2ebbb178296b63d88ec198f0976ad98bc1d4eb0d921ddd2eb86cb7e70a98e5)",
125            constants.cts[1].to_string()
126        );
127    }
128
129    #[test]
130    fn test_mimc() {
131        let b1: Fr = Fr::from_str("1").unwrap();
132        let b2: Fr = Fr::from_str("2").unwrap();
133        let mimc7 = Mimc7::new(91);
134        let h1 = mimc7.hash(&b1, &b2);
135        assert_eq!(
136            h1.to_string(),
137            "Fr(0x176c6eefc3fdf8d6136002d8e6f7a885bbd1c4e3957b93ddc1ec3ae7859f1a08)"
138        );
139
140        let b3: Fr = Fr::from_str("3").unwrap();
141        let mut arr: Vec<Fr> = Vec::new();
142        arr.push(b1.clone());
143        arr.push(b2.clone());
144        arr.push(b3.clone());
145        let h1 = mimc7.multi_hash(arr, &Fr::zero());
146        assert_eq!(
147            h1.to_string(),
148            "Fr(0x25f5a6429a9764564be3955e6f56b0b9143c571528fd30a80ae6c27dc8b4a40c)"
149        );
150
151        let b12: Fr = Fr::from_str("12").unwrap();
152        let b45: Fr = Fr::from_str("45").unwrap();
153        let b78: Fr = Fr::from_str("78").unwrap();
154        let b41: Fr = Fr::from_str("41").unwrap();
155
156        let mut big_arr1: Vec<Fr> = Vec::new();
157        big_arr1.push(b12.clone());
158        let mimc7 = Mimc7::new(91);
159        let h1 = mimc7.multi_hash(big_arr1, &Fr::zero());
160        assert_eq!(
161            h1.to_string(),
162            "Fr(0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd)"
163        );
164
165        let mh2 = mimc7.hash(&b12, &b45);
166        assert_eq!(
167            mh2.to_string(),
168            "Fr(0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4)"
169        );
170
171        let mut big_arr1: Vec<Fr> = Vec::new();
172        big_arr1.push(b78.clone());
173        big_arr1.push(b41.clone());
174        let h2 = mimc7.multi_hash(big_arr1, &Fr::zero());
175        assert_eq!(
176            h2.to_string(),
177            "Fr(0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70)"
178        );
179
180        let mut big_arr1: Vec<Fr> = Vec::new();
181        big_arr1.push(b12.clone());
182        big_arr1.push(b45.clone());
183        let h1 = mimc7.multi_hash(big_arr1, &Fr::zero());
184        assert_eq!(
185            h1.to_string(),
186            "Fr(0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879)"
187        );
188
189        let mut big_arr1: Vec<Fr> = Vec::new();
190        big_arr1.push(b12.clone());
191        big_arr1.push(b45.clone());
192        big_arr1.push(b78.clone());
193        big_arr1.push(b41.clone());
194        let mimc7 = Mimc7::new(91);
195        let h1 = mimc7.multi_hash(big_arr1, &Fr::zero());
196        assert_eq!(
197            h1.to_string(),
198            "Fr(0x284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb)"
199        );
200
201        let r_1: Fr = Fr::from_str(
202            "21888242871839275222246405745257275088548364400416034343698204186575808495616",
203        )
204        .unwrap();
205
206        let mut big_arr1: Vec<Fr> = Vec::new();
207        big_arr1.push(r_1.clone());
208        let mimc7 = Mimc7::new(91);
209        let h1 = mimc7.multi_hash(big_arr1, &Fr::zero());
210        assert_eq!(
211            h1.to_string(),
212            "Fr(0x0a4fffe99225f9972ec39fd780dd084f349286c723d4dd42ad05e2e7421fef0e)"
213        );
214    }
215}