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 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 n_rounds: i64 = 91;
45 let cts = get_constants(&r, SEED, n_rounds);
46
47 Constants {
48 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 mut keccak = Keccak::new_keccak256();
68 let mut h = [0u8; 32];
69 let (_, c_bytes) = c.to_bytes_be();
70 keccak.update(&c_bytes[..]);
71 keccak.finalize(&mut h);
72 c = BigInt::from_bytes_be(Sign::Plus, &h);
73 let n = modulus(&c, &r);
74 cts.push(n);
75 }
76 cts
77}
78
79pub fn mimc7_hash_generic(r: &BigInt, x_in: &BigInt, k: &BigInt, n_rounds: i64) -> BigInt {
80 let cts = get_constants(r, SEED, n_rounds);
81 let mut h: BigInt = Zero::zero();
82 for i in 0..n_rounds as usize {
83 let mut t: BigInt;
84 if i == 0 {
85 t = x_in + k;
86 } else {
87 t = h + k + &cts[i];
88 }
89 t = modulus(&t, &r);
90 let t2 = &t * &t;
91 let t4 = &t2 * &t2;
92 h = (t4 * t2) * t;
93 h = modulus(&h, &r);
94 }
95 modulus(&(h + k), &r)
96}
97
98pub fn hash_generic(iv: BigInt, arr: Vec<BigInt>, r: BigInt, n_rounds: i64) -> BigInt {
99 let mut h: BigInt = iv;
100 for i in 0..arr.len() {
101 h = mimc7_hash_generic(&r, &h, &arr[i], n_rounds);
102 }
103 h
104}
105
106pub fn check_bigint_in_field(a: &BigInt, q: &BigInt) -> bool {
107 if a >= q {
108 return false;
109 }
110 true
111}
112
113pub fn check_bigint_array_in_field(arr: &Vec<BigInt>, q: &BigInt) -> bool {
114 for a in arr {
115 if !check_bigint_in_field(a, &q) {
116 return false;
117 }
118 }
119 true
120}
121
122pub struct Mimc7 {
123 constants: Constants,
124}
125
126impl Mimc7 {
127 pub fn new() -> Mimc7 {
128 Mimc7 {
129 constants: generate_constants(),
130 }
131 }
132
133 pub fn hash(&self, arr: Vec<BigInt>) -> Result<BigInt, String> {
134 if !check_bigint_array_in_field(&arr, &self.constants.r) {
136 return Err("elements not inside the finite field over R".to_string());
137 }
138 let mut h: BigInt = Zero::zero();
139 for i in 0..arr.len() {
140 h = &h + &arr[i] + self.mimc7_hash(&arr[i], &h);
141 h = modulus(&h, &self.constants.r)
142 }
143 Ok(modulus(&h, &self.constants.r))
144 }
145
146 pub fn mimc7_hash(&self, x_in: &BigInt, k: &BigInt) -> BigInt {
147 let mut h: BigInt = Zero::zero();
148 for i in 0..self.constants.n_rounds as usize {
149 let t: BigInt;
150 if i == 0 {
151 t = x_in + k;
152 } else {
153 t = h + k + &self.constants.cts[i];
154 }
155 let t2 = &t * &t;
156 let t4 = &t2 * &t2;
157 h = (t4 * t2) * t;
158 h = modulus(&h, &self.constants.r);
159 }
160 modulus(&(h + k), &self.constants.r)
161 }
162
163 pub fn hash_bytes(&self, b: Vec<u8>) -> Result<BigInt, String> {
164 let n = 31;
165 let mut ints: Vec<BigInt> = Vec::new();
166 for i in 0..b.len() / n {
167 let v: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[n * i..n * (i + 1)]);
168 ints.push(v);
169 }
170 if b.len() % n != 0 {
171 let v: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[(b.len() / n) * n..]);
172 ints.push(v);
173 }
174 self.hash(ints)
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use rustc_hex::ToHex;
182
183 #[test]
184 fn test_sha3() {
185 let mut keccak = Keccak::new_keccak256();
186 let mut res = [0u8; 32];
187 keccak.update(SEED.as_bytes());
188 keccak.finalize(&mut res);
189 assert_eq!(
190 res.to_hex(),
191 "b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e"
192 );
193
194 let mut keccak = Keccak::new_keccak256();
195 let mut res = [0u8; 32];
196 keccak.update(SEED.as_bytes());
197 keccak.finalize(&mut res);
198 let c = BigInt::from_bytes_be(Sign::Plus, &res);
199 assert_eq!(
200 c.to_string(),
201 "82724731331859054037315113496710413141112897654334566532528783843265082629790"
202 );
203 }
204 #[test]
205 fn test_generate_constants() {
206 let constants = generate_constants();
207 assert_eq!(
208 "20888961410941983456478427210666206549300505294776164667214940546594746570981",
209 constants.cts[1].to_string()
210 );
211 }
212
213 #[test]
214 fn test_mimc7_generic() {
215 let b1: BigInt = BigInt::parse_bytes(b"1", 10).unwrap();
216 let b2: BigInt = BigInt::parse_bytes(b"2", 10).unwrap();
217 let constants = generate_constants();
218 let h1 = mimc7_hash_generic(&constants.r, &b1, &b2, 91);
219 assert_eq!(
220 h1.to_string(),
221 "10594780656576967754230020536574539122676596303354946869887184401991294982664"
222 );
223 }
224
225 #[test]
226 fn test_check_bigint_in_field() {
227 let r_0: BigInt = BigInt::parse_bytes(
228 b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
229 10,
230 )
231 .unwrap();
232
233 let mut big_arr0: Vec<BigInt> = Vec::new();
234 big_arr0.push(r_0.clone());
235 let mimc7 = Mimc7::new();
236 let h0 = mimc7.hash(big_arr0);
237 assert_eq!(h0.is_err(), true);
238
239 let r_1: BigInt = BigInt::parse_bytes(
240 b"21888242871839275222246405745257275088548364400416034343698204186575808495616",
241 10,
242 )
243 .unwrap();
244
245 let mut big_arr1: Vec<BigInt> = Vec::new();
246 big_arr1.push(r_1.clone());
247 let mimc7 = Mimc7::new();
248 let h1 = mimc7.hash(big_arr1);
249 assert_eq!(h1.is_err(), false);
250 assert_eq!(
251 h1.unwrap().to_string(),
252 "4664475646327377862961796881776103845487084034023211145221745907673012891406"
253 );
254 }
255
256 #[test]
257 fn test_mimc7() {
258 let b12: BigInt = BigInt::parse_bytes(b"12", 10).unwrap();
259 let b45: BigInt = BigInt::parse_bytes(b"45", 10).unwrap();
260 let b78: BigInt = BigInt::parse_bytes(b"78", 10).unwrap();
261 let b41: BigInt = BigInt::parse_bytes(b"41", 10).unwrap();
262
263 let mut big_arr1: Vec<BigInt> = Vec::new();
264 big_arr1.push(b12.clone());
265 let mimc7 = Mimc7::new();
266 let h1 = mimc7.hash(big_arr1).unwrap();
267 let (_, h1_bytes) = h1.to_bytes_be();
268 assert_eq!(
269 h1_bytes.to_hex(),
270 "237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd"
271 );
272
273 let mh2 = mimc7.mimc7_hash(&b12, &b45);
274 let (_, mh2_bytes) = mh2.to_bytes_be();
275 assert_eq!(
276 mh2_bytes.to_hex(),
277 "2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4"
278 );
279
280 let mut big_arr2: Vec<BigInt> = Vec::new();
281 big_arr2.push(b78.clone());
282 big_arr2.push(b41.clone());
283 let h2 = mimc7.hash(big_arr2).unwrap();
284 let (_, h2_bytes) = h2.to_bytes_be();
285 assert_eq!(
286 h2_bytes.to_hex(),
287 "067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70"
288 );
289
290 let mut big_arr2: Vec<BigInt> = Vec::new();
291 big_arr2.push(b12.clone());
292 big_arr2.push(b45.clone());
293 let h1 = mimc7.hash(big_arr2).unwrap();
294 let (_, h1_bytes) = h1.to_bytes_be();
295 assert_eq!(
296 h1_bytes.to_hex(),
297 "15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879"
298 );
299
300 let mut big_arr1: Vec<BigInt> = Vec::new();
301 big_arr1.push(b12.clone());
302 big_arr1.push(b45.clone());
303 big_arr1.push(b78.clone());
304 big_arr1.push(b41.clone());
305 let mimc7 = Mimc7::new();
306 let h1 = mimc7.hash(big_arr1).unwrap();
307 let (_, h1_bytes) = h1.to_bytes_be();
308 assert_eq!(
309 h1_bytes.to_hex(),
310 "284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb"
311 );
312 }
313 #[test]
314 fn test_hash_bytes() {
315 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.";
316 let mimc7 = Mimc7::new();
317 let h = mimc7.hash_bytes(msg.as_bytes().to_vec()).unwrap();
318 assert_eq!(
319 h.to_string(),
320 "16855787120419064316734350414336285711017110414939748784029922801367685456065"
321 );
322 }
323}