Compare commits

...

2 Commits

Author SHA1 Message Date
Carl-Zama
ccc4410515 fix custom modulus keyswitch and error generation 2023-04-19 00:30:48 +01:00
Arthur Meyre
31348cb1f8 refactor(tfhe): wip dynamic modulus for LWE ciphertexts 2023-03-24 17:34:40 +01:00
85 changed files with 4838 additions and 502 deletions

View File

@@ -36,16 +36,17 @@ criterion_group!(
criterion_main!(pbs_group);
struct BenchmarkPbsParameters {
struct BenchmarkPbsParameters<Scalar: UnsignedInteger> {
input_lwe_dimension: LweDimension,
lwe_modular_std_dev: StandardDev,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
glwe_dimension: GlweDimension,
polynomial_size: PolynomialSize,
ciphertext_modulus: CoreCiphertextModulus<Scalar>,
}
impl From<BooleanParameters> for BenchmarkPbsParameters {
impl From<BooleanParameters> for BenchmarkPbsParameters<u32> {
fn from(params: BooleanParameters) -> Self {
BenchmarkPbsParameters {
input_lwe_dimension: params.lwe_dimension,
@@ -54,11 +55,12 @@ impl From<BooleanParameters> for BenchmarkPbsParameters {
decomp_level_count: params.pbs_level,
glwe_dimension: params.glwe_dimension,
polynomial_size: params.polynomial_size,
ciphertext_modulus: CoreCiphertextModulus::<u32>::new_native(),
}
}
}
impl From<Parameters> for BenchmarkPbsParameters {
impl From<Parameters> for BenchmarkPbsParameters<u64> {
fn from(params: Parameters) -> Self {
BenchmarkPbsParameters {
input_lwe_dimension: params.lwe_dimension,
@@ -67,26 +69,41 @@ impl From<Parameters> for BenchmarkPbsParameters {
decomp_level_count: params.pbs_level,
glwe_dimension: params.glwe_dimension,
polynomial_size: params.polynomial_size,
ciphertext_modulus: params.ciphertext_modulus,
}
}
}
fn benchmark_parameters<Scalar: Numeric>() -> Vec<(String, BenchmarkPbsParameters)> {
fn benchmark_parameters<Scalar: UnsignedInteger>() -> Vec<(String, BenchmarkPbsParameters<Scalar>)>
{
if Scalar::BITS == 64 {
SHORTINT_BENCH_PARAMS
.iter()
.map(|params| {
(
format!("shortint_{}", params.name().to_lowercase()),
params.to_owned().into(),
)
})
.collect()
unsafe {
std::mem::transmute(
SHORTINT_BENCH_PARAMS
.iter()
.map(|params| {
(
format!("shortint_{}", params.name().to_lowercase()),
BenchmarkPbsParameters::<u64>::from(params.to_owned()),
)
})
.collect::<Vec<_>>(),
)
}
} else if Scalar::BITS == 32 {
BOOLEAN_BENCH_PARAMS
.iter()
.map(|(name, params)| (name.to_string(), params.to_owned().into()))
.collect()
unsafe {
std::mem::transmute(
BOOLEAN_BENCH_PARAMS
.iter()
.map(|(name, params)| {
(
name.to_string(),
BenchmarkPbsParameters::<u32>::from(params.to_owned()),
)
})
.collect::<Vec<_>>(),
)
}
} else {
vec![]
}
@@ -129,6 +146,7 @@ fn mem_optimized_pbs<Scalar: UnsignedTorus + CastInto<usize>>(c: &mut Criterion)
&input_lwe_secret_key,
Plaintext(Scalar::ZERO),
params.lwe_modular_std_dev,
params.ciphertext_modulus,
&mut encryption_generator,
);
@@ -142,6 +160,7 @@ fn mem_optimized_pbs<Scalar: UnsignedTorus + CastInto<usize>>(c: &mut Criterion)
let mut out_pbs_ct = LweCiphertext::new(
Scalar::ZERO,
output_lwe_secret_key.lwe_dimension().to_lwe_size(),
params.ciphertext_modulus,
);
let mut buffers = ComputationBuffers::new();

View File

@@ -109,7 +109,7 @@ void test_custom_keygen(void) {
ShortintParameters *params = NULL;
int params_ok = shortint_create_parameters(10, 1, 1024, 10e-100, 10e-100, 2, 3, 2, 3, 2, 3,
10e-100, 2, 3, 2, 2, &params);
10e-100, 2, 3, 2, 2, SHORTINT_NATIVE_MODULUS, &params);
assert(params_ok == 0);
int gen_keys_ok = shortint_gen_keys_with_parameters(params, &cks, &sks);

View File

@@ -18,6 +18,7 @@ use tfhe::core_crypto::prelude::*;
// Define parameters for LweCiphertext creation
let lwe_dimension = LweDimension(742);
let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
let ciphertext_modulus = CiphertextModulus::new_native();
// Create the PRNG
let mut seeder = new_seeder();
@@ -36,7 +37,7 @@ let msg = 3u64;
let plaintext = Plaintext(msg << 60);
// Create a new LweCiphertext
let mut lwe = LweCiphertext::new(0u64, lwe_dimension.to_lwe_size());
let mut lwe = LweCiphertext::new(0u64, lwe_dimension.to_lwe_size(), ciphertext_modulus);
encrypt_lwe_ciphertext(
&lwe_secret_key,

View File

@@ -53,6 +53,7 @@ pub fn main() {
let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
let pbs_base_log = DecompositionBaseLog(23);
let pbs_level = DecompositionLevelCount(1);
let ciphertext_modulus = CiphertextModulus::new_native();
// Request the best seeder possible, starting with hardware entropy sources and falling back to
// /dev/random on Unix systems if enabled via cargo features
@@ -124,6 +125,7 @@ pub fn main() {
&small_lwe_sk,
plaintext,
lwe_modular_std_dev,
ciphertext_modulus,
&mut encryption_generator,
);
@@ -217,8 +219,11 @@ pub fn main() {
);
// Allocate the LweCiphertext to store the result of the PBS
let mut pbs_multiplication_ct =
LweCiphertext::new(0u64, big_lwe_sk.lwe_dimension().to_lwe_size());
let mut pbs_multiplication_ct = LweCiphertext::new(
0u64,
big_lwe_sk.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
println!("Computing PBS...");
programmable_bootstrap_lwe_ciphertext(
&lwe_ciphertext_in,

View File

@@ -70,6 +70,7 @@ fn main() {
DecompositionBaseLog(0),
MessageModulus(4),
CarryModulus(1),
CiphertextModulus::new_native(),
)
};
}

View File

@@ -4,6 +4,7 @@ use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::computation_buffers::ComputationBuffers;
use crate::core_crypto::commons::generators::{DeterministicSeeder, EncryptionRandomGenerator};
use crate::core_crypto::commons::math::random::{ActivatedRandomGenerator, Seeder};
use crate::core_crypto::commons::parameters::CiphertextModulus;
use crate::core_crypto::entities::*;
use crate::core_crypto::fft_impl::math::fft::Fft;
use serde::{Deserialize, Serialize};
@@ -62,7 +63,8 @@ impl Memory {
server_key.bootstrapping_key.polynomial_size(),
);
let lwe = LweCiphertextMutView::from_container(lwe_elements);
let lwe =
LweCiphertextMutView::from_container(lwe_elements, CiphertextModulus::new_native());
(accumulator, lwe)
}
@@ -192,6 +194,7 @@ impl Bootstrapper {
cks.parameters.ks_base_log,
cks.parameters.ks_level,
cks.parameters.lwe_modular_std_dev,
CiphertextModulus::new_native(),
&mut self.encryption_generator,
);
@@ -234,6 +237,7 @@ impl Bootstrapper {
cks.parameters.ks_base_log,
cks.parameters.ks_level,
cks.parameters.lwe_modular_std_dev,
CiphertextModulus::new_native(),
&mut self.seeder,
);
@@ -277,6 +281,7 @@ impl Bootstrapper {
Ok(LweCiphertext::from_container(
buffer_after_pbs.as_ref().to_owned(),
input.ciphertext_modulus(),
))
}
@@ -292,6 +297,7 @@ impl Bootstrapper {
.bootstrapping_key
.input_lwe_dimension()
.to_lwe_size(),
input.ciphertext_modulus(),
);
keyswitch_lwe_ciphertext(&server_key.key_switching_key, input, &mut output);

View File

@@ -122,6 +122,7 @@ impl BooleanEngine {
&client_key.lwe_secret_key,
zero_encryption_count,
client_key.parameters.lwe_modular_std_dev,
CiphertextModulus::new_native(),
&mut self.encryption_generator,
);
@@ -130,6 +131,7 @@ impl BooleanEngine {
&client_key.lwe_secret_key,
zero_encryption_count,
client_key.parameters.lwe_modular_std_dev,
CiphertextModulus::new_native(),
&mut self.encryption_generator,
);
@@ -156,6 +158,7 @@ impl BooleanEngine {
&cks.lwe_secret_key,
plain,
cks.parameters.lwe_modular_std_dev,
CiphertextModulus::new_native(),
&mut self.encryption_generator,
);
@@ -175,6 +178,7 @@ impl BooleanEngine {
&cks.lwe_secret_key,
plain,
cks.parameters.lwe_modular_std_dev,
CiphertextModulus::new_native(),
&mut self.bootstrapper.seeder,
);
@@ -189,7 +193,11 @@ impl BooleanEngine {
Plaintext(PLAINTEXT_FALSE)
};
let mut output = LweCiphertext::new(0u32, pks.parameters.lwe_dimension.to_lwe_size());
let mut output = LweCiphertext::new(
0u32,
pks.parameters.lwe_dimension.to_lwe_size(),
CiphertextModulus::new_native(),
);
// encryption
encrypt_lwe_ciphertext_with_public_key(
@@ -292,6 +300,7 @@ impl BooleanEngine {
.input_lwe_dimension()
.to_lwe_size(),
plain,
CiphertextModulus::new_native(),
)
}
}
@@ -338,7 +347,7 @@ impl BooleanEngine {
};
}
// convert inputs into LweCiphertext32
// convert inputs into LweCiphertextOwned<u32>
let ct_then_ct = self.convert_into_lwe_ciphertext_32(ct_then, server_key);
let ct_else_ct = self.convert_into_lwe_ciphertext_32(ct_else, server_key);
@@ -348,6 +357,7 @@ impl BooleanEngine {
.bootstrapping_key
.input_lwe_dimension()
.to_lwe_size(),
ct_condition_ct.ciphertext_modulus(),
);
let buffer_lwe_before_pbs = &mut buffer_lwe_before_pbs_o;
@@ -413,6 +423,7 @@ impl BinaryGatesEngine<&Ciphertext, &Ciphertext, ServerKey> for BooleanEngine {
.bootstrapping_key
.input_lwe_dimension()
.to_lwe_size(),
ct_left_ct.ciphertext_modulus(),
);
let bootstrapper = &mut self.bootstrapper;
@@ -455,6 +466,7 @@ impl BinaryGatesEngine<&Ciphertext, &Ciphertext, ServerKey> for BooleanEngine {
.bootstrapping_key
.input_lwe_dimension()
.to_lwe_size(),
ct_left_ct.ciphertext_modulus(),
);
let bootstrapper = &mut self.bootstrapper;
@@ -497,6 +509,7 @@ impl BinaryGatesEngine<&Ciphertext, &Ciphertext, ServerKey> for BooleanEngine {
.bootstrapping_key
.input_lwe_dimension()
.to_lwe_size(),
ct_left_ct.ciphertext_modulus(),
);
let bootstrapper = &mut self.bootstrapper;
@@ -540,6 +553,7 @@ impl BinaryGatesEngine<&Ciphertext, &Ciphertext, ServerKey> for BooleanEngine {
.bootstrapping_key
.input_lwe_dimension()
.to_lwe_size(),
ct_left_ct.ciphertext_modulus(),
);
let bootstrapper = &mut self.bootstrapper;
@@ -581,6 +595,7 @@ impl BinaryGatesEngine<&Ciphertext, &Ciphertext, ServerKey> for BooleanEngine {
.bootstrapping_key
.input_lwe_dimension()
.to_lwe_size(),
ct_left_ct.ciphertext_modulus(),
);
let bootstrapper = &mut self.bootstrapper;
@@ -625,6 +640,7 @@ impl BinaryGatesEngine<&Ciphertext, &Ciphertext, ServerKey> for BooleanEngine {
.bootstrapping_key
.input_lwe_dimension()
.to_lwe_size(),
ct_left_ct.ciphertext_modulus(),
);
let bootstrapper = &mut self.bootstrapper;

View File

@@ -7,6 +7,8 @@ use std::os::raw::c_int;
use crate::shortint;
pub const SHORTINT_NATIVE_MODULUS: u64 = 0;
pub struct ShortintParameters(pub(in crate::c_api) shortint::parameters::Parameters);
#[no_mangle]
@@ -111,6 +113,7 @@ pub unsafe extern "C" fn shortint_create_parameters(
cbs_base_log: usize,
message_modulus: usize,
carry_modulus: usize,
ciphertext_modulus: u64,
result: *mut *mut ShortintParameters,
) -> c_int {
catch_panic(|| {
@@ -138,6 +141,10 @@ pub unsafe extern "C" fn shortint_create_parameters(
cbs_base_log: DecompositionBaseLog(cbs_base_log),
message_modulus: crate::shortint::parameters::MessageModulus(message_modulus),
carry_modulus: crate::shortint::parameters::CarryModulus(carry_modulus),
ciphertext_modulus: crate::shortint::parameters::CiphertextModulus::try_new(
ciphertext_modulus as u128,
)
.unwrap(),
}));
*result = Box::into_raw(heap_allocated_parameters);

View File

@@ -64,8 +64,11 @@ use crate::core_crypto::entities::*;
/// // Now we get the equivalent LweSecretKey from the GlweSecretKey
/// let equivalent_lwe_sk = glwe_secret_key.clone().into_lwe_secret_key();
///
/// let mut extracted_sample =
/// LweCiphertext::new(0u64, equivalent_lwe_sk.lwe_dimension().to_lwe_size());
/// let mut extracted_sample = LweCiphertext::new(
/// 0u64,
/// equivalent_lwe_sk.lwe_dimension().to_lwe_size(),
/// CiphertextModulus::new_native(),
/// );
///
/// // Here we chose to extract sample at index 42 (corresponding to the MonomialDegree(42))
/// extract_lwe_sample_from_glwe_ciphertext(&glwe, &mut extracted_sample, MonomialDegree(42));
@@ -91,6 +94,10 @@ pub fn extract_lwe_sample_from_glwe_ciphertext<Scalar, InputCont, OutputCont>(
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
assert!(
output_lwe.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
assert!(
input_glwe.glwe_size().to_glwe_dimension().0 * input_glwe.polynomial_size().0
== output_lwe.lwe_size().to_lwe_dimension().0,
@@ -105,7 +112,7 @@ pub fn extract_lwe_sample_from_glwe_ciphertext<Scalar, InputCont, OutputCont>(
let (glwe_mask, glwe_body) = input_glwe.get_mask_and_body();
// We copy the body
*lwe_body.0 = glwe_body.as_ref()[nth.0];
*lwe_body.data = glwe_body.as_ref()[nth.0];
// We copy the mask (each polynomial is in the wrong order)
lwe_mask.as_mut().copy_from_slice(glwe_mask.as_ref());
@@ -122,7 +129,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
slice_wrapping_opposite_assign(&mut lwe_mask_poly[0..opposite_count]);
slice_wrapping_opposite_assign_native_mod(&mut lwe_mask_poly[0..opposite_count]);
// We rotate the polynomial properly
lwe_mask_poly.rotate_left(opposite_count);
}

View File

@@ -174,6 +174,60 @@ where
/// Parallel variant of [`generate_lwe_bootstrap_key`], it is recommended to use this function for
/// better key generation times as LWE bootstrapping keys can be quite large.
///
/// # Example
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for LweBootstrapKey creation
/// let input_lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let output_lwe_dimension = LweDimension(2048);
/// let decomp_base_log = DecompositionBaseLog(3);
/// let decomp_level_count = DecompositionLevelCount(5);
/// let glwe_dimension = GlweDimension(1);
/// let polynomial_size = PolynomialSize(1024);
/// let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut encryption_generator =
/// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// // Create the LweSecretKey
/// let input_lwe_secret_key =
/// allocate_and_generate_new_binary_lwe_secret_key(input_lwe_dimension, &mut secret_generator);
/// let output_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key(
/// glwe_dimension,
/// polynomial_size,
/// &mut secret_generator,
/// );
///
/// let mut bsk = LweBootstrapKey::new(
/// 0u64,
/// glwe_dimension.to_glwe_size(),
/// polynomial_size,
/// decomp_base_log,
/// decomp_level_count,
/// input_lwe_dimension,
/// );
///
/// par_generate_lwe_bootstrap_key(
/// &input_lwe_secret_key,
/// &output_glwe_secret_key,
/// &mut bsk,
/// glwe_modular_std_dev,
/// &mut encryption_generator,
/// );
///
/// assert!(bsk.as_ref().iter().all(|&x| x == 0) == false);
/// ```
pub fn par_generate_lwe_bootstrap_key<Scalar, InputKeyCont, OutputKeyCont, OutputCont, Gen>(
input_lwe_secret_key: &LweSecretKey<InputKeyCont>,
output_glwe_secret_key: &GlweSecretKey<OutputKeyCont>,

View File

@@ -16,7 +16,7 @@ use rayon::prelude::*;
pub fn fill_lwe_mask_and_body_for_encryption<Scalar, KeyCont, OutputCont, Gen>(
lwe_secret_key: &LweSecretKey<KeyCont>,
output_mask: &mut LweMask<OutputCont>,
output_body: LweBody<&mut Scalar>,
output_body: LweBodyRefMut<Scalar>,
encoded: Plaintext<Scalar>,
noise_parameters: impl DispersionParameter,
generator: &mut EncryptionRandomGenerator<Gen>,
@@ -26,18 +26,77 @@ pub fn fill_lwe_mask_and_body_for_encryption<Scalar, KeyCont, OutputCont, Gen>(
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert_eq!(
output_mask.ciphertext_modulus(),
output_body.ciphertext_modulus(),
"Mismatched moduli between mask ({:?}) and body ({:?})",
output_mask.ciphertext_modulus(),
output_body.ciphertext_modulus()
);
let ciphertext_modulus = output_body.ciphertext_modulus();
// First fill the output mask and output body with values of the output Scalar type
generator.fill_slice_with_random_mask(output_mask.as_mut());
// generate an error from the normal distribution described by std_dev
*output_body.0 = generator.random_noise(noise_parameters);
*output_body.data = generator.random_noise_custom_mod(noise_parameters, ciphertext_modulus);
// compute the multisum between the secret key and the mask
*output_body.0 = (*output_body.0).wrapping_add(slice_wrapping_dot_product(
output_mask.as_ref(),
lwe_secret_key.as_ref(),
));
// If the modulus is compatible with the native one then we just apply wrapping computation and
// enjoy the perf gain
if ciphertext_modulus.is_compatible_with_native_modulus() {
// compute the multisum between the secret key and the mask
*output_body.data = (*output_body.data).wrapping_add(slice_wrapping_dot_product(
output_mask.as_ref(),
lwe_secret_key.as_ref(),
));
*output_body.0 = (*output_body.0).wrapping_add(encoded.0);
*output_body.data = (*output_body.data).wrapping_add(encoded.0);
if !ciphertext_modulus.is_native_modulus() {
let modulus = Scalar::cast_from(ciphertext_modulus.get());
slice_wrapping_rem_assign(output_mask.as_mut(), modulus);
*output_body.data = (*output_body.data).wrapping_rem(modulus);
}
} else {
// If the modulus is not the native one, then as a fallback we use a bigger data type to
// compute without overflows and apply the modulus later
let mut ct_128 = LweCiphertext::new(
0u128,
lwe_secret_key.lwe_dimension().to_lwe_size(),
CiphertextModulus::new_native(),
);
let mut key_128 = LweSecretKey::new_empty_key(0u128, lwe_secret_key.lwe_dimension());
let ciphertext_modulus = ciphertext_modulus.get();
copy_from_convert(&mut key_128, &lwe_secret_key);
let (mut mask_128, body_128) = ct_128.get_mut_mask_and_body();
copy_from_convert(&mut mask_128, &output_mask);
slice_wrapping_rem_assign(mask_128.as_mut(), ciphertext_modulus);
*body_128.data = (*output_body.data).cast_into();
// compute the multisum between the secret key and the mask
*body_128.data = (*body_128.data)
.wrapping_add(slice_wrapping_dot_product_custom_modulus(
mask_128.as_ref(),
key_128.as_ref(),
ciphertext_modulus,
))
.wrapping_rem(ciphertext_modulus);
*body_128.data = (*body_128.data)
.wrapping_add(encoded.0.cast_into())
.wrapping_rem(ciphertext_modulus);
copy_from_convert(output_mask, &mask_128);
*output_body.data = (*body_128.data).cast_into();
}
}
/// Encrypt an input plaintext in an output [`LWE ciphertext`](`LweCiphertext`).
@@ -73,7 +132,11 @@ pub fn fill_lwe_mask_and_body_for_encryption<Scalar, KeyCont, OutputCont, Gen>(
/// let plaintext = Plaintext(msg << 60);
///
/// // Create a new LweCiphertext
/// let mut lwe = LweCiphertext::new(0u64, lwe_dimension.to_lwe_size());
/// let mut lwe = LweCiphertext::new(
/// 0u64,
/// lwe_dimension.to_lwe_size(),
/// CiphertextModulus::new_native(),
/// );
///
/// encrypt_lwe_ciphertext(
/// &lwe_secret_key,
@@ -166,6 +229,7 @@ pub fn encrypt_lwe_ciphertext<Scalar, KeyCont, OutputCont, Gen>(
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// CiphertextModulus::new_native(),
/// &mut encryption_generator,
/// );
///
@@ -187,6 +251,7 @@ pub fn allocate_and_encrypt_new_lwe_ciphertext<Scalar, KeyCont, Gen>(
lwe_secret_key: &LweSecretKey<KeyCont>,
encoded: Plaintext<Scalar>,
noise_parameters: impl DispersionParameter,
ciphertext_modulus: CiphertextModulus<Scalar>,
generator: &mut EncryptionRandomGenerator<Gen>,
) -> LweCiphertextOwned<Scalar>
where
@@ -194,8 +259,11 @@ where
KeyCont: Container<Element = Scalar>,
Gen: ByteRandomGenerator,
{
let mut new_ct =
LweCiphertextOwned::new(Scalar::ZERO, lwe_secret_key.lwe_dimension().to_lwe_size());
let mut new_ct = LweCiphertextOwned::new(
Scalar::ZERO,
lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
encrypt_lwe_ciphertext(
lwe_secret_key,
@@ -238,13 +306,17 @@ where
/// let plaintext = Plaintext(msg << 60);
///
/// // Create a new LweCiphertext
/// let mut lwe = LweCiphertext::new(0u64, lwe_dimension.to_lwe_size());
/// let mut lwe = LweCiphertext::new(
/// 0u64,
/// lwe_dimension.to_lwe_size(),
/// CiphertextModulus::new_native(),
/// );
///
/// trivially_encrypt_lwe_ciphertext(&mut lwe, plaintext);
///
/// // Here we show the content of the trivial encryption is actually the input data in clear and
/// // that the mask is full of 0s
/// assert_eq!(*lwe.get_body().0, plaintext.0);
/// assert_eq!(*lwe.get_body().data, plaintext.0);
/// lwe.get_mask()
/// .as_ref()
/// .iter()
@@ -257,7 +329,7 @@ where
/// let decrypted_plaintext = decrypt_lwe_ciphertext(&lwe_secret_key, &lwe);
///
/// // Again the trivial encryption encrypts _nothing_
/// assert_eq!(decrypted_plaintext.0, *lwe.get_body().0);
/// assert_eq!(decrypted_plaintext.0, *lwe.get_body().data);
/// ```
pub fn trivially_encrypt_lwe_ciphertext<Scalar, OutputCont>(
output: &mut LweCiphertext<OutputCont>,
@@ -272,7 +344,16 @@ pub fn trivially_encrypt_lwe_ciphertext<Scalar, OutputCont>(
.iter_mut()
.for_each(|elt| *elt = Scalar::ZERO);
*output.get_mut_body().0 = encoded.0
let output_modulus = output.ciphertext_modulus();
let output_body = output.get_mut_body();
*output_body.data = encoded.0;
// output_modulus < native modulus always, so we can cast the u128 modulus to the smaller type
// and compute in the smaller type
if !output_modulus.is_native_modulus() {
*output_body.data = (*output_body.data).wrapping_rem(output_modulus.get().cast_into());
}
}
/// A trivial encryption uses a zero mask and no noise.
@@ -294,6 +375,7 @@ pub fn trivially_encrypt_lwe_ciphertext<Scalar, OutputCont>(
/// // computations
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -306,12 +388,15 @@ pub fn trivially_encrypt_lwe_ciphertext<Scalar, OutputCont>(
/// let plaintext = Plaintext(msg << 60);
///
/// // Create a new LweCiphertext
/// let mut lwe =
/// allocate_and_trivially_encrypt_new_lwe_ciphertext(lwe_dimension.to_lwe_size(), plaintext);
/// let mut lwe = allocate_and_trivially_encrypt_new_lwe_ciphertext(
/// lwe_dimension.to_lwe_size(),
/// plaintext,
/// ciphertext_modulus,
/// );
///
/// // Here we show the content of the trivial encryption is actually the input data in clear and
/// // that the mask is full of 0s
/// assert_eq!(*lwe.get_body().0, plaintext.0);
/// assert_eq!(*lwe.get_body().data, plaintext.0);
/// lwe.get_mask()
/// .as_ref()
/// .iter()
@@ -324,18 +409,30 @@ pub fn trivially_encrypt_lwe_ciphertext<Scalar, OutputCont>(
/// let decrypted_plaintext = decrypt_lwe_ciphertext(&lwe_secret_key, &lwe);
///
/// // Again the trivial encryption encrypts _nothing_
/// assert_eq!(decrypted_plaintext.0, *lwe.get_body().0);
/// assert_eq!(decrypted_plaintext.0, *lwe.get_body().data);
/// ```
pub fn allocate_and_trivially_encrypt_new_lwe_ciphertext<Scalar>(
lwe_size: LweSize,
encoded: Plaintext<Scalar>,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> LweCiphertextOwned<Scalar>
where
Scalar: UnsignedTorus,
{
let mut new_ct = LweCiphertextOwned::new(Scalar::ZERO, lwe_size);
let mut new_ct = LweCiphertextOwned::new(Scalar::ZERO, lwe_size, ciphertext_modulus);
*new_ct.get_mut_body().0 = encoded.0;
*new_ct.get_mut_body().data = encoded.0;
let output_modulus = new_ct.ciphertext_modulus();
let output_body = new_ct.get_mut_body();
*output_body.data = encoded.0;
// output_modulus < native modulus always, so we can cast the u128 modulus to the smaller type
// and compute in the smaller type
if !output_modulus.is_native_modulus() {
*output_body.data = (*output_body.data).wrapping_rem(output_modulus.get().cast_into());
}
new_ct
}
@@ -365,12 +462,49 @@ where
lwe_secret_key.lwe_dimension()
);
let (mask, body) = lwe_ciphertext.get_mask_and_body();
let ciphertext_modulus = lwe_ciphertext.ciphertext_modulus();
Plaintext(body.0.wrapping_sub(slice_wrapping_dot_product(
mask.as_ref(),
lwe_secret_key.as_ref(),
)))
if ciphertext_modulus.is_compatible_with_native_modulus() {
let (mask, body) = lwe_ciphertext.get_mask_and_body();
let decrypted_native_plaintext = body.data.wrapping_sub(slice_wrapping_dot_product(
mask.as_ref(),
lwe_secret_key.as_ref(),
));
if ciphertext_modulus.is_native_modulus() {
Plaintext(decrypted_native_plaintext)
} else {
// Power of two
Plaintext(decrypted_native_plaintext.wrapping_rem(ciphertext_modulus.get().cast_into()))
}
} else {
let mut ct_128 = LweCiphertext::new(
0u128,
lwe_ciphertext.lwe_size(),
CiphertextModulus::new_native(),
);
let mut key_128 = LweSecretKey::new_empty_key(0u128, lwe_secret_key.lwe_dimension());
copy_from_convert(&mut key_128, &lwe_secret_key);
copy_from_convert(&mut ct_128, &lwe_ciphertext);
let (mask_128, body_128) = ct_128.get_mask_and_body();
let ciphertext_modulus = lwe_ciphertext.ciphertext_modulus().get();
let decrypted: Scalar = (*body_128.data)
.wrapping_add(ciphertext_modulus)
.wrapping_sub(slice_wrapping_dot_product_custom_modulus(
mask_128.as_ref(),
key_128.as_ref(),
ciphertext_modulus,
))
.wrapping_rem(ciphertext_modulus)
.cast_into();
Plaintext(decrypted)
}
}
/// Encrypt an input plaintext list in an output [`LWE ciphertext list`](`LweCiphertextList`).
@@ -408,8 +542,12 @@ where
/// let plaintext_list = PlaintextList::new(encoded_msg, PlaintextCount(lwe_ciphertext_count.0));
///
/// // Create a new LweCiphertextList
/// let mut lwe_list =
/// LweCiphertextList::new(0u64, lwe_dimension.to_lwe_size(), lwe_ciphertext_count);
/// let mut lwe_list = LweCiphertextList::new(
/// 0u64,
/// lwe_dimension.to_lwe_size(),
/// lwe_ciphertext_count,
/// CiphertextModulus::new_native(),
/// );
///
/// encrypt_lwe_ciphertext_list(
/// &lwe_secret_key,
@@ -493,6 +631,7 @@ pub fn encrypt_lwe_ciphertext_list<Scalar, KeyCont, OutputCont, InputCont, Gen>(
/// let lwe_dimension = LweDimension(742);
/// let lwe_ciphertext_count = LweCiphertextCount(2);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -512,8 +651,12 @@ pub fn encrypt_lwe_ciphertext_list<Scalar, KeyCont, OutputCont, InputCont, Gen>(
/// let plaintext_list = PlaintextList::new(encoded_msg, PlaintextCount(lwe_ciphertext_count.0));
///
/// // Create a new LweCiphertextList
/// let mut lwe_list =
/// LweCiphertextList::new(0u64, lwe_dimension.to_lwe_size(), lwe_ciphertext_count);
/// let mut lwe_list = LweCiphertextList::new(
/// 0u64,
/// lwe_dimension.to_lwe_size(),
/// lwe_ciphertext_count,
/// ciphertext_modulus,
/// );
///
/// par_encrypt_lwe_ciphertext_list(
/// &lwe_secret_key,
@@ -633,6 +776,7 @@ pub fn decrypt_lwe_ciphertext_list<Scalar, KeyCont, InputCont, OutputCont>(
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let zero_encryption_count =
/// LwePublicKeyZeroEncryptionCount(lwe_dimension.to_lwe_size().0 * 64 + 128);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -650,6 +794,7 @@ pub fn decrypt_lwe_ciphertext_list<Scalar, KeyCont, InputCont, OutputCont>(
/// &lwe_secret_key,
/// zero_encryption_count,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -658,7 +803,7 @@ pub fn decrypt_lwe_ciphertext_list<Scalar, KeyCont, InputCont, OutputCont>(
/// let plaintext = Plaintext(msg << 60);
///
/// // Create a new LweCiphertext
/// let mut lwe = LweCiphertext::new(0u64, lwe_dimension.to_lwe_size());
/// let mut lwe = LweCiphertext::new(0u64, lwe_dimension.to_lwe_size(), ciphertext_modulus);
///
/// encrypt_lwe_ciphertext_with_public_key(
/// &lwe_public_key,
@@ -692,6 +837,14 @@ pub fn encrypt_lwe_ciphertext_with_public_key<Scalar, KeyCont, OutputCont, Gen>(
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert_eq!(
lwe_public_key.ciphertext_modulus(),
output.ciphertext_modulus(),
"Mismatched moduli between lwe_public_key ({:?}) and output ({:?})",
lwe_public_key.ciphertext_modulus(),
output.ciphertext_modulus()
);
assert!(
output.lwe_size().to_lwe_dimension() == lwe_public_key.lwe_size().to_lwe_dimension(),
"Mismatch between LweDimension of output ciphertext and input public key. \
@@ -700,6 +853,8 @@ pub fn encrypt_lwe_ciphertext_with_public_key<Scalar, KeyCont, OutputCont, Gen>(
lwe_public_key.lwe_size().to_lwe_dimension()
);
let ciphertext_modulus = output.ciphertext_modulus();
output.as_mut().fill(Scalar::ZERO);
let mut ct_choice = vec![Scalar::ZERO; lwe_public_key.zero_encryption_count().0];
@@ -709,13 +864,28 @@ pub fn encrypt_lwe_ciphertext_with_public_key<Scalar, KeyCont, OutputCont, Gen>(
// 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 {
// Already manages u128, avoids having to convert the pk to u128
lwe_ciphertext_add_assign(output, &public_encryption_of_zero);
}
}
// Add encoded plaintext
let body = output.get_mut_body();
*body.0 = (*body.0).wrapping_add(encoded.0);
if ciphertext_modulus.is_compatible_with_native_modulus() {
// Add encoded plaintext
let body = output.get_mut_body();
*body.data = (*body.data).wrapping_add(encoded.0);
if !ciphertext_modulus.is_native_modulus() {
*body.data = (*body.data).wrapping_rem(ciphertext_modulus.get().cast_into());
}
} else {
let body = output.get_mut_body();
let body_u128: u128 = (*body.data).cast_into();
*body.data = body_u128
.wrapping_add(encoded.0.cast_into())
.wrapping_rem(ciphertext_modulus.get())
.cast_into();
}
}
/// Encrypt an input plaintext in an output [`LWE ciphertext`](`LweCiphertext`) using a
@@ -734,6 +904,7 @@ pub fn encrypt_lwe_ciphertext_with_public_key<Scalar, KeyCont, OutputCont, Gen>(
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let zero_encryption_count =
/// LwePublicKeyZeroEncryptionCount(lwe_dimension.to_lwe_size().0 * 64 + 128);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -751,6 +922,7 @@ pub fn encrypt_lwe_ciphertext_with_public_key<Scalar, KeyCont, OutputCont, Gen>(
/// &lwe_secret_key,
/// zero_encryption_count,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// seeder,
/// );
///
@@ -759,7 +931,7 @@ pub fn encrypt_lwe_ciphertext_with_public_key<Scalar, KeyCont, OutputCont, Gen>(
/// let plaintext = Plaintext(msg << 60);
///
/// // Create a new LweCiphertext
/// let mut lwe = LweCiphertext::new(0u64, lwe_dimension.to_lwe_size());
/// let mut lwe = LweCiphertext::new(0u64, lwe_dimension.to_lwe_size(), ciphertext_modulus);
///
/// encrypt_lwe_ciphertext_with_seeded_public_key(
/// &lwe_public_key,
@@ -793,6 +965,14 @@ pub fn encrypt_lwe_ciphertext_with_seeded_public_key<Scalar, KeyCont, OutputCont
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert_eq!(
lwe_public_key.ciphertext_modulus(),
output.ciphertext_modulus(),
"Mismatched moduli between lwe_public_key ({:?}) and output ({:?})",
lwe_public_key.ciphertext_modulus(),
output.ciphertext_modulus()
);
assert!(
output.lwe_size().to_lwe_dimension() == lwe_public_key.lwe_size().to_lwe_dimension(),
"Mismatch between LweDimension of output ciphertext and input public key. \
@@ -807,25 +987,86 @@ pub fn encrypt_lwe_ciphertext_with_seeded_public_key<Scalar, KeyCont, OutputCont
generator.fill_slice_with_random_uniform_binary(&mut ct_choice);
let mut tmp_ciphertext = LweCiphertext::new(Scalar::ZERO, lwe_public_key.lwe_size());
let ciphertext_modulus = output.ciphertext_modulus();
let mut random_generator =
RandomGenerator::<ActivatedRandomGenerator>::new(lwe_public_key.compression_seed().seed);
if ciphertext_modulus.is_compatible_with_native_modulus() {
let mut tmp_ciphertext =
LweCiphertext::new(Scalar::ZERO, lwe_public_key.lwe_size(), ciphertext_modulus);
// Add the public encryption of zeros to get the zero encryption
for (&chosen, public_encryption_of_zero_body) in ct_choice.iter().zip(lwe_public_key.iter()) {
let (mut mask, body) = tmp_ciphertext.get_mut_mask_and_body();
random_generator.fill_slice_with_random_uniform(mask.as_mut());
*body.0 = *public_encryption_of_zero_body.0;
let mut random_generator = RandomGenerator::<ActivatedRandomGenerator>::new(
lwe_public_key.compression_seed().seed,
);
if chosen == Scalar::ONE {
lwe_ciphertext_add_assign(output, &tmp_ciphertext);
// Add the public encryption of zeros to get the zero encryption
for (&chosen, public_encryption_of_zero_body) in ct_choice.iter().zip(lwe_public_key.iter())
{
let (mut mask, body) = tmp_ciphertext.get_mut_mask_and_body();
random_generator.fill_slice_with_random_uniform(mask.as_mut());
*body.data = *public_encryption_of_zero_body.data;
if chosen == Scalar::ONE {
lwe_ciphertext_add_assign(output, &tmp_ciphertext);
}
}
}
// Add encoded plaintext
let body = output.get_mut_body();
*body.0 = (*body.0).wrapping_add(encoded.0);
// Add encoded plaintext
let body = output.get_mut_body();
*body.data = (*body.data).wrapping_add(encoded.0);
if !ciphertext_modulus.is_native_modulus() {
*body.data = (*body.data).wrapping_rem(ciphertext_modulus.get().cast_into());
}
} else {
let mut tmp_ciphertext = LweCiphertext::new(
Scalar::ZERO,
lwe_public_key.lwe_size(),
CiphertextModulus::new_native(),
);
let mut random_generator = RandomGenerator::<ActivatedRandomGenerator>::new(
lwe_public_key.compression_seed().seed,
);
let mut tmp_ct_128 = LweCiphertext::new(
0u128,
lwe_public_key.lwe_size(),
CiphertextModulus::new_native(),
);
let mut output_128 = LweCiphertext::new(
0u128,
lwe_public_key.lwe_size(),
CiphertextModulus::new_native(),
);
let ciphertext_modulus = ciphertext_modulus.get();
// Add the public encryption of zeros to get the zero encryption
for (&chosen, public_encryption_of_zero_body) in ct_choice.iter().zip(lwe_public_key.iter())
{
let (mut mask, body) = tmp_ciphertext.get_mut_mask_and_body();
random_generator.fill_slice_with_random_uniform(mask.as_mut());
*body.data = *public_encryption_of_zero_body.data;
// output_modulus < native modulus always, so we can cast the u128 modulus to the
// smaller type and compute in the smaller type
slice_wrapping_rem_assign(tmp_ciphertext.as_mut(), ciphertext_modulus.cast_into());
copy_from_convert(&mut tmp_ct_128, &tmp_ciphertext);
if chosen == Scalar::ONE {
lwe_ciphertext_add_assign(&mut output_128, &tmp_ct_128);
slice_wrapping_rem_assign(output_128.as_mut(), ciphertext_modulus);
}
}
// Add encoded plaintext
let output_body_128 = output_128.get_mut_body();
*output_body_128.data = (*output_body_128.data)
.wrapping_add(encoded.0.cast_into())
.wrapping_rem(ciphertext_modulus);
copy_from_convert(output, &output_128);
}
}
/// Convenience function to share the core logic of the seeded LWE encryption between all functions
@@ -864,8 +1105,10 @@ pub fn encrypt_seeded_lwe_ciphertext_list_with_existing_generator<
output.lwe_ciphertext_count()
);
let mut output_mask =
LweMask::from_container(vec![Scalar::ZERO; output.lwe_size().to_lwe_dimension().0]);
let mut output_mask = LweMask::from_container(
vec![Scalar::ZERO; output.lwe_size().to_lwe_dimension().0],
output.ciphertext_modulus(),
);
let gen_iter = generator
.fork_lwe_list_to_lwe::<Scalar>(output.lwe_ciphertext_count(), output.lwe_size())
@@ -897,6 +1140,7 @@ pub fn encrypt_seeded_lwe_ciphertext_list_with_existing_generator<
/// let lwe_dimension = LweDimension(742);
/// let lwe_ciphertext_count = LweCiphertextCount(2);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -921,6 +1165,7 @@ pub fn encrypt_seeded_lwe_ciphertext_list_with_existing_generator<
/// lwe_dimension.to_lwe_size(),
/// lwe_ciphertext_count,
/// seeder.seed().into(),
/// ciphertext_modulus,
/// );
///
/// encrypt_seeded_lwe_ciphertext_list(
@@ -1024,13 +1269,15 @@ pub fn par_encrypt_seeded_lwe_ciphertext_list_with_existing_generator<
.unwrap();
let lwe_dimension = output.lwe_size().to_lwe_dimension();
let ciphertext_modulus = output.ciphertext_modulus();
output
.par_iter_mut()
.zip(encoded.par_iter())
.zip(gen_iter)
.for_each(|((output_body, plaintext), mut loop_generator)| {
let mut output_mask = LweMask::from_container(vec![Scalar::ZERO; lwe_dimension.0]);
let mut output_mask =
LweMask::from_container(vec![Scalar::ZERO; lwe_dimension.0], ciphertext_modulus);
fill_lwe_mask_and_body_for_encryption(
lwe_secret_key,
&mut output_mask,
@@ -1053,6 +1300,7 @@ pub fn par_encrypt_seeded_lwe_ciphertext_list_with_existing_generator<
/// let lwe_dimension = LweDimension(742);
/// let lwe_ciphertext_count = LweCiphertextCount(2);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -1077,6 +1325,7 @@ pub fn par_encrypt_seeded_lwe_ciphertext_list_with_existing_generator<
/// lwe_dimension.to_lwe_size(),
/// lwe_ciphertext_count,
/// seeder.seed().into(),
/// ciphertext_modulus,
/// );
///
/// par_encrypt_seeded_lwe_ciphertext_list(
@@ -1152,7 +1401,10 @@ pub fn encrypt_seeded_lwe_ciphertext_with_existing_generator<Scalar, KeyCont, Ge
KeyCont: Container<Element = Scalar>,
Gen: ByteRandomGenerator,
{
let mut mask = LweMask::from_container(vec![Scalar::ZERO; lwe_secret_key.lwe_dimension().0]);
let mut mask = LweMask::from_container(
vec![Scalar::ZERO; lwe_secret_key.lwe_dimension().0],
output.ciphertext_modulus(),
);
fill_lwe_mask_and_body_for_encryption(
lwe_secret_key,
@@ -1195,7 +1447,12 @@ pub fn encrypt_seeded_lwe_ciphertext_with_existing_generator<Scalar, KeyCont, Ge
/// let plaintext = Plaintext(msg << 60);
///
/// // Create a new SeededLweCiphertext
/// let mut lwe = SeededLweCiphertext::new(0u64, lwe_dimension.to_lwe_size(), seeder.seed().into());
/// let mut lwe = SeededLweCiphertext::new(
/// 0u64,
/// lwe_dimension.to_lwe_size(),
/// seeder.seed().into(),
/// CiphertextModulus::new_native(),
/// );
///
/// encrypt_seeded_lwe_ciphertext(
/// &lwe_secret_key,
@@ -1283,6 +1540,7 @@ pub fn encrypt_seeded_lwe_ciphertext<Scalar, KeyCont, NoiseSeeder>(
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// CiphertextModulus::new_native(),
/// seeder,
/// );
///
@@ -1306,6 +1564,7 @@ pub fn allocate_and_encrypt_new_seeded_lwe_ciphertext<Scalar, KeyCont, NoiseSeed
lwe_secret_key: &LweSecretKey<KeyCont>,
encoded: Plaintext<Scalar>,
noise_parameters: impl DispersionParameter,
ciphertext_modulus: CiphertextModulus<Scalar>,
noise_seeder: &mut NoiseSeeder,
) -> SeededLweCiphertext<Scalar>
where
@@ -1318,6 +1577,7 @@ where
Scalar::ZERO,
lwe_secret_key.lwe_dimension().to_lwe_size(),
noise_seeder.seed().into(),
ciphertext_modulus,
);
encrypt_seeded_lwe_ciphertext(
@@ -1349,6 +1609,7 @@ mod test {
let lwe_dimension = LweDimension(742);
let lwe_ciphertext_count = LweCiphertextCount(10);
let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
let ciphertext_modulus = CiphertextModulus::new_native();
// Create the PRNG
let mut seeder = new_seeder();
let seeder = seeder.as_mut();
@@ -1376,6 +1637,7 @@ mod test {
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
ciphertext_modulus,
);
let mut determinisitic_seeder =
@@ -1397,6 +1659,7 @@ mod test {
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
ciphertext_modulus,
);
let mut determinisitic_seeder =
@@ -1424,6 +1687,7 @@ mod test {
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
determinisitic_seeder.seed().into(),
ciphertext_modulus,
);
par_encrypt_seeded_lwe_ciphertext_list(
@@ -1442,6 +1706,7 @@ mod test {
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
determinisitic_seeder.seed().into(),
ciphertext_modulus,
);
encrypt_seeded_lwe_ciphertext_list(
@@ -1477,6 +1742,7 @@ mod test {
// Define parameters for LweCiphertext creation
let lwe_dimension = LweDimension(742);
let lwe_modular_std_dev = StandardDev(4.998_277_131_225_527e-11);
let ciphertext_modulus = CiphertextModulus::new_native();
// Create the PRNG
let mut seeder = new_seeder();
@@ -1502,7 +1768,8 @@ mod test {
let plaintext = Plaintext(msg << ENCODING);
// Create a new LweCiphertext
let mut lwe = LweCiphertext::new(0u128, lwe_dimension.to_lwe_size());
let mut lwe =
LweCiphertext::new(0u128, lwe_dimension.to_lwe_size(), ciphertext_modulus);
encrypt_lwe_ciphertext(
&lwe_secret_key,

View File

@@ -1,9 +1,13 @@
//! Module containing primitives pertaining to [`LWE ciphertext
//! keyswitch`](`LweKeyswitchKey#lwe-keyswitch`).
use crate::core_crypto::algorithms::misc::copy_from_convert;
use crate::core_crypto::algorithms::slice_algorithms::*;
use crate::core_crypto::commons::math::decomposition::SignedDecomposer;
use crate::core_crypto::commons::math::decomposition::{
SignedDecomposer, SignedDecomposerNonNative,
};
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::parameters::CiphertextModulus;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
@@ -27,6 +31,7 @@ use crate::core_crypto::entities::*;
/// let output_lwe_dimension = LweDimension(2048);
/// let decomp_base_log = DecompositionBaseLog(3);
/// let decomp_level_count = DecompositionLevelCount(5);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -50,6 +55,7 @@ use crate::core_crypto::entities::*;
/// decomp_base_log,
/// decomp_level_count,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -62,10 +68,15 @@ use crate::core_crypto::entities::*;
/// &input_lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
/// let mut output_lwe = LweCiphertext::new(0, output_lwe_secret_key.lwe_dimension().to_lwe_size());
/// let mut output_lwe = LweCiphertext::new(
/// 0,
/// output_lwe_secret_key.lwe_dimension().to_lwe_size(),
/// ciphertext_modulus,
/// );
///
/// keyswitch_lwe_ciphertext(&ksk, &input_lwe, &mut output_lwe);
///
@@ -109,33 +120,102 @@ pub fn keyswitch_lwe_ciphertext<Scalar, KSKCont, InputCont, OutputCont>(
lwe_keyswitch_key.output_key_lwe_dimension(),
output_lwe_ciphertext.lwe_size().to_lwe_dimension(),
);
// Clear the output ciphertext, as it will get updated gradually
output_lwe_ciphertext.as_mut().fill(Scalar::ZERO);
// Copy the input body to the output ciphertext
*output_lwe_ciphertext.get_mut_body().0 = *input_lwe_ciphertext.get_body().0;
// We instantiate a decomposer
let decomposer = SignedDecomposer::new(
lwe_keyswitch_key.decomposition_base_log(),
lwe_keyswitch_key.decomposition_level_count(),
assert!(
lwe_keyswitch_key.ciphertext_modulus() == input_lwe_ciphertext.ciphertext_modulus(),
"Mismatched CiphertextModulus. LweKeyswitchKey: {:?}, input LweCiphertext {:?}.",
lwe_keyswitch_key.ciphertext_modulus(),
input_lwe_ciphertext.ciphertext_modulus(),
);
assert!(
lwe_keyswitch_key.ciphertext_modulus() == output_lwe_ciphertext.ciphertext_modulus(),
"Mismatched CiphertextModulus. LweKeyswitchKey: {:?}, output LweCiphertext {:?}.",
lwe_keyswitch_key.ciphertext_modulus(),
output_lwe_ciphertext.ciphertext_modulus(),
);
for (keyswitch_key_block, &input_mask_element) in lwe_keyswitch_key
.iter()
.zip(input_lwe_ciphertext.get_mask().as_ref())
{
let decomposition_iter = decomposer.decompose(input_mask_element);
// loop over the number of levels in reverse (from highest to lowest)
for (level_key_ciphertext, decomposed) in
keyswitch_key_block.iter().rev().zip(decomposition_iter)
let ciphertext_modulus = lwe_keyswitch_key.ciphertext_modulus();
if ciphertext_modulus.is_compatible_with_native_modulus() {
// Clear the output ciphertext, as it will get updated gradually
output_lwe_ciphertext.as_mut().fill(Scalar::ZERO);
// Copy the input body to the output ciphertext
*output_lwe_ciphertext.get_mut_body().data = *input_lwe_ciphertext.get_body().data;
// We instantiate a decomposer
let decomposer = SignedDecomposer::new(
lwe_keyswitch_key.decomposition_base_log(),
lwe_keyswitch_key.decomposition_level_count(),
);
for (keyswitch_key_block, &input_mask_element) in lwe_keyswitch_key
.iter()
.zip(input_lwe_ciphertext.get_mask().as_ref())
{
slice_wrapping_sub_scalar_mul_assign(
let decomposition_iter = decomposer.decompose(input_mask_element);
// loop over the number of levels in reverse (from highest to lowest)
for (level_key_ciphertext, decomposed) in
keyswitch_key_block.iter().rev().zip(decomposition_iter)
{
slice_wrapping_sub_scalar_mul_assign(
output_lwe_ciphertext.as_mut(),
level_key_ciphertext.as_ref(),
decomposed.value(),
);
}
}
if !ciphertext_modulus.is_native_modulus() {
slice_wrapping_rem_assign(
output_lwe_ciphertext.as_mut(),
level_key_ciphertext.as_ref(),
decomposed.value(),
ciphertext_modulus.get().cast_into(),
);
}
} else {
let mut output_ct_128 = LweCiphertext::new(
0u128,
output_lwe_ciphertext.lwe_size(),
CiphertextModulus::new_native(),
);
let mut level_ct_128 = LweCiphertext::new(
0u128,
lwe_keyswitch_key.output_lwe_size(),
CiphertextModulus::new_native(),
);
// Copy the input body to the output ciphertext
*output_ct_128.get_mut_body().data = (*input_lwe_ciphertext.get_body().data).cast_into();
// We instantiate a decomposer
let decomposer = SignedDecomposerNonNative::new(
lwe_keyswitch_key.decomposition_base_log(),
lwe_keyswitch_key.decomposition_level_count(),
ciphertext_modulus,
);
let ciphertext_modulus = ciphertext_modulus.get();
for (keyswitch_key_block, &input_mask_element) in lwe_keyswitch_key
.iter()
.zip(input_lwe_ciphertext.get_mask().as_ref())
{
let decomposition_iter = decomposer.decompose(input_mask_element);
// loop over the number of levels in reverse (from highest to lowest)
for (level_key_ciphertext, decomposed) in
keyswitch_key_block.iter().rev().zip(decomposition_iter)
{
copy_from_convert(&mut level_ct_128, &level_key_ciphertext);
slice_wrapping_sub_scalar_mul_assign_custom_modulus(
output_ct_128.as_mut(),
level_ct_128.as_ref(),
decomposed.value().cast_into(),
ciphertext_modulus,
);
}
}
copy_from_convert(output_lwe_ciphertext, &output_ct_128);
}
}

View File

@@ -5,7 +5,9 @@
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::dispersion::DispersionParameter;
use crate::core_crypto::commons::generators::EncryptionRandomGenerator;
use crate::core_crypto::commons::math::decomposition::{DecompositionLevel, DecompositionTerm};
use crate::core_crypto::commons::math::decomposition::{
DecompositionLevel, DecompositionTerm, DecompositionTermNonNative,
};
use crate::core_crypto::commons::math::random::ActivatedRandomGenerator;
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
@@ -25,6 +27,7 @@ use crate::core_crypto::entities::*;
/// let output_lwe_dimension = LweDimension(2048);
/// let decomp_base_log = DecompositionBaseLog(3);
/// let decomp_level_count = DecompositionLevelCount(5);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -48,6 +51,7 @@ use crate::core_crypto::entities::*;
/// decomp_level_count,
/// input_lwe_dimension,
/// output_lwe_dimension,
/// ciphertext_modulus,
/// );
///
/// generate_lwe_keyswitch_key(
@@ -90,33 +94,65 @@ pub fn generate_lwe_keyswitch_key<Scalar, InputKeyCont, OutputKeyCont, KSKeyCont
let decomp_base_log = lwe_keyswitch_key.decomposition_base_log();
let decomp_level_count = lwe_keyswitch_key.decomposition_level_count();
let ciphertext_modulus = lwe_keyswitch_key.ciphertext_modulus();
// The plaintexts used to encrypt a key element will be stored in this buffer
let mut decomposition_plaintexts_buffer =
PlaintextListOwned::new(Scalar::ZERO, PlaintextCount(decomp_level_count.0));
// Iterate over the input key elements and the destination lwe_keyswitch_key memory
for (input_key_element, mut keyswitch_key_block) in input_lwe_sk
.as_ref()
.iter()
.zip(lwe_keyswitch_key.iter_mut())
{
// We fill the buffer with the powers of the key elmements
for (level, message) in (1..=decomp_level_count.0)
.map(DecompositionLevel)
.zip(decomposition_plaintexts_buffer.iter_mut())
if ciphertext_modulus.is_compatible_with_native_modulus() {
// Iterate over the input key elements and the destination lwe_keyswitch_key memory
for (input_key_element, mut keyswitch_key_block) in input_lwe_sk
.as_ref()
.iter()
.zip(lwe_keyswitch_key.iter_mut())
{
*message.0 = DecompositionTerm::new(level, decomp_base_log, *input_key_element)
.to_recomposition_summand();
}
// We fill the buffer with the powers of the key elmements
for (level, message) in (1..=decomp_level_count.0)
.map(DecompositionLevel)
.zip(decomposition_plaintexts_buffer.iter_mut())
{
*message.0 = DecompositionTerm::new(level, decomp_base_log, *input_key_element)
.to_recomposition_summand();
}
encrypt_lwe_ciphertext_list(
output_lwe_sk,
&mut keyswitch_key_block,
&decomposition_plaintexts_buffer,
noise_parameters,
generator,
);
encrypt_lwe_ciphertext_list(
output_lwe_sk,
&mut keyswitch_key_block,
&decomposition_plaintexts_buffer,
noise_parameters,
generator,
);
}
} else {
// Iterate over the input key elements and the destination lwe_keyswitch_key memory
for (input_key_element, mut keyswitch_key_block) in input_lwe_sk
.as_ref()
.iter()
.zip(lwe_keyswitch_key.iter_mut())
{
// We fill the buffer with the powers of the key elmements
for (level, message) in (1..=decomp_level_count.0)
.map(DecompositionLevel)
.zip(decomposition_plaintexts_buffer.iter_mut())
{
*message.0 = DecompositionTermNonNative::new(
level,
decomp_base_log,
*input_key_element,
ciphertext_modulus,
)
.to_recomposition_summand();
}
encrypt_lwe_ciphertext_list(
output_lwe_sk,
&mut keyswitch_key_block,
&decomposition_plaintexts_buffer,
noise_parameters,
generator,
);
}
}
}
@@ -130,6 +166,7 @@ pub fn allocate_and_generate_new_lwe_keyswitch_key<Scalar, InputKeyCont, OutputK
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
noise_parameters: impl DispersionParameter,
ciphertext_modulus: CiphertextModulus<Scalar>,
generator: &mut EncryptionRandomGenerator<Gen>,
) -> LweKeyswitchKeyOwned<Scalar>
where
@@ -144,6 +181,7 @@ where
decomp_level_count,
input_lwe_sk.lwe_dimension(),
output_lwe_sk.lwe_dimension(),
ciphertext_modulus,
);
generate_lwe_keyswitch_key(
@@ -171,6 +209,7 @@ where
/// let output_lwe_dimension = LweDimension(2048);
/// let decomp_base_log = DecompositionBaseLog(3);
/// let decomp_level_count = DecompositionLevelCount(5);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -193,6 +232,7 @@ where
/// input_lwe_dimension,
/// output_lwe_dimension,
/// seeder.seed().into(),
/// ciphertext_modulus,
/// );
///
/// generate_seeded_lwe_keyswitch_key(
@@ -242,6 +282,7 @@ pub fn generate_seeded_lwe_keyswitch_key<
let decomp_base_log = lwe_keyswitch_key.decomposition_base_log();
let decomp_level_count = lwe_keyswitch_key.decomposition_level_count();
let ciphertext_modulus = lwe_keyswitch_key.ciphertext_modulus();
// The plaintexts used to encrypt a key element will be stored in this buffer
let mut decomposition_plaintexts_buffer =
@@ -252,28 +293,59 @@ pub fn generate_seeded_lwe_keyswitch_key<
noise_seeder,
);
// Iterate over the input key elements and the destination lwe_keyswitch_key memory
for (input_key_element, mut keyswitch_key_block) in input_lwe_sk
.as_ref()
.iter()
.zip(lwe_keyswitch_key.iter_mut())
{
// We fill the buffer with the powers of the key elmements
for (level, message) in (1..=decomp_level_count.0)
.map(DecompositionLevel)
.zip(decomposition_plaintexts_buffer.iter_mut())
if ciphertext_modulus.is_compatible_with_native_modulus() {
// Iterate over the input key elements and the destination lwe_keyswitch_key memory
for (input_key_element, mut keyswitch_key_block) in input_lwe_sk
.as_ref()
.iter()
.zip(lwe_keyswitch_key.iter_mut())
{
*message.0 = DecompositionTerm::new(level, decomp_base_log, *input_key_element)
.to_recomposition_summand();
}
// We fill the buffer with the powers of the key elmements
for (level, message) in (1..=decomp_level_count.0)
.map(DecompositionLevel)
.zip(decomposition_plaintexts_buffer.iter_mut())
{
*message.0 = DecompositionTerm::new(level, decomp_base_log, *input_key_element)
.to_recomposition_summand();
}
encrypt_seeded_lwe_ciphertext_list_with_existing_generator(
output_lwe_sk,
&mut keyswitch_key_block,
&decomposition_plaintexts_buffer,
noise_parameters,
&mut generator,
);
encrypt_seeded_lwe_ciphertext_list_with_existing_generator(
output_lwe_sk,
&mut keyswitch_key_block,
&decomposition_plaintexts_buffer,
noise_parameters,
&mut generator,
);
}
} else {
// Iterate over the input key elements and the destination lwe_keyswitch_key memory
for (input_key_element, mut keyswitch_key_block) in input_lwe_sk
.as_ref()
.iter()
.zip(lwe_keyswitch_key.iter_mut())
{
// We fill the buffer with the powers of the key elmements
for (level, message) in (1..=decomp_level_count.0)
.map(DecompositionLevel)
.zip(decomposition_plaintexts_buffer.iter_mut())
{
*message.0 = DecompositionTermNonNative::new(
level,
decomp_base_log,
*input_key_element,
ciphertext_modulus,
)
.to_recomposition_summand();
}
encrypt_seeded_lwe_ciphertext_list_with_existing_generator(
output_lwe_sk,
&mut keyswitch_key_block,
&decomposition_plaintexts_buffer,
noise_parameters,
&mut generator,
);
}
}
}
@@ -291,6 +363,7 @@ pub fn allocate_and_generate_new_seeded_lwe_keyswitch_key<
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
noise_parameters: impl DispersionParameter,
ciphertext_modulus: CiphertextModulus<Scalar>,
noise_seeder: &mut NoiseSeeder,
) -> SeededLweKeyswitchKeyOwned<Scalar>
where
@@ -307,6 +380,7 @@ where
input_lwe_sk.lwe_dimension(),
output_lwe_sk.lwe_dimension(),
noise_seeder.seed().into(),
ciphertext_modulus,
);
generate_seeded_lwe_keyswitch_key(
@@ -365,6 +439,7 @@ mod test {
decomp_level_count,
input_lwe_dimension,
output_lwe_dimension,
CiphertextModulus::new_native(),
);
let mut deterministic_seeder =
@@ -390,6 +465,7 @@ mod test {
input_lwe_dimension,
output_lwe_dimension,
mask_seed.into(),
ksk.ciphertext_modulus(),
);
let mut deterministic_seeder =

View File

@@ -1,8 +1,10 @@
//! Module containing primitives pertaining to [`LWE ciphertext`](`LweCiphertext`) linear algebra,
//! like addition, multiplication, etc.
use crate::core_crypto::algorithms::misc::*;
use crate::core_crypto::algorithms::slice_algorithms::*;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::parameters::CiphertextModulus;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
@@ -19,6 +21,7 @@ use crate::core_crypto::entities::*;
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -41,6 +44,7 @@ use crate::core_crypto::entities::*;
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -70,7 +74,39 @@ pub fn lwe_ciphertext_add_assign<Scalar, LhsCont, RhsCont>(
LhsCont: ContainerMut<Element = Scalar>,
RhsCont: Container<Element = Scalar>,
{
slice_wrapping_add_assign(lhs.as_mut(), rhs.as_ref());
assert_eq!(
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus(),
"Mismatched moduli between lhs ({:?}) and rhs ({:?}) LweCiphertext",
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
let ciphertext_modulus = lhs.ciphertext_modulus();
if ciphertext_modulus.is_compatible_with_native_modulus() {
slice_wrapping_add_assign(lhs.as_mut(), rhs.as_ref());
if !ciphertext_modulus.is_native_modulus() {
slice_wrapping_rem_assign(lhs.as_mut(), ciphertext_modulus.get().cast_into());
}
} else {
let mut ct_128_lhs =
LweCiphertext::new(0u128, lhs.lwe_size(), CiphertextModulus::new_native());
copy_from_convert(&mut ct_128_lhs, lhs);
let mut ct_128_rhs =
LweCiphertext::new(0u128, rhs.lwe_size(), CiphertextModulus::new_native());
copy_from_convert(&mut ct_128_rhs, rhs);
slice_wrapping_add_assign(ct_128_lhs.as_mut(), ct_128_rhs.as_ref());
slice_wrapping_rem_assign(ct_128_lhs.as_mut(), ciphertext_modulus.get());
copy_from_convert(lhs, &ct_128_lhs);
}
}
/// Add the right-hand side [`LWE ciphertext`](`LweCiphertext`) to the left-hand side [`LWE
@@ -87,6 +123,7 @@ pub fn lwe_ciphertext_add_assign<Scalar, LhsCont, RhsCont>(
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -109,6 +146,7 @@ pub fn lwe_ciphertext_add_assign<Scalar, LhsCont, RhsCont>(
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -142,7 +180,24 @@ pub fn lwe_ciphertext_add<Scalar, OutputCont, LhsCont, RhsCont>(
LhsCont: Container<Element = Scalar>,
RhsCont: Container<Element = Scalar>,
{
slice_wrapping_add(output.as_mut(), lhs.as_ref(), rhs.as_ref());
assert_eq!(
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus(),
"Mismatched moduli between lhs ({:?}) and rhs ({:?}) LweCiphertext",
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
assert_eq!(
output.ciphertext_modulus(),
rhs.ciphertext_modulus(),
"Mismatched moduli between output ({:?}) and rhs ({:?}) LweCiphertext",
output.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
output.as_mut().copy_from_slice(lhs.as_ref());
lwe_ciphertext_add_assign(output, rhs);
}
/// Add the right-hand side encoded [`Plaintext`] to the left-hand side [`LWE
@@ -158,6 +213,7 @@ pub fn lwe_ciphertext_add<Scalar, OutputCont, LhsCont, RhsCont>(
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -180,6 +236,7 @@ pub fn lwe_ciphertext_add<Scalar, OutputCont, LhsCont, RhsCont>(
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -206,9 +263,22 @@ pub fn lwe_ciphertext_plaintext_add_assign<Scalar, InCont>(
Scalar: UnsignedInteger,
InCont: ContainerMut<Element = Scalar>,
{
let ciphertext_modulus = lhs.ciphertext_modulus();
let body = lhs.get_mut_body();
*body.0 = (*body.0).wrapping_add(rhs.0);
if ciphertext_modulus.is_compatible_with_native_modulus() {
*body.data = (*body.data).wrapping_add(rhs.0);
if !ciphertext_modulus.is_native_modulus() {
*body.data = (*body.data).wrapping_rem(ciphertext_modulus.get().cast_into());
}
} else {
let body_128: u128 = (*body.data).cast_into();
(*body.data) = body_128
.wrapping_add(rhs.0.cast_into())
.wrapping_rem(ciphertext_modulus.get())
.cast_into()
}
}
/// Add the right-hand side encoded [`Plaintext`] to the left-hand side [`LWE
@@ -246,6 +316,7 @@ pub fn lwe_ciphertext_plaintext_add_assign<Scalar, InCont>(
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// CiphertextModulus::new_native(),
/// &mut encryption_generator,
/// );
///
@@ -272,9 +343,22 @@ pub fn lwe_ciphertext_plaintext_sub_assign<Scalar, InCont>(
Scalar: UnsignedInteger,
InCont: ContainerMut<Element = Scalar>,
{
let ciphertext_modulus = lhs.ciphertext_modulus();
let body = lhs.get_mut_body();
*body.0 = (*body.0).wrapping_sub(rhs.0);
if ciphertext_modulus.is_compatible_with_native_modulus() {
*body.data = (*body.data).wrapping_sub(rhs.0);
if !ciphertext_modulus.is_native_modulus() {
*body.data = (*body.data).wrapping_rem(ciphertext_modulus.get().cast_into());
}
} else {
let body_128: u128 = (*body.data).cast_into();
(*body.data) = body_128
.wrapping_sub(rhs.0.cast_into())
.wrapping_rem(ciphertext_modulus.get())
.cast_into()
}
}
/// Compute the opposite of the input [`LWE ciphertext`](`LweCiphertext`) and update it in place.
@@ -289,6 +373,7 @@ pub fn lwe_ciphertext_plaintext_sub_assign<Scalar, InCont>(
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -311,6 +396,7 @@ pub fn lwe_ciphertext_plaintext_sub_assign<Scalar, InCont>(
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -335,7 +421,16 @@ where
Scalar: UnsignedInteger,
InCont: ContainerMut<Element = Scalar>,
{
slice_wrapping_opposite_assign(ct.as_mut());
let ciphertext_modulus = ct.ciphertext_modulus();
if ciphertext_modulus.is_compatible_with_native_modulus() {
slice_wrapping_opposite_assign_native_mod(ct.as_mut());
if !ciphertext_modulus.is_native_modulus() {
slice_wrapping_rem_assign(ct.as_mut(), ciphertext_modulus.get().cast_into());
}
} else {
slice_wrapping_opposite_assign_custom_mod(ct.as_mut(), ciphertext_modulus.get().cast_into())
}
}
/// Mulitply the left-hand side [`LWE ciphertext`](`LweCiphertext`) by the right-hand side cleartext
@@ -351,6 +446,7 @@ where
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -374,6 +470,7 @@ where
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -400,7 +497,104 @@ pub fn lwe_ciphertext_cleartext_mul_assign<Scalar, InCont>(
Scalar: UnsignedInteger,
InCont: ContainerMut<Element = Scalar>,
{
slice_wrapping_scalar_mul_assign(lhs.as_mut(), rhs.0);
let ciphertext_modulus = lhs.ciphertext_modulus();
if ciphertext_modulus.is_compatible_with_native_modulus() {
slice_wrapping_scalar_mul_assign(lhs.as_mut(), rhs.0);
if !ciphertext_modulus.is_native_modulus() {
slice_wrapping_rem_assign(lhs.as_mut(), ciphertext_modulus.get().cast_into());
}
} else {
let mut lhs_128 =
LweCiphertext::new(0u128, lhs.lwe_size(), CiphertextModulus::new_native());
copy_from_convert(&mut lhs_128, lhs);
slice_wrapping_scalar_mul_assign(lhs_128.as_mut(), rhs.0.cast_into());
slice_wrapping_rem_assign(lhs_128.as_mut(), ciphertext_modulus.get());
copy_from_convert(lhs, &lhs_128);
}
}
/// Mulitply the left-hand side [`LWE ciphertext`](`LweCiphertext`) by the right-hand side cleartext
/// writing the result in the output [`LWE ciphertext`](`LweCiphertext`).
///
/// # Example
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut encryption_generator =
/// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// // Create the LweSecretKey
/// let lwe_secret_key =
/// allocate_and_generate_new_binary_lwe_secret_key(lwe_dimension, &mut secret_generator);
///
/// // Create the plaintext
/// let msg = 3u64;
/// let plaintext = Plaintext(msg << 60);
/// let mul_cleartext = 2;
///
/// // Create a new LweCiphertext
/// let lwe = allocate_and_encrypt_new_lwe_ciphertext(
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
/// let mut output = lwe.clone();
///
/// lwe_ciphertext_cleartext_mul(&mut output, &lwe, Cleartext(mul_cleartext));
///
/// let decrypted_plaintext = decrypt_lwe_ciphertext(&lwe_secret_key, &output);
///
/// // Round and remove encoding
/// // First create a decomposer working on the high 4 bits corresponding to our encoding.
/// let decomposer = SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
///
/// let rounded = decomposer.closest_representable(decrypted_plaintext.0);
///
/// // Remove the encoding
/// let cleartext = rounded >> 60;
///
/// // Check we recovered the expected result
/// assert_eq!(cleartext, msg * mul_cleartext);
/// ```
pub fn lwe_ciphertext_cleartext_mul<Scalar, InputCont, OutputCont>(
output: &mut LweCiphertext<OutputCont>,
lhs: &LweCiphertext<InputCont>,
rhs: Cleartext<Scalar>,
) where
Scalar: UnsignedInteger,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
assert_eq!(
output.ciphertext_modulus(),
lhs.ciphertext_modulus(),
"Mismatched moduli between output ({:?}) and lhs ({:?}) LweCiphertext",
output.ciphertext_modulus(),
lhs.ciphertext_modulus()
);
output.as_mut().copy_from_slice(lhs.as_ref());
lwe_ciphertext_cleartext_mul_assign(output, rhs);
}
/// Subtract the right-hand side [`LWE ciphertext`](`LweCiphertext`) to the left-hand side [`LWE
@@ -416,6 +610,7 @@ pub fn lwe_ciphertext_cleartext_mul_assign<Scalar, InCont>(
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -438,6 +633,7 @@ pub fn lwe_ciphertext_cleartext_mul_assign<Scalar, InCont>(
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -467,7 +663,36 @@ pub fn lwe_ciphertext_sub_assign<Scalar, LhsCont, RhsCont>(
LhsCont: ContainerMut<Element = Scalar>,
RhsCont: Container<Element = Scalar>,
{
slice_wrapping_sub_assign(lhs.as_mut(), rhs.as_ref());
assert_eq!(
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus(),
"Mismatched moduli between lhs ({:?}) and rhs ({:?}) LweCiphertext",
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
let ciphertext_modulus = lhs.ciphertext_modulus();
if ciphertext_modulus.is_compatible_with_native_modulus() {
slice_wrapping_sub_assign(lhs.as_mut(), rhs.as_ref());
if !ciphertext_modulus.is_native_modulus() {
slice_wrapping_rem_assign(lhs.as_mut(), ciphertext_modulus.get().cast_into());
}
} else {
let mut ct_128_lhs =
LweCiphertext::new(0u128, lhs.lwe_size(), CiphertextModulus::new_native());
let mut ct_128_rhs =
LweCiphertext::new(0u128, rhs.lwe_size(), CiphertextModulus::new_native());
copy_from_convert(&mut ct_128_lhs, lhs);
copy_from_convert(&mut ct_128_rhs, rhs);
slice_wrapping_sub_assign(ct_128_lhs.as_mut(), ct_128_rhs.as_ref());
slice_wrapping_rem_assign(ct_128_lhs.as_mut(), ciphertext_modulus.get());
copy_from_convert(lhs, &ct_128_lhs);
}
}
/// Subtract the right-hand side [`LWE ciphertext`](`LweCiphertext`) to the left-hand side [`LWE
@@ -484,6 +709,7 @@ pub fn lwe_ciphertext_sub_assign<Scalar, LhsCont, RhsCont>(
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
@@ -508,12 +734,14 @@ pub fn lwe_ciphertext_sub_assign<Scalar, LhsCont, RhsCont>(
/// &lwe_secret_key,
/// plaintext1,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
/// let lwe2 = allocate_and_encrypt_new_lwe_ciphertext(
/// &lwe_secret_key,
/// plaintext2,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -545,75 +773,22 @@ pub fn lwe_ciphertext_sub<Scalar, OutputCont, LhsCont, RhsCont>(
LhsCont: Container<Element = Scalar>,
RhsCont: Container<Element = Scalar>,
{
slice_wrapping_sub(output.as_mut(), lhs.as_ref(), rhs.as_ref());
}
assert_eq!(
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus(),
"Mismatched moduli between lhs ({:?}) and rhs ({:?}) LweCiphertext",
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
assert_eq!(
output.ciphertext_modulus(),
rhs.ciphertext_modulus(),
"Mismatched moduli between output ({:?}) and rhs ({:?}) LweCiphertext",
output.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
/// Mulitply the left-hand side [`LWE ciphertext`](`LweCiphertext`) by the right-hand side cleartext
/// writing the result in the output [`LWE ciphertext`](`LweCiphertext`).
///
/// # Example
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut encryption_generator =
/// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// // Create the LweSecretKey
/// let lwe_secret_key =
/// allocate_and_generate_new_binary_lwe_secret_key(lwe_dimension, &mut secret_generator);
///
/// // Create the plaintext
/// let msg = 3u64;
/// let plaintext = Plaintext(msg << 60);
/// let mul_cleartext = 2;
///
/// // Create a new LweCiphertext
/// let lwe = allocate_and_encrypt_new_lwe_ciphertext(
/// &lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// &mut encryption_generator,
/// );
///
/// let mut output = lwe.clone();
///
/// lwe_ciphertext_cleartext_mul(&mut output, &lwe, Cleartext(mul_cleartext));
///
/// let decrypted_plaintext = decrypt_lwe_ciphertext(&lwe_secret_key, &output);
///
/// // Round and remove encoding
/// // First create a decomposer working on the high 4 bits corresponding to our encoding.
/// let decomposer = SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
///
/// let rounded = decomposer.closest_representable(decrypted_plaintext.0);
///
/// // Remove the encoding
/// let cleartext = rounded >> 60;
///
/// // Check we recovered the expected result
/// assert_eq!(cleartext, msg * mul_cleartext);
/// ```
pub fn lwe_ciphertext_cleartext_mul<Scalar, InputCont, OutputCont>(
output: &mut LweCiphertext<OutputCont>,
lhs: &LweCiphertext<InputCont>,
rhs: Cleartext<Scalar>,
) where
Scalar: UnsignedInteger,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
output.as_mut().copy_from_slice(lhs.as_ref());
lwe_ciphertext_cleartext_mul_assign(output, rhs);
lwe_ciphertext_sub_assign(output, rhs);
}

View File

@@ -112,6 +112,7 @@ use std::thread;
/// &small_lwe_sk,
/// plaintext,
/// lwe_modular_std_dev,
/// CiphertextModulus::new_native(),
/// &mut encryption_generator,
/// );
///
@@ -175,8 +176,11 @@ use std::thread;
/// );
///
/// // Allocate the LweCiphertext to store the result of the PBS
/// let mut pbs_multiplication_ct =
/// LweCiphertext::new(0u64, big_lwe_sk.lwe_dimension().to_lwe_size());
/// let mut pbs_multiplication_ct = LweCiphertext::new(
/// 0u64,
/// big_lwe_sk.lwe_dimension().to_lwe_size(),
/// CiphertextModulus::new_native(),
/// );
/// println!("Performing blind rotation...");
/// // Use 4 threads for the multi-bit blind rotation for example
/// multi_bit_blind_rotate_assign(
@@ -277,7 +281,7 @@ pub fn multi_bit_blind_rotate_assign<Scalar, InputCont, OutputCont, KeyCont>(
let lut_poly_size = accumulator.polynomial_size();
let monomial_degree = pbs_modulus_switch(
*lwe_body.0,
*lwe_body.data,
lut_poly_size,
ModulusSwitchOffset(0),
LutCountLog(0),
@@ -587,6 +591,7 @@ pub fn multi_bit_blind_rotate_assign<Scalar, InputCont, OutputCont, KeyCont>(
/// &small_lwe_sk,
/// plaintext,
/// lwe_modular_std_dev,
/// CiphertextModulus::new_native(),
/// &mut encryption_generator,
/// );
///
@@ -650,8 +655,11 @@ pub fn multi_bit_blind_rotate_assign<Scalar, InputCont, OutputCont, KeyCont>(
/// );
///
/// // Allocate the LweCiphertext to store the result of the PBS
/// let mut pbs_multiplication_ct =
/// LweCiphertext::new(0u64, big_lwe_sk.lwe_dimension().to_lwe_size());
/// let mut pbs_multiplication_ct = LweCiphertext::new(
/// 0u64,
/// big_lwe_sk.lwe_dimension().to_lwe_size(),
/// CiphertextModulus::new_native(),
/// );
/// println!("Computing PBS...");
/// // Use 4 threads to compute the multi-bit PBS
/// multi_bit_programmable_bootstrap_lwe_ciphertext(
@@ -767,6 +775,7 @@ mod test {
let glwe_dimension = GlweDimension(1);
let polynomial_size = PolynomialSize(1024);
let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
let ciphertext_modulus = CiphertextModulus::new_native();
while input_lwe_dimension.0 % grouping_factor.0 != 0 {
input_lwe_dimension = LweDimension(input_lwe_dimension.0 + 1);
@@ -884,6 +893,7 @@ mod test {
&input_lwe_secret_key,
plaintext,
lwe_modular_std_dev,
ciphertext_modulus,
&mut encryption_generator,
);
@@ -896,8 +906,11 @@ mod test {
);
// Allocate the LweCiphertext to store the result of the PBS
let mut out_pbs_ct =
LweCiphertext::new(0u64, output_lwe_secret_key.lwe_dimension().to_lwe_size());
let mut out_pbs_ct = LweCiphertext::new(
0u64,
output_lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
println!("Computing PBS...");
multi_bit_programmable_bootstrap_lwe_ciphertext(
&lwe_ciphertext_in,

View File

@@ -31,6 +31,13 @@ pub fn private_functional_keyswitch_lwe_ciphertext_into_glwe_ciphertext<
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
assert!(
input_lwe_ciphertext
.ciphertext_modulus()
.is_native_modulus(),
"This operation only supports native moduli"
);
assert!(
lwe_pfpksk.input_lwe_key_dimension().0
== input_lwe_ciphertext.lwe_size().to_lwe_dimension().0
@@ -87,6 +94,11 @@ pub fn private_functional_keyswitch_lwe_ciphertext_list_and_pack_in_glwe_ciphert
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
assert!(
input.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
assert!(input.lwe_ciphertext_count().0 <= output.polynomial_size().0);
output.as_mut().fill(Scalar::ZERO);
let mut buffer =

View File

@@ -116,6 +116,7 @@ use dyn_stack::{DynStack, SizeOverflow, StackReq};
/// &small_lwe_sk,
/// plaintext,
/// lwe_modular_std_dev,
/// CiphertextModulus::new_native(),
/// &mut encryption_generator,
/// );
///
@@ -179,8 +180,11 @@ use dyn_stack::{DynStack, SizeOverflow, StackReq};
/// );
///
/// // Allocate the LweCiphertext to store the result of the PBS
/// let mut pbs_multiplication_ct =
/// LweCiphertext::new(0u64, big_lwe_sk.lwe_dimension().to_lwe_size());
/// let mut pbs_multiplication_ct = LweCiphertext::new(
/// 0u64,
/// big_lwe_sk.lwe_dimension().to_lwe_size(),
/// CiphertextModulus::new_native(),
/// );
/// println!("Performing blind rotation...");
/// blind_rotate_assign(&lwe_ciphertext_in, &mut accumulator, &fourier_bsk);
/// println!("Performing sample extraction...");
@@ -221,6 +225,11 @@ pub fn blind_rotate_assign<Scalar, InputCont, OutputCont, KeyCont>(
OutputCont: ContainerMut<Element = Scalar>,
KeyCont: Container<Element = c64>,
{
assert!(
input.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
let mut buffers = ComputationBuffers::new();
let fft = Fft::new(fourier_bsk.polynomial_size());
@@ -257,6 +266,10 @@ pub fn blind_rotate_assign_mem_optimized<Scalar, InputCont, OutputCont, KeyCont>
OutputCont: ContainerMut<Element = Scalar>,
KeyCont: Container<Element = c64>,
{
assert!(
input.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
fourier_bsk
.as_view()
.blind_rotate_assign(lut.as_mut_view(), input.as_ref(), fft, stack);
@@ -765,6 +778,7 @@ pub fn cmux_assign_mem_optimized_requirement<Scalar>(
/// let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
/// let pbs_base_log = DecompositionBaseLog(23);
/// let pbs_level = DecompositionLevelCount(1);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Request the best seeder possible, starting with hardware entropy sources and falling back to
/// // /dev/random on Unix systems if enabled via cargo features
@@ -841,6 +855,7 @@ pub fn cmux_assign_mem_optimized_requirement<Scalar>(
/// &small_lwe_sk,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -904,8 +919,11 @@ pub fn cmux_assign_mem_optimized_requirement<Scalar>(
/// );
///
/// // Allocate the LweCiphertext to store the result of the PBS
/// let mut pbs_multiplication_ct =
/// LweCiphertext::new(0u64, big_lwe_sk.lwe_dimension().to_lwe_size());
/// let mut pbs_multiplication_ct = LweCiphertext::new(
/// 0u64,
/// big_lwe_sk.lwe_dimension().to_lwe_size(),
/// ciphertext_modulus,
/// );
/// println!("Computing PBS...");
/// programmable_bootstrap_lwe_ciphertext(
/// &lwe_ciphertext_in,
@@ -1000,8 +1018,8 @@ pub fn programmable_bootstrap_lwe_ciphertext_mem_optimized<
KeyCont: Container<Element = c64>,
{
fourier_bsk.as_view().bootstrap(
output.as_mut(),
input.as_ref(),
output.as_mut_view(),
input.as_view(),
accumulator.as_view(),
fft,
stack,

View File

@@ -50,6 +50,7 @@ pub fn allocate_and_generate_new_lwe_public_key<Scalar, InputKeyCont, Gen>(
lwe_secret_key: &LweSecretKey<InputKeyCont>,
zero_encryption_count: LwePublicKeyZeroEncryptionCount,
noise_parameters: impl DispersionParameter,
ciphertext_modulus: CiphertextModulus<Scalar>,
generator: &mut EncryptionRandomGenerator<Gen>,
) -> LwePublicKeyOwned<Scalar>
where
@@ -61,6 +62,7 @@ where
Scalar::ZERO,
lwe_secret_key.lwe_dimension().to_lwe_size(),
zero_encryption_count,
ciphertext_modulus,
);
generate_lwe_public_key(lwe_secret_key, &mut pk, noise_parameters, generator);
@@ -102,6 +104,7 @@ pub fn par_allocate_and_generate_new_lwe_public_key<Scalar, InputKeyCont, Gen>(
lwe_secret_key: &LweSecretKey<InputKeyCont>,
zero_encryption_count: LwePublicKeyZeroEncryptionCount,
noise_parameters: impl DispersionParameter + Sync,
ciphertext_modulus: CiphertextModulus<Scalar>,
generator: &mut EncryptionRandomGenerator<Gen>,
) -> LwePublicKeyOwned<Scalar>
where
@@ -113,6 +116,7 @@ where
Scalar::ZERO,
lwe_secret_key.lwe_dimension().to_lwe_size(),
zero_encryption_count,
ciphertext_modulus,
);
par_generate_lwe_public_key(lwe_secret_key, &mut pk, noise_parameters, generator);
@@ -167,6 +171,7 @@ pub fn allocate_and_generate_new_seeded_lwe_public_key<Scalar, InputKeyCont, Noi
lwe_secret_key: &LweSecretKey<InputKeyCont>,
zero_encryption_count: LwePublicKeyZeroEncryptionCount,
noise_parameters: impl DispersionParameter,
ciphertext_modulus: CiphertextModulus<Scalar>,
noise_seeder: &mut NoiseSeeder,
) -> SeededLwePublicKeyOwned<Scalar>
where
@@ -182,6 +187,7 @@ where
CompressionSeed {
seed: noise_seeder.seed(),
},
ciphertext_modulus,
);
generate_seeded_lwe_public_key(lwe_secret_key, &mut pk, noise_parameters, noise_seeder);
@@ -230,6 +236,7 @@ pub fn par_allocate_and_generate_new_seeded_lwe_public_key<Scalar, InputKeyCont,
lwe_secret_key: &LweSecretKey<InputKeyCont>,
zero_encryption_count: LwePublicKeyZeroEncryptionCount,
noise_parameters: impl DispersionParameter + Sync,
ciphertext_modulus: CiphertextModulus<Scalar>,
noise_seeder: &mut NoiseSeeder,
) -> SeededLwePublicKeyOwned<Scalar>
where
@@ -245,6 +252,7 @@ where
CompressionSeed {
seed: noise_seeder.seed(),
},
ciphertext_modulus,
);
par_generate_seeded_lwe_public_key(lwe_secret_key, &mut pk, noise_parameters, noise_seeder);

View File

@@ -391,6 +391,7 @@ pub fn extract_bits_from_lwe_ciphertext_mem_optimized_requirement<Scalar>(
/// let polynomial_size = PolynomialSize(1024);
/// let glwe_dimension = GlweDimension(1);
/// let lwe_dimension = LweDimension(481);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// let var_small = Variance::from_variance(2f64.powf(-80.0));
/// let var_big = Variance::from_variance(2f64.powf(-70.0));
@@ -441,6 +442,7 @@ pub fn extract_bits_from_lwe_ciphertext_mem_optimized_requirement<Scalar>(
/// ksk_base_log,
/// ksk_level_count,
/// var_big,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -525,6 +527,7 @@ pub fn extract_bits_from_lwe_ciphertext_mem_optimized_requirement<Scalar>(
/// &lwe_big_sk,
/// encoded_message,
/// var_big,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
@@ -533,6 +536,7 @@ pub fn extract_bits_from_lwe_ciphertext_mem_optimized_requirement<Scalar>(
/// 0u64,
/// lwe_dimension.to_lwe_size(),
/// LweCiphertextCount(bits_to_extract.0),
/// ciphertext_modulus,
/// );
///
/// extract_bits_from_lwe_ciphertext_mem_optimized(
@@ -568,6 +572,7 @@ pub fn extract_bits_from_lwe_ciphertext_mem_optimized_requirement<Scalar>(
/// 0u64,
/// lwe_big_sk.lwe_dimension().to_lwe_size(),
/// number_of_luts_and_output_vp_ciphertexts,
/// ciphertext_modulus,
/// );
///
/// circuit_bootstrap_boolean_vertical_packing_lwe_ciphertext_list_mem_optimized(

View File

@@ -0,0 +1,99 @@
//! Miscellaneous algorithms.
use crate::core_crypto::prelude::*;
#[inline]
pub fn copy_from_convert<ScalarDst, ScalarSrc, Dst, Src>(dst: &mut Dst, src: &Src)
where
ScalarSrc: Copy + CastInto<ScalarDst>,
Dst: AsMut<[ScalarDst]>,
Src: AsRef<[ScalarSrc]>,
{
let dst = dst.as_mut();
let src = src.as_ref();
assert_eq!(dst.len(), src.len());
dst.iter_mut()
.zip(src.iter())
.for_each(|(dst, &src)| *dst = src.cast_into());
}
#[inline]
pub fn divide_round<Scalar>(numerator: Scalar, denominator: Scalar) -> Scalar
where
Scalar: UnsignedInteger,
{
let numerator_128: u128 = numerator.cast_into();
let half_denominator: u128 = (denominator / Scalar::TWO).cast_into();
let denominator_128: u128 = denominator.cast_into();
let rounded_128 = (numerator_128 + half_denominator) / denominator_128;
rounded_128.cast_into()
}
#[inline]
pub fn divide_round_to_u128<Scalar>(numerator: Scalar, denominator: Scalar) -> u128
where
Scalar: UnsignedInteger,
{
let numerator_128: u128 = numerator.cast_into();
let half_denominator: u128 = (denominator / Scalar::TWO).cast_into();
let denominator_128: u128 = denominator.cast_into();
// That's the rounding
(numerator_128 + half_denominator) / denominator_128
}
pub fn odd_modular_inverse_pow_2<Scalar>(odd_value_to_invert: Scalar, log2_modulo: usize) -> Scalar
where
Scalar: UnsignedInteger,
{
let t = log2_modulo.ilog2() + if log2_modulo.is_power_of_two() { 0 } else { 1 };
let mut y = Scalar::ONE;
let e = odd_value_to_invert;
for i in 1..=t {
// 1 << (1 << i) == 2 ^ {2 ^ i}
let curr_mod = Scalar::ONE.shl(1 << i);
// y = y * (2 - y * e) mod 2 ^ {2 ^ i}
// Here using wrapping ops is ok as the modulus used is a power of 2, as long as 2 ^ {2 ^ i}
// is smaller than Scalar::BITS, we are good to go, the discarded values would not have been
// Used anyways, and 2 ^ {2 ^ i} is compatible with a native modulus
y = (y.wrapping_mul(Scalar::TWO.wrapping_sub(y.wrapping_mul(e)))).wrapping_rem(curr_mod);
}
y.wrapping_rem(Scalar::ONE.shl(log2_modulo))
}
#[test]
fn test_divide_round() {
use rand::Rng;
let mut rng = rand::thread_rng();
const NB_TESTS: usize = 1_000_000_000;
const SCALING: f64 = u64::MAX as f64;
for _ in 0..NB_TESTS {
let num: f64 = rng.gen();
let mut denom = 0.0f64;
while denom == 0.0f64 {
denom = rng.gen();
}
let num = (num * SCALING).round();
let denom = (denom * SCALING).round();
let rounded = (num / denom).round();
let expected_rounded_u64: u64 = rounded as u64;
let num_u64: u64 = num as u64;
let denom_u64: u64 = denom as u64;
// sanity check
assert_eq!(num, num_u64 as f64);
assert_eq!(denom, denom_u64 as f64);
let rounded_u64 = divide_round(num_u64, denom_u64);
assert_eq!(expected_rounded_u64, rounded_u64);
}
}

View File

@@ -25,6 +25,7 @@ pub mod lwe_programmable_bootstrapping;
pub mod lwe_public_key_generation;
pub mod lwe_secret_key_generation;
pub mod lwe_wopbs;
pub mod misc;
pub mod polynomial_algorithms;
pub mod seeded_ggsw_ciphertext_decompression;
pub mod seeded_ggsw_ciphertext_list_decompression;
@@ -37,6 +38,9 @@ pub mod seeded_lwe_keyswitch_key_decompression;
pub mod seeded_lwe_public_key_decompression;
pub mod slice_algorithms;
#[cfg(test)]
mod test;
// No pub use for slice and polynomial algorithms which would not interest higher level users
// They can still be used via `use crate::core_crypto::algorithms::slice_algorithms::*;`
pub use ggsw_conversion::*;
@@ -62,6 +66,7 @@ pub use lwe_programmable_bootstrapping::*;
pub use lwe_public_key_generation::*;
pub use lwe_secret_key_generation::*;
pub use lwe_wopbs::*;
pub use misc::*;
pub use seeded_ggsw_ciphertext_decompression::*;
pub use seeded_ggsw_ciphertext_list_decompression::*;
pub use seeded_glwe_ciphertext_decompression::*;

View File

@@ -1,5 +1,6 @@
//! Module with primitives pertaining to [`SeededLweCiphertext`] decompression.
use crate::core_crypto::algorithms::slice_algorithms::slice_wrapping_rem_assign;
use crate::core_crypto::commons::math::random::RandomGenerator;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
@@ -15,11 +16,27 @@ pub fn decompress_seeded_lwe_ciphertext_with_existing_generator<Scalar, OutputCo
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert_eq!(
output_lwe.ciphertext_modulus(),
input_seeded_lwe.ciphertext_modulus(),
"Mismatched CiphertextModulus \
between input SeededLweCiphertext ({:?}) and output LweCiphertext ({:?})",
input_seeded_lwe.ciphertext_modulus(),
output_lwe.ciphertext_modulus(),
);
let ciphertext_modulus = output_lwe.ciphertext_modulus();
let (mut output_mask, output_body) = output_lwe.get_mut_mask_and_body();
// generate a uniformly random mask
generator.fill_slice_with_random_uniform(output_mask.as_mut());
*output_body.0 = *input_seeded_lwe.get_body().0
*output_body.data = *input_seeded_lwe.get_body().data;
if !ciphertext_modulus.is_native_modulus() {
// output_modulus < native modulus always, so we can cast the u128 modulus to the smaller
// type and compute in the smaller type
slice_wrapping_rem_assign(output_lwe.as_mut(), ciphertext_modulus.get().cast_into());
}
}
/// Decompress a [`SeededLweCiphertext`], without consuming it, into a standard
@@ -32,6 +49,15 @@ pub fn decompress_seeded_lwe_ciphertext<Scalar, OutputCont, Gen>(
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert_eq!(
output_lwe.ciphertext_modulus(),
input_seeded_lwe.ciphertext_modulus(),
"Mismatched CiphertextModulus \
between input SeededLweCiphertext ({:?}) and output LweCiphertext ({:?})",
input_seeded_lwe.ciphertext_modulus(),
output_lwe.ciphertext_modulus(),
);
let mut generator = RandomGenerator::<Gen>::new(input_seeded_lwe.compression_seed().seed);
decompress_seeded_lwe_ciphertext_with_existing_generator::<_, _, Gen>(
output_lwe,

View File

@@ -1,5 +1,6 @@
//! Module with primitives pertaining to [`SeededLweCiphertextList`] decompression.
use crate::core_crypto::algorithms::slice_algorithms::slice_wrapping_rem_assign;
use crate::core_crypto::commons::math::random::RandomGenerator;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
@@ -21,12 +22,29 @@ pub fn decompress_seeded_lwe_ciphertext_list_with_existing_generator<
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert_eq!(
output_list.ciphertext_modulus(),
input_seeded_list.ciphertext_modulus(),
"Mismatched CiphertextModulus \
between input SeededLweCiphertextList ({:?}) and output LweCiphertextList ({:?})",
input_seeded_list.ciphertext_modulus(),
output_list.ciphertext_modulus(),
);
let ciphertext_modulus = output_list.ciphertext_modulus();
for (mut lwe_out, body_in) in output_list.iter_mut().zip(input_seeded_list.iter()) {
let (mut output_mask, output_body) = lwe_out.get_mut_mask_and_body();
// generate a uniformly random mask
generator.fill_slice_with_random_uniform(output_mask.as_mut());
*output_body.0 = *body_in.0;
*output_body.data = *body_in.data;
if !ciphertext_modulus.is_native_modulus() {
// output_modulus < native modulus always, so we can cast the u128 modulus to the
// smaller type and compute in the smaller type
slice_wrapping_rem_assign(lwe_out.as_mut(), ciphertext_modulus.get().cast_into());
}
}
}
@@ -41,6 +59,15 @@ pub fn decompress_seeded_lwe_ciphertext_list<Scalar, InputCont, OutputCont, Gen>
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert_eq!(
output_list.ciphertext_modulus(),
input_seeded_list.ciphertext_modulus(),
"Mismatched CiphertextModulus \
between input SeededLweCiphertextList ({:?}) and output LweCiphertextList ({:?})",
input_seeded_list.ciphertext_modulus(),
output_list.ciphertext_modulus(),
);
let mut generator = RandomGenerator::<Gen>::new(input_seeded_list.compression_seed().seed);
decompress_seeded_lwe_ciphertext_list_with_existing_generator::<_, _, _, Gen>(
output_list,

View File

@@ -40,6 +40,10 @@ pub fn decompress_seeded_lwe_keyswitch_key<Scalar, InputCont, OutputCont, Gen>(
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert!(
output_ksk.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
let mut generator = RandomGenerator::<Gen>::new(input_ksk.compression_seed().seed);
decompress_seeded_lwe_keyswitch_key_with_existing_generator::<_, _, _, Gen>(
output_ksk,

View File

@@ -16,6 +16,15 @@ pub fn decompress_seeded_lwe_public_key<Scalar, InputCont, OutputCont, Gen>(
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert_eq!(
output_pk.ciphertext_modulus(),
input_pk.ciphertext_modulus(),
"Mismatched CiphertextModulus \
between input SeededLwePublicKey ({:?}) and output LwePublicKey ({:?})",
output_pk.ciphertext_modulus(),
input_pk.ciphertext_modulus(),
);
let mut generator = RandomGenerator::<Gen>::new(input_pk.compression_seed().seed);
decompress_seeded_lwe_ciphertext_list_with_existing_generator::<_, _, _, Gen>(
output_pk,

View File

@@ -36,6 +36,32 @@ where
})
}
/// This primitive is meant to manage the dot product of values that were cast to a bigger type, for
/// example u64 to u128, avoiding overflow on each multiplication (as u64::MAX * u64::MAX <
/// u128::MAX )
pub fn slice_wrapping_dot_product_custom_modulus<Scalar>(
lhs: &[Scalar],
rhs: &[Scalar],
modulus: Scalar,
) -> Scalar
where
Scalar: UnsignedInteger,
{
assert!(
lhs.len() == rhs.len(),
"lhs (len: {}) and rhs (len: {}) must have the same length",
lhs.len(),
rhs.len()
);
lhs.iter()
.zip(rhs.iter())
.fold(Scalar::ZERO, |acc, (&left, &right)| {
acc.wrapping_add(left.wrapping_mul(right).wrapping_rem(modulus))
.wrapping_rem(modulus)
})
}
/// Add a slice containing unsigned integers to another one element-wise.
///
/// # Note
@@ -254,6 +280,31 @@ pub fn slice_wrapping_sub_scalar_mul_assign<Scalar>(
.for_each(|(lhs, &rhs)| *lhs = (*lhs).wrapping_sub(rhs.wrapping_mul(scalar)));
}
/// This primitive is meant to manage the sub_scalar_mul operation for values that were cast to a
/// bigger type, for example u64 to u128, avoiding overflow on each multiplication (as u64::MAX *
/// u64::MAX < u128::MAX )
pub fn slice_wrapping_sub_scalar_mul_assign_custom_modulus<Scalar>(
lhs: &mut [Scalar],
rhs: &[Scalar],
scalar: Scalar,
modulus: Scalar,
) where
Scalar: UnsignedInteger,
{
assert!(
lhs.len() == rhs.len(),
"lhs (len: {}) and rhs (len: {}) must have the same length",
lhs.len(),
rhs.len()
);
lhs.iter_mut().zip(rhs.iter()).for_each(|(lhs, &rhs)| {
*lhs = (*lhs)
.wrapping_add(modulus)
.wrapping_sub(rhs.wrapping_mul(scalar).wrapping_rem(modulus))
.wrapping_rem(modulus)
});
}
/// Compute the opposite of a slice containing unsigned integers, element-wise and in place.
///
/// # Note
@@ -266,10 +317,10 @@ pub fn slice_wrapping_sub_scalar_mul_assign<Scalar>(
/// ```
/// use tfhe::core_crypto::algorithms::slice_algorithms::*;
/// let mut first = vec![1u8, 2, 3, 4, 5, 6];
/// slice_wrapping_opposite_assign(&mut first);
/// slice_wrapping_opposite_assign_native_mod(&mut first);
/// assert_eq!(&first, &[255u8, 254, 253, 252, 251, 250]);
/// ```
pub fn slice_wrapping_opposite_assign<Scalar>(slice: &mut [Scalar])
pub fn slice_wrapping_opposite_assign_native_mod<Scalar>(slice: &mut [Scalar])
where
Scalar: UnsignedInteger,
{
@@ -278,6 +329,18 @@ where
.for_each(|elt| *elt = (*elt).wrapping_neg());
}
/// This primitive is meant to compute the modular opposite of values for non native moduli.
pub fn slice_wrapping_opposite_assign_custom_mod<Scalar>(slice: &mut [Scalar], modulus: Scalar)
where
Scalar: UnsignedInteger,
{
slice.as_mut().iter_mut().for_each(|x| {
*x = modulus
.wrapping_sub(*x)
.wrapping_rem(modulus)
});
}
/// Multiply a slice containing unsigned integers by a scalar, element-wise and in place.
///
/// # Note
@@ -301,3 +364,29 @@ where
lhs.iter_mut()
.for_each(|lhs| *lhs = (*lhs).wrapping_mul(rhs));
}
/// Compute the reaminder of a slice containing unsigned integers by a scalar, element-wise and in
/// place.
///
/// # Note
///
/// Computations wrap around (similar to computing modulo $2^{n\_{bits}}$) when exceeding the
/// unsigned integer capacity.
///
/// # Example
///
/// ```
/// use tfhe::core_crypto::algorithms::slice_algorithms::*;
/// let mut first = vec![1u8, 2, 3, 4, 5, 6];
/// let modulus = 3;
/// slice_wrapping_rem_assign(&mut first, modulus);
/// assert_eq!(&first, &[1, 2, 0, 1, 2, 0]);
/// ```
pub fn slice_wrapping_rem_assign<Scalar>(slice: &mut [Scalar], modulus: Scalar)
where
Scalar: UnsignedInteger,
{
slice
.iter_mut()
.for_each(|x| *x = (*x).wrapping_rem(modulus))
}

View File

@@ -0,0 +1,829 @@
use super::*;
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::commons::test_tools;
fn test_parallel_and_seeded_lwe_list_encryption_equivalence<Scalar: UnsignedTorus + Sync + Send>(
params: TestParams<Scalar>,
) {
// DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
// computations
// Define parameters for LweCiphertext creation
let lwe_dimension = params.lwe_dimension;
let lwe_ciphertext_count = LweCiphertextCount(10);
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
// Create the PRNG
let mut seeder = new_seeder();
let seeder = seeder.as_mut();
let main_seed = seeder.seed();
let mut secret_generator =
SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
const NB_TESTS: usize = 10;
for _ in 0..NB_TESTS {
// Create the LweSecretKey
let lwe_secret_key =
allocate_and_generate_new_binary_lwe_secret_key(lwe_dimension, &mut secret_generator);
// Create the plaintext
let msg: Scalar = test_tools::random_uint_between(Scalar::ZERO..Scalar::TWO.shl(2));
let encoded_msg = msg << 60;
let plaintext_list =
PlaintextList::new(encoded_msg, PlaintextCount(lwe_ciphertext_count.0));
// Create a new LweCiphertextList
let mut par_lwe_list = LweCiphertextList::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
ciphertext_modulus,
);
let mut determinisitic_seeder =
DeterministicSeeder::<ActivatedRandomGenerator>::new(main_seed);
let mut encryption_generator = EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(
determinisitic_seeder.seed(),
&mut determinisitic_seeder,
);
par_encrypt_lwe_ciphertext_list(
&lwe_secret_key,
&mut par_lwe_list,
&plaintext_list,
lwe_modular_std_dev,
&mut encryption_generator,
);
let mut ser_lwe_list = LweCiphertextList::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
ciphertext_modulus,
);
let mut determinisitic_seeder =
DeterministicSeeder::<ActivatedRandomGenerator>::new(main_seed);
let mut encryption_generator = EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(
determinisitic_seeder.seed(),
&mut determinisitic_seeder,
);
encrypt_lwe_ciphertext_list(
&lwe_secret_key,
&mut ser_lwe_list,
&plaintext_list,
lwe_modular_std_dev,
&mut encryption_generator,
);
assert_eq!(par_lwe_list, ser_lwe_list);
let mut determinisitic_seeder =
DeterministicSeeder::<ActivatedRandomGenerator>::new(main_seed);
// Create a new LweCiphertextList
let mut par_seeded_lwe_list = SeededLweCiphertextList::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
determinisitic_seeder.seed().into(),
ciphertext_modulus,
);
par_encrypt_seeded_lwe_ciphertext_list(
&lwe_secret_key,
&mut par_seeded_lwe_list,
&plaintext_list,
lwe_modular_std_dev,
&mut determinisitic_seeder,
);
let mut determinisitic_seeder =
DeterministicSeeder::<ActivatedRandomGenerator>::new(main_seed);
let mut ser_seeded_lwe_list = SeededLweCiphertextList::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
determinisitic_seeder.seed().into(),
ciphertext_modulus,
);
encrypt_seeded_lwe_ciphertext_list(
&lwe_secret_key,
&mut ser_seeded_lwe_list,
&plaintext_list,
lwe_modular_std_dev,
&mut determinisitic_seeder,
);
assert_eq!(par_seeded_lwe_list, ser_seeded_lwe_list);
let decompressed_lwe_list = ser_seeded_lwe_list.decompress_into_lwe_ciphertext_list();
assert_eq!(decompressed_lwe_list, ser_lwe_list);
}
}
#[test]
fn test_parallel_and_seeded_lwe_list_encryption_equivalence_native_mod_u64() {
test_parallel_and_seeded_lwe_list_encryption_equivalence(TEST_PARAMS_4_BITS_NATIVE_U64);
}
#[test]
fn test_parallel_and_seeded_lwe_list_encryption_equivalence_non_native_power_of_2_mod_u64() {
test_parallel_and_seeded_lwe_list_encryption_equivalence(TEST_PARAMS_3_BITS_63_U64);
}
#[test]
fn test_parallel_and_seeded_lwe_list_encryption_equivalence_native_mod_u32() {
test_parallel_and_seeded_lwe_list_encryption_equivalence(DUMMY_NATIVE_U32);
}
#[test]
fn test_parallel_and_seeded_lwe_list_encryption_equivalence_non_native_power_of_2_mod_u32() {
test_parallel_and_seeded_lwe_list_encryption_equivalence(DUMMY_31_U32);
}
fn lwe_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded);
}
}
}
create_parametrized_test!(lwe_encrypt_decrypt_custom_mod);
fn lwe_allocate_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let plaintext = Plaintext(msg * delta);
let ct = allocate_and_encrypt_new_lwe_ciphertext(
&lwe_sk,
plaintext,
lwe_modular_std_dev,
ciphertext_modulus,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded);
}
}
}
create_parametrized_test!(lwe_allocate_encrypt_decrypt_custom_mod);
fn lwe_trivial_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
trivially_encrypt_lwe_ciphertext(&mut ct, plaintext);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded);
}
}
}
create_parametrized_test!(lwe_trivial_encrypt_decrypt_custom_mod);
fn lwe_allocate_trivial_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
params: TestParams<Scalar>,
) {
let lwe_dimension = params.lwe_dimension;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let plaintext = Plaintext(msg * delta);
let ct = allocate_and_trivially_encrypt_new_lwe_ciphertext(
lwe_dimension.to_lwe_size(),
plaintext,
ciphertext_modulus,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded);
}
}
}
create_parametrized_test!(lwe_allocate_trivial_encrypt_decrypt_custom_mod);
fn lwe_list_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let ct_count = LweCiphertextCount(10);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut list = LweCiphertextList::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ct_count,
ciphertext_modulus,
);
let encoded_list =
PlaintextList::new(msg * delta, PlaintextCount(list.lwe_ciphertext_count().0));
encrypt_lwe_ciphertext_list(
&lwe_sk,
&mut list,
&encoded_list,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&list, ciphertext_modulus));
let mut plaintext_list =
PlaintextList::new(Scalar::ZERO, PlaintextCount(list.lwe_ciphertext_count().0));
decrypt_lwe_ciphertext_list(&lwe_sk, &list, &mut plaintext_list);
let mut decoded = vec![Scalar::ZERO; plaintext_list.plaintext_count().0];
decoded
.iter_mut()
.zip(plaintext_list.iter())
.for_each(|(dst, src)| *dst = round_decode(*src.0, delta) % msg_modulus);
assert!(decoded.iter().all(|&x| x == msg));
}
}
}
create_parametrized_test!(lwe_list_encrypt_decrypt_custom_mod);
fn lwe_list_par_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus + Sync + Send>(
params: TestParams<Scalar>,
) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let ct_count = LweCiphertextCount(10);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut list = LweCiphertextList::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ct_count,
ciphertext_modulus,
);
let encoded_list =
PlaintextList::new(msg * delta, PlaintextCount(list.lwe_ciphertext_count().0));
par_encrypt_lwe_ciphertext_list(
&lwe_sk,
&mut list,
&encoded_list,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&list, ciphertext_modulus));
let mut plaintext_list =
PlaintextList::new(Scalar::ZERO, PlaintextCount(list.lwe_ciphertext_count().0));
decrypt_lwe_ciphertext_list(&lwe_sk, &list, &mut plaintext_list);
let mut decoded = vec![Scalar::ZERO; plaintext_list.plaintext_count().0];
decoded
.iter_mut()
.zip(plaintext_list.iter())
.for_each(|(dst, src)| *dst = round_decode(*src.0, delta) % msg_modulus);
assert!(decoded.iter().all(|&x| x == msg));
}
}
}
create_parametrized_test!(lwe_list_par_encrypt_decrypt_custom_mod);
fn lwe_public_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let zero_encryption_count = LwePublicKeyZeroEncryptionCount(10);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let pk = allocate_and_generate_new_lwe_public_key(
&lwe_sk,
zero_encryption_count,
lwe_modular_std_dev,
ciphertext_modulus,
&mut rsc.encryption_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext_with_public_key(
&pk,
&mut ct,
plaintext,
&mut rsc.secret_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded);
}
}
}
create_parametrized_test!(lwe_public_encrypt_decrypt_custom_mod);
fn lwe_seeded_public_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let zero_encryption_count = LwePublicKeyZeroEncryptionCount(10);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut seeded_pk = SeededLwePublicKey::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
zero_encryption_count,
rsc.seeder.seed().into(),
ciphertext_modulus,
);
generate_seeded_lwe_public_key(
&lwe_sk,
&mut seeded_pk,
lwe_modular_std_dev,
rsc.seeder.as_mut(),
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext_with_seeded_public_key(
&seeded_pk,
&mut ct,
plaintext,
&mut rsc.secret_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded);
}
}
}
create_parametrized_test!(lwe_seeded_public_encrypt_decrypt_custom_mod);
fn lwe_seeded_list_par_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus + Sync + Send>(
params: TestParams<Scalar>,
) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let ct_count = LweCiphertextCount(10);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut seeded_list = SeededLweCiphertextList::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ct_count,
rsc.seeder.seed().into(),
ciphertext_modulus,
);
let encoded_list = PlaintextList::new(
msg * delta,
PlaintextCount(seeded_list.lwe_ciphertext_count().0),
);
par_encrypt_seeded_lwe_ciphertext_list(
&lwe_sk,
&mut seeded_list,
&encoded_list,
lwe_modular_std_dev,
rsc.seeder.as_mut(),
);
assert!(check_content_respects_mod(&seeded_list, ciphertext_modulus));
let mut plaintext_list = PlaintextList::new(
Scalar::ZERO,
PlaintextCount(seeded_list.lwe_ciphertext_count().0),
);
let lwe_list = seeded_list.decompress_into_lwe_ciphertext_list();
assert!(check_content_respects_mod(&lwe_list, ciphertext_modulus));
decrypt_lwe_ciphertext_list(&lwe_sk, &lwe_list, &mut plaintext_list);
let mut decoded = vec![Scalar::ZERO; plaintext_list.plaintext_count().0];
decoded
.iter_mut()
.zip(plaintext_list.iter())
.for_each(|(dst, src)| *dst = round_decode(*src.0, delta) % msg_modulus);
assert!(decoded.iter().all(|&x| x == msg));
}
}
}
create_parametrized_test!(lwe_seeded_list_par_encrypt_decrypt_custom_mod);
fn lwe_seeded_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut seeded_ct = SeededLweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
rsc.seeder.seed().into(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_seeded_lwe_ciphertext(
&lwe_sk,
&mut seeded_ct,
plaintext,
lwe_modular_std_dev,
rsc.seeder.as_mut(),
);
assert!(check_scalar_respects_mod(
*seeded_ct.get_body().data,
ciphertext_modulus
));
let ct = seeded_ct.decompress_into_lwe_ciphertext();
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded);
}
}
}
create_parametrized_test!(lwe_seeded_encrypt_decrypt_custom_mod);
fn lwe_seeded_allocate_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
params: TestParams<Scalar>,
) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let plaintext = Plaintext(msg * delta);
let seeded_ct = allocate_and_encrypt_new_seeded_lwe_ciphertext(
&lwe_sk,
plaintext,
lwe_modular_std_dev,
ciphertext_modulus,
rsc.seeder.as_mut(),
);
assert!(check_scalar_respects_mod(
*seeded_ct.get_body().data,
ciphertext_modulus
));
let ct = seeded_ct.decompress_into_lwe_ciphertext();
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded);
}
}
}
create_parametrized_test!(lwe_seeded_allocate_encrypt_decrypt_custom_mod);
#[test]
fn test_u128_encryption() {
// DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
// computations
// Define parameters for LweCiphertext creation
let lwe_dimension = LweDimension(742);
let lwe_modular_std_dev = StandardDev(4.998_277_131_225_527e-11);
// Create the PRNG
let mut seeder = new_seeder();
let seeder = seeder.as_mut();
let mut encryption_generator =
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
let mut secret_generator =
SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
const NB_TESTS: usize = 10;
const MSG_BITS: u32 = 4;
for _ in 0..NB_TESTS {
for msg in 0..2u128.pow(MSG_BITS) {
// Create the LweSecretKey
let lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut secret_generator,
);
// Create the plaintext
const ENCODING: u32 = u128::BITS - MSG_BITS;
let plaintext = Plaintext(msg << ENCODING);
// Create a new LweCiphertext
let mut lwe = LweCiphertext::new(
0u128,
lwe_dimension.to_lwe_size(),
CiphertextModulus::new_native(),
);
encrypt_lwe_ciphertext(
&lwe_secret_key,
&mut lwe,
plaintext,
lwe_modular_std_dev,
&mut encryption_generator,
);
let decrypted_plaintext = decrypt_lwe_ciphertext(&lwe_secret_key, &lwe);
// Round and remove encoding
// First create a decomposer working on the high 4 bits corresponding to our
// encoding.
let decomposer =
SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
let rounded = decomposer.closest_representable(decrypted_plaintext.0);
// Remove the encoding
let cleartext = rounded >> ENCODING;
// Check we recovered the original message
assert_eq!(cleartext, msg);
}
}
}

View File

@@ -0,0 +1,97 @@
use super::*;
fn lwe_encrypt_ks_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let glwe_dimension = params.glwe_dimension;
let polynomial_size = params.polynomial_size;
let ks_decomp_base_log = params.ks_base_log;
let ks_decomp_level_count = params.ks_level;
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar =
divide_round(encoding_with_padding, cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let glwe_sk = allocate_and_generate_new_binary_glwe_secret_key(
glwe_dimension,
polynomial_size,
&mut rsc.secret_random_generator,
);
let big_lwe_sk = glwe_sk.into_lwe_secret_key();
let ksk_big_to_small = allocate_and_generate_new_lwe_keyswitch_key(
&big_lwe_sk,
&lwe_sk,
ks_decomp_base_log,
ks_decomp_level_count,
lwe_modular_std_dev,
ciphertext_modulus,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(
&ksk_big_to_small,
ciphertext_modulus
));
let plaintext = Plaintext(msg * delta);
let ct = allocate_and_encrypt_new_lwe_ciphertext(
&big_lwe_sk,
plaintext,
lwe_modular_std_dev,
ciphertext_modulus,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let mut output_ct = LweCiphertext::new(
Scalar::ZERO,
lwe_sk.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
keyswitch_lwe_ciphertext(&ksk_big_to_small, &ct, &mut output_ct);
assert!(check_content_respects_mod(&output_ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &output_ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded);
}
}
}
#[test]
fn lwe_encrypt_ks_decrypt_native_mod() {
lwe_encrypt_ks_decrypt_custom_mod(TEST_PARAMS_4_BITS_NATIVE_U64);
}
#[test]
fn lwe_encrypt_ks_decrypt_non_native_mod() {
lwe_encrypt_ks_decrypt_custom_mod(TEST_PARAMS_3_BITS_63_U64);
}
#[test]
fn lwe_encrypt_ks_decrypt_solinas_mod() {
lwe_encrypt_ks_decrypt_custom_mod(TEST_PARAMS_3_BITS_SOLINAS_U64);
}

View File

@@ -0,0 +1,531 @@
use super::*;
fn lwe_encrypt_add_assign_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let rhs = ct.clone();
lwe_ciphertext_add_assign(&mut ct, &rhs);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!((msg + msg) % msg_modulus, decoded);
}
}
}
create_parametrized_test!(lwe_encrypt_add_assign_decrypt_custom_mod);
fn lwe_encrypt_add_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let mut res = ct.clone();
lwe_ciphertext_add(&mut res, &ct, &ct);
assert!(check_content_respects_mod(&res, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &res);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!((msg + msg) % msg_modulus, decoded);
}
}
}
create_parametrized_test!(lwe_encrypt_add_decrypt_custom_mod);
fn lwe_encrypt_plaintext_add_assign_decrypt_custom_mod<Scalar: UnsignedTorus>(
params: TestParams<Scalar>,
) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
lwe_ciphertext_plaintext_add_assign(&mut ct, plaintext);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!((msg + msg) % msg_modulus, decoded);
}
}
}
create_parametrized_test!(lwe_encrypt_plaintext_add_assign_decrypt_custom_mod);
fn lwe_encrypt_plaintext_sub_assign_decrypt_custom_mod<Scalar: UnsignedTorus>(
params: TestParams<Scalar>,
) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
lwe_ciphertext_plaintext_sub_assign(&mut ct, plaintext);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(Scalar::ZERO, decoded);
}
}
}
create_parametrized_test!(lwe_encrypt_plaintext_sub_assign_decrypt_custom_mod);
fn lwe_encrypt_plaintext_opposite_assign_decrypt_custom_mod<Scalar: UnsignedTorus>(
params: TestParams<Scalar>,
) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
lwe_ciphertext_opposite_assign(&mut ct);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg.wrapping_neg() % msg_modulus, decoded);
}
}
}
create_parametrized_test!(lwe_encrypt_plaintext_opposite_assign_decrypt_custom_mod);
fn lwe_encrypt_ciphertext_cleartext_mul_assign_decrypt_custom_mod<Scalar: UnsignedTorus>(
params: TestParams<Scalar>,
) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
let cleartext = Cleartext(Scalar::TWO);
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
lwe_ciphertext_cleartext_mul_assign(&mut ct, cleartext);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg * cleartext.0 % msg_modulus, decoded);
}
}
}
create_parametrized_test!(lwe_encrypt_ciphertext_cleartext_mul_assign_decrypt_custom_mod);
fn lwe_encrypt_cleartext_mul_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
let cleartext = Cleartext(Scalar::TWO);
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let mut res = ct.clone();
lwe_ciphertext_cleartext_mul(&mut res, &ct, cleartext);
assert!(check_content_respects_mod(&res, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &res);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!((msg * cleartext.0) % msg_modulus, decoded);
}
}
}
create_parametrized_test!(lwe_encrypt_cleartext_mul_decrypt_custom_mod);
fn lwe_encrypt_sub_assign_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct1 = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let mut ct2 = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct1,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
let plaintext2 = Plaintext(Scalar::ONE * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct2,
plaintext2,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct1, ciphertext_modulus));
lwe_ciphertext_sub_assign(&mut ct1, &ct2);
assert!(check_content_respects_mod(&ct1, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct1);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!((msg - Scalar::ONE) % msg_modulus, decoded);
}
}
assert!(false);
}
create_parametrized_test!(lwe_encrypt_sub_assign_decrypt_custom_mod);
fn lwe_encrypt_sub_decrypt_custom_mod<Scalar: UnsignedTorus>(params: TestParams<Scalar>) {
let lwe_dimension = params.lwe_dimension;
let lwe_modular_std_dev = params.lwe_modular_std_dev;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
let mut msg = msg_modulus;
let delta: Scalar = (encoding_with_padding / cast_into_u128(msg_modulus)).cast_into();
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
for _ in 0..NB_TESTS {
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
lwe_dimension,
&mut rsc.secret_random_generator,
);
let mut ct = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let plaintext = Plaintext(msg * delta);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut ct,
plaintext,
lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&ct, ciphertext_modulus));
let mut res = ct.clone();
lwe_ciphertext_sub(&mut res, &ct, &ct);
assert!(check_content_respects_mod(&res, ciphertext_modulus));
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &res);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(Scalar::ZERO, decoded);
}
}
}
create_parametrized_test!(lwe_encrypt_sub_decrypt_custom_mod);

