ysc1 0.1.1

YSC1 (Yeun's Stream Cipher 1) based on the Amaryllis-1024 specification
Documentation
use crate::{arx, core::Ysc1Core, Ysc1Variant};
use cipher::{Block, BlockSizeUser, ParBlocksSizeUser, StreamBackend};

/// The software (scalar) backend for YSC1.
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;
}

// Re-add ParBlocksSizeUser for compatibility with cipher v0.4.4
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());
        }
    }
}

/// The state permutation function based on the (2x2) Lai-Massey structure.
#[inline(always)]
pub(crate) fn permutation(state: &mut [u64; 16]) {
    let mut delta = [0u64; 8];

    // 1. Calculate Difference Vector: Δ = (A ⊕ C) || (B ⊕ D)
    for i in 0..4 {
        delta[i] = state[i] ^ state[i + 8];
        delta[i + 4] = state[i + 4] ^ state[i + 12];
    }

    // 2. Apply Round Function: T = ARX(Δ)
    arx::arx_round(&mut delta);

    // 3. State Update
    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];
    }

    // 4. Apply Half-Round Function σ (Linear Permutation)
    state.rotate_left(1);
}