macro_rules! kalyna_ofb_variant {
($name:ident, $expanded:ident, $key_bytes:literal, $block_bytes:literal) => {
#[doc = concat!(
"OFB mode over [`super::kalyna::", stringify!($expanded), "`] - see the module doc ",
"comment for the citation and the misuse warning."
)]
pub struct $name {
key: super::kalyna::$expanded,
gamma: [u8; $block_bytes],
used_gamma_len: usize,
}
impl $name {
#[must_use]
pub fn new(key: &[u8; $key_bytes], iv: &[u8; $block_bytes]) -> Self {
Self {
key: super::kalyna::$expanded::new(key),
gamma: *iv,
used_gamma_len: 0,
}
}
pub fn apply_in_place(&mut self, buf: &mut [u8]) {
let mut data_off = 0usize;
if self.used_gamma_len != 0 {
let avail = $block_bytes - self.used_gamma_len;
let n = avail.min(buf.len());
for (b, g) in buf[..n]
.iter_mut()
.zip(&self.gamma[self.used_gamma_len..])
{
*b ^= *g;
}
data_off = n;
self.used_gamma_len += n;
}
while data_off < buf.len() {
self.gamma = self.key.encrypt_block(&self.gamma);
let n = $block_bytes.min(buf.len() - data_off);
for (b, g) in buf[data_off..data_off + n].iter_mut().zip(&self.gamma) {
*b ^= *g;
}
data_off += n;
self.used_gamma_len = n;
}
}
}
};
}
kalyna_ofb_variant!(Kalyna128_128Ofb, Kalyna128_128ExpandedKey, 16, 16);
kalyna_ofb_variant!(Kalyna128_256Ofb, Kalyna128_256ExpandedKey, 32, 16);
kalyna_ofb_variant!(Kalyna256_256Ofb, Kalyna256_256ExpandedKey, 32, 32);
kalyna_ofb_variant!(Kalyna256_512Ofb, Kalyna256_512ExpandedKey, 64, 32);
kalyna_ofb_variant!(Kalyna512_512Ofb, Kalyna512_512ExpandedKey, 64, 64);