use tfhe_versionable::Versionize;
use crate::conformance::ParameterSetConformant;
use crate::core_crypto::backward_compatibility::entities::lwe_keyswitch_key::LweKeyswitchKeyVersions;
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Versionize)]
#[versionize(LweKeyswitchKeyVersions)]
pub struct LweKeyswitchKey<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
output_lwe_size: LweSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for LweKeyswitchKey<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for LweKeyswitchKey<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
pub fn lwe_keyswitch_key_input_key_element_encrypted_size(
decomp_level_count: DecompositionLevelCount,
output_lwe_size: LweSize,
) -> usize {
decomp_level_count.0 * output_lwe_size.0
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
pub fn from_container(
container: C,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
output_lwe_size: LweSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
assert!(
container.container_len() > 0,
"Got an empty container to create an LweKeyswitchKey"
);
assert!(
container.container_len().is_multiple_of(
lwe_keyswitch_key_input_key_element_encrypted_size(
decomp_level_count,
output_lwe_size
)
),
"The provided container length is not valid. \
It needs to be dividable by decomp_level_count * output_lwe_size: {}. \
Got container length: {} and decomp_level_count: {decomp_level_count:?}, \
output_lwe_size: {output_lwe_size:?}.",
decomp_level_count.0 * output_lwe_size.0,
container.container_len()
);
Self {
data: container,
decomp_base_log,
decomp_level_count,
output_lwe_size,
ciphertext_modulus,
}
}
pub fn decomposition_base_log(&self) -> DecompositionBaseLog {
self.decomp_base_log
}
pub fn decomposition_level_count(&self) -> DecompositionLevelCount {
self.decomp_level_count
}
pub fn input_key_lwe_dimension(&self) -> LweDimension {
LweDimension(self.data.container_len() / self.input_key_element_encrypted_size())
}
pub fn output_key_lwe_dimension(&self) -> LweDimension {
self.output_lwe_size.to_lwe_dimension()
}
pub fn output_lwe_size(&self) -> LweSize {
self.output_lwe_size
}
pub fn input_key_element_encrypted_size(&self) -> usize {
lwe_keyswitch_key_input_key_element_encrypted_size(
self.decomp_level_count,
self.output_lwe_size,
)
}
pub fn as_view(&self) -> LweKeyswitchKeyView<'_, Scalar> {
LweKeyswitchKey::from_container(
self.as_ref(),
self.decomp_base_log,
self.decomp_level_count,
self.output_lwe_size,
self.ciphertext_modulus,
)
}
pub fn into_container(self) -> C {
self.data
}
pub fn as_lwe_ciphertext_list(&self) -> LweCiphertextListView<'_, Scalar> {
LweCiphertextListView::from_container(
self.as_ref(),
self.output_lwe_size(),
self.ciphertext_modulus(),
)
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> LweKeyswitchKey<C> {
pub fn as_mut_view(&mut self) -> LweKeyswitchKeyMutView<'_, Scalar> {
let decomp_base_log = self.decomp_base_log;
let decomp_level_count = self.decomp_level_count;
let output_lwe_size = self.output_lwe_size;
let ciphertext_modulus = self.ciphertext_modulus;
LweKeyswitchKey::from_container(
self.as_mut(),
decomp_base_log,
decomp_level_count,
output_lwe_size,
ciphertext_modulus,
)
}
pub fn as_mut_lwe_ciphertext_list(&mut self) -> LweCiphertextListMutView<'_, Scalar> {
let output_lwe_size = self.output_lwe_size();
let ciphertext_modulus = self.ciphertext_modulus();
LweCiphertextListMutView::from_container(self.as_mut(), output_lwe_size, ciphertext_modulus)
}
}
pub type LweKeyswitchKeyOwned<Scalar> = LweKeyswitchKey<Vec<Scalar>>;
pub type LweKeyswitchKeyView<'data, Scalar> = LweKeyswitchKey<&'data [Scalar]>;
pub type LweKeyswitchKeyMutView<'data, Scalar> = LweKeyswitchKey<&'data mut [Scalar]>;
impl<Scalar: UnsignedInteger> LweKeyswitchKeyOwned<Scalar> {
pub fn new(
fill_with: Scalar,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
input_key_lwe_dimension: LweDimension,
output_key_lwe_dimension: LweDimension,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> Self {
Self::from_container(
vec![
fill_with;
input_key_lwe_dimension.0
* lwe_keyswitch_key_input_key_element_encrypted_size(
decomp_level_count,
output_key_lwe_dimension.to_lwe_size()
)
],
decomp_base_log,
decomp_level_count,
output_key_lwe_dimension.to_lwe_size(),
ciphertext_modulus,
)
}
}
#[derive(Clone, Copy)]
pub struct LweKeyswitchKeyCreationMetadata<Scalar: UnsignedInteger> {
pub decomp_base_log: DecompositionBaseLog,
pub decomp_level_count: DecompositionLevelCount,
pub output_lwe_size: LweSize,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C> for LweKeyswitchKey<C> {
type Metadata = LweKeyswitchKeyCreationMetadata<Scalar>;
#[inline]
fn create_from(from: C, meta: Self::Metadata) -> Self {
let LweKeyswitchKeyCreationMetadata {
decomp_base_log,
decomp_level_count,
output_lwe_size,
ciphertext_modulus,
} = meta;
Self::from_container(
from,
decomp_base_log,
decomp_level_count,
output_lwe_size,
ciphertext_modulus,
)
}
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> ContiguousEntityContainer
for LweKeyswitchKey<C>
{
type Element = C::Element;
type EntityViewMetadata = LweCiphertextListCreationMetadata<Self::Element>;
type EntityView<'this>
= LweCiphertextListView<'this, Self::Element>
where
Self: 'this;
type SelfViewMetadata = LweKeyswitchKeyCreationMetadata<Self::Element>;
type SelfView<'this>
= LweKeyswitchKeyView<'this, Self::Element>
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
LweCiphertextListCreationMetadata {
lwe_size: self.output_lwe_size(),
ciphertext_modulus: self.ciphertext_modulus(),
}
}
fn get_entity_view_pod_size(&self) -> usize {
self.input_key_element_encrypted_size()
}
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
LweKeyswitchKeyCreationMetadata {
decomp_base_log: self.decomposition_base_log(),
decomp_level_count: self.decomposition_level_count(),
output_lwe_size: self.output_lwe_size(),
ciphertext_modulus: self.ciphertext_modulus(),
}
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> ContiguousEntityContainerMut
for LweKeyswitchKey<C>
{
type EntityMutView<'this>
= LweCiphertextListMutView<'this, Self::Element>
where
Self: 'this;
type SelfMutView<'this>
= LweKeyswitchKeyMutView<'this, Self::Element>
where
Self: 'this;
}
pub struct LweKeyswitchKeyConformanceParams<Scalar: UnsignedInteger> {
pub decomp_base_log: DecompositionBaseLog,
pub decomp_level_count: DecompositionLevelCount,
pub output_lwe_size: LweSize,
pub input_lwe_dimension: LweDimension,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> ParameterSetConformant
for LweKeyswitchKey<C>
{
type ParameterSet = LweKeyswitchKeyConformanceParams<Scalar>;
fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool {
let Self {
data,
decomp_base_log,
decomp_level_count,
output_lwe_size,
ciphertext_modulus,
} = self;
*ciphertext_modulus == parameter_set.ciphertext_modulus
&& data.container_len()
== parameter_set.input_lwe_dimension.0
* lwe_keyswitch_key_input_key_element_encrypted_size(
parameter_set.decomp_level_count,
parameter_set.output_lwe_size,
)
&& *decomp_base_log == parameter_set.decomp_base_log
&& *decomp_level_count == parameter_set.decomp_level_count
&& *output_lwe_size == parameter_set.output_lwe_size
}
}