darkfi_sdk/crypto/
mimc_vdf.rs1use num_bigint::BigUint;
22use num_traits::Num;
23
24const MODULUS: &str =
26 "115792089237316195423570985008687907853269984665640564039457584006405596119041";
27
28const L_FERMAT_EXPONENT: &str =
30 "77194726158210796949047323339125271902179989777093709359638389337603730746027";
31
32fn calculate_round_constants() -> [BigUint; 64] {
34 let mut round_constants: Vec<BigUint> = vec![];
35 #[allow(clippy::needless_range_loop)]
36 for i in 0u64..64 {
37 round_constants.push(BigUint::from(i).pow(7) ^ BigUint::from(42u64));
38 }
39
40 round_constants.try_into().unwrap()
41}
42
43fn forward_mimc(num_steps: u64, input: &BigUint) -> BigUint {
45 let modulus = BigUint::from_str_radix(MODULUS, 10).unwrap();
46 let round_constants = calculate_round_constants();
47
48 let mut result = input.clone();
49 let three = BigUint::from(3_u64);
50 for i in 1..num_steps {
51 result = (result.modpow(&three, &modulus) +
52 &round_constants[i as usize % round_constants.len()])
53 .modpow(&BigUint::from(1_u64), &modulus);
54 }
55
56 result
57}
58
59fn backward_mimc(num_steps: u64, input: &BigUint) -> BigUint {
64 let modulus = BigUint::from_str_radix(MODULUS, 10).unwrap();
65 let l_fermat_exp = BigUint::from_str_radix(L_FERMAT_EXPONENT, 10).unwrap();
66 let round_constants = calculate_round_constants();
67
68 let mut result = input.clone();
69 for i in (1..num_steps).rev() {
70 let round_constant = &round_constants[i as usize % round_constants.len()];
71 result = (&result - round_constant).modpow(&l_fermat_exp, &modulus);
72 }
73
74 result
75}
76
77pub fn eval(seed: &BigUint, num_steps: u64) -> BigUint {
79 backward_mimc(num_steps, seed)
80}
81
82pub fn verify(seed: &BigUint, num_steps: u64, witness: &BigUint) -> bool {
84 forward_mimc(num_steps, witness) == *seed
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn mimc_vdf_eval_and_verify() {
93 let steps = 1000;
94 let challenge = blake3::hash(b"69420").to_hex();
95 let challenge = BigUint::from_str_radix(&challenge, 16).unwrap();
96
97 let witness = eval(&challenge, steps);
98 assert!(verify(&challenge, steps, &witness));
99 assert!(!verify(&(&challenge - 1_u64), steps, &witness));
100 assert!(!verify(&challenge, steps - 1, &witness));
101 assert!(!verify(&challenge, steps, &(&witness - 1_u64)));
102 }
103}