diff --git a/pallas-codec/src/utils.rs b/pallas-codec/src/utils.rs index 5781b4c..172ef2c 100644 --- a/pallas-codec/src/utils.rs +++ b/pallas-codec/src/utils.rs @@ -4,6 +4,7 @@ use minicbor::{ Decode, Encode, }; use serde::{Deserialize, Serialize}; +use std::str::FromStr; use std::{collections::HashMap, fmt, hash::Hash as StdHash, ops::Deref}; static TAG_SET: u64 = 258; @@ -1348,6 +1349,14 @@ impl Deref for Bytes { } } +impl TryFrom<&Bytes> for [u8; N] { + type Error = core::array::TryFromSliceError; + + fn try_from(value: &Bytes) -> Result { + value.0.as_slice().try_into() + } +} + impl TryFrom for Bytes { type Error = hex::FromHexError; @@ -1357,6 +1366,15 @@ impl TryFrom for Bytes { } } +impl FromStr for Bytes { + type Err = hex::FromHexError; + + fn from_str(s: &str) -> Result { + let v = hex::decode(s)?; + Ok(Bytes(minicbor::bytes::ByteVec::from(v))) + } +} + impl From for String { fn from(b: Bytes) -> Self { hex::encode(b.deref()) diff --git a/pallas-crypto/src/vrf/mod.rs b/pallas-crypto/src/vrf/mod.rs index 0dd8eaf..bb0d0de 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 5e795dd..02fc516 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 ddcb9b8..7eefe7a 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)), } }