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}