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 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 struct Mimc7 {
107 constants: Constants,
108}
109
110impl Mimc7 {
111 pub fn new() -> Mimc7 {
112 Mimc7 {
113 constants: generate_constants(),
114 }
115 }
116
117 pub fn hash(&self, arr: Vec<BigInt>) -> BigInt {
118 // TODO check if arr elements are inside the Finite Field over R
119 let mut h: BigInt = Zero::zero();
120 for i in 0..arr.len() {
121 h = &h + &arr[i] + self.mimc7_hash(&arr[i], &h);
122 h = modulus(&h, &self.constants.r)
123 }
124 modulus(&h, &self.constants.r)
125 }
126
127 pub fn mimc7_hash(&self, x_in: &BigInt, k: &BigInt) -> BigInt {
128 let mut h: BigInt = Zero::zero();
129 for i in 0..self.constants.n_rounds as usize {
130 let t: BigInt;
131 if i == 0 {
132 t = x_in + k;
133 } else {
134 t = h + k + &self.constants.cts[i];
135 }
136 let t2 = &t * &t;
137 let t4 = &t2 * &t2;
138 h = (t4 * t2) * t;
139 h = modulus(&h, &self.constants.r);
140 }
141 modulus(&(h + k), &self.constants.r)
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148 use rustc_hex::ToHex;
149
150 #[test]
151 fn test_sha3() {
152 let mut keccak = Keccak::new_keccak256();
153 let mut res = [0u8; 32];
154 keccak.update(SEED.as_bytes());
155 keccak.finalize(&mut res);
156 assert_eq!(
157 res.to_hex(),
158 "b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e"
159 );
160
161 let mut keccak = Keccak::new_keccak256();
162 let mut res = [0u8; 32];
163 keccak.update(SEED.as_bytes());
164 keccak.finalize(&mut res);
165 let c = BigInt::from_bytes_be(Sign::Plus, &res);
166 assert_eq!(
167 c.to_string(),
168 "82724731331859054037315113496710413141112897654334566532528783843265082629790"
169 );
170 }
171 #[test]
172 fn test_generate_constants() {
173 let constants = generate_constants();
174 assert_eq!(
175 "20888961410941983456478427210666206549300505294776164667214940546594746570981",
176 constants.cts[1].to_string()
177 );
178 }
179
180 #[test]
181 fn test_mimc7_generic() {
182 let b1: BigInt = BigInt::parse_bytes(b"1", 10).unwrap();
183 let b2: BigInt = BigInt::parse_bytes(b"2", 10).unwrap();
184 let constants = generate_constants();
185 let h1 = mimc7_hash_generic(&constants.r, &b1, &b2, 91);
186 assert_eq!(
187 h1.to_string(),
188 "10594780656576967754230020536574539122676596303354946869887184401991294982664"
189 );
190 }
191 #[test]
192 fn test_mimc7() {
193 let b12: BigInt = BigInt::parse_bytes(b"12", 10).unwrap();
194 let b45: BigInt = BigInt::parse_bytes(b"45", 10).unwrap();
195 let b78: BigInt = BigInt::parse_bytes(b"78", 10).unwrap();
196 let b41: BigInt = BigInt::parse_bytes(b"41", 10).unwrap();
197
198 let mut big_arr1: Vec<BigInt> = Vec::new();
199 big_arr1.push(b12.clone());
200 let mimc7 = Mimc7::new();
201 let h1 = mimc7.hash(big_arr1);
202 let (_, h1_bytes) = h1.to_bytes_be();
203 assert_eq!(
204 h1_bytes.to_hex(),
205 "237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd"
206 );
207
208 let mh2 = mimc7.mimc7_hash(&b12, &b45);
209 let (_, mh2_bytes) = mh2.to_bytes_be();
210 assert_eq!(
211 mh2_bytes.to_hex(),
212 "2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4"
213 );
214
215 let mut big_arr2: Vec<BigInt> = Vec::new();
216 big_arr2.push(b78.clone());
217 big_arr2.push(b41.clone());
218 let h2 = mimc7.hash(big_arr2);
219 let (_, h2_bytes) = h2.to_bytes_be();
220 assert_eq!(
221 h2_bytes.to_hex(),
222 "067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70"
223 );
224
225 let mut big_arr2: Vec<BigInt> = Vec::new();
226 big_arr2.push(b12.clone());
227 big_arr2.push(b45.clone());
228 let h1 = mimc7.hash(big_arr2);
229 let (_, h1_bytes) = h1.to_bytes_be();
230 assert_eq!(
231 h1_bytes.to_hex(),
232 "15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879"
233 );
234
235 let mut big_arr1: Vec<BigInt> = Vec::new();
236 big_arr1.push(b12.clone());
237 big_arr1.push(b45.clone());
238 big_arr1.push(b78.clone());
239 big_arr1.push(b41.clone());
240 let mimc7 = Mimc7::new();
241 let h1 = mimc7.hash(big_arr1);
242 let (_, h1_bytes) = h1.to_bytes_be();
243 assert_eq!(
244 h1_bytes.to_hex(),
245 "284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb"
246 );
247 }
248}