use super::super::parameters::RadixCiphertextConformanceParams;
use crate::conformance::ParameterSetConformant;
use crate::core_crypto::prelude::UnsignedNumeric;
use crate::integer::backward_compatibility::ciphertext::{
BaseCrtCiphertextVersions, BaseRadixCiphertextVersions, BaseSignedRadixCiphertextVersions,
};
use crate::integer::block_decomposition::{
BlockRecomposer, RecomposableFrom, RecomposableSignedInteger,
};
use crate::integer::ciphertext::{
re_randomize_ciphertext_blocks, ReRandomizationKey, ReRandomizationSeed,
};
use crate::shortint::ciphertext::NotTrivialCiphertextError;
use crate::shortint::parameters::CiphertextConformanceParams;
use crate::shortint::Ciphertext;
use serde::{Deserialize, Serialize};
use tfhe_versionable::Versionize;
#[derive(Serialize, Clone, Deserialize, PartialEq, Eq, Debug, Versionize)]
#[versionize(BaseRadixCiphertextVersions)]
pub struct BaseRadixCiphertext<Block> {
pub(crate) blocks: Vec<Block>,
}
impl<Block> From<Vec<Block>> for BaseRadixCiphertext<Block> {
fn from(blocks: Vec<Block>) -> Self {
Self { blocks }
}
}
pub type RadixCiphertext = BaseRadixCiphertext<Ciphertext>;
impl<T: ParameterSetConformant<ParameterSet = CiphertextConformanceParams>> ParameterSetConformant
for BaseRadixCiphertext<T>
{
type ParameterSet = RadixCiphertextConformanceParams;
fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool {
let Self { blocks } = self;
blocks.len() == params.num_blocks_per_integer
&& blocks
.iter()
.all(|block| block.is_conformant(¶ms.shortint_params))
}
}
impl RadixCiphertext {
pub fn block_carries_are_empty(&self) -> bool {
self.blocks.iter().all(Ciphertext::carry_is_empty)
}
pub fn is_trivial(&self) -> bool {
self.blocks.iter().all(Ciphertext::is_trivial)
}
pub fn decrypt_trivial<Clear>(&self) -> Result<Clear, NotTrivialCiphertextError>
where
Clear: UnsignedNumeric + RecomposableFrom<u64>,
{
if !self.blocks.iter().all(|b| b.is_trivial()) {
return Err(NotTrivialCiphertextError);
}
let bits_in_block = self.blocks[0].message_modulus.0.ilog2();
let decrypted_block_iter = self
.blocks
.iter()
.map(|block| block.decrypt_trivial_message_and_carry().unwrap());
Ok(BlockRecomposer::recompose_unsigned(
decrypted_block_iter,
bits_in_block,
))
}
pub fn re_randomize(
&mut self,
re_randomization_key: ReRandomizationKey<'_>,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
re_randomize_ciphertext_blocks(&mut self.blocks, re_randomization_key, seed)?;
Ok(())
}
}
#[derive(Serialize, Clone, Deserialize, PartialEq, Eq, Debug, Versionize)]
#[versionize(BaseSignedRadixCiphertextVersions)]
pub struct BaseSignedRadixCiphertext<Block> {
pub(crate) blocks: Vec<Block>,
}
impl<Block> From<Vec<Block>> for BaseSignedRadixCiphertext<Block> {
fn from(blocks: Vec<Block>) -> Self {
Self { blocks }
}
}
pub type SignedRadixCiphertext = BaseSignedRadixCiphertext<Ciphertext>;
impl<T: ParameterSetConformant<ParameterSet = CiphertextConformanceParams>> ParameterSetConformant
for BaseSignedRadixCiphertext<T>
{
type ParameterSet = RadixCiphertextConformanceParams;
fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool {
let Self { blocks } = self;
blocks.len() == params.num_blocks_per_integer
&& blocks
.iter()
.all(|block| block.is_conformant(¶ms.shortint_params))
}
}
impl SignedRadixCiphertext {
pub fn block_carries_are_empty(&self) -> bool {
self.blocks.iter().all(Ciphertext::carry_is_empty)
}
pub fn is_trivial(&self) -> bool {
self.blocks.iter().all(Ciphertext::is_trivial)
}
pub fn decrypt_trivial<Clear>(&self) -> Result<Clear, NotTrivialCiphertextError>
where
Clear: RecomposableSignedInteger,
{
if !self.blocks.iter().all(|b| b.is_trivial()) {
return Err(NotTrivialCiphertextError);
}
let bits_in_block = self.blocks[0].message_modulus.0.ilog2();
let decrypted_block_iter = self
.blocks
.iter()
.map(|block| block.decrypt_trivial_message_and_carry().unwrap());
Ok(BlockRecomposer::recompose_signed(
decrypted_block_iter,
bits_in_block,
))
}
pub fn re_randomize(
&mut self,
re_randomization_key: ReRandomizationKey<'_>,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
re_randomize_ciphertext_blocks(&mut self.blocks, re_randomization_key, seed)?;
Ok(())
}
}
#[derive(Serialize, Clone, Deserialize, Versionize)]
#[versionize(BaseCrtCiphertextVersions)]
pub struct BaseCrtCiphertext<Block> {
pub(crate) blocks: Vec<Block>,
pub(crate) moduli: Vec<u64>,
}
pub type CrtCiphertext = BaseCrtCiphertext<Ciphertext>;
impl<Block> From<(Vec<Block>, Vec<u64>)> for BaseCrtCiphertext<Block> {
fn from((blocks, moduli): (Vec<Block>, Vec<u64>)) -> Self {
Self { blocks, moduli }
}
}