use serde::{Deserialize, Serialize};
use tfhe_versionable::Versionize;
use crate::conformance::ParameterSetConformant;
use crate::named::Named;
use crate::shortint::client_key::ClientKey;
use crate::transciphering::backward_compatibility::OneTimePadPlainSecretMaskVersions;
use crate::transciphering::ciphers::one_time_pad::fhe::OneTimePadFheSecretMask;
use crate::transciphering::ciphers::unpack_bits_lsb_first;
use crate::transciphering::{InsufficientKeystream, StreamCipher, StreamCipherKind};
#[derive(Clone, Serialize, Deserialize, Versionize)]
#[versionize(OneTimePadPlainSecretMaskVersions)]
pub struct OneTimePadPlainSecretMask {
secret_mask: Vec<u8>,
bit_count: usize,
}
impl OneTimePadPlainSecretMask {
pub fn try_new(secret_mask: Vec<u8>, bit_count: usize) -> Result<Self, &'static str> {
let expected_byte_count = bit_count.div_ceil(8);
if secret_mask.len() != expected_byte_count {
return Err("Invalid bit_count for provided secret_mask");
}
Ok(Self {
secret_mask,
bit_count,
})
}
pub fn new(secret_mask: Vec<u8>, bit_count: usize) -> Self {
Self::try_new(secret_mask, bit_count).unwrap()
}
pub fn encrypt(&self, client_key: &ClientKey) -> OneTimePadFheSecretMask {
let mut bits = vec![false; self.bit_count];
unpack_bits_lsb_first(&self.secret_mask, &mut bits);
let secret_mask = bits
.into_iter()
.map(|b| client_key.encrypt_bool(b))
.collect();
OneTimePadFheSecretMask::new(secret_mask)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct OneTimePadPlainSecretMaskConformanceParams {
pub n_bits: usize,
}
impl ParameterSetConformant for OneTimePadPlainSecretMask {
type ParameterSet = OneTimePadPlainSecretMaskConformanceParams;
fn is_conformant(&self, params: &Self::ParameterSet) -> bool {
self.bit_count == params.n_bits && self.secret_mask.len() == self.bit_count.div_ceil(8)
}
}
impl Named for OneTimePadPlainSecretMask {
const NAME: &'static str = "transciphering::OneTimePadPlainSecretMask";
}
pub struct OneTimePadPlainState {
secret_mask: OneTimePadPlainSecretMask,
current_counter: u64,
}
impl OneTimePadPlainState {
pub fn new(secret_mask: OneTimePadPlainSecretMask) -> Self {
Self {
secret_mask,
current_counter: 0,
}
}
pub fn remaining_bits(&self) -> u64 {
let bit_count_u64: u64 = self.secret_mask.bit_count.try_into().unwrap();
bit_count_u64.saturating_sub(self.current_counter)
}
}
impl StreamCipher for OneTimePadPlainState {
fn kind(&self) -> StreamCipherKind {
StreamCipherKind::OneTimePad
}
fn next_keystream_bits(&mut self, n_bits: usize) -> Result<Vec<u8>, InsufficientKeystream> {
if n_bits == 0 {
return Ok(vec![]);
}
let n_bits_u64: u64 = n_bits.try_into().unwrap();
if self.remaining_bits() < n_bits_u64 {
return Err(InsufficientKeystream);
}
let start_mask_idx: usize = (self.current_counter / 8).try_into().unwrap();
let last_bit_idx = self.current_counter.checked_add(n_bits_u64 - 1).unwrap();
let stop_mask_idx: usize = (last_bit_idx / 8 + 1).try_into().unwrap();
let mask_bytes_to_return_count = n_bits.div_ceil(8);
let mut result = vec![0u8; mask_bytes_to_return_count];
let mask_bytes = &self.secret_mask.secret_mask[start_mask_idx..stop_mask_idx];
let first_bit_position_in_byte = (self.current_counter % 8) as u32;
if first_bit_position_in_byte == 0 {
result.copy_from_slice(mask_bytes);
} else {
let shift_down = first_bit_position_in_byte;
let shift_up = 8 - shift_down;
for (result_byte, (mask, mask_next)) in result.iter_mut().zip(
mask_bytes
.iter()
.copied()
.zip(mask_bytes[1..].iter().copied().chain(core::iter::once(0))),
) {
*result_byte = (mask >> shift_down) | (mask_next << shift_up);
}
}
let last_bit_position_in_byte = ((n_bits_u64 - 1) % 8) as u32;
let shift_to_apply = 7 - last_bit_position_in_byte;
let last_byte_mask = u8::MAX >> shift_to_apply;
result[mask_bytes_to_return_count - 1] &= last_byte_mask;
self.current_counter = self.current_counter.checked_add(n_bits_u64).unwrap();
Ok(result)
}
fn seek(&mut self, target_counter: u64) {
self.current_counter = target_counter;
}
fn current_counter(&self) -> u64 {
self.current_counter
}
}