use crate::{arx, core::Ysc1Core, Ysc1Variant};
use cipher::{Block, BlockSizeUser, ParBlocksSizeUser, StreamBackend};
pub struct Backend<'a, V: Ysc1Variant>(pub(crate) &'a mut Ysc1Core<V>);
impl<'a, V: Ysc1Variant> BlockSizeUser for Backend<'a, V> {
type BlockSize = cipher::consts::U64;
}
impl<'a, V: Ysc1Variant> ParBlocksSizeUser for Backend<'a, V> {
type ParBlocksSize = cipher::consts::U64;
}
impl<'a, V: Ysc1Variant> StreamBackend for Backend<'a, V> {
#[inline]
fn gen_ks_block(&mut self, block: &mut Block<Self>) {
self.0.counter = self.0.counter.wrapping_add(1);
let mut working_state = self.0.state;
working_state[0] ^= self.0.counter;
for _ in 0..V::KEYSTREAM_ROUNDS {
permutation(&mut working_state);
}
let keystream_s_l = &working_state[0..8];
for (i, chunk) in block.chunks_exact_mut(8).enumerate() {
chunk.copy_from_slice(&keystream_s_l[i].to_le_bytes());
}
}
}
#[inline(always)]
pub(crate) fn permutation(state: &mut [u64; 16]) {
let mut delta = [0u64; 8];
for i in 0..4 {
delta[i] = state[i] ^ state[i + 8];
delta[i + 4] = state[i + 4] ^ state[i + 12];
}
arx::arx_round(&mut delta);
for i in 0..4 {
state[i] ^= delta[i];
state[i + 4] ^= delta[i + 4];
state[i + 8] ^= delta[i];
state[i + 12] ^= delta[i + 4];
}
state.rotate_left(1);
}