Skip to content

Commit

Permalink
Implement EpochNonce as a NonceGenerator
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewWestberg committed Aug 13, 2024
1 parent 2443503 commit ceeec1a
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 4 deletions.
1 change: 1 addition & 0 deletions pallas-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pallas-codec = { version = "=0.29.0", path = "../pallas-codec" }
serde = "1.0.143"

[dev-dependencies]
itertools = "0.13"
quickcheck = "1.0"
quickcheck_macros = "1.0"
rand = "0.8"
Expand Down
86 changes: 86 additions & 0 deletions pallas-crypto/src/nonce/epoch_nonce.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use crate::hash::{Hash, Hasher};
use crate::nonce::{Error, NonceGenerator};

/// A nonce generator that calculates an epoch nonce from the eta_v value (nc) of the block right before
/// the stability window and the block hash of the first block from the previous epoch (nh).
#[derive(Debug, Clone)]
pub struct EpochNonce {
pub nonce: Hash<32>,
}

impl EpochNonce {
/// Create a new [`EpochNonce`] generator.
/// params:
/// - nc: the eta_v value of the block right before the stability window.
/// - nh: the block hash of the first block from the previous epoch.
/// - extra_entropy: optional extra entropy to be used in the nonce calculation.
pub fn new(nc: Hash<32>, nh: Hash<32>, extra_entropy: Option<&[u8]>) -> Self {
let mut hasher = Hasher::<256>::new();
hasher.input(nc.as_ref());
hasher.input(nh.as_ref());
let epoch_nonce = hasher.finalize();
if let Some(extra_entropy) = extra_entropy {
let mut hasher = Hasher::<256>::new();
hasher.input(epoch_nonce.as_ref());
hasher.input(extra_entropy);
let extra_nonce = hasher.finalize();
Self { nonce: extra_nonce }
} else {
Self { nonce: epoch_nonce }
}
}
}

impl NonceGenerator for EpochNonce {
fn finalize(&mut self) -> Result<Hash<32>, Error> {
Ok(self.nonce)
}
}

#[cfg(test)]
mod tests {
use itertools::izip;

use crate::hash::Hash;

use super::*;

#[test]
fn test_epoch_nonce() {
let nc_values = vec![
hex::decode("e86e133bd48ff5e79bec43af1ac3e348b539172f33e502d2c96735e8c51bd04d")
.unwrap(),
hex::decode("d1340a9c1491f0face38d41fd5c82953d0eb48320d65e952414a0c5ebaf87587")
.unwrap(),
];
let nh_values = vec![
hex::decode("d7a1ff2a365abed59c9ae346cba842b6d3df06d055dba79a113e0704b44cc3e9")
.unwrap(),
hex::decode("ee91d679b0a6ce3015b894c575c799e971efac35c7a8cbdc2b3f579005e69abd")
.unwrap(),
];
let ee = hex::decode("d982e06fd33e7440b43cefad529b7ecafbaa255e38178ad4189a37e4ce9bf1fa")
.unwrap();
let extra_entropy_values: Vec<Option<&[u8]>> = vec![None, Some(&ee)];
let expected_epoch_nonces = vec![
hex::decode("e536a0081ddd6d19786e9d708a85819a5c3492c0da7349f59c8ad3e17e4acd98")
.unwrap(),
hex::decode("0022cfa563a5328c4fb5c8017121329e964c26ade5d167b1bd9b2ec967772b60")
.unwrap(),
];

for (nc_value, nh_value, extra_entropy_value, expected_epoch_nonce) in izip!(
nc_values.iter(),
nh_values.iter(),
extra_entropy_values.iter(),
expected_epoch_nonces.iter()
) {
let nc: Hash<32> = Hash::from(nc_value.as_slice());
let nh: Hash<32> = Hash::from(nh_value.as_slice());
let extra_entropy = *extra_entropy_value;
let mut epoch_nonce = EpochNonce::new(nc, nh, extra_entropy);
let nonce = epoch_nonce.finalize().unwrap();
assert_eq!(nonce.as_ref(), expected_epoch_nonce.as_slice());
}
}
}
5 changes: 4 additions & 1 deletion pallas-crypto/src/nonce/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use thiserror::Error;

use crate::hash::Hash;

pub mod epoch_nonce;
pub mod rolling_nonce;

#[derive(Error, Debug)]
Expand All @@ -10,5 +13,5 @@ pub enum Error {

/// A trait for generating nonces.
pub trait NonceGenerator: Sized {
fn finalize(&mut self) -> Result<Self, Error>;
fn finalize(&mut self) -> Result<Hash<32>, Error>;
}
6 changes: 3 additions & 3 deletions pallas-crypto/src/nonce/rolling_nonce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl RollingNonce {
}

impl NonceGenerator for RollingNonce {
fn finalize(&mut self) -> Result<Self, Error> {
fn finalize(&mut self) -> Result<Hash<32>, Error> {
if self.block_eta_v.is_none() {
return Err(Error::Nonce(
"Must call apply_block before finalize!".to_string(),
Expand All @@ -40,7 +40,7 @@ impl NonceGenerator for RollingNonce {
let mut hasher = Hasher::<256>::new();
hasher.input(self.nonce.as_ref());
hasher.input(self.block_eta_v.unwrap().as_ref());
Ok(RollingNonce::new(hasher.finalize()))
Ok(hasher.finalize())
}
}

Expand Down Expand Up @@ -155,7 +155,7 @@ mod tests {
for (eta_vrf_0, expected_eta_v) in eta_vrf_0_values.iter().zip(expected_eta_v_values.iter())
{
nonce.apply_block(eta_vrf_0).unwrap();
nonce = nonce.finalize().unwrap();
nonce = RollingNonce::new(nonce.finalize().unwrap());
assert_eq!(nonce.nonce.as_ref(), expected_eta_v.as_slice());
}
}
Expand Down

0 comments on commit ceeec1a

Please sign in to comment.