use {
crate::{
Aes256,
BlockEncrypt,
BlockSizeTooSmall,
CipherEncrypt,
Csprng,
Ctr,
Entropy,
Hash,
Sha256,
},
std::iter,
};
const SEED_SIZE: usize = 32;
const RESEED_SIZE: usize = 2048;
#[derive(Debug, Clone)]
pub struct Fortuna<Ent, Enc = Aes256, H = Sha256> {
entropy: Ent,
ctr: Ctr<Enc>,
hash: H,
}
impl<Ent, Enc, H, const BLOCK_SIZE: usize> Fortuna<Ent, Enc, H>
where
Enc: BlockEncrypt<EncryptionBlock = [u8; BLOCK_SIZE]>,
{
pub fn new(entropy: Ent, enc: Enc, hash: H) -> Result<Self, BlockSizeTooSmall> {
Ok(Self {
entropy,
ctr: Ctr::new(enc, 0)?,
hash,
})
}
}
impl<Ent, Enc, H> Csprng for Fortuna<Ent, Enc, H>
where
Ent: Entropy,
Enc: BlockEncrypt,
H: Hash<Digest = Enc::EncryptionKey>,
Enc::EncryptionBlock: IntoIterator<Item = u8> + AsMut<[u8]> + Default,
Enc::EncryptionKey: 'static + AsRef<[u8]> + Clone + Default,
{
}
impl<Ent, Enc, H> IntoIterator for Fortuna<Ent, Enc, H>
where
Ent: Entropy,
Enc: BlockEncrypt,
H: Hash<Digest = Enc::EncryptionKey>,
Enc::EncryptionBlock: IntoIterator<Item = u8> + AsMut<[u8]> + Default,
Enc::EncryptionKey: 'static + AsRef<[u8]> + Clone + Default,
{
type Item = u8;
type IntoIter = impl Iterator<Item = u8>;
fn into_iter(mut self) -> Self::IntoIter {
let mut key = Enc::EncryptionKey::default();
iter::repeat_with(move || {
let mut seed = [0; SEED_SIZE];
self.entropy.get(&mut seed);
let mut key_and_seed = Vec::new();
key_and_seed.extend(key.as_ref());
key_and_seed.extend(seed);
key = self.hash.hash(&key_and_seed);
self.ctr.encrypt(vec![0; RESEED_SIZE], key.clone()).unwrap()
})
.flatten()
}
}