tfhe 1.8.0

TFHE-rs is a fully homomorphic encryption (FHE) library that implements Zama's variant of TFHE.
Documentation
use tfhe_csprng::generators::aes_ctr::{Aes128Key, AesBlockCipher};
use tfhe_csprng::generators::default::DefaultAes128BlockCipher;

use crate::transciphering::ciphers::aes::{AesIv, AesPlainKey};
use crate::transciphering::{InsufficientKeystream, StreamCipher, StreamCipherKind};

/// Client-side AES-128 in CTR mode, in clear. Mirrors [`super::fhe::AesFheState`].
pub struct AesPlainState {
    cipher: DefaultAes128BlockCipher,
    iv: AesIv,
    counter: u64,
}

impl AesPlainState {
    pub fn new(key: impl Into<AesPlainKey>, iv: impl Into<AesIv>) -> Self {
        Self {
            cipher: DefaultAes128BlockCipher::new(Aes128Key::new(key.into().to_csprng_key_u128())),
            iv: iv.into(),
            counter: 0,
        }
    }
}

impl StreamCipher for AesPlainState {
    fn kind(&self) -> StreamCipherKind {
        StreamCipherKind::Aes
    }

    fn next_keystream_bits(&mut self, n_bits: usize) -> Result<Vec<u8>, InsufficientKeystream> {
        let end_counter = self
            .counter
            .checked_add(n_bits as u64)
            .ok_or(InsufficientKeystream)?;

        let skip_head = (self.counter % 128) as usize;
        let start_block = self.counter / 128;
        let n_blocks = end_counter.div_ceil(128) - start_block;

        // `generate_next` outputs 16 bytes in NIST order, LSB-first within each
        // byte, matching the trait convention.
        let mut keystream_bytes: Vec<u8> = Vec::with_capacity(n_blocks as usize * 16);
        for i in 0..n_blocks as u128 {
            let counter_value = self.iv.to_u128().wrapping_add(start_block as u128 + i);
            let counter_csprng = u128::from_ne_bytes(counter_value.to_be_bytes());
            let block = self.cipher.generate_next(counter_csprng);
            keystream_bytes.extend_from_slice(&block);
        }

        self.counter = end_counter;

        let mut result = vec![0u8; n_bits.div_ceil(8)];
        for out_idx in 0..n_bits {
            let src_idx = skip_head + out_idx;
            let bit = (keystream_bytes[src_idx / 8] >> (src_idx % 8)) & 1;
            result[out_idx / 8] |= bit << (out_idx % 8);
        }
        Ok(result)
    }

    fn seek(&mut self, target_counter: u64) {
        self.counter = target_counter;
    }

    fn current_counter(&self) -> u64 {
        self.counter
    }
}