View File

@@ -0,0 +1,214 @@
use crate::core_crypto::prelude::*;
use paste::paste;
mod lwe_encryption;
mod lwe_keyswitch;
mod lwe_linear_algebra;
pub struct TestResources {
pub seeder: Box<dyn Seeder>,
pub encryption_random_generator: EncryptionRandomGenerator<ActivatedRandomGenerator>,
pub secret_random_generator: SecretRandomGenerator<ActivatedRandomGenerator>,
}
impl TestResources {
pub fn new() -> Self {
let mut seeder = new_seeder();
let encryption_random_generator =
EncryptionRandomGenerator::new(seeder.seed(), seeder.as_mut());
let secret_random_generator = SecretRandomGenerator::new(seeder.seed());
Self {
seeder,
encryption_random_generator,
secret_random_generator,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct TestParams<Scalar: UnsignedTorus> {
pub lwe_dimension: LweDimension,
pub glwe_dimension: GlweDimension,
pub polynomial_size: PolynomialSize,
pub lwe_modular_std_dev: StandardDev,
pub glwe_modular_std_dev: StandardDev,
pub pbs_base_log: DecompositionBaseLog,
pub pbs_level: DecompositionLevelCount,
pub ks_base_log: DecompositionBaseLog,
pub ks_level: DecompositionLevelCount,
pub pfks_level: DecompositionLevelCount,
pub pfks_base_log: DecompositionBaseLog,
pub pfks_modular_std_dev: StandardDev,
pub cbs_level: DecompositionLevelCount,
pub cbs_base_log: DecompositionBaseLog,
pub message_modulus_log: CiphertextModulusLog,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
pub const TEST_PARAMS_4_BITS_NATIVE_U64: TestParams<u64> = TestParams {
lwe_dimension: LweDimension(742),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
lwe_modular_std_dev: StandardDev(0.000007069849454709433),
glwe_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ks_level: DecompositionLevelCount(5),
ks_base_log: DecompositionBaseLog(3),
pfks_level: DecompositionLevelCount(1),
pfks_base_log: DecompositionBaseLog(23),
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const TEST_PARAMS_3_BITS_63_U64: TestParams<u64> = TestParams {
lwe_dimension: LweDimension(742),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
lwe_modular_std_dev: StandardDev(0.000007069849454709433),
glwe_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ks_level: DecompositionLevelCount(5),
ks_base_log: DecompositionBaseLog(3),
pfks_level: DecompositionLevelCount(1),
pfks_base_log: DecompositionBaseLog(23),
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(3),
ciphertext_modulus: CiphertextModulus::new_unchecked(1 << 63),
};
pub const TEST_PARAMS_3_BITS_SOLINAS_U64: TestParams<u64> = TestParams {
lwe_dimension: LweDimension(742),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
lwe_modular_std_dev: StandardDev(0.000007069849454709433),
glwe_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ks_level: DecompositionLevelCount(5),
ks_base_log: DecompositionBaseLog(3),
pfks_level: DecompositionLevelCount(1),
pfks_base_log: DecompositionBaseLog(23),
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(3),
ciphertext_modulus: CiphertextModulus::new_unchecked((1 << 64) - (1 << 32) + 1),
};
pub const DUMMY_NATIVE_U32: TestParams<u32> = TestParams {
lwe_dimension: LweDimension(742),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
lwe_modular_std_dev: StandardDev(0.000007069849454709433),
glwe_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ks_level: DecompositionLevelCount(5),
ks_base_log: DecompositionBaseLog(3),
pfks_level: DecompositionLevelCount(1),
pfks_base_log: DecompositionBaseLog(23),
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const DUMMY_31_U32: TestParams<u32> = TestParams {
lwe_dimension: LweDimension(742),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
lwe_modular_std_dev: StandardDev(0.000007069849454709433),
glwe_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ks_level: DecompositionLevelCount(5),
ks_base_log: DecompositionBaseLog(3),
pfks_level: DecompositionLevelCount(1),
pfks_base_log: DecompositionBaseLog(23),
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(3),
ciphertext_modulus: CiphertextModulus::new_unchecked(1 << 31),
};
pub fn cast_into_u128<Scalar: CastInto<u128>>(val: Scalar) -> u128 {
val.cast_into()
}
pub fn check_content_respects_mod<Scalar: UnsignedInteger, Input: AsRef<[Scalar]>>(
input: &Input,
modulus: CiphertextModulus<Scalar>,
) -> bool {
if !modulus.is_native_modulus() {
return input
.as_ref()
.iter()
.all(|&x| cast_into_u128(x) < modulus.get());
}
true
}
pub fn check_scalar_respects_mod<Scalar: UnsignedInteger>(
input: Scalar,
modulus: CiphertextModulus<Scalar>,
) -> bool {
if !modulus.is_native_modulus() {
return cast_into_u128(input) < modulus.get();
}
true
}
pub fn get_encoding_with_padding<Scalar: UnsignedInteger>(
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> u128 {
if ciphertext_modulus.is_native_modulus() {
1 << (Scalar::BITS - 1)
} else {
ciphertext_modulus.get() / 2
}
}
pub fn round_decode<Scalar: UnsignedInteger>(decrypted: Scalar, delta: Scalar) -> Scalar {
// Get half interval on the discretized torus
let rounding_margin = delta.wrapping_div(Scalar::TWO);
// Add the half interval mapping
// [delta * (m - 1/2); delta * (m + 1/2)[ to [delta * m; delta * (m + 1)[
// Dividing by delta gives m which is what we want
(decrypted.wrapping_add(rounding_margin)).wrapping_div(delta)
}
// Macro to generate tests for all parameter sets
macro_rules! create_parametrized_test{
($name:ident { $($param:ident),* }) => {
paste! {
$(
#[test]
fn [<test_ $name _ $param:lower>]() {
$name($param)
}
)*
}
};
($name:ident)=> {
create_parametrized_test!($name
{
TEST_PARAMS_4_BITS_NATIVE_U64,
TEST_PARAMS_3_BITS_63_U64,
TEST_PARAMS_3_BITS_SOLINAS_U64
});
};
}
pub(self) use create_parametrized_test;

View File

@@ -0,0 +1,201 @@
//! Module containing the definition of the [`CiphertextModulus`].
use crate::core_crypto::commons::traits::UnsignedInteger;
use std::marker::PhantomData;
#[derive(Clone, Copy, PartialEq, Eq)]
/// A value of 0 is always interpreted as a native modulus, this is useful to work with u128 using
/// the native modulus as $2^{128}$ cannot be stored in a u128 value.
///
/// This also allows to not rely on an enum which would require a discriminant field adding 8 bytes
/// to store 1 bit of information (native variant vs custom variant with u128 payload).
pub struct CiphertextModulus<Scalar: UnsignedInteger>(u128, PhantomData<Scalar>);
#[derive(serde::Serialize, serde::Deserialize)]
struct SerialiazableLweCiphertextModulus {
pub modulus: u128,
pub scalar_bits: usize,
}
// Manual impl to be able to carry the UnsignedInteger bitwidth information
impl<Scalar: UnsignedInteger> serde::Serialize for CiphertextModulus<Scalar> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
SerialiazableLweCiphertextModulus {
modulus: self.get(),
scalar_bits: Scalar::BITS,
}
.serialize(serializer)
}
}
impl<'de, Scalar: UnsignedInteger> serde::Deserialize<'de> for CiphertextModulus<Scalar> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let thing = SerialiazableLweCiphertextModulus::deserialize(deserializer)
.map_err(serde::de::Error::custom)?;
if thing.scalar_bits != Scalar::BITS {
return Err(serde::de::Error::custom(format!(
"Expected an unsigned integer with {} bits, \
found {} bits during deserialization of CiphertextModulus, \
have you mixed types during deserialization?",
Scalar::BITS,
thing.scalar_bits
)));
}
Ok(CiphertextModulus(thing.modulus, PhantomData))
}
}
impl<Scalar: UnsignedInteger> CiphertextModulus<Scalar> {
pub const fn try_new(modulus: u128) -> Result<Self, &'static str> {
if (Scalar::BITS < 128) && (modulus > (1 << Scalar::BITS)) {
return Err("Modulus is bigger than the maximum value of the associated Scalar type");
}
Ok(Self(modulus, PhantomData).canonicalize())
}
pub const fn new_native() -> Self {
Self(0, PhantomData)
}
#[cfg(test)]
pub const fn new_unchecked(modulus: u128) -> Self {
Self(modulus, PhantomData)
}
#[inline]
/// Return the u128 value storing the modulus. This returns 0 if the modulus is the native
/// modulus of the associated scalar type.
pub const fn get(&self) -> u128 {
self.0
}
pub const fn get_non_canonical(&self) -> u128 {
if self.is_native_modulus() {
1 << Scalar::BITS
} else {
self.get()
}
}
pub const fn canonicalize(self) -> Self {
if self.is_native_modulus() {
Self(0, PhantomData)
} else {
self
}
}
/// Depending on the Scalar type used in the call, this function will determine whether the
/// current modulus is the native modulus of the given Scalar type allowing for more efficient
/// implementations than can rely on wrapping arithmetic operations behavior to compute the
/// modulus.
pub const fn is_native_modulus(&self) -> bool {
if self.0 == 0 {
return true;
}
if Scalar::BITS < 128 {
return self.0 == (1 << Scalar::BITS);
}
false
}
pub const fn is_compatible_with_native_modulus(&self) -> bool {
self.is_native_modulus() || self.is_power_of_two()
}
pub const fn is_power_of_two(&self) -> bool {
self.0.is_power_of_two()
}
pub const fn is_odd(&self) -> bool {
self.0 % 2 == 1
}
}
impl<Scalar: UnsignedInteger> std::fmt::Display for CiphertextModulus<Scalar> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_native_modulus() {
write!(f, "CiphertextModulus(2^{})", Scalar::BITS)
} else {
write!(f, "CiphertextModulus({})", self.0)
}
}
}
impl<Scalar: UnsignedInteger> std::fmt::Debug for CiphertextModulus<Scalar> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as std::fmt::Display>::fmt(self, f)
}
}
#[cfg(test)]
mod tests {
use crate::core_crypto::prelude::CiphertextModulus;
#[test]
fn test_modulus_struct() {
{
let mod_32_res = CiphertextModulus::<u32>::try_new(0);
assert!(mod_32_res.is_ok());
let mod_32 = mod_32_res.unwrap();
assert!(mod_32.is_native_modulus());
let std_fmt = format!("{mod_32}");
assert_eq!(&std_fmt, "CiphertextModulus(2^32)");
let dbg_fmt = format!("{mod_32:?}");
assert_eq!(&dbg_fmt, "CiphertextModulus(2^32)");
}
{
let mod_32_res = CiphertextModulus::<u32>::try_new(1 << 32);
assert!(mod_32_res.is_ok());
let mod_32 = mod_32_res.unwrap();
assert!(mod_32.is_native_modulus());
let std_fmt = format!("{mod_32}");
assert_eq!(&std_fmt, "CiphertextModulus(2^32)");
let dbg_fmt = format!("{mod_32:?}");
assert_eq!(&dbg_fmt, "CiphertextModulus(2^32)");
}
{
let bad_mod_32 = CiphertextModulus::<u32>::try_new(1 << 64);
assert!(bad_mod_32.is_err());
match bad_mod_32 {
Ok(_) => unreachable!(),
Err(e) => assert_eq!(
e,
"Modulus is bigger than the maximum value of the associated Scalar type"
),
}
}
{
let native_mod_128 = CiphertextModulus::<u128>::new_native();
assert!(native_mod_128.is_native_modulus());
}
{
let mod_128_res = CiphertextModulus::<u128>::try_new(1234567890);
assert!(mod_128_res.is_ok());
let mod_128 = mod_128_res.unwrap();
assert_eq!(mod_128.get(), 1234567890);
}
}
}

