use crate::core_crypto::commons::ciphertext_modulus::CiphertextModulus;
use crate::core_crypto::commons::math::decomposition::DecompositionLevel;
use crate::core_crypto::commons::numeric::{Numeric, UnsignedInteger};
use crate::core_crypto::commons::parameters::DecompositionBaseLog;
use std::fmt::Debug;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DecompositionTerm<T>
where
T: UnsignedInteger,
{
level: usize,
base_log: usize,
value: T,
}
impl<T> DecompositionTerm<T>
where
T: UnsignedInteger,
{
pub(crate) fn new(level: DecompositionLevel, base_log: DecompositionBaseLog, value: T) -> Self {
Self {
level: level.0,
base_log: base_log.0,
value,
}
}
pub fn to_recomposition_summand(&self) -> T {
let shift: usize = <T as Numeric>::BITS - self.base_log * self.level;
self.value << shift
}
pub fn value(&self) -> T {
self.value
}
pub fn level(&self) -> DecompositionLevel {
DecompositionLevel(self.level)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DecompositionTermNonNative<T>
where
T: UnsignedInteger,
{
level: usize,
base_log: usize,
value: T,
ciphertext_modulus: CiphertextModulus<T>,
}
impl<T> DecompositionTermNonNative<T>
where
T: UnsignedInteger,
{
pub(crate) fn new(
level: DecompositionLevel,
base_log: DecompositionBaseLog,
value: T,
ciphertext_modulus: CiphertextModulus<T>,
) -> Self {
Self {
level: level.0,
base_log: base_log.0,
value,
ciphertext_modulus,
}
}
pub fn to_recomposition_summand(&self) -> T {
let modulus_as_t = T::cast_from(self.ciphertext_modulus.get_custom_modulus());
let ciphertext_modulus_bit_count: usize = modulus_as_t.ceil_ilog2().try_into().unwrap();
let shift: usize = ciphertext_modulus_bit_count - self.base_log * self.level;
let value = self.value;
if value.into_signed() >= T::Signed::ZERO {
value << shift
} else {
modulus_as_t.wrapping_add(value << shift)
}
}
pub fn value(&self) -> T {
self.value
}
pub fn modular_value(&self) -> T {
let value = self.value;
if value.into_signed() >= T::Signed::ZERO {
value
} else {
let modulus_as_t = T::cast_from(self.ciphertext_modulus.get_custom_modulus());
modulus_as_t.wrapping_add(value)
}
}
pub fn level(&self) -> DecompositionLevel {
DecompositionLevel(self.level)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DecompositionTermSlice<'a, T>
where
T: UnsignedInteger,
{
slice: &'a [T],
level: usize,
base_log: usize,
}
impl<'a, T> DecompositionTermSlice<'a, T>
where
T: UnsignedInteger,
{
pub(crate) fn new(
level: DecompositionLevel,
base_log: DecompositionBaseLog,
slice: &'a [T],
) -> Self {
Self {
level: level.0,
base_log: base_log.0,
slice,
}
}
pub fn fill_slice_with_recomposition_summand(&self, output: &mut [T]) {
assert_eq!(self.slice.len(), output.len());
output
.iter_mut()
.zip(self.slice.iter())
.for_each(|(dst, &value)| {
let shift: usize = <T as Numeric>::BITS - self.base_log * self.level;
*dst = value << shift
});
}
pub fn as_slice(&self) -> &'a [T] {
self.slice
}
pub fn level(&self) -> DecompositionLevel {
DecompositionLevel(self.level)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DecompositionTermSliceNonNative<'a, T>
where
T: UnsignedInteger,
{
slice: &'a [T],
level: usize,
base_log: usize,
ciphertext_modulus: CiphertextModulus<T>,
}
impl<'a, T> DecompositionTermSliceNonNative<'a, T>
where
T: UnsignedInteger,
{
pub(crate) fn new(
level: DecompositionLevel,
base_log: DecompositionBaseLog,
slice: &'a [T],
ciphertext_modulus: CiphertextModulus<T>,
) -> Self {
Self {
level: level.0,
base_log: base_log.0,
slice,
ciphertext_modulus,
}
}
pub fn to_recomposition_summand(&self, output: &mut [T]) {
assert_eq!(self.slice.len(), output.len());
let modulus_as_t = T::cast_from(self.ciphertext_modulus.get_custom_modulus());
let ciphertext_modulus_bit_count: usize = modulus_as_t.ceil_ilog2().try_into().unwrap();
let shift: usize = ciphertext_modulus_bit_count - self.base_log * self.level;
output
.iter_mut()
.zip(self.slice.iter())
.for_each(|(dst, &value)| {
if value.into_signed() >= T::Signed::ZERO {
*dst = value << shift
} else {
*dst = modulus_as_t.wrapping_add(value << shift)
}
});
}
pub(crate) fn modular_value(&self, output: &mut [T]) {
assert_eq!(self.slice.len(), output.len());
let modulus_as_t = T::cast_from(self.ciphertext_modulus.get_custom_modulus());
self.slice
.iter()
.zip(output.iter_mut())
.for_each(|(&value, output)| {
if value.into_signed() >= T::Signed::ZERO {
*output = value
} else {
*output = modulus_as_t.wrapping_add(value)
}
});
}
pub fn as_slice(&self) -> &'a [T] {
self.slice
}
pub fn level(&self) -> DecompositionLevel {
DecompositionLevel(self.level)
}
}