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 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]

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();
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 {

View File

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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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(),

View File

@@ -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>(

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
// 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());
}
}

View File

@@ -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(

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_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::*;

View File

@@ -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>(

View File

@@ -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,
{

View File

@@ -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();

View File

@@ -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,

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_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::*;

View File

@@ -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>>;

View File

@@ -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));

View File

@@ -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;

View File

@@ -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 {

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

View File

@@ -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,
),

View File

@@ -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;

View File

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

View File

@@ -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,
})
}

View File

@@ -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

View File

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