refactor(tfhe): remove core engines from ShortintEngine

This commit is contained in:
Arthur Meyre
2022-12-02 14:18:35 +01:00
committed by jborfila
parent 4aef755a81
commit b182d8ef05
28 changed files with 577 additions and 235 deletions

View File

@@ -8,10 +8,10 @@ pub type AccumulatorCallback = Option<extern "C" fn(u64) -> u64>;
pub type BivariateAccumulatorCallback = Option<extern "C" fn(u64, u64) -> u64>; pub type BivariateAccumulatorCallback = Option<extern "C" fn(u64, u64) -> u64>;
pub struct ShortintPBSAccumulator( 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 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] #[no_mangle]

View File

@@ -190,7 +190,7 @@ fn encrypt_ggsw_level_matrix_row<Scalar, KeyCont, InputCont, OutputCont, Gen>(
let mut body = row_as_glwe.get_mut_body(); let mut body = row_as_glwe.get_mut_body();
body.as_mut().copy_from_slice(sk_poly.as_ref()); 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); encrypt_glwe_ciphertext_in_place(glwe_secret_key, row_as_glwe, noise_parameters, generator);
} else { } else {

View File

@@ -5,6 +5,7 @@ use crate::core_crypto::commons::math::torus::UnsignedTorus;
use crate::core_crypto::commons::traits::*; use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*; use crate::core_crypto::entities::*;
use crate::core_crypto::specification::dispersion::DispersionParameter; use crate::core_crypto::specification::dispersion::DispersionParameter;
use crate::core_crypto::specification::parameters::*;
pub fn encrypt_glwe_ciphertext_in_place<Scalar, KeyCont, OutputCont, Gen>( pub fn encrypt_glwe_ciphertext_in_place<Scalar, KeyCont, OutputCont, Gen>(
glwe_secret_key: &GlweSecretKeyBase<KeyCont>, 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); 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
}

View File

@@ -43,7 +43,7 @@ pub fn extract_lwe_sample_from_glwe_ciphertext<Scalar, InputCont, OutputCont>(
// We reverse the polynomial // We reverse the polynomial
lwe_mask_poly.reverse(); lwe_mask_poly.reverse();
// We compute the opposite of the proper coefficients // 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 // We rotate the polynomial properly
lwe_mask_poly.rotate_left(opposite_count); lwe_mask_poly.rotate_left(opposite_count);
} }

View File

@@ -1,8 +1,13 @@
//! Module containing functions related to LWE ciphertext encryption and decryption //! Module containing functions related to LWE ciphertext encryption and decryption
use crate::core_crypto::algorithms::slice_algorithms::*; 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; 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::math::torus::UnsignedTorus;
use crate::core_crypto::commons::numeric::UnsignedInteger; use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::*; 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); *body.0 = generator.random_noise(noise_parameters);
// compute the multisum between the secret key and the mask // 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); *body.0 = (*body.0).wrapping_add(encoded.0);
} }
@@ -115,10 +123,10 @@ where
let (mask, body) = lwe_ciphertext.get_mask_and_body(); let (mask, body) = lwe_ciphertext.get_mask_and_body();
Plaintext( Plaintext(body.0.wrapping_sub(slice_wrapping_dot_product(
body.0 mask.as_ref(),
.wrapping_sub(wrapping_dot_product(mask.as_ref(), lwe_secret_key.as_ref())), lwe_secret_key.as_ref(),
) )))
} }
pub fn encrypt_lwe_ciphertext_list<Scalar, KeyCont, OutputCont, InputCont, Gen>( 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);
}

View File

@@ -55,7 +55,7 @@ pub fn keyswitch_lwe_ciphertext<Scalar, KSKCont, InputCont, OutputCont>(
for (level_key_ciphertext, decomposed) in for (level_key_ciphertext, decomposed) in
keyswitch_key_block.iter().rev().zip(decomposition_iter) 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(), output_lwe_ciphertext.as_mut(),
level_key_ciphertext.as_ref(), level_key_ciphertext.as_ref(),
decomposed.value(), decomposed.value(),

View File

@@ -14,7 +14,7 @@ pub fn lwe_ciphertext_in_place_addition<Scalar, LhsCont, RhsCont>(
LhsCont: ContainerMut<Element = Scalar>, LhsCont: ContainerMut<Element = Scalar>,
RhsCont: Container<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>( pub fn lwe_ciphertext_in_place_encoded_addition<Scalar, InCont>(
@@ -34,7 +34,7 @@ where
Scalar: UnsignedInteger, Scalar: UnsignedInteger,
InCont: ContainerMut<Element = Scalar>, 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>( 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, Scalar: UnsignedInteger,
InCont: ContainerMut<Element = Scalar>, 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>( 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>, LhsCont: ContainerMut<Element = Scalar>,
RhsCont: Container<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>( pub fn lwe_ciphertext_cleartext_multiplication<Scalar, InputCont, OutputCont>(

View File

@@ -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 // 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 // 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) { 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(), output_glwe_ciphertext.as_mut(),
level_key_cipher.as_ref(), level_key_cipher.as_ref(),
decomposed.value(), decomposed.value(),
@@ -94,6 +94,6 @@ pub fn private_functional_keyswitch_lwe_ciphertext_list_and_pack_in_glwe_ciphere
MonomialDegree(degree), MonomialDegree(degree),
) )
}); });
update_with_wrapping_add(output.as_mut(), buffer.as_ref()); update_slice_with_wrapping_add(output.as_mut(), buffer.as_ref());
} }
} }

View File