View File

@@ -6,12 +6,12 @@ use crate::core_crypto::commons::math::random::{
Seed, Seeder, Uniform,
};
use crate::core_crypto::commons::math::torus::UnsignedTorus;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::numeric::{CastInto, UnsignedInteger};
#[cfg(feature = "experimental-multi_bit_pbs")]
use crate::core_crypto::commons::parameters::LweBskGroupingFactor;
use crate::core_crypto::commons::parameters::{
DecompositionLevelCount, FunctionalPackingKeyswitchKeyCount, GlweDimension, GlweSize,
LweCiphertextCount, LweDimension, LweSize, PolynomialSize,
CiphertextModulus, DecompositionLevelCount, FunctionalPackingKeyswitchKeyCount, GlweDimension,
GlweSize, LweCiphertextCount, LweDimension, LweSize, PolynomialSize,
};
use concrete_csprng::generators::ForkError;
use rayon::prelude::*;
@@ -197,6 +197,18 @@ impl<G: ByteRandomGenerator> EncryptionRandomGenerator<G> {
self.mask.fill_slice_with_random_uniform(output)
}
// Fills the slice with random uniform values, using the mask generator
pub(crate) fn fill_slice_with_random_mask_custom_mod<Scalar>(
&mut self,
output: &mut [Scalar],
ciphertext_modulus: CiphertextModulus<Scalar>,
) where
Scalar: UnsignedInteger + RandomGenerable<Uniform>,
{
self.mask
.fill_slice_with_random_uniform_custom_mod(output, ciphertext_modulus);
}
// Sample a noise value, using the noise generator.
pub(crate) fn random_noise<Scalar>(&mut self, std: impl DispersionParameter) -> Scalar
where
@@ -211,6 +223,26 @@ impl<G: ByteRandomGenerator> EncryptionRandomGenerator<G> {
)
}
// Sample a noise value, using the noise generator.
pub(crate) fn random_noise_custom_mod<Scalar>(
&mut self,
std: impl DispersionParameter,
custom_modulus: CiphertextModulus<Scalar>,
) -> Scalar
where
Scalar: UnsignedInteger + RandomGenerable<Gaussian<f64>, CustomModulus = u128>,
{
let custom_modulus_u128 = custom_modulus.get().cast_into();
Scalar::generate_one_custom_modulus(
&mut self.noise,
Gaussian {
std: std.get_standard_dev(),
mean: 0.,
},
custom_modulus_u128,
)
}
// Fills the input slice with random noise, using the noise generator.
pub(crate) fn fill_slice_with_random_noise<Scalar>(
&mut self,
@@ -223,6 +255,24 @@ impl<G: ByteRandomGenerator> EncryptionRandomGenerator<G> {
.fill_slice_with_random_gaussian(output, 0., std.get_standard_dev());
}
// Fills the input slice with random noise, using the noise generator.
pub(crate) fn fill_slice_with_random_noise_custom_mod<Scalar>(
&mut self,
output: &mut [Scalar],
std: impl DispersionParameter,
custom_modulus: CiphertextModulus<Scalar>,
) where
Scalar: UnsignedInteger,
(Scalar, Scalar): RandomGenerable<Gaussian<f64>, CustomModulus = f64>,
{
self.noise.fill_slice_with_random_gaussian_custom_mod(
output,
0.,
std.get_standard_dev(),
custom_modulus,
);
}
// Adds noise on top of existing data for in place encryption
pub(crate) fn unsigned_torus_slice_wrapping_add_random_noise_assign<Scalar>(
&mut self,
@@ -239,6 +289,25 @@ impl<G: ByteRandomGenerator> EncryptionRandomGenerator<G> {
std.get_standard_dev(),
);
}
// Adds noise on top of existing data for in place encryption
pub(crate) fn unsigned_torus_slice_wrapping_add_random_noise_custom_mod_assign<Scalar>(
&mut self,
output: &mut [Scalar],
std: impl DispersionParameter,
custom_modulus: CiphertextModulus<Scalar>,
) where
Scalar: UnsignedTorus,
(Scalar, Scalar): RandomGenerable<Gaussian<f64>, CustomModulus = f64>,
{
self.noise
.unsigned_torus_slice_wrapping_add_random_gaussian_custom_mod_assign(
output,
0.,
std.get_standard_dev(),
custom_modulus,
);
}
}
impl<G: ParallelByteRandomGenerator> EncryptionRandomGenerator<G> {

View File

@@ -1,6 +1,11 @@
use crate::core_crypto::commons::math::decomposition::SignedDecompositionIter;
use crate::core_crypto::algorithms::misc::*;
use crate::core_crypto::commons::math::decomposition::{
SignedDecompositionIter, SignedDecompositionIterNonNative,
};
use crate::core_crypto::commons::numeric::{Numeric, UnsignedInteger};
use crate::core_crypto::commons::parameters::{DecompositionBaseLog, DecompositionLevelCount};
use crate::core_crypto::commons::parameters::{
CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
};
use std::marker::PhantomData;
/// A structure which allows to decompose unsigned integers into a set of smaller terms.
@@ -131,9 +136,11 @@ where
/// assert!(1 <= term.level().0);
/// assert!(term.level().0 <= 3);
/// let signed_term = term.value().into_signed();
/// println!("signed_term: {signed_term}");
/// let half_basis = 2i32.pow(4) / 2i32;
/// println!("half_basis: {half_basis}");
/// assert!(-half_basis <= signed_term);
/// assert!(signed_term < half_basis);
/// assert!(signed_term <= half_basis);
/// }
/// assert_eq!(decomposer.decompose(1).count(), 3);
/// ```
@@ -174,3 +181,218 @@ where
}
}
}
/// A structure which allows to decompose unsigned integers into a set of smaller terms.
///
/// See the [module level](super) documentation for a description of the signed decomposition.
#[derive(Debug)]
pub struct SignedDecomposerNonNative<Scalar>
where
Scalar: UnsignedInteger,
{
pub(crate) base_log: usize,
pub(crate) level_count: usize,
integer_type: PhantomData<Scalar>,
ciphertext_modulus: CiphertextModulus<Scalar>,
}
impl<Scalar> SignedDecomposerNonNative<Scalar>
where
Scalar: UnsignedInteger,
{
/// Create a new decomposer.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::<u64>::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new((1 << 64) - (1 << 32) + 1).unwrap(),
/// );
/// assert_eq!(decomposer.level_count(), DecompositionLevelCount(3));
/// assert_eq!(decomposer.base_log(), DecompositionBaseLog(4));
/// ```
pub fn new(
base_log: DecompositionBaseLog,
level_count: DecompositionLevelCount,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> SignedDecomposerNonNative<Scalar> {
debug_assert!(
Scalar::BITS > base_log.0 * level_count.0,
"Decomposed bits exceeds the size of the integer to be decomposed"
);
SignedDecomposerNonNative {
base_log: base_log.0,
level_count: level_count.0,
integer_type: PhantomData,
ciphertext_modulus,
}
}
/// Return the logarithm in base two of the base of this decomposer.
///
/// If the decomposer uses a base $B=2^b$, this returns $b$.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::<u64>::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new((1 << 64) - (1 << 32) + 1).unwrap(),
/// );
/// assert_eq!(decomposer.base_log(), DecompositionBaseLog(4));
/// ```
pub fn base_log(&self) -> DecompositionBaseLog {
DecompositionBaseLog(self.base_log)
}
/// Return the number of levels of this decomposer.
///
/// If the decomposer uses $l$ levels, this returns $l$.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::<u64>::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new((1 << 64) - (1 << 32) + 1).unwrap(),
/// );
/// assert_eq!(decomposer.level_count(), DecompositionLevelCount(3));
/// ```
pub fn level_count(&self) -> DecompositionLevelCount {
DecompositionLevelCount(self.level_count)
}
/// Return the closet value representable by the decomposition.
///
/// For some input integer `k`, decomposition base `B`, decomposition level count `l` and given
/// ciphertext modulus `q` the performed operation is the following:
///
/// $$
/// \lfloor \frac{k\cdot q}{B^{l}} \rceil \cdot B^{l}
/// $$
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new(1 << 32).unwrap(),
/// );
/// let closest = decomposer.closest_representable(1_340_987_234_u64);
/// assert_eq!(closest, 1_341_128_704_u64);
/// ```
#[inline]
pub fn closest_representable(&self, input: Scalar) -> Scalar {
// Floored approach
// B^l
let base_to_level_count = 1 << (self.base_log * self.level_count);
// sr = floor(q/(B^l))
let smallest_representable = self.ciphertext_modulus.get() / base_to_level_count;
let input_128: u128 = input.cast_into();
// rounded = round(input/sr)
let rounded = divide_round_to_u128(input_128, smallest_representable);
// rounded * sr
let closest_representable = rounded * smallest_representable;
Scalar::cast_from(closest_representable)
}
/// Generate an iterator over the terms of the decomposition of the input.
///
/// # Warning
///
/// The returned iterator yields the terms $\tilde{\theta}\_i$ in order of decreasing $i$.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::numeric::UnsignedInteger;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new((1 << 64) - (1 << 32) + 1).unwrap(),
/// // CiphertextModulus::try_new(1 << 32).unwrap(),
/// );
///
/// for term in decomposer.decompose(1u64 << 63) {
/// assert!(1 <= term.level().0);
/// assert!(term.level().0 <= 3);
/// let signed_term = term.value().into_signed();
/// println!("signed_term: {signed_term}");
/// let half_basis = 2i64.pow(4) / 2i64;
/// println!("half_basis: {half_basis}");
/// assert!(-half_basis <= signed_term);
/// assert!(signed_term <= half_basis);
/// }
/// assert_eq!(decomposer.decompose(1).count(), 3);
/// ```
pub fn decompose(&self, input: Scalar) -> SignedDecompositionIterNonNative<Scalar> {
// Note that there would be no sense of making the decomposition on an input which was
// not rounded to the closest representable first. We then perform it before decomposing.
SignedDecompositionIterNonNative::new(
self.closest_representable(input),
DecompositionBaseLog(self.base_log),
DecompositionLevelCount(self.level_count),
self.ciphertext_modulus,
)
}
/// Recomposes a decomposed value by summing all the terms.
///
/// If the input iterator yields $\tilde{\theta}\_i$, this returns
/// $\sum\_{i=1}^l\tilde{\theta}\_i\frac{q}{B^i}$.
///
/// # Example
///
/// ```
/// use rand::Rng;
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let mut rng = rand::thread_rng();
/// let decomposer = SignedDecomposerNonNative::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new(1 << 32).unwrap(),
/// );
/// let val = 1_340_987_234_u64;
/// let dec = decomposer.decompose(val);
/// let rec = decomposer.recompose(dec);
/// assert_eq!(decomposer.closest_representable(val), rec.unwrap());
/// ```
pub fn recompose(&self, decomp: SignedDecompositionIterNonNative<Scalar>) -> Option<Scalar> {
if decomp.is_fresh() {
Some(decomp.fold(Scalar::ZERO, |acc, term| {
acc.wrapping_add(term.to_recomposition_summand())
}))
} else {
None
}
}
}

View File

@@ -1,6 +1,12 @@
use crate::core_crypto::commons::math::decomposition::{DecompositionLevel, DecompositionTerm};
use crate::core_crypto::commons::math::decomposition::{
DecompositionLevel, DecompositionTerm, DecompositionTermNonNative,
};
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::parameters::{DecompositionBaseLog, DecompositionLevelCount};
use crate::core_crypto::commons::parameters::{
CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
};
// TODO clean up decomposition logic
/// An iterator that yields the terms of the signed decomposition of an integer.
///
@@ -122,3 +128,158 @@ fn decompose_one_level<S: UnsignedInteger>(base_log: usize, state: &mut S, mod_b
*state += carry;
res.wrapping_sub(carry << base_log)
}
/// An iterator that yields the terms of the signed decomposition of an integer.
///
/// # Warning
///
/// This iterator yields the decomposition in reverse order. That means that the highest level
/// will be yielded first.
#[derive(Clone,Debug)]
pub struct SignedDecompositionIterNonNative<T>
where
T: UnsignedInteger,
{
// The base log of the decomposition
base_log: usize,
// The number of levels of the decomposition
level_count: usize,
// The internal state of the decomposition
state: T,
// The current level
current_level: usize,
// A mask which allows to compute the mod B of a value. For B=2^4, this guy is of the form:
// ...0001111
mod_b_mask: T,
// Ciphertext modulus
ciphertext_modulus: CiphertextModulus<T>,
// A flag which store whether the iterator is a fresh one (for the recompose method)
fresh: bool,
}
impl<T> SignedDecompositionIterNonNative<T>
where
T: UnsignedInteger,
{
pub(crate) fn new(
input: T,
base_log: DecompositionBaseLog,
level: DecompositionLevelCount,
ciphertext_modulus: CiphertextModulus<T>,
) -> SignedDecompositionIterNonNative<T> {
let base_to_the_level = 1 << (base_log.0 * level.0);
let smallest_representable = ciphertext_modulus.get() / base_to_the_level;
let input_128: u128 = input.cast_into();
let state = T::cast_from(input_128 / smallest_representable);
SignedDecompositionIterNonNative {
base_log: base_log.0,
level_count: level.0,
state,
current_level: level.0,
mod_b_mask: (T::ONE << base_log.0) - T::ONE,
ciphertext_modulus,
fresh: true,
}
}
pub(crate) fn is_fresh(&self) -> bool {
self.fresh
}
/// Return the logarithm in base two of the base of this decomposition.
///
/// If the decomposition uses a base $B=2^b$, this returns $b$.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new((1 << 64) - (1 << 32) + 1).unwrap(),
/// );
/// let val = 9_223_372_036_854_775_808u64;
/// let decomp = decomposer.decompose(val);
/// assert_eq!(decomp.base_log(), DecompositionBaseLog(4));
/// ```
pub fn base_log(&self) -> DecompositionBaseLog {
DecompositionBaseLog(self.base_log)
}
/// Return the number of levels of this decomposition.
///
/// If the decomposition uses $l$ levels, this returns $l$.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new((1 << 64) - (1 << 32) + 1).unwrap(),
/// );
/// let val = 9_223_372_036_854_775_808u64;
/// let decomp = decomposer.decompose(val);
/// assert_eq!(decomp.level_count(), DecompositionLevelCount(3));
/// ```
pub fn level_count(&self) -> DecompositionLevelCount {
DecompositionLevelCount(self.level_count)
}
}
impl<T> Iterator for SignedDecompositionIterNonNative<T>
where
T: UnsignedInteger,
{
type Item = DecompositionTermNonNative<T>;
fn next(&mut self) -> Option<Self::Item> {
// The iterator is not fresh anymore
self.fresh = false;
// We check if the decomposition is over
if self.current_level == 0 {
return None;
}
// We decompose the current level
let output = decompose_one_level_non_native(
self.base_log,
&mut self.state,
self.mod_b_mask,
T::cast_from(self.ciphertext_modulus.get()),
);
self.current_level -= 1;
// We return the output for this level
Some(DecompositionTermNonNative::new(
DecompositionLevel(self.current_level + 1),
DecompositionBaseLog(self.base_log),
output,
self.ciphertext_modulus,
))
}
}
fn decompose_one_level_non_native<S: UnsignedInteger>(
base_log: usize,
state: &mut S,
mod_b_mask: S,
ciphertext_modulus: S,
) -> S {
let res = *state & mod_b_mask;
*state >>= base_log;
let mut carry = (res.wrapping_sub(S::ONE) | *state) & res;
carry >>= base_log - 1;
*state += carry;
res.wrapping_add(ciphertext_modulus)
.wrapping_sub(carry << base_log)
.wrapping_rem(ciphertext_modulus)
}

View File

@@ -1,6 +1,6 @@
use crate::core_crypto::commons::math::decomposition::DecompositionLevel;
use crate::core_crypto::commons::numeric::{Numeric, UnsignedInteger};
use crate::core_crypto::commons::parameters::DecompositionBaseLog;
use crate::core_crypto::commons::parameters::{CiphertextModulus, DecompositionBaseLog};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
@@ -91,3 +91,117 @@ where
DecompositionLevel(self.level)
}
}
/// A member of the decomposition.
///
/// If we decompose a value $\theta$ as a sum $\sum\_{i=1}^l\tilde{\theta}\_i\frac{q}{B^i}$, this
/// represents a $\tilde{\theta}\_i$.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct DecompositionTermNonNative<T>
where
T: UnsignedInteger,
{
level: usize,
base_log: usize,
value: T,
ciphertext_modulus: CiphertextModulus<T>,
}
impl<T> DecompositionTermNonNative<T>
where
T: UnsignedInteger,
{
// Creates a new decomposition term.
pub(crate) fn new(
level: DecompositionLevel,
base_log: DecompositionBaseLog,
value: T,
ciphertext_modulus: CiphertextModulus<T>,
) -> DecompositionTermNonNative<T> {
DecompositionTermNonNative {
level: level.0,
base_log: base_log.0,
value,
ciphertext_modulus,
}
}
/// Turn this term into a summand.
///
/// If our member represents one $\tilde{\theta}\_i$ of the decomposition, this method returns
/// $\tilde{\theta}\_i\frac{q}{B^i}$.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new(1 << 32).unwrap(),
/// );
/// let output = decomposer.decompose(2u64.pow(19)).next().unwrap();
/// assert_eq!(output.to_recomposition_summand(), 1048576);
/// ```
pub fn to_recomposition_summand(&self) -> T {
// Floored approach
// * floor(q / B^j)
let base_to_the_level = 1 << (self.base_log * self.level);
let digit_radix = self.ciphertext_modulus.get() / base_to_the_level;
let value_u128: u128 = self.value.cast_into();
let summand_u128 = value_u128 * digit_radix;
T::cast_from(summand_u128)
}
/// Return the value of the term.
///
/// If our member represents one $\tilde{\theta}\_i$, this returns its actual value.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::SignedDecomposerNonNative;
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new(1 << 32).unwrap(),
/// );
/// let output = decomposer.decompose(2u64.pow(19)).next().unwrap();
/// assert_eq!(output.value(), 1);
/// ```
pub fn value(&self) -> T {
self.value
}
/// Return the level of the term.
///
/// If our member represents one $\tilde{\theta}\_i$, this returns the value of $i$.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::commons::math::decomposition::{
/// DecompositionLevel, SignedDecomposerNonNative,
/// };
/// use tfhe::core_crypto::commons::parameters::{
/// CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
/// };
/// let decomposer = SignedDecomposerNonNative::new(
/// DecompositionBaseLog(4),
/// DecompositionLevelCount(3),
/// CiphertextModulus::try_new(1 << 32).unwrap(),
/// );
/// let output = decomposer.decompose(2u64.pow(19)).next().unwrap();
/// assert_eq!(output.level(), DecompositionLevel(3));
/// ```
pub fn level(&self) -> DecompositionLevel {
DecompositionLevel(self.level)
}
}

