diff --git a/pallas-codec/src/utils.rs b/pallas-codec/src/utils.rs index 5781b4c6..81bfdfa8 100644 --- a/pallas-codec/src/utils.rs +++ b/pallas-codec/src/utils.rs @@ -1340,6 +1340,12 @@ impl From for Vec { } } +impl From for [u8; N] { + fn from(b: Bytes) -> Self { + b.0.as_slice()[..N].try_into().expect("Infallible") + } +} + impl Deref for Bytes { type Target = Vec; diff --git a/pallas-crypto/src/vrf/mod.rs b/pallas-crypto/src/vrf/mod.rs index 0dd8eaf8..bb0d0dee 100644 --- a/pallas-crypto/src/vrf/mod.rs +++ b/pallas-crypto/src/vrf/mod.rs @@ -19,6 +19,12 @@ pub const VRF_PUBLIC_KEY_SIZE: usize = 32; pub const VRF_SECRET_KEY_SIZE: usize = 32; pub const VRF_PROOF_HASH_SIZE: usize = 64; +pub type VrfSeedBytes = [u8; VRF_SEED_SIZE]; +pub type VrfProofBytes = [u8; VRF_PROOF_SIZE]; +pub type VrfPublicKeyBytes = [u8; VRF_PUBLIC_KEY_SIZE]; +pub type VrfSecretKeyBytes = [u8; VRF_SECRET_KEY_SIZE]; +pub type VrfProofHashBytes = [u8; VRF_PROOF_HASH_SIZE]; + // Wrapper for VRF secret key pub struct VrfSecretKey { secret_key_03: SecretKey03, @@ -35,8 +41,8 @@ pub struct VrfProof { } // Create a VrfSecretKey from a slice -impl From<&[u8; VRF_SECRET_KEY_SIZE]> for VrfSecretKey { - fn from(slice: &[u8; VRF_SECRET_KEY_SIZE]) -> Self { +impl From<&VrfSecretKeyBytes> for VrfSecretKey { + fn from(slice: &VrfSecretKeyBytes) -> Self { VrfSecretKey { secret_key_03: SecretKey03::from_bytes(slice), } @@ -44,8 +50,8 @@ impl From<&[u8; VRF_SECRET_KEY_SIZE]> for VrfSecretKey { } // Create a VrfPublicKey from a slice -impl From<&[u8; VRF_PUBLIC_KEY_SIZE]> for VrfPublicKey { - fn from(slice: &[u8; VRF_PUBLIC_KEY_SIZE]) -> Self { +impl From<&VrfPublicKeyBytes> for VrfPublicKey { + fn from(slice: &VrfPublicKeyBytes) -> Self { VrfPublicKey { public_key_03: PublicKey03::from_bytes(slice), } @@ -53,10 +59,10 @@ impl From<&[u8; VRF_PUBLIC_KEY_SIZE]> for VrfPublicKey { } // Create a VrfProof from a slice -impl From<&[u8; VRF_PROOF_SIZE]> for VrfProof { - fn from(slice: &[u8; VRF_PROOF_SIZE]) -> Self { +impl From<&VrfProofBytes> for VrfProof { + fn from(slice: &VrfProofBytes) -> Self { VrfProof { - proof_03: VrfProof03::from_bytes(slice).unwrap(), + proof_03: VrfProof03::from_bytes(slice).expect("Infallible"), } } } diff --git a/pallas-primitives/src/babbage/model.rs b/pallas-primitives/src/babbage/model.rs index 5e795dd5..02fc5166 100644 --- a/pallas-primitives/src/babbage/model.rs +++ b/pallas-primitives/src/babbage/model.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use pallas_codec::minicbor::{Decode, Encode}; -use pallas_crypto::hash::Hash; +use pallas_crypto::hash::{Hash, Hasher}; use pallas_codec::utils::{Bytes, CborWrap, KeepRaw, KeyValuePairs, MaybeIndefArray, Nullable}; @@ -313,6 +313,34 @@ impl<'a> From> for TransactionBody { } } +pub enum VrfDerivation { + Leader, + Nonce, +} + +pub fn derive_tagged_vrf_output( + block_vrf_output_bytes: &[u8], + derivation: VrfDerivation, +) -> Vec { + let mut tagged_vrf: Vec = match derivation { + VrfDerivation::Leader => vec![0x4C_u8], /* "L" */ + VrfDerivation::Nonce => vec![0x4E_u8], /* "N" */ + }; + + tagged_vrf.extend(block_vrf_output_bytes); + Hasher::<256>::hash(&tagged_vrf).to_vec() +} + +impl HeaderBody { + pub fn leader_vrf_output(&self) -> Vec { + derive_tagged_vrf_output(&self.vrf_result.0, VrfDerivation::Leader) + } + + pub fn nonce_vrf_output(&self) -> Vec { + derive_tagged_vrf_output(&self.vrf_result.0, VrfDerivation::Nonce) + } +} + #[derive(Debug, PartialEq, Eq, Clone)] pub enum PseudoTransactionOutput { Legacy(LegacyTransactionOutput), diff --git a/pallas-traverse/src/header.rs b/pallas-traverse/src/header.rs index ddcb9b8f..7eefe7a7 100644 --- a/pallas-traverse/src/header.rs +++ b/pallas-traverse/src/header.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::ops::Deref; use pallas_codec::minicbor; -use pallas_crypto::hash::{Hash, Hasher}; +use pallas_crypto::hash::Hash; use pallas_primitives::{alonzo, babbage, byron}; use crate::{wellknown::GenesisValues, Era, Error, MultiEraHeader, OriginalHash}; @@ -109,11 +109,7 @@ impl<'b> MultiEraHeader<'b> { match self { MultiEraHeader::EpochBoundary(_) => Err(Error::InvalidEra(Era::Byron)), MultiEraHeader::ShelleyCompatible(x) => Ok(x.header_body.leader_vrf.0.to_vec()), - MultiEraHeader::BabbageCompatible(x) => { - let mut leader_tagged_vrf: Vec = vec![0x4C_u8]; /* "L" */ - leader_tagged_vrf.extend(&*x.header_body.vrf_result.0); - Ok(Hasher::<256>::hash(&leader_tagged_vrf).to_vec()) - } + MultiEraHeader::BabbageCompatible(x) => Ok(x.header_body.leader_vrf_output()), MultiEraHeader::Byron(_) => Err(Error::InvalidEra(Era::Byron)), } } @@ -122,11 +118,7 @@ impl<'b> MultiEraHeader<'b> { match self { MultiEraHeader::EpochBoundary(_) => Err(Error::InvalidEra(Era::Byron)), MultiEraHeader::ShelleyCompatible(x) => Ok(x.header_body.nonce_vrf.0.to_vec()), - MultiEraHeader::BabbageCompatible(x) => { - let mut nonce_tagged_vrf: Vec = vec![0x4E_u8]; /* "N" */ - nonce_tagged_vrf.extend(&*x.header_body.vrf_result.0); - Ok(Hasher::<256>::hash(&nonce_tagged_vrf).to_vec()) - } + MultiEraHeader::BabbageCompatible(x) => Ok(x.header_body.nonce_vrf_output()), MultiEraHeader::Byron(_) => Err(Error::InvalidEra(Era::Byron)), } }