#[cfg(feature = "alloc")]
use alloc::{format, vec::Vec};
pub mod cardano_compat;
pub mod draft03;
pub mod draft13;
pub mod test_vectors;
pub use draft03::{
VrfDraft03, OUTPUT_SIZE, PROOF_SIZE as DRAFT03_PROOF_SIZE, PUBLIC_KEY_SIZE, SECRET_KEY_SIZE,
SEED_SIZE,
};
pub use draft13::{VrfDraft13, PROOF_SIZE as DRAFT13_PROOF_SIZE};
pub use cardano_compat::{
cardano_clear_cofactor, cardano_hash_to_curve, cardano_vrf_prove, cardano_vrf_verify,
};
pub trait VrfAlgorithm: Clone + Send + Sync + 'static {
type SecretKey;
type VerificationKey;
type Proof;
type Output;
const ALGORITHM_NAME: &'static str;
const SEED_SIZE: usize;
const SECRET_KEY_SIZE: usize;
const VERIFICATION_KEY_SIZE: usize;
const PROOF_SIZE: usize;
const OUTPUT_SIZE: usize;
fn keypair_from_seed(seed: &[u8; 32]) -> (Self::SecretKey, Self::VerificationKey);
fn derive_verification_key(sk: &Self::SecretKey) -> Self::VerificationKey;
fn prove(sk: &Self::SecretKey, message: &[u8]) -> crate::common::CryptoResult<Self::Proof>;
fn verify(
vk: &Self::VerificationKey,
proof: &Self::Proof,
message: &[u8],
) -> crate::common::CryptoResult<Self::Output>;
fn proof_to_hash(proof: &Self::Proof) -> crate::common::CryptoResult<Self::Output>;
fn raw_serialize_verification_key(vk: &Self::VerificationKey) -> &[u8];
fn raw_deserialize_verification_key(bytes: &[u8]) -> Option<Self::VerificationKey>;
fn raw_serialize_proof(proof: &Self::Proof) -> &[u8];
fn raw_deserialize_proof(bytes: &[u8]) -> Option<Self::Proof>;
#[cfg(feature = "alloc")]
fn hash_verification_key<H: crate::hash::HashAlgorithm>(vk: &Self::VerificationKey) -> Vec<u8> {
let raw = Self::raw_serialize_verification_key(vk);
H::hash(raw)
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct OutputVrf([u8; OUTPUT_SIZE]);
impl core::fmt::Debug for OutputVrf {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "OutputVrf(<{} bytes>)", self.0.len())
}
}
impl OutputVrf {
pub fn new(bytes: [u8; OUTPUT_SIZE]) -> Self {
Self(bytes)
}
pub fn from_slice(bytes: &[u8]) -> Option<Self> {
if bytes.len() != OUTPUT_SIZE {
return None;
}
let mut arr = [0u8; OUTPUT_SIZE];
arr.copy_from_slice(bytes);
Some(Self(arr))
}
pub fn as_bytes(&self) -> &[u8; OUTPUT_SIZE] {
&self.0
}
#[cfg(feature = "alloc")]
pub fn to_natural(&self) -> alloc::vec::Vec<u8> {
self.0.to_vec()
}
pub fn to_u128(&self) -> u128 {
let mut bytes = [0u8; 16];
bytes.copy_from_slice(&self.0[..16]);
u128::from_be_bytes(bytes)
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct CertifiedVrf {
pub output: OutputVrf,
pub proof: [u8; DRAFT03_PROOF_SIZE],
}
impl core::fmt::Debug for CertifiedVrf {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("CertifiedVrf")
.field("output", &self.output)
.field("proof", &format!("<{} bytes>", self.proof.len()))
.finish()
}
}
impl CertifiedVrf {
pub fn eval(
secret_key: &[u8; SECRET_KEY_SIZE],
message: &[u8],
) -> crate::common::CryptoResult<Self> {
let proof = VrfDraft03::prove(secret_key, message)?;
let output_bytes = VrfDraft03::proof_to_hash(&proof)?;
Ok(Self {
output: OutputVrf::new(output_bytes),
proof,
})
}
pub fn verify(
&self,
public_key: &[u8; PUBLIC_KEY_SIZE],
message: &[u8],
) -> crate::common::CryptoResult<()> {
let output = VrfDraft03::verify(public_key, &self.proof, message)?;
if output != *self.output.as_bytes() {
return Err(crate::common::CryptoError::VerificationFailed);
}
Ok(())
}
pub fn get_output(&self) -> &OutputVrf {
&self.output
}
pub fn get_proof(&self) -> &[u8; DRAFT03_PROOF_SIZE] {
&self.proof
}
}
pub type VrfSigningKey = [u8; SECRET_KEY_SIZE];
pub type VrfVerificationKey = [u8; PUBLIC_KEY_SIZE];
pub type VrfProof = [u8; DRAFT03_PROOF_SIZE];
#[derive(Clone, PartialEq, Eq)]
pub struct VrfKeyPair {
pub signing_key: VrfSigningKey,
pub verification_key: VrfVerificationKey,
}
impl core::fmt::Debug for VrfKeyPair {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("VrfKeyPair")
.field("signing_key", &"<redacted>")
.field(
"verification_key",
&format!("<{} bytes>", self.verification_key.len()),
)
.finish()
}
}
impl VrfKeyPair {
pub fn generate(seed: &[u8; SEED_SIZE]) -> Self {
let (signing_key, verification_key) = VrfDraft03::keypair_from_seed(seed);
Self {
signing_key,
verification_key,
}
}
pub fn from_keys(signing_key: VrfSigningKey, verification_key: VrfVerificationKey) -> Self {
Self {
signing_key,
verification_key,
}
}
}
#[cfg(feature = "cbor")]
mod cbor_impl {
use super::*;
use crate::cbor::{
decode_bytes, encode_bytes, encoded_size_bytes, CborError, FromCbor, ToCbor,
};
impl ToCbor for OutputVrf {
#[cfg(feature = "alloc")]
fn to_cbor(&self) -> Vec<u8> {
encode_bytes(&self.0)
}
fn encoded_size(&self) -> usize {
encoded_size_bytes(OUTPUT_SIZE)
}
}
impl FromCbor for OutputVrf {
fn from_cbor(bytes: &[u8]) -> Result<Self, CborError> {
let decoded = decode_bytes(bytes)?;
Self::from_slice(&decoded).ok_or(CborError::InvalidLength)
}
}
impl ToCbor for CertifiedVrf {
#[cfg(feature = "alloc")]
fn to_cbor(&self) -> Vec<u8> {
encode_bytes(&self.proof)
}
fn encoded_size(&self) -> usize {
encoded_size_bytes(DRAFT03_PROOF_SIZE)
}
}
impl FromCbor for CertifiedVrf {
fn from_cbor(bytes: &[u8]) -> Result<Self, CborError> {
let decoded = decode_bytes(bytes)?;
if decoded.len() != DRAFT03_PROOF_SIZE {
return Err(CborError::InvalidLength);
}
let mut proof = [0u8; DRAFT03_PROOF_SIZE];
proof.copy_from_slice(&decoded);
let output_bytes =
VrfDraft03::proof_to_hash(&proof).map_err(|_| CborError::DeserializationFailed)?;
Ok(Self {
output: OutputVrf::new(output_bytes),
proof,
})
}
}
}