Skip to main content

chaincraft_rust/crypto/
vrf.rs

1//! ECDSA-based VRF primitive (matches Python ECDSAVRFPrimitive)
2//!
3//! Simplified VRF using ECDSA secp256k1:
4//! - Proof = ECDSA signature on input
5//! - VRF output = SHA256(proof), used as randomness
6//! This is a mocked VRF approach, not a real production VRF.
7
8use crate::error::{ChaincraftError, CryptoError, Result};
9use k256::ecdsa::{signature::Signer, SigningKey};
10use rand_core::OsRng;
11use sha2::{Digest, Sha256};
12use std::fmt;
13
14/// ECDSA-based VRF: proof = ECDSA sign, output = hash(proof)
15#[derive(Debug, Clone)]
16pub struct ECDSAVRF {
17    signing_key: SigningKey,
18}
19
20impl ECDSAVRF {
21    /// Generate new keypair (secp256k1)
22    pub fn new() -> Result<Self> {
23        let signing_key = SigningKey::random(&mut OsRng);
24        Ok(Self { signing_key })
25    }
26
27    /// Create from existing signing key bytes
28    pub fn from_signing_key_bytes(bytes: &[u8]) -> Result<Self> {
29        let signing_key = SigningKey::from_slice(bytes)
30            .map_err(|_| ChaincraftError::Crypto(CryptoError::InvalidPrivateKey {
31                reason: "Invalid secp256k1 key".to_string(),
32            }))?;
33        Ok(Self { signing_key })
34    }
35
36    /// Sign data (VRF input) to produce proof
37    pub fn prove(&self, data: &[u8]) -> Result<Vec<u8>> {
38        let signature: k256::ecdsa::Signature = self.signing_key.sign(data);
39        Ok(signature.to_bytes().to_vec())
40    }
41
42    /// Verify proof and return VRF output (hash of proof) if valid
43    pub fn verify(&self, data: &[u8], proof: &[u8]) -> Result<Vec<u8>> {
44        use k256::ecdsa::{signature::Verifier, VerifyingKey};
45        let sig = k256::ecdsa::Signature::from_slice(proof)
46            .map_err(|_| ChaincraftError::Crypto(CryptoError::InvalidSignature))?;
47        let vk = VerifyingKey::from(&self.signing_key);
48        vk.verify(data, &sig).map_err(|_| {
49            ChaincraftError::Crypto(CryptoError::VrfVerificationFailed)
50        })?;
51        Ok(Self::vrf_output(proof))
52    }
53
54    /// VRF output = SHA256(proof)
55    pub fn vrf_output(proof: &[u8]) -> Vec<u8> {
56        Sha256::digest(proof).to_vec()
57    }
58
59    /// Public key as bytes (sec1 compressed)
60    pub fn public_key_bytes(&self) -> Vec<u8> {
61        use k256::elliptic_curve::sec1::ToEncodedPoint;
62        self.signing_key
63            .verifying_key()
64            .to_encoded_point(true)
65            .as_bytes()
66            .to_vec()
67    }
68
69    /// Verify proof using public key bytes
70    pub fn verify_with_public_key(
71        public_key_bytes: &[u8],
72        data: &[u8],
73        proof: &[u8],
74    ) -> Result<Vec<u8>> {
75        use k256::ecdsa::{signature::Verifier, VerifyingKey};
76        let pk = k256::PublicKey::from_sec1_bytes(public_key_bytes)
77            .map_err(|_| ChaincraftError::Crypto(CryptoError::InvalidPublicKey {
78                reason: "Invalid secp256k1 public key".to_string(),
79            }))?;
80        let vk = VerifyingKey::from(pk);
81        let sig = k256::ecdsa::Signature::from_slice(proof)
82            .map_err(|_| ChaincraftError::Crypto(CryptoError::InvalidSignature))?;
83        vk.verify(data, &sig).map_err(|_| {
84            ChaincraftError::Crypto(CryptoError::VrfVerificationFailed)
85        })?;
86        Ok(Self::vrf_output(proof))
87    }
88}
89
90impl Default for ECDSAVRF {
91    fn default() -> Self {
92        Self::new().expect("VRF keygen")
93    }
94}
95
96/// Legacy alias for backward compatibility
97#[derive(Debug, Clone)]
98pub struct VerifiableRandomFunction(ECDSAVRF);
99
100impl VerifiableRandomFunction {
101    pub fn new() -> Result<Self> {
102        ECDSAVRF::new().map(Self)
103    }
104}
105
106impl Default for VerifiableRandomFunction {
107    fn default() -> Self {
108        Self(ECDSAVRF::default())
109    }
110}
111
112impl fmt::Display for VerifiableRandomFunction {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        write!(f, "VerifiableRandomFunction(ECDSA)")
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn test_vrf_prove_verify() {
124        let vrf = ECDSAVRF::new().unwrap();
125        let data = b"vrf_input";
126        let proof = vrf.prove(data).unwrap();
127        assert!(!proof.is_empty());
128        let output = vrf.verify(data, &proof).unwrap();
129        assert_eq!(output.len(), 32);
130        assert_eq!(output, ECDSAVRF::vrf_output(&proof));
131    }
132
133    #[test]
134    fn test_vrf_verify_with_public_key() {
135        let vrf = ECDSAVRF::new().unwrap();
136        let pk = vrf.public_key_bytes();
137        let data = b"test";
138        let proof = vrf.prove(data).unwrap();
139        let output = ECDSAVRF::verify_with_public_key(&pk, data, &proof).unwrap();
140        assert_eq!(output, ECDSAVRF::vrf_output(&proof));
141    }
142
143    #[test]
144    fn test_vrf_invalid_proof_fails() {
145        let vrf = ECDSAVRF::new().unwrap();
146        let data = b"input";
147        let bad_proof = vec![0u8; 64];
148        assert!(vrf.verify(data, &bad_proof).is_err());
149    }
150}