mimc-rs/src/lib.rs
src/lib.rsRaw
1extern crate rand;
2#[macro_use]
3extern crate ff;
4use ff::*;
5
6#[derive(PrimeField)]
7#[PrimeFieldModulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617"]
8#[PrimeFieldGenerator = "7"]
9pub struct Fr(FrRepr);
10
11extern crate num;
12extern crate num_bigint;
13use num_bigint::{BigInt, Sign};
14use tiny_keccak::Keccak;
15
16const SEED: &str = "mimc";
17
18pub struct Constants {
19 n_rounds: usize,
20 cts: Vec<Fr>,
21}
22
23pub fn generate_constants(n_rounds: usize) -> Constants {
24 let cts = get_constants(SEED, n_rounds);
25
26 Constants {
27 n_rounds: n_rounds,
28 cts: cts,
29 }
30}
31
32pub fn get_constants(seed: &str, n_rounds: usize) -> Vec<Fr> {
33 let mut cts: Vec<Fr> = Vec::new();
34 cts.push(Fr::zero());
35
36 let mut keccak = Keccak::new_keccak256();
37 let mut h = [0u8; 32];
38 keccak.update(seed.as_bytes());
39 keccak.finalize(&mut h);
40
41 let r: BigInt = BigInt::parse_bytes(
42 b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
43 10,
44 )
45 .unwrap();
46
47 let mut c = BigInt::from_bytes_be(Sign::Plus, &h);
48 for _ in 1..n_rounds {
49 let (_, c_bytes) = c.to_bytes_be();
50 let mut c_bytes32: [u8; 32] = [0; 32];
51 let diff = c_bytes32.len() - c_bytes.len();
52 c_bytes32[diff..].copy_from_slice(&c_bytes[..]);
53
54 let mut keccak = Keccak::new_keccak256();
55 let mut h = [0u8; 32];
56 keccak.update(&c_bytes[..]);
57 keccak.finalize(&mut h);
58 c = BigInt::from_bytes_be(Sign::Plus, &h);
59
60 let n = modulus(&c, &r);
61 cts.push(Fr::from_str(&n.to_string()).unwrap());
62 }
63 cts
64}
65
66pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt {
67 ((a % m) + m) % m
68}
69
70pub struct Mimc7 {
71 constants: Constants,
72}
73
74impl Mimc7 {
75 pub fn new(n_rounds: usize) -> Mimc7 {
76 Mimc7 {
77 constants: generate_constants(n_rounds),
78 }
79 }
80
81 pub fn hash(&self, x_in: &Fr, k: &Fr) -> Fr {
82 let mut h: Fr = Fr::zero();
83 for i in 0..self.constants.n_rounds {
84 let mut t: Fr;
85 if i == 0 {
86 t = x_in.clone();
87 t.add_assign(k);
88 } else {
89 t = h.clone();
90 t.add_assign(&k);
91 t.add_assign(&self.constants.cts[i]);
92 }
93 let mut t2 = t.clone();
94 t2.square();
95 let mut t7 = t2.clone();
96 t7.square();
97 t7.mul_assign(&t2);
98 t7.mul_assign(&t);
99 h = t7.clone();
100 }
101 h.add_assign(&k);
102 h
103 }
104
105 pub fn multi_hash(&self, arr: Vec<Fr>, key: &Fr) -> Fr {
106 let mut r = key.clone();
107 for i in 0..arr.len() {
108 let h = self.hash(&arr[i], &r);
109 r.add_assign(&arr[i]);
110 r.add_assign(&h);
111 }
112 r
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn test_generate_constants() {
122 let constants = generate_constants(91);
123 assert_eq!(
124 "Fr(0x2e2ebbb178296b63d88ec198f0976ad98bc1d4eb0d921ddd2eb86cb7e70a98e5)",
125 constants.cts[1].to_string()
126 );
127 }
128
129 #[test]
130 fn test_mimc() {
131 let b1: Fr = Fr::from_str("1").unwrap();
132 let b2: Fr = Fr::from_str("2").unwrap();
133 let mimc7 = Mimc7::new(91);
134 let h1 = mimc7.hash(&b1, &b2);
135 assert_eq!(
136 h1.to_string(),
137 "Fr(0x176c6eefc3fdf8d6136002d8e6f7a885bbd1c4e3957b93ddc1ec3ae7859f1a08)"
138 );
139
140 let b3: Fr = Fr::from_str("3").unwrap();
141 let mut arr: Vec<Fr> = Vec::new();
142 arr.push(b1.clone());
143 arr.push(b2.clone());
144 arr.push(b3.clone());
145 let h1 = mimc7.multi_hash(arr, &Fr::zero());
146 assert_eq!(
147 h1.to_string(),
148 "Fr(0x25f5a6429a9764564be3955e6f56b0b9143c571528fd30a80ae6c27dc8b4a40c)"
149 );
150
151 let b12: Fr = Fr::from_str("12").unwrap();
152 let b45: Fr = Fr::from_str("45").unwrap();
153 let b78: Fr = Fr::from_str("78").unwrap();
154 let b41: Fr = Fr::from_str("41").unwrap();
155
156 let mut big_arr1: Vec<Fr> = Vec::new();
157 big_arr1.push(b12.clone());
158 let mimc7 = Mimc7::new(91);
159 let h1 = mimc7.multi_hash(big_arr1, &Fr::zero());
160 assert_eq!(
161 h1.to_string(),
162 "Fr(0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd)"
163 );
164
165 let mh2 = mimc7.hash(&b12, &b45);
166 assert_eq!(
167 mh2.to_string(),
168 "Fr(0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4)"
169 );
170
171 let mut big_arr1: Vec<Fr> = Vec::new();
172 big_arr1.push(b78.clone());
173 big_arr1.push(b41.clone());
174 let h2 = mimc7.multi_hash(big_arr1, &Fr::zero());
175 assert_eq!(
176 h2.to_string(),
177 "Fr(0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70)"
178 );
179
180 let mut big_arr1: Vec<Fr> = Vec::new();
181 big_arr1.push(b12.clone());
182 big_arr1.push(b45.clone());
183 let h1 = mimc7.multi_hash(big_arr1, &Fr::zero());
184 assert_eq!(
185 h1.to_string(),
186 "Fr(0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879)"
187 );
188
189 let mut big_arr1: Vec<Fr> = Vec::new();
190 big_arr1.push(b12.clone());
191 big_arr1.push(b45.clone());
192 big_arr1.push(b78.clone());
193 big_arr1.push(b41.clone());
194 let mimc7 = Mimc7::new(91);
195 let h1 = mimc7.multi_hash(big_arr1, &Fr::zero());
196 assert_eq!(
197 h1.to_string(),
198 "Fr(0x284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb)"
199 );
200
201 let r_1: Fr = Fr::from_str(
202 "21888242871839275222246405745257275088548364400416034343698204186575808495616",
203 )
204 .unwrap();
205
206 let mut big_arr1: Vec<Fr> = Vec::new();
207 big_arr1.push(r_1.clone());
208 let mimc7 = Mimc7::new(91);
209 let h1 = mimc7.multi_hash(big_arr1, &Fr::zero());
210 assert_eq!(
211 h1.to_string(),
212 "Fr(0x0a4fffe99225f9972ec39fd780dd084f349286c723d4dd42ad05e2e7421fef0e)"
213 );
214 }
215}