View File

@@ -15,6 +15,7 @@ pub struct Gaussian<T: FloatingPoint> {
macro_rules! implement_gaussian {
($T:ty, $S:ty) => {
impl RandomGenerable<Gaussian<$T>> for ($T, $T) {
type CustomModulus = $T;
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
Gaussian { std, mean }: Gaussian<$T>,
@@ -54,6 +55,8 @@ impl<Torus> RandomGenerable<Gaussian<f64>> for (Torus, Torus)
where
Torus: UnsignedTorus,
{
type CustomModulus = u128;
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
distribution: Gaussian<f64>,
@@ -64,12 +67,26 @@ where
<Torus as FromTorus<f64>>::from_torus(s2),
)
}
fn generate_one_custom_modulus<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
distribution: Gaussian<f64>,
custom_modulus: Self::CustomModulus,
) -> Self {
let (s1, s2) = <(f64, f64)>::generate_one(generator, distribution);
(
<Torus as FromTorus<f64>>::from_torus_custom_modulus(s1, custom_modulus),
<Torus as FromTorus<f64>>::from_torus_custom_modulus(s2, custom_modulus),
)
}
}
impl<Torus> RandomGenerable<Gaussian<f64>> for Torus
where
Torus: UnsignedTorus,
{
type CustomModulus = u128;
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
distribution: Gaussian<f64>,
@@ -77,4 +94,13 @@ where
let (s1, _) = <(f64, f64)>::generate_one(generator, distribution);
<Torus as FromTorus<f64>>::from_torus(s1)
}
fn generate_one_custom_modulus<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
distribution: Gaussian<f64>,
custom_modulus: Self::CustomModulus,
) -> Self {
let (s1, _) = <(f64, f64)>::generate_one(generator, distribution);
<Torus as FromTorus<f64>>::from_torus_custom_modulus(s1, custom_modulus)
}
}

