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.

249 lines
6.8 KiB

4 years ago
  1. extern crate num;
  2. extern crate num_bigint;
  3. extern crate num_traits;
  4. use blake2::digest::{Input, VariableOutput};
  5. use blake2::VarBlake2b;
  6. use num_bigint::{BigInt, Sign};
  7. use num_traits::{One, Zero};
  8. const SEED: &str = "poseidon";
  9. const NROUNDSF: usize = 8;
  10. const NROUNDSP: usize = 57;
  11. const T: usize = 6;
  12. pub struct Constants {
  13. r: BigInt,
  14. c: Vec<BigInt>,
  15. m: Vec<Vec<BigInt>>,
  16. }
  17. pub fn generate_constants() -> Constants {
  18. let r: BigInt = BigInt::parse_bytes(
  19. b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
  20. 10,
  21. )
  22. .unwrap();
  23. let c = get_pseudo_random(&r, format!("{}{}", SEED, "_constants"), NROUNDSF + NROUNDSP);
  24. let m = get_mds(&r);
  25. Constants { r: r, c: c, m: m }
  26. }
  27. pub fn get_pseudo_random(r: &BigInt, seed: String, n: usize) -> Vec<BigInt> {
  28. let mut hasher = VarBlake2b::new(32).unwrap();
  29. hasher.input(seed.as_bytes());
  30. let mut h = hasher.vec_result();
  31. let mut res: Vec<BigInt> = Vec::new();
  32. while res.len() < n {
  33. let new_n: BigInt = modulus(&BigInt::from_bytes_le(Sign::Plus, &h), &r);
  34. res.push(new_n);
  35. let mut hasher = VarBlake2b::new(32).unwrap();
  36. hasher.input(h);
  37. h = hasher.vec_result();
  38. }
  39. res
  40. }
  41. pub fn nonce_to_string(n: usize) -> String {
  42. let mut r = format!("{}", n);
  43. while r.len() < 4 {
  44. r = format!("0{}", r);
  45. }
  46. r
  47. }
  48. pub fn get_mds(r: &BigInt) -> Vec<Vec<BigInt>> {
  49. let mut nonce = 0;
  50. let mut cauchy_matrix = get_pseudo_random(
  51. r,
  52. format!("{}_matrix_{}", SEED, nonce_to_string(nonce)),
  53. T * 2,
  54. );
  55. while !check_all_different(&cauchy_matrix) {
  56. nonce = nonce + 1;
  57. cauchy_matrix = get_pseudo_random(
  58. r,
  59. format!("{}_matrix_{}", SEED, nonce_to_string(nonce)),
  60. T * 2,
  61. );
  62. }
  63. let mut m: Vec<Vec<BigInt>> = Vec::new();
  64. for i in 0..T {
  65. let mut mi: Vec<BigInt> = Vec::new();
  66. for j in 0..T {
  67. mi.push(modinv(
  68. &modulus(&(&cauchy_matrix[i] - &cauchy_matrix[T + j]), &r),
  69. &r,
  70. ));
  71. }
  72. m.push(mi);
  73. }
  74. m
  75. }
  76. pub fn check_all_different(v: &Vec<BigInt>) -> bool {
  77. let zero: BigInt = Zero::zero();
  78. for i in 0..v.len() {
  79. if v[i] == zero {
  80. return false;
  81. }
  82. for j in i + 1..v.len() {
  83. if v[i] == v[j] {
  84. return false;
  85. }
  86. }
  87. }
  88. true
  89. }
  90. pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt {
  91. ((a % m) + m) % m
  92. }
  93. pub fn modinv(a: &BigInt, q: &BigInt) -> BigInt {
  94. let mut mn = (q.clone(), a.clone());
  95. let mut xy: (BigInt, BigInt) = (Zero::zero(), One::one());
  96. let big_zero: BigInt = Zero::zero();
  97. while mn.1 != big_zero {
  98. xy = (xy.1.clone(), xy.0 - (mn.0.clone() / mn.1.clone()) * xy.1);
  99. mn = (mn.1.clone(), modulus(&mn.0, &mn.1));
  100. }
  101. while xy.0 < Zero::zero() {
  102. xy.0 = modulus(&xy.0, q);
  103. }
  104. xy.0
  105. }
  106. pub fn check_bigint_in_field(a: &BigInt, q: &BigInt) -> bool {
  107. if a >= q {
  108. return false;
  109. }
  110. true
  111. }
  112. pub fn check_bigint_array_in_field(arr: &Vec<BigInt>, q: &BigInt) -> bool {
  113. for a in arr {
  114. if !check_bigint_in_field(a, &q) {
  115. return false;
  116. }
  117. }
  118. true
  119. }
  120. pub struct Poseidon {
  121. constants: Constants,
  122. }
  123. impl Poseidon {
  124. pub fn new() -> Poseidon {
  125. Poseidon {
  126. constants: generate_constants(),
  127. }
  128. }
  129. pub fn ark(&self, state: &Vec<BigInt>, c: &BigInt) -> Vec<BigInt> {
  130. let mut new_state: Vec<BigInt> = state.clone();
  131. for i in 0..state.len() {
  132. new_state[i] = modulus(&(&state[i] + c), &self.constants.r);
  133. }
  134. new_state
  135. }
  136. pub fn cubic(&self, a: &BigInt) -> BigInt {
  137. modulus(&(a * a * a * a * a), &self.constants.r)
  138. }
  139. pub fn sbox(&self, state: &Vec<BigInt>, i: usize) -> Vec<BigInt> {
  140. let mut new_state: Vec<BigInt> = state.clone();
  141. if i < NROUNDSF / 2 || i >= NROUNDSF / 2 + NROUNDSP {
  142. for j in 0..T {
  143. new_state[j] = self.cubic(&state[j]);
  144. }
  145. } else {
  146. new_state[0] = self.cubic(&state[0]);
  147. }
  148. new_state
  149. }
  150. pub fn mix(&self, state: &Vec<BigInt>, m: &Vec<Vec<BigInt>>) -> Vec<BigInt> {
  151. let mut new_state: Vec<BigInt> = Vec::new();
  152. for i in 0..state.len() {
  153. new_state.push(Zero::zero());
  154. for j in 0..state.len() {
  155. new_state[i] = modulus(
  156. &(&new_state[i] + modulus(&(&m[i][j] * &state[j]), &self.constants.r)),
  157. &self.constants.r,
  158. )
  159. }
  160. }
  161. new_state
  162. }
  163. pub fn poseidon_hash(&self, inp: Vec<BigInt>) -> Result<BigInt, String> {
  164. if inp.len() == 0 || inp.len() > T {
  165. return Err("Wrong inputs length".to_string());
  166. }
  167. // check if arr elements are inside the finite field over R
  168. if !check_bigint_array_in_field(&inp, &self.constants.r) {
  169. return Err("elements not inside the finite field over R".to_string());
  170. }
  171. let mut state = inp.clone();
  172. for _ in inp.len()..T {
  173. state.push(Zero::zero());
  174. }
  175. for i in 0..(NROUNDSF + NROUNDSP) {
  176. state = self.ark(&state, &self.constants.c[i]);
  177. state = self.sbox(&state, i);
  178. state = self.mix(&state, &self.constants.m);
  179. }
  180. Ok(state[0].clone())
  181. }
  182. }
  183. #[cfg(test)]
  184. mod tests {
  185. use super::*;
  186. use rustc_hex::ToHex;
  187. #[test]
  188. fn test_blake2_version() {
  189. let mut hasher = VarBlake2b::new(32).unwrap();
  190. hasher.input(b"poseidon_constants");
  191. let h = hasher.vec_result();
  192. assert_eq!(
  193. h.to_hex(),
  194. "e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1"
  195. );
  196. }
  197. #[test]
  198. fn test_poseidon_hash() {
  199. let b1: BigInt = BigInt::parse_bytes(b"1", 10).unwrap();
  200. let b2: BigInt = BigInt::parse_bytes(b"2", 10).unwrap();
  201. let mut big_arr: Vec<BigInt> = Vec::new();
  202. big_arr.push(b1.clone());
  203. big_arr.push(b2.clone());
  204. let poseidon = Poseidon::new();
  205. let h = poseidon.poseidon_hash(big_arr).unwrap();
  206. assert_eq!(
  207. h.to_string(),
  208. "12242166908188651009877250812424843524687801523336557272219921456462821518061"
  209. );
  210. let b3: BigInt = BigInt::parse_bytes(b"3", 10).unwrap();
  211. let b4: BigInt = BigInt::parse_bytes(b"4", 10).unwrap();
  212. let mut big_arr34: Vec<BigInt> = Vec::new();
  213. big_arr34.push(b3.clone());
  214. big_arr34.push(b4.clone());
  215. let h34 = poseidon.poseidon_hash(big_arr34).unwrap();
  216. assert_eq!(
  217. h34.to_string(),
  218. "17185195740979599334254027721507328033796809509313949281114643312710535000993"
  219. );
  220. }
  221. }