extern crate rand; #[macro_use] extern crate ff; use ff::*; #[derive(PrimeField)] #[PrimeFieldModulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617"] #[PrimeFieldGenerator = "7"] pub struct Fr(FrRepr); extern crate num; extern crate num_bigint; use num_bigint::{BigInt, Sign}; use tiny_keccak::Keccak; const SEED: &str = "mimc"; pub struct Constants { n_rounds: usize, cts: Vec, } pub fn generate_constants(n_rounds: usize) -> Constants { let cts = get_constants(SEED, n_rounds); Constants { n_rounds: n_rounds, cts: cts, } } pub fn get_constants(seed: &str, n_rounds: usize) -> Vec { let mut cts: Vec = Vec::new(); cts.push(Fr::zero()); let mut keccak = Keccak::new_keccak256(); let mut h = [0u8; 32]; keccak.update(seed.as_bytes()); keccak.finalize(&mut h); let r: BigInt = BigInt::parse_bytes( b"21888242871839275222246405745257275088548364400416034343698204186575808495617", 10, ) .unwrap(); let mut c = BigInt::from_bytes_be(Sign::Plus, &h); for _ in 1..n_rounds { let (_, c_bytes) = c.to_bytes_be(); let mut c_bytes32: [u8; 32] = [0; 32]; let diff = c_bytes32.len() - c_bytes.len(); c_bytes32[diff..].copy_from_slice(&c_bytes[..]); let mut keccak = Keccak::new_keccak256(); let mut h = [0u8; 32]; keccak.update(&c_bytes[..]); keccak.finalize(&mut h); c = BigInt::from_bytes_be(Sign::Plus, &h); let n = modulus(&c, &r); cts.push(Fr::from_str(&n.to_string()).unwrap()); } cts } pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt { ((a % m) + m) % m } pub struct Mimc7 { constants: Constants, } impl Mimc7 { pub fn new(n_rounds: usize) -> Mimc7 { Mimc7 { constants: generate_constants(n_rounds), } } pub fn hash(&self, x_in: &Fr, k: &Fr) -> Fr { let mut h: Fr = Fr::zero(); for i in 0..self.constants.n_rounds { let mut t: Fr; if i == 0 { t = x_in.clone(); t.add_assign(k); } else { t = h.clone(); t.add_assign(&k); t.add_assign(&self.constants.cts[i]); } let mut t2 = t.clone(); t2.square(); let mut t7 = t2.clone(); t7.square(); t7.mul_assign(&t2); t7.mul_assign(&t); h = t7.clone(); } h.add_assign(&k); h } pub fn multi_hash(&self, arr: Vec, key: &Fr) -> Fr { let mut r = key.clone(); for i in 0..arr.len() { let h = self.hash(&arr[i], &r); r.add_assign(&arr[i]); r.add_assign(&h); } r } } #[cfg(test)] mod tests { use super::*; #[test] fn test_generate_constants() { let constants = generate_constants(91); assert_eq!( "Fr(0x2e2ebbb178296b63d88ec198f0976ad98bc1d4eb0d921ddd2eb86cb7e70a98e5)", constants.cts[1].to_string() ); } #[test] fn test_mimc() { let b1: Fr = Fr::from_str("1").unwrap(); let b2: Fr = Fr::from_str("2").unwrap(); let mimc7 = Mimc7::new(91); let h1 = mimc7.hash(&b1, &b2); assert_eq!( h1.to_string(), "Fr(0x176c6eefc3fdf8d6136002d8e6f7a885bbd1c4e3957b93ddc1ec3ae7859f1a08)" ); let b3: Fr = Fr::from_str("3").unwrap(); let mut arr: Vec = Vec::new(); arr.push(b1.clone()); arr.push(b2.clone()); arr.push(b3.clone()); let h1 = mimc7.multi_hash(arr, &Fr::zero()); assert_eq!( h1.to_string(), "Fr(0x25f5a6429a9764564be3955e6f56b0b9143c571528fd30a80ae6c27dc8b4a40c)" ); let b12: Fr = Fr::from_str("12").unwrap(); let b45: Fr = Fr::from_str("45").unwrap(); let b78: Fr = Fr::from_str("78").unwrap(); let b41: Fr = Fr::from_str("41").unwrap(); let mut big_arr1: Vec = Vec::new(); big_arr1.push(b12.clone()); let mimc7 = Mimc7::new(91); let h1 = mimc7.multi_hash(big_arr1, &Fr::zero()); assert_eq!( h1.to_string(), "Fr(0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd)" ); let mh2 = mimc7.hash(&b12, &b45); assert_eq!( mh2.to_string(), "Fr(0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4)" ); let mut big_arr1: Vec = Vec::new(); big_arr1.push(b78.clone()); big_arr1.push(b41.clone()); let h2 = mimc7.multi_hash(big_arr1, &Fr::zero()); assert_eq!( h2.to_string(), "Fr(0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70)" ); let mut big_arr1: Vec = Vec::new(); big_arr1.push(b12.clone()); big_arr1.push(b45.clone()); let h1 = mimc7.multi_hash(big_arr1, &Fr::zero()); assert_eq!( h1.to_string(), "Fr(0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879)" ); let mut big_arr1: Vec = Vec::new(); big_arr1.push(b12.clone()); big_arr1.push(b45.clone()); big_arr1.push(b78.clone()); big_arr1.push(b41.clone()); let mimc7 = Mimc7::new(91); let h1 = mimc7.multi_hash(big_arr1, &Fr::zero()); assert_eq!( h1.to_string(), "Fr(0x284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb)" ); let r_1: Fr = Fr::from_str( "21888242871839275222246405745257275088548364400416034343698204186575808495616", ) .unwrap(); let mut big_arr1: Vec = Vec::new(); big_arr1.push(r_1.clone()); let mimc7 = Mimc7::new(91); let h1 = mimc7.multi_hash(big_arr1, &Fr::zero()); assert_eq!( h1.to_string(), "Fr(0x0a4fffe99225f9972ec39fd780dd084f349286c723d4dd42ad05e2e7421fef0e)" ); } }