mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-11 07:38:08 -05:00
Compare commits
2 Commits
as/add_deb
...
testing_lw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccc4410515 | ||
|
|
31348cb1f8 |
@@ -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();
|
||||
|
||||
@@ -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, ¶ms);
|
||||
10e-100, 2, 3, 2, 2, SHORTINT_NATIVE_MODULUS, ¶ms);
|
||||
assert(params_ok == 0);
|
||||
|
||||
int gen_keys_ok = shortint_gen_keys_with_parameters(params, &cks, &sks);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -70,6 +70,7 @@ fn main() {
|
||||
DecompositionBaseLog(0),
|
||||
MessageModulus(4),
|
||||
CarryModulus(1),
|
||||
CiphertextModulus::new_native(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
99
tfhe/src/core_crypto/algorithms/misc.rs
Normal file
99
tfhe/src/core_crypto/algorithms/misc.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
829
tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs
Normal file
829
tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
97
tfhe/src/core_crypto/algorithms/test/lwe_keyswitch.rs
Normal file
97
tfhe/src/core_crypto/algorithms/test/lwe_keyswitch.rs
Normal 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);
|
||||
}
|
||||
531
tfhe/src/core_crypto/algorithms/test/lwe_linear_algebra.rs
Normal file
531
tfhe/src/core_crypto/algorithms/test/lwe_linear_algebra.rs
Normal 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);
|
||||
214
tfhe/src/core_crypto/algorithms/test/mod.rs
Normal file
214
tfhe/src/core_crypto/algorithms/test/mod.rs
Normal 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;
|
||||
201
tfhe/src/core_crypto/commons/ciphertext_modulus.rs
Normal file
201
tfhe/src/core_crypto/commons/ciphertext_modulus.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#[allow(unused_imports)]
|
||||
use crate::typed_api::prelude::*;
|
||||
#[cfg(feature = "boolean")]
|
||||
use crate::typed_api::FheBool;
|
||||
|
||||
Reference in New Issue
Block a user