From 4caa94ecc8c7dbc7cbbb9230139a436a73bafb58 Mon Sep 17 00:00:00 2001
From: Andrew Westberg <andrewwestberg@gmail.com>
Date: Thu, 3 Oct 2024 14:02:36 +0000
Subject: [PATCH] feat(crypto): Add extra types and conversions

---
 pallas-codec/src/utils.rs              |  6 ++++++
 pallas-crypto/src/vrf/mod.rs           | 20 +++++++++++------
 pallas-primitives/src/babbage/model.rs | 30 +++++++++++++++++++++++++-
 pallas-traverse/src/header.rs          | 14 +++---------
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/pallas-codec/src/utils.rs b/pallas-codec/src/utils.rs
index 5781b4c6..86645aa9 100644
--- a/pallas-codec/src/utils.rs
+++ b/pallas-codec/src/utils.rs
@@ -1340,6 +1340,12 @@ impl From<Bytes> for Vec<u8> {
     }
 }
 
+impl<const N: usize> From<&Bytes> for [u8; N] {
+    fn from(b: &Bytes) -> Self {
+        b.0.as_slice()[..N].try_into().expect("Infallible")
+    }
+}
+
 impl Deref for Bytes {
     type Target = Vec<u8>;
 
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<MintedTransactionBody<'a>> for TransactionBody {
     }
 }
 
+pub enum VrfDerivation {
+    Leader,
+    Nonce,
+}
+
+pub fn derive_tagged_vrf_output(
+    block_vrf_output_bytes: &[u8],
+    derivation: VrfDerivation,
+) -> Vec<u8> {
+    let mut tagged_vrf: Vec<u8> = 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<u8> {
+        derive_tagged_vrf_output(&self.vrf_result.0, VrfDerivation::Leader)
+    }
+
+    pub fn nonce_vrf_output(&self) -> Vec<u8> {
+        derive_tagged_vrf_output(&self.vrf_result.0, VrfDerivation::Nonce)
+    }
+}
+
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum PseudoTransactionOutput<T> {
     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<u8> = 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<u8> = 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)),
         }
     }