Skip to main content

chaincraft_rust/crypto/
vdf.rs

1//! Verifiable Delay Function implementation
2//!
3//! Uses the `vdf` crate (Pietrzak/Wesolowski) when feature `vdf-crypto` is enabled.
4//! Requires GMP: `apt-get install libgmp-dev` or `dnf install gmp-devel`.
5
6use crate::error::{ChaincraftError, Result};
7
8/// Verifiable Delay Function wrapper
9#[derive(Debug, Clone)]
10pub struct VerifiableDelayFunction {
11    num_bits: u16,
12}
13
14impl VerifiableDelayFunction {
15    pub fn new() -> Self {
16        Self::with_bits(2048)
17    }
18
19    pub fn with_bits(num_bits: u16) -> Self {
20        Self { num_bits }
21    }
22
23    /// Solve the VDF: compute output for challenge after `iterations` steps
24    pub fn solve(&self, challenge: &[u8], iterations: u64) -> Result<Vec<u8>> {
25        #[cfg(feature = "vdf-crypto")]
26        {
27            use vdf::{PietrzakVDFParams, VDF, VDFParams};
28            let vdf = PietrzakVDFParams(self.num_bits).new();
29            vdf.solve(challenge, iterations).map_err(|e| {
30                ChaincraftError::Crypto(crate::error::CryptoError::VdfError {
31                    reason: format!("{:?}", e),
32                })
33            })
34        }
35        #[cfg(not(feature = "vdf-crypto"))]
36        {
37            let _ = (challenge, iterations);
38            Err(ChaincraftError::Crypto(crate::error::CryptoError::VdfError {
39                reason: "VDF requires feature 'vdf-crypto'. Enable with: chaincraft-rust = { version = \"..\", features = [\"vdf-crypto\"] }".to_string(),
40            }))
41        }
42    }
43
44    /// Verify a VDF solution
45    pub fn verify(&self, challenge: &[u8], iterations: u64, solution: &[u8]) -> Result<bool> {
46        #[cfg(feature = "vdf-crypto")]
47        {
48            use vdf::{PietrzakVDFParams, VDF, VDFParams};
49            let vdf = PietrzakVDFParams(self.num_bits).new();
50            vdf.verify(challenge, iterations, solution)
51                .map(|_| true)
52                .map_err(|e| {
53                    ChaincraftError::Crypto(crate::error::CryptoError::VdfError {
54                        reason: format!("{:?}", e),
55                    })
56                })
57        }
58        #[cfg(not(feature = "vdf-crypto"))]
59        {
60            let _ = (challenge, iterations, solution);
61            Err(ChaincraftError::Crypto(crate::error::CryptoError::VdfError {
62                reason: "VDF requires feature 'vdf-crypto'".to_string(),
63            }))
64        }
65    }
66}
67
68impl Default for VerifiableDelayFunction {
69    fn default() -> Self {
70        Self::new()
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[cfg(not(feature = "vdf-crypto"))]
79    #[test]
80    fn test_vdf_without_feature_returns_error() {
81        let vdf = VerifiableDelayFunction::new();
82        let err = vdf.solve(b"challenge", 10);
83        assert!(err.is_err());
84        assert!(err.unwrap_err().to_string().contains("vdf-crypto"));
85    }
86
87    #[cfg(feature = "vdf-crypto")]
88    #[test]
89    fn test_vdf_solve_and_verify() {
90        let vdf = VerifiableDelayFunction::with_bits(1024);
91        let challenge = b"test";
92        let iterations = 66u64; // Pietrzak requires at least 66 iterations
93        let solution = vdf.solve(challenge, iterations).expect("solve");
94        assert!(!solution.is_empty());
95        assert!(vdf.verify(challenge, iterations, &solution).unwrap());
96    }
97}