mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-08 22:28:01 -05:00
refactor(tfhe): remove core engines from ShortintEngine
This commit is contained in:
@@ -8,10 +8,10 @@ pub type AccumulatorCallback = Option<extern "C" fn(u64) -> u64>;
|
||||
pub type BivariateAccumulatorCallback = Option<extern "C" fn(u64, u64) -> u64>;
|
||||
|
||||
pub struct ShortintPBSAccumulator(
|
||||
pub(in crate::c_api) crate::core_crypto::prelude::GlweCiphertext64,
|
||||
pub(in crate::c_api) crate::core_crypto::entities::GlweCiphertext<u64>,
|
||||
);
|
||||
pub struct ShortintBivariatePBSAccumulator(
|
||||
pub(in crate::c_api) crate::core_crypto::prelude::GlweCiphertext64,
|
||||
pub(in crate::c_api) crate::core_crypto::entities::GlweCiphertext<u64>,
|
||||
);
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -190,7 +190,7 @@ fn encrypt_ggsw_level_matrix_row<Scalar, KeyCont, InputCont, OutputCont, Gen>(
|
||||
let mut body = row_as_glwe.get_mut_body();
|
||||
body.as_mut().copy_from_slice(sk_poly.as_ref());
|
||||
|
||||
update_with_wrapping_scalar_mul(body.as_mut(), factor);
|
||||
update_slice_with_wrapping_scalar_mul(body.as_mut(), factor);
|
||||
|
||||
encrypt_glwe_ciphertext_in_place(glwe_secret_key, row_as_glwe, noise_parameters, generator);
|
||||
} else {
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::core_crypto::commons::math::torus::UnsignedTorus;
|
||||
use crate::core_crypto::commons::traits::*;
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::specification::dispersion::DispersionParameter;
|
||||
use crate::core_crypto::specification::parameters::*;
|
||||
|
||||
pub fn encrypt_glwe_ciphertext_in_place<Scalar, KeyCont, OutputCont, Gen>(
|
||||
glwe_secret_key: &GlweSecretKeyBase<KeyCont>,
|
||||
@@ -215,3 +216,40 @@ pub fn decrypt_glwe_ciphertext_list<Scalar, KeyCont, InputCont, OutputCont>(
|
||||
decrypt_glwe_ciphertext(glwe_secret_key, &ciphertext, &mut output_sublist);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trivially_encrypt_glwe_ciphertext<Scalar, InputCont, OutputCont>(
|
||||
output: &mut GlweCiphertextBase<OutputCont>,
|
||||
encoded: &PlaintextListBase<InputCont>,
|
||||
) where
|
||||
Scalar: UnsignedTorus,
|
||||
OutputCont: ContainerMut<Element = Scalar>,
|
||||
InputCont: Container<Element = Scalar>,
|
||||
{
|
||||
assert!(
|
||||
output.polynomial_size().0 == encoded.plaintext_count().0,
|
||||
"TODO Error message"
|
||||
);
|
||||
|
||||
let (mut mask, mut body) = output.get_mut_mask_and_body();
|
||||
|
||||
mask.as_mut().fill(Scalar::ZERO);
|
||||
body.as_mut().copy_from_slice(encoded.as_ref());
|
||||
}
|
||||
|
||||
pub fn allocate_and_trivially_encrypt_new_glwe_ciphertext<Scalar, InputCont>(
|
||||
glwe_size: GlweSize,
|
||||
encoded: &PlaintextListBase<InputCont>,
|
||||
) -> GlweCiphertext<Scalar>
|
||||
where
|
||||
Scalar: UnsignedTorus,
|
||||
InputCont: Container<Element = Scalar>,
|
||||
{
|
||||
let polynomial_size = PolynomialSize(encoded.plaintext_count().0);
|
||||
|
||||
let mut new_ct = GlweCiphertext::new(Scalar::ZERO, polynomial_size, glwe_size);
|
||||
|
||||
let mut body = new_ct.get_mut_body();
|
||||
body.as_mut().copy_from_slice(encoded.as_ref());
|
||||
|
||||
new_ct
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ pub fn extract_lwe_sample_from_glwe_ciphertext<Scalar, InputCont, OutputCont>(
|
||||
// We reverse the polynomial
|
||||
lwe_mask_poly.reverse();
|
||||
// We compute the opposite of the proper coefficients
|
||||
update_with_wrapping_opposite(&mut lwe_mask_poly[0..opposite_count]);
|
||||
update_slice_with_wrapping_opposite(&mut lwe_mask_poly[0..opposite_count]);
|
||||
// We rotate the polynomial properly
|
||||
lwe_mask_poly.rotate_left(opposite_count);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
//! Module containing functions related to LWE ciphertext encryption and decryption
|
||||
|
||||
use crate::core_crypto::algorithms::slice_algorithms::*;
|
||||
use crate::core_crypto::commons::crypto::secret::generators::EncryptionRandomGenerator;
|
||||
use crate::core_crypto::algorithms::*;
|
||||
use crate::core_crypto::commons::crypto::secret::generators::{
|
||||
EncryptionRandomGenerator, SecretRandomGenerator,
|
||||
};
|
||||
use crate::core_crypto::commons::math::random::ByteRandomGenerator;
|
||||
#[cfg(feature = "__commons_parallel")]
|
||||
use crate::core_crypto::commons::math::random::ParallelByteRandomGenerator;
|
||||
use crate::core_crypto::commons::math::torus::UnsignedTorus;
|
||||
use crate::core_crypto::commons::numeric::UnsignedInteger;
|
||||
use crate::core_crypto::commons::traits::*;
|
||||
@@ -38,7 +43,10 @@ pub fn encrypt_lwe_ciphertext<Scalar, KeyCont, OutputCont, Gen>(
|
||||
*body.0 = generator.random_noise(noise_parameters);
|
||||
|
||||
// compute the multisum between the secret key and the mask
|
||||
*body.0 = (*body.0).wrapping_add(wrapping_dot_product(mask.as_ref(), lwe_secret_key.as_ref()));
|
||||
*body.0 = (*body.0).wrapping_add(slice_wrapping_dot_product(
|
||||
mask.as_ref(),
|
||||
lwe_secret_key.as_ref(),
|
||||
));
|
||||
|
||||
*body.0 = (*body.0).wrapping_add(encoded.0);
|
||||
}
|
||||
@@ -115,10 +123,10 @@ where
|
||||
|
||||
let (mask, body) = lwe_ciphertext.get_mask_and_body();
|
||||
|
||||
Plaintext(
|
||||
body.0
|
||||
.wrapping_sub(wrapping_dot_product(mask.as_ref(), lwe_secret_key.as_ref())),
|
||||
)
|
||||
Plaintext(body.0.wrapping_sub(slice_wrapping_dot_product(
|
||||
mask.as_ref(),
|
||||
lwe_secret_key.as_ref(),
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn encrypt_lwe_ciphertext_list<Scalar, KeyCont, OutputCont, InputCont, Gen>(
|
||||
@@ -152,3 +160,82 @@ pub fn encrypt_lwe_ciphertext_list<Scalar, KeyCont, OutputCont, InputCont, Gen>(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "__commons_parallel")]
|
||||
use rayon::prelude::*;
|
||||
pub fn par_encrypt_lwe_ciphertext_list<Scalar, KeyCont, OutputCont, InputCont, Gen>(
|
||||
lwe_secret_key: &LweSecretKeyBase<KeyCont>,
|
||||
output: &mut LweCiphertextListBase<OutputCont>,
|
||||
encoded: &PlaintextListBase<InputCont>,
|
||||
noise_parameters: impl DispersionParameter + Sync,
|
||||
generator: &mut EncryptionRandomGenerator<Gen>,
|
||||
) where
|
||||
Scalar: UnsignedTorus + Sync + Send,
|
||||
KeyCont: Container<Element = Scalar> + Sync,
|
||||
OutputCont: ContainerMut<Element = Scalar>,
|
||||
InputCont: Container<Element = Scalar>,
|
||||
Gen: ParallelByteRandomGenerator,
|
||||
{
|
||||
assert!(
|
||||
output.lwe_ciphertext_count().0 == encoded.plaintext_count().0,
|
||||
"Mismatch between number of output cipertexts and input plaintexts. \
|
||||
Got {:?} plaintexts, and {:?} ciphertext.",
|
||||
encoded.plaintext_count(),
|
||||
output.lwe_ciphertext_count()
|
||||
);
|
||||
|
||||
let gen_iter = generator
|
||||
.par_fork_lwe_list_to_lwe::<Scalar>(output.lwe_ciphertext_count(), output.lwe_size())
|
||||
.unwrap();
|
||||
|
||||
encoded
|
||||
.par_iter()
|
||||
.zip(output.par_iter_mut())
|
||||
.zip(gen_iter)
|
||||
.for_each(|((encoded_plaintext_ref, mut ciphertext), mut generator)| {
|
||||
encrypt_lwe_ciphertext(
|
||||
lwe_secret_key,
|
||||
&mut ciphertext,
|
||||
encoded_plaintext_ref.into(),
|
||||
noise_parameters,
|
||||
&mut generator,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
pub fn encrypt_lwe_ciphertext_with_public_key<Scalar, KeyCont, OutputCont, Gen>(
|
||||
lwe_public_key: &LwePublicKeyBase<KeyCont>,
|
||||
output: &mut LweCiphertextBase<OutputCont>,
|
||||
encoded: Plaintext<Scalar>,
|
||||
generator: &mut SecretRandomGenerator<Gen>,
|
||||
) where
|
||||
Scalar: UnsignedTorus,
|
||||
KeyCont: Container<Element = Scalar>,
|
||||
OutputCont: ContainerMut<Element = Scalar>,
|
||||
Gen: ByteRandomGenerator,
|
||||
{
|
||||
assert!(
|
||||
output.lwe_size().to_lwe_dimension() == lwe_public_key.lwe_size().to_lwe_dimension(),
|
||||
"Mismatch between LweDimension of output cipertext and input public key. \
|
||||
Got {:?} in output, and {:?} in public key.",
|
||||
output.lwe_size().to_lwe_dimension(),
|
||||
lwe_public_key.lwe_size().to_lwe_dimension()
|
||||
);
|
||||
|
||||
output.as_mut().fill(Scalar::ZERO);
|
||||
|
||||
let mut ct_choice = vec![Scalar::ZERO; lwe_public_key.zero_encryption_count().0];
|
||||
|
||||
generator.fill_slice_with_random_uniform_binary(&mut ct_choice);
|
||||
|
||||
// Add the public encryption of zeros to get the zero encryption
|
||||
for (&chosen, public_encryption_of_zero) in ct_choice.iter().zip(lwe_public_key.iter()) {
|
||||
if chosen == Scalar::ONE {
|
||||
lwe_ciphertext_in_place_addition(output, &public_encryption_of_zero);
|
||||
}
|
||||
}
|
||||
|
||||
// Add encoded plaintext
|
||||
let body = output.get_mut_body();
|
||||
*body.0 = (*body.0).wrapping_add(encoded.0);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ pub fn keyswitch_lwe_ciphertext<Scalar, KSKCont, InputCont, OutputCont>(
|
||||
for (level_key_ciphertext, decomposed) in
|
||||
keyswitch_key_block.iter().rev().zip(decomposition_iter)
|
||||
{
|
||||
update_with_wrapping_sub_scalar_mul(
|
||||
update_slice_with_wrapping_sub_scalar_mul(
|
||||
output_lwe_ciphertext.as_mut(),
|
||||
level_key_ciphertext.as_ref(),
|
||||
decomposed.value(),
|
||||
|
||||
@@ -14,7 +14,7 @@ pub fn lwe_ciphertext_in_place_addition<Scalar, LhsCont, RhsCont>(
|
||||
LhsCont: ContainerMut<Element = Scalar>,
|
||||
RhsCont: Container<Element = Scalar>,
|
||||
{
|
||||
update_with_wrapping_add(lhs.as_mut(), rhs.as_ref());
|
||||
update_slice_with_wrapping_add(lhs.as_mut(), rhs.as_ref());
|
||||
}
|
||||
|
||||
pub fn lwe_ciphertext_in_place_encoded_addition<Scalar, InCont>(
|
||||
@@ -34,7 +34,7 @@ where
|
||||
Scalar: UnsignedInteger,
|
||||
InCont: ContainerMut<Element = Scalar>,
|
||||
{
|
||||
update_with_wrapping_opposite(ct.as_mut());
|
||||
update_slice_with_wrapping_opposite(ct.as_mut());
|
||||
}
|
||||
|
||||
pub fn lwe_ciphertext_in_place_cleartext_multiplication<Scalar, InCont>(
|
||||
@@ -44,7 +44,7 @@ pub fn lwe_ciphertext_in_place_cleartext_multiplication<Scalar, InCont>(
|
||||
Scalar: UnsignedInteger,
|
||||
InCont: ContainerMut<Element = Scalar>,
|
||||
{
|
||||
update_with_wrapping_scalar_mul(lhs.as_mut(), rhs.0);
|
||||
update_slice_with_wrapping_scalar_mul(lhs.as_mut(), rhs.0);
|
||||
}
|
||||
|
||||
pub fn lwe_ciphertext_in_place_subtraction<Scalar, LhsCont, RhsCont>(
|
||||
@@ -55,7 +55,7 @@ pub fn lwe_ciphertext_in_place_subtraction<Scalar, LhsCont, RhsCont>(
|
||||
LhsCont: ContainerMut<Element = Scalar>,
|
||||
RhsCont: Container<Element = Scalar>,
|
||||
{
|
||||
update_with_wrapping_sub(lhs.as_mut(), rhs.as_ref());
|
||||
update_slice_with_wrapping_sub(lhs.as_mut(), rhs.as_ref());
|
||||
}
|
||||
|
||||
pub fn lwe_ciphertext_cleartext_multiplication<Scalar, InputCont, OutputCont>(
|
||||
|
||||
@@ -51,7 +51,7 @@ pub fn private_functional_keyswitch_lwe_ciphertext_into_glwe_ciphertext<
|
||||
// We compute the multiplication of a ciphertext from the private functional
|
||||
// keyswitching key with a piece of the decomposition and subtract it to the buffer
|
||||
for (level_key_cipher, decomposed) in keyswitch_key_block.iter().rev().zip(decomp) {
|
||||
update_with_wrapping_sub_scalar_mul(
|
||||
update_slice_with_wrapping_sub_scalar_mul(
|
||||
output_glwe_ciphertext.as_mut(),
|
||||
level_key_cipher.as_ref(),
|
||||
decomposed.value(),
|
||||
@@ -94,6 +94,6 @@ pub fn private_functional_keyswitch_lwe_ciphertext_list_and_pack_in_glwe_ciphere
|
||||
MonomialDegree(degree),
|
||||
)
|
||||
});
|
||||
update_with_wrapping_add(output.as_mut(), buffer.as_ref());
|
||||
update_slice_with_wrapping_add(output.as_mut(), buffer.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ pub fn generate_lwe_private_functional_packing_keyswitch_key<
|
||||
.map(DecompositionLevel)
|
||||
.zip(messages.chunks_exact_mut(polynomial_size.0))
|
||||
{
|
||||
update_with_wrapping_add_scalar_mul(
|
||||
update_slice_with_wrapping_add_scalar_mul(
|
||||
message.as_mut(),
|
||||
polynomial.as_ref(),
|
||||
DecompositionTerm::new(
|
||||
@@ -192,7 +192,7 @@ pub fn par_generate_lwe_private_functional_packing_keyswitch_key<
|
||||
.map(DecompositionLevel)
|
||||
.zip(messages.chunks_exact_mut(polynomial_size.0))
|
||||
{
|
||||
update_with_wrapping_add_scalar_mul(
|
||||
update_slice_with_wrapping_add_scalar_mul(
|
||||
message.as_mut(),
|
||||
polynomial.as_ref(),
|
||||
DecompositionTerm::new(
|
||||
|
||||
104
tfhe/src/core_crypto/algorithms/lwe_public_key_generation.rs
Normal file
104
tfhe/src/core_crypto/algorithms/lwe_public_key_generation.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
use crate::core_crypto::algorithms::*;
|
||||
use crate::core_crypto::commons::crypto::secret::generators::EncryptionRandomGenerator;
|
||||
use crate::core_crypto::commons::math::random::ByteRandomGenerator;
|
||||
#[cfg(feature = "__commons_parallel")]
|
||||
use crate::core_crypto::commons::math::random::ParallelByteRandomGenerator;
|
||||
use crate::core_crypto::commons::math::torus::UnsignedTorus;
|
||||
use crate::core_crypto::commons::traits::*;
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::specification::dispersion::DispersionParameter;
|
||||
use crate::core_crypto::specification::parameters::*;
|
||||
|
||||
pub fn generate_lwe_public_key<Scalar, InputKeyCont, OutputKeyCont, Gen>(
|
||||
lwe_secret_key: &LweSecretKeyBase<InputKeyCont>,
|
||||
output: &mut LwePublicKeyBase<OutputKeyCont>,
|
||||
noise_parameters: impl DispersionParameter,
|
||||
generator: &mut EncryptionRandomGenerator<Gen>,
|
||||
) where
|
||||
Scalar: UnsignedTorus,
|
||||
InputKeyCont: Container<Element = Scalar>,
|
||||
OutputKeyCont: ContainerMut<Element = Scalar>,
|
||||
Gen: ByteRandomGenerator,
|
||||
{
|
||||
assert!(
|
||||
lwe_secret_key.lwe_dimension() == output.lwe_size().to_lwe_dimension(),
|
||||
"TODO error message"
|
||||
);
|
||||
|
||||
let zeros = PlaintextList::new(
|
||||
Scalar::ZERO,
|
||||
PlaintextCount(output.zero_encryption_count().0),
|
||||
);
|
||||
|
||||
encrypt_lwe_ciphertext_list(lwe_secret_key, output, &zeros, noise_parameters, generator)
|
||||
}
|
||||
|
||||
pub fn allocate_and_generate_new_lwe_public_key<Scalar, InputKeyCont, OutputKeyCont, Gen>(
|
||||
lwe_secret_key: &LweSecretKeyBase<InputKeyCont>,
|
||||
zero_encryption_count: LwePublicKeyZeroEncryptionCount,
|
||||
noise_parameters: impl DispersionParameter,
|
||||
generator: &mut EncryptionRandomGenerator<Gen>,
|
||||
) -> LwePublicKey<Scalar>
|
||||
where
|
||||
Scalar: UnsignedTorus,
|
||||
InputKeyCont: Container<Element = Scalar>,
|
||||
Gen: ByteRandomGenerator,
|
||||
{
|
||||
let mut pk = LwePublicKey::new(
|
||||
Scalar::ZERO,
|
||||
lwe_secret_key.lwe_dimension().to_lwe_size(),
|
||||
zero_encryption_count,
|
||||
);
|
||||
|
||||
generate_lwe_public_key(lwe_secret_key, &mut pk, noise_parameters, generator);
|
||||
|
||||
pk
|
||||
}
|
||||
|
||||
#[cfg(feature = "__commons_parallel")]
|
||||
pub fn par_generate_lwe_public_key<Scalar, InputKeyCont, OutputKeyCont, Gen>(
|
||||
lwe_secret_key: &LweSecretKeyBase<InputKeyCont>,
|
||||
output: &mut LwePublicKeyBase<OutputKeyCont>,
|
||||
noise_parameters: impl DispersionParameter + Sync,
|
||||
generator: &mut EncryptionRandomGenerator<Gen>,
|
||||
) where
|
||||
Scalar: UnsignedTorus + Sync + Send,
|
||||
InputKeyCont: Container<Element = Scalar> + Sync,
|
||||
OutputKeyCont: ContainerMut<Element = Scalar>,
|
||||
Gen: ParallelByteRandomGenerator,
|
||||
{
|
||||
assert!(
|
||||
lwe_secret_key.lwe_dimension() == output.lwe_size().to_lwe_dimension(),
|
||||
"TODO error message"
|
||||
);
|
||||
|
||||
let zeros = PlaintextList::new(
|
||||
Scalar::ZERO,
|
||||
PlaintextCount(output.zero_encryption_count().0),
|
||||
);
|
||||
|
||||
par_encrypt_lwe_ciphertext_list(lwe_secret_key, output, &zeros, noise_parameters, generator)
|
||||
}
|
||||
|
||||
#[cfg(feature = "__commons_parallel")]
|
||||
pub fn par_allocate_and_generate_new_lwe_public_key<Scalar, InputKeyCont, Gen>(
|
||||
lwe_secret_key: &LweSecretKeyBase<InputKeyCont>,
|
||||
zero_encryption_count: LwePublicKeyZeroEncryptionCount,
|
||||
noise_parameters: impl DispersionParameter + Sync,
|
||||
generator: &mut EncryptionRandomGenerator<Gen>,
|
||||
) -> LwePublicKey<Scalar>
|
||||
where
|
||||
Scalar: UnsignedTorus + Sync + Send,
|
||||
InputKeyCont: Container<Element = Scalar> + Sync,
|
||||
Gen: ParallelByteRandomGenerator,
|
||||
{
|
||||
let mut pk = LwePublicKey::new(
|
||||
Scalar::ZERO,
|
||||
lwe_secret_key.lwe_dimension().to_lwe_size(),
|
||||
zero_encryption_count,
|
||||
);
|
||||
|
||||
generate_lwe_public_key(lwe_secret_key, &mut pk, noise_parameters, generator);
|
||||
|
||||
pk
|
||||
}
|
||||
@@ -11,6 +11,7 @@ pub mod lwe_linear_algebra;
|
||||
pub mod lwe_private_functional_packing_keyswitch;
|
||||
pub mod lwe_private_functional_packing_keyswitch_key_generation;
|
||||
pub mod lwe_programmable_bootstrapping;
|
||||
pub mod lwe_public_key_generation;
|
||||
pub mod lwe_secret_key_generation;
|
||||
pub mod lwe_wopbs;
|
||||
pub mod polynomial_algorithms;
|
||||
@@ -31,5 +32,6 @@ pub use lwe_linear_algebra::*;
|
||||
pub use lwe_private_functional_packing_keyswitch::*;
|
||||
pub use lwe_private_functional_packing_keyswitch_key_generation::*;
|
||||
pub use lwe_programmable_bootstrapping::*;
|
||||
pub use lwe_public_key_generation::*;
|
||||
pub use lwe_secret_key_generation::*;
|
||||
pub use lwe_wopbs::*;
|
||||
|
||||
@@ -14,7 +14,7 @@ pub fn update_polynomial_with_wrapping_add<Scalar, OutputCont, InputCont>(
|
||||
InputCont: Container<Element = Scalar>,
|
||||
{
|
||||
assert!(lhs.polynomial_size() == rhs.polynomial_size());
|
||||
update_with_wrapping_add(lhs.as_mut(), rhs.as_ref())
|
||||
update_slice_with_wrapping_add(lhs.as_mut(), rhs.as_ref())
|
||||
}
|
||||
|
||||
pub fn update_polynomial_with_wrapping_add_multisum<Scalar, OutputCont, InputCont1, InputCont2>(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::core_crypto::commons::numeric::UnsignedInteger;
|
||||
|
||||
pub fn wrapping_dot_product<Scalar>(lhs: &[Scalar], rhs: &[Scalar]) -> Scalar
|
||||
pub fn slice_wrapping_dot_product<Scalar>(lhs: &[Scalar], rhs: &[Scalar]) -> Scalar
|
||||
where
|
||||
Scalar: UnsignedInteger,
|
||||
{
|
||||
@@ -18,7 +18,7 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update_with_wrapping_add<Scalar>(lhs: &mut [Scalar], rhs: &[Scalar])
|
||||
pub fn update_slice_with_wrapping_add<Scalar>(lhs: &mut [Scalar], rhs: &[Scalar])
|
||||
where
|
||||
Scalar: UnsignedInteger,
|
||||
{
|
||||
@@ -34,7 +34,7 @@ where
|
||||
.for_each(|(lhs, &rhs)| *lhs = (*lhs).wrapping_add(rhs));
|
||||
}
|
||||
|
||||
pub fn update_with_wrapping_add_scalar_mul<Scalar>(
|
||||
pub fn update_slice_with_wrapping_add_scalar_mul<Scalar>(
|
||||
lhs: &mut [Scalar],
|
||||
rhs: &[Scalar],
|
||||
scalar: Scalar,
|
||||
@@ -52,7 +52,7 @@ pub fn update_with_wrapping_add_scalar_mul<Scalar>(
|
||||
.for_each(|(lhs, &rhs)| *lhs = (*lhs).wrapping_add(rhs.wrapping_mul(scalar)));
|
||||
}
|
||||
|
||||
pub fn update_with_wrapping_sub<Scalar>(lhs: &mut [Scalar], rhs: &[Scalar])
|
||||
pub fn update_slice_with_wrapping_sub<Scalar>(lhs: &mut [Scalar], rhs: &[Scalar])
|
||||
where
|
||||
Scalar: UnsignedInteger,
|
||||
{
|
||||
@@ -68,7 +68,7 @@ where
|
||||
.for_each(|(lhs, &rhs)| *lhs = (*lhs).wrapping_sub(rhs));
|
||||
}
|
||||
|
||||
pub fn update_with_wrapping_sub_scalar_mul<Scalar>(
|
||||
pub fn update_slice_with_wrapping_sub_scalar_mul<Scalar>(
|
||||
lhs: &mut [Scalar],
|
||||
rhs: &[Scalar],
|
||||
scalar: Scalar,
|
||||
@@ -86,7 +86,7 @@ pub fn update_with_wrapping_sub_scalar_mul<Scalar>(
|
||||
.for_each(|(lhs, &rhs)| *lhs = (*lhs).wrapping_sub(rhs.wrapping_mul(scalar)));
|
||||
}
|
||||
|
||||
pub fn update_with_wrapping_opposite<Scalar>(slice: &mut [Scalar])
|
||||
pub fn update_slice_with_wrapping_opposite<Scalar>(slice: &mut [Scalar])
|
||||
where
|
||||
Scalar: UnsignedInteger,
|
||||
{
|
||||
@@ -95,7 +95,7 @@ where
|
||||
.for_each(|elt| *elt = (*elt).wrapping_neg());
|
||||
}
|
||||
|
||||
pub fn update_with_wrapping_scalar_mul<Scalar>(lhs: &mut [Scalar], rhs: Scalar)
|
||||
pub fn update_slice_with_wrapping_scalar_mul<Scalar>(lhs: &mut [Scalar], rhs: Scalar)
|
||||
where
|
||||
Scalar: UnsignedInteger,
|
||||
{
|
||||
|
||||
@@ -12,13 +12,13 @@ impl<C: Container> std::ops::Deref for LweBootstrapKeyBase<C> {
|
||||
type Target = GgswCiphertextListBase<C>;
|
||||
|
||||
fn deref(&self) -> &GgswCiphertextListBase<C> {
|
||||
self.as_ggsw_ciphertext_list()
|
||||
&self.ggsw_list
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ContainerMut> std::ops::DerefMut for LweBootstrapKeyBase<C> {
|
||||
fn deref_mut(&mut self) -> &mut GgswCiphertextListBase<C> {
|
||||
self.as_mut_ggsw_ciphertext_list()
|
||||
&mut self.ggsw_list
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,10 +49,6 @@ impl<Scalar, C: Container<Element = Scalar>> LweBootstrapKeyBase<C> {
|
||||
LweDimension(self.glwe_size().to_glwe_dimension().0 * self.polynomial_size().0)
|
||||
}
|
||||
|
||||
pub fn as_ggsw_ciphertext_list(&self) -> &GgswCiphertextListBase<C> {
|
||||
&self.ggsw_list
|
||||
}
|
||||
|
||||
pub fn into_container(self) -> C {
|
||||
self.ggsw_list.into_container()
|
||||
}
|
||||
@@ -69,10 +65,6 @@ impl<Scalar, C: Container<Element = Scalar>> LweBootstrapKeyBase<C> {
|
||||
}
|
||||
|
||||
impl<Scalar, C: ContainerMut<Element = Scalar>> LweBootstrapKeyBase<C> {
|
||||
pub fn as_mut_ggsw_ciphertext_list(&mut self) -> &mut GgswCiphertextListBase<C> {
|
||||
&mut self.ggsw_list
|
||||
}
|
||||
|
||||
pub fn as_mut_view(&mut self) -> LweBootstrapKeyBase<&'_ mut [Scalar]> {
|
||||
let glwe_size = self.glwe_size();
|
||||
let polynomial_size = self.polynomial_size();
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::core_crypto::commons::traits::*;
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::specification::parameters::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct LweCiphertextListBase<C: Container> {
|
||||
data: C,
|
||||
lwe_size: LweSize,
|
||||
|
||||
90
tfhe/src/core_crypto/entities/lwe_public_key.rs
Normal file
90
tfhe/src/core_crypto/entities/lwe_public_key.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use crate::core_crypto::commons::traits::*;
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::specification::parameters::*;
|
||||
|
||||
// An LwePublicKey is literally an LweCiphertextList, so we wrap an LweCiphertextList and use
|
||||
// Deref to have access to all the primitives of the LweCiphertextList easily
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct LwePublicKeyBase<C: Container> {
|
||||
lwe_list: LweCiphertextListBase<C>,
|
||||
}
|
||||
|
||||
impl<C: Container> std::ops::Deref for LwePublicKeyBase<C> {
|
||||
type Target = LweCiphertextListBase<C>;
|
||||
|
||||
fn deref(&self) -> &LweCiphertextListBase<C> {
|
||||
&self.lwe_list
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: ContainerMut> std::ops::DerefMut for LwePublicKeyBase<C> {
|
||||
fn deref_mut(&mut self) -> &mut LweCiphertextListBase<C> {
|
||||
&mut self.lwe_list
|
||||
}
|
||||
}
|
||||
|
||||
impl<Scalar, C: Container<Element = Scalar>> LwePublicKeyBase<C> {
|
||||
pub fn from_container(container: C, lwe_size: LweSize) -> LwePublicKeyBase<C> {
|
||||
assert!(
|
||||
container.container_len() > 0,
|
||||
"Got an empty container to create an LwePublicKey"
|
||||
);
|
||||
LwePublicKeyBase {
|
||||
lwe_list: LweCiphertextListBase::from_container(container, lwe_size),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zero_encryption_count(&self) -> LwePublicKeyZeroEncryptionCount {
|
||||
LwePublicKeyZeroEncryptionCount(self.lwe_ciphertext_count().0)
|
||||
}
|
||||
|
||||
pub fn into_container(self) -> C {
|
||||
self.lwe_list.into_container()
|
||||
}
|
||||
|
||||
pub fn as_view(&self) -> LwePublicKeyBase<&'_ [Scalar]> {
|
||||
LwePublicKeyBase::from_container(self.as_ref(), self.lwe_size())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Scalar, C: ContainerMut<Element = Scalar>> LwePublicKeyBase<C> {
|
||||
pub fn as_mut_view(&mut self) -> LwePublicKeyBase<&'_ mut [Scalar]> {
|
||||
let lwe_size = self.lwe_size();
|
||||
LwePublicKeyBase::from_container(self.as_mut(), lwe_size)
|
||||
}
|
||||
}
|
||||
|
||||
pub type LwePublicKey<Scalar> = LwePublicKeyBase<Vec<Scalar>>;
|
||||
|
||||
impl<Scalar: Copy> LwePublicKey<Scalar> {
|
||||
pub fn new(
|
||||
fill_with: Scalar,
|
||||
lwe_size: LweSize,
|
||||
zero_encryption_count: LwePublicKeyZeroEncryptionCount,
|
||||
) -> LwePublicKey<Scalar> {
|
||||
LwePublicKey::from_container(
|
||||
vec![fill_with; lwe_size.0 * zero_encryption_count.0],
|
||||
lwe_size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LwePublicKey<u64>> for crate::core_crypto::prelude::LwePublicKey64 {
|
||||
fn from(new_key: LwePublicKey<u64>) -> Self {
|
||||
use crate::core_crypto::commons::crypto::lwe::LweList as ImpLwePublicKey;
|
||||
use crate::core_crypto::prelude::LwePublicKey64;
|
||||
|
||||
let lwe_size = new_key.lwe_size();
|
||||
LwePublicKey64(ImpLwePublicKey::from_container(
|
||||
new_key.into_container(),
|
||||
lwe_size,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::core_crypto::prelude::LwePublicKey64> for LwePublicKey<u64> {
|
||||
fn from(old_key: crate::core_crypto::prelude::LwePublicKey64) -> Self {
|
||||
let lwe_size = old_key.0.lwe_size();
|
||||
LwePublicKey::from_container(old_key.0.into_container(), lwe_size)
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ pub mod lwe_ciphertext_list;
|
||||
pub mod lwe_keyswitch_key;
|
||||
pub mod lwe_private_functional_packing_keyswitch_key;
|
||||
pub mod lwe_private_functional_packing_keyswitch_key_list;
|
||||
pub mod lwe_public_key;
|
||||
pub mod lwe_secret_key;
|
||||
pub mod plaintext;
|
||||
pub mod plaintext_list;
|
||||
@@ -28,6 +29,7 @@ pub use lwe_ciphertext_list::*;
|
||||
pub use lwe_keyswitch_key::*;
|
||||
pub use lwe_private_functional_packing_keyswitch_key::*;
|
||||
pub use lwe_private_functional_packing_keyswitch_key_list::*;
|
||||
pub use lwe_public_key::*;
|
||||
pub use lwe_secret_key::*;
|
||||
pub use plaintext::*;
|
||||
pub use plaintext_list::*;
|
||||
|
||||
@@ -34,12 +34,20 @@ impl<Scalar, C: Container<Element = Scalar>> PlaintextListBase<C> {
|
||||
pub fn into_container(self) -> C {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn as_view(&self) -> PlaintextListView<'_, Scalar> {
|
||||
PlaintextListView::from_container(self.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Scalar, C: ContainerMut<Element = Scalar>> PlaintextListBase<C> {
|
||||
pub fn as_mut_polynomial(&mut self) -> PolynomialMutView<'_, Scalar> {
|
||||
PolynomialMutView::from_container(self.as_mut())
|
||||
}
|
||||
|
||||
pub fn as_mut_view(&mut self) -> PlaintextListMutView<'_, Scalar> {
|
||||
PlaintextListMutView::from_container(self.as_mut())
|
||||
}
|
||||
}
|
||||
|
||||
pub type PlaintextList<Scalar> = PlaintextListBase<Vec<Scalar>>;
|
||||
|
||||
@@ -324,7 +324,10 @@ fn test_circuit_bootstrapping_binary() {
|
||||
|
||||
let multiplying_factor = 0u64.wrapping_sub(value);
|
||||
|
||||
update_with_wrapping_scalar_mul(expected_decryption.as_mut(), multiplying_factor);
|
||||
update_slice_with_wrapping_scalar_mul(
|
||||
expected_decryption.as_mut(),
|
||||
multiplying_factor,
|
||||
);
|
||||
|
||||
let decomposer =
|
||||
SignedDecomposer::new(base_log_cbs, DecompositionLevelCount(current_level));
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
//! Module with the definition of a short-integer ciphertext.
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::prelude::*;
|
||||
use crate::core_crypto::prelude::{
|
||||
AbstractEngine, DefaultSerializationEngine, EntityDeserializationEngine,
|
||||
EntitySerializationEngine, LweCiphertext64,
|
||||
};
|
||||
use crate::shortint::parameters::{CarryModulus, MessageModulus};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::cmp;
|
||||
|
||||
@@ -11,14 +11,14 @@ impl ShortintEngine {
|
||||
// generate the lwe secret key
|
||||
let small_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key(
|
||||
parameters.lwe_dimension,
|
||||
self.engine.get_secret_generator(),
|
||||
&mut self.secret_generator,
|
||||
);
|
||||
|
||||
// generate the rlwe secret key
|
||||
let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key(
|
||||
parameters.glwe_dimension,
|
||||
parameters.polynomial_size,
|
||||
self.engine.get_secret_generator(),
|
||||
&mut self.secret_generator,
|
||||
);
|
||||
|
||||
let large_lwe_secret_key = glwe_secret_key.clone().into_lwe_secret_key();
|
||||
@@ -68,7 +68,7 @@ impl ShortintEngine {
|
||||
&client_key.lwe_secret_key,
|
||||
encoded,
|
||||
client_key.parameters.lwe_modular_std_dev,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
Ok(Ciphertext {
|
||||
@@ -95,7 +95,7 @@ impl ShortintEngine {
|
||||
&client_key.lwe_secret_key,
|
||||
encoded,
|
||||
client_key.parameters.lwe_modular_std_dev,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
Ok(Ciphertext {
|
||||
@@ -155,7 +155,7 @@ impl ShortintEngine {
|
||||
&client_key.lwe_secret_key,
|
||||
encoded,
|
||||
client_key.parameters.lwe_modular_std_dev,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
Ok(Ciphertext {
|
||||
@@ -215,7 +215,7 @@ impl ShortintEngine {
|
||||
&client_key.lwe_secret_key,
|
||||
encoded,
|
||||
client_key.parameters.lwe_modular_std_dev,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
Ok(Ciphertext {
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
use crate::core_crypto::algorithms::*;
|
||||
use crate::core_crypto::commons::crypto::secret::generators::{
|
||||
EncryptionRandomGenerator, SecretRandomGenerator,
|
||||
};
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::prelude::*;
|
||||
use crate::core_crypto::prelude::{Seeder, *};
|
||||
use crate::seeders::new_seeder;
|
||||
use crate::shortint::ServerKey;
|
||||
use core::mem::MaybeUninit;
|
||||
use dyn_stack::DynStack;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Debug;
|
||||
@@ -25,6 +31,30 @@ pub struct Buffers {
|
||||
pub(crate) buffer_lwe_after_ks: LweCiphertext<u64>,
|
||||
}
|
||||
|
||||
pub struct FftBuffers {
|
||||
memory: Vec<MaybeUninit<u8>>,
|
||||
}
|
||||
|
||||
impl FftBuffers {
|
||||
pub fn new() -> Self {
|
||||
FftBuffers { memory: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, capacity: usize) {
|
||||
self.memory.resize_with(capacity, MaybeUninit::uninit);
|
||||
}
|
||||
|
||||
pub fn stack(&mut self) -> DynStack<'_> {
|
||||
DynStack::new(&mut self.memory)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FftBuffers {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// This allows to store and retrieve the `Buffers`
|
||||
/// corresponding to a `ServerKey` in a `BTreeMap`
|
||||
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
|
||||
@@ -74,9 +104,16 @@ pub(crate) type EngineResult<T> = Result<T, EngineError>;
|
||||
///
|
||||
/// This structs actually implements the logics into its methods.
|
||||
pub struct ShortintEngine {
|
||||
pub(crate) engine: DefaultEngine,
|
||||
pub(crate) fft_engine: FftEngine,
|
||||
pub(crate) par_engine: DefaultParallelEngine,
|
||||
/// A structure containing a single CSPRNG to generate secret key coefficients.
|
||||
pub(crate) secret_generator: SecretRandomGenerator<ActivatedRandomGenerator>,
|
||||
/// A structure containing two CSPRNGs to generate material for encryption like public masks
|
||||
/// and secret errors.
|
||||
///
|
||||
/// The [`ImplEncryptionRandomGenerator`] contains two CSPRNGs, one publicly seeded used to
|
||||
/// generate mask coefficients and one privately seeded used to generate errors during
|
||||
/// encryption.
|
||||
pub(crate) encryption_generator: EncryptionRandomGenerator<ActivatedRandomGenerator>,
|
||||
pub(crate) fft_buffers: FftBuffers,
|
||||
buffers: BTreeMap<KeyId, Buffers>,
|
||||
}
|
||||
|
||||
@@ -111,31 +148,25 @@ impl ShortintEngine {
|
||||
let mut deterministic_seeder =
|
||||
DeterministicSeeder::<ActivatedRandomGenerator>::new(root_seeder.seed());
|
||||
|
||||
let default_engine_seeder = Box::new(DeterministicSeeder::<ActivatedRandomGenerator>::new(
|
||||
deterministic_seeder.seed(),
|
||||
));
|
||||
let default_parallel_engine_seeder = Box::new(DeterministicSeeder::<
|
||||
ActivatedRandomGenerator,
|
||||
>::new(deterministic_seeder.seed()));
|
||||
|
||||
let engine =
|
||||
DefaultEngine::new(default_engine_seeder).expect("Failed to create a DefaultEngine");
|
||||
let par_engine = DefaultParallelEngine::new(default_parallel_engine_seeder)
|
||||
.expect("Failed to create a DefaultParallelEngine");
|
||||
let fft_engine = FftEngine::new(()).unwrap();
|
||||
// Note that the operands are evaluated from left to right for Rust Struct expressions
|
||||
// See: https://doc.rust-lang.org/stable/reference/expressions.html?highlight=left#evaluation-order-of-operands
|
||||
// So parameters is moved in seeder after the calls to seed and the potential calls when it
|
||||
// is passed as_mut in EncryptionRandomGenerator::new
|
||||
Self {
|
||||
engine,
|
||||
fft_engine,
|
||||
par_engine,
|
||||
secret_generator: SecretRandomGenerator::new(deterministic_seeder.seed()),
|
||||
encryption_generator: EncryptionRandomGenerator::new(
|
||||
deterministic_seeder.seed(),
|
||||
&mut deterministic_seeder,
|
||||
),
|
||||
fft_buffers: Default::default(),
|
||||
buffers: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_accumulator_with_engine<F>(
|
||||
engine: &mut DefaultEngine,
|
||||
server_key: &ServerKey,
|
||||
f: F,
|
||||
) -> EngineResult<GlweCiphertext64>
|
||||
) -> EngineResult<GlweCiphertext<u64>>
|
||||
where
|
||||
F: Fn(u64) -> u64,
|
||||
{
|
||||
@@ -171,21 +202,20 @@ impl ShortintEngine {
|
||||
accumulator_u64.rotate_left(half_box_size);
|
||||
|
||||
// Everywhere
|
||||
let accumulator_plaintext = engine.create_plaintext_vector_from(&accumulator_u64)?;
|
||||
let accumulator_plaintext = PlaintextList::from_container(accumulator_u64);
|
||||
|
||||
let accumulator = engine.trivially_encrypt_glwe_ciphertext(
|
||||
let accumulator = allocate_and_trivially_encrypt_new_glwe_ciphertext(
|
||||
server_key.bootstrapping_key.glwe_size(),
|
||||
&accumulator_plaintext,
|
||||
)?;
|
||||
);
|
||||
|
||||
Ok(accumulator)
|
||||
}
|
||||
|
||||
fn generate_accumulator_bivariate_with_engine<F>(
|
||||
engine: &mut DefaultEngine,
|
||||
server_key: &ServerKey,
|
||||
f: F,
|
||||
) -> EngineResult<GlweCiphertext64>
|
||||
) -> EngineResult<GlweCiphertext<u64>>
|
||||
where
|
||||
F: Fn(u64, u64) -> u64,
|
||||
{
|
||||
@@ -196,7 +226,7 @@ impl ShortintEngine {
|
||||
|
||||
f(lhs, rhs)
|
||||
};
|
||||
ShortintEngine::generate_accumulator_with_engine(engine, server_key, wrapped_f)
|
||||
ShortintEngine::generate_accumulator_with_engine(server_key, wrapped_f)
|
||||
}
|
||||
|
||||
/// Returns the `Buffers` for the given `ServerKey`
|
||||
@@ -206,43 +236,32 @@ impl ShortintEngine {
|
||||
/// This also `&mut CoreEngine` to simply borrow checking for the caller
|
||||
/// (since returned buffers are borrowed from `self`, using the `self.engine`
|
||||
/// wouldn't be possible after calling `buffers_for_key`)
|
||||
pub fn buffers_for_key(
|
||||
&mut self,
|
||||
server_key: &ServerKey,
|
||||
) -> (&mut Buffers, &mut DefaultEngine, &mut FftEngine) {
|
||||
pub fn buffers_for_key(&mut self, server_key: &ServerKey) -> (&mut Buffers, &mut FftBuffers) {
|
||||
let key = server_key.key_id();
|
||||
// To make borrow checker happy
|
||||
let engine = &mut self.engine;
|
||||
let buffers_map = &mut self.buffers;
|
||||
let buffers = buffers_map.entry(key).or_insert_with(|| {
|
||||
let accumulator = Self::generate_accumulator_with_engine(engine, server_key, |n| {
|
||||
let accumulator = Self::generate_accumulator_with_engine(server_key, |n| {
|
||||
n % server_key.message_modulus.0 as u64
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Allocate the buffer for the output of the PBS
|
||||
let zero_plaintext = engine.create_plaintext_from(&0_u64).unwrap();
|
||||
let buffer_lwe_after_pbs = engine
|
||||
.trivially_encrypt_lwe_ciphertext(
|
||||
server_key
|
||||
.key_switching_key
|
||||
.output_key_lwe_dimension()
|
||||
.to_lwe_size(),
|
||||
&zero_plaintext,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let polynomial_size = accumulator.polynomial_size();
|
||||
let zero_plaintext = Plaintext(0_u64);
|
||||
let buffer_lwe_after_ks = allocate_and_trivially_encrypt_new_lwe_ciphertext(
|
||||
server_key
|
||||
.key_switching_key
|
||||
.output_key_lwe_dimension()
|
||||
.to_lwe_size(),
|
||||
zero_plaintext,
|
||||
);
|
||||
|
||||
Buffers {
|
||||
accumulator: GlweCiphertext::from_container(
|
||||
accumulator.0.into_container(),
|
||||
polynomial_size,
|
||||
),
|
||||
buffer_lwe_after_ks: buffer_lwe_after_pbs.into(),
|
||||
accumulator,
|
||||
buffer_lwe_after_ks,
|
||||
}
|
||||
});
|
||||
|
||||
(buffers, engine, &mut self.fft_engine)
|
||||
(buffers, &mut self.fft_buffers)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
//! All the `ShortintEngine` method related to client side (encrypt / decrypt)
|
||||
use super::{EngineResult, ShortintEngine};
|
||||
use crate::core_crypto::algorithms::*;
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::prelude::*;
|
||||
use crate::shortint::ciphertext::Degree;
|
||||
use crate::shortint::parameters::{CarryModulus, MessageModulus};
|
||||
@@ -19,14 +21,17 @@ impl ShortintEngine {
|
||||
+ 128,
|
||||
);
|
||||
|
||||
let lwe_public_key = par_allocate_and_generate_new_lwe_public_key(
|
||||
&client_key.lwe_secret_key,
|
||||
zero_encryption_count,
|
||||
client_key.parameters.glwe_modular_std_dev,
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
// TODO REFACTOR
|
||||
// Remove the clone + into
|
||||
Ok(PublicKey {
|
||||
lwe_public_key: self.par_engine.generate_new_lwe_public_key(
|
||||
&client_key.lwe_secret_key.clone().into(),
|
||||
Variance(client_key.parameters.lwe_modular_std_dev.get_variance()),
|
||||
zero_encryption_count,
|
||||
)?,
|
||||
lwe_public_key,
|
||||
parameters: client_key.parameters.to_owned(),
|
||||
})
|
||||
}
|
||||
@@ -72,23 +77,20 @@ impl ShortintEngine {
|
||||
|
||||
let shifted_message = m * delta;
|
||||
// encode the message
|
||||
let plain: Plaintext64 = self.engine.create_plaintext_from(&shifted_message)?;
|
||||
let plain = Plaintext(shifted_message);
|
||||
|
||||
// This allocates the required ct
|
||||
let mut encrypted_ct = self.engine.trivially_encrypt_lwe_ciphertext(
|
||||
public_key.lwe_public_key.lwe_dimension().to_lwe_size(),
|
||||
&plain,
|
||||
)?;
|
||||
let mut encrypted_ct = LweCiphertext::new(0u64, public_key.lwe_public_key.lwe_size());
|
||||
|
||||
// encryption
|
||||
self.engine.discard_encrypt_lwe_ciphertext_with_public_key(
|
||||
encrypt_lwe_ciphertext_with_public_key(
|
||||
&public_key.lwe_public_key,
|
||||
&mut encrypted_ct,
|
||||
&plain,
|
||||
)?;
|
||||
plain,
|
||||
&mut self.secret_generator,
|
||||
);
|
||||
|
||||
Ok(Ciphertext {
|
||||
ct: encrypted_ct.into(),
|
||||
ct: encrypted_ct,
|
||||
degree: Degree(message_modulus.0 - 1),
|
||||
message_modulus,
|
||||
carry_modulus: CarryModulus(carry_modulus),
|
||||
@@ -108,23 +110,21 @@ impl ShortintEngine {
|
||||
|
||||
let shifted_message = message * delta;
|
||||
// encode the message
|
||||
let plain: Plaintext64 = self.engine.create_plaintext_from(&shifted_message)?;
|
||||
let plain = Plaintext(shifted_message);
|
||||
|
||||
// This allocates the required ct
|
||||
let mut encrypted_ct = self.engine.trivially_encrypt_lwe_ciphertext(
|
||||
public_key.lwe_public_key.lwe_dimension().to_lwe_size(),
|
||||
&plain,
|
||||
)?;
|
||||
let mut encrypted_ct = LweCiphertext::new(0u64, public_key.lwe_public_key.lwe_size());
|
||||
|
||||
// encryption
|
||||
self.engine.discard_encrypt_lwe_ciphertext_with_public_key(
|
||||
encrypt_lwe_ciphertext_with_public_key(
|
||||
&public_key.lwe_public_key,
|
||||
&mut encrypted_ct,
|
||||
&plain,
|
||||
)?;
|
||||
plain,
|
||||
&mut self.secret_generator,
|
||||
);
|
||||
|
||||
Ok(Ciphertext {
|
||||
ct: encrypted_ct.into(),
|
||||
ct: encrypted_ct,
|
||||
degree: Degree(public_key.parameters.message_modulus.0 - 1),
|
||||
message_modulus: public_key.parameters.message_modulus,
|
||||
carry_modulus: public_key.parameters.carry_modulus,
|
||||
@@ -141,25 +141,21 @@ impl ShortintEngine {
|
||||
let m = (message % message_modulus as u64) as u128;
|
||||
let shifted_message = m * (1 << 64) / message_modulus as u128;
|
||||
// encode the message
|
||||
let plain: Plaintext64 = self
|
||||
.engine
|
||||
.create_plaintext_from(&(shifted_message as u64))?;
|
||||
|
||||
let plain = Plaintext(shifted_message as u64);
|
||||
|
||||
// This allocates the required ct
|
||||
let mut encrypted_ct = self.engine.trivially_encrypt_lwe_ciphertext(
|
||||
public_key.lwe_public_key.lwe_dimension().to_lwe_size(),
|
||||
&plain,
|
||||
)?;
|
||||
let mut encrypted_ct = LweCiphertext::new(0u64, public_key.lwe_public_key.lwe_size());
|
||||
|
||||
// encryption
|
||||
self.engine.discard_encrypt_lwe_ciphertext_with_public_key(
|
||||
encrypt_lwe_ciphertext_with_public_key(
|
||||
&public_key.lwe_public_key,
|
||||
&mut encrypted_ct,
|
||||
&plain,
|
||||
)?;
|
||||
plain,
|
||||
&mut self.secret_generator,
|
||||
);
|
||||
|
||||
Ok(Ciphertext {
|
||||
ct: encrypted_ct.into(),
|
||||
ct: encrypted_ct,
|
||||
degree: Degree(message_modulus as usize - 1),
|
||||
message_modulus: MessageModulus(message_modulus as usize),
|
||||
carry_modulus: CarryModulus(carry_modulus),
|
||||
@@ -176,23 +172,20 @@ impl ShortintEngine {
|
||||
as u64;
|
||||
let shifted_message = message * delta;
|
||||
// encode the message
|
||||
let plain: Plaintext64 = self.engine.create_plaintext_from(&shifted_message)?;
|
||||
let plain = Plaintext(shifted_message);
|
||||
|
||||
// This allocates the required ct
|
||||
let mut encrypted_ct = self.engine.trivially_encrypt_lwe_ciphertext(
|
||||
public_key.lwe_public_key.lwe_dimension().to_lwe_size(),
|
||||
&plain,
|
||||
)?;
|
||||
let mut encrypted_ct = LweCiphertext::new(0u64, public_key.lwe_public_key.lwe_size());
|
||||
|
||||
// encryption
|
||||
self.engine.discard_encrypt_lwe_ciphertext_with_public_key(
|
||||
encrypt_lwe_ciphertext_with_public_key(
|
||||
&public_key.lwe_public_key,
|
||||
&mut encrypted_ct,
|
||||
&plain,
|
||||
)?;
|
||||
plain,
|
||||
&mut self.secret_generator,
|
||||
);
|
||||
|
||||
Ok(Ciphertext {
|
||||
ct: encrypted_ct.into(),
|
||||
ct: encrypted_ct,
|
||||
degree: Degree(
|
||||
public_key.parameters.message_modulus.0 * public_key.parameters.carry_modulus.0 - 1,
|
||||
),
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use super::ShortintEngine;
|
||||
use crate::core_crypto::algorithms::*;
|
||||
use crate::core_crypto::commons::math::tensor::{AsRefSlice, AsRefTensor};
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::fft_impl::crypto::bootstrap::FourierLweBootstrapKey;
|
||||
use crate::core_crypto::fft_impl::math::fft::Fft;
|
||||
use crate::core_crypto::prelude::*;
|
||||
use crate::shortint::ciphertext::Degree;
|
||||
use crate::shortint::engine::EngineResult;
|
||||
use crate::shortint::server_key::MaxDegree;
|
||||
@@ -44,7 +42,7 @@ impl ShortintEngine {
|
||||
cks.parameters.pbs_base_log,
|
||||
cks.parameters.pbs_level,
|
||||
cks.parameters.glwe_modular_std_dev,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
// Creation of the bootstrapping key in the Fourier domain
|
||||
@@ -58,12 +56,12 @@ impl ShortintEngine {
|
||||
|
||||
let fft = Fft::new(bootstrap_key.polynomial_size());
|
||||
let fft = fft.as_view();
|
||||
self.fft_engine.resize(
|
||||
self.fft_buffers.resize(
|
||||
convert_standard_lwe_bootstrap_key_to_fourier_scratch(fft)
|
||||
.unwrap()
|
||||
.unaligned_bytes_required(),
|
||||
);
|
||||
let stack = self.fft_engine.stack();
|
||||
let stack = self.fft_buffers.stack();
|
||||
|
||||
// Conversion to fourier domain
|
||||
convert_standard_lwe_bootstrap_key_to_fourier(&bootstrap_key, &mut fourier_bsk, fft, stack);
|
||||
@@ -75,7 +73,7 @@ impl ShortintEngine {
|
||||
cks.parameters.ks_base_log,
|
||||
cks.parameters.ks_level,
|
||||
cks.parameters.lwe_modular_std_dev,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
// Pack the keys in the server key set:
|
||||
@@ -92,11 +90,11 @@ impl ShortintEngine {
|
||||
&mut self,
|
||||
server_key: &ServerKey,
|
||||
f: F,
|
||||
) -> EngineResult<GlweCiphertext64>
|
||||
) -> EngineResult<GlweCiphertext<u64>>
|
||||
where
|
||||
F: Fn(u64) -> u64,
|
||||
{
|
||||
Self::generate_accumulator_with_engine(&mut self.engine, server_key, f)
|
||||
Self::generate_accumulator_with_engine(server_key, f)
|
||||
}
|
||||
|
||||
pub(crate) fn keyswitch_bootstrap(
|
||||
@@ -115,7 +113,7 @@ impl ShortintEngine {
|
||||
ct: &mut Ciphertext,
|
||||
) -> EngineResult<()> {
|
||||
// Compute the programmable bootstrapping with fixed test polynomial
|
||||
let (buffers, _, fft_engine) = self.buffers_for_key(server_key);
|
||||
let (buffers, fft_buffers) = self.buffers_for_key(server_key);
|
||||
|
||||
// Compute a keyswitch
|
||||
keyswitch_lwe_ciphertext(
|
||||
@@ -128,7 +126,7 @@ impl ShortintEngine {
|
||||
|
||||
let fft = Fft::new(fourier_bsk.polynomial_size());
|
||||
let fft = fft.as_view();
|
||||
fft_engine.resize(
|
||||
fft_buffers.resize(
|
||||
programmable_bootstrap_lwe_ciphertext_scratch::<u64>(
|
||||
fourier_bsk.glwe_size(),
|
||||
fourier_bsk.polynomial_size(),
|
||||
@@ -137,7 +135,7 @@ impl ShortintEngine {
|
||||
.unwrap()
|
||||
.unaligned_bytes_required(),
|
||||
);
|
||||
let stack = fft_engine.stack();
|
||||
let stack = fft_buffers.stack();
|
||||
|
||||
// Compute a bootstrap
|
||||
programmable_bootstrap_lwe_ciphertext(
|
||||
@@ -156,7 +154,7 @@ impl ShortintEngine {
|
||||
&mut self,
|
||||
server_key: &ServerKey,
|
||||
ct: &Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) -> EngineResult<Ciphertext> {
|
||||
let mut ct_res = ct.clone();
|
||||
self.programmable_bootstrap_keyswitch_assign(server_key, &mut ct_res, acc)?;
|
||||
@@ -167,10 +165,10 @@ impl ShortintEngine {
|
||||
&mut self,
|
||||
server_key: &ServerKey,
|
||||
ct: &mut Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) -> EngineResult<()> {
|
||||
// Compute the programmable bootstrapping with fixed test polynomial
|
||||
let (buffers, _, fft_engine) = self.buffers_for_key(server_key);
|
||||
let (buffers, fft_buffers) = self.buffers_for_key(server_key);
|
||||
|
||||
// Compute a key switch
|
||||
keyswitch_lwe_ciphertext(
|
||||
@@ -183,7 +181,7 @@ impl ShortintEngine {
|
||||
|
||||
let fft = Fft::new(fourier_bsk.polynomial_size());
|
||||
let fft = fft.as_view();
|
||||
fft_engine.resize(
|
||||
fft_buffers.resize(
|
||||
programmable_bootstrap_lwe_ciphertext_scratch::<u64>(
|
||||
fourier_bsk.glwe_size(),
|
||||
fourier_bsk.polynomial_size(),
|
||||
@@ -192,16 +190,13 @@ impl ShortintEngine {
|
||||
.unwrap()
|
||||
.unaligned_bytes_required(),
|
||||
);
|
||||
let stack = fft_engine.stack();
|
||||
let stack = fft_buffers.stack();
|
||||
|
||||
// Compute a bootstrap
|
||||
programmable_bootstrap_lwe_ciphertext(
|
||||
&buffers.buffer_lwe_after_ks,
|
||||
&mut ct.ct,
|
||||
&GlweCiphertextBase::from_container(
|
||||
acc.0.as_tensor().as_slice(),
|
||||
acc.polynomial_size(),
|
||||
),
|
||||
acc,
|
||||
fourier_bsk,
|
||||
fft,
|
||||
stack,
|
||||
@@ -214,7 +209,7 @@ impl ShortintEngine {
|
||||
server_key: &ServerKey,
|
||||
ct_left: &Ciphertext,
|
||||
ct_right: &Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) -> EngineResult<Ciphertext> {
|
||||
let mut ct_res = ct_left.clone();
|
||||
self.programmable_bootstrap_keyswitch_bivariate_assign(
|
||||
@@ -231,7 +226,7 @@ impl ShortintEngine {
|
||||
server_key: &ServerKey,
|
||||
ct_left: &mut Ciphertext,
|
||||
ct_right: &Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) -> EngineResult<()> {
|
||||
let modulus = (ct_right.degree.0 + 1) as u64;
|
||||
|
||||
@@ -251,11 +246,11 @@ impl ShortintEngine {
|
||||
&mut self,
|
||||
server_key: &ServerKey,
|
||||
f: F,
|
||||
) -> EngineResult<GlweCiphertext64>
|
||||
) -> EngineResult<GlweCiphertext<u64>>
|
||||
where
|
||||
F: Fn(u64, u64) -> u64,
|
||||
{
|
||||
Self::generate_accumulator_bivariate_with_engine(&mut self.engine, server_key, f)
|
||||
Self::generate_accumulator_bivariate_with_engine(server_key, f)
|
||||
}
|
||||
|
||||
pub(crate) fn unchecked_functional_bivariate_pbs<F>(
|
||||
@@ -307,7 +302,7 @@ impl ShortintEngine {
|
||||
server_key: &ServerKey,
|
||||
ct_left: &Ciphertext,
|
||||
ct_right: &mut Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) -> EngineResult<Ciphertext> {
|
||||
let mut ct_res = ct_left.clone();
|
||||
self.smart_bivariate_pbs_assign(server_key, &mut ct_res, ct_right, acc)?;
|
||||
@@ -320,7 +315,7 @@ impl ShortintEngine {
|
||||
server_key: &ServerKey,
|
||||
ct_left: &mut Ciphertext,
|
||||
ct_right: &mut Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) -> EngineResult<()> {
|
||||
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
|
||||
self.message_extract_assign(server_key, ct_left)?;
|
||||
@@ -336,7 +331,7 @@ impl ShortintEngine {
|
||||
server_key: &ServerKey,
|
||||
ct_left: &mut Ciphertext,
|
||||
ct_right: &Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) -> EngineResult<()> {
|
||||
let modulus = (ct_right.degree.0 + 1) as u64;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ impl ShortintEngine {
|
||||
cks.parameters.pfks_base_log,
|
||||
cks.parameters.pfks_level,
|
||||
cks.parameters.pfks_modular_std_dev,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
let sks_cpy = sks.clone();
|
||||
@@ -48,13 +48,13 @@ impl ShortintEngine {
|
||||
//Independent client key generation dedicated to the WoPBS
|
||||
let small_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key(
|
||||
parameters.lwe_dimension,
|
||||
self.engine.get_secret_generator(),
|
||||
&mut self.secret_generator,
|
||||
);
|
||||
|
||||
let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key(
|
||||
parameters.glwe_dimension,
|
||||
parameters.polynomial_size,
|
||||
self.engine.get_secret_generator(),
|
||||
&mut self.secret_generator,
|
||||
);
|
||||
|
||||
let large_lwe_secret_key = glwe_secret_key.clone().into_lwe_secret_key();
|
||||
@@ -66,7 +66,7 @@ impl ShortintEngine {
|
||||
parameters.pbs_base_log,
|
||||
parameters.pbs_level,
|
||||
parameters.glwe_modular_std_dev,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
// Creation of the bootstrapping key in the Fourier domain
|
||||
@@ -80,12 +80,12 @@ impl ShortintEngine {
|
||||
|
||||
let fft = Fft::new(bootstrap_key.polynomial_size());
|
||||
let fft = fft.as_view();
|
||||
self.fft_engine.resize(
|
||||
self.fft_buffers.resize(
|
||||
convert_standard_lwe_bootstrap_key_to_fourier_scratch(fft)
|
||||
.unwrap()
|
||||
.unaligned_bytes_required(),
|
||||
);
|
||||
let stack = self.fft_engine.stack();
|
||||
let stack = self.fft_buffers.stack();
|
||||
|
||||
// Conversion to fourier domain
|
||||
convert_standard_lwe_bootstrap_key_to_fourier(&bootstrap_key, &mut small_bsk, fft, stack);
|
||||
@@ -99,7 +99,7 @@ impl ShortintEngine {
|
||||
parameters.ks_base_log,
|
||||
parameters.ks_level,
|
||||
var_lwe,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
//KSK to convert from input ciphertext key to the wopbs input one
|
||||
@@ -111,7 +111,7 @@ impl ShortintEngine {
|
||||
cks.parameters.ks_base_log,
|
||||
cks.parameters.ks_level,
|
||||
var_lwe,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
//KSK large_wopbs_key -> small PBS key (used after the WoPBS computation to compute a
|
||||
@@ -125,7 +125,7 @@ impl ShortintEngine {
|
||||
cks.parameters.ks_base_log,
|
||||
cks.parameters.ks_level,
|
||||
var_lwe_pbs,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
let cbs_pfpksk = par_allocate_and_generate_new_circuit_bootstrap_lwe_pfpksk_list(
|
||||
@@ -134,7 +134,7 @@ impl ShortintEngine {
|
||||
parameters.pfks_base_log,
|
||||
parameters.pfks_level,
|
||||
parameters.pfks_modular_std_dev,
|
||||
self.engine.get_encryption_generator(),
|
||||
&mut self.encryption_generator,
|
||||
);
|
||||
|
||||
let wopbs_server_key = ServerKey {
|
||||
@@ -188,7 +188,7 @@ impl ShortintEngine {
|
||||
let fft = Fft::new(bsk.polynomial_size());
|
||||
let fft = fft.as_view();
|
||||
|
||||
self.fft_engine.resize(
|
||||
self.fft_buffers.resize(
|
||||
extract_bits_from_lwe_ciphertext_scratch::<u64>(
|
||||
lwe_in.lwe_size().to_lwe_dimension(),
|
||||
ksk.output_key_lwe_dimension(),
|
||||
@@ -200,7 +200,7 @@ impl ShortintEngine {
|
||||
.unaligned_bytes_required(),
|
||||
);
|
||||
|
||||
let stack = self.fft_engine.stack();
|
||||
let stack = self.fft_buffers.stack();
|
||||
|
||||
extract_bits_from_lwe_ciphertext(
|
||||
lwe_in,
|
||||
@@ -220,7 +220,7 @@ impl ShortintEngine {
|
||||
&mut self,
|
||||
wopbs_key: &WopbsKey,
|
||||
extracted_bits: &LweCiphertextListView<'_, u64>,
|
||||
lut: &PlaintextVector64,
|
||||
lut: &PlaintextListView<'_, u64>,
|
||||
count: LweCiphertextCount,
|
||||
) -> EngineResult<LweCiphertextList<u64>> {
|
||||
let sks = &wopbs_key.wopbs_server_key;
|
||||
@@ -232,7 +232,7 @@ impl ShortintEngine {
|
||||
|
||||
let fft = Fft::new(fourier_bsk.polynomial_size());
|
||||
let fft = fft.as_view();
|
||||
self.fft_engine.resize(
|
||||
self.fft_buffers.resize(
|
||||
circuit_bootstrap_boolean_vertical_packing_lwe_ciphertext_list_scracth::<u64>(
|
||||
extracted_bits.lwe_ciphertext_count(),
|
||||
output_cbs_vp_ct.lwe_ciphertext_count(),
|
||||
@@ -248,12 +248,9 @@ impl ShortintEngine {
|
||||
.unaligned_bytes_required(),
|
||||
);
|
||||
|
||||
let lut = PolynomialListView::from_container(
|
||||
lut.0.tensor.as_container().as_slice(),
|
||||
fourier_bsk.polynomial_size(),
|
||||
);
|
||||
let lut = PolynomialListView::from_container(lut.as_ref(), fourier_bsk.polynomial_size());
|
||||
|
||||
let stack = self.fft_engine.stack();
|
||||
let stack = self.fft_buffers.stack();
|
||||
|
||||
circuit_bootstrap_boolean_vertical_packing_lwe_ciphertext_list(
|
||||
extracted_bits,
|
||||
@@ -281,7 +278,7 @@ impl ShortintEngine {
|
||||
let extracted_bits =
|
||||
self.extract_bits(delta_log, &ct_in.ct, wopbs_key, nb_bit_to_extract)?;
|
||||
|
||||
let plaintext_lut = self.engine.create_plaintext_vector_from(lut)?;
|
||||
let plaintext_lut = PlaintextListBase::from_container(lut);
|
||||
|
||||
let ciphertext_list = self.circuit_bootstrap_with_bits(
|
||||
wopbs_key,
|
||||
@@ -373,7 +370,7 @@ impl ShortintEngine {
|
||||
// 2. PBS to remove the noise added by the previous KS
|
||||
//
|
||||
let acc = self.generate_accumulator(&wopbs_key.pbs_server_key, |x| x)?;
|
||||
let (buffers, _, fftw_engine) = self.buffers_for_key(&wopbs_key.pbs_server_key);
|
||||
let (buffers, fft_buffers) = self.buffers_for_key(&wopbs_key.pbs_server_key);
|
||||
// Compute a key switch
|
||||
keyswitch_lwe_ciphertext(
|
||||
&wopbs_key.pbs_server_key.key_switching_key,
|
||||
@@ -381,20 +378,34 @@ impl ShortintEngine {
|
||||
&mut buffers.buffer_lwe_after_ks,
|
||||
);
|
||||
|
||||
let out_lwe_size = wopbs_key
|
||||
.pbs_server_key
|
||||
.bootstrapping_key
|
||||
.output_lwe_dimension()
|
||||
.to_lwe_size();
|
||||
let mut ct_out = LweCiphertext::from_container(vec![0; out_lwe_size.0]);
|
||||
let fourier_bsk = &wopbs_key.pbs_server_key.bootstrapping_key;
|
||||
|
||||
let out_lwe_size = fourier_bsk.output_lwe_dimension().to_lwe_size();
|
||||
let mut ct_out = LweCiphertext::new(0, out_lwe_size);
|
||||
|
||||
let fft = Fft::new(fourier_bsk.polynomial_size());
|
||||
let fft = fft.as_view();
|
||||
fft_buffers.resize(
|
||||
programmable_bootstrap_lwe_ciphertext_scratch::<u64>(
|
||||
fourier_bsk.glwe_size(),
|
||||
fourier_bsk.polynomial_size(),
|
||||
fft,
|
||||
)
|
||||
.unwrap()
|
||||
.unaligned_bytes_required(),
|
||||
);
|
||||
let stack = fft_buffers.stack();
|
||||
|
||||
// Compute a bootstrap
|
||||
fftw_engine.discard_bootstrap_lwe_ciphertext(
|
||||
&mut ct_out.as_old_ct_mut_view(),
|
||||
&buffers.buffer_lwe_after_ks.as_old_ct_view(),
|
||||
&GlweCiphertextView64(acc.0.as_view()),
|
||||
&wopbs_key.pbs_server_key.bootstrapping_key.clone().into(),
|
||||
)?;
|
||||
programmable_bootstrap_lwe_ciphertext(
|
||||
&buffers.buffer_lwe_after_ks,
|
||||
&mut ct_out,
|
||||
&acc,
|
||||
fourier_bsk,
|
||||
fft,
|
||||
stack,
|
||||
);
|
||||
|
||||
Ok(Ciphertext {
|
||||
ct: ct_out,
|
||||
degree: ct_in.degree,
|
||||
@@ -477,28 +488,22 @@ impl ShortintEngine {
|
||||
&mut self,
|
||||
wopbs_key: &WopbsKey,
|
||||
vec_lut: Vec<Vec<u64>>,
|
||||
extracted_bits_blocks: Vec<LweCiphertextVector64>,
|
||||
) -> Vec<LweCiphertext64> {
|
||||
let lwe_size = extracted_bits_blocks[0].lwe_dimension().to_lwe_size();
|
||||
extracted_bits_blocks: Vec<LweCiphertextList<u64>>,
|
||||
) -> Vec<LweCiphertext<u64>> {
|
||||
let lwe_size = extracted_bits_blocks[0].lwe_size();
|
||||
|
||||
let mut all_datas = vec![];
|
||||
for lwe_vec in extracted_bits_blocks.into_iter() {
|
||||
let data = self
|
||||
.engine
|
||||
.consume_retrieve_lwe_ciphertext_vector(lwe_vec)
|
||||
.unwrap();
|
||||
for lwe_vec in extracted_bits_blocks.iter() {
|
||||
let data = lwe_vec.as_ref();
|
||||
|
||||
all_datas.extend_from_slice(data.as_slice());
|
||||
all_datas.extend_from_slice(data);
|
||||
}
|
||||
|
||||
let flatenned_extracted_bits_view =
|
||||
LweCiphertextListView::from_container(all_datas.as_slice(), lwe_size);
|
||||
|
||||
let flattened_lut: Vec<u64> = vec_lut.iter().flatten().copied().collect();
|
||||
let plaintext_lut = self
|
||||
.engine
|
||||
.create_plaintext_vector_from(&flattened_lut)
|
||||
.unwrap();
|
||||
let plaintext_lut = PlaintextListView::from_container(&flattened_lut);
|
||||
let output_list = self
|
||||
.circuit_bootstrap_with_bits(
|
||||
wopbs_key,
|
||||
@@ -511,16 +516,11 @@ impl ShortintEngine {
|
||||
assert_eq!(output_list.lwe_ciphertext_count().0, vec_lut.len());
|
||||
|
||||
let output_container = output_list.into_container();
|
||||
let lwes: Result<Vec<_>, Box<dyn std::error::Error>> = output_container
|
||||
let lwes: Vec<_> = output_container
|
||||
.chunks_exact(output_container.len() / vec_lut.len())
|
||||
.map(|s| {
|
||||
let lwe = self.engine.create_lwe_ciphertext_from(s.to_vec())?;
|
||||
Ok(lwe)
|
||||
})
|
||||
.map(|s| LweCiphertext::from_container(s.to_vec()))
|
||||
.collect();
|
||||
|
||||
let lwes = lwes.unwrap();
|
||||
|
||||
assert_eq!(lwes.len(), vec_lut.len());
|
||||
lwes
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//! Module with the definition of the PublicKey.
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::prelude::*;
|
||||
use crate::shortint::ciphertext::Ciphertext;
|
||||
use crate::shortint::engine::ShortintEngine;
|
||||
@@ -10,7 +11,7 @@ use std::fmt::Debug;
|
||||
/// A structure containing a public key.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PublicKey {
|
||||
pub(crate) lwe_public_key: LwePublicKey64,
|
||||
pub(crate) lwe_public_key: LwePublicKey<u64>,
|
||||
pub parameters: Parameters,
|
||||
}
|
||||
|
||||
@@ -213,8 +214,10 @@ impl Serialize for PublicKey {
|
||||
{
|
||||
let mut ser_eng = DefaultSerializationEngine::new(()).map_err(serde::ser::Error::custom)?;
|
||||
|
||||
let tmp_public_key: LwePublicKey64 = self.lwe_public_key.clone().into();
|
||||
|
||||
let lwe_public_key = ser_eng
|
||||
.serialize(&self.lwe_public_key)
|
||||
.serialize(&tmp_public_key)
|
||||
.map_err(serde::ser::Error::custom)?;
|
||||
|
||||
SerializablePublicKey {
|
||||
@@ -234,10 +237,12 @@ impl<'de> Deserialize<'de> for PublicKey {
|
||||
SerializablePublicKey::deserialize(deserializer).map_err(serde::de::Error::custom)?;
|
||||
let mut de_eng = DefaultSerializationEngine::new(()).map_err(serde::de::Error::custom)?;
|
||||
|
||||
let tmp_public_key: LwePublicKey64 = de_eng
|
||||
.deserialize(thing.lwe_public_key.as_slice())
|
||||
.map_err(serde::de::Error::custom)?;
|
||||
|
||||
Ok(Self {
|
||||
lwe_public_key: de_eng
|
||||
.deserialize(thing.lwe_public_key.as_slice())
|
||||
.map_err(serde::de::Error::custom)?,
|
||||
lwe_public_key: tmp_public_key.into(),
|
||||
parameters: thing.parameters,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ impl ServerKey {
|
||||
/// // 3^2 mod 4 = 1
|
||||
/// assert_eq!(dec, f(msg));
|
||||
/// ```
|
||||
pub fn generate_accumulator<F>(&self, f: F) -> GlweCiphertext64
|
||||
pub fn generate_accumulator<F>(&self, f: F) -> GlweCiphertext<u64>
|
||||
where
|
||||
F: Fn(u64) -> u64,
|
||||
{
|
||||
@@ -152,7 +152,7 @@ impl ServerKey {
|
||||
/// // 3^2 mod 4 = 1
|
||||
/// assert_eq!(dec, f(msg, 0));
|
||||
/// ```
|
||||
pub fn generate_accumulator_bivariate<F>(&self, f: F) -> GlweCiphertext64
|
||||
pub fn generate_accumulator_bivariate<F>(&self, f: F) -> GlweCiphertext<u64>
|
||||
where
|
||||
F: Fn(u64, u64) -> u64,
|
||||
{
|
||||
@@ -245,7 +245,7 @@ impl ServerKey {
|
||||
&self,
|
||||
ct_left: &Ciphertext,
|
||||
ct_right: &Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) -> Ciphertext {
|
||||
ShortintEngine::with_thread_local_mut(|engine| {
|
||||
engine
|
||||
@@ -258,7 +258,7 @@ impl ServerKey {
|
||||
&self,
|
||||
ct_left: &mut Ciphertext,
|
||||
ct_right: &Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) {
|
||||
ShortintEngine::with_thread_local_mut(|engine| {
|
||||
engine
|
||||
@@ -293,7 +293,7 @@ impl ServerKey {
|
||||
pub fn keyswitch_programmable_bootstrap(
|
||||
&self,
|
||||
ct_in: &Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) -> Ciphertext {
|
||||
ShortintEngine::with_thread_local_mut(|engine| {
|
||||
engine
|
||||
@@ -305,7 +305,7 @@ impl ServerKey {
|
||||
pub fn keyswitch_programmable_bootstrap_assign(
|
||||
&self,
|
||||
ct_in: &mut Ciphertext,
|
||||
acc: &GlweCiphertext64,
|
||||
acc: &GlweCiphertext<u64>,
|
||||
) {
|
||||
ShortintEngine::with_thread_local_mut(|engine| {
|
||||
engine
|
||||
|
||||
@@ -347,8 +347,8 @@ impl WopbsKey {
|
||||
pub fn circuit_bootstrapping_vertical_packing(
|
||||
&self,
|
||||
vec_lut: Vec<Vec<u64>>,
|
||||
extracted_bits_blocks: Vec<LweCiphertextVector64>,
|
||||
) -> Vec<LweCiphertext64> {
|
||||
extracted_bits_blocks: Vec<LweCiphertextList<u64>>,
|
||||
) -> Vec<LweCiphertext<u64>> {
|
||||
ShortintEngine::with_thread_local_mut(|engine| {
|
||||
engine.circuit_bootstrapping_vertical_packing(self, vec_lut, extracted_bits_blocks)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user