mimc_vdf.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! https://vitalik.ca/general/2018/07/21/starks_part_3.html
  19. use num_bigint::BigUint;
  20. use num_traits::Num;
  21. /// Modulus of prime field 2^256 - 2^32 * 351 + 1
  22. const MODULUS: &str =
  23. "115792089237316195423570985008687907853269984665640564039457584006405596119041";
  24. /// An exponent to perform inverse of x^3 on prime field based on Fermat's Little Theorem
  25. const L_FERMAT_EXPONENT: &str =
  26. "77194726158210796949047323339125271902179989777093709359638389337603730746027";
  27. /// Calculates set of round constants to perform MiMC-calculation on.
  28. fn calculate_round_constants() -> [u64; 64] {
  29. let mut round_constants = [0u64; 64];
  30. #[allow(clippy::needless_range_loop)]
  31. for i in 0usize..64 {
  32. round_constants[i] = (i.pow(7) ^ 42) as u64;
  33. }
  34. round_constants
  35. }
  36. /// Executes `num_steps` of MiMC-calculation in forward direction for the given `input`
  37. fn forward_mimc(num_steps: u64, input: &BigUint) -> BigUint {
  38. let modulus = BigUint::from_str_radix(MODULUS, 10).unwrap();
  39. let round_constants = calculate_round_constants();
  40. let mut result = input.clone();
  41. let three = BigUint::from(3_u64);
  42. for i in 1..num_steps {
  43. result = (result.modpow(&three, &modulus) +
  44. BigUint::from(round_constants[i as usize % round_constants.len()])) %
  45. &modulus;
  46. }
  47. result
  48. }
  49. /// Executes `num_steps` of MiMC-calculation in backward direction for the given `input`.
  50. ///
  51. /// The properties of MiMC-scheme guarantees that calculation in backward direction is
  52. /// always slower than in forward for correctly chosen parameters.
  53. fn backward_mimc(num_steps: u64, input: &BigUint) -> BigUint {
  54. let modulus = BigUint::from_str_radix(MODULUS, 10).unwrap();
  55. let l_fermat_exp = BigUint::from_str_radix(L_FERMAT_EXPONENT, 10).unwrap();
  56. let round_constants = calculate_round_constants();
  57. let mut result = input.clone();
  58. for i in (1..num_steps).rev() {
  59. let round_constant = BigUint::from(round_constants[i as usize % round_constants.len()]);
  60. result = (&result - &round_constant).modpow(&l_fermat_exp, &modulus);
  61. }
  62. result
  63. }
  64. /// Performs an Eval() step of the MiMC-based VDF
  65. pub fn eval(seed: &BigUint, num_steps: u64) -> BigUint {
  66. backward_mimc(num_steps, seed)
  67. }
  68. /// Performs a Verify() step for the MiMC-based VDF result
  69. pub fn verify(seed: &BigUint, num_steps: u64, witness: &BigUint) -> bool {
  70. forward_mimc(num_steps, witness) == *seed
  71. }
  72. #[cfg(test)]
  73. mod tests {
  74. use super::*;
  75. #[test]
  76. fn mimc_vdf_eval_and_verify() {
  77. let steps = 1000;
  78. let challenge = blake3::hash(b"69420").to_hex();
  79. let challenge = BigUint::from_str_radix(&challenge, 16).unwrap();
  80. let witness = eval(&challenge, steps);
  81. assert!(verify(&challenge, steps, &witness));
  82. assert!(!verify(&(&challenge - 1_u64), steps, &witness));
  83. assert!(!verify(&challenge, steps - 1, &witness));
  84. assert!(!verify(&challenge, steps, &(&witness - 1_u64)));
  85. }
  86. }