@@ -90,7 +90,7 @@ pub fn generate_lwe_private_functional_packing_keyswitch_key<
.map(DecompositionLevel) .map(DecompositionLevel)
.zip(messages.chunks_exact_mut(polynomial_size.0)) .zip(messages.chunks_exact_mut(polynomial_size.0))
{ {
update_with_wrapping_add_scalar_mul( update_slice_with_wrapping_add_scalar_mul(
message.as_mut(), message.as_mut(),
polynomial.as_ref(), polynomial.as_ref(),
DecompositionTerm::new( DecompositionTerm::new(
@@ -192,7 +192,7 @@ pub fn par_generate_lwe_private_functional_packing_keyswitch_key<
.map(DecompositionLevel) .map(DecompositionLevel)
.zip(messages.chunks_exact_mut(polynomial_size.0)) .zip(messages.chunks_exact_mut(polynomial_size.0))
{ {
update_with_wrapping_add_scalar_mul( update_slice_with_wrapping_add_scalar_mul(
message.as_mut(), message.as_mut(),
polynomial.as_ref(), polynomial.as_ref(),
DecompositionTerm::new( DecompositionTerm::new(

View 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
}

View File

@@ -11,6 +11,7 @@ pub mod lwe_linear_algebra;
pub mod lwe_private_functional_packing_keyswitch; pub mod lwe_private_functional_packing_keyswitch;
pub mod lwe_private_functional_packing_keyswitch_key_generation; pub mod lwe_private_functional_packing_keyswitch_key_generation;
pub mod lwe_programmable_bootstrapping; pub mod lwe_programmable_bootstrapping;
pub mod lwe_public_key_generation;
pub mod lwe_secret_key_generation; pub mod lwe_secret_key_generation;
pub mod lwe_wopbs; pub mod lwe_wopbs;
pub mod polynomial_algorithms; 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::*;
pub use lwe_private_functional_packing_keyswitch_key_generation::*; pub use lwe_private_functional_packing_keyswitch_key_generation::*;
pub use lwe_programmable_bootstrapping::*; pub use lwe_programmable_bootstrapping::*;
pub use lwe_public_key_generation::*;
pub use lwe_secret_key_generation::*; pub use lwe_secret_key_generation::*;
pub use lwe_wopbs::*; pub use lwe_wopbs::*;

View File

@@ -14,7 +14,7 @@ pub fn update_polynomial_with_wrapping_add<Scalar, OutputCont, InputCont>(
InputCont: Container<Element = Scalar>, InputCont: Container<Element = Scalar>,
{ {
assert!(lhs.polynomial_size() == rhs.polynomial_size()); 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>( pub fn update_polynomial_with_wrapping_add_multisum<Scalar, OutputCont, InputCont1, InputCont2>(

View File

@@ -1,6 +1,6 @@
use crate::core_crypto::commons::numeric::UnsignedInteger; 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 where
Scalar: UnsignedInteger, 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 where
Scalar: UnsignedInteger, Scalar: UnsignedInteger,
{ {
@@ -34,7 +34,7 @@ where
.for_each(|(lhs, &rhs)| *lhs = (*lhs).wrapping_add(rhs)); .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], lhs: &mut [Scalar],
rhs: &[Scalar], rhs: &[Scalar],
scalar: 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))); .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 where
Scalar: UnsignedInteger, Scalar: UnsignedInteger,
{ {
@@ -68,7 +68,7 @@ where
.for_each(|(lhs, &rhs)| *lhs = (*lhs).wrapping_sub(rhs)); .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], lhs: &mut [Scalar],
rhs: &[Scalar], rhs: &[Scalar],
scalar: 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))); .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 where
Scalar: UnsignedInteger, Scalar: UnsignedInteger,
{ {
@@ -95,7 +95,7 @@ where
.for_each(|elt| *elt = (*elt).wrapping_neg()); .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 where
Scalar: UnsignedInteger, Scalar: UnsignedInteger,
{ {

View File

@@ -12,13 +12,13 @@ impl<C: Container> std::ops::Deref for LweBootstrapKeyBase<C> {
type Target = GgswCiphertextListBase<C>; type Target = GgswCiphertextListBase<C>;
fn deref(&self) -> &GgswCiphertextListBase<C> { fn deref(&self) -> &GgswCiphertextListBase<C> {
self.as_ggsw_ciphertext_list() &self.ggsw_list
} }
} }
impl<C: ContainerMut> std::ops::DerefMut for LweBootstrapKeyBase<C> { impl<C: ContainerMut> std::ops::DerefMut for LweBootstrapKeyBase<C> {
fn deref_mut(&mut self) -> &mut GgswCiphertextListBase<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) 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 { pub fn into_container(self) -> C {
self.ggsw_list.into_container() 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> { 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]> { pub fn as_mut_view(&mut self) -> LweBootstrapKeyBase<&'_ mut [Scalar]> {
let glwe_size = self.glwe_size(); let glwe_size = self.glwe_size();
let polynomial_size = self.polynomial_size(); let polynomial_size = self.polynomial_size();

View File

@@ -2,6 +2,7 @@ use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*; use crate::core_crypto::entities::*;
use crate::core_crypto::specification::parameters::*; use crate::core_crypto::specification::parameters::*;
#[derive(Clone, Debug, PartialEq)]
pub struct LweCiphertextListBase<C: Container> { pub struct LweCiphertextListBase<C: Container> {
data: C, data: C,
lwe_size: LweSize, lwe_size: LweSize,

View 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)
}
}

View File

@@ -10,6 +10,7 @@ pub mod lwe_ciphertext_list;
pub mod lwe_keyswitch_key; pub mod lwe_keyswitch_key;
pub mod lwe_private_functional_packing_keyswitch_key; pub mod lwe_private_functional_packing_keyswitch_key;
pub mod lwe_private_functional_packing_keyswitch_key_list; pub mod lwe_private_functional_packing_keyswitch_key_list;
pub mod lwe_public_key;
pub mod lwe_secret_key; pub mod lwe_secret_key;
pub mod plaintext; pub mod plaintext;
pub mod plaintext_list; pub mod plaintext_list;
@@ -28,6 +29,7 @@ pub use lwe_ciphertext_list::*;
pub use lwe_keyswitch_key::*; pub use lwe_keyswitch_key::*;
pub use lwe_private_functional_packing_keyswitch_key::*; pub use lwe_private_functional_packing_keyswitch_key::*;
pub use lwe_private_functional_packing_keyswitch_key_list::*; pub use lwe_private_functional_packing_keyswitch_key_list::*;
pub use lwe_public_key::*;
pub use lwe_secret_key::*; pub use lwe_secret_key::*;
pub use plaintext::*; pub use plaintext::*;
pub use plaintext_list::*; pub use plaintext_list::*;

View File

@@ -34,12 +34,20 @@ impl<Scalar, C: Container<Element = Scalar>> PlaintextListBase<C> {
pub fn into_container(self) -> C { pub fn into_container(self) -> C {
self.data self.data
} }
pub fn as_view(&self) -> PlaintextListView<'_, Scalar> {
PlaintextListView::from_container(self.as_ref())
}
} }
impl<Scalar, C: ContainerMut<Element = Scalar>> PlaintextListBase<C> { impl<Scalar, C: ContainerMut<Element = Scalar>> PlaintextListBase<C> {
pub fn as_mut_polynomial(&mut self) -> PolynomialMutView<'_, Scalar> { pub fn as_mut_polynomial(&mut self) -> PolynomialMutView<'_, Scalar> {
PolynomialMutView::from_container(self.as_mut()) 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>>; pub type PlaintextList<Scalar> = PlaintextListBase<Vec<Scalar>>;

View File

@@ -324,7 +324,10 @@ fn test_circuit_bootstrapping_binary() {
let multiplying_factor = 0u64.wrapping_sub(value); 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 = let decomposer =
SignedDecomposer::new(base_log_cbs, DecompositionLevelCount(current_level)); SignedDecomposer::new(base_log_cbs, DecompositionLevelCount(current_level));

View File

@@ -1,6 +1,9 @@
//! Module with the definition of a short-integer ciphertext. //! Module with the definition of a short-integer ciphertext.
use crate::core_crypto::entities::*; 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 crate::shortint::parameters::{CarryModulus, MessageModulus};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp; use std::cmp;

View File

@@ -11,14 +11,14 @@ impl ShortintEngine {
// generate the lwe secret key // generate the lwe secret key
let small_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( let small_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key(
parameters.lwe_dimension, parameters.lwe_dimension,
self.engine.get_secret_generator(), &mut self.secret_generator,
); );
// generate the rlwe secret key // generate the rlwe secret key
let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key(
parameters.glwe_dimension, parameters.glwe_dimension,
parameters.polynomial_size, 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(); let large_lwe_secret_key = glwe_secret_key.clone().into_lwe_secret_key();
@@ -68,7 +68,7 @@ impl ShortintEngine {
&client_key.lwe_secret_key, &client_key.lwe_secret_key,
encoded, encoded,
client_key.parameters.lwe_modular_std_dev, client_key.parameters.lwe_modular_std_dev,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
Ok(Ciphertext { Ok(Ciphertext {
@@ -95,7 +95,7 @@ impl ShortintEngine {
&client_key.lwe_secret_key, &client_key.lwe_secret_key,
encoded, encoded,
client_key.parameters.lwe_modular_std_dev, client_key.parameters.lwe_modular_std_dev,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
Ok(Ciphertext { Ok(Ciphertext {
@@ -155,7 +155,7 @@ impl ShortintEngine {
&client_key.lwe_secret_key, &client_key.lwe_secret_key,
encoded, encoded,
client_key.parameters.lwe_modular_std_dev, client_key.parameters.lwe_modular_std_dev,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
Ok(Ciphertext { Ok(Ciphertext {
@@ -215,7 +215,7 @@ impl ShortintEngine {
&client_key.lwe_secret_key, &client_key.lwe_secret_key,
encoded, encoded,
client_key.parameters.lwe_modular_std_dev, client_key.parameters.lwe_modular_std_dev,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
Ok(Ciphertext { Ok(Ciphertext {

View File

@@ -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::entities::*;
use crate::core_crypto::prelude::*; use crate::core_crypto::prelude::{Seeder, *};
use crate::seeders::new_seeder; use crate::seeders::new_seeder;
use crate::shortint::ServerKey; use crate::shortint::ServerKey;
use core::mem::MaybeUninit;
use dyn_stack::DynStack;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::Debug; use std::fmt::Debug;
@@ -25,6 +31,30 @@ pub struct Buffers {
pub(crate) buffer_lwe_after_ks: LweCiphertext<u64>, 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` /// This allows to store and retrieve the `Buffers`
/// corresponding to a `ServerKey` in a `BTreeMap` /// corresponding to a `ServerKey` in a `BTreeMap`
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] #[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. /// This structs actually implements the logics into its methods.
pub struct ShortintEngine { pub struct ShortintEngine {
pub(crate) engine: DefaultEngine, /// A structure containing a single CSPRNG to generate secret key coefficients.
pub(crate) fft_engine: FftEngine, pub(crate) secret_generator: SecretRandomGenerator<ActivatedRandomGenerator>,
pub(crate) par_engine: DefaultParallelEngine, /// 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>, buffers: BTreeMap<KeyId, Buffers>,
} }
@@ -111,31 +148,25 @@ impl ShortintEngine {
let mut deterministic_seeder = let mut deterministic_seeder =
DeterministicSeeder::<ActivatedRandomGenerator>::new(root_seeder.seed()); DeterministicSeeder::<ActivatedRandomGenerator>::new(root_seeder.seed());
let default_engine_seeder = Box::new(DeterministicSeeder::<ActivatedRandomGenerator>::new( // Note that the operands are evaluated from left to right for Rust Struct expressions
deterministic_seeder.seed(), // 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
let default_parallel_engine_seeder = Box::new(DeterministicSeeder::< // is passed as_mut in EncryptionRandomGenerator::new
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();
Self { Self {
engine, secret_generator: SecretRandomGenerator::new(deterministic_seeder.seed()),
fft_engine, encryption_generator: EncryptionRandomGenerator::new(
par_engine, deterministic_seeder.seed(),
&mut deterministic_seeder,
),
fft_buffers: Default::default(),
buffers: Default::default(), buffers: Default::default(),
} }
} }
fn generate_accumulator_with_engine<F>( fn generate_accumulator_with_engine<F>(
engine: &mut DefaultEngine,
server_key: &ServerKey, server_key: &ServerKey,
f: F, f: F,
) -> EngineResult<GlweCiphertext64> ) -> EngineResult<GlweCiphertext<u64>>
where where
F: Fn(u64) -> u64, F: Fn(u64) -> u64,
{ {
@@ -171,21 +202,20 @@ impl ShortintEngine {
accumulator_u64.rotate_left(half_box_size); accumulator_u64.rotate_left(half_box_size);
// Everywhere // 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(), server_key.bootstrapping_key.glwe_size(),
&accumulator_plaintext, &accumulator_plaintext,
)?; );
Ok(accumulator) Ok(accumulator)
} }
fn generate_accumulator_bivariate_with_engine<F>( fn generate_accumulator_bivariate_with_engine<F>(
engine: &mut DefaultEngine,
server_key: &ServerKey, server_key: &ServerKey,
f: F, f: F,
) -> EngineResult<GlweCiphertext64> ) -> EngineResult<GlweCiphertext<u64>>
where where
F: Fn(u64, u64) -> u64, F: Fn(u64, u64) -> u64,
{ {
@@ -196,7 +226,7 @@ impl ShortintEngine {
f(lhs, rhs) 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` /// Returns the `Buffers` for the given `ServerKey`
@@ -206,43 +236,32 @@ impl ShortintEngine {
/// This also `&mut CoreEngine` to simply borrow checking for the caller /// This also `&mut CoreEngine` to simply borrow checking for the caller
/// (since returned buffers are borrowed from `self`, using the `self.engine` /// (since returned buffers are borrowed from `self`, using the `self.engine`
/// wouldn't be possible after calling `buffers_for_key`) /// wouldn't be possible after calling `buffers_for_key`)
pub fn buffers_for_key( pub fn buffers_for_key(&mut self, server_key: &ServerKey) -> (&mut Buffers, &mut FftBuffers) {
&mut self,
server_key: &ServerKey,
) -> (&mut Buffers, &mut DefaultEngine, &mut FftEngine) {
let key = server_key.key_id(); let key = server_key.key_id();
// To make borrow checker happy // To make borrow checker happy
let engine = &mut self.engine;
let buffers_map = &mut self.buffers; let buffers_map = &mut self.buffers;
let buffers = buffers_map.entry(key).or_insert_with(|| { 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 n % server_key.message_modulus.0 as u64
}) })
.unwrap(); .unwrap();
// Allocate the buffer for the output of the PBS // Allocate the buffer for the output of the PBS
let zero_plaintext = engine.create_plaintext_from(&0_u64).unwrap(); let zero_plaintext = Plaintext(0_u64);
let buffer_lwe_after_pbs = engine let buffer_lwe_after_ks = allocate_and_trivially_encrypt_new_lwe_ciphertext(
.trivially_encrypt_lwe_ciphertext( server_key
server_key .key_switching_key
.key_switching_key .output_key_lwe_dimension()
.output_key_lwe_dimension() .to_lwe_size(),
.to_lwe_size(), zero_plaintext,
&zero_plaintext, );
)
.unwrap();
let polynomial_size = accumulator.polynomial_size();
Buffers { Buffers {
accumulator: GlweCiphertext::from_container( accumulator,
accumulator.0.into_container(), buffer_lwe_after_ks,
polynomial_size,
),
buffer_lwe_after_ks: buffer_lwe_after_pbs.into(),
} }
}); });
(buffers, engine, &mut self.fft_engine) (buffers, &mut self.fft_buffers)
} }
} }

View File

@@ -1,5 +1,7 @@
//! All the `ShortintEngine` method related to client side (encrypt / decrypt) //! All the `ShortintEngine` method related to client side (encrypt / decrypt)
use super::{EngineResult, ShortintEngine}; use super::{EngineResult, ShortintEngine};
use crate::core_crypto::algorithms::*;
use crate::core_crypto::entities::*;
use crate::core_crypto::prelude::*; use crate::core_crypto::prelude::*;
use crate::shortint::ciphertext::Degree; use crate::shortint::ciphertext::Degree;
use crate::shortint::parameters::{CarryModulus, MessageModulus}; use crate::shortint::parameters::{CarryModulus, MessageModulus};
@@ -19,14 +21,17 @@ impl ShortintEngine {
+ 128, + 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 // TODO REFACTOR
// Remove the clone + into // Remove the clone + into
Ok(PublicKey { Ok(PublicKey {
lwe_public_key: self.par_engine.generate_new_lwe_public_key( lwe_public_key,
&client_key.lwe_secret_key.clone().into(),
Variance(client_key.parameters.lwe_modular_std_dev.get_variance()),
zero_encryption_count,
)?,
parameters: client_key.parameters.to_owned(), parameters: client_key.parameters.to_owned(),
}) })
} }
@@ -72,23 +77,20 @@ impl ShortintEngine {
let shifted_message = m * delta; let shifted_message = m * delta;
// encode the message // encode the message
let plain: Plaintext64 = self.engine.create_plaintext_from(&shifted_message)?; let plain = Plaintext(shifted_message);
// This allocates the required ct // This allocates the required ct
let mut encrypted_ct = self.engine.trivially_encrypt_lwe_ciphertext( let mut encrypted_ct = LweCiphertext::new(0u64, public_key.lwe_public_key.lwe_size());
public_key.lwe_public_key.lwe_dimension().to_lwe_size(),
&plain,
)?;
// encryption encrypt_lwe_ciphertext_with_public_key(
self.engine.discard_encrypt_lwe_ciphertext_with_public_key(
&public_key.lwe_public_key, &public_key.lwe_public_key,
&mut encrypted_ct, &mut encrypted_ct,
&plain, plain,
)?; &mut self.secret_generator,
);
Ok(Ciphertext { Ok(Ciphertext {
ct: encrypted_ct.into(), ct: encrypted_ct,
degree: Degree(message_modulus.0 - 1), degree: Degree(message_modulus.0 - 1),
message_modulus, message_modulus,
carry_modulus: CarryModulus(carry_modulus), carry_modulus: CarryModulus(carry_modulus),
@@ -108,23 +110,21 @@ impl ShortintEngine {
let shifted_message = message * delta; let shifted_message = message * delta;
// encode the message // encode the message
let plain: Plaintext64 = self.engine.create_plaintext_from(&shifted_message)?; let plain = Plaintext(shifted_message);
// This allocates the required ct // This allocates the required ct
let mut encrypted_ct = self.engine.trivially_encrypt_lwe_ciphertext( let mut encrypted_ct = LweCiphertext::new(0u64, public_key.lwe_public_key.lwe_size());
public_key.lwe_public_key.lwe_dimension().to_lwe_size(),
&plain,
)?;
// encryption // encryption
self.engine.discard_encrypt_lwe_ciphertext_with_public_key( encrypt_lwe_ciphertext_with_public_key(
&public_key.lwe_public_key, &public_key.lwe_public_key,
&mut encrypted_ct, &mut encrypted_ct,
&plain, plain,
)?; &mut self.secret_generator,
);
Ok(Ciphertext { Ok(Ciphertext {
ct: encrypted_ct.into(), ct: encrypted_ct,
degree: Degree(public_key.parameters.message_modulus.0 - 1), degree: Degree(public_key.parameters.message_modulus.0 - 1),
message_modulus: public_key.parameters.message_modulus, message_modulus: public_key.parameters.message_modulus,
carry_modulus: public_key.parameters.carry_modulus, carry_modulus: public_key.parameters.carry_modulus,
@@ -141,25 +141,21 @@ impl ShortintEngine {
let m = (message % message_modulus as u64) as u128; let m = (message % message_modulus as u64) as u128;
let shifted_message = m * (1 << 64) / message_modulus as u128; let shifted_message = m * (1 << 64) / message_modulus as u128;
// encode the message // encode the message
let plain: Plaintext64 = self
.engine let plain = Plaintext(shifted_message as u64);
.create_plaintext_from(&(shifted_message as u64))?;
// This allocates the required ct // This allocates the required ct
let mut encrypted_ct = self.engine.trivially_encrypt_lwe_ciphertext( let mut encrypted_ct = LweCiphertext::new(0u64, public_key.lwe_public_key.lwe_size());
public_key.lwe_public_key.lwe_dimension().to_lwe_size(),
&plain,
)?;
// encryption encrypt_lwe_ciphertext_with_public_key(
self.engine.discard_encrypt_lwe_ciphertext_with_public_key(
&public_key.lwe_public_key, &public_key.lwe_public_key,
&mut encrypted_ct, &mut encrypted_ct,
&plain, plain,
)?; &mut self.secret_generator,
);
Ok(Ciphertext { Ok(Ciphertext {
ct: encrypted_ct.into(), ct: encrypted_ct,
degree: Degree(message_modulus as usize - 1), degree: Degree(message_modulus as usize - 1),
message_modulus: MessageModulus(message_modulus as usize), message_modulus: MessageModulus(message_modulus as usize),
carry_modulus: CarryModulus(carry_modulus), carry_modulus: CarryModulus(carry_modulus),
@@ -176,23 +172,20 @@ impl ShortintEngine {
as u64; as u64;
let shifted_message = message * delta; let shifted_message = message * delta;
// encode the message // encode the message
let plain: Plaintext64 = self.engine.create_plaintext_from(&shifted_message)?; let plain = Plaintext(shifted_message);
// This allocates the required ct // This allocates the required ct
let mut encrypted_ct = self.engine.trivially_encrypt_lwe_ciphertext( let mut encrypted_ct = LweCiphertext::new(0u64, public_key.lwe_public_key.lwe_size());
public_key.lwe_public_key.lwe_dimension().to_lwe_size(),
&plain,
)?;
// encryption encrypt_lwe_ciphertext_with_public_key(
self.engine.discard_encrypt_lwe_ciphertext_with_public_key(
&public_key.lwe_public_key, &public_key.lwe_public_key,
&mut encrypted_ct, &mut encrypted_ct,
&plain, plain,
)?; &mut self.secret_generator,
);
Ok(Ciphertext { Ok(Ciphertext {
ct: encrypted_ct.into(), ct: encrypted_ct,
degree: Degree( degree: Degree(
public_key.parameters.message_modulus.0 * public_key.parameters.carry_modulus.0 - 1, public_key.parameters.message_modulus.0 * public_key.parameters.carry_modulus.0 - 1,
), ),

View File

@@ -1,10 +1,8 @@
use super::ShortintEngine; use super::ShortintEngine;
use crate::core_crypto::algorithms::*; use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::math::tensor::{AsRefSlice, AsRefTensor};
use crate::core_crypto::entities::*; use crate::core_crypto::entities::*;
use crate::core_crypto::fft_impl::crypto::bootstrap::FourierLweBootstrapKey; use crate::core_crypto::fft_impl::crypto::bootstrap::FourierLweBootstrapKey;
use crate::core_crypto::fft_impl::math::fft::Fft; use crate::core_crypto::fft_impl::math::fft::Fft;
use crate::core_crypto::prelude::*;
use crate::shortint::ciphertext::Degree; use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::EngineResult; use crate::shortint::engine::EngineResult;
use crate::shortint::server_key::MaxDegree; use crate::shortint::server_key::MaxDegree;
@@ -44,7 +42,7 @@ impl ShortintEngine {
cks.parameters.pbs_base_log, cks.parameters.pbs_base_log,
cks.parameters.pbs_level, cks.parameters.pbs_level,
cks.parameters.glwe_modular_std_dev, cks.parameters.glwe_modular_std_dev,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
// Creation of the bootstrapping key in the Fourier domain // 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::new(bootstrap_key.polynomial_size());
let fft = fft.as_view(); let fft = fft.as_view();
self.fft_engine.resize( self.fft_buffers.resize(
convert_standard_lwe_bootstrap_key_to_fourier_scratch(fft) convert_standard_lwe_bootstrap_key_to_fourier_scratch(fft)
.unwrap() .unwrap()
.unaligned_bytes_required(), .unaligned_bytes_required(),
); );
let stack = self.fft_engine.stack(); let stack = self.fft_buffers.stack();
// Conversion to fourier domain // Conversion to fourier domain
convert_standard_lwe_bootstrap_key_to_fourier(&bootstrap_key, &mut fourier_bsk, fft, stack); 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_base_log,
cks.parameters.ks_level, cks.parameters.ks_level,
cks.parameters.lwe_modular_std_dev, cks.parameters.lwe_modular_std_dev,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
// Pack the keys in the server key set: // Pack the keys in the server key set:
@@ -92,11 +90,11 @@ impl ShortintEngine {
&mut self, &mut self,
server_key: &ServerKey, server_key: &ServerKey,
f: F, f: F,
) -> EngineResult<GlweCiphertext64> ) -> EngineResult<GlweCiphertext<u64>>
where where
F: Fn(u64) -> u64, 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( pub(crate) fn keyswitch_bootstrap(
@@ -115,7 +113,7 @@ impl ShortintEngine {
ct: &mut Ciphertext, ct: &mut Ciphertext,
) -> EngineResult<()> { ) -> EngineResult<()> {
// Compute the programmable bootstrapping with fixed test polynomial // 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 // Compute a keyswitch
keyswitch_lwe_ciphertext( keyswitch_lwe_ciphertext(
@@ -128,7 +126,7 @@ impl ShortintEngine {
let fft = Fft::new(fourier_bsk.polynomial_size()); let fft = Fft::new(fourier_bsk.polynomial_size());
let fft = fft.as_view(); let fft = fft.as_view();
fft_engine.resize( fft_buffers.resize(
programmable_bootstrap_lwe_ciphertext_scratch::<u64>( programmable_bootstrap_lwe_ciphertext_scratch::<u64>(
fourier_bsk.glwe_size(), fourier_bsk.glwe_size(),
fourier_bsk.polynomial_size(), fourier_bsk.polynomial_size(),
@@ -137,7 +135,7 @@ impl ShortintEngine {
.unwrap() .unwrap()
.unaligned_bytes_required(), .unaligned_bytes_required(),
); );
let stack = fft_engine.stack(); let stack = fft_buffers.stack();
// Compute a bootstrap // Compute a bootstrap
programmable_bootstrap_lwe_ciphertext( programmable_bootstrap_lwe_ciphertext(
@@ -156,7 +154,7 @@ impl ShortintEngine {
&mut self, &mut self,
server_key: &ServerKey, server_key: &ServerKey,
ct: &Ciphertext, ct: &Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) -> EngineResult<Ciphertext> { ) -> EngineResult<Ciphertext> {
let mut ct_res = ct.clone(); let mut ct_res = ct.clone();
self.programmable_bootstrap_keyswitch_assign(server_key, &mut ct_res, acc)?; self.programmable_bootstrap_keyswitch_assign(server_key, &mut ct_res, acc)?;
@@ -167,10 +165,10 @@ impl ShortintEngine {
&mut self, &mut self,
server_key: &ServerKey, server_key: &ServerKey,
ct: &mut Ciphertext, ct: &mut Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) -> EngineResult<()> { ) -> EngineResult<()> {
// Compute the programmable bootstrapping with fixed test polynomial // 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 // Compute a key switch
keyswitch_lwe_ciphertext( keyswitch_lwe_ciphertext(
@@ -183,7 +181,7 @@ impl ShortintEngine {
let fft = Fft::new(fourier_bsk.polynomial_size()); let fft = Fft::new(fourier_bsk.polynomial_size());
let fft = fft.as_view(); let fft = fft.as_view();
fft_engine.resize( fft_buffers.resize(
programmable_bootstrap_lwe_ciphertext_scratch::<u64>( programmable_bootstrap_lwe_ciphertext_scratch::<u64>(
fourier_bsk.glwe_size(), fourier_bsk.glwe_size(),
fourier_bsk.polynomial_size(), fourier_bsk.polynomial_size(),
@@ -192,16 +190,13 @@ impl ShortintEngine {
.unwrap() .unwrap()
.unaligned_bytes_required(), .unaligned_bytes_required(),
); );
let stack = fft_engine.stack(); let stack = fft_buffers.stack();
// Compute a bootstrap // Compute a bootstrap
programmable_bootstrap_lwe_ciphertext( programmable_bootstrap_lwe_ciphertext(
&buffers.buffer_lwe_after_ks, &buffers.buffer_lwe_after_ks,
&mut ct.ct, &mut ct.ct,
&GlweCiphertextBase::from_container( acc,
acc.0.as_tensor().as_slice(),
acc.polynomial_size(),
),
fourier_bsk, fourier_bsk,
fft, fft,
stack, stack,
@@ -214,7 +209,7 @@ impl ShortintEngine {
server_key: &ServerKey, server_key: &ServerKey,
ct_left: &Ciphertext, ct_left: &Ciphertext,
ct_right: &Ciphertext, ct_right: &Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) -> EngineResult<Ciphertext> { ) -> EngineResult<Ciphertext> {
let mut ct_res = ct_left.clone(); let mut ct_res = ct_left.clone();
self.programmable_bootstrap_keyswitch_bivariate_assign( self.programmable_bootstrap_keyswitch_bivariate_assign(
@@ -231,7 +226,7 @@ impl ShortintEngine {
server_key: &ServerKey, server_key: &ServerKey,
ct_left: &mut Ciphertext, ct_left: &mut Ciphertext,
ct_right: &Ciphertext, ct_right: &Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) -> EngineResult<()> { ) -> EngineResult<()> {
let modulus = (ct_right.degree.0 + 1) as u64; let modulus = (ct_right.degree.0 + 1) as u64;
@@ -251,11 +246,11 @@ impl ShortintEngine {
&mut self, &mut self,
server_key: &ServerKey, server_key: &ServerKey,
f: F, f: F,
) -> EngineResult<GlweCiphertext64> ) -> EngineResult<GlweCiphertext<u64>>
where where
F: Fn(u64, u64) -> u64, 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>( pub(crate) fn unchecked_functional_bivariate_pbs<F>(
@@ -307,7 +302,7 @@ impl ShortintEngine {
server_key: &ServerKey, server_key: &ServerKey,
ct_left: &Ciphertext, ct_left: &Ciphertext,
ct_right: &mut Ciphertext, ct_right: &mut Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) -> EngineResult<Ciphertext> { ) -> EngineResult<Ciphertext> {
let mut ct_res = ct_left.clone(); let mut ct_res = ct_left.clone();
self.smart_bivariate_pbs_assign(server_key, &mut ct_res, ct_right, acc)?; self.smart_bivariate_pbs_assign(server_key, &mut ct_res, ct_right, acc)?;
@@ -320,7 +315,7 @@ impl ShortintEngine {
server_key: &ServerKey, server_key: &ServerKey,
ct_left: &mut Ciphertext, ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext, ct_right: &mut Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) -> EngineResult<()> { ) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) { if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?; self.message_extract_assign(server_key, ct_left)?;
@@ -336,7 +331,7 @@ impl ShortintEngine {
server_key: &ServerKey, server_key: &ServerKey,
ct_left: &mut Ciphertext, ct_left: &mut Ciphertext,
ct_right: &Ciphertext, ct_right: &Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) -> EngineResult<()> { ) -> EngineResult<()> {
let modulus = (ct_right.degree.0 + 1) as u64; let modulus = (ct_right.degree.0 + 1) as u64;

View File

@@ -23,7 +23,7 @@ impl ShortintEngine {
cks.parameters.pfks_base_log, cks.parameters.pfks_base_log,
cks.parameters.pfks_level, cks.parameters.pfks_level,
cks.parameters.pfks_modular_std_dev, cks.parameters.pfks_modular_std_dev,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
let sks_cpy = sks.clone(); let sks_cpy = sks.clone();
@@ -48,13 +48,13 @@ impl ShortintEngine {
//Independent client key generation dedicated to the WoPBS //Independent client key generation dedicated to the WoPBS
let small_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( let small_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key(
parameters.lwe_dimension, parameters.lwe_dimension,
self.engine.get_secret_generator(), &mut self.secret_generator,
); );
let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key(
parameters.glwe_dimension, parameters.glwe_dimension,
parameters.polynomial_size, 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(); 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_base_log,
parameters.pbs_level, parameters.pbs_level,
parameters.glwe_modular_std_dev, parameters.glwe_modular_std_dev,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
// Creation of the bootstrapping key in the Fourier domain // 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::new(bootstrap_key.polynomial_size());
let fft = fft.as_view(); let fft = fft.as_view();
self.fft_engine.resize( self.fft_buffers.resize(
convert_standard_lwe_bootstrap_key_to_fourier_scratch(fft) convert_standard_lwe_bootstrap_key_to_fourier_scratch(fft)
.unwrap() .unwrap()
.unaligned_bytes_required(), .unaligned_bytes_required(),
); );
let stack = self.fft_engine.stack(); let stack = self.fft_buffers.stack();
// Conversion to fourier domain // Conversion to fourier domain
convert_standard_lwe_bootstrap_key_to_fourier(&bootstrap_key, &mut small_bsk, fft, stack); 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_base_log,
parameters.ks_level, parameters.ks_level,
var_lwe, var_lwe,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
//KSK to convert from input ciphertext key to the wopbs input one //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_base_log,
cks.parameters.ks_level, cks.parameters.ks_level,
var_lwe, 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 //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_base_log,
cks.parameters.ks_level, cks.parameters.ks_level,
var_lwe_pbs, 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( 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_base_log,
parameters.pfks_level, parameters.pfks_level,
parameters.pfks_modular_std_dev, parameters.pfks_modular_std_dev,
self.engine.get_encryption_generator(), &mut self.encryption_generator,
); );
let wopbs_server_key = ServerKey { let wopbs_server_key = ServerKey {
@@ -188,7 +188,7 @@ impl ShortintEngine {
let fft = Fft::new(bsk.polynomial_size()); let fft = Fft::new(bsk.polynomial_size());
let fft = fft.as_view(); let fft = fft.as_view();
self.fft_engine.resize( self.fft_buffers.resize(
extract_bits_from_lwe_ciphertext_scratch::<u64>( extract_bits_from_lwe_ciphertext_scratch::<u64>(
lwe_in.lwe_size().to_lwe_dimension(), lwe_in.lwe_size().to_lwe_dimension(),
ksk.output_key_lwe_dimension(), ksk.output_key_lwe_dimension(),
@@ -200,7 +200,7 @@ impl ShortintEngine {
.unaligned_bytes_required(), .unaligned_bytes_required(),
); );
let stack = self.fft_engine.stack(); let stack = self.fft_buffers.stack();
extract_bits_from_lwe_ciphertext( extract_bits_from_lwe_ciphertext(
lwe_in, lwe_in,
@@ -220,7 +220,7 @@ impl ShortintEngine {
&mut self, &mut self,
wopbs_key: &WopbsKey, wopbs_key: &WopbsKey,
extracted_bits: &LweCiphertextListView<'_, u64>, extracted_bits: &LweCiphertextListView<'_, u64>,
lut: &PlaintextVector64, lut: &PlaintextListView<'_, u64>,
count: LweCiphertextCount, count: LweCiphertextCount,
) -> EngineResult<LweCiphertextList<u64>> { ) -> EngineResult<LweCiphertextList<u64>> {
let sks = &wopbs_key.wopbs_server_key; let sks = &wopbs_key.wopbs_server_key;
@@ -232,7 +232,7 @@ impl ShortintEngine {
let fft = Fft::new(fourier_bsk.polynomial_size()); let fft = Fft::new(fourier_bsk.polynomial_size());
let fft = fft.as_view(); let fft = fft.as_view();
self.fft_engine.resize( self.fft_buffers.resize(
circuit_bootstrap_boolean_vertical_packing_lwe_ciphertext_list_scracth::<u64>( circuit_bootstrap_boolean_vertical_packing_lwe_ciphertext_list_scracth::<u64>(
extracted_bits.lwe_ciphertext_count(), extracted_bits.lwe_ciphertext_count(),
output_cbs_vp_ct.lwe_ciphertext_count(), output_cbs_vp_ct.lwe_ciphertext_count(),
@@ -248,12 +248,9 @@ impl ShortintEngine {
.unaligned_bytes_required(), .unaligned_bytes_required(),
); );
let lut = PolynomialListView::from_container( let lut = PolynomialListView::from_container(lut.as_ref(), fourier_bsk.polynomial_size());
lut.0.tensor.as_container().as_slice(),
fourier_bsk.polynomial_size(),
);
let stack = self.fft_engine.stack(); let stack = self.fft_buffers.stack();
circuit_bootstrap_boolean_vertical_packing_lwe_ciphertext_list( circuit_bootstrap_boolean_vertical_packing_lwe_ciphertext_list(
extracted_bits, extracted_bits,
@@ -281,7 +278,7 @@ impl ShortintEngine {
let extracted_bits = let extracted_bits =
self.extract_bits(delta_log, &ct_in.ct, wopbs_key, nb_bit_to_extract)?; 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( let ciphertext_list = self.circuit_bootstrap_with_bits(
wopbs_key, wopbs_key,
@@ -373,7 +370,7 @@ impl ShortintEngine {
// 2. PBS to remove the noise added by the previous KS // 2. PBS to remove the noise added by the previous KS
// //
let acc = self.generate_accumulator(&wopbs_key.pbs_server_key, |x| x)?; 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 // Compute a key switch
keyswitch_lwe_ciphertext( keyswitch_lwe_ciphertext(
&wopbs_key.pbs_server_key.key_switching_key, &wopbs_key.pbs_server_key.key_switching_key,
@@ -381,20 +378,34 @@ impl ShortintEngine {
&mut buffers.buffer_lwe_after_ks, &mut buffers.buffer_lwe_after_ks,
); );
let out_lwe_size = wopbs_key let fourier_bsk = &wopbs_key.pbs_server_key.bootstrapping_key;
.pbs_server_key
.bootstrapping_key let out_lwe_size = fourier_bsk.output_lwe_dimension().to_lwe_size();
.output_lwe_dimension() let mut ct_out = LweCiphertext::new(0, out_lwe_size);
.to_lwe_size();
let mut ct_out = LweCiphertext::from_container(vec![0; out_lwe_size.0]); 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 // Compute a bootstrap
fftw_engine.discard_bootstrap_lwe_ciphertext( programmable_bootstrap_lwe_ciphertext(
&mut ct_out.as_old_ct_mut_view(), &buffers.buffer_lwe_after_ks,
&buffers.buffer_lwe_after_ks.as_old_ct_view(), &mut ct_out,
&GlweCiphertextView64(acc.0.as_view()), &acc,
&wopbs_key.pbs_server_key.bootstrapping_key.clone().into(), fourier_bsk,
)?; fft,
stack,
);
Ok(Ciphertext { Ok(Ciphertext {
ct: ct_out, ct: ct_out,
degree: ct_in.degree, degree: ct_in.degree,
@@ -477,28 +488,22 @@ impl ShortintEngine {
&mut self, &mut self,
wopbs_key: &WopbsKey, wopbs_key: &WopbsKey,
vec_lut: Vec<Vec<u64>>, vec_lut: Vec<Vec<u64>>,
extracted_bits_blocks: Vec<LweCiphertextVector64>, extracted_bits_blocks: Vec<LweCiphertextList<u64>>,
) -> Vec<LweCiphertext64> { ) -> Vec<LweCiphertext<u64>> {
let lwe_size = extracted_bits_blocks[0].lwe_dimension().to_lwe_size(); let lwe_size = extracted_bits_blocks[0].lwe_size();
let mut all_datas = vec![]; let mut all_datas = vec![];
for lwe_vec in extracted_bits_blocks.into_iter() { for lwe_vec in extracted_bits_blocks.iter() {
let data = self let data = lwe_vec.as_ref();
.engine
.consume_retrieve_lwe_ciphertext_vector(lwe_vec)
.unwrap();
all_datas.extend_from_slice(data.as_slice()); all_datas.extend_from_slice(data);
} }
let flatenned_extracted_bits_view = let flatenned_extracted_bits_view =
LweCiphertextListView::from_container(all_datas.as_slice(), lwe_size); LweCiphertextListView::from_container(all_datas.as_slice(), lwe_size);
let flattened_lut: Vec<u64> = vec_lut.iter().flatten().copied().collect(); let flattened_lut: Vec<u64> = vec_lut.iter().flatten().copied().collect();
let plaintext_lut = self let plaintext_lut = PlaintextListView::from_container(&flattened_lut);
.engine
.create_plaintext_vector_from(&flattened_lut)
.unwrap();
let output_list = self let output_list = self
.circuit_bootstrap_with_bits( .circuit_bootstrap_with_bits(
wopbs_key, wopbs_key,
@@ -511,16 +516,11 @@ impl ShortintEngine {
assert_eq!(output_list.lwe_ciphertext_count().0, vec_lut.len()); assert_eq!(output_list.lwe_ciphertext_count().0, vec_lut.len());
let output_container = output_list.into_container(); 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()) .chunks_exact(output_container.len() / vec_lut.len())
.map(|s| { .map(|s| LweCiphertext::from_container(s.to_vec()))
let lwe = self.engine.create_lwe_ciphertext_from(s.to_vec())?;
Ok(lwe)
})
.collect(); .collect();
let lwes = lwes.unwrap();
assert_eq!(lwes.len(), vec_lut.len()); assert_eq!(lwes.len(), vec_lut.len());
lwes lwes
} }

View File

@@ -1,4 +1,5 @@
//! Module with the definition of the PublicKey. //! Module with the definition of the PublicKey.
use crate::core_crypto::entities::*;
use crate::core_crypto::prelude::*; use crate::core_crypto::prelude::*;
use crate::shortint::ciphertext::Ciphertext; use crate::shortint::ciphertext::Ciphertext;
use crate::shortint::engine::ShortintEngine; use crate::shortint::engine::ShortintEngine;
@@ -10,7 +11,7 @@ use std::fmt::Debug;
/// A structure containing a public key. /// A structure containing a public key.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct PublicKey { pub struct PublicKey {
pub(crate) lwe_public_key: LwePublicKey64, pub(crate) lwe_public_key: LwePublicKey<u64>,
pub parameters: Parameters, pub parameters: Parameters,
} }
@@ -213,8 +214,10 @@ impl Serialize for PublicKey {
{ {
let mut ser_eng = DefaultSerializationEngine::new(()).map_err(serde::ser::Error::custom)?; 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 let lwe_public_key = ser_eng
.serialize(&self.lwe_public_key) .serialize(&tmp_public_key)
.map_err(serde::ser::Error::custom)?; .map_err(serde::ser::Error::custom)?;
SerializablePublicKey { SerializablePublicKey {
@@ -234,10 +237,12 @@ impl<'de> Deserialize<'de> for PublicKey {
SerializablePublicKey::deserialize(deserializer).map_err(serde::de::Error::custom)?; SerializablePublicKey::deserialize(deserializer).map_err(serde::de::Error::custom)?;
let mut de_eng = DefaultSerializationEngine::new(()).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 { Ok(Self {
lwe_public_key: de_eng lwe_public_key: tmp_public_key.into(),
.deserialize(thing.lwe_public_key.as_slice())
.map_err(serde::de::Error::custom)?,
parameters: thing.parameters, parameters: thing.parameters,
}) })
} }

View File

@@ -118,7 +118,7 @@ impl ServerKey {
/// // 3^2 mod 4 = 1 /// // 3^2 mod 4 = 1
/// assert_eq!(dec, f(msg)); /// 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 where
F: Fn(u64) -> u64, F: Fn(u64) -> u64,
{ {
@@ -152,7 +152,7 @@ impl ServerKey {
/// // 3^2 mod 4 = 1 /// // 3^2 mod 4 = 1
/// assert_eq!(dec, f(msg, 0)); /// 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 where
F: Fn(u64, u64) -> u64, F: Fn(u64, u64) -> u64,
{ {
@@ -245,7 +245,7 @@ impl ServerKey {
&self, &self,
ct_left: &Ciphertext, ct_left: &Ciphertext,
ct_right: &Ciphertext, ct_right: &Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) -> Ciphertext { ) -> Ciphertext {
ShortintEngine::with_thread_local_mut(|engine| { ShortintEngine::with_thread_local_mut(|engine| {
engine engine
@@ -258,7 +258,7 @@ impl ServerKey {
&self, &self,
ct_left: &mut Ciphertext, ct_left: &mut Ciphertext,
ct_right: &Ciphertext, ct_right: &Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) { ) {
ShortintEngine::with_thread_local_mut(|engine| { ShortintEngine::with_thread_local_mut(|engine| {
engine engine
@@ -293,7 +293,7 @@ impl ServerKey {
pub fn keyswitch_programmable_bootstrap( pub fn keyswitch_programmable_bootstrap(
&self, &self,
ct_in: &Ciphertext, ct_in: &Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) -> Ciphertext { ) -> Ciphertext {
ShortintEngine::with_thread_local_mut(|engine| { ShortintEngine::with_thread_local_mut(|engine| {
engine engine
@@ -305,7 +305,7 @@ impl ServerKey {
pub fn keyswitch_programmable_bootstrap_assign( pub fn keyswitch_programmable_bootstrap_assign(
&self, &self,
ct_in: &mut Ciphertext, ct_in: &mut Ciphertext,
acc: &GlweCiphertext64, acc: &GlweCiphertext<u64>,
) { ) {
ShortintEngine::with_thread_local_mut(|engine| { ShortintEngine::with_thread_local_mut(|engine| {
engine engine

View File

@@ -347,8 +347,8 @@ impl WopbsKey {
pub fn circuit_bootstrapping_vertical_packing( pub fn circuit_bootstrapping_vertical_packing(
&self, &self,
vec_lut: Vec<Vec<u64>>, vec_lut: Vec<Vec<u64>>,
extracted_bits_blocks: Vec<LweCiphertextVector64>, extracted_bits_blocks: Vec<LweCiphertextList<u64>>,
) -> Vec<LweCiphertext64> { ) -> Vec<LweCiphertext<u64>> {
ShortintEngine::with_thread_local_mut(|engine| { ShortintEngine::with_thread_local_mut(|engine| {
engine.circuit_bootstrapping_vertical_packing(self, vec_lut, extracted_bits_blocks) engine.circuit_bootstrapping_vertical_packing(self, vec_lut, extracted_bits_blocks)
}) })