You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
7.1 KiB

4 years ago
  1. extern crate num;
  2. extern crate num_bigint;
  3. extern crate num_traits;
  4. use tiny_keccak::Keccak;
  5. use num_bigint::{BigInt, Sign};
  6. use num_traits::Zero;
  7. const SEED: &str = "mimc";
  8. pub struct Constants {
  9. seed_hash: BigInt,
  10. iv: BigInt,
  11. r: BigInt,
  12. n_rounds: i64,
  13. cts: Vec<BigInt>,
  14. }
  15. pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt {
  16. ((a % m) + m) % m
  17. }
  18. pub fn generate_constants() -> Constants {
  19. let r: BigInt = BigInt::parse_bytes(
  20. b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
  21. 10,
  22. )
  23. .unwrap();
  24. let mut keccak = Keccak::new_keccak256();
  25. let mut h = [0u8; 32];
  26. keccak.update(SEED.as_bytes());
  27. keccak.finalize(&mut h);
  28. let mut keccak = Keccak::new_keccak256();
  29. let mut h_iv = [0u8; 32];
  30. let seed_iv = format!("{}{}", SEED, "_iv");
  31. keccak.update(seed_iv.as_bytes());
  32. keccak.finalize(&mut h_iv);
  33. let seed_hash: BigInt = BigInt::from_bytes_be(Sign::Plus, &h);
  34. let c: BigInt = BigInt::from_bytes_be(Sign::Plus, &h_iv);
  35. let iv: BigInt = c % &r;
  36. let n_rounds: i64 = 91;
  37. let cts = get_constants(&r, SEED, n_rounds);
  38. Constants {
  39. seed_hash: seed_hash,
  40. iv: iv,
  41. r: r,
  42. n_rounds: n_rounds,
  43. cts: cts,
  44. }
  45. }
  46. pub fn get_constants(r: &BigInt, seed: &str, n_rounds: i64) -> Vec<BigInt> {
  47. let mut cts: Vec<BigInt> = Vec::new();
  48. cts.push(Zero::zero());
  49. let mut keccak = Keccak::new_keccak256();
  50. let mut h = [0u8; 32];
  51. keccak.update(seed.as_bytes());
  52. keccak.finalize(&mut h);
  53. let mut c = BigInt::from_bytes_be(Sign::Plus, &h);
  54. for _ in 1..n_rounds {
  55. let mut keccak = Keccak::new_keccak256();
  56. let mut h = [0u8; 32];
  57. let (_, c_bytes) = c.to_bytes_be();
  58. keccak.update(&c_bytes[..]);
  59. keccak.finalize(&mut h);
  60. c = BigInt::from_bytes_be(Sign::Plus, &h);
  61. let n = modulus(&c, &r);
  62. cts.push(n);
  63. }
  64. cts
  65. }
  66. pub fn mimc7_hash_generic(r: &BigInt, x_in: &BigInt, k: &BigInt, n_rounds: i64) -> BigInt {
  67. let cts = get_constants(r, SEED, n_rounds);
  68. let mut h: BigInt = Zero::zero();
  69. for i in 0..n_rounds as usize {
  70. let mut t: BigInt;
  71. if i == 0 {
  72. t = x_in + k;
  73. } else {
  74. t = h + k + &cts[i];
  75. }
  76. t = modulus(&t, &r);
  77. let t2 = &t * &t;
  78. let t4 = &t2 * &t2;
  79. h = (t4 * t2) * t;
  80. h = modulus(&h, &r);
  81. }
  82. modulus(&(h + k), &r)
  83. }
  84. pub fn hash_generic(iv: BigInt, arr: Vec<BigInt>, r: BigInt, n_rounds: i64) -> BigInt {
  85. let mut h: BigInt = iv;
  86. for i in 0..arr.len() {
  87. h = mimc7_hash_generic(&r, &h, &arr[i], n_rounds);
  88. }
  89. h
  90. }
  91. pub struct Mimc7 {
  92. constants: Constants,
  93. }
  94. impl Mimc7 {
  95. pub fn new() -> Mimc7 {
  96. Mimc7 {
  97. constants: generate_constants(),
  98. }
  99. }
  100. pub fn hash(&self, arr: Vec<BigInt>) -> BigInt {
  101. // TODO check if arr elements are inside the Finite Field over R
  102. let mut h: BigInt = Zero::zero();
  103. for i in 0..arr.len() {
  104. h = &h + &arr[i] + self.mimc7_hash(&arr[i], &h);
  105. h = modulus(&h, &self.constants.r)
  106. }
  107. modulus(&h, &self.constants.r)
  108. }
  109. pub fn mimc7_hash(&self, x_in: &BigInt, k: &BigInt) -> BigInt {
  110. let mut h: BigInt = Zero::zero();
  111. for i in 0..self.constants.n_rounds as usize {
  112. let t: BigInt;
  113. if i == 0 {
  114. t = x_in + k;
  115. } else {
  116. t = h + k + &self.constants.cts[i];
  117. }
  118. let t2 = &t * &t;
  119. let t4 = &t2 * &t2;
  120. h = (t4 * t2) * t;
  121. h = modulus(&h, &self.constants.r);
  122. }
  123. modulus(&(h + k), &self.constants.r)
  124. }
  125. }
  126. #[cfg(test)]
  127. mod tests {
  128. use super::*;
  129. use rustc_hex::ToHex;
  130. #[test]
  131. fn test_sha3() {
  132. let mut keccak = Keccak::new_keccak256();
  133. let mut res = [0u8; 32];
  134. keccak.update(SEED.as_bytes());
  135. keccak.finalize(&mut res);
  136. assert_eq!(
  137. res.to_hex(),
  138. "b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e"
  139. );
  140. let mut keccak = Keccak::new_keccak256();
  141. let mut res = [0u8; 32];
  142. keccak.update(SEED.as_bytes());
  143. keccak.finalize(&mut res);
  144. let c = BigInt::from_bytes_be(Sign::Plus, &res);
  145. assert_eq!(
  146. c.to_string(),
  147. "82724731331859054037315113496710413141112897654334566532528783843265082629790"
  148. );
  149. }
  150. #[test]
  151. fn test_generate_constants() {
  152. let constants = generate_constants();
  153. assert_eq!(
  154. "20888961410941983456478427210666206549300505294776164667214940546594746570981",
  155. constants.cts[1].to_string()
  156. );
  157. }
  158. #[test]
  159. fn test_mimc7_generic() {
  160. let b1: BigInt = BigInt::parse_bytes(b"1", 10).unwrap();
  161. let b2: BigInt = BigInt::parse_bytes(b"2", 10).unwrap();
  162. let constants = generate_constants();
  163. let h1 = mimc7_hash_generic(&constants.r, &b1, &b2, 91);
  164. assert_eq!(
  165. h1.to_string(),
  166. "10594780656576967754230020536574539122676596303354946869887184401991294982664"
  167. );
  168. }
  169. #[test]
  170. fn test_mimc7() {
  171. let b12: BigInt = BigInt::parse_bytes(b"12", 10).unwrap();
  172. let b45: BigInt = BigInt::parse_bytes(b"45", 10).unwrap();
  173. let b78: BigInt = BigInt::parse_bytes(b"78", 10).unwrap();
  174. let b41: BigInt = BigInt::parse_bytes(b"41", 10).unwrap();
  175. let mut big_arr1: Vec<BigInt> = Vec::new();
  176. big_arr1.push(b12.clone());
  177. let mimc7 = Mimc7::new();
  178. let h1 = mimc7.hash(big_arr1);
  179. let (_, h1_bytes) = h1.to_bytes_be();
  180. assert_eq!(
  181. h1_bytes.to_hex(),
  182. "237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd"
  183. );
  184. let mh2 = mimc7.mimc7_hash(&b12, &b45);
  185. let (_, mh2_bytes) = mh2.to_bytes_be();
  186. assert_eq!(
  187. mh2_bytes.to_hex(),
  188. "2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4"
  189. );
  190. let mut big_arr2: Vec<BigInt> = Vec::new();
  191. big_arr2.push(b78.clone());
  192. big_arr2.push(b41.clone());
  193. let h2 = mimc7.hash(big_arr2);
  194. let (_, h2_bytes) = h2.to_bytes_be();
  195. assert_eq!(
  196. h2_bytes.to_hex(),
  197. "067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70"
  198. );
  199. let mut big_arr2: Vec<BigInt> = Vec::new();
  200. big_arr2.push(b12.clone());
  201. big_arr2.push(b45.clone());
  202. let h1 = mimc7.hash(big_arr2);
  203. let (_, h1_bytes) = h1.to_bytes_be();
  204. assert_eq!(
  205. h1_bytes.to_hex(),
  206. "15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879"
  207. );
  208. let mut big_arr1: Vec<BigInt> = Vec::new();
  209. big_arr1.push(b12.clone());
  210. big_arr1.push(b45.clone());
  211. big_arr1.push(b78.clone());
  212. big_arr1.push(b41.clone());
  213. let mimc7 = Mimc7::new();
  214. let h1 = mimc7.hash(big_arr1);
  215. let (_, h1_bytes) = h1.to_bytes_be();
  216. assert_eq!(
  217. h1_bytes.to_hex(),
  218. "284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb"
  219. );
  220. }
  221. }