View File

@@ -2,8 +2,9 @@ use crate::core_crypto::commons::math::random::{
Gaussian, RandomGenerable, Uniform, UniformBinary, UniformLsb, UniformMsb, UniformTernary,
UniformWithZeros,
};
use crate::core_crypto::commons::math::torus::UnsignedTorus;
use crate::core_crypto::commons::numeric::FloatingPoint;
use crate::core_crypto::commons::math::torus::{UnsignedInteger, UnsignedTorus};
use crate::core_crypto::commons::numeric::{CastFrom, CastInto, FloatingPoint};
use crate::core_crypto::commons::parameters::CiphertextModulus;
use concrete_csprng::generators::{BytesPerChild, ChildrenCount, ForkError};
use rayon::prelude::*;
use std::convert::TryInto;
@@ -184,6 +185,40 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
Scalar::fill_slice(self, Uniform, output);
}
/// Fill a slice with random uniform values, for non-native power of 2 moduli, a shift is
/// applied to only keep log2(modulus) MSBs and zeroed out LSBs
///
/// # Example
///
/// ```
/// use concrete_csprng::generators::SoftwareRandomGenerator;
/// use concrete_csprng::seeders::Seed;
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
/// use tfhe::core_crypto::commons::parameters::CiphertextModulus;
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
/// let mut vec = vec![1u32; 100];
/// generator.fill_slice_with_random_uniform_custom_mod(
/// &mut vec,
/// CiphertextModulus::try_new_power_of_2(31).unwrap(),
/// );
/// ```
pub fn fill_slice_with_random_uniform_custom_mod<Scalar>(
&mut self,
output: &mut [Scalar],
custom_modulus: CiphertextModulus<Scalar>,
) where
Scalar: UnsignedInteger + RandomGenerable<Uniform>,
{
self.fill_slice_with_random_uniform(output);
if !custom_modulus.is_native_modulus() {
output
.as_mut()
.iter_mut()
.for_each(|x| *x = (*x).wrapping_rem(custom_modulus.get().cast_into()));
}
}
/// Generate a random uniform binary value.
///
/// # Example
@@ -359,6 +394,51 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
});
}
/// Fill a slice with random gaussian values.
///
/// # Example
///
/// ```
/// use concrete_csprng::generators::SoftwareRandomGenerator;
/// use concrete_csprng::seeders::Seed;
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
/// use tfhe::core_crypto::commons::parameters::CiphertextModulus;
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
/// let mut vec = vec![1000u64; 100];
/// generator.fill_slice_with_random_gaussian_custom_mod(
/// &mut vec,
/// 0.,
/// 1.,
/// CiphertextModulus::try_new_power_of_2(63).unwrap(),
/// );
/// ```
pub fn fill_slice_with_random_gaussian_custom_mod<Float, Scalar>(
&mut self,
output: &mut [Scalar],
mean: Float,
std: Float,
custom_modulus: CiphertextModulus<Scalar>,
) where
Float: FloatingPoint + CastFrom<u128>,
Scalar: UnsignedInteger,
(Scalar, Scalar): RandomGenerable<Gaussian<Float>, CustomModulus = Float>,
{
let custom_modulus_float: Float = custom_modulus.get().cast_into();
output.chunks_mut(2).for_each(|s| {
let (g1, g2) = <(Scalar, Scalar)>::generate_one_custom_modulus(
self,
Gaussian { std, mean },
custom_modulus_float,
);
if let Some(elem) = s.get_mut(0) {
*elem = g1;
}
if let Some(elem) = s.get_mut(1) {
*elem = g2;
}
});
}
/// Add a random gaussian value to each element in a slice.
///
/// # Example
@@ -391,6 +471,45 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
}
});
}
/// Add a random gaussian value to each element in a slice.
///
/// # Example
///
/// ```
/// use concrete_csprng::generators::SoftwareRandomGenerator;
/// use concrete_csprng::seeders::Seed;
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
/// let mut vec = vec![1000u32; 100];
/// generator.unsigned_torus_slice_wrapping_add_random_gaussian_assign(&mut vec, 0., 1.);
/// ```
pub fn unsigned_torus_slice_wrapping_add_random_gaussian_custom_mod_assign<Float, Scalar>(
&mut self,
output: &mut [Scalar],
mean: Float,
std: Float,
custom_modulus: CiphertextModulus<Scalar>,
) where
Scalar: UnsignedTorus,
Float: FloatingPoint + CastFrom<u128>,
(Scalar, Scalar): RandomGenerable<Gaussian<Float>, CustomModulus = Float>,
{
let custom_modulus_float: Float = custom_modulus.get().cast_into();
output.chunks_mut(2).for_each(|s| {
let (g1, g2) = <(Scalar, Scalar)>::generate_one_custom_modulus(
self,
Gaussian { std, mean },
custom_modulus_float,
);
if let Some(elem) = s.get_mut(0) {
*elem = (*elem).wrapping_add(g1);
}
if let Some(elem) = s.get_mut(1) {
*elem = (*elem).wrapping_add(g2);
}
});
}
}
impl<G: ParallelByteRandomGenerator> RandomGenerator<G> {

View File

@@ -44,11 +44,24 @@ pub trait RandomGenerable<D: Distribution>
where
Self: Sized,
{
type CustomModulus;
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
distribution: D,
) -> Self;
fn generate_one_custom_modulus<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
distribution: D,
custom_modulus: Self::CustomModulus,
) -> Self {
let _ = generator;
let _ = distribution;
let _ = custom_modulus;
todo!("This distribution does not support custom modulus generation at this time.");
}
fn fill_slice<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
distribution: D,

View File

