cardano_crypto/vrf/
mod.rs

1//! Verifiable Random Functions (VRF)
2//!
3//! This module provides VRF implementations following IETF specifications:
4//! - **Draft-03** (ECVRF-ED25519-SHA512-Elligator2) - 80-byte proofs, Cardano standard
5//! - **Draft-13** (ECVRF-ED25519-SHA512-TAI) - 128-byte proofs, batch-compatible
6//!
7//! Both variants maintain byte-level compatibility with Cardano's libsodium VRF implementation.
8//!
9//! # Examples
10//!
11//! ## VRF Draft-03 (Cardano Standard)
12//!
13//! ```
14//! use cardano_crypto::vrf::VrfDraft03;
15//!
16//! // Generate keypair
17//! let seed = [42u8; 32];
18//! let (secret_key, public_key) = VrfDraft03::keypair_from_seed(&seed);
19//!
20//! // Prove
21//! let message = b"Cardano block slot 12345";
22//! let proof = VrfDraft03::prove(&secret_key, message).unwrap();
23//!
24//! // Verify and get output
25//! let output = VrfDraft03::verify(&public_key, &proof, message).unwrap();
26//! assert_eq!(output.len(), 64);
27//! ```
28//!
29//! ## VRF Draft-13
30//!
31//! ```
32//! use cardano_crypto::vrf::VrfDraft13;
33//!
34//! let seed = [42u8; 32];
35//! let (secret_key, public_key) = VrfDraft13::keypair_from_seed(&seed);
36//!
37//! let message = b"Random seed input";
38//! let proof = VrfDraft13::prove(&secret_key, message).unwrap();
39//! let output = VrfDraft13::verify(&public_key, &proof, message).unwrap();
40//! ```
41
42#[cfg(feature = "alloc")]
43use alloc::{format, vec::Vec};
44
45pub mod cardano_compat;
46pub mod draft03;
47pub mod draft13;
48pub mod test_vectors;
49
50// Re-export main types
51pub use draft03::{
52    VrfDraft03, OUTPUT_SIZE, PROOF_SIZE as DRAFT03_PROOF_SIZE, PUBLIC_KEY_SIZE, SECRET_KEY_SIZE,
53    SEED_SIZE,
54};
55
56pub use draft13::{VrfDraft13, PROOF_SIZE as DRAFT13_PROOF_SIZE};
57
58// Re-export Cardano compatibility functions for advanced usage
59pub use cardano_compat::{
60    cardano_clear_cofactor, cardano_hash_to_curve, cardano_vrf_prove, cardano_vrf_verify,
61};
62
63// ============================================================================
64// VRF Algorithm trait (matching Cardano's VRFAlgorithm class)
65// ============================================================================
66
67/// Trait for VRF algorithms
68///
69/// This trait provides a unified interface for VRF implementations,
70/// matching the structure of Cardano's `VRFAlgorithm` type class.
71///
72/// # Associated Types
73///
74/// - `SecretKey`: VRF secret key type
75/// - `VerificationKey`: VRF public key type
76/// - `Proof`: VRF proof type
77/// - `Output`: VRF output type (hash)
78///
79/// # Example
80///
81/// ```
82/// use cardano_crypto::vrf::{VrfAlgorithm, VrfDraft03};
83/// use cardano_crypto::hash::{Blake2b256, HashAlgorithm};
84///
85/// let seed = [42u8; 32];
86/// let (sk, vk) = VrfDraft03::keypair_from_seed(&seed);
87///
88/// // Hash the verification key
89/// let vk_hash = VrfDraft03::hash_verification_key::<Blake2b256>(&vk);
90/// assert_eq!(vk_hash.len(), 32);
91/// ```
92pub trait VrfAlgorithm: Clone + Send + Sync + 'static {
93    /// Secret key type
94    type SecretKey;
95    /// Verification key type
96    type VerificationKey;
97    /// Proof type
98    type Proof;
99    /// Output type
100    type Output;
101
102    /// Algorithm name
103    const ALGORITHM_NAME: &'static str;
104    /// Seed size in bytes
105    const SEED_SIZE: usize;
106    /// Secret key size in bytes
107    const SECRET_KEY_SIZE: usize;
108    /// Verification key size in bytes
109    const VERIFICATION_KEY_SIZE: usize;
110    /// Proof size in bytes
111    const PROOF_SIZE: usize;
112    /// Output size in bytes
113    const OUTPUT_SIZE: usize;
114
115    /// Generate keypair from seed
116    fn keypair_from_seed(seed: &[u8; 32]) -> (Self::SecretKey, Self::VerificationKey);
117
118    /// Derive verification key from secret key
119    fn derive_verification_key(sk: &Self::SecretKey) -> Self::VerificationKey;
120
121    /// Generate a VRF proof
122    fn prove(sk: &Self::SecretKey, message: &[u8]) -> crate::common::CryptoResult<Self::Proof>;
123
124    /// Verify a VRF proof and return the output
125    fn verify(
126        vk: &Self::VerificationKey,
127        proof: &Self::Proof,
128        message: &[u8],
129    ) -> crate::common::CryptoResult<Self::Output>;
130
131    /// Convert proof to output hash directly (without verification)
132    fn proof_to_hash(proof: &Self::Proof) -> crate::common::CryptoResult<Self::Output>;
133
134    /// Serialize verification key to raw bytes
135    fn raw_serialize_verification_key(vk: &Self::VerificationKey) -> &[u8];
136
137    /// Deserialize verification key from raw bytes
138    fn raw_deserialize_verification_key(bytes: &[u8]) -> Option<Self::VerificationKey>;
139
140    /// Serialize proof to raw bytes
141    fn raw_serialize_proof(proof: &Self::Proof) -> &[u8];
142
143    /// Deserialize proof from raw bytes
144    fn raw_deserialize_proof(bytes: &[u8]) -> Option<Self::Proof>;
145
146    /// Hash a verification key
147    ///
148    /// This corresponds to `hashVerKeyVRF` in cardano-base.
149    ///
150    /// # Type Parameters
151    ///
152    /// - `H`: The hash algorithm to use
153    #[cfg(feature = "alloc")]
154    fn hash_verification_key<H: crate::hash::HashAlgorithm>(vk: &Self::VerificationKey) -> Vec<u8> {
155        let raw = Self::raw_serialize_verification_key(vk);
156        H::hash(raw)
157    }
158}
159
160// ============================================================================
161// OutputVRF - VRF output wrapper matching Cardano's OutputVRF
162// ============================================================================
163
164/// VRF output wrapper
165///
166/// Matches Cardano's `OutputVRF v` type from cardano-crypto-class.
167/// The output is the result of a VRF evaluation and can be converted
168/// to a natural number for use in leader election.
169///
170/// # Examples
171///
172/// ```
173/// use cardano_crypto::vrf::{VrfDraft03, OutputVrf};
174///
175/// let seed = [42u8; 32];
176/// let (secret_key, public_key) = VrfDraft03::keypair_from_seed(&seed);
177/// let message = b"test";
178/// let proof = VrfDraft03::prove(&secret_key, message).unwrap();
179/// let output_bytes = VrfDraft03::verify(&public_key, &proof, message).unwrap();
180///
181/// let output = OutputVrf::new(output_bytes);
182/// assert_eq!(output.as_bytes().len(), 64);
183/// ```
184#[derive(Clone, PartialEq, Eq)]
185pub struct OutputVrf([u8; OUTPUT_SIZE]);
186
187impl core::fmt::Debug for OutputVrf {
188    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
189        write!(f, "OutputVrf(<{} bytes>)", self.0.len())
190    }
191}
192
193impl OutputVrf {
194    /// Create an OutputVrf from raw bytes
195    pub fn new(bytes: [u8; OUTPUT_SIZE]) -> Self {
196        Self(bytes)
197    }
198
199    /// Create from a slice (returns None if wrong length)
200    pub fn from_slice(bytes: &[u8]) -> Option<Self> {
201        if bytes.len() != OUTPUT_SIZE {
202            return None;
203        }
204        let mut arr = [0u8; OUTPUT_SIZE];
205        arr.copy_from_slice(bytes);
206        Some(Self(arr))
207    }
208
209    /// Get the raw output bytes
210    pub fn as_bytes(&self) -> &[u8; OUTPUT_SIZE] {
211        &self.0
212    }
213
214    /// Convert VRF output to a natural number (big-endian)
215    ///
216    /// This matches Cardano's `getOutputVRFNatural` function used in
217    /// leader election to compare against the stake threshold.
218    ///
219    /// # Example
220    ///
221    /// ```
222    /// use cardano_crypto::vrf::OutputVrf;
223    ///
224    /// let output = OutputVrf::new([0u8; 64]);
225    /// let natural = output.to_natural();
226    /// // natural is a big integer representation
227    /// ```
228    #[cfg(feature = "alloc")]
229    pub fn to_natural(&self) -> alloc::vec::Vec<u8> {
230        // Return bytes in big-endian order (already in big-endian from SHA-512)
231        self.0.to_vec()
232    }
233
234    /// Convert to u128 (truncated, using first 16 bytes)
235    ///
236    /// Useful for quick comparisons where full precision isn't needed.
237    pub fn to_u128(&self) -> u128 {
238        let mut bytes = [0u8; 16];
239        bytes.copy_from_slice(&self.0[..16]);
240        u128::from_be_bytes(bytes)
241    }
242}
243
244// ============================================================================
245// CertifiedVRF - VRF output with proof (certificate)
246// ============================================================================
247
248/// A VRF output certified by its proof
249///
250/// Matches Cardano's `CertifiedVRF v a` type from cardano-crypto-class.
251/// Bundles the VRF output with its proof (certificate) for verification.
252///
253/// # Examples
254///
255/// ```
256/// use cardano_crypto::vrf::{VrfDraft03, CertifiedVrf};
257///
258/// let seed = [42u8; 32];
259/// let (secret_key, public_key) = VrfDraft03::keypair_from_seed(&seed);
260/// let message = b"test input";
261///
262/// // Generate certified VRF output
263/// let certified = CertifiedVrf::eval(&secret_key, message).unwrap();
264///
265/// // Verify the certified output
266/// assert!(certified.verify(&public_key, message).is_ok());
267/// ```
268#[derive(Clone, PartialEq, Eq)]
269pub struct CertifiedVrf {
270    /// The VRF output (hash)
271    pub output: OutputVrf,
272    /// The VRF proof (certificate)
273    pub proof: [u8; DRAFT03_PROOF_SIZE],
274}
275
276impl core::fmt::Debug for CertifiedVrf {
277    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
278        f.debug_struct("CertifiedVrf")
279            .field("output", &self.output)
280            .field("proof", &format!("<{} bytes>", self.proof.len()))
281            .finish()
282    }
283}
284
285impl CertifiedVrf {
286    /// Evaluate VRF and return certified output
287    ///
288    /// This corresponds to `evalCertified` in cardano-crypto-class.
289    ///
290    /// # Parameters
291    ///
292    /// * `secret_key` - The VRF secret key (64 bytes)
293    /// * `message` - The input message to hash
294    ///
295    /// # Returns
296    ///
297    /// A `CertifiedVrf` containing both the output and proof
298    pub fn eval(
299        secret_key: &[u8; SECRET_KEY_SIZE],
300        message: &[u8],
301    ) -> crate::common::CryptoResult<Self> {
302        let proof = VrfDraft03::prove(secret_key, message)?;
303        let output_bytes = VrfDraft03::proof_to_hash(&proof)?;
304
305        Ok(Self {
306            output: OutputVrf::new(output_bytes),
307            proof,
308        })
309    }
310
311    /// Verify the certified VRF output
312    ///
313    /// This corresponds to `verifyCertified` in cardano-crypto-class.
314    ///
315    /// # Parameters
316    ///
317    /// * `public_key` - The VRF public key
318    /// * `message` - The original input message
319    ///
320    /// # Returns
321    ///
322    /// * `Ok(())` if verification succeeds
323    /// * `Err(...)` if verification fails
324    pub fn verify(
325        &self,
326        public_key: &[u8; PUBLIC_KEY_SIZE],
327        message: &[u8],
328    ) -> crate::common::CryptoResult<()> {
329        let output = VrfDraft03::verify(public_key, &self.proof, message)?;
330
331        if output != *self.output.as_bytes() {
332            return Err(crate::common::CryptoError::VerificationFailed);
333        }
334
335        Ok(())
336    }
337
338    /// Get the VRF output
339    pub fn get_output(&self) -> &OutputVrf {
340        &self.output
341    }
342
343    /// Get the VRF proof (certificate)
344    pub fn get_proof(&self) -> &[u8; DRAFT03_PROOF_SIZE] {
345        &self.proof
346    }
347}
348
349// ============================================================================
350// Cardano-node compatible type aliases
351// ============================================================================
352
353/// VRF signing key type (matches cardano-node's `VrfSigningKey`)
354///
355/// This is a 64-byte array containing the seed and public key.
356pub type VrfSigningKey = [u8; SECRET_KEY_SIZE];
357
358/// VRF verification key type (matches cardano-node's `VrfVerificationKey`)
359///
360/// This is a 32-byte compressed Edwards curve point.
361pub type VrfVerificationKey = [u8; PUBLIC_KEY_SIZE];
362
363/// VRF proof type
364///
365/// This is an 80-byte proof for Draft-03.
366pub type VrfProof = [u8; DRAFT03_PROOF_SIZE];
367
368/// VRF key pair (matches cardano-node's `KeyPair VrfKey`)
369///
370/// Contains both the signing key and verification key.
371///
372/// # Example
373///
374/// ```
375/// use cardano_crypto::vrf::{VrfDraft03, VrfKeyPair};
376///
377/// let seed = [42u8; 32];
378/// let keypair = VrfKeyPair::generate(&seed);
379///
380/// let message = b"test";
381/// let proof = VrfDraft03::prove(&keypair.signing_key, message).unwrap();
382/// let output = VrfDraft03::verify(&keypair.verification_key, &proof, message).unwrap();
383/// ```
384#[derive(Clone, PartialEq, Eq)]
385pub struct VrfKeyPair {
386    /// The VRF signing (secret) key
387    pub signing_key: VrfSigningKey,
388    /// The VRF verification (public) key
389    pub verification_key: VrfVerificationKey,
390}
391
392impl core::fmt::Debug for VrfKeyPair {
393    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
394        f.debug_struct("VrfKeyPair")
395            .field("signing_key", &"<redacted>")
396            .field(
397                "verification_key",
398                &format!("<{} bytes>", self.verification_key.len()),
399            )
400            .finish()
401    }
402}
403
404impl VrfKeyPair {
405    /// Generate a VRF key pair from a seed
406    pub fn generate(seed: &[u8; SEED_SIZE]) -> Self {
407        let (signing_key, verification_key) = VrfDraft03::keypair_from_seed(seed);
408        Self {
409            signing_key,
410            verification_key,
411        }
412    }
413
414    /// Create from existing keys
415    pub fn from_keys(signing_key: VrfSigningKey, verification_key: VrfVerificationKey) -> Self {
416        Self {
417            signing_key,
418            verification_key,
419        }
420    }
421}
422
423// ============================================================================
424// CBOR Trait Implementations for VRF Types
425// ============================================================================
426
427#[cfg(feature = "cbor")]
428mod cbor_impl {
429    use super::*;
430    use crate::cbor::{
431        decode_bytes, encode_bytes, encoded_size_bytes, CborError, FromCbor, ToCbor,
432    };
433
434    impl ToCbor for OutputVrf {
435        #[cfg(feature = "alloc")]
436        fn to_cbor(&self) -> Vec<u8> {
437            encode_bytes(&self.0)
438        }
439
440        fn encoded_size(&self) -> usize {
441            encoded_size_bytes(OUTPUT_SIZE)
442        }
443    }
444
445    impl FromCbor for OutputVrf {
446        fn from_cbor(bytes: &[u8]) -> Result<Self, CborError> {
447            let decoded = decode_bytes(bytes)?;
448            Self::from_slice(&decoded).ok_or(CborError::InvalidLength)
449        }
450    }
451
452    impl ToCbor for CertifiedVrf {
453        #[cfg(feature = "alloc")]
454        fn to_cbor(&self) -> Vec<u8> {
455            // Encode as CBOR bytes containing the proof
456            // The output can be recomputed from the proof
457            encode_bytes(&self.proof)
458        }
459
460        fn encoded_size(&self) -> usize {
461            encoded_size_bytes(DRAFT03_PROOF_SIZE)
462        }
463    }
464
465    impl FromCbor for CertifiedVrf {
466        fn from_cbor(bytes: &[u8]) -> Result<Self, CborError> {
467            let decoded = decode_bytes(bytes)?;
468            if decoded.len() != DRAFT03_PROOF_SIZE {
469                return Err(CborError::InvalidLength);
470            }
471            let mut proof = [0u8; DRAFT03_PROOF_SIZE];
472            proof.copy_from_slice(&decoded);
473
474            // Compute output from proof
475            let output_bytes =
476                VrfDraft03::proof_to_hash(&proof).map_err(|_| CborError::DeserializationFailed)?;
477
478            Ok(Self {
479                output: OutputVrf::new(output_bytes),
480                proof,
481            })
482        }
483    }
484
485    // Note: VrfVerificationKey, VrfSigningKey, and VrfProof are type aliases for [u8; N],
486    // so they use the implementations in cbor/mod.rs for [u8; 32], [u8; 64], and [u8; 80].
487}