use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::generators::EncryptionRandomGenerator;
use crate::core_crypto::commons::math::random::{Distribution, Uniform};
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
use crate::core_crypto::fft_impl::fft64::crypto::wop_pbs::{
circuit_bootstrap_boolean_vertical_packing, circuit_bootstrap_boolean_vertical_packing_scratch,
extract_bits, extract_bits_scratch,
};
use crate::core_crypto::fft_impl::fft64::math::fft::FftView;
use dyn_stack::{PodStack, StackReq};
use rayon::prelude::*;
use tfhe_fft::c64;
pub fn allocate_and_generate_new_circuit_bootstrap_lwe_pfpksk_list<
Scalar,
NoiseDistribution,
LweKeyCont,
GlweKeyCont,
Gen,
>(
input_lwe_secret_key: &LweSecretKey<LweKeyCont>,
output_glwe_secret_key: &GlweSecretKey<GlweKeyCont>,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
noise_distribution: NoiseDistribution,
ciphertext_modulus: CiphertextModulus<Scalar>,
generator: &mut EncryptionRandomGenerator<Gen>,
) -> LwePrivateFunctionalPackingKeyswitchKeyListOwned<Scalar>
where
Scalar: Encryptable<Uniform, NoiseDistribution>,
NoiseDistribution: Distribution,
LweKeyCont: Container<Element = Scalar>,
GlweKeyCont: Container<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert!(
ciphertext_modulus.is_native_modulus(),
"This operation currently only supports native moduli, got modulus {ciphertext_modulus:?}"
);
let mut cbs_pfpksk_list = LwePrivateFunctionalPackingKeyswitchKeyListOwned::new(
Scalar::ZERO,
decomp_base_log,
decomp_level_count,
input_lwe_secret_key.lwe_dimension(),
output_glwe_secret_key.glwe_dimension().to_glwe_size(),
output_glwe_secret_key.polynomial_size(),
FunctionalPackingKeyswitchKeyCount(
output_glwe_secret_key.glwe_dimension().to_glwe_size().0,
),
ciphertext_modulus,
);
generate_circuit_bootstrap_lwe_pfpksk_list(
&mut cbs_pfpksk_list,
input_lwe_secret_key,
output_glwe_secret_key,
noise_distribution,
generator,
);
cbs_pfpksk_list
}
pub fn generate_circuit_bootstrap_lwe_pfpksk_list<
Scalar,
NoiseDistribution,
OutputCont,
LweKeyCont,
GlweKeyCont,
Gen,
>(
output_cbs_pfpksk_list: &mut LwePrivateFunctionalPackingKeyswitchKeyList<OutputCont>,
input_lwe_secret_key: &LweSecretKey<LweKeyCont>,
output_glwe_secret_key: &GlweSecretKey<GlweKeyCont>,
noise_distribution: NoiseDistribution,
generator: &mut EncryptionRandomGenerator<Gen>,
) where
Scalar: Encryptable<Uniform, NoiseDistribution>,
NoiseDistribution: Distribution,
OutputCont: ContainerMut<Element = Scalar>,
LweKeyCont: Container<Element = Scalar>,
GlweKeyCont: Container<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert!(
output_cbs_pfpksk_list.lwe_pfpksk_count().0
== output_glwe_secret_key.glwe_dimension().to_glwe_size().0,
"Current list has {} pfpksk, need to have {} \
(output_glwe_key.glwe_dimension().to_glwe_size())",
output_cbs_pfpksk_list.lwe_pfpksk_count().0,
output_glwe_secret_key.glwe_dimension().to_glwe_size().0
);
assert!(
output_cbs_pfpksk_list
.ciphertext_modulus()
.is_native_modulus(),
"This operation currently only supports native moduli, got modulus {:?}",
output_cbs_pfpksk_list.ciphertext_modulus()
);
let gen_iter = generator
.try_fork_from_config(
output_cbs_pfpksk_list.encryption_fork_config(Uniform, noise_distribution),
)
.unwrap();
let mut last_polynomial_as_list = PolynomialListOwned::new(
Scalar::ZERO,
output_glwe_secret_key.polynomial_size(),
PolynomialCount(1),
);
last_polynomial_as_list.get_mut(0)[0] = Scalar::MAX;
for ((mut lwe_pfpksk, polynomial_to_encrypt), mut loop_generator) in output_cbs_pfpksk_list
.iter_mut()
.zip(
output_glwe_secret_key
.as_polynomial_list()
.iter()
.chain(last_polynomial_as_list.iter()),
)
.zip(gen_iter)
{
generate_lwe_private_functional_packing_keyswitch_key(
input_lwe_secret_key,
output_glwe_secret_key,
&mut lwe_pfpksk,
noise_distribution,
&mut loop_generator,
|x| Scalar::ZERO.wrapping_sub(x),
&polynomial_to_encrypt,
);
}
}
pub fn par_allocate_and_generate_new_circuit_bootstrap_lwe_pfpksk_list<
Scalar,
NoiseDistribution,
LweKeyCont,
GlweKeyCont,
Gen,
>(
input_lwe_secret_key: &LweSecretKey<LweKeyCont>,
output_glwe_secret_key: &GlweSecretKey<GlweKeyCont>,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
noise_distribution: NoiseDistribution,
ciphertext_modulus: CiphertextModulus<Scalar>,
generator: &mut EncryptionRandomGenerator<Gen>,
) -> LwePrivateFunctionalPackingKeyswitchKeyListOwned<Scalar>
where
Scalar: Encryptable<Uniform, NoiseDistribution> + Sync + Send,
NoiseDistribution: Distribution + Sync,
LweKeyCont: Container<Element = Scalar> + Sync,
GlweKeyCont: Container<Element = Scalar> + Sync,
Gen: ParallelByteRandomGenerator,
{
assert!(
ciphertext_modulus.is_native_modulus(),
"This operation currently only supports native moduli, got modulus {ciphertext_modulus:?}"
);
let mut cbs_pfpksk_list = LwePrivateFunctionalPackingKeyswitchKeyListOwned::new(
Scalar::ZERO,
decomp_base_log,
decomp_level_count,
input_lwe_secret_key.lwe_dimension(),
output_glwe_secret_key.glwe_dimension().to_glwe_size(),
output_glwe_secret_key.polynomial_size(),
FunctionalPackingKeyswitchKeyCount(
output_glwe_secret_key.glwe_dimension().to_glwe_size().0,
),
ciphertext_modulus,
);
par_generate_circuit_bootstrap_lwe_pfpksk_list(
&mut cbs_pfpksk_list,
input_lwe_secret_key,
output_glwe_secret_key,
noise_distribution,
generator,
);
cbs_pfpksk_list
}
pub fn par_generate_circuit_bootstrap_lwe_pfpksk_list<
Scalar,
NoiseDistribution,
OutputCont,
LweKeyCont,
GlweKeyCont,
Gen,
>(
output_cbs_pfpksk_list: &mut LwePrivateFunctionalPackingKeyswitchKeyList<OutputCont>,
input_lwe_secret_key: &LweSecretKey<LweKeyCont>,
output_glwe_secret_key: &GlweSecretKey<GlweKeyCont>,
noise_distribution: NoiseDistribution,
generator: &mut EncryptionRandomGenerator<Gen>,
) where
Scalar: Encryptable<Uniform, NoiseDistribution> + Sync + Send,
NoiseDistribution: Distribution + Sync,
OutputCont: ContainerMut<Element = Scalar>,
LweKeyCont: Container<Element = Scalar> + Sync,
GlweKeyCont: Container<Element = Scalar> + Sync,
Gen: ParallelByteRandomGenerator,
{
assert!(
output_cbs_pfpksk_list.lwe_pfpksk_count().0
== output_glwe_secret_key.glwe_dimension().to_glwe_size().0,
"Current list has {} pfpksk, need to have {} \
(output_glwe_key.glwe_dimension().to_glwe_size())",
output_cbs_pfpksk_list.lwe_pfpksk_count().0,
output_glwe_secret_key.glwe_dimension().to_glwe_size().0
);
assert!(
output_cbs_pfpksk_list
.ciphertext_modulus()
.is_native_modulus(),
"This operation currently only supports native moduli, got modulus {:?}",
output_cbs_pfpksk_list.ciphertext_modulus()
);
let gen_iter = generator
.par_try_fork_from_config(
output_cbs_pfpksk_list.encryption_fork_config(Uniform, noise_distribution),
)
.unwrap();
let mut last_polynomial_as_list = PolynomialListOwned::new(
Scalar::ZERO,
output_glwe_secret_key.polynomial_size(),
PolynomialCount(1),
);
last_polynomial_as_list.get_mut(0)[0] = Scalar::MAX;
output_cbs_pfpksk_list
.par_iter_mut()
.zip(
output_glwe_secret_key
.as_polynomial_list()
.par_iter()
.chain(last_polynomial_as_list.par_iter()),
)
.zip(gen_iter)
.for_each(
|((mut lwe_pfpksk, polynomial_to_encrypt), mut loop_generator)| {
par_generate_lwe_private_functional_packing_keyswitch_key(
input_lwe_secret_key,
output_glwe_secret_key,
&mut lwe_pfpksk,
noise_distribution,
&mut loop_generator,
|x| Scalar::ZERO.wrapping_sub(x),
&polynomial_to_encrypt,
);
},
);
}
#[allow(clippy::too_many_arguments)]
pub fn extract_bits_from_lwe_ciphertext_mem_optimized<
Scalar,
InputCont,
OutputCont,
BskCont,
KSKCont,
>(
lwe_in: &LweCiphertext<InputCont>,
lwe_list_out: &mut LweCiphertextList<OutputCont>,
fourier_bsk: &FourierLweBootstrapKey<BskCont>,
ksk: &LweKeyswitchKey<KSKCont>,
delta_log: DeltaLog,
number_of_bits_to_extract: ExtractedBitsCount,
fft: FftView<'_>,
stack: &mut PodStack,
) where
Scalar: UnsignedTorus + CastInto<usize>,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
BskCont: Container<Element = c64>,
KSKCont: Container<Element = Scalar>,
{
assert_eq!(
lwe_list_out.ciphertext_modulus(),
lwe_in.ciphertext_modulus()
);
assert_eq!(lwe_in.ciphertext_modulus(), ksk.ciphertext_modulus());
assert!(
ksk.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
extract_bits(
lwe_list_out.as_mut_view(),
lwe_in.as_view(),
ksk.as_view(),
fourier_bsk.as_view(),
delta_log,
number_of_bits_to_extract,
fft,
stack,
);
}
pub fn extract_bits_from_lwe_ciphertext_mem_optimized_requirement<Scalar>(
lwe_dimension: LweDimension,
ksk_output_key_lwe_dimension: LweDimension,
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
fft: FftView<'_>,
) -> StackReq {
extract_bits_scratch::<Scalar>(
lwe_dimension,
ksk_output_key_lwe_dimension,
glwe_size,
polynomial_size,
fft,
)
}
#[allow(clippy::too_many_arguments)]
pub fn circuit_bootstrap_boolean_vertical_packing_lwe_ciphertext_list_mem_optimized<
Scalar,
InputCont,
OutputCont,
LutCont,
BskCont,
PFPKSKCont,
>(
lwe_list_in: &LweCiphertextList<InputCont>,
lwe_list_out: &mut LweCiphertextList<OutputCont>,
big_lut_as_polynomial_list: &PolynomialList<LutCont>,
fourier_bsk: &FourierLweBootstrapKey<BskCont>,
pfpksk_list: &LwePrivateFunctionalPackingKeyswitchKeyList<PFPKSKCont>,
base_log_cbs: DecompositionBaseLog,
level_cbs: DecompositionLevelCount,
fft: FftView<'_>,
stack: &mut PodStack,
) where
Scalar: UnsignedTorus + CastInto<usize>,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
LutCont: Container<Element = Scalar>,
BskCont: Container<Element = c64>,
PFPKSKCont: Container<Element = Scalar>,
{
assert_eq!(
lwe_list_out.ciphertext_modulus(),
lwe_list_in.ciphertext_modulus()
);
assert_eq!(
lwe_list_in.ciphertext_modulus(),
pfpksk_list.ciphertext_modulus()
);
assert!(
pfpksk_list.ciphertext_modulus().is_native_modulus(),
"This operation currently only supports native moduli"
);
circuit_bootstrap_boolean_vertical_packing(
big_lut_as_polynomial_list.as_view(),
fourier_bsk.as_view(),
lwe_list_out.as_mut_view(),
lwe_list_in.as_view(),
pfpksk_list.as_view(),
level_cbs,
base_log_cbs,
fft,
stack,
);
}
#[allow(clippy::too_many_arguments)]
pub fn circuit_bootstrap_boolean_vertical_packing_lwe_ciphertext_list_mem_optimized_requirement<
Scalar,
>(
lwe_list_in_count: LweCiphertextCount,
lwe_list_out_count: LweCiphertextCount,
lwe_in_size: LweSize,
big_lut_polynomial_count: PolynomialCount,
bsk_output_lwe_size: LweSize,
glwe_size: GlweSize,
fpksk_output_polynomial_size: PolynomialSize,
level_cbs: DecompositionLevelCount,
fft: FftView<'_>,
) -> StackReq {
circuit_bootstrap_boolean_vertical_packing_scratch::<Scalar>(
lwe_list_in_count,
lwe_list_out_count,
lwe_in_size,
big_lut_polynomial_count,
bsk_output_lwe_size,
glwe_size,
fpksk_output_polynomial_size,
level_cbs,
fft,
)
}