@@ -8,6 +8,7 @@ pub struct Uniform;
macro_rules! implement_uniform {
($T:ty) => {
impl RandomGenerable<Uniform> for $T {
type CustomModulus = $T;
#[allow(unused)]
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,

View File

@@ -7,6 +7,7 @@ pub struct UniformBinary;
macro_rules! implement_uniform_binary {
($T:ty) => {
impl RandomGenerable<UniformBinary> for $T {
type CustomModulus = $T;
#[allow(unused)]
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,

View File

@@ -11,6 +11,7 @@ pub struct UniformLsb {
macro_rules! implement_uniform_some_lsb {
($T:ty) => {
impl RandomGenerable<UniformLsb> for $T {
type CustomModulus = $T;
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
UniformLsb { n }: UniformLsb,

View File

@@ -12,6 +12,7 @@ pub struct UniformMsb {
macro_rules! implement_uniform_some_msb {
($T:ty) => {
impl RandomGenerable<UniformMsb> for $T {
type CustomModulus = $T;
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,
UniformMsb { n }: UniformMsb,

View File

@@ -7,6 +7,7 @@ pub struct UniformTernary;
macro_rules! implement_uniform_ternary {
($T:ty) => {
impl RandomGenerable<UniformTernary> for $T {
type CustomModulus = $T;
#[allow(unused)]
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,

View File

@@ -13,6 +13,7 @@ pub struct UniformWithZeros {
macro_rules! implement_uniform_with_zeros {
($T:ty, $bits:literal) => {
impl RandomGenerable<UniformWithZeros> for $T {
type CustomModulus = $T;
#[allow(unused)]
fn generate_one<G: ByteRandomGenerator>(
generator: &mut RandomGenerator<G>,

View File

@@ -15,7 +15,8 @@
use crate::core_crypto::commons::math::random::{
Gaussian, RandomGenerable, Uniform, UniformBinary, UniformTernary,
};
pub use crate::core_crypto::commons::numeric::{CastInto, FloatingPoint, Numeric, UnsignedInteger};
pub use crate::core_crypto::commons::numeric::{CastFrom, CastInto, FloatingPoint, Numeric,
UnsignedInteger};
use std::fmt::{Debug, Display};
/// A trait that converts a torus element in unsigned integer representation to the closest
@@ -38,6 +39,8 @@ where
{
/// Consume `input` and returns its closest unsigned integer representation.
fn from_torus(input: F) -> Self;
/// Consume `input` and returns its closest unsigned integer representation for a given modulus.
fn from_torus_custom_modulus(input: F, custom_modulus: u128) -> Self;
}
macro_rules! implement {
@@ -55,7 +58,7 @@ macro_rules! implement {
}
impl<F> FromTorus<F> for $Type
where
F: FloatingPoint + CastInto<Self> + CastInto<Self::Signed>,
F: FloatingPoint + CastInto<Self> + CastInto<Self::Signed> + CastFrom<u128>,
Self: CastInto<F>,
{
#[inline]
@@ -66,6 +69,19 @@ macro_rules! implement {
let signed: Self::Signed = fract.cast_into();
return signed.cast_into();
}
#[inline]
fn from_torus_custom_modulus(input: F, custom_modulus: u128) -> Self {
let mut fract = input - F::round(input);
let custom_modulus_float: F = custom_modulus.cast_into();
fract *= custom_modulus_float;
fract = F::round(fract);
let mut signed: Self::Signed = fract.cast_into();
if signed < 0 {
let cm = custom_modulus as Self::Signed;
signed += cm;
}
return signed.cast_into();
}
}
};
}
@@ -85,6 +101,10 @@ pub trait UnsignedTorus:
+ RandomGenerable<UniformBinary>
+ RandomGenerable<UniformTernary>
+ RandomGenerable<Uniform>
+ RandomGenerable<Gaussian<f64>, CustomModulus = u128>
+ RandomGenerable<UniformBinary, CustomModulus = Self>
+ RandomGenerable<UniformTernary, CustomModulus = Self>
+ RandomGenerable<Uniform, CustomModulus = Self>
+ Display
+ Debug
{

View File

@@ -46,6 +46,7 @@ macro_rules! modular_distance {
};
}
pub mod ciphertext_modulus;
pub mod computation_buffers;
pub mod dispersion;
pub mod generators;
@@ -78,7 +79,7 @@ pub mod test_tools {
fn modular_distance<T: UnsignedInteger>(first: T, other: T) -> T {
let d0 = first.wrapping_sub(other);
let d1 = other.wrapping_sub(first);
std::cmp::min(d0, d1)
d0.min(d1)
}
fn torus_modular_distance<T: UnsignedInteger>(first: T, other: T) -> f64 {

View File

@@ -21,7 +21,7 @@ mod signed;
mod unsigned;
/// A trait implemented by any generic numeric type suitable for computations.
pub trait Numeric: Sized + Copy + PartialEq + PartialOrd + 'static {
pub trait Numeric: Sized + Copy + PartialEq + PartialOrd + std::fmt::Debug + 'static {
/// This size of the type in bits.
const BITS: usize;

View File

@@ -32,6 +32,9 @@ pub trait UnsignedInteger:
+ ShrAssign<usize>
+ CastFrom<f64>
+ CastInto<f64>
+ CastFrom<u128>
+ CastInto<u128>
+ std::fmt::Binary
{
/// The signed type of the same precision.
type Signed: SignedInteger<Unsigned = Self> + CastFrom<Self>;
@@ -47,6 +50,9 @@ pub trait UnsignedInteger:
/// Compute a multiplication, modulo the max of the type.
#[must_use]
fn wrapping_mul(self, other: Self) -> Self;
/// Compute the remainder, modulo the max of the type.
#[must_use]
fn wrapping_rem(self, other: Self) -> Self;
/// Compute a negation, modulo the max of the type.
#[must_use]
fn wrapping_neg(self) -> Self;
@@ -113,6 +119,10 @@ macro_rules! implement {
fn wrapping_mul(self, other: Self) -> Self {
self.wrapping_mul(other)
}
#[must_use]
fn wrapping_rem(self, other: Self) -> Self {
self.wrapping_rem(other)
}
#[inline]
fn wrapping_neg(self) -> Self {
self.wrapping_neg()

View File

@@ -5,6 +5,8 @@
use serde::{Deserialize, Serialize};
pub use super::ciphertext_modulus::CiphertextModulus;
/// The number plaintexts in a plaintext list.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct PlaintextCount(pub usize);

View File

@@ -3,5 +3,5 @@
use crate::core_crypto::commons::numeric::Numeric;
/// A cleartext, not encoded, value.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
pub struct Cleartext<T: Numeric>(pub T);

View File

@@ -262,7 +262,7 @@ impl<C: Container> ContiguousEntityContainer for GgswCiphertextList<C> {
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> GgswCiphertextCreationMetadata {
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
GgswCiphertextCreationMetadata(self.glwe_size, self.polynomial_size, self.decomp_base_log)
}

View File

@@ -178,7 +178,7 @@ impl<C: Container> ContiguousEntityContainer for GlweCiphertextList<C> {
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> GlweCiphertextCreationMetadata {
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
GlweCiphertextCreationMetadata(self.polynomial_size())
}
@@ -186,7 +186,7 @@ impl<C: Container> ContiguousEntityContainer for GlweCiphertextList<C> {
glwe_ciphertext_size(self.glwe_size(), self.polynomial_size())
}
fn get_self_view_creation_metadata(&self) -> GlweCiphertextListCreationMetadata {
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
GlweCiphertextListCreationMetadata(self.glwe_size(), self.polynomial_size())
}
}

View File

@@ -1,18 +1,38 @@
//! Module containing the definition of the LweCiphertext.
//! Module containing the definition of the [`LweCiphertext`].
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
/// A convenience structure to easily manipulate the body of an [`LweCiphertext`].
#[derive(Clone, Debug)]
pub struct LweBody<T>(pub T);
pub struct LweBody<T: UnsignedInteger> {
pub data: T,
pub ciphertext_modulus: CiphertextModulus<T>,
}
#[derive(Debug)]
pub struct LweBodyRef<'a, T: UnsignedInteger> {
pub data: &'a T,
pub ciphertext_modulus: CiphertextModulus<T>,
}
#[derive(Debug)]
pub struct LweBodyRefMut<'a, T: UnsignedInteger> {
pub data: &'a mut T,
pub ciphertext_modulus: CiphertextModulus<T>,
}
#[derive(Clone, Debug)]
pub struct LweMask<C: Container> {
pub struct LweMask<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
/// A convenience structure to easily manipulate the mask of an [`LweCiphertext`].
impl<C: Container> LweMask<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> LweMask<C> {
/// Create an [`LweMask`] from an existing container.
///
/// # Note
@@ -26,13 +46,18 @@ impl<C: Container> LweMask<C> {
/// // computations
/// // Define parameters for LweMask creation
/// let lwe_dimension = LweDimension(600);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// let lwe_mask = LweMask::from_container(vec![0u64; lwe_dimension.0]);
/// let lwe_mask = LweMask::from_container(vec![0u64; lwe_dimension.0], ciphertext_modulus);
///
/// assert_eq!(lwe_mask.lwe_dimension(), lwe_dimension);
/// assert_eq!(lwe_mask.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_container(container: C) -> Self {
LweMask { data: container }
pub fn from_container(container: C, ciphertext_modulus: CiphertextModulus<C::Element>) -> Self {
LweMask {
data: container,
ciphertext_modulus,
}
}
/// Return the [`LweDimension`] of the [`LweMask`].
@@ -41,35 +66,65 @@ impl<C: Container> LweMask<C> {
pub fn lwe_dimension(&self) -> LweDimension {
LweDimension(self.data.container_len())
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
}
impl<T, C: Container<Element = T>> AsRef<[T]> for LweMask<C> {
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for LweMask<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T, C: ContainerMut<Element = T>> AsMut<[T]> for LweMask<C> {
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for LweMask<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
impl<'data, T> CreateFrom<&'data [T]> for LweBody<&'data T> {
type Metadata = ();
#[inline]
fn create_from(from: &[T], _meta: Self::Metadata) -> LweBody<&'_ T> {
LweBody(&from[0])
impl<Scalar: UnsignedInteger> LweBody<Scalar> {
pub fn ciphertext_modulus(&self) -> CiphertextModulus<Scalar> {
self.ciphertext_modulus
}
}
impl<'data, T> CreateFrom<&'data mut [T]> for LweBody<&'data mut T> {
type Metadata = ();
impl<T: UnsignedInteger> LweBodyRef<'_, T> {
pub fn ciphertext_modulus(&self) -> CiphertextModulus<T> {
self.ciphertext_modulus
}
}
impl<T: UnsignedInteger> LweBodyRefMut<'_, T> {
pub fn ciphertext_modulus(&self) -> CiphertextModulus<T> {
self.ciphertext_modulus
}
}
impl<'data, T: UnsignedInteger> CreateFrom<&'data [T]> for LweBodyRef<'data, T> {
type Metadata = LweCiphertextCreationMetadata<T>;
#[inline]
fn create_from(from: &mut [T], _meta: Self::Metadata) -> LweBody<&'_ mut T> {
LweBody(&mut from[0])
fn create_from(from: &[T], meta: Self::Metadata) -> LweBodyRef<T> {
let LweCiphertextCreationMetadata(ciphertext_modulus) = meta;
LweBodyRef {
data: &from[0],
ciphertext_modulus,
}
}
}
impl<'data, T: UnsignedInteger> CreateFrom<&'data mut [T]> for LweBodyRefMut<'data, T> {
type Metadata = LweCiphertextCreationMetadata<T>;
#[inline]
fn create_from(from: &mut [T], meta: Self::Metadata) -> LweBodyRefMut<T> {
let LweCiphertextCreationMetadata(ciphertext_modulus) = meta;
LweBodyRefMut {
data: &mut from[0],
ciphertext_modulus,
}
}
}
@@ -126,23 +181,27 @@ impl<'data, T> CreateFrom<&'data mut [T]> for LweBody<&'data mut T> {
/// **Remark:** Observe that the decryption is followed by a decoding phase that will contain a
/// rounding.
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct LweCiphertext<C: Container> {
pub struct LweCiphertext<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<T, C: Container<Element = T>> AsRef<[T]> for LweCiphertext<C> {
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for LweCiphertext<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T, C: ContainerMut<Element = T>> AsMut<[T]> for LweCiphertext<C> {
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for LweCiphertext<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
impl<Scalar, C: Container<Element = Scalar>> LweCiphertext<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> LweCiphertext<C> {
/// Create an [`LweCiphertext`] from an existing container.
///
/// # Note
@@ -160,9 +219,10 @@ impl<Scalar, C: Container<Element = Scalar>> LweCiphertext<C> {
/// // computations
/// // Define parameters for LweCiphertext creation
/// let lwe_size = LweSize(601);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create a new LweCiphertext
/// let mut lwe = LweCiphertext::new(0u64, lwe_size);
/// let mut lwe = LweCiphertext::new(0u64, lwe_size, ciphertext_modulus);
///
/// assert_eq!(lwe.lwe_size(), lwe_size);
/// assert_eq!(lwe.get_mask().lwe_dimension(), lwe_size.to_lwe_dimension());
@@ -170,12 +230,13 @@ impl<Scalar, C: Container<Element = Scalar>> LweCiphertext<C> {
/// lwe.get_mut_mask().lwe_dimension(),
/// lwe_size.to_lwe_dimension()
/// );
/// assert_eq!(lwe.ciphertext_modulus(), ciphertext_modulus);
///
/// // Demonstrate how to recover the allocated container
/// let underlying_container: Vec<u64> = lwe.into_container();
///
/// // Recreate a ciphertext using from_container
/// let mut lwe = LweCiphertext::from_container(underlying_container);
/// let mut lwe = LweCiphertext::from_container(underlying_container, ciphertext_modulus);
///
/// assert_eq!(lwe.lwe_size(), lwe_size);
/// assert_eq!(lwe.get_mask().lwe_dimension(), lwe_size.to_lwe_dimension());
@@ -183,13 +244,20 @@ impl<Scalar, C: Container<Element = Scalar>> LweCiphertext<C> {
/// lwe.get_mut_mask().lwe_dimension(),
/// lwe_size.to_lwe_dimension()
/// );
/// assert_eq!(lwe.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_container(container: C) -> LweCiphertext<C> {
pub fn from_container(
container: C,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> LweCiphertext<C> {
assert!(
container.container_len() > 0,
"Got an empty container to create an LweCiphertext"
);
LweCiphertext { data: container }
LweCiphertext {
data: container,
ciphertext_modulus,
}
}
/// Return the [`LweSize`] of the [`LweCiphertext`].
@@ -200,30 +268,44 @@ impl<Scalar, C: Container<Element = Scalar>> LweCiphertext<C> {
}
/// Return immutable views to the [`LweMask`] and [`LweBody`] of an [`LweCiphertext`].
pub fn get_mask_and_body(&self) -> (LweMask<&[Scalar]>, LweBody<&Scalar>) {
pub fn get_mask_and_body(&self) -> (LweMask<&[Scalar]>, LweBodyRef<'_, Scalar>) {
let (body, mask) = self.data.as_ref().split_last().unwrap();
let ciphertext_modulus = self.ciphertext_modulus();
(LweMask::from_container(mask), LweBody(body))
(
LweMask::from_container(mask, ciphertext_modulus),
LweBodyRef {
data: body,
ciphertext_modulus,
},
)
}
/// Return an immutable view to the [`LweBody`] of an [`LweCiphertext`].
pub fn get_body(&self) -> LweBody<&Scalar> {
pub fn get_body(&self) -> LweBodyRef<'_, Scalar> {
let body = self.data.as_ref().last().unwrap();
let ciphertext_modulus = self.ciphertext_modulus();
LweBody(body)
LweBodyRef {
data: body,
ciphertext_modulus,
}
}
/// Return an immutable view to the [`LweMask`] of an [`LweCiphertext`].
///
/// See [`LweCiphertext::from_container`] for usage.
pub fn get_mask(&self) -> LweMask<&[Scalar]> {
LweMask::from_container(&self.as_ref()[0..self.lwe_size().to_lwe_dimension().0])
LweMask::from_container(
&self.as_ref()[0..self.lwe_size().to_lwe_dimension().0],
self.ciphertext_modulus(),
)
}
/// Return a view of the [`LweCiphertext`]. This is useful if an algorithm takes a view by
/// value.
pub fn as_view(&self) -> LweCiphertextView<'_, Scalar> {
LweCiphertextView::from_container(self.as_ref())
LweCiphertextView::from_container(self.as_ref(), self.ciphertext_modulus())
}
/// Consume the entity and return its underlying container.
@@ -232,21 +314,36 @@ impl<Scalar, C: Container<Element = Scalar>> LweCiphertext<C> {
pub fn into_container(self) -> C {
self.data
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
}
impl<Scalar, C: ContainerMut<Element = Scalar>> LweCiphertext<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> LweCiphertext<C> {
/// Mutable variant of [`LweCiphertext::get_mask_and_body`].
pub fn get_mut_mask_and_body(&mut self) -> (LweMask<&mut [Scalar]>, LweBody<&mut Scalar>) {
pub fn get_mut_mask_and_body(&mut self) -> (LweMask<&mut [Scalar]>, LweBodyRefMut<'_, Scalar>) {
let ciphertext_modulus = self.ciphertext_modulus();
let (body, mask) = self.data.as_mut().split_last_mut().unwrap();
(LweMask::from_container(mask), LweBody(body))
(
LweMask::from_container(mask, ciphertext_modulus),
LweBodyRefMut {
data: body,
ciphertext_modulus,
},
)
}
/// Mutable variant of [`LweCiphertext::get_body`].
pub fn get_mut_body(&mut self) -> LweBody<&mut Scalar> {
pub fn get_mut_body(&mut self) -> LweBodyRefMut<'_, Scalar> {
let ciphertext_modulus = self.ciphertext_modulus();
let body = self.data.as_mut().last_mut().unwrap();
LweBody(body)
LweBodyRefMut {
data: body,
ciphertext_modulus,
}
}
/// Mutable variant of [`LweCiphertext::get_mask`].
@@ -254,12 +351,15 @@ impl<Scalar, C: ContainerMut<Element = Scalar>> LweCiphertext<C> {
/// See [`LweCiphertext::from_container`] for usage.
pub fn get_mut_mask(&mut self) -> LweMask<&mut [Scalar]> {
let lwe_dimension = self.lwe_size().to_lwe_dimension();
LweMask::from_container(&mut self.as_mut()[0..lwe_dimension.0])
let ciphertext_modulus = self.ciphertext_modulus();
LweMask::from_container(&mut self.as_mut()[0..lwe_dimension.0], ciphertext_modulus)
}
/// Mutable variant of [`LweCiphertext::as_view`].
pub fn as_mut_view(&mut self) -> LweCiphertextMutView<'_, Scalar> {
LweCiphertextMutView::from_container(self.as_mut())
let ciphertext_modulus = self.ciphertext_modulus();
LweCiphertextMutView::from_container(self.as_mut(), ciphertext_modulus)
}
}
@@ -270,7 +370,7 @@ pub type LweCiphertextView<'data, Scalar> = LweCiphertext<&'data [Scalar]>;
/// An [`LweCiphertext`] mutably borrowing memory for its own storage.
pub type LweCiphertextMutView<'data, Scalar> = LweCiphertext<&'data mut [Scalar]>;
impl<Scalar: Copy> LweCiphertextOwned<Scalar> {
impl<Scalar: UnsignedInteger> LweCiphertextOwned<Scalar> {
/// Allocate memory and create a new owned [`LweCiphertext`].
///
/// # Note
@@ -281,20 +381,25 @@ impl<Scalar: Copy> LweCiphertextOwned<Scalar> {
/// output.
///
/// See [`LweCiphertext::from_container`] for usage.
pub fn new(fill_with: Scalar, lwe_size: LweSize) -> LweCiphertextOwned<Scalar> {
LweCiphertextOwned::from_container(vec![fill_with; lwe_size.0])
pub fn new(
fill_with: Scalar,
lwe_size: LweSize,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> LweCiphertextOwned<Scalar> {
LweCiphertextOwned::from_container(vec![fill_with; lwe_size.0], ciphertext_modulus)
}
}
/// Metadata used in the [`CreateFrom`] implementation to create [`LweCiphertext`] entities.
#[derive(Clone, Copy)]
pub struct LweCiphertextCreationMetadata();
pub struct LweCiphertextCreationMetadata<Scalar: UnsignedInteger>(pub CiphertextModulus<Scalar>);
impl<C: Container> CreateFrom<C> for LweCiphertext<C> {
type Metadata = LweCiphertextCreationMetadata;
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C> for LweCiphertext<C> {
type Metadata = LweCiphertextCreationMetadata<C::Element>;
#[inline]
fn create_from(from: C, _: Self::Metadata) -> LweCiphertext<C> {
LweCiphertext::from_container(from)
fn create_from(from: C, meta: Self::Metadata) -> LweCiphertext<C> {
let LweCiphertextCreationMetadata(modulus) = meta;
LweCiphertext::from_container(from, modulus)
}
}

View File

@@ -1,4 +1,4 @@
//! Module containing the definition of the LweCiphertextList.
//! Module containing the definition of the [`LweCiphertextList`].
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
@@ -7,24 +7,28 @@ use crate::core_crypto::entities::*;
/// A contiguous list containing
/// [`LWE ciphertexts`](`crate::core_crypto::entities::LweCiphertext`).
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct LweCiphertextList<C: Container> {
pub struct LweCiphertextList<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
lwe_size: LweSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<T, C: Container<Element = T>> AsRef<[T]> for LweCiphertextList<C> {
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for LweCiphertextList<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T, C: ContainerMut<Element = T>> AsMut<[T]> for LweCiphertextList<C> {
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for LweCiphertextList<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
impl<Scalar, C: Container<Element = Scalar>> LweCiphertextList<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> LweCiphertextList<C> {
/// Create an [`LweCiphertextList`] from an existing container.
///
/// # Note
@@ -44,23 +48,31 @@ impl<Scalar, C: Container<Element = Scalar>> LweCiphertextList<C> {
/// // Define parameters for LweCiphertextList creation
/// let lwe_size = LweSize(601);
/// let lwe_ciphertext_count = LweCiphertextCount(3);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create a new LweCiphertextList
/// let lwe_list = LweCiphertextList::new(0u64, lwe_size, lwe_ciphertext_count);
/// let lwe_list = LweCiphertextList::new(0u64, lwe_size, lwe_ciphertext_count, ciphertext_modulus);
///
/// assert_eq!(lwe_list.lwe_size(), lwe_size);
/// assert_eq!(lwe_list.lwe_ciphertext_count(), lwe_ciphertext_count);
/// assert_eq!(lwe_list.ciphertext_modulus(), ciphertext_modulus);
///
/// // Demonstrate how to recover the allocated container
/// let underlying_container: Vec<u64> = lwe_list.into_container();
///
/// // Recreate a list using from_container
/// let lwe_list = LweCiphertextList::from_container(underlying_container, lwe_size);
/// let lwe_list =
/// LweCiphertextList::from_container(underlying_container, lwe_size, ciphertext_modulus);
///
/// assert_eq!(lwe_list.lwe_size(), lwe_size);
/// assert_eq!(lwe_list.lwe_ciphertext_count(), lwe_ciphertext_count);
/// assert_eq!(lwe_list.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_container(container: C, lwe_size: LweSize) -> LweCiphertextList<C> {
pub fn from_container(
container: C,
lwe_size: LweSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> LweCiphertextList<C> {
assert!(
container.container_len() % lwe_size.0 == 0,
"The provided container length is not valid. \
@@ -71,6 +83,7 @@ impl<Scalar, C: Container<Element = Scalar>> LweCiphertextList<C> {
LweCiphertextList {
data: container,
lwe_size,
ciphertext_modulus,
}
}
@@ -91,7 +104,11 @@ impl<Scalar, C: Container<Element = Scalar>> LweCiphertextList<C> {
/// Return a view of the [`LweCiphertextList`]. This is useful if an algorithm takes a view by
/// value.
pub fn as_view(&self) -> LweCiphertextListView<'_, Scalar> {
LweCiphertextListView::from_container(self.as_ref(), self.lwe_size)
LweCiphertextListView::from_container(
self.as_ref(),
self.lwe_size(),
self.ciphertext_modulus(),
)
}
/// Consume the entity and return its underlying container.
@@ -100,13 +117,18 @@ impl<Scalar, C: Container<Element = Scalar>> LweCiphertextList<C> {
pub fn into_container(self) -> C {
self.data
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
}
impl<Scalar, C: ContainerMut<Element = Scalar>> LweCiphertextList<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> LweCiphertextList<C> {
/// Mutable variant of [`LweCiphertextList::as_view`].
pub fn as_mut_view(&mut self) -> LweCiphertextListMutView<'_, Scalar> {
let lwe_size = self.lwe_size;
LweCiphertextListMutView::from_container(self.as_mut(), lwe_size)
let lwe_size = self.lwe_size();
let ciphertext_modulus = self.ciphertext_modulus();
LweCiphertextListMutView::from_container(self.as_mut(), lwe_size, ciphertext_modulus)
}
}
@@ -117,7 +139,7 @@ pub type LweCiphertextListView<'data, Scalar> = LweCiphertextList<&'data [Scalar
/// An [`LweCiphertextList`] mutably borrowing memory for its own storage.
pub type LweCiphertextListMutView<'data, Scalar> = LweCiphertextList<&'data mut [Scalar]>;
impl<Scalar: Copy> LweCiphertextListOwned<Scalar> {
impl<Scalar: UnsignedInteger> LweCiphertextListOwned<Scalar> {
/// Allocate memory and create a new owned [`LweCiphertextList`].
///
/// # Note
@@ -133,57 +155,68 @@ impl<Scalar: Copy> LweCiphertextListOwned<Scalar> {
fill_with: Scalar,
lwe_size: LweSize,
ciphertext_count: LweCiphertextCount,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> LweCiphertextListOwned<Scalar> {
LweCiphertextListOwned::from_container(
vec![fill_with; lwe_size.0 * ciphertext_count.0],
lwe_size,
ciphertext_modulus,
)
}
}
/// Metadata used in the [`CreateFrom`] implementation to create [`LweCiphertextList`] entities.
#[derive(Clone, Copy)]
pub struct LweCiphertextListCreationMetadata(pub LweSize);
pub struct LweCiphertextListCreationMetadata<Scalar: UnsignedInteger>(
pub LweSize,
pub CiphertextModulus<Scalar>,
);
impl<C: Container> CreateFrom<C> for LweCiphertextList<C> {
type Metadata = LweCiphertextListCreationMetadata;
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C>
for LweCiphertextList<C>
{
type Metadata = LweCiphertextListCreationMetadata<Scalar>;
#[inline]
fn create_from(from: C, meta: Self::Metadata) -> LweCiphertextList<C> {
let lwe_size = meta.0;
LweCiphertextList::from_container(from, lwe_size)
let LweCiphertextListCreationMetadata(lwe_size, modulus) = meta;
LweCiphertextList::from_container(from, lwe_size, modulus)
}
}
impl<C: Container> ContiguousEntityContainer for LweCiphertextList<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> ContiguousEntityContainer
for LweCiphertextList<C>
{
type Element = C::Element;
type EntityViewMetadata = LweCiphertextCreationMetadata;
type EntityViewMetadata = LweCiphertextCreationMetadata<Self::Element>;
type EntityView<'this> = LweCiphertextView<'this, Self::Element>
where
Self: 'this;
type SelfViewMetadata = LweCiphertextListCreationMetadata;
type SelfViewMetadata = LweCiphertextListCreationMetadata<Self::Element>;
type SelfView<'this> = LweCiphertextListView<'this, Self::Element>
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> LweCiphertextCreationMetadata {
LweCiphertextCreationMetadata()
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
LweCiphertextCreationMetadata(self.ciphertext_modulus())
}
fn get_entity_view_pod_size(&self) -> usize {
self.lwe_size.0
self.lwe_size().0
}
fn get_self_view_creation_metadata(&self) -> LweCiphertextListCreationMetadata {
LweCiphertextListCreationMetadata(self.lwe_size)
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
LweCiphertextListCreationMetadata(self.lwe_size(), self.ciphertext_modulus())
}
}
impl<C: ContainerMut> ContiguousEntityContainerMut for LweCiphertextList<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> ContiguousEntityContainerMut
for LweCiphertextList<C>
{
type EntityMutView<'this> = LweCiphertextMutView<'this, Self::Element>
where
Self: 'this;

View File

@@ -1,4 +1,4 @@
//! Module containing the definition of the LweKeyswitchKey.
//! Module containing the definition of the [`LweKeyswitchKey`].
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
@@ -74,20 +74,24 @@ use crate::core_crypto::entities::*;
/// \right)$
/// 3. output $\mathsf{ct}\_{\mathsf{out}}$
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct LweKeyswitchKey<C: Container> {
pub struct LweKeyswitchKey<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
output_lwe_size: LweSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<T, C: Container<Element = T>> AsRef<[T]> for LweKeyswitchKey<C> {
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for LweKeyswitchKey<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T, C: ContainerMut<Element = T>> AsMut<[T]> for LweKeyswitchKey<C> {
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for LweKeyswitchKey<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
@@ -103,7 +107,7 @@ pub fn lwe_keyswitch_key_input_key_element_encrypted_size(
decomp_level_count.0 * output_lwe_size.0
}
impl<Scalar, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
/// Create an [`LweKeyswitchKey`] from an existing container.
///
/// # Note
@@ -124,6 +128,7 @@ impl<Scalar, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
/// let output_lwe_dimension = LweDimension(1024);
/// let decomp_base_log = DecompositionBaseLog(4);
/// let decomp_level_count = DecompositionLevelCount(5);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create a new LweKeyswitchKey
/// let lwe_ksk = LweKeyswitchKey::new(
@@ -132,6 +137,7 @@ impl<Scalar, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
/// decomp_level_count,
/// input_lwe_dimension,
/// output_lwe_dimension,
/// ciphertext_modulus,
/// );
///
/// assert_eq!(lwe_ksk.decomposition_base_log(), decomp_base_log);
@@ -142,6 +148,7 @@ impl<Scalar, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
/// lwe_ksk.output_lwe_size(),
/// output_lwe_dimension.to_lwe_size()
/// );
/// assert_eq!(lwe_ksk.ciphertext_modulus(), ciphertext_modulus);
///
/// // Demonstrate how to recover the allocated container
/// let underlying_container: Vec<u64> = lwe_ksk.into_container();
@@ -152,6 +159,7 @@ impl<Scalar, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
/// decomp_base_log,
/// decomp_level_count,
/// output_lwe_dimension.to_lwe_size(),
/// ciphertext_modulus,
/// );
///
/// assert_eq!(lwe_ksk.decomposition_base_log(), decomp_base_log);
@@ -162,12 +170,14 @@ impl<Scalar, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
/// lwe_ksk.output_lwe_size(),
/// output_lwe_dimension.to_lwe_size()
/// );
/// assert_eq!(lwe_ksk.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_container(
container: C,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
output_lwe_size: LweSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
assert!(
container.container_len() > 0,
@@ -188,6 +198,7 @@ impl<Scalar, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
decomp_base_log,
decomp_level_count,
output_lwe_size,
ciphertext_modulus,
}
}
@@ -243,6 +254,7 @@ impl<Scalar, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
self.decomp_base_log,
self.decomp_level_count,
self.output_lwe_size,
self.ciphertext_modulus,
)
}
@@ -254,34 +266,45 @@ impl<Scalar, C: Container<Element = Scalar>> LweKeyswitchKey<C> {
}
pub fn as_lwe_ciphertext_list(&self) -> LweCiphertextListView<'_, Scalar> {
LweCiphertextListView::from_container(self.as_ref(), self.output_lwe_size())
LweCiphertextListView::from_container(
self.as_ref(),
self.output_lwe_size(),
self.ciphertext_modulus(),
)
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
}
impl<Scalar, C: ContainerMut<Element = Scalar>> LweKeyswitchKey<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> LweKeyswitchKey<C> {
/// Mutable variant of [`LweKeyswitchKey::as_view`].
pub fn as_mut_view(&mut self) -> LweKeyswitchKey<&'_ mut [Scalar]> {
let decomp_base_log = self.decomp_base_log;
let decomp_level_count = self.decomp_level_count;
let output_lwe_size = self.output_lwe_size;
let ciphertext_modulus = self.ciphertext_modulus;
LweKeyswitchKey::from_container(
self.as_mut(),
decomp_base_log,
decomp_level_count,
output_lwe_size,
ciphertext_modulus,
)
}
pub fn as_mut_lwe_ciphertext_list(&mut self) -> LweCiphertextListMutView<'_, Scalar> {
let output_lwe_size = self.output_lwe_size();
LweCiphertextListMutView::from_container(self.as_mut(), output_lwe_size)
let ciphertext_modulus = self.ciphertext_modulus();
LweCiphertextListMutView::from_container(self.as_mut(), output_lwe_size, ciphertext_modulus)
}
}
/// An [`LweKeyswitchKey`] owning the memory for its own storage.
pub type LweKeyswitchKeyOwned<Scalar> = LweKeyswitchKey<Vec<Scalar>>;
impl<Scalar: Copy> LweKeyswitchKeyOwned<Scalar> {
impl<Scalar: UnsignedInteger> LweKeyswitchKeyOwned<Scalar> {
/// Allocate memory and create a new owned [`LweKeyswitchKey`].
///
/// # Note
@@ -297,6 +320,7 @@ impl<Scalar: Copy> LweKeyswitchKeyOwned<Scalar> {
decomp_level_count: DecompositionLevelCount,
input_key_lwe_dimension: LweDimension,
output_key_lwe_dimension: LweDimension,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> LweKeyswitchKeyOwned<Scalar> {
LweKeyswitchKeyOwned::from_container(
vec![
@@ -310,14 +334,17 @@ impl<Scalar: Copy> LweKeyswitchKeyOwned<Scalar> {
decomp_base_log,
decomp_level_count,
output_key_lwe_dimension.to_lwe_size(),
ciphertext_modulus,
)
}
}
impl<C: Container> ContiguousEntityContainer for LweKeyswitchKey<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> ContiguousEntityContainer
for LweKeyswitchKey<C>
{
type Element = C::Element;
type EntityViewMetadata = LweCiphertextListCreationMetadata;
type EntityViewMetadata = LweCiphertextListCreationMetadata<Self::Element>;
type EntityView<'this> = LweCiphertextListView<'this, Self::Element>
where
@@ -331,8 +358,8 @@ impl<C: Container> ContiguousEntityContainer for LweKeyswitchKey<C> {
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> LweCiphertextListCreationMetadata {
LweCiphertextListCreationMetadata(self.output_lwe_size())
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
LweCiphertextListCreationMetadata(self.output_lwe_size(), self.ciphertext_modulus())
}
fn get_entity_view_pod_size(&self) -> usize {
@@ -341,7 +368,7 @@ impl<C: Container> ContiguousEntityContainer for LweKeyswitchKey<C> {
/// Unimplemented for [`LweKeyswitchKey`]. At the moment it does not make sense to
/// return "sub" keyswitch keys.
fn get_self_view_creation_metadata(&self) {
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
unimplemented!(
"This function is not supported for LweKeyswitchKey. \
At the moment it does not make sense to return 'sub' keyswitch keys."
@@ -349,7 +376,9 @@ impl<C: Container> ContiguousEntityContainer for LweKeyswitchKey<C> {
}
}
impl<C: ContainerMut> ContiguousEntityContainerMut for LweKeyswitchKey<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> ContiguousEntityContainerMut
for LweKeyswitchKey<C>
{
type EntityMutView<'this> = LweCiphertextListMutView<'this, Self::Element>
where
Self: 'this;

View File

@@ -1,4 +1,4 @@
//! Module containing the definition of the LwePublicKey.
//! Module containing the definition of the [`LwePublicKey`].
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
@@ -21,11 +21,14 @@ use crate::core_crypto::entities::*;
/// $\vec{s}\in\mathbb{Z}\_q^n$ where $n$ is the LWE dimension of the ciphertexts contained in the
/// public key.
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct LwePublicKey<C: Container> {
pub struct LwePublicKey<C: Container>
where
C::Element: UnsignedInteger,
{
lwe_list: LweCiphertextList<C>,
}
impl<C: Container> std::ops::Deref for LwePublicKey<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> std::ops::Deref for LwePublicKey<C> {
type Target = LweCiphertextList<C>;
fn deref(&self) -> &LweCiphertextList<C> {
@@ -33,13 +36,15 @@ impl<C: Container> std::ops::Deref for LwePublicKey<C> {
}
}
impl<C: ContainerMut> std::ops::DerefMut for LwePublicKey<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> std::ops::DerefMut
for LwePublicKey<C>
{
fn deref_mut(&mut self) -> &mut LweCiphertextList<C> {
&mut self.lwe_list
}
}
impl<Scalar, C: Container<Element = Scalar>> LwePublicKey<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> LwePublicKey<C> {
/// Create an [`LwePublicKey`] from an existing container.
///
/// # Note
@@ -58,9 +63,11 @@ impl<Scalar, C: Container<Element = Scalar>> LwePublicKey<C> {
/// // Define parameters for LwePublicKey creation
/// let lwe_size = LweSize(600);
/// let zero_encryption_count = LwePublicKeyZeroEncryptionCount(3);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create a new LwePublicKey
/// let lwe_public_key = LwePublicKey::new(0u64, lwe_size, zero_encryption_count);
/// let lwe_public_key =
/// LwePublicKey::new(0u64, lwe_size, zero_encryption_count, ciphertext_modulus);
///
/// // This is a method from LweCiphertextList
/// assert_eq!(lwe_public_key.lwe_size(), lwe_size);
@@ -69,26 +76,33 @@ impl<Scalar, C: Container<Element = Scalar>> LwePublicKey<C> {
/// lwe_public_key.zero_encryption_count(),
/// zero_encryption_count
/// );
/// assert_eq!(lwe_public_key.ciphertext_modulus(), ciphertext_modulus);
///
/// // Demonstrate how to recover the allocated container
/// let underlying_container: Vec<u64> = lwe_public_key.into_container();
///
/// // Recreate a public key using from_container
/// let lwe_public_key = LwePublicKey::from_container(underlying_container, lwe_size);
/// let lwe_public_key =
/// LwePublicKey::from_container(underlying_container, lwe_size, ciphertext_modulus);
///
/// assert_eq!(lwe_public_key.lwe_size(), lwe_size);
/// assert_eq!(
/// lwe_public_key.zero_encryption_count(),
/// zero_encryption_count
/// );
/// assert_eq!(lwe_public_key.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_container(container: C, lwe_size: LweSize) -> LwePublicKey<C> {
pub fn from_container(
container: C,
lwe_size: LweSize,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> LwePublicKey<C> {
assert!(
container.container_len() > 0,
"Got an empty container to create an LwePublicKey"
);
LwePublicKey {
lwe_list: LweCiphertextList::from_container(container, lwe_size),
lwe_list: LweCiphertextList::from_container(container, lwe_size, ciphertext_modulus),
}
}
@@ -109,22 +123,23 @@ impl<Scalar, C: Container<Element = Scalar>> LwePublicKey<C> {
/// Return a view of the [`LwePublicKey`]. This is useful if an algorithm takes a view by
/// value.
pub fn as_view(&self) -> LwePublicKey<&'_ [Scalar]> {
LwePublicKey::from_container(self.as_ref(), self.lwe_size())
LwePublicKey::from_container(self.as_ref(), self.lwe_size(), self.ciphertext_modulus())
}
}
impl<Scalar, C: ContainerMut<Element = Scalar>> LwePublicKey<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> LwePublicKey<C> {
/// Mutable variant of [`LwePublicKey::as_view`].
pub fn as_mut_view(&mut self) -> LwePublicKey<&'_ mut [Scalar]> {
let lwe_size = self.lwe_size();
LwePublicKey::from_container(self.as_mut(), lwe_size)
let ciphertext_modulus = self.ciphertext_modulus();
LwePublicKey::from_container(self.as_mut(), lwe_size, ciphertext_modulus)
}
}
/// An [`LwePublicKey`] owning the memory for its own storage.
pub type LwePublicKeyOwned<Scalar> = LwePublicKey<Vec<Scalar>>;
impl<Scalar: Copy> LwePublicKeyOwned<Scalar> {
impl<Scalar: UnsignedInteger> LwePublicKeyOwned<Scalar> {
/// Allocate memory and create a new owned [`LwePublicKey`].
///
/// # Note
@@ -138,10 +153,12 @@ impl<Scalar: Copy> LwePublicKeyOwned<Scalar> {
fill_with: Scalar,
lwe_size: LweSize,
zero_encryption_count: LwePublicKeyZeroEncryptionCount,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> LwePublicKeyOwned<Scalar> {
LwePublicKeyOwned::from_container(
vec![fill_with; lwe_size.0 * zero_encryption_count.0],
lwe_size,
ciphertext_modulus,
)
}
}

View File

@@ -125,7 +125,7 @@ impl<C: Container> CreateFrom<C> for PlaintextList<C> {
}
}
impl<Scalar: Numeric, C: Container<Element = Scalar>> ContiguousEntityContainer
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> ContiguousEntityContainer
for PlaintextList<C>
{
type Element = C::Element;
@@ -151,7 +151,7 @@ impl<Scalar: Numeric, C: Container<Element = Scalar>> ContiguousEntityContainer
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {}
}
impl<Scalar: Numeric, C: ContainerMut<Element = Scalar>> ContiguousEntityContainerMut
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> ContiguousEntityContainerMut
for PlaintextList<C>
{
type EntityMutView<'this>= PlaintextRefMut<'this, Self::Element>

View File

@@ -275,7 +275,7 @@ impl<C: Container> ContiguousEntityContainer for SeededGgswCiphertextList<C> {
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> SeededGgswCiphertextCreationMetadata {
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
SeededGgswCiphertextCreationMetadata(
self.glwe_size,
self.polynomial_size,
@@ -294,7 +294,7 @@ impl<C: Container> ContiguousEntityContainer for SeededGgswCiphertextList<C> {
/// Unimplemented for [`SeededGgswCiphertextList`]. At the moment it does not make sense to
/// return "sub" seeded lists.
fn get_self_view_creation_metadata(&self) {
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
unimplemented!(
"This function is not supported for SeededGgswCiphertextList. \
At the moment it does not make sense to return 'sub' seeded lists."

View File

@@ -243,7 +243,7 @@ impl<C: Container> ContiguousEntityContainer for SeededGlweCiphertextList<C> {
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> SeededGlweCiphertextCreationMetadata {
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
SeededGlweCiphertextCreationMetadata(self.glwe_size(), self.compression_seed())
}
@@ -253,7 +253,7 @@ impl<C: Container> ContiguousEntityContainer for SeededGlweCiphertextList<C> {
/// Unimplemented for [`SeededGlweCiphertextList`]. At the moment it does not make sense to
/// return "sub" seeded lists.
fn get_self_view_creation_metadata(&self) {
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
unimplemented!(
"This function is not supported for SeededGlweCiphertextList. \
At the moment it does not make sense to return 'sub' seeded lists."

View File

@@ -1,3 +1,5 @@
//! Module containing the definition of the [`SeededLweCiphertext`].
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::math::random::{ActivatedRandomGenerator, CompressionSeed};
use crate::core_crypto::commons::parameters::*;
@@ -6,13 +8,14 @@ use crate::core_crypto::entities::*;
/// A [`seeded GLWE ciphertext`](`SeededLweCiphertext`).
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct SeededLweCiphertext<Scalar> {
pub struct SeededLweCiphertext<Scalar: UnsignedInteger> {
data: Scalar,
lwe_size: LweSize,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<Scalar>,
}
impl<Scalar> SeededLweCiphertext<Scalar> {
impl<Scalar: UnsignedInteger> SeededLweCiphertext<Scalar> {
/// Create a [`SeededLweCiphertext`] from a scalar.
///
/// # Note
@@ -32,16 +35,22 @@ impl<Scalar> SeededLweCiphertext<Scalar> {
/// // computations
/// // Define parameters for SeededLweCiphertextList creation
/// let lwe_dimension = LweDimension(742);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Get a seeder
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
///
/// // Create a new SeededLweCiphertext
/// let mut seeded_lwe =
/// SeededLweCiphertext::new(0u64, lwe_dimension.to_lwe_size(), seeder.seed().into());
/// let mut seeded_lwe = SeededLweCiphertext::new(
/// 0u64,
/// lwe_dimension.to_lwe_size(),
/// seeder.seed().into(),
/// ciphertext_modulus,
/// );
///
/// assert_eq!(seeded_lwe.lwe_size(), lwe_dimension.to_lwe_size());
/// assert_eq!(seeded_lwe.ciphertext_modulus(), ciphertext_modulus);
///
/// let compression_seed = seeded_lwe.compression_seed();
///
@@ -53,24 +62,29 @@ impl<Scalar> SeededLweCiphertext<Scalar> {
/// underlying_data,
/// lwe_dimension.to_lwe_size(),
/// compression_seed,
/// ciphertext_modulus,
/// );
///
/// assert_eq!(seeded_lwe.lwe_size(), lwe_dimension.to_lwe_size());
/// assert_eq!(seeded_lwe.ciphertext_modulus(), ciphertext_modulus);
///
/// // Decompress the list
/// let lwe_list = seeded_lwe.decompress_into_lwe_ciphertext();
///
/// assert_eq!(lwe_list.lwe_size(), lwe_dimension.to_lwe_size());
/// assert_eq!(lwe_list.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_scalar(
scalar: Scalar,
lwe_size: LweSize,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> SeededLweCiphertext<Scalar> {
SeededLweCiphertext {
data: scalar,
lwe_size,
compression_seed,
ciphertext_modulus,
}
}
@@ -91,8 +105,11 @@ impl<Scalar> SeededLweCiphertext<Scalar> {
/// Return an immutable view to the [`LweBody`] of a [`SeededLweCiphertext`].
///
/// See [`SeededLweCiphertext::from_scalar`] for usage.
pub fn get_body(&self) -> LweBody<&Scalar> {
LweBody(&self.data)
pub fn get_body(&self) -> LweBodyRef<'_, Scalar> {
LweBodyRef {
data: &self.data,
ciphertext_modulus: self.ciphertext_modulus,
}
}
/// Return the stored scalar containing the body of the [`SeededLweCiphertext`].
@@ -110,7 +127,8 @@ impl<Scalar> SeededLweCiphertext<Scalar> {
where
Scalar: UnsignedTorus,
{
let mut decompressed_ct = LweCiphertext::new(Scalar::ZERO, self.lwe_size());
let mut decompressed_ct =
LweCiphertext::new(Scalar::ZERO, self.lwe_size(), self.ciphertext_modulus());
decompress_seeded_lwe_ciphertext::<_, _, ActivatedRandomGenerator>(
&mut decompressed_ct,
&self,
@@ -118,6 +136,10 @@ impl<Scalar> SeededLweCiphertext<Scalar> {
decompressed_ct
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<Scalar> {
self.ciphertext_modulus
}
/// Allocate memory and create a new owned [`SeededLweCiphertext`].
///
/// # Note
@@ -132,16 +154,20 @@ impl<Scalar> SeededLweCiphertext<Scalar> {
scalar: Scalar,
lwe_size: LweSize,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> SeededLweCiphertext<Scalar> {
SeededLweCiphertext::from_scalar(scalar, lwe_size, compression_seed)
SeededLweCiphertext::from_scalar(scalar, lwe_size, compression_seed, ciphertext_modulus)
}
}
impl<Scalar> SeededLweCiphertext<Scalar> {
impl<Scalar: UnsignedInteger> SeededLweCiphertext<Scalar> {
/// Mutable variant of [`SeededLweCiphertext::get_body`].
///
/// See [`SeededLweCiphertext::from_scalar`] for usage.
pub fn get_mut_body(&mut self) -> LweBody<&mut Scalar> {
LweBody(&mut self.data)
pub fn get_mut_body(&mut self) -> LweBodyRefMut<'_, Scalar> {
LweBodyRefMut {
data: &mut self.data,
ciphertext_modulus: self.ciphertext_modulus,
}
}
}

View File

@@ -1,4 +1,4 @@
//! Module containing the definition of the SeededLweCiphertextList.
//! Module containing the definition of the [`SeededLweCiphertextList`].
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::math::random::{ActivatedRandomGenerator, CompressionSeed};
@@ -9,25 +9,29 @@ use crate::core_crypto::entities::*;
/// A seeded list containing
/// [`LWE ciphertexts`](`crate::core_crypto::entities::LweCiphertext`).
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct SeededLweCiphertextList<C: Container> {
pub struct SeededLweCiphertextList<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
lwe_size: LweSize,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<T, C: Container<Element = T>> AsRef<[T]> for SeededLweCiphertextList<C> {
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for SeededLweCiphertextList<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T, C: ContainerMut<Element = T>> AsMut<[T]> for SeededLweCiphertextList<C> {
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for SeededLweCiphertextList<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
impl<Scalar, C: Container<Element = Scalar>> SeededLweCiphertextList<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> SeededLweCiphertextList<C> {
/// Create an [`SeededLweCiphertextList`] from an existing container.
///
/// # Note
@@ -47,6 +51,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweCiphertextList<C> {
/// // Define parameters for SeededLweCiphertextList creation
/// let lwe_dimension = LweDimension(742);
/// let lwe_ciphertext_count = LweCiphertextCount(2);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Get a seeder
/// let mut seeder = new_seeder();
@@ -58,10 +63,12 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweCiphertextList<C> {
/// lwe_dimension.to_lwe_size(),
/// lwe_ciphertext_count,
/// seeder.seed().into(),
/// ciphertext_modulus,
/// );
///
/// assert_eq!(seeded_lwe_list.lwe_size(), lwe_dimension.to_lwe_size());
/// assert_eq!(seeded_lwe_list.lwe_ciphertext_count(), lwe_ciphertext_count);
/// assert_eq!(seeded_lwe_list.ciphertext_modulus(), ciphertext_modulus);
///
/// let compression_seed = seeded_lwe_list.compression_seed();
///
@@ -73,26 +80,31 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweCiphertextList<C> {
/// underlying_container,
/// lwe_dimension.to_lwe_size(),
/// compression_seed,
/// ciphertext_modulus,
/// );
///
/// assert_eq!(seeded_lwe_list.lwe_size(), lwe_dimension.to_lwe_size());
/// assert_eq!(seeded_lwe_list.lwe_ciphertext_count(), lwe_ciphertext_count);
/// assert_eq!(seeded_lwe_list.ciphertext_modulus(), ciphertext_modulus);
///
/// // Decompress the list
/// let lwe_list = seeded_lwe_list.decompress_into_lwe_ciphertext_list();
///
/// assert_eq!(lwe_list.lwe_size(), lwe_dimension.to_lwe_size());
/// assert_eq!(lwe_list.lwe_ciphertext_count(), lwe_ciphertext_count);
/// assert_eq!(lwe_list.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_container(
container: C,
lwe_size: LweSize,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> SeededLweCiphertextList<C> {
SeededLweCiphertextList {
data: container,
lwe_size,
compression_seed,
ciphertext_modulus,
}
}
@@ -132,8 +144,12 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweCiphertextList<C> {
where
Scalar: UnsignedTorus,
{
let mut decompressed_list =
LweCiphertextList::new(Scalar::ZERO, self.lwe_size(), self.lwe_ciphertext_count());
let mut decompressed_list = LweCiphertextList::new(
Scalar::ZERO,
self.lwe_size(),
self.lwe_ciphertext_count(),
self.ciphertext_modulus(),
);
decompress_seeded_lwe_ciphertext_list::<_, _, _, ActivatedRandomGenerator>(
&mut decompressed_list,
&self,
@@ -148,16 +164,27 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweCiphertextList<C> {
self.as_ref(),
self.lwe_size(),
self.compression_seed(),
self.ciphertext_modulus(),
)
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
}
impl<Scalar, C: ContainerMut<Element = Scalar>> SeededLweCiphertextList<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> SeededLweCiphertextList<C> {
/// Mutable variant of [`SeededLweCiphertextList::as_view`].
pub fn as_mut_view(&mut self) -> SeededLweCiphertextList<&'_ mut [Scalar]> {
let lwe_size = self.lwe_size();
let compression_seed = self.compression_seed();
SeededLweCiphertextList::from_container(self.as_mut(), lwe_size, compression_seed)
let ciphertext_modulus = self.ciphertext_modulus();
SeededLweCiphertextList::from_container(
self.as_mut(),
lwe_size,
compression_seed,
ciphertext_modulus,
)
}
}
@@ -169,7 +196,7 @@ pub type SeededLweCiphertextListView<'data, Scalar> = SeededLweCiphertextList<&'
pub type SeededLweCiphertextListMutView<'data, Scalar> =
SeededLweCiphertextList<&'data mut [Scalar]>;
impl<Scalar: Copy> SeededLweCiphertextListOwned<Scalar> {
impl<Scalar: UnsignedInteger> SeededLweCiphertextListOwned<Scalar> {
/// Allocate memory and create a new owned [`SeededLweCiphertextList`].
///
/// # Note
@@ -186,11 +213,13 @@ impl<Scalar: Copy> SeededLweCiphertextListOwned<Scalar> {
lwe_size: LweSize,
ciphertext_count: LweCiphertextCount,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> SeededLweCiphertextListOwned<Scalar> {
SeededLweCiphertextListOwned::from_container(
vec![fill_with; ciphertext_count.0],
lwe_size,
compression_seed,
ciphertext_modulus,
)
}
}
@@ -198,24 +227,32 @@ impl<Scalar: Copy> SeededLweCiphertextListOwned<Scalar> {
/// Metadata used in the [`CreateFrom`] implementation to create [`SeededLweCiphertextList`]
/// entities.
#[derive(Clone, Copy)]
pub struct SeededLweCiphertextListCreationMetadata(pub LweSize, pub CompressionSeed);
pub struct SeededLweCiphertextListCreationMetadata<Scalar: UnsignedInteger>(
pub LweSize,
pub CompressionSeed,
pub CiphertextModulus<Scalar>,
);
impl<C: Container> CreateFrom<C> for SeededLweCiphertextList<C> {
type Metadata = SeededLweCiphertextListCreationMetadata;
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C>
for SeededLweCiphertextList<C>
{
type Metadata = SeededLweCiphertextListCreationMetadata<C::Element>;
#[inline]
fn create_from(from: C, meta: Self::Metadata) -> SeededLweCiphertextList<C> {
let SeededLweCiphertextListCreationMetadata(lwe_size, compression_seed) = meta;
SeededLweCiphertextList::from_container(from, lwe_size, compression_seed)
let SeededLweCiphertextListCreationMetadata(lwe_size, compression_seed, modulus) = meta;
SeededLweCiphertextList::from_container(from, lwe_size, compression_seed, modulus)
}
}
impl<C: Container> ContiguousEntityContainer for SeededLweCiphertextList<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> ContiguousEntityContainer
for SeededLweCiphertextList<C>
{
type Element = C::Element;
type EntityViewMetadata = ();
type EntityViewMetadata = LweCiphertextCreationMetadata<Self::Element>;
type EntityView<'this> = LweBody<&'this Self::Element>
type EntityView<'this> = LweBodyRef<'this, Self::Element>
where
Self: 'this;
@@ -225,7 +262,9 @@ impl<C: Container> ContiguousEntityContainer for SeededLweCiphertextList<C> {
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) {}
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
LweCiphertextCreationMetadata(self.ciphertext_modulus())
}
fn get_entity_view_pod_size(&self) -> usize {
1
@@ -233,7 +272,7 @@ impl<C: Container> ContiguousEntityContainer for SeededLweCiphertextList<C> {
/// Unimplemented for [`SeededLweCiphertextList`]. At the moment it does not make sense to
/// return "sub" seeded lists.
fn get_self_view_creation_metadata(&self) {
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
unimplemented!(
"This function is not supported for SeededLweCiphertextList. \
At the moment it does not make sense to return 'sub' seeded lists."
@@ -241,8 +280,10 @@ impl<C: Container> ContiguousEntityContainer for SeededLweCiphertextList<C> {
}
}
impl<C: ContainerMut> ContiguousEntityContainerMut for SeededLweCiphertextList<C> {
type EntityMutView<'this> = LweBody<&'this mut Self::Element>
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> ContiguousEntityContainerMut
for SeededLweCiphertextList<C>
{
type EntityMutView<'this> = LweBodyRefMut<'this, Self::Element>
where
Self: 'this;

View File

@@ -1,4 +1,4 @@
//! Module containing the definition of the SeededLweKeyswitchKey.
//! Module containing the definition of the [`SeededLweKeyswitchKey`].
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::math::random::{ActivatedRandomGenerator, CompressionSeed};
@@ -8,21 +8,25 @@ use crate::core_crypto::entities::*;
/// A [`seeded LWE keyswitch key`](`SeededLweKeyswitchKey`).
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct SeededLweKeyswitchKey<C: Container> {
pub struct SeededLweKeyswitchKey<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
output_lwe_size: LweSize,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<T, C: Container<Element = T>> AsRef<[T]> for SeededLweKeyswitchKey<C> {
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for SeededLweKeyswitchKey<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T, C: ContainerMut<Element = T>> AsMut<[T]> for SeededLweKeyswitchKey<C> {
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for SeededLweKeyswitchKey<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
@@ -37,7 +41,7 @@ pub fn seeded_lwe_keyswitch_key_input_key_element_encrypted_size(
decomp_level_count.0
}
impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
/// Create an [`SeededLweKeyswitchKey`] from an existing container.
///
/// # Note
@@ -59,6 +63,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
/// let output_lwe_dimension = LweDimension(1024);
/// let decomp_base_log = DecompositionBaseLog(4);
/// let decomp_level_count = DecompositionLevelCount(5);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Get a seeder
/// let mut seeder = new_seeder();
@@ -72,6 +77,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
/// input_lwe_dimension,
/// output_lwe_dimension,
/// seeder.seed().into(),
/// ciphertext_modulus,
/// );
///
/// assert_eq!(lwe_ksk.decomposition_base_log(), decomp_base_log);
@@ -82,6 +88,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
/// lwe_ksk.output_lwe_size(),
/// output_lwe_dimension.to_lwe_size()
/// );
/// assert_eq!(lwe_ksk.ciphertext_modulus(), ciphertext_modulus);
///
/// let compression_seed = lwe_ksk.compression_seed();
///
@@ -95,6 +102,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
/// decomp_level_count,
/// output_lwe_dimension.to_lwe_size(),
/// compression_seed,
/// ciphertext_modulus,
/// );
///
/// assert_eq!(lwe_ksk.decomposition_base_log(), decomp_base_log);
@@ -105,6 +113,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
/// lwe_ksk.output_lwe_size(),
/// output_lwe_dimension.to_lwe_size()
/// );
/// assert_eq!(lwe_ksk.ciphertext_modulus(), ciphertext_modulus);
///
/// let lwe_ksk = lwe_ksk.decompress_into_lwe_keyswitch_key();
///
@@ -116,6 +125,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
/// lwe_ksk.output_lwe_size(),
/// output_lwe_dimension.to_lwe_size()
/// );
/// assert_eq!(lwe_ksk.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_container(
container: C,
@@ -123,6 +133,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
decomp_level_count: DecompositionLevelCount,
output_lwe_size: LweSize,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
assert!(
container.container_len() > 0,
@@ -143,6 +154,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
decomp_level_count,
output_lwe_size,
compression_seed,
ciphertext_modulus,
}
}
@@ -203,6 +215,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
self.decomp_level_count,
self.output_lwe_size,
self.compression_seed,
self.ciphertext_modulus,
)
}
@@ -227,6 +240,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
self.decomposition_level_count(),
self.input_key_lwe_dimension(),
self.output_key_lwe_dimension(),
self.ciphertext_modulus(),
);
decompress_seeded_lwe_keyswitch_key::<_, _, _, ActivatedRandomGenerator>(
&mut decompressed_ksk,
@@ -240,23 +254,30 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLweKeyswitchKey<C> {
self.as_ref(),
self.output_lwe_size(),
self.compression_seed(),
self.ciphertext_modulus(),
)
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
}
impl<Scalar, C: ContainerMut<Element = Scalar>> SeededLweKeyswitchKey<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> SeededLweKeyswitchKey<C> {
/// Mutable variant of [`SeededLweKeyswitchKey::as_view`].
pub fn as_mut_view(&mut self) -> SeededLweKeyswitchKey<&'_ mut [Scalar]> {
let decomp_base_log = self.decomp_base_log;
let decomp_level_count = self.decomp_level_count;
let output_lwe_size = self.output_lwe_size;
let compression_seed = self.compression_seed;
let ciphertext_modulus = self.ciphertext_modulus;
SeededLweKeyswitchKey::from_container(
self.as_mut(),
decomp_base_log,
decomp_level_count,
output_lwe_size,
compression_seed,
ciphertext_modulus,
)
}
@@ -265,10 +286,12 @@ impl<Scalar, C: ContainerMut<Element = Scalar>> SeededLweKeyswitchKey<C> {
) -> SeededLweCiphertextListMutView<'_, Scalar> {
let output_lwe_size = self.output_lwe_size();
let compression_seed = self.compression_seed();
let ciphertext_modulus = self.ciphertext_modulus();
SeededLweCiphertextListMutView::from_container(
self.as_mut(),
output_lwe_size,
compression_seed,
ciphertext_modulus,
)
}
}
@@ -276,7 +299,7 @@ impl<Scalar, C: ContainerMut<Element = Scalar>> SeededLweKeyswitchKey<C> {
/// An [`SeededLweKeyswitchKey`] owning the memory for its own storage.
pub type SeededLweKeyswitchKeyOwned<Scalar> = SeededLweKeyswitchKey<Vec<Scalar>>;
impl<Scalar: Copy> SeededLweKeyswitchKeyOwned<Scalar> {
impl<Scalar: UnsignedInteger> SeededLweKeyswitchKeyOwned<Scalar> {
/// Allocate memory and create a new owned [`SeededLweKeyswitchKey`].
///
/// # Note
@@ -294,6 +317,7 @@ impl<Scalar: Copy> SeededLweKeyswitchKeyOwned<Scalar> {
input_key_lwe_dimension: LweDimension,
output_key_lwe_dimension: LweDimension,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> SeededLweKeyswitchKeyOwned<Scalar> {
SeededLweKeyswitchKeyOwned::from_container(
vec![
@@ -305,14 +329,17 @@ impl<Scalar: Copy> SeededLweKeyswitchKeyOwned<Scalar> {
decomp_level_count,
output_key_lwe_dimension.to_lwe_size(),
compression_seed,
ciphertext_modulus,
)
}
}
impl<C: Container> ContiguousEntityContainer for SeededLweKeyswitchKey<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> ContiguousEntityContainer
for SeededLweKeyswitchKey<C>
{
type Element = C::Element;
type EntityViewMetadata = SeededLweCiphertextListCreationMetadata;
type EntityViewMetadata = SeededLweCiphertextListCreationMetadata<Self::Element>;
type EntityView<'this> = SeededLweCiphertextListView<'this, Self::Element>
where
@@ -326,8 +353,14 @@ impl<C: Container> ContiguousEntityContainer for SeededLweKeyswitchKey<C> {
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> SeededLweCiphertextListCreationMetadata {
SeededLweCiphertextListCreationMetadata(self.output_lwe_size(), self.compression_seed())
fn get_entity_view_creation_metadata(
&self,
) -> SeededLweCiphertextListCreationMetadata<Self::Element> {
SeededLweCiphertextListCreationMetadata(
self.output_lwe_size(),
self.compression_seed(),
self.ciphertext_modulus(),
)
}
fn get_entity_view_pod_size(&self) -> usize {
@@ -336,7 +369,7 @@ impl<C: Container> ContiguousEntityContainer for SeededLweKeyswitchKey<C> {
/// Unimplemented for [`SeededLweKeyswitchKey`]. At the moment it does not make sense to
/// return "sub" keyswitch keys.
fn get_self_view_creation_metadata(&self) {
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
unimplemented!(
"This function is not supported for SeededLweKeyswitchKey. \
At the moment it does not make sense to return 'sub' keyswitch keys."
@@ -344,7 +377,9 @@ impl<C: Container> ContiguousEntityContainer for SeededLweKeyswitchKey<C> {
}
}
impl<C: ContainerMut> ContiguousEntityContainerMut for SeededLweKeyswitchKey<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> ContiguousEntityContainerMut
for SeededLweKeyswitchKey<C>
{
type EntityMutView<'this> = SeededLweCiphertextListMutView<'this, Self::Element>
where
Self: 'this;

View File

@@ -1,4 +1,4 @@
//! Module containing the definition of the SeededLwePublicKey.
//! Module containing the definition of the [`SeededLwePublicKey`].
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::math::random::{ActivatedRandomGenerator, CompressionSeed};
@@ -25,11 +25,16 @@ use crate::core_crypto::entities::*;
/// $\vec{s}\in\mathbb{Z}\_q^n$ where $n$ is the LWE dimension of the ciphertexts contained in the
/// public key.
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct SeededLwePublicKey<C: Container> {
pub struct SeededLwePublicKey<C: Container>
where
C::Element: UnsignedInteger,
{
lwe_list: SeededLweCiphertextList<C>,
}
impl<C: Container> std::ops::Deref for SeededLwePublicKey<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> std::ops::Deref
for SeededLwePublicKey<C>
{
type Target = SeededLweCiphertextList<C>;
fn deref(&self) -> &SeededLweCiphertextList<C> {
@@ -37,13 +42,15 @@ impl<C: Container> std::ops::Deref for SeededLwePublicKey<C> {
}
}
impl<C: ContainerMut> std::ops::DerefMut for SeededLwePublicKey<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> std::ops::DerefMut
for SeededLwePublicKey<C>
{
fn deref_mut(&mut self) -> &mut SeededLweCiphertextList<C> {
&mut self.lwe_list
}
}
impl<Scalar, C: Container<Element = Scalar>> SeededLwePublicKey<C> {
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> SeededLwePublicKey<C> {
/// Create an [`SeededLwePublicKey`] from an existing container.
///
/// # Note
@@ -62,14 +69,20 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLwePublicKey<C> {
/// // Define parameters for SeededLwePublicKey creation
/// let lwe_size = LweSize(600);
/// let zero_encryption_count = LwePublicKeyZeroEncryptionCount(3);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Get a seeder
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
///
/// // Create a new SeededLwePublicKey
/// let seeded_lwe_public_key =
/// SeededLwePublicKey::new(0u64, lwe_size, zero_encryption_count, seeder.seed().into());
/// let seeded_lwe_public_key = SeededLwePublicKey::new(
/// 0u64,
/// lwe_size,
/// zero_encryption_count,
/// seeder.seed().into(),
/// ciphertext_modulus,
/// );
///
/// // This is a method from LweCiphertextList
/// assert_eq!(seeded_lwe_public_key.lwe_size(), lwe_size);
@@ -78,6 +91,10 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLwePublicKey<C> {
/// seeded_lwe_public_key.zero_encryption_count(),
/// zero_encryption_count
/// );
/// assert_eq!(
/// seeded_lwe_public_key.ciphertext_modulus(),
/// ciphertext_modulus
/// );
///
/// let compression_seed = seeded_lwe_public_key.compression_seed();
///
@@ -85,14 +102,22 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLwePublicKey<C> {
/// let underlying_container: Vec<u64> = seeded_lwe_public_key.into_container();
///
/// // Recreate a public key using from_container
/// let seeded_lwe_public_key =
/// SeededLwePublicKey::from_container(underlying_container, lwe_size, compression_seed);
/// let seeded_lwe_public_key = SeededLwePublicKey::from_container(
/// underlying_container,
/// lwe_size,
/// compression_seed,
/// ciphertext_modulus,
/// );
///
/// assert_eq!(seeded_lwe_public_key.lwe_size(), lwe_size);
/// assert_eq!(
/// seeded_lwe_public_key.zero_encryption_count(),
/// zero_encryption_count
/// );
/// assert_eq!(
/// seeded_lwe_public_key.ciphertext_modulus(),
/// ciphertext_modulus
/// );
///
/// // Decompress the key
/// let lwe_public_key = seeded_lwe_public_key.decompress_into_lwe_public_key();
@@ -102,11 +127,13 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLwePublicKey<C> {
/// lwe_public_key.zero_encryption_count(),
/// zero_encryption_count
/// );
/// assert_eq!(lwe_public_key.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_container(
container: C,
lwe_size: LweSize,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> SeededLwePublicKey<C> {
assert!(
container.container_len() > 0,
@@ -117,6 +144,7 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLwePublicKey<C> {
container,
lwe_size,
compression_seed,
ciphertext_modulus,
),
}
}
@@ -143,8 +171,12 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLwePublicKey<C> {
where
Scalar: UnsignedTorus,
{
let mut decompressed_list =
LwePublicKey::new(Scalar::ZERO, self.lwe_size(), self.zero_encryption_count());
let mut decompressed_list = LwePublicKey::new(
Scalar::ZERO,
self.lwe_size(),
self.zero_encryption_count(),
self.ciphertext_modulus(),
);
decompress_seeded_lwe_public_key::<_, _, _, ActivatedRandomGenerator>(
&mut decompressed_list,
&self,
@@ -155,23 +187,34 @@ impl<Scalar, C: Container<Element = Scalar>> SeededLwePublicKey<C> {
/// Return a view of the [`SeededLwePublicKey`]. This is useful if an algorithm takes a view by
/// value.
pub fn as_view(&self) -> SeededLwePublicKey<&'_ [Scalar]> {
SeededLwePublicKey::from_container(self.as_ref(), self.lwe_size(), self.compression_seed())
SeededLwePublicKey::from_container(
self.as_ref(),
self.lwe_size(),
self.compression_seed(),
self.ciphertext_modulus(),
)
}
}
impl<Scalar, C: ContainerMut<Element = Scalar>> SeededLwePublicKey<C> {
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> SeededLwePublicKey<C> {
/// Mutable variant of [`SeededLwePublicKey::as_view`].
pub fn as_mut_view(&mut self) -> SeededLwePublicKey<&'_ mut [Scalar]> {
let lwe_size = self.lwe_size();
let compression_seed = self.compression_seed();
SeededLwePublicKey::from_container(self.as_mut(), lwe_size, compression_seed)
let ciphertext_modulus = self.ciphertext_modulus();
SeededLwePublicKey::from_container(
self.as_mut(),
lwe_size,
compression_seed,
ciphertext_modulus,
)
}
}
/// An [`SeededLwePublicKey`] owning the memory for its own storage.
pub type SeededLwePublicKeyOwned<Scalar> = SeededLwePublicKey<Vec<Scalar>>;
impl<Scalar: Copy> SeededLwePublicKeyOwned<Scalar> {
impl<Scalar: UnsignedInteger> SeededLwePublicKeyOwned<Scalar> {
/// Allocate memory and create a new owned [`SeededLwePublicKey`].
///
/// # Note
@@ -186,11 +229,13 @@ impl<Scalar: Copy> SeededLwePublicKeyOwned<Scalar> {
lwe_size: LweSize,
zero_encryption_count: LwePublicKeyZeroEncryptionCount,
compression_seed: CompressionSeed,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> SeededLwePublicKeyOwned<Scalar> {
SeededLwePublicKeyOwned::from_container(
vec![fill_with; zero_encryption_count.0],
lwe_size,
compression_seed,
ciphertext_modulus,
)
}
}

View File

@@ -273,8 +273,8 @@ impl<'a> FourierLweBootstrapKeyView<'a> {
pub fn bootstrap<Scalar>(
self,
lwe_out: &mut [Scalar],
lwe_in: &[Scalar],
mut lwe_out: LweCiphertextMutView<'_, Scalar>,
lwe_in: LweCiphertextView<'_, Scalar>,
accumulator: GlweCiphertextView<'_, Scalar>,
fft: FftView<'_>,
stack: DynStack<'_>,
@@ -282,16 +282,21 @@ impl<'a> FourierLweBootstrapKeyView<'a> {
// CastInto required for PBS modulus switch which returns a usize
Scalar: UnsignedTorus + CastInto<usize>,
{
assert!(
lwe_in.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
let (mut local_accumulator_data, stack) =
stack.collect_aligned(CACHELINE_ALIGN, accumulator.as_ref().iter().copied());
let mut local_accumulator = GlweCiphertextMutView::from_container(
&mut *local_accumulator_data,
accumulator.polynomial_size(),
);
self.blind_rotate_assign(local_accumulator.as_mut_view(), lwe_in, fft, stack);
self.blind_rotate_assign(local_accumulator.as_mut_view(), lwe_in.as_ref(), fft, stack);
extract_lwe_sample_from_glwe_ciphertext(
&local_accumulator,
&mut LweCiphertextMutView::from_container(&mut *lwe_out),
&mut lwe_out,
MonomialDegree(0),
);
}

View File

@@ -66,6 +66,11 @@ pub fn extract_bits<Scalar: UnsignedTorus + CastInto<usize>>(
fft: FftView<'_>,
stack: DynStack<'_>,
) {
assert!(
lwe_in.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
let ciphertext_n_bits = Scalar::BITS;
let number_of_bits_to_extract = number_of_bits_to_extract.0;
@@ -111,11 +116,13 @@ pub fn extract_bits<Scalar: UnsignedTorus + CastInto<usize>>(
let (mut lwe_in_buffer_data, stack) =
stack.collect_aligned(align, lwe_in.as_ref().iter().copied());
let mut lwe_in_buffer = LweCiphertext::from_container(&mut *lwe_in_buffer_data);
let mut lwe_in_buffer =
LweCiphertext::from_container(&mut *lwe_in_buffer_data, lwe_in.ciphertext_modulus());
let (mut lwe_out_ks_buffer_data, stack) =
stack.make_aligned_with(ksk.output_lwe_size().0, align, |_| Scalar::ZERO);
let mut lwe_out_ks_buffer = LweCiphertext::from_container(&mut *lwe_out_ks_buffer_data);
let mut lwe_out_ks_buffer =
LweCiphertext::from_container(&mut *lwe_out_ks_buffer_data, ksk.ciphertext_modulus());
let (mut pbs_accumulator_data, stack) =
stack.make_aligned_with(glwe_size.0 * polynomial_size.0, align, |_| Scalar::ZERO);
@@ -125,7 +132,10 @@ pub fn extract_bits<Scalar: UnsignedTorus + CastInto<usize>>(
let lwe_size = LweSize(glwe_dimension.0 * polynomial_size.0 + 1);
let (mut lwe_out_pbs_buffer_data, mut stack) =
stack.make_aligned_with(lwe_size.0, align, |_| Scalar::ZERO);
let mut lwe_out_pbs_buffer = LweCiphertext::from_container(&mut *lwe_out_pbs_buffer_data);
let mut lwe_out_pbs_buffer = LweCiphertext::from_container(
&mut *lwe_out_pbs_buffer_data,
lwe_list_out.ciphertext_modulus(),
);
// We iterate on the list in reverse as we want to store the extracted MSB at index 0
for (bit_idx, mut output_ct) in lwe_list_out.iter_mut().rev().enumerate() {
@@ -141,7 +151,10 @@ pub fn extract_bits<Scalar: UnsignedTorus + CastInto<usize>>(
// Key switch to input PBS key
keyswitch_lwe_ciphertext(
&ksk,
&LweCiphertext::from_container(&*lwe_bit_left_shift_buffer_data),
&LweCiphertext::from_container(
&*lwe_bit_left_shift_buffer_data,
lwe_in.ciphertext_modulus(),
),
&mut lwe_out_ks_buffer,
);
@@ -160,7 +173,7 @@ pub fn extract_bits<Scalar: UnsignedTorus + CastInto<usize>>(
}
// Add q/4 to center the error while computing a negacyclic LUT
let out_ks_body = lwe_out_ks_buffer.get_mut_body().0;
let out_ks_body = lwe_out_ks_buffer.get_mut_body().data;
*out_ks_body = (*out_ks_body).wrapping_add(Scalar::ONE << (ciphertext_n_bits - 2));
// Fill lut for the current bit (equivalent to trivial encryption as mask is 0s)
@@ -175,8 +188,8 @@ pub fn extract_bits<Scalar: UnsignedTorus + CastInto<usize>>(
}
fourier_bsk.bootstrap(
lwe_out_pbs_buffer.as_mut(),
lwe_out_ks_buffer.as_ref(),
lwe_out_pbs_buffer.as_mut_view(),
lwe_out_ks_buffer.as_view(),
pbs_accumulator.as_view(),
fft,
stack.rb_mut(),
@@ -184,7 +197,7 @@ pub fn extract_bits<Scalar: UnsignedTorus + CastInto<usize>>(
// Add alpha where alpha = delta*2^{bit_idx-1} to end up with an encryption of 0 if the
// extracted bit was 0 and 1 in the other case
let out_pbs_body = lwe_out_pbs_buffer.get_mut_body().0;
let out_pbs_body = lwe_out_pbs_buffer.get_mut_body().data;
*out_pbs_body = (*out_pbs_body).wrapping_add(Scalar::ONE << (delta_log.0 + bit_idx - 1));
@@ -219,6 +232,11 @@ pub fn circuit_bootstrap_boolean<Scalar: UnsignedTorus + CastInto<usize>>(
fft: FftView<'_>,
stack: DynStack<'_>,
) {
assert!(
lwe_in.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
let level_cbs = ggsw_out.decomposition_level_count();
let base_log_cbs = ggsw_out.decomposition_base_log();
@@ -276,7 +294,8 @@ pub fn circuit_bootstrap_boolean<Scalar: UnsignedTorus + CastInto<usize>>(
CACHELINE_ALIGN,
|_| Scalar::ZERO,
);
let mut lwe_out_bs_buffer = LweCiphertext::from_container(&mut *lwe_out_bs_buffer_data);
let mut lwe_out_bs_buffer =
LweCiphertext::from_container(&mut *lwe_out_bs_buffer_data, lwe_in.ciphertext_modulus());
// Output for every pfksk that come from the output GGSW
let mut glwe_out_pfksk_buffer = ggsw_out.as_mut_glwe_list();
@@ -339,13 +358,21 @@ pub fn homomorphic_shift_boolean<Scalar: UnsignedTorus + CastInto<usize>>(
fft: FftView<'_>,
stack: DynStack<'_>,
) {
assert!(
lwe_in.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
let ciphertext_n_bits = Scalar::BITS;
let lwe_in_size = lwe_in.lwe_size();
let polynomial_size = fourier_bsk.polynomial_size();
let (mut lwe_left_shift_buffer_data, stack) =
stack.make_aligned_with(lwe_in_size.0, CACHELINE_ALIGN, |_| Scalar::ZERO);
let mut lwe_left_shift_buffer = LweCiphertext::from_container(&mut *lwe_left_shift_buffer_data);
let mut lwe_left_shift_buffer = LweCiphertext::from_container(
&mut *lwe_left_shift_buffer_data,
lwe_in.ciphertext_modulus(),
);
// Shift message LSB on padding bit, at this point we expect to have messages with only 1 bit
// of information
lwe_ciphertext_cleartext_mul(
@@ -356,8 +383,8 @@ pub fn homomorphic_shift_boolean<Scalar: UnsignedTorus + CastInto<usize>>(
// Add q/4 to center the error while computing a negacyclic LUT
let shift_buffer_body = lwe_left_shift_buffer.get_mut_body();
*shift_buffer_body.0 =
(*shift_buffer_body.0).wrapping_add(Scalar::ONE << (ciphertext_n_bits - 2));
*shift_buffer_body.data =
(*shift_buffer_body.data).wrapping_add(Scalar::ONE << (ciphertext_n_bits - 2));
let (mut pbs_accumulator_data, stack) = stack.make_aligned_with(
polynomial_size.0 * fourier_bsk.glwe_size().0,
@@ -379,8 +406,8 @@ pub fn homomorphic_shift_boolean<Scalar: UnsignedTorus + CastInto<usize>>(
// Applying a negacyclic LUT on a ciphertext with one bit of message in the MSB and no bit
// of padding
fourier_bsk.bootstrap(
lwe_out.as_mut(),
lwe_left_shift_buffer.as_ref(),
lwe_out.as_mut_view(),
lwe_left_shift_buffer.as_view(),
pbs_accumulator.as_view(),
fft,
stack,
@@ -389,7 +416,7 @@ pub fn homomorphic_shift_boolean<Scalar: UnsignedTorus + CastInto<usize>>(
// Add alpha where alpha = 2^{log(q) - 1 - base_log * level}
// To end up with an encryption of 0 if the message bit was 0 and 1 in the other case
let out_body = lwe_out.get_mut_body();
*out_body.0 = (*out_body.0)
*out_body.data = (*out_body.data)
.wrapping_add(Scalar::ONE << (ciphertext_n_bits - 1 - base_log_cbs.0 * level_count_cbs.0));
}
@@ -947,6 +974,11 @@ pub fn vertical_packing<Scalar: UnsignedTorus + CastInto<usize>>(
fft: FftView<'_>,
stack: DynStack<'_>,
) {
assert!(
lwe_out.ciphertext_modulus().is_native_modulus(),
"This operation only supports native moduli"
);
let polynomial_size = ggsw_list.polynomial_size();
let glwe_size = ggsw_list.glwe_size();
let glwe_dimension = glwe_size.to_glwe_dimension();

View File

@@ -33,6 +33,8 @@ pub fn test_extract_bits() {
let std = LogStandardDev::from_log_standard_dev(-60.);
let ciphertext_modulus = CiphertextModulus::new_native();
let number_of_bits_of_message_including_padding = 5_usize;
// Tests take about 2-3 seconds on a laptop with this number
let number_of_test_runs = 32;
@@ -74,14 +76,16 @@ pub fn test_extract_bits() {
let fft = fft.as_view();
let lwe_big_sk = glwe_sk.clone().into_lwe_secret_key();
let ksk_lwe_big_to_small = allocate_and_generate_new_lwe_keyswitch_key(
&lwe_big_sk,
&lwe_small_sk,
base_log_ksk,
level_ksk,
std,
&mut encryption_generator,
);
let ksk_lwe_big_to_small: LweKeyswitchKeyOwned<u64> =
allocate_and_generate_new_lwe_keyswitch_key(
&lwe_big_sk,
&lwe_small_sk,
base_log_ksk,
level_ksk,
std,
ciphertext_modulus,
&mut encryption_generator,
);
let req = || {
StackReq::try_any_of([
@@ -118,7 +122,11 @@ pub fn test_extract_bits() {
// Encryption
let message = Plaintext(val << delta_log.0);
println!("{message:?}");
let mut lwe_in = LweCiphertextOwned::new(0u64, lwe_big_sk.lwe_dimension().to_lwe_size());
let mut lwe_in = LweCiphertextOwned::new(
0u64,
lwe_big_sk.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
encrypt_lwe_ciphertext(
&lwe_big_sk,
&mut lwe_in,
@@ -135,6 +143,7 @@ pub fn test_extract_bits() {
0u64,
ksk_lwe_big_to_small.output_lwe_size(),
LweCiphertextCount(number_values_to_extract.0),
ciphertext_modulus,
);
extract_bits(
@@ -188,6 +197,8 @@ fn test_circuit_bootstrapping_binary() {
let std = LogStandardDev::from_log_standard_dev(-60.);
let ciphertext_modulus = CiphertextModulus::new_native();
let mut seeder = new_seeder();
let seeder = seeder.as_mut();
@@ -252,7 +263,8 @@ fn test_circuit_bootstrapping_binary() {
let value: u64 = test_tools::random_uint_between(0..2u64);
// Encryption of an LWE with the value 'message'
let message = Plaintext((value) << delta_log.0);
let mut lwe_in = LweCiphertextOwned::new(0u64, lwe_dimension.to_lwe_size());
let mut lwe_in =
LweCiphertextOwned::new(0u64, lwe_dimension.to_lwe_size(), ciphertext_modulus);
encrypt_lwe_ciphertext(
&lwe_sk,
&mut lwe_in,
@@ -519,6 +531,8 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() {
let level_cbs = DecompositionLevelCount(4);
let base_log_cbs = DecompositionBaseLog(6);
let ciphertext_modulus = CiphertextModulus::new_native();
// Value was 0.000_000_000_000_000_221_486_881_160_055_68_513645324585951
// But rust indicates it gets truncated anyways to
// 0.000_000_000_000_000_221_486_881_160_055_68
@@ -575,14 +589,16 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() {
DynStack::new(&mut mem),
);
let ksk_lwe_big_to_small = allocate_and_generate_new_lwe_keyswitch_key(
&lwe_big_sk,
&lwe_small_sk,
base_log_ksk,
level_ksk,
std_big,
&mut encryption_generator,
);
let ksk_lwe_big_to_small: LweKeyswitchKeyOwned<u64> =
allocate_and_generate_new_lwe_keyswitch_key(
&lwe_big_sk,
&lwe_small_sk,
base_log_ksk,
level_ksk,
std_big,
ciphertext_modulus,
&mut encryption_generator,
);
// Creation of all the pfksk for the circuit bootstrapping
let vec_pfpksk = par_allocate_and_generate_new_circuit_bootstrap_lwe_pfpksk_list(
@@ -614,8 +630,11 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() {
println!("cleartext bits: {cleartext:b}");
let message = Plaintext(cleartext << delta_log.0);
let mut lwe_in =
LweCiphertextOwned::new(0u64, LweSize(glwe_dimension.0 * polynomial_size.0 + 1));
let mut lwe_in = LweCiphertextOwned::new(
0u64,
LweSize(glwe_dimension.0 * polynomial_size.0 + 1),
ciphertext_modulus,
);
encrypt_lwe_ciphertext(
&lwe_big_sk,
&mut lwe_in,
@@ -628,6 +647,7 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() {
0u64,
ksk_lwe_big_to_small.output_lwe_size(),
LweCiphertextCount(number_of_values_to_extract.0),
ciphertext_modulus,
);
let mut mem = GlobalMemBuffer::new(
@@ -697,6 +717,7 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() {
0u64,
LweDimension(polynomial_size.0 * glwe_dimension.0).to_lwe_size(),
LweCiphertextCount(number_of_luts_and_output_vp_ciphertexts),
ciphertext_modulus,
);
// Perform circuit bootstrap + vertical packing

View File

@@ -322,7 +322,7 @@ impl ClientKey {
// We want to take at most 64 bits of data from the bit buffer
// since our words are 64 bits
let power_to_write = std::cmp::min(valid_until_power, U64_MODULUS);
let power_to_write = valid_until_power.min(U64_MODULUS);
let mask = power_to_write - 1;
*current_clear_word = (bit_buffer & mask) as u64;
bit_buffer /= power_to_write;

View File

@@ -1,5 +1,5 @@
#![allow(clippy::excessive_precision)]
pub use crate::shortint::Parameters;
pub use crate::shortint::{CiphertextModulus, Parameters};
use crate::shortint::parameters::{CarryModulus, MessageModulus};
pub use crate::shortint::parameters::{
@@ -29,6 +29,7 @@ pub const PARAM_MESSAGE_4_CARRY_4_16_BITS: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_2_CARRY_2_16_BITS: Parameters = Parameters {
@@ -48,6 +49,7 @@ pub const PARAM_MESSAGE_2_CARRY_2_16_BITS: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_4_CARRY_4_32_BITS: Parameters = Parameters {
@@ -67,7 +69,9 @@ pub const PARAM_MESSAGE_4_CARRY_4_32_BITS: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_2_CARRY_2_32_BITS: Parameters = Parameters {
lwe_dimension: LweDimension(481),
glwe_dimension: GlweDimension(1),
@@ -85,7 +89,9 @@ pub const PARAM_MESSAGE_2_CARRY_2_32_BITS: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_1_CARRY_1_32_BITS: Parameters = Parameters {
lwe_dimension: LweDimension(493),
glwe_dimension: GlweDimension(1),
@@ -103,6 +109,7 @@ pub const PARAM_MESSAGE_1_CARRY_1_32_BITS: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_4_BITS_5_BLOCKS: Parameters = Parameters {
@@ -122,4 +129,5 @@ pub const PARAM_4_BITS_5_BLOCKS: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};

View File

@@ -220,6 +220,7 @@ impl WopbsKey {
0u64,
extract_bits_output_lwe_size,
LweCiphertextCount(total_bits_extracted),
self.wopbs_key.param.ciphertext_modulus,
);
let mut bits_extracted_so_far = 0;
@@ -304,6 +305,7 @@ impl WopbsKey {
0u64,
extract_bits_output_lwe_size,
LweCiphertextCount(total_bits_extracted),
self.wopbs_key.param.ciphertext_modulus,
);
let mut bits_extracted_so_far = 0;
@@ -991,6 +993,7 @@ impl WopbsKey {
0u64,
extract_bits_output_lwe_size,
LweCiphertextCount(total_bits_extracted),
self.wopbs_key.param.ciphertext_modulus,
);
let mut bits_extracted_so_far = 0;

View File

@@ -53,6 +53,8 @@ pub struct Shortint {}
#[wasm_bindgen]
pub struct ShortintParameters(pub(crate) crate::shortint::Parameters);
pub const SHORTINT_NATIVE_MODULUS: u64 = 0;
#[wasm_bindgen]
impl Shortint {
#[wasm_bindgen]
@@ -148,6 +150,7 @@ impl Shortint {
cbs_base_log: usize,
message_modulus: usize,
carry_modulus: usize,
ciphertext_modulus: u64,
) -> ShortintParameters {
set_hook(Box::new(console_error_panic_hook::hook));
use crate::core_crypto::prelude::*;
@@ -168,6 +171,10 @@ impl Shortint {
cbs_base_log: DecompositionBaseLog(cbs_base_log),
message_modulus: crate::shortint::parameters::MessageModulus(message_modulus),
carry_modulus: crate::shortint::parameters::CarryModulus(carry_modulus),
ciphertext_modulus: crate::shortint::parameters::CiphertextModulus::try_new(
ciphertext_modulus as u128,
)
.unwrap(),
})
}

View File

@@ -83,6 +83,7 @@ impl ShortintEngine {
client_lwe_sk,
encoded,
noise_parameter,
client_key_parameters.ciphertext_modulus,
&mut self.encryption_generator,
)
}
@@ -166,6 +167,7 @@ impl ShortintEngine {
encryption_lwe_sk,
encoded,
encryption_noise,
client_key.parameters.ciphertext_modulus,
&mut self.seeder,
);
@@ -205,6 +207,7 @@ impl ShortintEngine {
encryption_lwe_sk,
encoded,
encryption_noise,
client_key.parameters.ciphertext_modulus,
&mut self.encryption_generator,
);
@@ -286,6 +289,7 @@ impl ShortintEngine {
encryption_lwe_sk,
encoded,
encryption_noise,
client_key.parameters.ciphertext_modulus,
&mut self.encryption_generator,
);
@@ -328,6 +332,7 @@ impl ShortintEngine {
encryption_lwe_sk,
encoded,
encryption_noise,
client_key.parameters.ciphertext_modulus,
&mut self.seeder,
);
@@ -405,6 +410,7 @@ impl ShortintEngine {
encryption_lwe_sk,
encoded,
encryption_noise,
client_key.parameters.ciphertext_modulus,
&mut self.encryption_generator,
);
@@ -444,6 +450,7 @@ impl ShortintEngine {
encryption_lwe_sk,
encoded,
encryption_noise,
client_key.parameters.ciphertext_modulus,
&mut self.seeder,
);

View File

@@ -83,8 +83,10 @@ impl Memory {
let (after_ks_elements, after_pbs_elements) =
other_elements.split_at_mut(num_elem_in_lwe_after_ks);
let buffer_lwe_after_ks = LweCiphertextMutView::from_container(after_ks_elements);
let buffer_lwe_after_pbs = LweCiphertextMutView::from_container(after_pbs_elements);
let buffer_lwe_after_ks =
LweCiphertextMutView::from_container(after_ks_elements, server_key.ciphertext_modulus);
let buffer_lwe_after_pbs =
LweCiphertextMutView::from_container(after_pbs_elements, server_key.ciphertext_modulus);
BuffersRef {
accumulator,

View File

@@ -48,6 +48,7 @@ impl ShortintEngine {
secret_encryption_key,
zero_encryption_count,
encryption_noise,
client_key.parameters.ciphertext_modulus,
&mut self.encryption_generator,
);
@@ -56,6 +57,7 @@ impl ShortintEngine {
secret_encryption_key,
zero_encryption_count,
encryption_noise,
client_key.parameters.ciphertext_modulus,
&mut self.encryption_generator,
);
@@ -92,6 +94,7 @@ impl ShortintEngine {
secret_encryption_key,
zero_encryption_count,
encryption_noise,
client_parameters.ciphertext_modulus,
&mut self.seeder,
);
@@ -100,6 +103,7 @@ impl ShortintEngine {
secret_encryption_key,
zero_encryption_count,
encryption_noise,
client_parameters.ciphertext_modulus,
&mut self.seeder,
);
@@ -163,7 +167,11 @@ impl ShortintEngine {
let plain = Plaintext(shifted_message);
// This allocates the required ct
let mut encrypted_ct = LweCiphertextOwned::new(0u64, public_key.lwe_public_key.lwe_size());
let mut encrypted_ct = LweCiphertextOwned::new(
0u64,
public_key.lwe_public_key.lwe_size(),
public_key.lwe_public_key.ciphertext_modulus(),
);
encrypt_lwe_ciphertext_with_public_key(
&public_key.lwe_public_key,
@@ -208,7 +216,11 @@ impl ShortintEngine {
let plain = Plaintext(shifted_message);
// This allocates the required ct
let mut encrypted_ct = LweCiphertext::new(0u64, public_key.lwe_public_key.lwe_size());
let mut encrypted_ct = LweCiphertext::new(
0u64,
public_key.lwe_public_key.lwe_size(),
public_key.lwe_public_key.ciphertext_modulus(),
);
// encryption
encrypt_lwe_ciphertext_with_seeded_public_key(
@@ -243,7 +255,11 @@ impl ShortintEngine {
let plain = Plaintext(shifted_message);
// This allocates the required ct
let mut encrypted_ct = LweCiphertextOwned::new(0u64, public_key.lwe_public_key.lwe_size());
let mut encrypted_ct = LweCiphertextOwned::new(
0u64,
public_key.lwe_public_key.lwe_size(),
public_key.lwe_public_key.ciphertext_modulus(),
);
// encryption
encrypt_lwe_ciphertext_with_public_key(
@@ -278,7 +294,11 @@ impl ShortintEngine {
let plain = Plaintext(shifted_message);
// This allocates the required ct
let mut encrypted_ct = LweCiphertextOwned::new(0u64, public_key.lwe_public_key.lwe_size());
let mut encrypted_ct = LweCiphertextOwned::new(
0u64,
public_key.lwe_public_key.lwe_size(),
public_key.lwe_public_key.ciphertext_modulus(),
);
// encryption
encrypt_lwe_ciphertext_with_seeded_public_key(
@@ -311,7 +331,11 @@ impl ShortintEngine {
let plain = Plaintext(shifted_message as u64);
// This allocates the required ct
let mut encrypted_ct = LweCiphertextOwned::new(0u64, public_key.lwe_public_key.lwe_size());
let mut encrypted_ct = LweCiphertextOwned::new(
0u64,
public_key.lwe_public_key.lwe_size(),
public_key.lwe_public_key.ciphertext_modulus(),
);
encrypt_lwe_ciphertext_with_public_key(
&public_key.lwe_public_key,
@@ -343,7 +367,11 @@ impl ShortintEngine {
let plain = Plaintext(shifted_message as u64);
// This allocates the required ct
let mut encrypted_ct = LweCiphertextOwned::new(0u64, public_key.lwe_public_key.lwe_size());
let mut encrypted_ct = LweCiphertextOwned::new(
0u64,
public_key.lwe_public_key.lwe_size(),
public_key.lwe_public_key.ciphertext_modulus(),
);
encrypt_lwe_ciphertext_with_seeded_public_key(
&public_key.lwe_public_key,
@@ -374,7 +402,11 @@ impl ShortintEngine {
let plain = Plaintext(shifted_message);
// This allocates the required ct
let mut encrypted_ct = LweCiphertextOwned::new(0u64, public_key.lwe_public_key.lwe_size());
let mut encrypted_ct = LweCiphertextOwned::new(
0u64,
public_key.lwe_public_key.lwe_size(),
public_key.lwe_public_key.ciphertext_modulus(),
);
encrypt_lwe_ciphertext_with_public_key(
&public_key.lwe_public_key,
@@ -407,7 +439,11 @@ impl ShortintEngine {
let plain = Plaintext(shifted_message);
// This allocates the required ct
let mut encrypted_ct = LweCiphertextOwned::new(0u64, public_key.lwe_public_key.lwe_size());
let mut encrypted_ct = LweCiphertextOwned::new(
0u64,
public_key.lwe_public_key.lwe_size(),
public_key.lwe_public_key.ciphertext_modulus(),
);
encrypt_lwe_ciphertext_with_seeded_public_key(
&public_key.lwe_public_key,

View File

@@ -1,5 +1,6 @@
use super::ShortintEngine;
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::ciphertext_modulus::CiphertextModulus;
use crate::core_crypto::entities::*;
use crate::core_crypto::fft_impl::crypto::bootstrap::FourierLweBootstrapKey;
use crate::core_crypto::fft_impl::math::fft::Fft;
@@ -82,6 +83,7 @@ impl ShortintEngine {
cks.parameters.ks_base_log,
cks.parameters.ks_level,
cks.parameters.lwe_modular_std_dev,
cks.parameters.ciphertext_modulus,
&mut self.encryption_generator,
);
@@ -92,6 +94,7 @@ impl ShortintEngine {
message_modulus: cks.parameters.message_modulus,
carry_modulus: cks.parameters.carry_modulus,
max_degree,
ciphertext_modulus: cks.parameters.ciphertext_modulus,
})
}
@@ -139,6 +142,7 @@ impl ShortintEngine {
cks.parameters.ks_base_log,
cks.parameters.ks_level,
cks.parameters.lwe_modular_std_dev,
cks.parameters.ciphertext_modulus,
&mut self.seeder,
);
@@ -149,6 +153,7 @@ impl ShortintEngine {
message_modulus: cks.parameters.message_modulus,
carry_modulus: cks.parameters.carry_modulus,
max_degree,
ciphertext_modulus: cks.parameters.ciphertext_modulus,
})
}
@@ -645,6 +650,7 @@ impl ShortintEngine {
&mut self,
server_key: &ServerKey,
value: u64,
ciphertext_modulus: CiphertextModulus<u64>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let lwe_size = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => server_key
@@ -666,7 +672,11 @@ impl ShortintEngine {
let encoded = Plaintext(shifted_value);
let ct = allocate_and_trivially_encrypt_new_lwe_ciphertext(lwe_size, encoded);
let ct = allocate_and_trivially_encrypt_new_lwe_ciphertext(
lwe_size,
encoded,
ciphertext_modulus,
);
let degree = Degree(modular_value);

View File

@@ -104,6 +104,7 @@ impl ShortintEngine {
parameters.ks_base_log,
parameters.ks_level,
parameters.lwe_modular_std_dev,
parameters.ciphertext_modulus,
&mut self.encryption_generator,
);
@@ -114,6 +115,7 @@ impl ShortintEngine {
cks.parameters.ks_base_log,
cks.parameters.ks_level,
parameters.lwe_modular_std_dev,
parameters.ciphertext_modulus,
&mut self.encryption_generator,
);
@@ -125,6 +127,7 @@ impl ShortintEngine {
cks.parameters.ks_base_log,
cks.parameters.ks_level,
cks.parameters.lwe_modular_std_dev,
parameters.ciphertext_modulus,
&mut self.encryption_generator,
);
@@ -143,6 +146,7 @@ impl ShortintEngine {
message_modulus: parameters.message_modulus,
carry_modulus: parameters.carry_modulus,
max_degree: MaxDegree(parameters.message_modulus.0 * parameters.carry_modulus.0 - 1),
ciphertext_modulus: parameters.ciphertext_modulus,
};
let pbs_server_key = ServerKey {
@@ -153,6 +157,7 @@ impl ShortintEngine {
max_degree: MaxDegree(
cks.parameters.message_modulus.0 * cks.parameters.carry_modulus.0 - 1,
),
ciphertext_modulus: cks.parameters.ciphertext_modulus,
};
let wopbs_key = WopbsKey {
@@ -179,8 +184,12 @@ impl ShortintEngine {
.output_key_lwe_dimension()
.to_lwe_size();
let mut output =
LweCiphertextListOwned::new(0u64, lwe_size, LweCiphertextCount(extracted_bit_count.0));
let mut output = LweCiphertextListOwned::new(
0u64,
lwe_size,
LweCiphertextCount(extracted_bit_count.0),
wopbs_key.param.ciphertext_modulus,
);
self.extract_bits_assign(
delta_log,
@@ -252,7 +261,12 @@ impl ShortintEngine {
let output_lwe_size = fourier_bsk.output_lwe_dimension().to_lwe_size();
let mut output_cbs_vp_ct = LweCiphertextListOwned::new(0u64, output_lwe_size, count);
let mut output_cbs_vp_ct = LweCiphertextListOwned::new(
0u64,
output_lwe_size,
count,
wopbs_key.param.ciphertext_modulus,
);
let lut = PolynomialListView::from_container(lut.as_ref(), fourier_bsk.polynomial_size());
let fft = Fft::new(fourier_bsk.polynomial_size());
@@ -312,7 +326,10 @@ impl ShortintEngine {
// Here the output list contains a single ciphertext, we can consume the container to
// convert it to a single ciphertext
let ciphertext = LweCiphertextOwned::from_container(ciphertext_list.into_container());
let ciphertext = LweCiphertextOwned::from_container(
ciphertext_list.into_container(),
wopbs_key.param.ciphertext_modulus,
);
let sks = &wopbs_key.wopbs_server_key;
let ct_out = CiphertextBase {
@@ -366,6 +383,7 @@ impl ShortintEngine {
.ksk_pbs_to_wopbs
.output_key_lwe_dimension()
.to_lwe_size(),
wopbs_key.param.ciphertext_modulus,
);
// Compute a key switch
@@ -407,7 +425,8 @@ impl ShortintEngine {
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 = LweCiphertextOwned::new(0, out_lwe_size);
let mut ct_out =
LweCiphertextOwned::new(0, out_lwe_size, wopbs_key.param.ciphertext_modulus);
let fft = Fft::new(fourier_bsk.polynomial_size());
let fft = fft.as_view();
@@ -493,7 +512,7 @@ impl ShortintEngine {
let mut cont = vec![0u64; lwe_size];
cont[lwe_size - 1] =
(1 << (64 - nb_bit_to_extract - 1)) - (1 << (64 - nb_bit_to_extract - 5));
let tmp = LweCiphertextOwned::from_container(cont);
let tmp = LweCiphertextOwned::from_container(cont, wopbs_key.param.ciphertext_modulus);
lwe_ciphertext_sub_assign(&mut ct_in.ct, &tmp);
@@ -534,9 +553,10 @@ impl ShortintEngine {
assert_eq!(output_list.lwe_ciphertext_count().0, vec_lut.len());
let output_container = output_list.into_container();
let ciphertext_modulus = wopbs_key.param.ciphertext_modulus;
let lwes: Vec<_> = output_container
.chunks_exact(output_container.len() / vec_lut.len())
.map(|s| LweCiphertextOwned::from_container(s.to_vec()))
.map(|s| LweCiphertextOwned::from_container(s.to_vec(), ciphertext_modulus))
.collect();
assert_eq!(lwes.len(), vec_lut.len());

View File

@@ -63,7 +63,7 @@ pub use ciphertext::{
CompressedCiphertextBig, CompressedCiphertextSmall, PBSOrder, PBSOrderMarker,
};
pub use client_key::ClientKey;
pub use parameters::Parameters;
pub use parameters::{CarryModulus, CiphertextModulus, MessageModulus, Parameters};
pub use public_key::{
CompressedPublicKeyBase, CompressedPublicKeyBig, CompressedPublicKeySmall, PublicKeyBase,
PublicKeyBig, PublicKeySmall,

View File

@@ -7,7 +7,8 @@
pub use crate::core_crypto::commons::dispersion::{DispersionParameter, StandardDev};
pub use crate::core_crypto::commons::parameters::{
DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LweDimension, PolynomialSize,
CiphertextModulus as CoreCiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
GlweDimension, LweDimension, PolynomialSize,
};
use serde::{Deserialize, Serialize};
@@ -23,6 +24,9 @@ pub struct MessageModulus(pub usize);
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
pub struct CarryModulus(pub usize);
/// Determines in what ring computations are made
pub type CiphertextModulus = CoreCiphertextModulus<u64>;
/// A structure defining the set of cryptographic parameters for homomorphic integer circuit
/// evaluation.
#[derive(Serialize, Copy, Clone, Deserialize, Debug, PartialEq)]
@@ -43,6 +47,7 @@ pub struct Parameters {
pub cbs_base_log: DecompositionBaseLog,
pub message_modulus: MessageModulus,
pub carry_modulus: CarryModulus,
pub ciphertext_modulus: CiphertextModulus,
}
impl Parameters {
@@ -71,6 +76,7 @@ impl Parameters {
cbs_base_log: DecompositionBaseLog,
message_modulus: MessageModulus,
carry_modulus: CarryModulus,
ciphertext_modulus: CiphertextModulus,
) -> Parameters {
Parameters {
lwe_dimension,
@@ -89,6 +95,7 @@ impl Parameters {
cbs_base_log,
message_modulus,
carry_modulus,
ciphertext_modulus,
}
}
}
@@ -178,6 +185,7 @@ pub const PARAM_MESSAGE_1_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_1_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(684),
@@ -196,6 +204,7 @@ pub const PARAM_MESSAGE_1_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_2_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(656),
@@ -214,6 +223,7 @@ pub const PARAM_MESSAGE_2_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_1_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(742),
@@ -232,6 +242,7 @@ pub const PARAM_MESSAGE_1_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_2_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(742),
@@ -250,6 +261,7 @@ pub const PARAM_MESSAGE_2_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_3_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(742),
@@ -268,6 +280,7 @@ pub const PARAM_MESSAGE_3_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_1_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(745),
@@ -286,6 +299,7 @@ pub const PARAM_MESSAGE_1_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_2_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(742),
@@ -304,6 +318,7 @@ pub const PARAM_MESSAGE_2_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_3_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(742),
@@ -322,6 +337,7 @@ pub const PARAM_MESSAGE_3_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_4_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(742),
@@ -340,6 +356,7 @@ pub const PARAM_MESSAGE_4_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_1_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(807),
@@ -358,6 +375,7 @@ pub const PARAM_MESSAGE_1_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_2_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(856),
@@ -376,6 +394,7 @@ pub const PARAM_MESSAGE_2_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_3_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(812),
@@ -394,6 +413,7 @@ pub const PARAM_MESSAGE_3_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_4_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(808),
@@ -412,6 +432,7 @@ pub const PARAM_MESSAGE_4_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_5_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(807),
@@ -430,6 +451,7 @@ pub const PARAM_MESSAGE_5_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_1_CARRY_5: Parameters = Parameters {
lwe_dimension: LweDimension(864),
@@ -448,6 +470,7 @@ pub const PARAM_MESSAGE_1_CARRY_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(32),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_2_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(864),
@@ -466,6 +489,7 @@ pub const PARAM_MESSAGE_2_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_3_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(864),
@@ -484,6 +508,7 @@ pub const PARAM_MESSAGE_3_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_4_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(864),
@@ -502,6 +527,7 @@ pub const PARAM_MESSAGE_4_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_5_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(875),
@@ -520,6 +546,7 @@ pub const PARAM_MESSAGE_5_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_6_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(915),
@@ -538,6 +565,7 @@ pub const PARAM_MESSAGE_6_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_1_CARRY_6: Parameters = Parameters {
lwe_dimension: LweDimension(930),
@@ -556,6 +584,7 @@ pub const PARAM_MESSAGE_1_CARRY_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(64),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_2_CARRY_5: Parameters = Parameters {
lwe_dimension: LweDimension(934),
@@ -574,6 +603,7 @@ pub const PARAM_MESSAGE_2_CARRY_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(32),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_3_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(930),
@@ -592,6 +622,7 @@ pub const PARAM_MESSAGE_3_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_4_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(930),
@@ -610,6 +641,7 @@ pub const PARAM_MESSAGE_4_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_5_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(930),
@@ -628,6 +660,7 @@ pub const PARAM_MESSAGE_5_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_6_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(930),
@@ -646,6 +679,7 @@ pub const PARAM_MESSAGE_6_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_7_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(930),
@@ -664,6 +698,7 @@ pub const PARAM_MESSAGE_7_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_1_CARRY_7: Parameters = Parameters {
lwe_dimension: LweDimension(1004),
@@ -682,6 +717,7 @@ pub const PARAM_MESSAGE_1_CARRY_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(128),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_2_CARRY_6: Parameters = Parameters {
lwe_dimension: LweDimension(987),
@@ -700,6 +736,7 @@ pub const PARAM_MESSAGE_2_CARRY_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(64),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_3_CARRY_5: Parameters = Parameters {
lwe_dimension: LweDimension(985),
@@ -718,6 +755,7 @@ pub const PARAM_MESSAGE_3_CARRY_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(32),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_4_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(996),
@@ -736,6 +774,7 @@ pub const PARAM_MESSAGE_4_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_5_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(1020),
@@ -754,6 +793,7 @@ pub const PARAM_MESSAGE_5_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_6_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(1018),
@@ -772,6 +812,7 @@ pub const PARAM_MESSAGE_6_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_7_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(1017),
@@ -790,6 +831,7 @@ pub const PARAM_MESSAGE_7_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_MESSAGE_8_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(1017),
@@ -808,6 +850,7 @@ pub const PARAM_MESSAGE_8_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_SMALL_MESSAGE_1_CARRY_1: Parameters = Parameters {
@@ -827,6 +870,7 @@ pub const PARAM_SMALL_MESSAGE_1_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_SMALL_MESSAGE_2_CARRY_2: Parameters = Parameters {
@@ -846,6 +890,7 @@ pub const PARAM_SMALL_MESSAGE_2_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_SMALL_MESSAGE_3_CARRY_3: Parameters = Parameters {
@@ -865,6 +910,7 @@ pub const PARAM_SMALL_MESSAGE_3_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_SMALL_MESSAGE_4_CARRY_4: Parameters = Parameters {
@@ -884,6 +930,7 @@ pub const PARAM_SMALL_MESSAGE_4_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
/// Return a parameter set from a message and carry moduli.

View File

@@ -4,7 +4,7 @@ pub use crate::core_crypto::commons::dispersion::{DispersionParameter, StandardD
pub use crate::core_crypto::commons::parameters::{
DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LweDimension, PolynomialSize,
};
use crate::shortint::parameters::{CarryModulus, MessageModulus};
use crate::shortint::parameters::{CarryModulus, CiphertextModulus, MessageModulus};
use crate::shortint::Parameters;
pub const ALL_PARAMETER_VEC_WOPBS_NORM2: [Parameters; 31] = [
@@ -58,6 +58,7 @@ pub const WOPBS_PARAM_MESSAGE_1_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(2),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(502),
@@ -76,6 +77,7 @@ pub const WOPBS_PARAM_MESSAGE_1_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(499),
@@ -94,6 +96,7 @@ pub const WOPBS_PARAM_MESSAGE_1_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(500),
@@ -112,6 +115,7 @@ pub const WOPBS_PARAM_MESSAGE_1_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(488),
@@ -130,6 +134,7 @@ pub const WOPBS_PARAM_MESSAGE_2_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(488),
@@ -148,6 +153,7 @@ pub const WOPBS_PARAM_MESSAGE_2_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -166,6 +172,7 @@ pub const WOPBS_PARAM_MESSAGE_2_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -184,6 +191,7 @@ pub const WOPBS_PARAM_MESSAGE_2_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(488),
@@ -202,6 +210,7 @@ pub const WOPBS_PARAM_MESSAGE_3_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -220,6 +229,7 @@ pub const WOPBS_PARAM_MESSAGE_3_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(494),
@@ -238,6 +248,7 @@ pub const WOPBS_PARAM_MESSAGE_3_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(494),
@@ -256,6 +267,7 @@ pub const WOPBS_PARAM_MESSAGE_3_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(486),
@@ -274,6 +286,7 @@ pub const WOPBS_PARAM_MESSAGE_4_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -292,6 +305,7 @@ pub const WOPBS_PARAM_MESSAGE_4_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -310,6 +324,7 @@ pub const WOPBS_PARAM_MESSAGE_4_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -328,6 +343,7 @@ pub const WOPBS_PARAM_MESSAGE_4_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_5_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -346,6 +362,7 @@ pub const WOPBS_PARAM_MESSAGE_5_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_5_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -364,6 +381,7 @@ pub const WOPBS_PARAM_MESSAGE_5_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_5_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -382,6 +400,7 @@ pub const WOPBS_PARAM_MESSAGE_5_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_5_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -400,6 +419,7 @@ pub const WOPBS_PARAM_MESSAGE_5_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(5),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_6_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -418,6 +438,7 @@ pub const WOPBS_PARAM_MESSAGE_6_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_6_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -436,6 +457,7 @@ pub const WOPBS_PARAM_MESSAGE_6_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_6_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -454,6 +476,7 @@ pub const WOPBS_PARAM_MESSAGE_6_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_6_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -472,6 +495,7 @@ pub const WOPBS_PARAM_MESSAGE_6_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_7_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -490,6 +514,7 @@ pub const WOPBS_PARAM_MESSAGE_7_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_7_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -508,6 +533,7 @@ pub const WOPBS_PARAM_MESSAGE_7_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_7_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -526,6 +552,7 @@ pub const WOPBS_PARAM_MESSAGE_7_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_7_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -544,6 +571,7 @@ pub const WOPBS_PARAM_MESSAGE_7_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_8_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -562,6 +590,7 @@ pub const WOPBS_PARAM_MESSAGE_8_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_8_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -580,6 +609,7 @@ pub const WOPBS_PARAM_MESSAGE_8_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_8_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -598,6 +628,7 @@ pub const WOPBS_PARAM_MESSAGE_8_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PARAM_4_BITS_5_BLOCKS: Parameters = Parameters {
@@ -617,4 +648,5 @@ pub const PARAM_4_BITS_5_BLOCKS: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};

View File

@@ -6,7 +6,7 @@ pub use crate::core_crypto::commons::parameters::{
};
use crate::shortint::parameters::parameters_wopbs::*;
use crate::shortint::parameters::parameters_wopbs_prime_moduli::*;
use crate::shortint::parameters::{CarryModulus, MessageModulus};
use crate::shortint::parameters::{CarryModulus, CiphertextModulus, MessageModulus};
use crate::shortint::Parameters;
pub const ALL_PARAMETER_VEC_WOPBS: [Parameters; 116] = [
@@ -145,6 +145,7 @@ pub const WOPBS_PARAM_MESSAGE_1_CARRY_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(32),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_CARRY_6: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -163,6 +164,7 @@ pub const WOPBS_PARAM_MESSAGE_1_CARRY_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(64),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_CARRY_7: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -181,6 +183,7 @@ pub const WOPBS_PARAM_MESSAGE_1_CARRY_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(128),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -199,6 +202,7 @@ pub const WOPBS_PARAM_MESSAGE_1_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_CARRY_8: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -217,6 +221,7 @@ pub const WOPBS_PARAM_MESSAGE_1_CARRY_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(7),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(256),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -235,6 +240,7 @@ pub const WOPBS_PARAM_MESSAGE_1_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(498),
@@ -253,6 +259,7 @@ pub const WOPBS_PARAM_MESSAGE_1_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(2),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(653),
@@ -271,6 +278,7 @@ pub const WOPBS_PARAM_MESSAGE_1_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(5),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_1_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(487),
@@ -289,6 +297,7 @@ pub const WOPBS_PARAM_MESSAGE_1_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -307,6 +316,7 @@ pub const WOPBS_PARAM_MESSAGE_2_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_CARRY_5: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -325,6 +335,7 @@ pub const WOPBS_PARAM_MESSAGE_2_CARRY_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(32),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_CARRY_6: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -343,6 +354,7 @@ pub const WOPBS_PARAM_MESSAGE_2_CARRY_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(64),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_CARRY_7: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -361,6 +373,7 @@ pub const WOPBS_PARAM_MESSAGE_2_CARRY_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(128),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -379,6 +392,7 @@ pub const WOPBS_PARAM_MESSAGE_2_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(500),
@@ -397,6 +411,7 @@ pub const WOPBS_PARAM_MESSAGE_2_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(2),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(769),
@@ -415,6 +430,7 @@ pub const WOPBS_PARAM_MESSAGE_2_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(5),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_2_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(487),
@@ -433,6 +449,7 @@ pub const WOPBS_PARAM_MESSAGE_2_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -451,6 +468,7 @@ pub const WOPBS_PARAM_MESSAGE_3_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_CARRY_5: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -469,6 +487,7 @@ pub const WOPBS_PARAM_MESSAGE_3_CARRY_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(32),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(873),
@@ -487,6 +506,7 @@ pub const WOPBS_PARAM_MESSAGE_3_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_CARRY_6: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -505,6 +525,7 @@ pub const WOPBS_PARAM_MESSAGE_3_CARRY_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(64),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -523,6 +544,7 @@ pub const WOPBS_PARAM_MESSAGE_3_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(486),
@@ -541,6 +563,7 @@ pub const WOPBS_PARAM_MESSAGE_3_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_3_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(487),
@@ -559,6 +582,7 @@ pub const WOPBS_PARAM_MESSAGE_3_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(2),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(953),
@@ -577,6 +601,7 @@ pub const WOPBS_PARAM_MESSAGE_4_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -595,6 +620,7 @@ pub const WOPBS_PARAM_MESSAGE_4_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_CARRY_5: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -613,6 +639,7 @@ pub const WOPBS_PARAM_MESSAGE_4_CARRY_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(32),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -631,6 +658,7 @@ pub const WOPBS_PARAM_MESSAGE_4_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(486),
@@ -649,6 +677,7 @@ pub const WOPBS_PARAM_MESSAGE_4_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_4_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(486),
@@ -667,6 +696,7 @@ pub const WOPBS_PARAM_MESSAGE_4_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_5_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -685,6 +715,7 @@ pub const WOPBS_PARAM_MESSAGE_5_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_5_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -703,6 +734,7 @@ pub const WOPBS_PARAM_MESSAGE_5_CARRY_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(16),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_5_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -721,6 +753,7 @@ pub const WOPBS_PARAM_MESSAGE_5_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_5_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -739,6 +772,7 @@ pub const WOPBS_PARAM_MESSAGE_5_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_5_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(486),
@@ -757,6 +791,7 @@ pub const WOPBS_PARAM_MESSAGE_5_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_6_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -775,6 +810,7 @@ pub const WOPBS_PARAM_MESSAGE_6_CARRY_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(8),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_6_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -793,6 +829,7 @@ pub const WOPBS_PARAM_MESSAGE_6_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_6_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -811,6 +848,7 @@ pub const WOPBS_PARAM_MESSAGE_6_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_6_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(486),
@@ -829,6 +867,7 @@ pub const WOPBS_PARAM_MESSAGE_6_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_7_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(481),
@@ -847,6 +886,7 @@ pub const WOPBS_PARAM_MESSAGE_7_CARRY_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_7_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -865,6 +905,7 @@ pub const WOPBS_PARAM_MESSAGE_7_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_7_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -883,6 +924,7 @@ pub const WOPBS_PARAM_MESSAGE_7_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_8_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -901,6 +943,7 @@ pub const WOPBS_PARAM_MESSAGE_8_CARRY_1: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_8_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(497),
@@ -919,6 +962,7 @@ pub const WOPBS_PARAM_MESSAGE_8_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PARAM_MESSAGE_9_CARRY_0: Parameters = Parameters {
lwe_dimension: LweDimension(493),
@@ -937,6 +981,7 @@ pub const WOPBS_PARAM_MESSAGE_9_CARRY_0: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(512),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub fn get_parameters_from_message_and_carry_wopbs(

View File

@@ -2,7 +2,7 @@ pub use crate::core_crypto::commons::dispersion::{DispersionParameter, StandardD
pub use crate::core_crypto::commons::parameters::{
DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LweDimension, PolynomialSize,
};
use crate::shortint::parameters::{CarryModulus, MessageModulus};
use crate::shortint::parameters::{CarryModulus, CiphertextModulus, MessageModulus};
use crate::shortint::Parameters;
pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_2: Parameters = Parameters {
@@ -22,6 +22,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_3: Parameters = Parameters {
lwe_dimension: LweDimension(693),
@@ -40,6 +41,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(757),
@@ -58,6 +60,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_5: Parameters = Parameters {
lwe_dimension: LweDimension(689),
@@ -76,6 +79,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(695),
@@ -94,6 +98,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_7: Parameters = Parameters {
lwe_dimension: LweDimension(705),
@@ -112,6 +117,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(710),
@@ -130,6 +136,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_2_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(697),
@@ -148,6 +155,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_3: Parameters = Parameters {
lwe_dimension: LweDimension(728),
@@ -166,6 +174,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(690),
@@ -184,6 +193,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_5: Parameters = Parameters {
lwe_dimension: LweDimension(699),
@@ -202,6 +212,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(694),
@@ -220,6 +231,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_7: Parameters = Parameters {
lwe_dimension: LweDimension(730),
@@ -238,6 +250,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(706),
@@ -256,6 +269,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_3_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(702),
@@ -274,6 +288,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_3: Parameters = Parameters {
lwe_dimension: LweDimension(689),
@@ -292,6 +307,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(696),
@@ -310,6 +326,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_5: Parameters = Parameters {
lwe_dimension: LweDimension(713),
@@ -328,6 +345,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(716),
@@ -346,6 +364,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_7: Parameters = Parameters {
lwe_dimension: LweDimension(745),
@@ -364,6 +383,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(692),
@@ -382,6 +402,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_4_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(702),
@@ -400,6 +421,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_3: Parameters = Parameters {
lwe_dimension: LweDimension(689),
@@ -418,6 +440,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(696),
@@ -436,6 +459,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_5: Parameters = Parameters {
lwe_dimension: LweDimension(713),
@@ -454,6 +478,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(716),
@@ -472,6 +497,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_7: Parameters = Parameters {
lwe_dimension: LweDimension(745),
@@ -490,6 +516,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(692),
@@ -508,6 +535,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_5_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(32),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(702),
@@ -526,6 +554,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_3: Parameters = Parameters {
lwe_dimension: LweDimension(689),
@@ -544,6 +573,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(696),
@@ -562,6 +592,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_5: Parameters = Parameters {
lwe_dimension: LweDimension(713),
@@ -580,6 +611,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(716),
@@ -598,6 +630,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_7: Parameters = Parameters {
lwe_dimension: LweDimension(745),
@@ -616,6 +649,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(692),
@@ -634,6 +668,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_6_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(64),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(702),
@@ -652,6 +687,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_3: Parameters = Parameters {
lwe_dimension: LweDimension(689),
@@ -670,6 +706,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(696),
@@ -688,6 +725,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_5: Parameters = Parameters {
lwe_dimension: LweDimension(713),
@@ -706,6 +744,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(716),
@@ -724,6 +763,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_7: Parameters = Parameters {
lwe_dimension: LweDimension(745),
@@ -742,6 +782,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(692),
@@ -760,6 +801,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_7_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(128),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_2: Parameters = Parameters {
lwe_dimension: LweDimension(702),
@@ -778,6 +820,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_2: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_3: Parameters = Parameters {
lwe_dimension: LweDimension(689),
@@ -796,6 +839,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_3: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_4: Parameters = Parameters {
lwe_dimension: LweDimension(696),
@@ -814,6 +858,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_4: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_5: Parameters = Parameters {
lwe_dimension: LweDimension(713),
@@ -832,6 +877,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_5: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(3),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_6: Parameters = Parameters {
lwe_dimension: LweDimension(716),
@@ -850,6 +896,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_6: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_7: Parameters = Parameters {
lwe_dimension: LweDimension(745),
@@ -868,6 +915,7 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_7: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(4),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_8: Parameters = Parameters {
lwe_dimension: LweDimension(692),
@@ -886,4 +934,5 @@ pub const WOPBS_PRIME_PARAM_MESSAGE_8_NORM2_8: Parameters = Parameters {
cbs_base_log: DecompositionBaseLog(6),
message_modulus: MessageModulus(256),
carry_modulus: CarryModulus(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};

View File

@@ -10,8 +10,8 @@ pub use super::ciphertext::{
pub use super::client_key::ClientKey;
pub use super::gen_keys;
pub use super::parameters::{
CarryModulus, DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LweDimension,
MessageModulus, Parameters, PolynomialSize, StandardDev, DEFAULT_PARAMETERS,
CarryModulus, CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount, GlweDimension,
LweDimension, MessageModulus, Parameters, PolynomialSize, StandardDev, DEFAULT_PARAMETERS,
PARAM_MESSAGE_1_CARRY_1, PARAM_MESSAGE_1_CARRY_2, PARAM_MESSAGE_1_CARRY_3,
PARAM_MESSAGE_1_CARRY_4, PARAM_MESSAGE_1_CARRY_5, PARAM_MESSAGE_1_CARRY_6,
PARAM_MESSAGE_1_CARRY_7, PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_2_CARRY_3,

View File

@@ -3,7 +3,7 @@
use super::MaxDegree;
use crate::core_crypto::prelude::*;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::parameters::{CarryModulus, MessageModulus};
use crate::shortint::parameters::{CarryModulus, CiphertextModulus, MessageModulus};
use crate::shortint::ClientKey;
use serde::{Deserialize, Serialize};
@@ -21,6 +21,7 @@ pub struct CompressedServerKey {
pub carry_modulus: CarryModulus,
// Maximum number of operations that can be done before emptying the operation buffer
pub max_degree: MaxDegree,
pub ciphertext_modulus: CiphertextModulus,
}
impl CompressedServerKey {

View File

@@ -27,7 +27,7 @@ use crate::core_crypto::fft_impl::crypto::bootstrap::FourierLweBootstrapKeyOwned
use crate::shortint::ciphertext::{CiphertextBase, CiphertextBig, CiphertextSmall, Degree};
use crate::shortint::client_key::ClientKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::parameters::{CarryModulus, MessageModulus};
use crate::shortint::parameters::{CarryModulus, CiphertextModulus, MessageModulus};
use crate::shortint::PBSOrderMarker;
use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Display, Formatter};
@@ -68,6 +68,8 @@ pub struct ServerKey {
pub carry_modulus: CarryModulus,
// Maximum number of operations that can be done before emptying the operation buffer
pub max_degree: MaxDegree,
// Modulus use for computations on the ciphertext
pub ciphertext_modulus: CiphertextModulus,
}
/// Returns whether it is possible to pack lhs and rhs into a unique
@@ -760,7 +762,11 @@ impl ServerKey {
/// assert_eq!(1, ct_res);
/// ```
pub fn create_trivial(&self, value: u64) -> CiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| engine.create_trivial(self, value).unwrap())
ShortintEngine::with_thread_local_mut(|engine| {
engine
.create_trivial(self, value, self.ciphertext_modulus)
.unwrap()
})
}
/// Compute a trivial shortint ciphertext with the dimension of the small LWE secret key from a
@@ -784,7 +790,11 @@ impl ServerKey {
/// assert_eq!(1, ct_res);
/// ```
pub fn create_trivial_small(&self, value: u64) -> CiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| engine.create_trivial(self, value).unwrap())
ShortintEngine::with_thread_local_mut(|engine| {
engine
.create_trivial(self, value, self.ciphertext_modulus)
.unwrap()
})
}
pub fn create_trivial_assign<OpOrder: PBSOrderMarker>(
@@ -822,6 +832,7 @@ impl From<CompressedServerKey> for ServerKey {
message_modulus,
carry_modulus,
max_degree,
ciphertext_modulus,
} = compressed_server_key;
let key_switching_key = key_switching_key.decompress_into_lwe_keyswitch_key();
@@ -846,6 +857,7 @@ impl From<CompressedServerKey> for ServerKey {
message_modulus,
carry_modulus,
max_degree,
ciphertext_modulus,
}
}
}

View File

@@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize};
use std::fmt::Formatter;
use crate::shortint::parameters::{
CarryModulus, DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LweDimension,
MessageModulus, Parameters, PolynomialSize, StandardDev,
CarryModulus, CoreCiphertextModulus, DecompositionBaseLog, DecompositionLevelCount,
GlweDimension, LweDimension, MessageModulus, Parameters, PolynomialSize, StandardDev,
};
use crate::typed_api::shortints::{CompressedGenericShortint, GenericShortInt};
@@ -36,6 +36,7 @@ pub struct ShortIntegerParameterSet<const MESSAGE_BITS: u8> {
pub cbs_level: DecompositionLevelCount,
pub cbs_base_log: DecompositionBaseLog,
pub carry_modulus: CarryModulus,
pub ciphertext_modulus: CoreCiphertextModulus<u64>,
}
impl<const MESSAGE_BITS: u8> ShortIntegerParameterSet<MESSAGE_BITS> {
@@ -59,6 +60,7 @@ impl<const MESSAGE_BITS: u8> ShortIntegerParameterSet<MESSAGE_BITS> {
cbs_level: params.cbs_level,
cbs_base_log: params.cbs_base_log,
carry_modulus: params.carry_modulus,
ciphertext_modulus: params.ciphertext_modulus,
}
}
}
@@ -82,6 +84,7 @@ impl<const MESSAGE_BITS: u8> From<ShortIntegerParameterSet<MESSAGE_BITS>> for Pa
cbs_base_log: params.cbs_base_log,
message_modulus: MessageModulus(1 << MESSAGE_BITS as usize),
carry_modulus: params.carry_modulus,
ciphertext_modulus: params.ciphertext_modulus,
}
}
}

View File

@@ -1,3 +1,4 @@
#[allow(unused_imports)]
use crate::typed_api::prelude::*;
#[cfg(feature = "boolean")]
use crate::typed_api::FheBool;