use core::marker::PhantomData;
use crate::{
encoding::ternary::{Btrit, T1B1Buf, TritBuf, Trits, T1B1},
hashes::ternary::{Sponge, HASH_LENGTH},
keys::ternary::{
wots::{Error, WotsSecurityLevel},
PrivateKeyGenerator,
},
signatures::ternary::{wots::WotsPrivateKey, SIGNATURE_FRAGMENT_LENGTH},
};
#[derive(Default)]
pub struct WotsSpongePrivateKeyGeneratorBuilder<S> {
security_level: Option<WotsSecurityLevel>,
marker: PhantomData<S>,
}
impl<S: Sponge + Default> WotsSpongePrivateKeyGeneratorBuilder<S> {
pub fn with_security_level(mut self, security_level: WotsSecurityLevel) -> Self {
self.security_level.replace(security_level);
self
}
pub fn build(self) -> Result<WotsSpongePrivateKeyGenerator<S>, Error> {
Ok(WotsSpongePrivateKeyGenerator {
security_level: self.security_level.ok_or(Error::MissingSecurityLevel)?,
marker: PhantomData,
})
}
}
pub struct WotsSpongePrivateKeyGenerator<S> {
security_level: WotsSecurityLevel,
marker: PhantomData<S>,
}
impl<S: Sponge + Default> PrivateKeyGenerator for WotsSpongePrivateKeyGenerator<S> {
type PrivateKey = WotsPrivateKey<S>;
type Error = Error;
fn generate_from_entropy(&self, entropy: &Trits<T1B1>) -> Result<Self::PrivateKey, Self::Error> {
if entropy.len() != HASH_LENGTH {
return Err(Error::InvalidEntropyLength(entropy.len()));
}
if entropy[HASH_LENGTH - 1] != Btrit::Zero {
return Err(Error::NonNullEntropyLastTrit);
}
let mut sponge = S::default();
let mut state = TritBuf::<T1B1Buf>::zeros(self.security_level as usize * SIGNATURE_FRAGMENT_LENGTH);
sponge
.digest_into(entropy, &mut state)
.map_err(|_| Self::Error::FailedSpongeOperation)?;
Ok(Self::PrivateKey {
state,
marker: PhantomData,
})
}
}