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}