arnaucube
arnaucube/mimc-rsPublic Self-hosted repository
mimc-rs/src/lib.rs
src/lib.rsRaw
  1extern crate num;
  2extern crate num_bigint;
  3extern crate num_traits;
  4
  5use tiny_keccak::Keccak;
  6
  7use num_bigint::{BigInt, Sign};
  8use num_traits::Zero;
  9
 10const SEED: &str = "mimc";
 11
 12pub struct Constants {
 13    // seed_hash: BigInt,
 14    // iv: BigInt,
 15    r: BigInt,
 16    n_rounds: i64,
 17    cts: Vec<BigInt>,
 18}
 19
 20pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt {
 21    ((a % m) + m) % m
 22}
 23
 24pub fn generate_constants() -> Constants {
 25    let r: BigInt = BigInt::parse_bytes(
 26        b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
 27        10,
 28    )
 29    .unwrap();
 30
 31    let mut keccak = Keccak::new_keccak256();
 32    let mut h = [0u8; 32];
 33    keccak.update(SEED.as_bytes());
 34    keccak.finalize(&mut h);
 35    let mut keccak = Keccak::new_keccak256();
 36    let mut h_iv = [0u8; 32];
 37    let seed_iv = format!("{}{}", SEED, "_iv");
 38    keccak.update(seed_iv.as_bytes());
 39    keccak.finalize(&mut h_iv);
 40
 41    // let seed_hash: BigInt = BigInt::from_bytes_be(Sign::Plus, &h);
 42    // let c: BigInt = BigInt::from_bytes_be(Sign::Plus, &h_iv);
 43    // let iv: BigInt = c % &r;
 44    let n_rounds: i64 = 91;
 45    let cts = get_constants(&r, SEED, n_rounds);
 46
 47    Constants {
 48        // seed_hash: seed_hash,
 49        // iv: iv,
 50        r: r,
 51        n_rounds: n_rounds,
 52        cts: cts,
 53    }
 54}
 55
 56pub fn get_constants(r: &BigInt, seed: &str, n_rounds: i64) -> Vec<BigInt> {
 57    let mut cts: Vec<BigInt> = Vec::new();
 58    cts.push(Zero::zero());
 59
 60    let mut keccak = Keccak::new_keccak256();
 61    let mut h = [0u8; 32];
 62    keccak.update(seed.as_bytes());
 63    keccak.finalize(&mut h);
 64
 65    let mut c = BigInt::from_bytes_be(Sign::Plus, &h);
 66    for _ in 1..n_rounds {
 67        let (_, c_bytes) = c.to_bytes_be();
 68        let mut c_bytes32: [u8;32] = [0;32];
 69        let diff = c_bytes32.len() - c_bytes.len();
 70        c_bytes32[diff..].copy_from_slice(&c_bytes[..]);
 71
 72        let mut keccak = Keccak::new_keccak256();
 73        let mut h = [0u8; 32];
 74        keccak.update(&c_bytes[..]);
 75        keccak.finalize(&mut h);
 76        c = BigInt::from_bytes_be(Sign::Plus, &h);
 77
 78        let n = modulus(&c, &r);
 79        cts.push(n);
 80    }
 81    // let l = cts.len();
 82    // cts[l-1] = Zero::zero();
 83    cts
 84}
 85
 86pub fn mimc7_hash_generic(r: &BigInt, x_in: &BigInt, k: &BigInt, n_rounds: i64) -> BigInt {
 87    let cts = get_constants(r, SEED, n_rounds);
 88    let mut h: BigInt = Zero::zero();
 89    for i in 0..n_rounds as usize {
 90        let mut t: BigInt;
 91        if i == 0 {
 92            t = x_in + k;
 93        } else {
 94            t = h + k + &cts[i];
 95        }
 96        t = modulus(&t, &r);
 97        let t2 = &t * &t;
 98        let t4 = &t2 * &t2;
 99        h = (t4 * t2) * t;
100        h = modulus(&h, &r);
101    }
102    modulus(&(h + k), &r)
103}
104
105pub fn hash_generic(iv: BigInt, arr: Vec<BigInt>, r: BigInt, n_rounds: i64) -> BigInt {
106    let mut h: BigInt = iv;
107    for i in 0..arr.len() {
108        h = mimc7_hash_generic(&r, &h, &arr[i], n_rounds);
109    }
110    h
111}
112
113pub fn check_bigint_in_field(a: &BigInt, q: &BigInt) -> bool {
114    if a >= q {
115        return false;
116    }
117    true
118}
119
120pub fn check_bigint_array_in_field(arr: &Vec<BigInt>, q: &BigInt) -> bool {
121    for a in arr {
122        if !check_bigint_in_field(a, &q) {
123            return false;
124        }
125    }
126    true
127}
128
129pub struct Mimc7 {
130    constants: Constants,
131}
132
133impl Mimc7 {
134    pub fn new() -> Mimc7 {
135        Mimc7 {
136            constants: generate_constants(),
137        }
138    }
139
140    pub fn hash(&self, arr: Vec<BigInt>) -> Result<BigInt, String> {
141        // check if arr elements are inside the Finite Field over R
142        if !check_bigint_array_in_field(&arr, &self.constants.r) {
143            return Err("elements not inside the finite field over R".to_string());
144        }
145        let mut h: BigInt = Zero::zero();
146        for i in 0..arr.len() {
147            h = &h + &arr[i] + self.mimc7_hash(&arr[i], &h);
148            h = modulus(&h, &self.constants.r)
149        }
150        Ok(modulus(&h, &self.constants.r))
151    }
152
153    pub fn mimc7_hash(&self, x_in: &BigInt, k: &BigInt) -> BigInt {
154        let mut h: BigInt = Zero::zero();
155        for i in 0..self.constants.n_rounds as usize {
156            let t: BigInt;
157            if i == 0 {
158                t = x_in + k;
159            } else {
160                t = h + k + &self.constants.cts[i];
161            }
162            let t2 = &t * &t;
163            let t4 = &t2 * &t2;
164            h = (t4 * t2) * t;
165            h = modulus(&h, &self.constants.r);
166        }
167        modulus(&(h + k), &self.constants.r)
168    }
169
170    pub fn hash_bytes(&self, b: Vec<u8>) -> Result<BigInt, String> {
171        let n = 31;
172        let mut ints: Vec<BigInt> = Vec::new();
173        for i in 0..b.len() / n {
174            let v: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[n * i..n * (i + 1)]);
175            ints.push(v);
176        }
177        if b.len() % n != 0 {
178            let v: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[(b.len() / n) * n..]);
179            ints.push(v);
180        }
181        self.hash(ints)
182    }
183}
184
185#[cfg(test)]
186mod tests {
187    use super::*;
188    use rustc_hex::ToHex;
189
190    #[test]
191    fn test_sha3() {
192        let mut keccak = Keccak::new_keccak256();
193        let mut res = [0u8; 32];
194        keccak.update(SEED.as_bytes());
195        keccak.finalize(&mut res);
196        assert_eq!(
197            res.to_hex(),
198            "b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e"
199        );
200
201        let mut keccak = Keccak::new_keccak256();
202        let mut res = [0u8; 32];
203        keccak.update(SEED.as_bytes());
204        keccak.finalize(&mut res);
205        let c = BigInt::from_bytes_be(Sign::Plus, &res);
206        assert_eq!(
207            c.to_string(),
208            "82724731331859054037315113496710413141112897654334566532528783843265082629790"
209        );
210    }
211    #[test]
212    fn test_generate_constants() {
213        let constants = generate_constants();
214        assert_eq!(
215            "20888961410941983456478427210666206549300505294776164667214940546594746570981",
216            constants.cts[1].to_string()
217        );
218    }
219
220    #[test]
221    fn test_mimc7_generic() {
222        let b1: BigInt = BigInt::parse_bytes(b"1", 10).unwrap();
223        let b2: BigInt = BigInt::parse_bytes(b"2", 10).unwrap();
224        let constants = generate_constants();
225        let h1 = mimc7_hash_generic(&constants.r, &b1, &b2, 91);
226        assert_eq!(
227            h1.to_string(),
228            "10594780656576967754230020536574539122676596303354946869887184401991294982664"
229        );
230    }
231
232    #[test]
233    fn test_check_bigint_in_field() {
234        let r_0: BigInt = BigInt::parse_bytes(
235            b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
236            10,
237        )
238        .unwrap();
239
240        let mut big_arr0: Vec<BigInt> = Vec::new();
241        big_arr0.push(r_0.clone());
242        let mimc7 = Mimc7::new();
243        let h0 = mimc7.hash(big_arr0);
244        assert_eq!(h0.is_err(), true);
245
246        let r_1: BigInt = BigInt::parse_bytes(
247            b"21888242871839275222246405745257275088548364400416034343698204186575808495616",
248            10,
249        )
250        .unwrap();
251
252        let mut big_arr1: Vec<BigInt> = Vec::new();
253        big_arr1.push(r_1.clone());
254        let mimc7 = Mimc7::new();
255        let h1 = mimc7.hash(big_arr1);
256        assert_eq!(h1.is_err(), false);
257        assert_eq!(
258            h1.unwrap().to_string(),
259            "4664475646327377862961796881776103845487084034023211145221745907673012891406"
260        );
261    }
262
263    #[test]
264    fn test_mimc7() {
265        let b12: BigInt = BigInt::parse_bytes(b"12", 10).unwrap();
266        let b45: BigInt = BigInt::parse_bytes(b"45", 10).unwrap();
267        let b78: BigInt = BigInt::parse_bytes(b"78", 10).unwrap();
268        let b41: BigInt = BigInt::parse_bytes(b"41", 10).unwrap();
269
270        let mut big_arr1: Vec<BigInt> = Vec::new();
271        big_arr1.push(b12.clone());
272        let mimc7 = Mimc7::new();
273        let h1 = mimc7.hash(big_arr1).unwrap();
274        let (_, h1_bytes) = h1.to_bytes_be();
275        assert_eq!(
276            h1_bytes.to_hex(),
277            "237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd"
278        );
279
280        let mh2 = mimc7.mimc7_hash(&b12, &b45);
281        let (_, mh2_bytes) = mh2.to_bytes_be();
282        assert_eq!(
283            mh2_bytes.to_hex(),
284            "2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4"
285        );
286
287        let mut big_arr2: Vec<BigInt> = Vec::new();
288        big_arr2.push(b78.clone());
289        big_arr2.push(b41.clone());
290        let h2 = mimc7.hash(big_arr2).unwrap();
291        let (_, h2_bytes) = h2.to_bytes_be();
292        assert_eq!(
293            h2_bytes.to_hex(),
294            "067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70"
295        );
296
297        let mut big_arr2: Vec<BigInt> = Vec::new();
298        big_arr2.push(b12.clone());
299        big_arr2.push(b45.clone());
300        let h1 = mimc7.hash(big_arr2).unwrap();
301        let (_, h1_bytes) = h1.to_bytes_be();
302        assert_eq!(
303            h1_bytes.to_hex(),
304            "15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879"
305        );
306
307        let mut big_arr1: Vec<BigInt> = Vec::new();
308        big_arr1.push(b12.clone());
309        big_arr1.push(b45.clone());
310        big_arr1.push(b78.clone());
311        big_arr1.push(b41.clone());
312        let mimc7 = Mimc7::new();
313        let h1 = mimc7.hash(big_arr1).unwrap();
314        let (_, h1_bytes) = h1.to_bytes_be();
315        assert_eq!(
316            h1_bytes.to_hex(),
317            "284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb"
318        );
319    }
320    #[test]
321    fn test_hash_bytes() {
322        let msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
323        let mimc7 = Mimc7::new();
324        let h = mimc7.hash_bytes(msg.as_bytes().to_vec()).unwrap();
325        assert_eq!(
326            h.to_string(),
327            "16855787120419064316734350414336285711017110414939748784029922801367685456065"
328        );
329    }
330}