use crate::core_crypto::algorithms::polynomial_algorithms::*;
use crate::core_crypto::commons::math::decomposition::{
SignedDecomposer, SignedDecomposerNonNative,
};
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
pub fn keyswitch_glwe_ciphertext<Scalar, KSKCont, InputCont, OutputCont>(
glwe_keyswitch_key: &GlweKeyswitchKey<KSKCont>,
input_glwe_ciphertext: &GlweCiphertext<InputCont>,
output_glwe_ciphertext: &mut GlweCiphertext<OutputCont>,
) where
Scalar: UnsignedInteger,
KSKCont: Container<Element = Scalar>,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
if glwe_keyswitch_key
.ciphertext_modulus()
.is_compatible_with_native_modulus()
{
keyswitch_glwe_ciphertext_native_mod_compatible(
glwe_keyswitch_key,
input_glwe_ciphertext,
output_glwe_ciphertext,
)
} else {
keyswitch_glwe_ciphertext_other_mod(
glwe_keyswitch_key,
input_glwe_ciphertext,
output_glwe_ciphertext,
)
}
}
pub fn keyswitch_glwe_ciphertext_native_mod_compatible<Scalar, KSKCont, InputCont, OutputCont>(
glwe_keyswitch_key: &GlweKeyswitchKey<KSKCont>,
input_glwe_ciphertext: &GlweCiphertext<InputCont>,
output_glwe_ciphertext: &mut GlweCiphertext<OutputCont>,
) where
Scalar: UnsignedInteger,
KSKCont: Container<Element = Scalar>,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
assert!(
glwe_keyswitch_key.input_key_glwe_dimension()
== input_glwe_ciphertext.glwe_size().to_glwe_dimension(),
"Mismatched input GlweDimension. \
GlweKeyswitchKey input GlweDimension: {:?}, input GlweCiphertext GlweDimension {:?}.",
glwe_keyswitch_key.input_key_glwe_dimension(),
input_glwe_ciphertext.glwe_size().to_glwe_dimension(),
);
assert!(
glwe_keyswitch_key.output_key_glwe_dimension()
== output_glwe_ciphertext.glwe_size().to_glwe_dimension(),
"Mismatched output GlweDimension. \
GlweKeyswitchKey output GlweDimension: {:?}, output GlweCiphertext GlweDimension {:?}.",
glwe_keyswitch_key.output_key_glwe_dimension(),
output_glwe_ciphertext.glwe_size().to_glwe_dimension(),
);
assert!(
glwe_keyswitch_key.polynomial_size() == input_glwe_ciphertext.polynomial_size(),
"Mismatched input PolynomialSize. \
GlweKeyswitchKey input PolynomialSize: {:?}, input GlweCiphertext PolynomialSize {:?}.",
glwe_keyswitch_key.polynomial_size(),
input_glwe_ciphertext.polynomial_size(),
);
assert!(
glwe_keyswitch_key.polynomial_size() == output_glwe_ciphertext.polynomial_size(),
"Mismatched output PolynomialSize. \
GlweKeyswitchKey output PolynomialSize: {:?}, output GlweCiphertext PolynomialSize {:?}.",
glwe_keyswitch_key.polynomial_size(),
output_glwe_ciphertext.polynomial_size(),
);
assert!(glwe_keyswitch_key
.ciphertext_modulus()
.is_compatible_with_native_modulus());
output_glwe_ciphertext.as_mut().fill(Scalar::ZERO);
output_glwe_ciphertext
.get_mut_body()
.as_mut()
.copy_from_slice(input_glwe_ciphertext.get_body().as_ref());
let decomposer = SignedDecomposer::new(
glwe_keyswitch_key.decomposition_base_log(),
glwe_keyswitch_key.decomposition_level_count(),
);
for (keyswitch_key_block, input_mask_element) in glwe_keyswitch_key
.iter()
.zip(input_glwe_ciphertext.get_mask().as_polynomial_list().iter())
{
let mut decomposition_iter = decomposer.decompose_slice(input_mask_element.as_ref());
let mut keyswitch_key_block_iter = keyswitch_key_block.iter();
while let (Some(level_key_ciphertext), Some(decomposed)) = (
keyswitch_key_block_iter.next(),
decomposition_iter.next_term(),
) {
polynomial_list_wrapping_sub_mul_assign(
&mut output_glwe_ciphertext.as_mut_polynomial_list(),
&level_key_ciphertext.as_polynomial_list(),
&Polynomial::from_container(decomposed.as_slice()),
);
}
}
}
pub fn keyswitch_glwe_ciphertext_other_mod<Scalar, KSKCont, InputCont, OutputCont>(
glwe_keyswitch_key: &GlweKeyswitchKey<KSKCont>,
input_glwe_ciphertext: &GlweCiphertext<InputCont>,
output_glwe_ciphertext: &mut GlweCiphertext<OutputCont>,
) where
Scalar: UnsignedInteger,
KSKCont: Container<Element = Scalar>,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
assert!(
glwe_keyswitch_key.input_key_glwe_dimension()
== input_glwe_ciphertext.glwe_size().to_glwe_dimension(),
"Mismatched input GlweDimension. \
GlweKeyswitchKey input GlweDimension: {:?}, input GlweCiphertext GlweDimension {:?}.",
glwe_keyswitch_key.input_key_glwe_dimension(),
input_glwe_ciphertext.glwe_size().to_glwe_dimension(),
);
assert!(
glwe_keyswitch_key.output_key_glwe_dimension()
== output_glwe_ciphertext.glwe_size().to_glwe_dimension(),
"Mismatched output GlweDimension. \
GlweKeyswitchKey output GlweDimension: {:?}, output GlweCiphertext GlweDimension {:?}.",
glwe_keyswitch_key.output_key_glwe_dimension(),
output_glwe_ciphertext.glwe_size().to_glwe_dimension(),
);
assert!(
glwe_keyswitch_key.polynomial_size() == input_glwe_ciphertext.polynomial_size(),
"Mismatched input PolynomialSize. \
GlweKeyswitchKey input PolynomialSize: {:?}, input GlweCiphertext PolynomialSize {:?}.",
glwe_keyswitch_key.polynomial_size(),
input_glwe_ciphertext.polynomial_size(),
);
assert!(
glwe_keyswitch_key.polynomial_size() == output_glwe_ciphertext.polynomial_size(),
"Mismatched output PolynomialSize. \
GlweKeyswitchKey output PolynomialSize: {:?}, output GlweCiphertext PolynomialSize {:?}.",
glwe_keyswitch_key.polynomial_size(),
output_glwe_ciphertext.polynomial_size(),
);
let ciphertext_modulus = glwe_keyswitch_key.ciphertext_modulus();
assert!(!ciphertext_modulus.is_compatible_with_native_modulus());
output_glwe_ciphertext.as_mut().fill(Scalar::ZERO);
polynomial_wrapping_add_assign(
&mut output_glwe_ciphertext.get_mut_body().as_mut_polynomial(),
&input_glwe_ciphertext.get_body().as_polynomial(),
);
let decomposer = SignedDecomposerNonNative::new(
glwe_keyswitch_key.decomposition_base_log(),
glwe_keyswitch_key.decomposition_level_count(),
ciphertext_modulus,
);
let mut scalar_poly = Polynomial::new(Scalar::ZERO, input_glwe_ciphertext.polynomial_size());
for (keyswitch_key_block, input_mask_element) in glwe_keyswitch_key
.iter()
.zip(input_glwe_ciphertext.get_mask().as_polynomial_list().iter())
{
let mut decomposition_iter = decomposer.decompose_slice(input_mask_element.as_ref());
let mut keyswitch_key_block_iter = keyswitch_key_block.iter();
while let (Some(level_key_ciphertext), Some(decomposed)) = (
keyswitch_key_block_iter.next(),
decomposition_iter.next_term(),
) {
decomposed.modular_value(scalar_poly.as_mut());
polynomial_list_wrapping_sub_mul_assign_custom_mod(
&mut output_glwe_ciphertext.as_mut_polynomial_list(),
&level_key_ciphertext.as_polynomial_list(),
&scalar_poly,
ciphertext_modulus.get_custom_modulus().cast_into(),
);
}
}
}