diff --git a/apps/trivium/README.md b/apps/trivium/README.md index c4b0d388c5..eb084e4671 100644 --- a/apps/trivium/README.md +++ b/apps/trivium/README.md @@ -15,7 +15,6 @@ Example of a Rust main below: ```rust use tfhe::{ConfigBuilder, generate_keys, FheBool}; use tfhe::prelude::*; - use tfhe_trivium::TriviumStream; fn get_hexadecimal_string_from_lsb_first_stream(a: Vec) -> String { @@ -139,10 +138,8 @@ Example code: ```rust use tfhe::shortint::prelude::*; use tfhe::shortint::CastingKey; - use tfhe::{ConfigBuilder, generate_keys, FheUint64}; use tfhe::prelude::*; - use tfhe_trivium::TriviumStreamShortint; fn test_shortint() { diff --git a/apps/trivium/benches/kreyvium_bool.rs b/apps/trivium/benches/kreyvium_bool.rs index 1efe827e81..e85d87c30a 100644 --- a/apps/trivium/benches/kreyvium_bool.rs +++ b/apps/trivium/benches/kreyvium_bool.rs @@ -1,10 +1,8 @@ +use criterion::Criterion; use tfhe::prelude::*; use tfhe::{generate_keys, ConfigBuilder, FheBool}; - use tfhe_trivium::KreyviumStream; -use criterion::Criterion; - pub fn kreyvium_bool_gen(c: &mut Criterion) { let config = ConfigBuilder::default().build(); let (client_key, server_key) = generate_keys(config); diff --git a/apps/trivium/benches/kreyvium_byte.rs b/apps/trivium/benches/kreyvium_byte.rs index 272dce6105..5d402243a4 100644 --- a/apps/trivium/benches/kreyvium_byte.rs +++ b/apps/trivium/benches/kreyvium_byte.rs @@ -1,10 +1,8 @@ +use criterion::Criterion; use tfhe::prelude::*; use tfhe::{generate_keys, ConfigBuilder, FheUint64, FheUint8}; - use tfhe_trivium::{KreyviumStreamByte, TransCiphering}; -use criterion::Criterion; - pub fn kreyvium_byte_gen(c: &mut Criterion) { let config = ConfigBuilder::default() .enable_function_evaluation() diff --git a/apps/trivium/benches/trivium_bool.rs b/apps/trivium/benches/trivium_bool.rs index e4ad691a9a..273cb355b1 100644 --- a/apps/trivium/benches/trivium_bool.rs +++ b/apps/trivium/benches/trivium_bool.rs @@ -1,10 +1,8 @@ +use criterion::Criterion; use tfhe::prelude::*; use tfhe::{generate_keys, ConfigBuilder, FheBool}; - use tfhe_trivium::TriviumStream; -use criterion::Criterion; - pub fn trivium_bool_gen(c: &mut Criterion) { let config = ConfigBuilder::default().build(); let (client_key, server_key) = generate_keys(config); diff --git a/apps/trivium/benches/trivium_byte.rs b/apps/trivium/benches/trivium_byte.rs index 5b922e5303..a27abb486c 100644 --- a/apps/trivium/benches/trivium_byte.rs +++ b/apps/trivium/benches/trivium_byte.rs @@ -1,10 +1,8 @@ +use criterion::Criterion; use tfhe::prelude::*; use tfhe::{generate_keys, ConfigBuilder, FheUint64, FheUint8}; - use tfhe_trivium::{TransCiphering, TriviumStreamByte}; -use criterion::Criterion; - pub fn trivium_byte_gen(c: &mut Criterion) { let config = ConfigBuilder::default().build(); let (client_key, server_key) = generate_keys(config); diff --git a/apps/trivium/src/kreyvium/kreyvium.rs b/apps/trivium/src/kreyvium/kreyvium.rs index 28d50610bb..695607cffd 100644 --- a/apps/trivium/src/kreyvium/kreyvium.rs +++ b/apps/trivium/src/kreyvium/kreyvium.rs @@ -2,12 +2,10 @@ //! for the representation of the inner bits. use crate::static_deque::StaticDeque; - +use rayon::prelude::*; use tfhe::prelude::*; use tfhe::{set_server_key, unset_server_key, FheBool, ServerKey}; -use rayon::prelude::*; - /// Internal trait specifying which operations are necessary for KreyviumStream generic type pub trait KreyviumBoolInput: Sized diff --git a/apps/trivium/src/kreyvium/kreyvium_byte.rs b/apps/trivium/src/kreyvium/kreyvium_byte.rs index ebd26800b6..5ca3cfc615 100644 --- a/apps/trivium/src/kreyvium/kreyvium_byte.rs +++ b/apps/trivium/src/kreyvium/kreyvium_byte.rs @@ -2,12 +2,10 @@ //! for the representation of the inner bits. use crate::static_deque::{StaticByteDeque, StaticByteDequeInput}; - +use rayon::prelude::*; use tfhe::prelude::*; use tfhe::{set_server_key, unset_server_key, FheUint8, ServerKey}; -use rayon::prelude::*; - /// Internal trait specifying which operations are necessary for KreyviumStreamByte generic type pub trait KreyviumByteInput: Sized diff --git a/apps/trivium/src/kreyvium/kreyvium_shortint.rs b/apps/trivium/src/kreyvium/kreyvium_shortint.rs index 157fbac21c..1375c78756 100644 --- a/apps/trivium/src/kreyvium/kreyvium_shortint.rs +++ b/apps/trivium/src/kreyvium/kreyvium_shortint.rs @@ -1,8 +1,6 @@ use crate::static_deque::StaticDeque; - -use tfhe::shortint::prelude::*; - use rayon::prelude::*; +use tfhe::shortint::prelude::*; /// KreyviumStreamShortint: a struct implementing the Kreyvium stream cipher, using a generic /// Ciphertext for the internal representation of bits (intended to represent a single bit). To be diff --git a/apps/trivium/src/kreyvium/test.rs b/apps/trivium/src/kreyvium/test.rs index 0c5d20a7fb..df9b2c0c7f 100644 --- a/apps/trivium/src/kreyvium/test.rs +++ b/apps/trivium/src/kreyvium/test.rs @@ -1,8 +1,7 @@ +use crate::{KreyviumStream, KreyviumStreamByte, KreyviumStreamShortint, TransCiphering}; use tfhe::prelude::*; use tfhe::{generate_keys, ConfigBuilder, FheBool, FheUint64, FheUint8}; -use crate::{KreyviumStream, KreyviumStreamByte, KreyviumStreamShortint, TransCiphering}; - // Values for these tests come from the github repo renaud1239/Kreyvium, // commit fd6828f68711276c25f55e605935028f5e843f43 diff --git a/apps/trivium/src/static_deque/mod.rs b/apps/trivium/src/static_deque/mod.rs index 8832d54381..9480a60b90 100644 --- a/apps/trivium/src/static_deque/mod.rs +++ b/apps/trivium/src/static_deque/mod.rs @@ -1,5 +1,6 @@ #[allow(clippy::module_inception)] mod static_deque; pub use static_deque::StaticDeque; + mod static_byte_deque; pub use static_byte_deque::{StaticByteDeque, StaticByteDequeInput}; diff --git a/apps/trivium/src/static_deque/static_byte_deque.rs b/apps/trivium/src/static_deque/static_byte_deque.rs index 62e900fbbe..7b921a5973 100644 --- a/apps/trivium/src/static_deque/static_byte_deque.rs +++ b/apps/trivium/src/static_deque/static_byte_deque.rs @@ -4,7 +4,6 @@ //! This is pretending to store bits, and allows accessing bits in chunks of 8 consecutive. use crate::static_deque::StaticDeque; - use tfhe::FheUint8; /// Internal trait specifying which operations are needed by StaticByteDeque diff --git a/apps/trivium/src/trans_ciphering/mod.rs b/apps/trivium/src/trans_ciphering/mod.rs index fb290fbf98..40f8bba940 100644 --- a/apps/trivium/src/trans_ciphering/mod.rs +++ b/apps/trivium/src/trans_ciphering/mod.rs @@ -2,13 +2,11 @@ //! when trans ciphering is available to them. use crate::{KreyviumStreamByte, KreyviumStreamShortint, TriviumStreamByte, TriviumStreamShortint}; -use tfhe::shortint::Ciphertext; - +use rayon::prelude::*; use tfhe::prelude::*; +use tfhe::shortint::Ciphertext; use tfhe::{set_server_key, unset_server_key, FheUint64, FheUint8, ServerKey}; -use rayon::prelude::*; - /// Triat specifying the interface for trans ciphering a FheUint64 object. Since it is meant /// to be used with stream ciphers, encryption and decryption are by default the same. pub trait TransCiphering { diff --git a/apps/trivium/src/trivium/test.rs b/apps/trivium/src/trivium/test.rs index a039b8e14f..dda42c3ffb 100644 --- a/apps/trivium/src/trivium/test.rs +++ b/apps/trivium/src/trivium/test.rs @@ -1,8 +1,7 @@ +use crate::{TransCiphering, TriviumStream, TriviumStreamByte, TriviumStreamShortint}; use tfhe::prelude::*; use tfhe::{generate_keys, ConfigBuilder, FheBool, FheUint64, FheUint8}; -use crate::{TransCiphering, TriviumStream, TriviumStreamByte, TriviumStreamShortint}; - // Values for these tests come from the github repo cantora/avr-crypto-lib, commit 2a5b018, // file testvectors/trivium-80.80.test-vectors diff --git a/apps/trivium/src/trivium/trivium_bool.rs b/apps/trivium/src/trivium/trivium_bool.rs index eb0bff7900..4e46927c31 100644 --- a/apps/trivium/src/trivium/trivium_bool.rs +++ b/apps/trivium/src/trivium/trivium_bool.rs @@ -2,12 +2,10 @@ //! for the representation of the inner bits. use crate::static_deque::StaticDeque; - +use rayon::prelude::*; use tfhe::prelude::*; use tfhe::{set_server_key, unset_server_key, FheBool, ServerKey}; -use rayon::prelude::*; - /// Internal trait specifying which operations are necessary for TriviumStream generic type pub trait TriviumBoolInput: Sized diff --git a/apps/trivium/src/trivium/trivium_byte.rs b/apps/trivium/src/trivium/trivium_byte.rs index bd578dcc09..edb417ef9c 100644 --- a/apps/trivium/src/trivium/trivium_byte.rs +++ b/apps/trivium/src/trivium/trivium_byte.rs @@ -2,12 +2,10 @@ //! for the representation of the inner bits. use crate::static_deque::{StaticByteDeque, StaticByteDequeInput}; - +use rayon::prelude::*; use tfhe::prelude::*; use tfhe::{set_server_key, unset_server_key, FheUint8, ServerKey}; -use rayon::prelude::*; - /// Internal trait specifying which operations are necessary for TriviumStreamByte generic type pub trait TriviumByteInput: Sized diff --git a/apps/trivium/src/trivium/trivium_shortint.rs b/apps/trivium/src/trivium/trivium_shortint.rs index 300dc4ee05..729ae468f3 100644 --- a/apps/trivium/src/trivium/trivium_shortint.rs +++ b/apps/trivium/src/trivium/trivium_shortint.rs @@ -1,8 +1,6 @@ use crate::static_deque::StaticDeque; - -use tfhe::shortint::prelude::*; - use rayon::prelude::*; +use tfhe::shortint::prelude::*; /// TriviumStreamShortint: a struct implementing the Trivium stream cipher, using a generic /// Ciphertext for the internal representation of bits (intended to represent a single bit). To be diff --git a/concrete-csprng/examples/generate.rs b/concrete-csprng/examples/generate.rs index 6e82076c86..96ce70f6e2 100644 --- a/concrete-csprng/examples/generate.rs +++ b/concrete-csprng/examples/generate.rs @@ -6,6 +6,7 @@ use clap::{value_parser, Arg, Command}; use concrete_csprng::generators::AesniRandomGenerator as ActivatedRandomGenerator; #[cfg(feature = "generator_aarch64_aes")] use concrete_csprng::generators::NeonAesRandomGenerator as ActivatedRandomGenerator; +use concrete_csprng::generators::RandomGenerator; #[cfg(all( not(feature = "generator_x86_64_aesni"), not(feature = "generator_aarch64_aes"), @@ -13,21 +14,17 @@ use concrete_csprng::generators::NeonAesRandomGenerator as ActivatedRandomGenera ))] use concrete_csprng::generators::SoftwareRandomGenerator as ActivatedRandomGenerator; -use concrete_csprng::generators::RandomGenerator; - #[cfg(target_os = "macos")] use concrete_csprng::seeders::AppleSecureEnclaveSeeder as ActivatedSeeder; #[cfg(all(not(target_os = "macos"), feature = "seeder_x86_64_rdseed"))] use concrete_csprng::seeders::RdseedSeeder as ActivatedSeeder; +use concrete_csprng::seeders::Seeder; #[cfg(all( not(target_os = "macos"), not(feature = "seeder_x86_64_rdseed"), feature = "seeder_unix" ))] use concrete_csprng::seeders::UnixSeeder as ActivatedSeeder; - -use concrete_csprng::seeders::Seeder; - use std::io::prelude::*; use std::io::{stdout, StdoutLock}; diff --git a/tasks/src/main.rs b/tasks/src/main.rs index 7e10582242..090c62a755 100644 --- a/tasks/src/main.rs +++ b/tasks/src/main.rs @@ -1,10 +1,7 @@ -#[macro_use] -extern crate lazy_static; use clap::{Arg, Command}; +use lazy_static::lazy_static; use log::LevelFilter; use simplelog::{ColorChoice, CombinedLogger, Config, TermLogger, TerminalMode}; -use std::collections::HashMap; -use std::path::PathBuf; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering::Relaxed; @@ -16,26 +13,6 @@ mod utils; // ------------------------------------------------------------------------------------------------- lazy_static! { static ref DRY_RUN: AtomicBool = AtomicBool::new(false); - static ref ROOT_DIR: PathBuf = utils::project_root(); - static ref ENV_TARGET_NATIVE: utils::Environment = { - let mut env = HashMap::new(); - env.insert("RUSTFLAGS", "-Ctarget-cpu=native"); - env - }; -} - -// ------------------------------------------------------------------------------------------------- -// MACROS -// ------------------------------------------------------------------------------------------------- - -#[macro_export] -macro_rules! cmd { - (<$env: ident> $cmd: expr) => { - $crate::utils::execute($cmd, Some(&*$env), Some(&*$crate::ROOT_DIR)) - }; - ($cmd: expr) => { - $crate::utils::execute($cmd, None, Some(&*$crate::ROOT_DIR)) - }; } // ------------------------------------------------------------------------------------------------- diff --git a/tasks/src/utils.rs b/tasks/src/utils.rs index f4cd05e0ee..f288879233 100644 --- a/tasks/src/utils.rs +++ b/tasks/src/utils.rs @@ -1,45 +1,4 @@ -use log::{debug, info}; -use std::collections::HashMap; -use std::io::{Error, ErrorKind}; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; -use std::sync::atomic::Ordering::Relaxed; - -pub type Environment = HashMap<&'static str, &'static str>; - -#[allow(dead_code)] -pub fn execute(cmd: &str, env: Option<&Environment>, cwd: Option<&PathBuf>) -> Result<(), Error> { - info!("Executing {}", cmd); - debug!("Env {:?}", env); - debug!("Cwd {:?}", cwd); - if crate::DRY_RUN.load(Relaxed) { - info!("Skipping execution because of --dry-run mode"); - return Ok(()); - } - let mut command = Command::new("sh"); - command - .arg("-c") - .arg(cmd) - .stderr(Stdio::inherit()) - .stdout(Stdio::inherit()); - if let Some(env) = env { - for (key, val) in env.iter() { - command.env(key, val); - } - } - if let Some(cwd) = cwd { - command.current_dir(cwd); - } - let output = command.output()?; - if !output.status.success() { - Err(Error::new( - ErrorKind::Other, - "Command exited with nonzero status.", - )) - } else { - Ok(()) - } -} pub fn project_root() -> PathBuf { Path::new(&env!("CARGO_MANIFEST_DIR")) diff --git a/tfhe/benches/boolean/bench.rs b/tfhe/benches/boolean/bench.rs index d592d79da8..21080baf79 100644 --- a/tfhe/benches/boolean/bench.rs +++ b/tfhe/benches/boolean/bench.rs @@ -1,7 +1,7 @@ #[path = "../utilities.rs"] mod utilities; -use crate::utilities::{write_to_json, CryptoParametersRecord, OperatorType}; +use crate::utilities::{write_to_json, CryptoParametersRecord, OperatorType}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use tfhe::boolean::client_key::ClientKey; use tfhe::boolean::parameters::{ diff --git a/tfhe/benches/core_crypto/ks_bench.rs b/tfhe/benches/core_crypto/ks_bench.rs index 670e1bcc03..608912d5a6 100644 --- a/tfhe/benches/core_crypto/ks_bench.rs +++ b/tfhe/benches/core_crypto/ks_bench.rs @@ -1,5 +1,6 @@ #[path = "../utilities.rs"] mod utilities; + use crate::utilities::{write_to_json, CryptoParametersRecord, OperatorType}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use serde::Serialize; diff --git a/tfhe/benches/core_crypto/pbs_bench.rs b/tfhe/benches/core_crypto/pbs_bench.rs index 64e96a022c..2f1f2fa934 100644 --- a/tfhe/benches/core_crypto/pbs_bench.rs +++ b/tfhe/benches/core_crypto/pbs_bench.rs @@ -1,14 +1,13 @@ #[path = "../utilities.rs"] mod utilities; -use crate::utilities::{write_to_json, CryptoParametersRecord, OperatorType}; -use rayon::prelude::*; +use crate::utilities::{write_to_json, CryptoParametersRecord, OperatorType}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use rayon::prelude::*; use serde::Serialize; use tfhe::boolean::parameters::{ BooleanParameters, DEFAULT_PARAMETERS, PARAMETERS_ERROR_PROB_2_POW_MINUS_165, }; - use tfhe::core_crypto::prelude::*; use tfhe::keycache::NamedParam; use tfhe::shortint::parameters::*; diff --git a/tfhe/benches/high_level_api/bench.rs b/tfhe/benches/high_level_api/bench.rs index 532f1afc4e..ded674f82d 100644 --- a/tfhe/benches/high_level_api/bench.rs +++ b/tfhe/benches/high_level_api/bench.rs @@ -1,9 +1,7 @@ -use std::ops::*; - use criterion::{black_box, Criterion}; - use rand::prelude::*; use std::fmt::Write; +use std::ops::*; use tfhe::prelude::*; use tfhe::shortint::parameters::*; use tfhe::{ diff --git a/tfhe/benches/integer/bench.rs b/tfhe/benches/integer/bench.rs index 6b3c9d6302..872372ea2f 100644 --- a/tfhe/benches/integer/bench.rs +++ b/tfhe/benches/integer/bench.rs @@ -4,24 +4,15 @@ mod utilities; use crate::utilities::{write_to_json, EnvConfig, OperatorType}; -use std::env; - use criterion::{criterion_group, Criterion}; use itertools::iproduct; use rand::prelude::*; +use std::env; use std::vec::IntoIter; use tfhe::integer::keycache::KEY_CACHE; -use tfhe::integer::{IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey}; +use tfhe::integer::{IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey, U256}; use tfhe::keycache::NamedParam; - -use tfhe::integer::U256; - -#[allow(unused_imports)] -use tfhe::shortint::parameters::{ - PARAM_MESSAGE_1_CARRY_1_KS_PBS, PARAM_MESSAGE_2_CARRY_2_KS_PBS, PARAM_MESSAGE_3_CARRY_3_KS_PBS, - PARAM_MESSAGE_4_CARRY_4_KS_PBS, PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS, -}; +use tfhe::shortint::parameters::*; /// The type used to hold scalar values /// It must be as big as the largest bit size tested diff --git a/tfhe/benches/integer/signed_bench.rs b/tfhe/benches/integer/signed_bench.rs index 17b3e0cd09..31928f8622 100644 --- a/tfhe/benches/integer/signed_bench.rs +++ b/tfhe/benches/integer/signed_bench.rs @@ -2,16 +2,14 @@ mod utilities; use crate::utilities::{write_to_json, EnvConfig, OperatorType}; -use std::env; - use criterion::{criterion_group, Criterion}; use itertools::iproduct; use rand::prelude::*; +use std::env; use std::vec::IntoIter; use tfhe::integer::keycache::KEY_CACHE; use tfhe::integer::{IntegerKeyKind, RadixCiphertext, ServerKey, SignedRadixCiphertext, I256}; use tfhe::keycache::NamedParam; - use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; #[cfg(not(feature = "gpu"))] use tfhe::shortint::parameters::PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS; diff --git a/tfhe/benches/shortint/bench.rs b/tfhe/benches/shortint/bench.rs index 7f86bdf246..3846f25009 100644 --- a/tfhe/benches/shortint/bench.rs +++ b/tfhe/benches/shortint/bench.rs @@ -2,17 +2,14 @@ mod utilities; use crate::utilities::{write_to_json, OperatorType}; -use std::env; - use criterion::{criterion_group, Criterion}; -use tfhe::keycache::NamedParam; -use tfhe::shortint::parameters::*; -use tfhe::shortint::{Ciphertext, CompressedServerKey, ServerKey}; - use rand::Rng; +use std::env; +use tfhe::keycache::NamedParam; use tfhe::shortint::keycache::{KEY_CACHE, KEY_CACHE_WOPBS}; - use tfhe::shortint::parameters::parameters_wopbs::WOPBS_PARAM_MESSAGE_4_NORM2_6_KS_PBS; +use tfhe::shortint::parameters::*; +use tfhe::shortint::{Ciphertext, CompressedServerKey, ServerKey}; const SERVER_KEY_BENCH_PARAMS: [ClassicPBSParameters; 4] = [ PARAM_MESSAGE_1_CARRY_1_KS_PBS, diff --git a/tfhe/benches/shortint/casting.rs b/tfhe/benches/shortint/casting.rs index 221543ae00..535e832593 100644 --- a/tfhe/benches/shortint/casting.rs +++ b/tfhe/benches/shortint/casting.rs @@ -1,10 +1,7 @@ use crate::utilities::{write_to_json, OperatorType}; - -use tfhe::shortint::prelude::*; - -use rayon::prelude::*; - use criterion::Criterion; +use rayon::prelude::*; +use tfhe::shortint::prelude::*; pub fn pack_cast_64(c: &mut Criterion) { let bench_name = "pack_cast_64"; diff --git a/tfhe/docs/fine_grained_api/integer/serialization.md b/tfhe/docs/fine_grained_api/integer/serialization.md index bcd2fdf992..857b3bc2d6 100644 --- a/tfhe/docs/fine_grained_api/integer/serialization.md +++ b/tfhe/docs/fine_grained_api/integer/serialization.md @@ -18,7 +18,6 @@ bincode = "1.3.3" // main.rs use bincode; - use std::io::Cursor; use tfhe::integer::{gen_keys_radix, ServerKey, RadixCiphertext}; use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; diff --git a/tfhe/docs/fine_grained_api/shortint/operations.md b/tfhe/docs/fine_grained_api/shortint/operations.md index 533edec462..e468f74e0f 100644 --- a/tfhe/docs/fine_grained_api/shortint/operations.md +++ b/tfhe/docs/fine_grained_api/shortint/operations.md @@ -83,7 +83,6 @@ If we redo this same circuit with the `checked` flavor, a panic will occur: ```rust use tfhe::shortint::prelude::*; - use std::error::Error; fn main() { diff --git a/tfhe/docs/how_to/serialization.md b/tfhe/docs/how_to/serialization.md index 36ad70a391..5d218dcfce 100644 --- a/tfhe/docs/how_to/serialization.md +++ b/tfhe/docs/how_to/serialization.md @@ -19,9 +19,7 @@ bincode = "1.3.3" // main.rs use bincode; - use std::io::Cursor; - use tfhe::{ConfigBuilder, ServerKey, generate_keys, set_server_key, FheUint8}; use tfhe::prelude::*; diff --git a/tfhe/docs/how_to/trait_bounds.md b/tfhe/docs/how_to/trait_bounds.md index c1f73f69b8..a431cd5a08 100644 --- a/tfhe/docs/how_to/trait_bounds.md +++ b/tfhe/docs/how_to/trait_bounds.md @@ -31,7 +31,6 @@ only allowing easier debugging. ```rust use std::ops::{Add, Mul}; - use tfhe::prelude::*; use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint32, FheUint64}; diff --git a/tfhe/docs/tutorials/parity_bit.md b/tfhe/docs/tutorials/parity_bit.md index e768145696..a4961e87f2 100644 --- a/tfhe/docs/tutorials/parity_bit.md +++ b/tfhe/docs/tutorials/parity_bit.md @@ -297,7 +297,6 @@ Here is a complete example that uses this function for both clear and FHE values ```rust use tfhe::{FheBool, ConfigBuilder, generate_keys, set_server_key}; use tfhe::prelude::*; - use std::ops::{Not, BitXor}; #[derive(Copy, Clone, Debug)] diff --git a/tfhe/examples/dark_market/fhe.rs b/tfhe/examples/dark_market/fhe.rs index 23ed4e0d83..09edc1d49f 100644 --- a/tfhe/examples/dark_market/fhe.rs +++ b/tfhe/examples/dark_market/fhe.rs @@ -1,9 +1,8 @@ +use crate::NUMBER_OF_BLOCKS; use std::time::Instant; use tfhe::integer::ciphertext::RadixCiphertext; use tfhe::integer::{ClientKey, ServerKey}; -use crate::NUMBER_OF_BLOCKS; - fn vector_sum(server_key: &ServerKey, orders: &mut [RadixCiphertext]) -> RadixCiphertext { let mut total_volume = server_key.create_trivial_zero_radix(NUMBER_OF_BLOCKS); for order in orders { diff --git a/tfhe/examples/dark_market/improved_parallel_fhe.rs b/tfhe/examples/dark_market/improved_parallel_fhe.rs index d3a08d3550..a41a81bab1 100644 --- a/tfhe/examples/dark_market/improved_parallel_fhe.rs +++ b/tfhe/examples/dark_market/improved_parallel_fhe.rs @@ -1,12 +1,9 @@ -use std::time::Instant; - +use crate::NUMBER_OF_BLOCKS; use rayon::prelude::*; - +use std::time::Instant; use tfhe::integer::ciphertext::RadixCiphertext; use tfhe::integer::{IntegerCiphertext, ServerKey}; -use crate::NUMBER_OF_BLOCKS; - fn compute_prefix_sum(server_key: &ServerKey, arr: &[RadixCiphertext]) -> Vec { if arr.is_empty() { return arr.to_vec(); diff --git a/tfhe/examples/dark_market/main.rs b/tfhe/examples/dark_market/main.rs index 1da696f5a8..3f424dd1fa 100644 --- a/tfhe/examples/dark_market/main.rs +++ b/tfhe/examples/dark_market/main.rs @@ -1,5 +1,4 @@ use std::time::Instant; - use tfhe::integer::ciphertext::RadixCiphertext; use tfhe::integer::keycache::IntegerKeyCache; use tfhe::integer::{IntegerKeyKind, ServerKey}; diff --git a/tfhe/examples/dark_market/parallel_fhe.rs b/tfhe/examples/dark_market/parallel_fhe.rs index 4122a93383..5f3ad642be 100644 --- a/tfhe/examples/dark_market/parallel_fhe.rs +++ b/tfhe/examples/dark_market/parallel_fhe.rs @@ -1,12 +1,9 @@ -use std::time::Instant; - +use crate::NUMBER_OF_BLOCKS; use rayon::prelude::*; - +use std::time::Instant; use tfhe::integer::ciphertext::RadixCiphertext; use tfhe::integer::ServerKey; -use crate::NUMBER_OF_BLOCKS; - // Calculate the element sum of the given vector in parallel fn vector_sum(server_key: &ServerKey, orders: Vec) -> RadixCiphertext { orders.into_par_iter().reduce( diff --git a/tfhe/examples/regex_engine/engine.rs b/tfhe/examples/regex_engine/engine.rs index 9fdb486ac2..86d40805cc 100644 --- a/tfhe/examples/regex_engine/engine.rs +++ b/tfhe/examples/regex_engine/engine.rs @@ -1,5 +1,6 @@ use crate::execution::{Executed, Execution, LazyExecution}; use crate::parser::{parse, RegExpr}; +use log::{info, trace}; use std::rc::Rc; use tfhe::integer::{RadixCiphertext, ServerKey}; diff --git a/tfhe/examples/regex_engine/execution.rs b/tfhe/examples/regex_engine/execution.rs index 6a34e90168..e17e2e6c67 100644 --- a/tfhe/examples/regex_engine/execution.rs +++ b/tfhe/examples/regex_engine/execution.rs @@ -1,9 +1,9 @@ +use crate::parser::u8_to_char; +use log::{debug, trace}; use std::collections::HashMap; use std::rc::Rc; use tfhe::integer::{IntegerCiphertext, RadixCiphertext, ServerKey}; -use crate::parser::u8_to_char; - #[derive(Clone, PartialEq, Eq, Hash)] pub(crate) enum Executed { Constant { c: u8 }, diff --git a/tfhe/examples/regex_engine/main.rs b/tfhe/examples/regex_engine/main.rs index 96dab9bf53..74bab30f2c 100644 --- a/tfhe/examples/regex_engine/main.rs +++ b/tfhe/examples/regex_engine/main.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate log; - mod ciphertext; mod engine; mod execution; diff --git a/tfhe/examples/regex_engine/parser.rs b/tfhe/examples/regex_engine/parser.rs index 34cdc440b6..8ae80298dd 100644 --- a/tfhe/examples/regex_engine/parser.rs +++ b/tfhe/examples/regex_engine/parser.rs @@ -1,7 +1,6 @@ use combine::parser::byte; use combine::parser::byte::byte; use combine::*; - use std::fmt; #[derive(Clone, PartialEq, Eq, Hash)] diff --git a/tfhe/examples/sha256.rs b/tfhe/examples/sha256.rs index cdae69dafd..371c538e8a 100644 --- a/tfhe/examples/sha256.rs +++ b/tfhe/examples/sha256.rs @@ -1,4 +1,3 @@ -#[doc(hidden)] use rayon as __rayon_reexport; use rayon::prelude::*; use std::io::{stdin, Read}; @@ -13,8 +12,6 @@ use tfhe::{set_server_key, ClientKey, CompressedServerKey, ConfigBuilder, Device pub fn __requires_sendable_closure R + Send>(x: F) -> F { x } - -#[macro_export] #[doc(hidden)] macro_rules! __join_implementation { ($len:expr; $($f:ident $r:ident $a:expr),*; $b:expr, $($c:expr,)*) => { @@ -37,7 +34,8 @@ macro_rules! __join_implementation { }; } -#[macro_export] +pub(crate) use __join_implementation; + macro_rules! join { ($($($a:expr),+$(,)?)?) => { $crate::__join_implementation!{0;;$($($a,)+)?} diff --git a/tfhe/examples/utilities/boolean_key_sizes.rs b/tfhe/examples/utilities/boolean_key_sizes.rs index 26796a8846..5ffa14eef5 100644 --- a/tfhe/examples/utilities/boolean_key_sizes.rs +++ b/tfhe/examples/utilities/boolean_key_sizes.rs @@ -1,7 +1,7 @@ #[path = "../../benches/utilities.rs"] mod utilities; -use crate::utilities::{write_to_json, OperatorType}; +use crate::utilities::{write_to_json, OperatorType}; use std::fs::{File, OpenOptions}; use std::io::Write; use std::path::Path; diff --git a/tfhe/examples/utilities/hlapi_compact_pk_ct_sizes.rs b/tfhe/examples/utilities/hlapi_compact_pk_ct_sizes.rs index b1c0d2b757..a45a6162e6 100644 --- a/tfhe/examples/utilities/hlapi_compact_pk_ct_sizes.rs +++ b/tfhe/examples/utilities/hlapi_compact_pk_ct_sizes.rs @@ -1,7 +1,7 @@ #[path = "../../benches/utilities.rs"] mod utilities; -use crate::utilities::{write_to_json, OperatorType}; +use crate::utilities::{write_to_json, OperatorType}; use rand::Rng; use std::fs::{File, OpenOptions}; use std::io::Write; diff --git a/tfhe/examples/utilities/shortint_key_sizes.rs b/tfhe/examples/utilities/shortint_key_sizes.rs index 089b4c0c1f..37bbd59733 100644 --- a/tfhe/examples/utilities/shortint_key_sizes.rs +++ b/tfhe/examples/utilities/shortint_key_sizes.rs @@ -1,7 +1,7 @@ #[path = "../../benches/utilities.rs"] mod utilities; -use crate::utilities::{write_to_json, OperatorType}; +use crate::utilities::{write_to_json, OperatorType}; use std::fs::{File, OpenOptions}; use std::io::Write; use std::path::Path; diff --git a/tfhe/examples/utilities/wasm_benchmarks_parser.rs b/tfhe/examples/utilities/wasm_benchmarks_parser.rs index da5129e77c..80e5542ca6 100644 --- a/tfhe/examples/utilities/wasm_benchmarks_parser.rs +++ b/tfhe/examples/utilities/wasm_benchmarks_parser.rs @@ -5,7 +5,6 @@ use crate::utilities::{write_to_json, OperatorType}; use clap::Parser; use std::collections::HashMap; use std::fs; - use std::fs::{File, OpenOptions}; use std::io::Write; use std::path::Path; diff --git a/tfhe/src/boolean/engine/mod.rs b/tfhe/src/boolean/engine/mod.rs index 90b8678850..f019b66bd4 100644 --- a/tfhe/src/boolean/engine/mod.rs +++ b/tfhe/src/boolean/engine/mod.rs @@ -4,19 +4,20 @@ //! underlying `core_crypto` module. use crate::boolean::ciphertext::{Ciphertext, CompressedCiphertext}; +use crate::boolean::engine::bootstrapping::{Bootstrapper, CompressedServerKey, ServerKey}; use crate::boolean::parameters::{BooleanKeySwitchingParameters, BooleanParameters}; use crate::boolean::{ClientKey, CompressedPublicKey, PublicKey, PLAINTEXT_FALSE, PLAINTEXT_TRUE}; use crate::core_crypto::algorithms::*; -use crate::core_crypto::entities::*; -use std::cell::RefCell; -pub mod bootstrapping; -use crate::boolean::engine::bootstrapping::{Bootstrapper, CompressedServerKey, ServerKey}; use crate::core_crypto::commons::generators::{ DeterministicSeeder, EncryptionRandomGenerator, SecretRandomGenerator, }; use crate::core_crypto::commons::math::random::{ActivatedRandomGenerator, Seeder}; use crate::core_crypto::commons::parameters::*; +use crate::core_crypto::entities::*; use crate::core_crypto::seeders::new_seeder; +use std::cell::RefCell; + +pub mod bootstrapping; #[cfg(test)] mod tests; @@ -253,7 +254,6 @@ cks1 has {choice1:?}, cks2 has: {choice2:?} ), }; - // encryption let ct = allocate_and_encrypt_new_lwe_ciphertext( &lwe_sk, plain, @@ -284,7 +284,6 @@ cks1 has {choice1:?}, cks2 has: {choice2:?} ), }; - // encryption let ct = allocate_and_encrypt_new_seeded_lwe_ciphertext( &lwe_sk, plain, @@ -310,7 +309,6 @@ cks1 has {choice1:?}, cks2 has: {choice2:?} CiphertextModulus::new_native(), ); - // encryption encrypt_lwe_ciphertext_with_public_key( &pks.lwe_public_key, &mut output, @@ -356,7 +354,6 @@ cks1 has {choice1:?}, cks2 has: {choice2:?} EncryptionKeyChoice::Small => cks.lwe_secret_key.as_view(), }; - // decryption let decrypted = decrypt_lwe_ciphertext(&lwe_sk, ciphertext); // cast as a u32 diff --git a/tfhe/src/boolean/key_switching_key/mod.rs b/tfhe/src/boolean/key_switching_key/mod.rs index 6348f6bf71..6ab6f5dd77 100644 --- a/tfhe/src/boolean/key_switching_key/mod.rs +++ b/tfhe/src/boolean/key_switching_key/mod.rs @@ -2,7 +2,6 @@ use crate::boolean::engine::{BooleanEngine, WithThreadLocalEngine}; use crate::boolean::parameters::BooleanKeySwitchingParameters; use crate::boolean::prelude::Ciphertext; use crate::boolean::ClientKey; - use crate::core_crypto::prelude::{keyswitch_lwe_ciphertext, LweKeyswitchKeyOwned}; #[cfg(test)] diff --git a/tfhe/src/boolean/keycache.rs b/tfhe/src/boolean/keycache.rs index 391ef5ae29..6db36a99a5 100644 --- a/tfhe/src/boolean/keycache.rs +++ b/tfhe/src/boolean/keycache.rs @@ -1,7 +1,7 @@ use crate::boolean::parameters::*; use crate::boolean::{ClientKey, ServerKey}; +use crate::keycache::utils::named_params_impl; use crate::keycache::*; -use crate::named_params_impl; use lazy_static::*; named_params_impl!( BooleanParameters => diff --git a/tfhe/src/boolean/public_key/compressed.rs b/tfhe/src/boolean/public_key/compressed.rs index e95147b9d7..5ab388cdd0 100644 --- a/tfhe/src/boolean/public_key/compressed.rs +++ b/tfhe/src/boolean/public_key/compressed.rs @@ -1,8 +1,7 @@ -use serde::{Deserialize, Serialize}; - use crate::boolean::engine::{BooleanEngine, WithThreadLocalEngine}; use crate::boolean::prelude::{BooleanParameters, Ciphertext, ClientKey}; use crate::core_crypto::prelude::SeededLwePublicKeyOwned; +use serde::{Deserialize, Serialize}; /// A structure containing a compressed public key. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] diff --git a/tfhe/src/boolean/public_key/standard.rs b/tfhe/src/boolean/public_key/standard.rs index add23bb8b4..c7966fdef8 100644 --- a/tfhe/src/boolean/public_key/standard.rs +++ b/tfhe/src/boolean/public_key/standard.rs @@ -1,5 +1,6 @@ //! Module with the definition of the encryption PublicKey. +use super::compressed::CompressedPublicKey; use crate::boolean::ciphertext::Ciphertext; use crate::boolean::client_key::ClientKey; use crate::boolean::engine::{BooleanEngine, WithThreadLocalEngine}; @@ -7,8 +8,6 @@ use crate::boolean::parameters::BooleanParameters; use crate::core_crypto::entities::*; use serde::{Deserialize, Serialize}; -use super::compressed::CompressedPublicKey; - /// A structure containing a public key. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PublicKey { diff --git a/tfhe/src/boolean/server_key/tests.rs b/tfhe/src/boolean/server_key/tests.rs index 468ae150d8..11dd2e5b8b 100644 --- a/tfhe/src/boolean/server_key/tests.rs +++ b/tfhe/src/boolean/server_key/tests.rs @@ -262,35 +262,25 @@ fn test_encrypt_decrypt_lwe_secret_key(parameters: BooleanParameters) { let (cks, sks) = (keys.client_key(), keys.server_key()); for _ in 0..NB_TESTS { - // encryption of false let ct_false = cks.encrypt(false); - // encryption of true let ct_true = cks.encrypt(true); - // decryption of false let dec_false = cks.decrypt(&ct_false); - // decryption of true let dec_true = cks.decrypt(&ct_true); - // assert assert!(!dec_false); assert!(dec_true); - // encryption of false let ct_false = sks.trivial_encrypt(false); - // encryption of true let ct_true = sks.trivial_encrypt(true); - // decryption of false let dec_false = cks.decrypt(&ct_false); - // decryption of true let dec_true = cks.decrypt(&ct_true); - // assert assert!(!dec_false); assert!(dec_true); } @@ -316,67 +306,53 @@ fn test_and_gate(parameters: BooleanParameters) { let b2 = random_boolean(); let expected_result = b1 && b2; - // encryption of b1 let ct1 = random_enum_encryption(cks, sks, b1); - // encryption of b2 let ct2 = random_enum_encryption(cks, sks, b2); // AND gate -> "left: {:?}, right: {:?}",ct1, ct2 let ct_res = sks.and(&ct1, &ct2); - // decryption let dec_and = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_and, "left: {ct1:?}, right: {ct2:?}"); // AND gate -> left: Ciphertext, right: bool let ct_res = sks.and(&ct1, b2); - // decryption let dec_and = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_and, "left: {ct1:?}, right: {b2:?}"); // AND gate -> left: bool, right: Ciphertext let ct_res = sks.and(b1, &ct2); - // decryption let dec_and = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_and, "left: {b1:?}, right: {ct2:?}"); // AND gate -> "left: {:?}, right: {:?}",ct1, ct2 let mut ct_res = ct1.clone(); sks.and_assign(&mut ct_res, &ct2); - // decryption let dec_and = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_and, "left: {ct1:?}, right: {ct2:?}"); // AND gate -> left: Ciphertext, right: bool let mut ct_res = ct1.clone(); sks.and_assign(&mut ct_res, b2); - // decryption let dec_and = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_and, "left: {ct1:?}, right: {b2:?}"); // AND gate -> left: bool, right: Ciphertext let mut ct_res = ct2.clone(); sks.and_assign(b1, &mut ct_res); - // decryption let dec_and = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_and, "left: {b1:?}, right: {ct2:?}"); } } @@ -392,22 +368,17 @@ fn test_mux_gate(parameters: BooleanParameters) { let b3 = random_boolean(); let expected_result = if b1 { b2 } else { b3 }; - // encryption of b1 let ct1 = random_enum_encryption(cks, sks, b1); - // encryption of b2 let ct2 = random_enum_encryption(cks, sks, b2); - // encryption of b3 let ct3 = random_enum_encryption(cks, sks, b3); // MUX gate let ct_res = sks.mux(&ct1, &ct2, &ct3); - // decryption let dec_mux = cks.decrypt(&ct_res); - // assert assert_eq!( expected_result, dec_mux, "cond: {ct1:?}, then: {ct2:?}, else: {ct3:?}" @@ -425,67 +396,53 @@ fn test_nand_gate(parameters: BooleanParameters) { let b2 = random_boolean(); let expected_result = !(b1 && b2); - // encryption of b1 let ct1 = random_enum_encryption(cks, sks, b1); - // encryption of b2 let ct2 = random_enum_encryption(cks, sks, b2); // NAND gate -> left: Ciphertext, right: Ciphertext let ct_res = sks.nand(&ct1, &ct2); - // decryption let dec_nand = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nand, "left: {ct1:?}, right: {ct2:?}"); // NAND gate -> left: Ciphertext, right: bool let ct_res = sks.nand(&ct1, b2); - // decryption let dec_nand = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nand, "left: {ct1:?}, right: {b2:?}"); // NAND gate -> left: bool, right: Ciphertext let ct_res = sks.nand(b1, &ct2); - // decryption let dec_nand = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nand, "left: {b1:?}, right: {ct2:?}"); // NAND gate -> "left: {:?}, right: {:?}",ct1, ct2 let mut ct_res = ct1.clone(); sks.nand_assign(&mut ct_res, &ct2); - // decryption let dec_nand = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nand, "left: {ct1:?}, right: {ct2:?}"); // NAND gate -> left: Ciphertext, right: bool let mut ct_res = ct1.clone(); sks.nand_assign(&mut ct_res, b2); - // decryption let dec_nand = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nand, "left: {ct1:?}, right: {b2:?}"); // NAND gate -> left: bool, right: Ciphertext let mut ct_res = ct2.clone(); sks.nand_assign(b1, &mut ct_res); - // decryption let dec_nand = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nand, "left: {b1:?}, right: {ct2:?}"); } } @@ -500,67 +457,53 @@ fn test_nor_gate(parameters: BooleanParameters) { let b2 = random_boolean(); let expected_result = !(b1 || b2); - // encryption of b1 let ct1 = random_enum_encryption(cks, sks, b1); - // encryption of b2 let ct2 = random_enum_encryption(cks, sks, b2); // NOR gate -> left: Ciphertext, right: Ciphertext let ct_res = sks.nor(&ct1, &ct2); - // decryption let dec_nor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nor, "left: {ct1:?}, right: {ct2:?}"); // NOR gate -> left: Ciphertext, right: bool let ct_res = sks.nor(&ct1, b2); - // decryption let dec_nor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nor, "left: {ct1:?}, right: {b2:?}"); // NOR gate -> left: bool, right: Ciphertext let ct_res = sks.nor(b1, &ct2); - // decryption let dec_nor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nor, "left: {b1:?}, right: {ct2:?}"); // NOR gate -> "left: {:?}, right: {:?}",ct1, ct2 let mut ct_res = ct1.clone(); sks.nor_assign(&mut ct_res, &ct2); - // decryption let dec_nor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nor, "left: {ct1:?}, right: {ct2:?}"); // NOR gate -> left: Ciphertext, right: bool let mut ct_res = ct1.clone(); sks.nor_assign(&mut ct_res, b2); - // decryption let dec_nor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nor, "left: {ct1:?}, right: {b2:?}"); // NOR gate -> left: bool, right: Ciphertext let mut ct_res = ct2.clone(); sks.nor_assign(b1, &mut ct_res); - // decryption let dec_nor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_nor, "left: {b1:?}, right: {ct2:?}"); } } @@ -574,26 +517,21 @@ fn test_not_gate(parameters: BooleanParameters) { let b1 = random_boolean(); let expected_result = !b1; - // encryption of b1 let ct1 = random_enum_encryption(cks, sks, b1); // NOT gate let ct_res = sks.not(&ct1); - // decryption let dec_not = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_not); // NOT gate let mut ct_res = ct1.clone(); sks.not_assign(&mut ct_res); - // decryption let dec_not = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_not); } } @@ -608,67 +546,53 @@ fn test_or_gate(parameters: BooleanParameters) { let b2 = random_boolean(); let expected_result = b1 || b2; - // encryption of b1 let ct1 = random_enum_encryption(cks, sks, b1); - // encryption of b2 let ct2 = random_enum_encryption(cks, sks, b2); // OR gate -> left: Ciphertext, right: Ciphertext let ct_res = sks.or(&ct1, &ct2); - // decryption let dec_or = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_or, "left: {ct1:?}, right: {ct2:?}"); // OR gate -> left: Ciphertext, right: bool let ct_res = sks.or(&ct1, b2); - // decryption let dec_or = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_or, "left: {ct1:?}, right: {b2:?}"); // OR gate -> left: bool, right: Ciphertext let ct_res = sks.or(b1, &ct2); - // decryption let dec_or = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_or, "left: {b1:?}, right: {ct2:?}"); // OR gate -> "left: {:?}, right: {:?}",ct1, ct2 let mut ct_res = ct1.clone(); sks.or_assign(&mut ct_res, &ct2); - // decryption let dec_or = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_or, "left: {ct1:?}, right: {ct2:?}"); // OR gate -> left: Ciphertext, right: bool let mut ct_res = ct1.clone(); sks.or_assign(&mut ct_res, b2); - // decryption let dec_or = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_or, "left: {ct1:?}, right: {b2:?}"); // OR gate -> left: bool, right: Ciphertext let mut ct_res = ct2.clone(); sks.or_assign(b1, &mut ct_res); - // decryption let dec_or = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_or, "left: {b1:?}, right: {ct2:?}"); } } @@ -683,67 +607,53 @@ fn test_xnor_gate(parameters: BooleanParameters) { let b2 = random_boolean(); let expected_result = b1 == b2; - // encryption of b1 let ct1 = random_enum_encryption(cks, sks, b1); - // encryption of b2 let ct2 = random_enum_encryption(cks, sks, b2); // XNOR gate -> left: Ciphertext, right: Ciphertext let ct_res = sks.xnor(&ct1, &ct2); - // decryption let dec_xnor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xnor, "left: {ct1:?}, right: {ct2:?}"); // XNOR gate -> left: Ciphertext, right: bool let ct_res = sks.xnor(&ct1, b2); - // decryption let dec_xnor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xnor, "left: {ct1:?}, right: {b2:?}"); // XNOR gate -> left: bool, right: Ciphertext let ct_res = sks.xnor(b1, &ct2); - // decryption let dec_xnor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xnor, "left: {b1:?}, right: {ct2:?}"); // XNOR gate -> "left: {:?}, right: {:?}",ct1, ct2 let mut ct_res = ct1.clone(); sks.xnor_assign(&mut ct_res, &ct2); - // decryption let dec_xnor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xnor, "left: {ct1:?}, right: {ct2:?}"); // XNOR gate -> left: Ciphertext, right: bool let mut ct_res = ct1.clone(); sks.xnor_assign(&mut ct_res, b2); - // decryption let dec_xnor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xnor, "left: {ct1:?}, right: {b2:?}"); // XNOR gate -> left: bool, right: Ciphertext let mut ct_res = ct2.clone(); sks.xnor_assign(b1, &mut ct_res); - // decryption let dec_xnor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xnor, "left: {b1:?}, right: {ct2:?}"); } } @@ -758,67 +668,53 @@ fn test_xor_gate(parameters: BooleanParameters) { let b2 = random_boolean(); let expected_result = b1 ^ b2; - // encryption of b1 let ct1 = random_enum_encryption(cks, sks, b1); - // encryption of b2 let ct2 = random_enum_encryption(cks, sks, b2); // XOR gate -> left: Ciphertext, right: Ciphertext let ct_res = sks.xor(&ct1, &ct2); - // decryption let dec_xor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xor, "left: {ct1:?}, right: {ct2:?}"); // XOR gate -> left: Ciphertext, right: bool let ct_res = sks.xor(&ct1, b2); - // decryption let dec_xor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xor, "left: {ct1:?}, right: {b2:?}"); // XOR gate -> left: bool, right: Ciphertext let ct_res = sks.xor(b1, &ct2); - // decryption let dec_xor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xor, "left: {b1:?}, right: {ct2:?}"); // XOR gate -> "left: {:?}, right: {:?}",ct1, ct2 let mut ct_res = ct1.clone(); sks.xor_assign(&mut ct_res, &ct2); - // decryption let dec_xor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xor, "left: {ct1:?}, right: {ct2:?}"); // XOR gate -> left: Ciphertext, right: bool let mut ct_res = ct1.clone(); sks.xor_assign(&mut ct_res, b2); - // decryption let dec_xor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xor, "left: {ct1:?}, right: {b2:?}"); // XOR gate -> left: bool, right: Ciphertext let mut ct_res = ct2.clone(); sks.xor_assign(b1, &mut ct_res); - // decryption let dec_xor = cks.decrypt(&ct_res); - // assert assert_eq!(expected_result, dec_xor, "left: {b1:?}, right: {ct2:?}"); } } diff --git a/tfhe/src/c_api/boolean/ciphertext.rs b/tfhe/src/c_api/boolean/ciphertext.rs index eb53d22dd5..32c15b5d98 100644 --- a/tfhe/src/c_api/boolean/ciphertext.rs +++ b/tfhe/src/c_api/boolean/ciphertext.rs @@ -1,9 +1,8 @@ +use crate::boolean; use crate::c_api::buffer::*; use crate::c_api::utils::*; use std::os::raw::c_int; -use crate::boolean; - pub struct BooleanCiphertext(pub(in crate::c_api) boolean::ciphertext::Ciphertext); pub struct BooleanCompressedCiphertext( diff --git a/tfhe/src/c_api/boolean/client_key.rs b/tfhe/src/c_api/boolean/client_key.rs index bc32491c19..778c549acb 100644 --- a/tfhe/src/c_api/boolean/client_key.rs +++ b/tfhe/src/c_api/boolean/client_key.rs @@ -1,10 +1,9 @@ +use super::{BooleanCiphertext, BooleanCompressedCiphertext}; +use crate::boolean; use crate::c_api::buffer::*; use crate::c_api::utils::*; use std::os::raw::c_int; -use crate::boolean; - -use super::{BooleanCiphertext, BooleanCompressedCiphertext}; pub struct BooleanClientKey(pub(in crate::c_api) boolean::client_key::ClientKey); #[no_mangle] diff --git a/tfhe/src/c_api/boolean/destroy.rs b/tfhe/src/c_api/boolean/destroy.rs index f365cd7d72..b1f9ce4f60 100644 --- a/tfhe/src/c_api/boolean/destroy.rs +++ b/tfhe/src/c_api/boolean/destroy.rs @@ -1,10 +1,9 @@ -use crate::c_api::utils::*; -use std::os::raw::c_int; - use super::{ BooleanCiphertext, BooleanClientKey, BooleanCompressedCiphertext, BooleanCompressedServerKey, BooleanPublicKey, BooleanServerKey, }; +use crate::c_api::utils::*; +use std::os::raw::c_int; #[no_mangle] pub unsafe extern "C" fn boolean_destroy_client_key(client_key: *mut BooleanClientKey) -> c_int { diff --git a/tfhe/src/c_api/boolean/mod.rs b/tfhe/src/c_api/boolean/mod.rs index 921e4dde2e..07e91e1ee5 100644 --- a/tfhe/src/c_api/boolean/mod.rs +++ b/tfhe/src/c_api/boolean/mod.rs @@ -5,11 +5,10 @@ pub mod parameters; pub mod public_key; pub mod server_key; +use crate::boolean; use crate::c_api::utils::*; use std::os::raw::c_int; -use crate::boolean; - pub use ciphertext::{BooleanCiphertext, BooleanCompressedCiphertext}; pub use client_key::BooleanClientKey; pub use public_key::BooleanPublicKey; diff --git a/tfhe/src/c_api/boolean/public_key.rs b/tfhe/src/c_api/boolean/public_key.rs index 7ffc1b00e0..2638e4cd2d 100644 --- a/tfhe/src/c_api/boolean/public_key.rs +++ b/tfhe/src/c_api/boolean/public_key.rs @@ -1,11 +1,9 @@ +use super::{BooleanCiphertext, BooleanClientKey}; +use crate::boolean; use crate::c_api::buffer::*; use crate::c_api::utils::*; use std::os::raw::c_int; -use crate::boolean; - -use super::{BooleanCiphertext, BooleanClientKey}; - pub struct BooleanPublicKey(pub(in crate::c_api) boolean::public_key::PublicKey); #[no_mangle] diff --git a/tfhe/src/c_api/boolean/server_key.rs b/tfhe/src/c_api/boolean/server_key.rs index 730c52049e..31fcd72e23 100644 --- a/tfhe/src/c_api/boolean/server_key.rs +++ b/tfhe/src/c_api/boolean/server_key.rs @@ -1,12 +1,10 @@ +use super::BooleanCiphertext; +use crate::boolean; +use crate::boolean::server_key::{BinaryBooleanGates, BinaryBooleanGatesAssign}; use crate::c_api::buffer::*; use crate::c_api::utils::*; use std::os::raw::c_int; -use crate::boolean; -use crate::boolean::server_key::{BinaryBooleanGates, BinaryBooleanGatesAssign}; - -use super::BooleanCiphertext; - pub struct BooleanServerKey(pub(in crate::c_api) boolean::server_key::ServerKey); pub struct BooleanCompressedServerKey( pub(in crate::c_api) boolean::server_key::CompressedServerKey, diff --git a/tfhe/src/c_api/high_level_api/booleans.rs b/tfhe/src/c_api/high_level_api/booleans.rs index c2c6d2b4da..b36caec31b 100644 --- a/tfhe/src/c_api/high_level_api/booleans.rs +++ b/tfhe/src/c_api/high_level_api/booleans.rs @@ -1,6 +1,6 @@ -use crate::high_level_api::prelude::*; - +use super::utils::*; use crate::c_api::utils::check_ptr_is_non_null_and_aligned; +use crate::high_level_api::prelude::*; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; pub struct FheBool(pub(in crate::c_api) crate::high_level_api::FheBool); diff --git a/tfhe/src/c_api/high_level_api/config.rs b/tfhe/src/c_api/high_level_api/config.rs index 432d034f18..cdc6fd2883 100644 --- a/tfhe/src/c_api/high_level_api/config.rs +++ b/tfhe/src/c_api/high_level_api/config.rs @@ -1,3 +1,4 @@ +use super::utils::*; use crate::c_api::utils::*; use std::os::raw::c_int; diff --git a/tfhe/src/c_api/high_level_api/integers.rs b/tfhe/src/c_api/high_level_api/integers.rs index 50dc702434..af404b24d4 100644 --- a/tfhe/src/c_api/high_level_api/integers.rs +++ b/tfhe/src/c_api/high_level_api/integers.rs @@ -1,3 +1,4 @@ +use super::utils::*; use crate::c_api::high_level_api::booleans::FheBool; use crate::c_api::high_level_api::i128::I128; use crate::c_api::high_level_api::i256::I256; diff --git a/tfhe/src/c_api/high_level_api/keys.rs b/tfhe/src/c_api/high_level_api/keys.rs index da04699a3c..cc32704837 100644 --- a/tfhe/src/c_api/high_level_api/keys.rs +++ b/tfhe/src/c_api/high_level_api/keys.rs @@ -1,3 +1,4 @@ +use super::utils::*; use crate::c_api::utils::*; use std::os::raw::c_int; diff --git a/tfhe/src/c_api/high_level_api/mod.rs b/tfhe/src/c_api/high_level_api/mod.rs index c0cce1aaa6..b90e95825f 100644 --- a/tfhe/src/c_api/high_level_api/mod.rs +++ b/tfhe/src/c_api/high_level_api/mod.rs @@ -1,5 +1,3 @@ -#[macro_use] -mod utils; #[cfg(feature = "boolean")] pub mod booleans; pub mod config; @@ -10,3 +8,4 @@ pub mod keys; mod threading; pub mod u128; pub mod u256; +mod utils; diff --git a/tfhe/src/c_api/high_level_api/utils.rs b/tfhe/src/c_api/high_level_api/utils.rs index 458906b9d6..21bcdbec59 100644 --- a/tfhe/src/c_api/high_level_api/utils.rs +++ b/tfhe/src/c_api/high_level_api/utils.rs @@ -62,6 +62,8 @@ macro_rules! impl_destroy_on_type { }; } +pub(crate) use impl_destroy_on_type; + macro_rules! impl_try_encrypt_with_client_key_on_type { ($wrapper_type:ty{$wrapped_type:ty}, $input_type:ty) => { ::paste::paste! { @@ -84,6 +86,8 @@ macro_rules! impl_try_encrypt_with_client_key_on_type { }; } +pub(crate) use impl_try_encrypt_with_client_key_on_type; + macro_rules! impl_try_encrypt_with_public_key_on_type { ($wrapper_type:ty{$wrapped_type:ty}, $input_type:ty) => { ::paste::paste! { @@ -107,6 +111,8 @@ macro_rules! impl_try_encrypt_with_public_key_on_type { }; } +pub(crate) use impl_try_encrypt_with_public_key_on_type; + macro_rules! impl_try_encrypt_with_compact_public_key_on_type { ($wrapper_type:ty{$wrapped_type:ty}, $input_type:ty) => { ::paste::paste! { @@ -130,6 +136,8 @@ macro_rules! impl_try_encrypt_with_compact_public_key_on_type { }; } +pub(crate) use impl_try_encrypt_with_compact_public_key_on_type; + macro_rules! impl_try_encrypt_list_with_compact_public_key_on_type { ($wrapper_type:ty{$wrapped_type:ty}, $input_type:ty) => { ::paste::paste! { @@ -152,6 +160,8 @@ macro_rules! impl_try_encrypt_list_with_compact_public_key_on_type { }; } +pub(crate) use impl_try_encrypt_list_with_compact_public_key_on_type; + macro_rules! impl_try_encrypt_trivial_on_type { ($wrapper_type:ty{$wrapped_type:ty}, $input_type:ty) => { ::paste::paste! { @@ -172,6 +182,8 @@ macro_rules! impl_try_encrypt_trivial_on_type { }; } +pub(crate) use impl_try_encrypt_trivial_on_type; + macro_rules! impl_decrypt_on_type { ($wrapper_type:ty, $output_type:ty) => { ::paste::paste! { @@ -196,6 +208,8 @@ macro_rules! impl_decrypt_on_type { }; } +pub(crate) use impl_decrypt_on_type; + macro_rules! impl_try_decrypt_trivial_on_type { ($wrapper_type:ty, $output_type:ty) => { ::paste::paste! { @@ -228,6 +242,8 @@ macro_rules! impl_try_decrypt_trivial_on_type { }; } +pub(crate) use impl_try_decrypt_trivial_on_type; + macro_rules! impl_clone_on_type { ($wrapper_type:ty) => { ::paste::paste! { @@ -250,6 +266,8 @@ macro_rules! impl_clone_on_type { }; } +pub(crate) use impl_clone_on_type; + macro_rules! impl_serialize_deserialize_on_type { ($wrapper_type:ty) => { ::paste::paste! { @@ -294,6 +312,8 @@ macro_rules! impl_serialize_deserialize_on_type { }; } +pub(crate) use impl_serialize_deserialize_on_type; + macro_rules! impl_safe_serialize_on_type { ($wrapper_type:ty) => { ::paste::paste! { @@ -320,6 +340,8 @@ macro_rules! impl_safe_serialize_on_type { }; } +pub(crate) use impl_safe_serialize_on_type; + macro_rules! impl_safe_deserialize_conformant_integer { ($wrapper_type:ty, $function_name:path) => { ::paste::paste! { @@ -359,6 +381,8 @@ macro_rules! impl_safe_deserialize_conformant_integer { }; } +pub(crate) use impl_safe_deserialize_conformant_integer; + macro_rules! impl_binary_fn_on_type { // More general binary fn case, // where the type of the left-hand side can be different @@ -405,6 +429,9 @@ macro_rules! impl_binary_fn_on_type { ); }; } + +pub(crate) use impl_binary_fn_on_type; + // Like binary fn, but an extra output value is needed for the overflow flag macro_rules! impl_binary_overflowing_fn_on_type { ( @@ -447,6 +474,8 @@ macro_rules! impl_binary_overflowing_fn_on_type { }; } +pub(crate) use impl_binary_overflowing_fn_on_type; + // Comparisons returns FheBool so we use a specialized // macro for them macro_rules! impl_comparison_fn_on_type { @@ -479,6 +508,8 @@ macro_rules! impl_comparison_fn_on_type { }; } +pub(crate) use impl_comparison_fn_on_type; + macro_rules! impl_scalar_comparison_fn_on_type { ( lhs_type: $lhs_type:ty, @@ -510,6 +541,8 @@ macro_rules! impl_scalar_comparison_fn_on_type { }; } +pub(crate) use impl_scalar_comparison_fn_on_type; + macro_rules! impl_unary_fn_on_type { ($wrapper_type:ty => $($unary_fn_name:ident),* $(,)?) => { $( @@ -532,6 +565,8 @@ macro_rules! impl_unary_fn_on_type { }; } +pub(crate) use impl_unary_fn_on_type; + macro_rules! impl_binary_assign_fn_on_type { // More general binary fn case, // where the type of the left-hand side can be different @@ -571,6 +606,8 @@ macro_rules! impl_binary_assign_fn_on_type { }; } +pub(crate) use impl_binary_assign_fn_on_type; + macro_rules! impl_scalar_binary_fn_on_type { ($wrapper_type:ty, $scalar_type:ty => $($binary_fn_name:ident),* $(,)?) => { $( @@ -595,6 +632,8 @@ macro_rules! impl_scalar_binary_fn_on_type { }; } +pub(crate) use impl_scalar_binary_fn_on_type; + macro_rules! impl_scalar_binary_assign_fn_on_type { ($wrapper_type:ty, $scalar_type:ty => $($binary_assign_fn_name:ident),* $(,)?) => { $( @@ -617,6 +656,8 @@ macro_rules! impl_scalar_binary_assign_fn_on_type { }; } +pub(crate) use impl_scalar_binary_assign_fn_on_type; + // Defines the function to cast `from` a type _into_ the given list of type macro_rules! define_casting_operation( ($from:ty => $($to:ty),*) => { @@ -639,3 +680,5 @@ macro_rules! define_casting_operation( )* } ); + +pub(crate) use define_casting_operation; diff --git a/tfhe/src/c_api/shortint/ciphertext.rs b/tfhe/src/c_api/shortint/ciphertext.rs index 6694c298fd..bacad31c15 100644 --- a/tfhe/src/c_api/shortint/ciphertext.rs +++ b/tfhe/src/c_api/shortint/ciphertext.rs @@ -1,10 +1,9 @@ use crate::c_api::buffer::*; use crate::c_api::utils::*; +use crate::shortint; use crate::shortint::ciphertext::Degree; use std::os::raw::c_int; -use crate::shortint; - pub struct ShortintCiphertext(pub(in crate::c_api) shortint::Ciphertext); pub struct ShortintCompressedCiphertext(pub(in crate::c_api) shortint::CompressedCiphertext); diff --git a/tfhe/src/c_api/shortint/client_key.rs b/tfhe/src/c_api/shortint/client_key.rs index 68d32ba9e0..0d81af71f8 100644 --- a/tfhe/src/c_api/shortint/client_key.rs +++ b/tfhe/src/c_api/shortint/client_key.rs @@ -1,10 +1,8 @@ +use super::{ShortintCiphertext, ShortintCompressedCiphertext}; use crate::c_api::buffer::*; use crate::c_api::utils::*; -use std::os::raw::c_int; - use crate::shortint; - -use super::{ShortintCiphertext, ShortintCompressedCiphertext}; +use std::os::raw::c_int; pub struct ShortintClientKey(pub(in crate::c_api) shortint::client_key::ClientKey); #[no_mangle] diff --git a/tfhe/src/c_api/shortint/destroy.rs b/tfhe/src/c_api/shortint/destroy.rs index 8043c930b3..3cfaa04f80 100644 --- a/tfhe/src/c_api/shortint/destroy.rs +++ b/tfhe/src/c_api/shortint/destroy.rs @@ -1,11 +1,10 @@ -use crate::c_api::utils::*; -use std::os::raw::c_int; - use super::{ ShortintBivariatePBSLookupTable, ShortintCiphertext, ShortintClientKey, ShortintCompressedCiphertext, ShortintCompressedPublicKey, ShortintCompressedServerKey, ShortintPBSLookupTable, ShortintPublicKey, ShortintServerKey, }; +use crate::c_api::utils::*; +use std::os::raw::c_int; #[no_mangle] pub unsafe extern "C" fn shortint_destroy_client_key(client_key: *mut ShortintClientKey) -> c_int { diff --git a/tfhe/src/c_api/shortint/mod.rs b/tfhe/src/c_api/shortint/mod.rs index 902a21c041..6bf9830089 100644 --- a/tfhe/src/c_api/shortint/mod.rs +++ b/tfhe/src/c_api/shortint/mod.rs @@ -6,9 +6,8 @@ pub mod public_key; pub mod server_key; use crate::c_api::utils::*; -use std::os::raw::c_int; - use crate::shortint; +use std::os::raw::c_int; pub use ciphertext::{ShortintCiphertext, ShortintCompressedCiphertext}; pub use client_key::ShortintClientKey; diff --git a/tfhe/src/c_api/shortint/public_key.rs b/tfhe/src/c_api/shortint/public_key.rs index 2e5873848e..9eb3622c04 100644 --- a/tfhe/src/c_api/shortint/public_key.rs +++ b/tfhe/src/c_api/shortint/public_key.rs @@ -1,10 +1,8 @@ +use super::{ShortintCiphertext, ShortintClientKey}; use crate::c_api::buffer::*; use crate::c_api::utils::*; -use std::os::raw::c_int; - use crate::shortint; - -use super::{ShortintCiphertext, ShortintClientKey}; +use std::os::raw::c_int; pub struct ShortintPublicKey(pub(in crate::c_api) shortint::PublicKey); diff --git a/tfhe/src/c_api/shortint/server_key/add.rs b/tfhe/src/c_api/shortint/server_key/add.rs index 122260a9b9..545ba8ba06 100644 --- a/tfhe/src/c_api/shortint/server_key/add.rs +++ b/tfhe/src/c_api/shortint/server_key/add.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_add( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/bitwise_op.rs b/tfhe/src/c_api/shortint/server_key/bitwise_op.rs index 0021527090..578a7f4dac 100644 --- a/tfhe/src/c_api/shortint/server_key/bitwise_op.rs +++ b/tfhe/src/c_api/shortint/server_key/bitwise_op.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_bitand( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/comp_op.rs b/tfhe/src/c_api/shortint/server_key/comp_op.rs index 9d5bf9b41b..c5f0153a02 100644 --- a/tfhe/src/c_api/shortint/server_key/comp_op.rs +++ b/tfhe/src/c_api/shortint/server_key/comp_op.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_greater( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/div_mod.rs b/tfhe/src/c_api/shortint/server_key/div_mod.rs index 7d17186ad5..34a3e6e39e 100644 --- a/tfhe/src/c_api/shortint/server_key/div_mod.rs +++ b/tfhe/src/c_api/shortint/server_key/div_mod.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_div( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/mod.rs b/tfhe/src/c_api/shortint/server_key/mod.rs index 805e939939..41f6431565 100644 --- a/tfhe/src/c_api/shortint/server_key/mod.rs +++ b/tfhe/src/c_api/shortint/server_key/mod.rs @@ -1,10 +1,8 @@ +use super::ShortintCiphertext; use crate::c_api::buffer::*; use crate::c_api::utils::*; -use std::os::raw::c_int; - use crate::shortint; - -use super::ShortintCiphertext; +use std::os::raw::c_int; pub mod add; pub mod bitwise_op; diff --git a/tfhe/src/c_api/shortint/server_key/mul.rs b/tfhe/src/c_api/shortint/server_key/mul.rs index 314842a37f..0237ca4a20 100644 --- a/tfhe/src/c_api/shortint/server_key/mul.rs +++ b/tfhe/src/c_api/shortint/server_key/mul.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_mul( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/neg.rs b/tfhe/src/c_api/shortint/server_key/neg.rs index e982b9e365..0d1a30188b 100644 --- a/tfhe/src/c_api/shortint/server_key/neg.rs +++ b/tfhe/src/c_api/shortint/server_key/neg.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_neg( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/pbs.rs b/tfhe/src/c_api/shortint/server_key/pbs.rs index 27de910cc3..a1ced14e83 100644 --- a/tfhe/src/c_api/shortint/server_key/pbs.rs +++ b/tfhe/src/c_api/shortint/server_key/pbs.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - // This is the accepted way to declare a pointer to a C function/callback in cbindgen pub type LookupTableCallback = Option u64>; pub type BivariateLookupTableCallback = Option u64>; diff --git a/tfhe/src/c_api/shortint/server_key/scalar_add.rs b/tfhe/src/c_api/shortint/server_key/scalar_add.rs index 6967509b13..1a18ab17a6 100644 --- a/tfhe/src/c_api/shortint/server_key/scalar_add.rs +++ b/tfhe/src/c_api/shortint/server_key/scalar_add.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_scalar_add( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/scalar_mul.rs b/tfhe/src/c_api/shortint/server_key/scalar_mul.rs index 9439f08101..c88f756c43 100644 --- a/tfhe/src/c_api/shortint/server_key/scalar_mul.rs +++ b/tfhe/src/c_api/shortint/server_key/scalar_mul.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_scalar_mul( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/scalar_sub.rs b/tfhe/src/c_api/shortint/server_key/scalar_sub.rs index f15481de2c..f0da400c4b 100644 --- a/tfhe/src/c_api/shortint/server_key/scalar_sub.rs +++ b/tfhe/src/c_api/shortint/server_key/scalar_sub.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_scalar_sub( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/shift.rs b/tfhe/src/c_api/shortint/server_key/shift.rs index c0c8520a77..d452a18b96 100644 --- a/tfhe/src/c_api/shortint/server_key/shift.rs +++ b/tfhe/src/c_api/shortint/server_key/shift.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_scalar_left_shift( server_key: *const ShortintServerKey, diff --git a/tfhe/src/c_api/shortint/server_key/sub.rs b/tfhe/src/c_api/shortint/server_key/sub.rs index ec20b0d56c..032d7fc173 100644 --- a/tfhe/src/c_api/shortint/server_key/sub.rs +++ b/tfhe/src/c_api/shortint/server_key/sub.rs @@ -1,8 +1,7 @@ +use super::{ShortintCiphertext, ShortintServerKey}; use crate::c_api::utils::*; use std::os::raw::c_int; -use super::{ShortintCiphertext, ShortintServerKey}; - #[no_mangle] pub unsafe extern "C" fn shortint_server_key_smart_sub( server_key: *const ShortintServerKey, diff --git a/tfhe/src/core_crypto/algorithms/lwe_programmable_bootstrapping.rs b/tfhe/src/core_crypto/algorithms/lwe_programmable_bootstrapping.rs index b06b3dd75d..18d65fcba7 100644 --- a/tfhe/src/core_crypto/algorithms/lwe_programmable_bootstrapping.rs +++ b/tfhe/src/core_crypto/algorithms/lwe_programmable_bootstrapping.rs @@ -211,7 +211,7 @@ use dyn_stack::{PodStack, SizeOverflow, StackReq}; /// let pbs_multiplication_plaintext: Plaintext = /// decrypt_lwe_ciphertext(&big_lwe_sk, &pbs_multiplication_ct); /// -/// /// // Create a SignedDecomposer to perform the rounding of the decrypted plaintext +/// // Create a SignedDecomposer to perform the rounding of the decrypted plaintext /// // We pass a DecompositionBaseLog of 5 and a DecompositionLevelCount of 1 indicating we want to /// // round the 5 MSB, 1 bit of padding plus our 4 bits of message /// let signed_decomposer = @@ -632,7 +632,7 @@ pub fn cmux_assign( /// &mut encryption_generator, /// ); /// -/// /// // Create the plaintext +/// // Create the plaintext /// let msg_ggsw_1 = Plaintext(1u64); /// /// // Create a new GgswCiphertext diff --git a/tfhe/src/core_crypto/algorithms/seeded_lwe_ciphertext_list_decompression.rs b/tfhe/src/core_crypto/algorithms/seeded_lwe_ciphertext_list_decompression.rs index 512d7a3b4d..44b468aa15 100644 --- a/tfhe/src/core_crypto/algorithms/seeded_lwe_ciphertext_list_decompression.rs +++ b/tfhe/src/core_crypto/algorithms/seeded_lwe_ciphertext_list_decompression.rs @@ -5,7 +5,6 @@ use crate::core_crypto::commons::ciphertext_modulus::CiphertextModulusKind; use crate::core_crypto::commons::generators::MaskRandomGenerator; use crate::core_crypto::commons::traits::*; use crate::core_crypto::entities::*; - use rayon::prelude::*; /// Convenience function to share the core logic of the decompression algorithm for diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_packing_keyswitch_key_generation.rs b/tfhe/src/core_crypto/algorithms/test/lwe_packing_keyswitch_key_generation.rs index 26ee3640e2..edc62ae884 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_packing_keyswitch_key_generation.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_packing_keyswitch_key_generation.rs @@ -1,5 +1,4 @@ use super::*; - use crate::core_crypto::commons::generators::DeterministicSeeder; #[cfg(not(tarpaulin))] diff --git a/tfhe/src/core_crypto/algorithms/test/mod.rs b/tfhe/src/core_crypto/algorithms/test/mod.rs index 832cf45430..3aae50f5b5 100644 --- a/tfhe/src/core_crypto/algorithms/test/mod.rs +++ b/tfhe/src/core_crypto/algorithms/test/mod.rs @@ -5,7 +5,6 @@ pub use super::misc::check_encrypted_content_respects_mod; use crate::core_crypto::algorithms::misc::divide_round; use crate::core_crypto::keycache::KeyCacheAccess; use crate::core_crypto::prelude::*; -use paste::paste; use std::fmt::Debug; mod ggsw_encryption; @@ -482,7 +481,7 @@ pub(crate) fn gen_keys_or_get_from_cache_if_enabled< // Macro to generate tests for all parameter sets macro_rules! create_parametrized_test{ ($name:ident { $($param:ident),* $(,)? }) => { - paste! { + ::paste::paste! { $( #[test] fn []() { diff --git a/tfhe/src/core_crypto/algorithms/test/modulus_switch_compression.rs b/tfhe/src/core_crypto/algorithms/test/modulus_switch_compression.rs index eb8f7499f4..337fd6c649 100644 --- a/tfhe/src/core_crypto/algorithms/test/modulus_switch_compression.rs +++ b/tfhe/src/core_crypto/algorithms/test/modulus_switch_compression.rs @@ -1,5 +1,5 @@ use super::*; -use crate::core_crypto::prelude::modulus_switched_lwe_ciphertext::PackedModulusSwitchedLweCiphertext; +use crate::core_crypto::prelude::compressed_modulus_switched_lwe_ciphertext::CompressedModulusSwitchedLweCiphertext; #[cfg(not(tarpaulin))] const NB_TESTS: usize = 10; @@ -42,7 +42,7 @@ fn encryption_ms_decryption( ); // Can be stored using much less space than the standard lwe ciphertexts - let compressed = PackedModulusSwitchedLweCiphertext::compress( + let compressed = CompressedModulusSwitchedLweCiphertext::compress( &lwe, CiphertextModulusLog(params.polynomial_size.log2().0 + 1), ); diff --git a/tfhe/src/core_crypto/commons/generators/encryption/mod.rs b/tfhe/src/core_crypto/commons/generators/encryption/mod.rs index f415c299ca..e1bb625580 100644 --- a/tfhe/src/core_crypto/commons/generators/encryption/mod.rs +++ b/tfhe/src/core_crypto/commons/generators/encryption/mod.rs @@ -4,6 +4,7 @@ pub(crate) mod mask_random_generator; pub(crate) mod noise_random_generator; #[cfg(test)] mod test; + use crate::core_crypto::commons::math::random::{ ByteRandomGenerator, Distribution, ParallelByteRandomGenerator, RandomGenerable, Seed, Seeder, Uniform, diff --git a/tfhe/src/core_crypto/commons/mod.rs b/tfhe/src/core_crypto/commons/mod.rs index 75e9957c60..9039f8d328 100644 --- a/tfhe/src/core_crypto/commons/mod.rs +++ b/tfhe/src/core_crypto/commons/mod.rs @@ -10,35 +10,6 @@ //! This module contains structures that wrap unsigned integer parameters like the ciphertext //! dimension or the polynomial degree. -#[allow(unused_macros)] -macro_rules! assert_delta { - ($A:expr, $B:expr, $d:expr) => { - for (x, y) in $A.iter().zip($B) { - assert!((*x as i64 - y as i64).abs() <= $d, "{} != {} ", *x, y); - } - }; -} - -#[allow(unused_macros)] -macro_rules! assert_delta_scalar { - ($A:expr, $B:expr, $d:expr) => { - assert!( - ($A as i64 - $B as i64).abs() <= $d, - "{} != {} +- {}", - $A, - $B, - $d - ); - }; -} - -#[allow(unused_macros)] -macro_rules! assert_delta_scalar_float { - ($A:expr, $B:expr, $d:expr) => { - assert!(($A - $B).abs() <= $d, "{} != {} +- {}", $A, $B, $d); - }; -} - pub mod ciphertext_modulus; pub mod computation_buffers; pub mod dispersion; diff --git a/tfhe/src/core_crypto/commons/utils.rs b/tfhe/src/core_crypto/commons/utils.rs index b00bfa9584..a40f1dd09c 100644 --- a/tfhe/src/core_crypto/commons/utils.rs +++ b/tfhe/src/core_crypto/commons/utils.rs @@ -26,7 +26,6 @@ pub trait ZipChecked: IntoIterator + Sized { impl ZipChecked for A {} // https://docs.rs/itertools/0.7.8/src/itertools/lib.rs.html#247-269 -#[allow(unused_macros)] macro_rules! izip { (@ __closure @ ($a:expr)) => { |a| (a,) }; (@ __closure @ ($a:expr, $b:expr)) => { |(a, b)| (a, b) }; @@ -62,32 +61,4 @@ macro_rules! izip { }; } -#[allow(unused_macros)] -macro_rules! dbgx { - // NOTE: We cannot use `concat!` to make a static string as a format argument - // of `eprintln!` because `file!` could contain a `{` or - // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!` - // will be malformed. - () => { - ::std::eprintln!("[{}:{}]", $crate::file!(), $crate::line!()) - }; - ($val:expr $(,)?) => { - // Use of `match` here is intentional because it affects the lifetimes - // of temporaries - https://stackoverflow.com/a/48732525/1063961 - match $val { - tmp => { - ::std::eprintln!("[{}:{}] {} = {:#x?}", - ::std::file!(), ::std::line!(), ::std::stringify!($val), &tmp); - tmp - } - } - }; - ($($val:expr),+ $(,)?) => { - ($($crate::core_crypto::commons::utils::dbgx!($val)),+,) - }; -} - -#[allow(unused_imports)] -pub(crate) use dbgx; -#[allow(unused_imports)] pub(crate) use izip; diff --git a/tfhe/src/core_crypto/entities/modulus_switched_lwe_ciphertext.rs b/tfhe/src/core_crypto/entities/compressed_modulus_switched_lwe_ciphertext.rs similarity index 94% rename from tfhe/src/core_crypto/entities/modulus_switched_lwe_ciphertext.rs rename to tfhe/src/core_crypto/entities/compressed_modulus_switched_lwe_ciphertext.rs index 31be860a9a..15c553b85b 100644 --- a/tfhe/src/core_crypto/entities/modulus_switched_lwe_ciphertext.rs +++ b/tfhe/src/core_crypto/entities/compressed_modulus_switched_lwe_ciphertext.rs @@ -8,17 +8,19 @@ use crate::core_crypto::prelude::*; /// /// ```rust /// use concrete_csprng::seeders::Seed; -/// use tfhe::core_crypto::prelude::*; /// use tfhe::core_crypto::fft_impl::common::modulus_switch; -/// use tfhe::core_crypto::prelude::modulus_switched_lwe_ciphertext::PackedModulusSwitchedLweCiphertext; +/// use tfhe::core_crypto::prelude::*; +/// use tfhe::core_crypto::prelude::compressed_modulus_switched_lwe_ciphertext::CompressedModulusSwitchedLweCiphertext; /// /// let log_modulus = 12; /// /// let mut secret_generator = SecretRandomGenerator::::new(Seed(0)); /// /// // Create the LweSecretKey -/// let lwe_secret_key = -/// allocate_and_generate_new_binary_lwe_secret_key::(LweDimension(2048), &mut secret_generator); +/// let lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key::( +/// LweDimension(2048), +/// &mut secret_generator, +/// ); /// let ciphertext_modulus = CiphertextModulus::new_native(); /// /// let mut seeder = new_seeder(); @@ -27,7 +29,6 @@ use crate::core_crypto::prelude::*; /// let mut encryption_generator = /// EncryptionRandomGenerator::::new(seeder.seed(), seeder); /// -/// /// // Unsecure parameters, do not use them /// let lwe = allocate_and_encrypt_new_lwe_ciphertext( /// &lwe_secret_key, @@ -38,7 +39,7 @@ use crate::core_crypto::prelude::*; /// ); /// /// // Can be stored using much less space than the standard lwe ciphertexts -/// let compressed = PackedModulusSwitchedLweCiphertext::compress( +/// let compressed = CompressedModulusSwitchedLweCiphertext::compress( /// &lwe, /// CiphertextModulusLog(log_modulus as usize), /// ); @@ -53,14 +54,15 @@ use crate::core_crypto::prelude::*; /// 0 /// ); /// ``` -pub struct PackedModulusSwitchedLweCiphertext { +#[derive(Clone, serde::Serialize, serde::Deserialize)] +pub struct CompressedModulusSwitchedLweCiphertext { packed_coeffs: Vec, lwe_dimension: LweDimension, log_modulus: CiphertextModulusLog, uncompressed_ciphertext_modulus: CiphertextModulus, } -impl PackedModulusSwitchedLweCiphertext { +impl CompressedModulusSwitchedLweCiphertext { /// Compresses a ciphertext by reducing its modulus /// This operation adds a lot of noise pub fn compress>( @@ -286,8 +288,10 @@ mod test { let lwe = LweCiphertextOwned::from_container(lwe, ciphertext_modulus); - let compressed = - PackedModulusSwitchedLweCiphertext::compress(&lwe, CiphertextModulusLog(log_modulus)); + let compressed = CompressedModulusSwitchedLweCiphertext::compress( + &lwe, + CiphertextModulusLog(log_modulus), + ); let lwe_ms_ed: Vec = compressed.extract().into_container(); diff --git a/tfhe/src/core_crypto/entities/mod.rs b/tfhe/src/core_crypto/entities/mod.rs index 486f900f1e..9f846d73cc 100644 --- a/tfhe/src/core_crypto/entities/mod.rs +++ b/tfhe/src/core_crypto/entities/mod.rs @@ -4,6 +4,7 @@ //! associated to the object, e.g., `get_mask` for the entity `LweCiphertext`. pub mod cleartext; +pub mod compressed_modulus_switched_lwe_ciphertext; pub mod ggsw_ciphertext; pub mod ggsw_ciphertext_list; pub mod glwe_ciphertext; @@ -22,7 +23,6 @@ pub mod lwe_private_functional_packing_keyswitch_key; pub mod lwe_private_functional_packing_keyswitch_key_list; pub mod lwe_public_key; pub mod lwe_secret_key; -pub mod modulus_switched_lwe_ciphertext; pub mod plaintext; pub mod plaintext_list; pub mod polynomial; diff --git a/tfhe/src/core_crypto/fft_impl/fft128/math/fft/tests.rs b/tfhe/src/core_crypto/fft_impl/fft128/math/fft/tests.rs index 73f71f4d1e..25fd1b0c93 100644 --- a/tfhe/src/core_crypto/fft_impl/fft128/math/fft/tests.rs +++ b/tfhe/src/core_crypto/fft_impl/fft128/math/fft/tests.rs @@ -1,8 +1,7 @@ -use dyn_stack::{GlobalPodBuffer, ReborrowMut}; - use super::*; use crate::core_crypto::commons::test_tools::{modular_distance, new_random_generator}; use aligned_vec::avec; +use dyn_stack::{GlobalPodBuffer, ReborrowMut}; fn test_roundtrip() { let mut generator = new_random_generator(); diff --git a/tfhe/src/core_crypto/fft_impl/fft128_u128/crypto/tests.rs b/tfhe/src/core_crypto/fft_impl/fft128_u128/crypto/tests.rs index b3136fad4f..1da0a7b825 100644 --- a/tfhe/src/core_crypto/fft_impl/fft128_u128/crypto/tests.rs +++ b/tfhe/src/core_crypto/fft_impl/fft128_u128/crypto/tests.rs @@ -1,5 +1,3 @@ -use dyn_stack::{GlobalPodBuffer, PodStack, ReborrowMut}; - use super::super::super::{fft128, fft128_u128}; use super::super::math::fft::Fft128View; use crate::core_crypto::fft_impl::common::tests::{ @@ -8,6 +6,7 @@ use crate::core_crypto::fft_impl::common::tests::{ use crate::core_crypto::prelude::test::{TestResources, FFT128_U128_PARAMS}; use crate::core_crypto::prelude::*; use aligned_vec::CACHELINE_ALIGN; +use dyn_stack::{GlobalPodBuffer, PodStack, ReborrowMut}; #[test] fn test_split_external_product() { diff --git a/tfhe/src/core_crypto/fft_impl/fft128_u128/math/fft/mod.rs b/tfhe/src/core_crypto/fft_impl/fft128_u128/math/fft/mod.rs index 053edd4c72..b6ed146396 100644 --- a/tfhe/src/core_crypto/fft_impl/fft128_u128/math/fft/mod.rs +++ b/tfhe/src/core_crypto/fft_impl/fft128_u128/math/fft/mod.rs @@ -2,7 +2,6 @@ use crate::core_crypto::commons::utils::izip; pub use crate::core_crypto::fft_impl::fft128::math::fft::Fft128View; use concrete_fft::fft128::f128; use dyn_stack::PodStack; - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use pulp::{f64x4, u64x4, x86::V3}; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] diff --git a/tfhe/src/core_crypto/fft_impl/fft64/crypto/wop_pbs/mod.rs b/tfhe/src/core_crypto/fft_impl/fft64/crypto/wop_pbs/mod.rs index 3be09d71ce..551c3aa7e9 100644 --- a/tfhe/src/core_crypto/fft_impl/fft64/crypto/wop_pbs/mod.rs +++ b/tfhe/src/core_crypto/fft_impl/fft64/crypto/wop_pbs/mod.rs @@ -1,8 +1,5 @@ #![allow(clippy::too_many_arguments)] -use aligned_vec::CACHELINE_ALIGN; -use dyn_stack::{PodStack, ReborrowMut, SizeOverflow, StackReq}; - use super::super::math::fft::FftView; use super::bootstrap::{bootstrap_scratch, FourierLweBootstrapKeyView}; use super::ggsw::{ @@ -17,8 +14,9 @@ use crate::core_crypto::commons::parameters::*; use crate::core_crypto::commons::traits::*; use crate::core_crypto::commons::utils::izip; use crate::core_crypto::entities::*; - +use aligned_vec::CACHELINE_ALIGN; use concrete_fft::c64; +use dyn_stack::{PodStack, ReborrowMut, SizeOverflow, StackReq}; pub fn extract_bits_scratch( input_lwe_dimension: LweDimension, diff --git a/tfhe/src/core_crypto/fft_impl/fft64/crypto/wop_pbs/tests.rs b/tfhe/src/core_crypto/fft_impl/fft64/crypto/wop_pbs/tests.rs index 58bda528c5..267856b773 100644 --- a/tfhe/src/core_crypto/fft_impl/fft64/crypto/wop_pbs/tests.rs +++ b/tfhe/src/core_crypto/fft_impl/fft64/crypto/wop_pbs/tests.rs @@ -328,7 +328,6 @@ fn test_circuit_bootstrapping_binary() { for _ in 0..NB_TESTS { // value is 0 or 1 as CBS works on messages expected to contain 1 bit of information 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, small_lwe_dimension.to_lwe_size(), ciphertext_modulus); diff --git a/tfhe/src/core_crypto/fft_impl/fft64/math/fft/x86.rs b/tfhe/src/core_crypto/fft_impl/fft64/math/fft/x86.rs index 9091e2ab4e..644835868a 100644 --- a/tfhe/src/core_crypto/fft_impl/fft64/math/fft/x86.rs +++ b/tfhe/src/core_crypto/fft_impl/fft64/math/fft/x86.rs @@ -9,15 +9,13 @@ //! //! more dispatch options may be added in the future +use super::super::super::c64; +use super::TwistiesView; +use crate::core_crypto::commons::utils::izip; #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] use core::arch::x86_64::*; - -use super::super::super::c64; -use super::TwistiesView; -use crate::core_crypto::commons::utils::izip; - use pulp::x86::V3; #[cfg(feature = "nightly-avx512")] use pulp::x86::V4; diff --git a/tfhe/src/core_crypto/gpu/algorithms/test/mod.rs b/tfhe/src/core_crypto/gpu/algorithms/test/mod.rs index 0436ae189f..2829ea1876 100644 --- a/tfhe/src/core_crypto/gpu/algorithms/test/mod.rs +++ b/tfhe/src/core_crypto/gpu/algorithms/test/mod.rs @@ -1,6 +1,5 @@ use crate::core_crypto::algorithms::test::*; use crate::core_crypto::prelude::*; -use paste::paste; mod lwe_keyswitch; mod lwe_linear_algebra; @@ -10,7 +9,7 @@ mod lwe_programmable_bootstrapping; // Macro to generate tests for all parameter sets macro_rules! create_gpu_parametrized_test{ ($name:ident { $($param:ident),* }) => { - paste! { + ::paste::paste! { $( #[test] fn []() { @@ -28,7 +27,7 @@ macro_rules! create_gpu_parametrized_test{ } macro_rules! create_gpu_multi_bit_parametrized_test{ ($name:ident { $($param:ident),* }) => { - paste! { + ::paste::paste! { $( #[test] fn []() { diff --git a/tfhe/src/core_crypto/gpu/mod.rs b/tfhe/src/core_crypto/gpu/mod.rs index 8c2dbb0aa0..7b4463ea7f 100644 --- a/tfhe/src/core_crypto/gpu/mod.rs +++ b/tfhe/src/core_crypto/gpu/mod.rs @@ -2,15 +2,14 @@ pub mod algorithms; pub mod entities; pub mod vec; -pub use algorithms::*; -pub use entities::*; - use crate::core_crypto::gpu::vec::CudaVec; use crate::core_crypto::prelude::{ CiphertextModulus, DecompositionBaseLog, DecompositionLevelCount, GlweCiphertextCount, GlweDimension, LweBskGroupingFactor, LweCiphertextCount, LweCiphertextIndex, LweDimension, PolynomialSize, UnsignedInteger, }; +pub use algorithms::*; +pub use entities::*; use std::ffi::c_void; use tfhe_cuda_backend::cuda_bind::*; diff --git a/tfhe/src/high_level_api/booleans/base.rs b/tfhe/src/high_level_api/booleans/base.rs index 23d2ff9bcb..82f4a86040 100644 --- a/tfhe/src/high_level_api/booleans/base.rs +++ b/tfhe/src/high_level_api/booleans/base.rs @@ -1,6 +1,4 @@ -use std::borrow::Borrow; -use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign}; - +use super::inner::InnerBoolean; use crate::conformance::ParameterSetConformant; use crate::high_level_api::booleans::compressed::CompressedFheBool; use crate::high_level_api::global_state; @@ -15,8 +13,8 @@ use crate::named::Named; use crate::shortint::ciphertext::NotTrivialCiphertextError; use crate::{CompactFheBool, Device}; use serde::{Deserialize, Serialize}; - -use super::inner::InnerBoolean; +use std::borrow::Borrow; +use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign}; /// The FHE boolean data type. /// diff --git a/tfhe/src/high_level_api/integers/signed/ops.rs b/tfhe/src/high_level_api/integers/signed/ops.rs index 23c67348bf..badc4f0c4e 100644 --- a/tfhe/src/high_level_api/integers/signed/ops.rs +++ b/tfhe/src/high_level_api/integers/signed/ops.rs @@ -1,17 +1,16 @@ use crate::high_level_api::global_state; use crate::high_level_api::integers::{FheIntId, FheUintId}; use crate::high_level_api::keys::InternalServerKey; -use crate::{FheBool, FheInt, FheUint}; -use std::ops::{ - Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, - Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, -}; - use crate::high_level_api::traits::{ DivRem, FheEq, FheMax, FheMin, FheOrd, RotateLeft, RotateLeftAssign, RotateRight, RotateRightAssign, }; +use crate::{FheBool, FheInt, FheUint}; use std::borrow::Borrow; +use std::ops::{ + Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, + Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, +}; impl<'a, Id> std::iter::Sum<&'a Self> for FheInt where diff --git a/tfhe/src/high_level_api/integers/signed/static_.rs b/tfhe/src/high_level_api/integers/signed/static_.rs index 925e8ec7bb..20de598bbd 100644 --- a/tfhe/src/high_level_api/integers/signed/static_.rs +++ b/tfhe/src/high_level_api/integers/signed/static_.rs @@ -1,8 +1,7 @@ -use serde::{Deserialize, Serialize}; - use super::{CompactFheInt, CompactFheIntList, CompressedFheInt, FheInt}; use crate::high_level_api::integers::signed::FheIntId; use crate::high_level_api::integers::IntegerId; +use serde::{Deserialize, Serialize}; macro_rules! static_int_type { // Defines a static integer type that uses diff --git a/tfhe/src/high_level_api/integers/unsigned/base.rs b/tfhe/src/high_level_api/integers/unsigned/base.rs index 3ac7d077c8..628fb7fa45 100644 --- a/tfhe/src/high_level_api/integers/unsigned/base.rs +++ b/tfhe/src/high_level_api/integers/unsigned/base.rs @@ -1,12 +1,9 @@ -use crate::conformance::ParameterSetConformant; - use super::inner::RadixCiphertext; +use crate::conformance::ParameterSetConformant; use crate::core_crypto::prelude::{CastFrom, UnsignedNumeric}; - use crate::high_level_api::integers::signed::{FheInt, FheIntId}; use crate::high_level_api::integers::IntegerId; use crate::high_level_api::keys::InternalServerKey; - use crate::high_level_api::{global_state, Device}; use crate::integer::block_decomposition::RecomposableFrom; use crate::integer::parameters::RadixCiphertextConformanceParams; diff --git a/tfhe/src/high_level_api/integers/unsigned/ops.rs b/tfhe/src/high_level_api/integers/unsigned/ops.rs index 7c91a5fffb..d6004c5924 100644 --- a/tfhe/src/high_level_api/integers/unsigned/ops.rs +++ b/tfhe/src/high_level_api/integers/unsigned/ops.rs @@ -1,8 +1,6 @@ // Ask clippy not to worry about this // this is the pattern we use for the macros #![allow(clippy::redundant_closure_call)] -use std::borrow::Borrow; - use super::inner::RadixCiphertext; use crate::high_level_api::global_state; #[cfg(feature = "gpu")] @@ -16,6 +14,7 @@ use crate::high_level_api::traits::{ #[cfg(feature = "gpu")] use crate::integer::gpu::ciphertext::CudaIntegerRadixCiphertext; use crate::{FheBool, FheUint}; +use std::borrow::Borrow; use std::ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, diff --git a/tfhe/src/high_level_api/integers/unsigned/static_.rs b/tfhe/src/high_level_api/integers/unsigned/static_.rs index ef8c03e32f..ceea7e710a 100644 --- a/tfhe/src/high_level_api/integers/unsigned/static_.rs +++ b/tfhe/src/high_level_api/integers/unsigned/static_.rs @@ -1,9 +1,8 @@ -use serde::{Deserialize, Serialize}; - use crate::high_level_api::integers::unsigned::base::{FheUint, FheUintId}; use crate::high_level_api::integers::unsigned::compact::{CompactFheUint, CompactFheUintList}; use crate::high_level_api::integers::unsigned::compressed::CompressedFheUint; use crate::high_level_api::integers::IntegerId; +use serde::{Deserialize, Serialize}; macro_rules! static_int_type { // Defines a static integer type that uses diff --git a/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs b/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs index d4ae5dcb10..eddf7bdd97 100644 --- a/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs +++ b/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs @@ -1,5 +1,3 @@ -use rand::Rng; - use crate::high_level_api::prelude::*; use crate::high_level_api::{generate_keys, set_server_key, ConfigBuilder, FheUint8}; use crate::integer::U256; @@ -9,6 +7,7 @@ use crate::{ CompressedFheUint256, CompressedPublicKey, Config, FheInt16, FheInt32, FheInt8, FheUint128, FheUint16, FheUint256, FheUint32, }; +use rand::Rng; fn setup_cpu(params: Option>) -> ClientKey { let config = params diff --git a/tfhe/src/high_level_api/keys/client.rs b/tfhe/src/high_level_api/keys/client.rs index 49c6415fd8..ae6257768c 100644 --- a/tfhe/src/high_level_api/keys/client.rs +++ b/tfhe/src/high_level_api/keys/client.rs @@ -2,13 +2,11 @@ //! //! - [ClientKey] aggregates the keys used to encrypt/decrypt between normal and homomorphic types. -use concrete_csprng::seeders::Seed; - +use super::{CompressedServerKey, ServerKey}; use crate::high_level_api::config::Config; use crate::high_level_api::keys::IntegerClientKey; use crate::shortint::MessageModulus; - -use super::{CompressedServerKey, ServerKey}; +use concrete_csprng::seeders::Seed; /// Key of the client /// diff --git a/tfhe/src/high_level_api/keys/inner.rs b/tfhe/src/high_level_api/keys/inner.rs index c4cf0bc241..9033f37e9e 100644 --- a/tfhe/src/high_level_api/keys/inner.rs +++ b/tfhe/src/high_level_api/keys/inner.rs @@ -1,12 +1,11 @@ -use concrete_csprng::seeders::Seed; -use serde::{Deserialize, Serialize}; - use crate::core_crypto::commons::generators::DeterministicSeeder; use crate::core_crypto::prelude::ActivatedRandomGenerator; use crate::integer::ciphertext::CompactCiphertextList; use crate::integer::public_key::CompactPublicKey; use crate::integer::CompressedCompactPublicKey; use crate::shortint::{EncryptionKeyChoice, MessageModulus}; +use concrete_csprng::seeders::Seed; +use serde::{Deserialize, Serialize}; #[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize)] pub(crate) struct IntegerConfig { diff --git a/tfhe/src/high_level_api/keys/mod.rs b/tfhe/src/high_level_api/keys/mod.rs index 62f70eb881..8899bd84d2 100644 --- a/tfhe/src/high_level_api/keys/mod.rs +++ b/tfhe/src/high_level_api/keys/mod.rs @@ -1,6 +1,4 @@ -#[macro_use] mod client; -#[macro_use] mod public; mod server; diff --git a/tfhe/src/high_level_api/keys/public.rs b/tfhe/src/high_level_api/keys/public.rs index 20e4d38f19..ef83bd9de6 100644 --- a/tfhe/src/high_level_api/keys/public.rs +++ b/tfhe/src/high_level_api/keys/public.rs @@ -13,12 +13,11 @@ //! transfer sizes. //! - [CompressedPublicKey] //! - [CompressedCompactPublicKey] +use super::ClientKey; use crate::high_level_api::keys::{IntegerCompactPublicKey, IntegerCompressedCompactPublicKey}; use crate::integer::encryption::KnowsMessageModulus; use crate::shortint::MessageModulus; -use super::ClientKey; - /// Classical public key. /// /// Works for any parameters, but uses a lot of memory / disk space diff --git a/tfhe/src/high_level_api/keys/server.rs b/tfhe/src/high_level_api/keys/server.rs index 3246d2521f..6a6be44c2f 100644 --- a/tfhe/src/high_level_api/keys/server.rs +++ b/tfhe/src/high_level_api/keys/server.rs @@ -1,9 +1,7 @@ +use super::ClientKey; use crate::high_level_api::keys::{IntegerCompressedServerKey, IntegerServerKey}; - use std::sync::Arc; -use super::ClientKey; - /// Key of the server /// /// This key contains the different keys needed to be able to do computations for diff --git a/tfhe/src/integer/bigint/static_signed.rs b/tfhe/src/integer/bigint/static_signed.rs index a529df7c8c..60afbeab7d 100644 --- a/tfhe/src/integer/bigint/static_signed.rs +++ b/tfhe/src/integer/bigint/static_signed.rs @@ -1,6 +1,5 @@ -use std::ops::{AddAssign, ShlAssign}; - use crate::core_crypto::prelude::{CastFrom, Numeric, SignedNumeric}; +use std::ops::{AddAssign, ShlAssign}; const fn max_value_for_signed_u64_based_integer() -> [u64; N] { let mut max = [u64::MAX; N]; diff --git a/tfhe/src/integer/bigint/static_unsigned.rs b/tfhe/src/integer/bigint/static_unsigned.rs index cfe83afd30..e377a896b4 100644 --- a/tfhe/src/integer/bigint/static_unsigned.rs +++ b/tfhe/src/integer/bigint/static_unsigned.rs @@ -1,6 +1,5 @@ -use std::ops::ShlAssign; - use crate::core_crypto::prelude::{CastFrom, Numeric, UnsignedNumeric}; +use std::ops::ShlAssign; const fn one_for_unsigned_u64_based_integer() -> [u64; N] { let mut max = [0u64; N]; diff --git a/tfhe/src/integer/block_decomposition.rs b/tfhe/src/integer/block_decomposition.rs index 1d6c98fecf..d3e1a95f6f 100644 --- a/tfhe/src/integer/block_decomposition.rs +++ b/tfhe/src/integer/block_decomposition.rs @@ -1,9 +1,8 @@ -use core::ops::{AddAssign, BitAnd, ShlAssign, ShrAssign}; -use std::ops::{BitOrAssign, Shl, Sub}; - use crate::core_crypto::prelude::{CastFrom, CastInto, Numeric}; use crate::integer::bigint::static_signed::StaticSignedBigInt; use crate::integer::bigint::static_unsigned::StaticUnsignedBigInt; +use core::ops::{AddAssign, BitAnd, ShlAssign, ShrAssign}; +use std::ops::{BitOrAssign, Shl, Sub}; // These work for signed number as rust uses 2-Complements // And Arithmetic shift for signed number (logical for unsigned) diff --git a/tfhe/src/integer/ciphertext/base.rs b/tfhe/src/integer/ciphertext/base.rs new file mode 100644 index 0000000000..7e1acdbcf7 --- /dev/null +++ b/tfhe/src/integer/ciphertext/base.rs @@ -0,0 +1,225 @@ +use super::super::parameters::RadixCiphertextConformanceParams; +use crate::conformance::ParameterSetConformant; +use crate::core_crypto::prelude::UnsignedNumeric; +use crate::integer::block_decomposition::{BlockRecomposer, RecomposableFrom}; +use crate::integer::client_key::{sign_extend_partial_number, RecomposableSignedInteger}; +use crate::shortint::ciphertext::NotTrivialCiphertextError; +use crate::shortint::Ciphertext; +use serde::{Deserialize, Serialize}; + +/// Structure containing a ciphertext in radix decomposition +/// holding an unsigned value. +#[derive(Serialize, Clone, Deserialize, PartialEq, Eq, Debug)] +pub struct BaseRadixCiphertext { + /// The blocks are stored from LSB to MSB + pub(crate) blocks: Vec, +} + +impl From> for BaseRadixCiphertext { + fn from(blocks: Vec) -> Self { + Self { blocks } + } +} + +// Type alias to save some typing in implementation parts +pub type RadixCiphertext = BaseRadixCiphertext; + +impl ParameterSetConformant for RadixCiphertext { + type ParameterSet = RadixCiphertextConformanceParams; + + fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool { + self.blocks.len() == params.num_blocks_per_integer + && self + .blocks + .iter() + .all(|block| block.is_conformant(¶ms.shortint_params)) + } +} + +impl RadixCiphertext { + pub fn block_carries_are_empty(&self) -> bool { + self.blocks.iter().all(Ciphertext::carry_is_empty) + } + + pub fn is_trivial(&self) -> bool { + self.blocks.iter().all(Ciphertext::is_trivial) + } + + /// Decrypts a trivial ciphertext + /// + /// Trivial ciphertexts are ciphertexts which are not encrypted + /// meaning they can be decrypted by any key, or even without a key. + /// + /// For debugging it can be useful to use trivial ciphertext to speed up + /// execution, and use [Self::decrypt_trivial] to decrypt temporary values + /// and debug. + /// + /// + /// # Example + /// + /// ```rust + /// use tfhe::integer::{gen_keys_radix, RadixCiphertext}; + /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; + /// + /// // 8 bits + /// let (cks, sks) = gen_keys_radix(PARAM_MESSAGE_2_CARRY_2_KS_PBS, 4); + /// + /// let msg = 124u8; + /// let msg2 = 17u8; + /// + /// // Trivial encryption + /// let trivial_ct: RadixCiphertext = sks.create_trivial_radix(msg, 4); + /// let non_trivial_ct = cks.encrypt(msg2); + /// + /// let res = trivial_ct.decrypt_trivial(); + /// assert_eq!(Ok(msg), res); + /// + /// let res = non_trivial_ct.decrypt_trivial::(); + /// matches!(res, Err(_)); + /// + /// // Doing operations that mixes trivial and non trivial + /// // will always return a non trivial + /// let ct_res = sks.add_parallelized(&trivial_ct, &non_trivial_ct); + /// let res = ct_res.decrypt_trivial::(); + /// matches!(res, Err(_)); + /// + /// // Doing operations using only trivial ciphertexts + /// // will return a trivial + /// let ct_res = sks.add_parallelized(&trivial_ct, &trivial_ct); + /// let res = ct_res.decrypt_trivial::(); + /// assert_eq!(Ok(msg + msg), res); + /// ``` + pub fn decrypt_trivial(&self) -> Result + where + Clear: UnsignedNumeric + RecomposableFrom, + { + let bits_in_block = self.blocks[0].message_modulus.0.ilog2(); + let mut recomposer = BlockRecomposer::::new(bits_in_block); + + for encrypted_block in &self.blocks { + let decrypted_block = encrypted_block.decrypt_trivial_message_and_carry()?; + recomposer.add_unmasked(decrypted_block); + } + + Ok(recomposer.value()) + } +} + +/// Structure containing a ciphertext in radix decomposition +/// holding a signed value. +#[derive(Serialize, Clone, Deserialize, PartialEq, Eq, Debug)] +pub struct BaseSignedRadixCiphertext { + /// The blocks are stored from LSB to MSB + pub(crate) blocks: Vec, +} + +impl From> for BaseSignedRadixCiphertext { + fn from(blocks: Vec) -> Self { + Self { blocks } + } +} + +// Type alias to save some typing in implementation parts +pub type SignedRadixCiphertext = BaseSignedRadixCiphertext; + +impl ParameterSetConformant for SignedRadixCiphertext { + type ParameterSet = RadixCiphertextConformanceParams; + + fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool { + self.blocks.len() == params.num_blocks_per_integer + && self + .blocks + .iter() + .all(|block| block.is_conformant(¶ms.shortint_params)) + } +} + +impl SignedRadixCiphertext { + pub fn block_carries_are_empty(&self) -> bool { + self.blocks.iter().all(Ciphertext::carry_is_empty) + } + + pub fn is_trivial(&self) -> bool { + self.blocks.iter().all(Ciphertext::is_trivial) + } + + /// Decrypts a trivial ciphertext + /// + /// Trivial ciphertexts are ciphertexts which are not encrypted + /// meaning they can be decrypted by any key, or even without a key. + /// + /// For debugging it can be useful to use trivial ciphertext to speed up + /// execution, and use [Self::decrypt_trivial] to decrypt temporary values + /// and debug. + /// + /// + /// # Example + /// + /// ```rust + /// use tfhe::integer::{gen_keys_radix, RadixCiphertext, SignedRadixCiphertext}; + /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; + /// + /// // 8 bits + /// let (cks, sks) = gen_keys_radix(PARAM_MESSAGE_2_CARRY_2_KS_PBS, 4); + /// + /// let msg = -35i8; + /// let msg2 = 17i8; + /// + /// // Trivial encryption + /// let trivial_ct: SignedRadixCiphertext = sks.create_trivial_radix(msg, 4); + /// let non_trivial_ct = cks.encrypt_signed(msg2); + /// + /// let res = trivial_ct.decrypt_trivial(); + /// assert_eq!(Ok(msg), res); + /// + /// let res = non_trivial_ct.decrypt_trivial::(); + /// matches!(res, Err(_)); + /// + /// // Doing operations that mixes trivial and non trivial + /// // will always return a non trivial + /// let ct_res = sks.add_parallelized(&trivial_ct, &non_trivial_ct); + /// let res = ct_res.decrypt_trivial::(); + /// matches!(res, Err(_)); + /// + /// // Doing operations using only trivial ciphertexts + /// // will return a trivial + /// let ct_res = sks.add_parallelized(&trivial_ct, &trivial_ct); + /// let res = ct_res.decrypt_trivial::(); + /// assert_eq!(Ok(msg + msg), res); + /// ``` + pub fn decrypt_trivial(&self) -> Result + where + Clear: RecomposableSignedInteger, + { + let bits_in_block = self.blocks[0].message_modulus.0.ilog2(); + let mut recomposer = BlockRecomposer::::new(bits_in_block); + + for encrypted_block in &self.blocks { + let decrypted_block = encrypted_block.decrypt_trivial_message_and_carry()?; + recomposer.add_unmasked(decrypted_block); + } + + let num_bits_in_ctxt = bits_in_block * self.blocks.len() as u32; + let unpadded_value = recomposer.value(); + Ok(sign_extend_partial_number(unpadded_value, num_bits_in_ctxt)) + } +} + +/// Structure containing a ciphertext in CRT decomposition. +/// +/// For this CRT decomposition, each block is encrypted using +/// the same parameters. +#[derive(Serialize, Clone, Deserialize)] +pub struct BaseCrtCiphertext { + pub(crate) blocks: Vec, + pub(crate) moduli: Vec, +} + +/// Structure containing a ciphertext in CRT decomposition. +pub type CrtCiphertext = BaseCrtCiphertext; + +impl From<(Vec, Vec)> for BaseCrtCiphertext { + fn from((blocks, moduli): (Vec, Vec)) -> Self { + Self { blocks, moduli } + } +} diff --git a/tfhe/src/integer/ciphertext/compact_list.rs b/tfhe/src/integer/ciphertext/compact_list.rs new file mode 100644 index 0000000000..0a9779c7a3 --- /dev/null +++ b/tfhe/src/integer/ciphertext/compact_list.rs @@ -0,0 +1,96 @@ +use super::super::parameters::RadixCompactCiphertextListConformanceParams; +use super::IntegerRadixCiphertext; +use crate::conformance::ParameterSetConformant; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Serialize, Deserialize)] +pub struct CompactCiphertextList { + pub(crate) ct_list: crate::shortint::ciphertext::CompactCiphertextList, + // Keep track of the num_blocks, as we allow + // storing many integer that have the same num_blocks + // into ct_list + pub(crate) num_blocks_per_integer: usize, +} + +impl ParameterSetConformant for CompactCiphertextList { + type ParameterSet = RadixCompactCiphertextListConformanceParams; + + fn is_conformant(&self, params: &RadixCompactCiphertextListConformanceParams) -> bool { + self.num_blocks_per_integer == params.num_blocks_per_integer + && self + .ct_list + .is_conformant(¶ms.to_shortint_ct_list_conformance_parameters()) + } +} + +impl CompactCiphertextList { + pub fn expand_one(&self) -> T { + let mut blocks = self.ct_list.expand(); + blocks.truncate(self.num_blocks_per_integer); + T::from(blocks) + } + + /// Deconstruct a [`CompactCiphertextList`] into its constituents. + pub fn into_raw_parts(self) -> (crate::shortint::ciphertext::CompactCiphertextList, usize) { + let Self { + ct_list, + num_blocks_per_integer, + } = self; + (ct_list, num_blocks_per_integer) + } + + /// Construct a [`CompactCiphertextList`] from its constituents. + /// + /// # Panics + /// + /// Panics if the constituents are not compatible with each others. + pub fn from_raw_parts( + ct_list: crate::shortint::ciphertext::CompactCiphertextList, + num_blocks_per_integer: usize, + ) -> Self { + assert_eq!( + ct_list.ct_list.lwe_ciphertext_count().0 % num_blocks_per_integer, + 0, + "CompactCiphertextList LweCiphertextCount is expected \ + to be a multiple of {num_blocks_per_integer}, got {:?}", + ct_list.ct_list.lwe_ciphertext_count() + ); + + Self { + ct_list, + num_blocks_per_integer, + } + } + + pub fn ciphertext_count(&self) -> usize { + self.ct_list.ct_list.lwe_ciphertext_count().0 / self.num_blocks_per_integer + } + + pub fn expand(&self) -> Vec { + let mut all_block_iter = self.ct_list.expand().into_iter(); + let num_ct = self.ciphertext_count(); + let mut ciphertexts = Vec::with_capacity(num_ct); + + for _ in 0..num_ct { + let ct_blocks = all_block_iter + .by_ref() + .take(self.num_blocks_per_integer) + .collect::>(); + if ct_blocks.len() < self.num_blocks_per_integer { + break; + } + let ct = T::from(ct_blocks); + ciphertexts.push(ct); + } + + ciphertexts + } + + pub fn size_elements(&self) -> usize { + self.ct_list.size_elements() + } + + pub fn size_bytes(&self) -> usize { + self.ct_list.size_bytes() + } +} diff --git a/tfhe/src/integer/ciphertext/compressed.rs b/tfhe/src/integer/ciphertext/compressed.rs new file mode 100644 index 0000000000..1db848ec5f --- /dev/null +++ b/tfhe/src/integer/ciphertext/compressed.rs @@ -0,0 +1,77 @@ +use super::super::parameters::RadixCiphertextConformanceParams; +use super::{ + BaseCrtCiphertext, BaseRadixCiphertext, BaseSignedRadixCiphertext, CrtCiphertext, + RadixCiphertext, SignedRadixCiphertext, +}; +use crate::conformance::ParameterSetConformant; +use crate::shortint::CompressedCiphertext; + +/// Structure containing a **compressed** ciphertext in radix decomposition. +pub type CompressedRadixCiphertext = BaseRadixCiphertext; + +impl ParameterSetConformant for CompressedRadixCiphertext { + type ParameterSet = RadixCiphertextConformanceParams; + + fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool { + self.blocks.len() == params.num_blocks_per_integer + && self + .blocks + .iter() + .all(|block| block.is_conformant(¶ms.shortint_params)) + } +} + +impl From for RadixCiphertext { + fn from(compressed: CompressedRadixCiphertext) -> Self { + Self::from( + compressed + .blocks + .into_iter() + .map(From::from) + .collect::>(), + ) + } +} + +/// Structure containing a **compressed** ciphertext in radix decomposition +/// holding a signed valued +pub type CompressedSignedRadixCiphertext = BaseSignedRadixCiphertext; + +impl ParameterSetConformant for CompressedSignedRadixCiphertext { + type ParameterSet = RadixCiphertextConformanceParams; + + fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool { + self.blocks.len() == params.num_blocks_per_integer + && self + .blocks + .iter() + .all(|block| block.is_conformant(¶ms.shortint_params)) + } +} + +impl From for SignedRadixCiphertext { + fn from(compressed: CompressedSignedRadixCiphertext) -> Self { + Self::from( + compressed + .blocks + .into_iter() + .map(From::from) + .collect::>(), + ) + } +} + +/// Structure containing a **compressed** ciphertext in CRT decomposition. +pub type CompressedCrtCiphertext = BaseCrtCiphertext; + +impl From for CrtCiphertext { + fn from(compressed: CompressedCrtCiphertext) -> Self { + let blocks = compressed + .blocks + .into_iter() + .map(From::from) + .collect::>(); + let moduli = compressed.moduli; + Self::from((blocks, moduli)) + } +} diff --git a/tfhe/src/integer/ciphertext/integer_ciphertext.rs b/tfhe/src/integer/ciphertext/integer_ciphertext.rs new file mode 100644 index 0000000000..32c1d15461 --- /dev/null +++ b/tfhe/src/integer/ciphertext/integer_ciphertext.rs @@ -0,0 +1,101 @@ +use super::{CrtCiphertext, RadixCiphertext, SignedRadixCiphertext}; +use crate::shortint::Ciphertext; + +pub trait IntegerCiphertext: Clone { + fn blocks(&self) -> &[Ciphertext]; + fn moduli(&self) -> Vec { + self.blocks() + .iter() + .map(|x| x.message_modulus.0 as u64) + .collect() + } + + fn from_blocks(blocks: Vec) -> Self; + + fn blocks_mut(&mut self) -> &mut [Ciphertext]; +} + +pub trait IntegerRadixCiphertext: IntegerCiphertext + Sync + Send + From> { + const IS_SIGNED: bool; + + fn block_carries_are_empty(&self) -> bool { + self.blocks().iter().all(Ciphertext::carry_is_empty) + } + + /// Returns whether the ciphertext _seems_ like it holds/encrypts + /// a boolean (0 or 1) value. + /// + /// Since it uses degree to do so, it will not + /// always return the correct answer. + fn holds_boolean_value(&self) -> bool { + self.blocks()[0].degree.get() <= 1 + && self.blocks()[1..] + .iter() + .all(|block| block.degree.get() == 0) + } + + fn into_blocks(self) -> Vec; +} + +impl IntegerCiphertext for RadixCiphertext { + fn blocks(&self) -> &[Ciphertext] { + &self.blocks + } + + fn from_blocks(blocks: Vec) -> Self { + Self::from(blocks) + } + + fn blocks_mut(&mut self) -> &mut [Ciphertext] { + &mut self.blocks + } +} + +impl IntegerRadixCiphertext for RadixCiphertext { + const IS_SIGNED: bool = false; + + fn into_blocks(self) -> Vec { + self.blocks + } +} + +impl IntegerCiphertext for SignedRadixCiphertext { + fn blocks(&self) -> &[Ciphertext] { + &self.blocks + } + + fn from_blocks(blocks: Vec) -> Self { + Self::from(blocks) + } + + fn blocks_mut(&mut self) -> &mut [Ciphertext] { + &mut self.blocks + } +} + +impl IntegerRadixCiphertext for SignedRadixCiphertext { + const IS_SIGNED: bool = true; + + fn into_blocks(self) -> Vec { + self.blocks + } +} + +impl IntegerCiphertext for CrtCiphertext { + fn blocks(&self) -> &[Ciphertext] { + &self.blocks + } + + fn from_blocks(blocks: Vec) -> Self { + let moduli = blocks.iter().map(|x| x.message_modulus.0 as u64).collect(); + Self { blocks, moduli } + } + + fn blocks_mut(&mut self) -> &mut [Ciphertext] { + &mut self.blocks + } + + fn moduli(&self) -> Vec { + self.moduli.clone() + } +} diff --git a/tfhe/src/integer/ciphertext/mod.rs b/tfhe/src/integer/ciphertext/mod.rs index 45c791e560..39f17db439 100644 --- a/tfhe/src/integer/ciphertext/mod.rs +++ b/tfhe/src/integer/ciphertext/mod.rs @@ -1,490 +1,11 @@ -//! This module implements the ciphertext structures. +mod base; pub mod boolean_value; - -use super::parameters::{ - RadixCiphertextConformanceParams, RadixCompactCiphertextListConformanceParams, -}; -use crate::conformance::ParameterSetConformant; -use crate::core_crypto::prelude::UnsignedNumeric; -use crate::integer::block_decomposition::{BlockRecomposer, RecomposableFrom}; -use crate::integer::client_key::{sign_extend_partial_number, RecomposableSignedInteger}; -use crate::shortint::ciphertext::NotTrivialCiphertextError; -use crate::shortint::{Ciphertext, CompressedCiphertext}; -use serde::{Deserialize, Serialize}; - -/// Structure containing a ciphertext in radix decomposition -/// holding an unsigned value. -#[derive(Serialize, Clone, Deserialize, PartialEq, Eq, Debug)] -pub struct BaseRadixCiphertext { - /// The blocks are stored from LSB to MSB - pub(crate) blocks: Vec, -} - -impl From> for BaseRadixCiphertext { - fn from(blocks: Vec) -> Self { - Self { blocks } - } -} - -// Type alias to save some typing in implementation parts -pub type RadixCiphertext = BaseRadixCiphertext; - -impl ParameterSetConformant for RadixCiphertext { - type ParameterSet = RadixCiphertextConformanceParams; - - fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool { - self.blocks.len() == params.num_blocks_per_integer - && self - .blocks - .iter() - .all(|block| block.is_conformant(¶ms.shortint_params)) - } -} - -/// Structure containing a **compressed** ciphertext in radix decomposition. -pub type CompressedRadixCiphertext = BaseRadixCiphertext; - -impl ParameterSetConformant for CompressedRadixCiphertext { - type ParameterSet = RadixCiphertextConformanceParams; - - fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool { - self.blocks.len() == params.num_blocks_per_integer - && self - .blocks - .iter() - .all(|block| block.is_conformant(¶ms.shortint_params)) - } -} - -impl From for RadixCiphertext { - fn from(compressed: CompressedRadixCiphertext) -> Self { - Self::from( - compressed - .blocks - .into_iter() - .map(From::from) - .collect::>(), - ) - } -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct CompactCiphertextList { - pub(crate) ct_list: crate::shortint::ciphertext::CompactCiphertextList, - // Keep track of the num_blocks, as we allow - // storing many integer that have the same num_blocks - // into ct_list - pub(crate) num_blocks_per_integer: usize, -} - -impl ParameterSetConformant for CompactCiphertextList { - type ParameterSet = RadixCompactCiphertextListConformanceParams; - - fn is_conformant(&self, params: &RadixCompactCiphertextListConformanceParams) -> bool { - self.num_blocks_per_integer == params.num_blocks_per_integer - && self - .ct_list - .is_conformant(¶ms.to_shortint_ct_list_conformance_parameters()) - } -} - -impl CompactCiphertextList { - pub fn expand_one(&self) -> T { - let mut blocks = self.ct_list.expand(); - blocks.truncate(self.num_blocks_per_integer); - T::from(blocks) - } - - /// Deconstruct a [`CompactCiphertextList`] into its constituents. - pub fn into_raw_parts(self) -> (crate::shortint::ciphertext::CompactCiphertextList, usize) { - let Self { - ct_list, - num_blocks_per_integer, - } = self; - (ct_list, num_blocks_per_integer) - } - - /// Construct a [`CompactCiphertextList`] from its constituents. - /// - /// # Panics - /// - /// Panics if the constituents are not compatible with each others. - pub fn from_raw_parts( - ct_list: crate::shortint::ciphertext::CompactCiphertextList, - num_blocks_per_integer: usize, - ) -> Self { - assert_eq!( - ct_list.ct_list.lwe_ciphertext_count().0 % num_blocks_per_integer, - 0, - "CompactCiphertextList LweCiphertextCount is expected \ - to be a multiple of {num_blocks_per_integer}, got {:?}", - ct_list.ct_list.lwe_ciphertext_count() - ); - - Self { - ct_list, - num_blocks_per_integer, - } - } - - pub fn ciphertext_count(&self) -> usize { - self.ct_list.ct_list.lwe_ciphertext_count().0 / self.num_blocks_per_integer - } - - pub fn expand(&self) -> Vec { - let mut all_block_iter = self.ct_list.expand().into_iter(); - let num_ct = self.ciphertext_count(); - let mut ciphertexts = Vec::with_capacity(num_ct); - - for _ in 0..num_ct { - let ct_blocks = all_block_iter - .by_ref() - .take(self.num_blocks_per_integer) - .collect::>(); - if ct_blocks.len() < self.num_blocks_per_integer { - break; - } - let ct = T::from(ct_blocks); - ciphertexts.push(ct); - } - - ciphertexts - } - - pub fn size_elements(&self) -> usize { - self.ct_list.size_elements() - } - - pub fn size_bytes(&self) -> usize { - self.ct_list.size_bytes() - } -} - -impl RadixCiphertext { - pub fn block_carries_are_empty(&self) -> bool { - self.blocks.iter().all(Ciphertext::carry_is_empty) - } - - pub fn is_trivial(&self) -> bool { - self.blocks.iter().all(Ciphertext::is_trivial) - } - - /// Decrypts a trivial ciphertext - /// - /// Trivial ciphertexts are ciphertexts which are not encrypted - /// meaning they can be decrypted by any key, or even without a key. - /// - /// For debugging it can be useful to use trivial ciphertext to speed up - /// execution, and use [Self::decrypt_trivial] to decrypt temporary values - /// and debug. - /// - /// - /// # Example - /// - /// ```rust - /// use tfhe::integer::{gen_keys_radix, RadixCiphertext}; - /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; - /// - /// // 8 bits - /// let (cks, sks) = gen_keys_radix(PARAM_MESSAGE_2_CARRY_2_KS_PBS, 4); - /// - /// let msg = 124u8; - /// let msg2 = 17u8; - /// - /// // Trivial encryption - /// let trivial_ct: RadixCiphertext = sks.create_trivial_radix(msg, 4); - /// let non_trivial_ct = cks.encrypt(msg2); - /// - /// let res = trivial_ct.decrypt_trivial(); - /// assert_eq!(Ok(msg), res); - /// - /// let res = non_trivial_ct.decrypt_trivial::(); - /// matches!(res, Err(_)); - /// - /// // Doing operations that mixes trivial and non trivial - /// // will always return a non trivial - /// let ct_res = sks.add_parallelized(&trivial_ct, &non_trivial_ct); - /// let res = ct_res.decrypt_trivial::(); - /// matches!(res, Err(_)); - /// - /// // Doing operations using only trivial ciphertexts - /// // will return a trivial - /// let ct_res = sks.add_parallelized(&trivial_ct, &trivial_ct); - /// let res = ct_res.decrypt_trivial::(); - /// assert_eq!(Ok(msg + msg), res); - /// ``` - pub fn decrypt_trivial(&self) -> Result - where - Clear: UnsignedNumeric + RecomposableFrom, - { - let bits_in_block = self.blocks[0].message_modulus.0.ilog2(); - let mut recomposer = BlockRecomposer::::new(bits_in_block); - - for encrypted_block in &self.blocks { - let decrypted_block = encrypted_block.decrypt_trivial_message_and_carry()?; - recomposer.add_unmasked(decrypted_block); - } - - Ok(recomposer.value()) - } -} - -/// Structure containing a ciphertext in radix decomposition -/// holding a signed value. -#[derive(Serialize, Clone, Deserialize, PartialEq, Eq, Debug)] -pub struct BaseSignedRadixCiphertext { - /// The blocks are stored from LSB to MSB - pub(crate) blocks: Vec, -} - -impl From> for BaseSignedRadixCiphertext { - fn from(blocks: Vec) -> Self { - Self { blocks } - } -} - -// Type alias to save some typing in implementation parts -pub type SignedRadixCiphertext = BaseSignedRadixCiphertext; - -impl ParameterSetConformant for SignedRadixCiphertext { - type ParameterSet = RadixCiphertextConformanceParams; - - fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool { - self.blocks.len() == params.num_blocks_per_integer - && self - .blocks - .iter() - .all(|block| block.is_conformant(¶ms.shortint_params)) - } -} - -/// Structure containing a **compressed** ciphertext in radix decomposition -/// holding a signed valued -pub type CompressedSignedRadixCiphertext = BaseSignedRadixCiphertext; - -impl ParameterSetConformant for CompressedSignedRadixCiphertext { - type ParameterSet = RadixCiphertextConformanceParams; - - fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool { - self.blocks.len() == params.num_blocks_per_integer - && self - .blocks - .iter() - .all(|block| block.is_conformant(¶ms.shortint_params)) - } -} - -impl SignedRadixCiphertext { - pub fn block_carries_are_empty(&self) -> bool { - self.blocks.iter().all(Ciphertext::carry_is_empty) - } - - pub fn is_trivial(&self) -> bool { - self.blocks.iter().all(Ciphertext::is_trivial) - } - - /// Decrypts a trivial ciphertext - /// - /// Trivial ciphertexts are ciphertexts which are not encrypted - /// meaning they can be decrypted by any key, or even without a key. - /// - /// For debugging it can be useful to use trivial ciphertext to speed up - /// execution, and use [Self::decrypt_trivial] to decrypt temporary values - /// and debug. - /// - /// - /// # Example - /// - /// ```rust - /// use tfhe::integer::{gen_keys_radix, RadixCiphertext, SignedRadixCiphertext}; - /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; - /// - /// // 8 bits - /// let (cks, sks) = gen_keys_radix(PARAM_MESSAGE_2_CARRY_2_KS_PBS, 4); - /// - /// let msg = -35i8; - /// let msg2 = 17i8; - /// - /// // Trivial encryption - /// let trivial_ct: SignedRadixCiphertext = sks.create_trivial_radix(msg, 4); - /// let non_trivial_ct = cks.encrypt_signed(msg2); - /// - /// let res = trivial_ct.decrypt_trivial(); - /// assert_eq!(Ok(msg), res); - /// - /// let res = non_trivial_ct.decrypt_trivial::(); - /// matches!(res, Err(_)); - /// - /// // Doing operations that mixes trivial and non trivial - /// // will always return a non trivial - /// let ct_res = sks.add_parallelized(&trivial_ct, &non_trivial_ct); - /// let res = ct_res.decrypt_trivial::(); - /// matches!(res, Err(_)); - /// - /// // Doing operations using only trivial ciphertexts - /// // will return a trivial - /// let ct_res = sks.add_parallelized(&trivial_ct, &trivial_ct); - /// let res = ct_res.decrypt_trivial::(); - /// assert_eq!(Ok(msg + msg), res); - /// ``` - pub fn decrypt_trivial(&self) -> Result - where - Clear: RecomposableSignedInteger, - { - let bits_in_block = self.blocks[0].message_modulus.0.ilog2(); - let mut recomposer = BlockRecomposer::::new(bits_in_block); - - for encrypted_block in &self.blocks { - let decrypted_block = encrypted_block.decrypt_trivial_message_and_carry()?; - recomposer.add_unmasked(decrypted_block); - } - - let num_bits_in_ctxt = bits_in_block * self.blocks.len() as u32; - let unpadded_value = recomposer.value(); - Ok(sign_extend_partial_number(unpadded_value, num_bits_in_ctxt)) - } -} -impl From for SignedRadixCiphertext { - fn from(compressed: CompressedSignedRadixCiphertext) -> Self { - Self::from( - compressed - .blocks - .into_iter() - .map(From::from) - .collect::>(), - ) - } -} - -pub trait IntegerCiphertext: Clone { - fn blocks(&self) -> &[Ciphertext]; - fn moduli(&self) -> Vec { - self.blocks() - .iter() - .map(|x| x.message_modulus.0 as u64) - .collect() - } - - fn from_blocks(blocks: Vec) -> Self; - - fn blocks_mut(&mut self) -> &mut [Ciphertext]; -} - -pub trait IntegerRadixCiphertext: IntegerCiphertext + Sync + Send + From> { - const IS_SIGNED: bool; - - fn block_carries_are_empty(&self) -> bool { - self.blocks().iter().all(Ciphertext::carry_is_empty) - } - - /// Returns whether the ciphertext _seems_ like it holds/encrypts - /// a boolean (0 or 1) value. - /// - /// Since it uses degree to do so, it will not - /// always return the correct answer. - fn holds_boolean_value(&self) -> bool { - self.blocks()[0].degree.get() <= 1 - && self.blocks()[1..] - .iter() - .all(|block| block.degree.get() == 0) - } - - fn into_blocks(self) -> Vec; -} - -impl IntegerCiphertext for RadixCiphertext { - fn blocks(&self) -> &[Ciphertext] { - &self.blocks - } - - fn from_blocks(blocks: Vec) -> Self { - Self::from(blocks) - } - - fn blocks_mut(&mut self) -> &mut [Ciphertext] { - &mut self.blocks - } -} - -impl IntegerRadixCiphertext for RadixCiphertext { - const IS_SIGNED: bool = false; - - fn into_blocks(self) -> Vec { - self.blocks - } -} - -impl IntegerCiphertext for SignedRadixCiphertext { - fn blocks(&self) -> &[Ciphertext] { - &self.blocks - } - - fn from_blocks(blocks: Vec) -> Self { - Self::from(blocks) - } - - fn blocks_mut(&mut self) -> &mut [Ciphertext] { - &mut self.blocks - } -} - -impl IntegerRadixCiphertext for SignedRadixCiphertext { - const IS_SIGNED: bool = true; - - fn into_blocks(self) -> Vec { - self.blocks - } -} - -impl IntegerCiphertext for CrtCiphertext { - fn blocks(&self) -> &[Ciphertext] { - &self.blocks - } - - fn from_blocks(blocks: Vec) -> Self { - let moduli = blocks.iter().map(|x| x.message_modulus.0 as u64).collect(); - Self { blocks, moduli } - } - - fn blocks_mut(&mut self) -> &mut [Ciphertext] { - &mut self.blocks - } - - fn moduli(&self) -> Vec { - self.moduli.clone() - } -} - -/// Structure containing a ciphertext in CRT decomposition. -/// -/// For this CRT decomposition, each block is encrypted using -/// the same parameters. -#[derive(Serialize, Clone, Deserialize)] -pub struct BaseCrtCiphertext { - pub(crate) blocks: Vec, - pub(crate) moduli: Vec, -} - -/// Structure containing a ciphertext in CRT decomposition. -pub type CrtCiphertext = BaseCrtCiphertext; - -/// Structure containing a **compressed** ciphertext in CRT decomposition. -pub type CompressedCrtCiphertext = BaseCrtCiphertext; - -impl From<(Vec, Vec)> for BaseCrtCiphertext { - fn from((blocks, moduli): (Vec, Vec)) -> Self { - Self { blocks, moduli } - } -} - -impl From for CrtCiphertext { - fn from(compressed: CompressedCrtCiphertext) -> Self { - let blocks = compressed - .blocks - .into_iter() - .map(From::from) - .collect::>(); - let moduli = compressed.moduli; - Self::from((blocks, moduli)) - } -} +mod compact_list; +mod compressed; +mod integer_ciphertext; + +pub use base::*; +pub use boolean_value::*; +pub use compact_list::*; +pub use compressed::*; +pub use integer_ciphertext::*; diff --git a/tfhe/src/integer/client_key/crt.rs b/tfhe/src/integer/client_key/crt.rs index bd7242b028..bdc1673454 100644 --- a/tfhe/src/integer/client_key/crt.rs +++ b/tfhe/src/integer/client_key/crt.rs @@ -1,6 +1,5 @@ use super::ClientKey; use crate::integer::CrtCiphertext; - use serde::{Deserialize, Serialize}; /// Client key "specialized" for CRT decomposition. diff --git a/tfhe/src/integer/client_key/mod.rs b/tfhe/src/integer/client_key/mod.rs index 5a61acce79..ea230f84c5 100644 --- a/tfhe/src/integer/client_key/mod.rs +++ b/tfhe/src/integer/client_key/mod.rs @@ -7,28 +7,26 @@ mod crt; mod radix; pub(crate) mod utils; +use super::block_decomposition::{DecomposableInto, RecomposableFrom}; +use super::ciphertext::{ + CompressedRadixCiphertext, CompressedSignedRadixCiphertext, RadixCiphertext, + SignedRadixCiphertext, +}; use crate::core_crypto::prelude::{CastFrom, SignedNumeric, UnsignedNumeric}; +use crate::integer::bigint::static_signed::StaticSignedBigInt; use crate::integer::block_decomposition::BlockRecomposer; +use crate::integer::ciphertext::boolean_value::BooleanBlock; use crate::integer::ciphertext::{CompressedCrtCiphertext, CrtCiphertext}; use crate::integer::client_key::utils::i_crt; use crate::integer::encryption::{encrypt_crt, encrypt_words_radix_impl}; +use crate::shortint::ciphertext::Degree; use crate::shortint::parameters::MessageModulus; use crate::shortint::{ Ciphertext, ClientKey as ShortintClientKey, ShortintParameterSet as ShortintParameters, }; -use serde::{Deserialize, Serialize}; - -use crate::integer::bigint::static_signed::StaticSignedBigInt; -use crate::integer::ciphertext::boolean_value::BooleanBlock; -use crate::shortint::ciphertext::Degree; pub use crt::CrtClientKey; pub use radix::RadixClientKey; - -use super::block_decomposition::{DecomposableInto, RecomposableFrom}; -use super::ciphertext::{ - CompressedRadixCiphertext, CompressedSignedRadixCiphertext, RadixCiphertext, - SignedRadixCiphertext, -}; +use serde::{Deserialize, Serialize}; pub trait RecomposableSignedInteger: RecomposableFrom @@ -197,7 +195,6 @@ impl ClientKey { /// // 2 * 4 = 8 bits of message /// let ct = cks.encrypt_radix(msg, num_block); /// - /// // Decryption /// let dec = cks.decrypt_radix(&ct); /// assert_eq!(msg, dec); /// ``` @@ -224,7 +221,6 @@ impl ClientKey { /// // 2 * 4 = 8 bits of message /// let ct = cks.encrypt_radix_without_padding(msg, num_block); /// - /// // Decryption /// let dec = cks.decrypt_radix_without_padding(&ct); /// assert_eq!(msg, dec); /// ``` @@ -297,10 +293,8 @@ impl ClientKey { /// /// let msg = 191_u64; /// - /// // Encryption /// let ct = cks.encrypt_radix(msg, num_block); /// - /// // Decryption /// let dec = cks.decrypt_radix(&ct); /// assert_eq!(msg, dec); /// ``` @@ -327,10 +321,8 @@ impl ClientKey { /// /// let msg = 191_u64; /// - /// // Encryption /// let ct = cks.encrypt_radix_without_padding(msg, num_block); /// - /// // Decryption /// let dec = cks.decrypt_radix_without_padding(&ct); /// assert_eq!(msg, dec); /// ``` @@ -476,10 +468,8 @@ impl ClientKey { /// /// let msg = 2_u64; /// - /// // Encryption /// let ct = cks.encrypt_one_block(msg); /// - /// // Decryption /// let dec = cks.decrypt_one_block(&ct); /// assert_eq!(msg, dec); /// ``` diff --git a/tfhe/src/integer/client_key/radix.rs b/tfhe/src/integer/client_key/radix.rs index 8ddba30132..3cd540f5a4 100644 --- a/tfhe/src/integer/client_key/radix.rs +++ b/tfhe/src/integer/client_key/radix.rs @@ -27,7 +27,6 @@ use serde::{Deserialize, Serialize}; /// /// let ct = cks.encrypt(msg); /// -/// // Decryption /// let dec = cks.decrypt(&ct); /// assert_eq!(msg, dec); /// ``` diff --git a/tfhe/src/integer/encryption.rs b/tfhe/src/integer/encryption.rs index ed314335dd..aee3b9df76 100644 --- a/tfhe/src/integer/encryption.rs +++ b/tfhe/src/integer/encryption.rs @@ -97,7 +97,6 @@ where // Put each decomposition into a new ciphertext for modulus in base_vec.iter().copied() { - // encryption let ct = encrypt_block(encrypting_key, message, MessageModulus(modulus as usize)); ctxt_vect.push(ct); diff --git a/tfhe/src/integer/gpu/server_key/radix/tests_unsigned/mod.rs b/tfhe/src/integer/gpu/server_key/radix/tests_unsigned/mod.rs index df640d9392..228b53f7d8 100644 --- a/tfhe/src/integer/gpu/server_key/radix/tests_unsigned/mod.rs +++ b/tfhe/src/integer/gpu/server_key/radix/tests_unsigned/mod.rs @@ -341,7 +341,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -392,7 +391,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -442,7 +440,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -483,7 +480,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -524,7 +520,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -564,7 +559,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -605,7 +599,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -651,7 +644,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -697,7 +689,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -755,7 +746,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -814,7 +804,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -873,7 +862,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -932,7 +920,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -973,7 +960,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1014,7 +1000,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1094,7 +1079,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1172,7 +1156,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1223,7 +1206,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1274,7 +1256,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1325,7 +1306,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1366,7 +1346,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1407,7 +1386,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1447,7 +1425,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1488,7 +1465,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1534,7 +1510,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1580,7 +1555,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1619,7 +1593,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1658,7 +1631,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1697,7 +1669,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1784,7 +1755,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1827,7 +1797,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1868,7 +1837,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1909,7 +1877,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1948,7 +1915,6 @@ where let (cks, sks) = gen_keys_gpu(param, &stream); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length diff --git a/tfhe/src/integer/key_switching_key/mod.rs b/tfhe/src/integer/key_switching_key/mod.rs index ec637cc929..2886129a74 100644 --- a/tfhe/src/integer/key_switching_key/mod.rs +++ b/tfhe/src/integer/key_switching_key/mod.rs @@ -1,8 +1,6 @@ use super::{ClientKey, ServerKey}; - use crate::integer::IntegerCiphertext; use crate::shortint::parameters::ShortintKeySwitchingParameters; - use rayon::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/tfhe/src/integer/key_switching_key/test.rs b/tfhe/src/integer/key_switching_key/test.rs index 36eddca375..464d464f27 100644 --- a/tfhe/src/integer/key_switching_key/test.rs +++ b/tfhe/src/integer/key_switching_key/test.rs @@ -1,9 +1,8 @@ -use crate::shortint::parameters::ShortintKeySwitchingParameters; -use crate::shortint::prelude::{PARAM_MESSAGE_1_CARRY_1_KS_PBS, PARAM_MESSAGE_2_CARRY_2_KS_PBS}; - use crate::integer::key_switching_key::KeySwitchingKey; use crate::integer::keycache::KEY_CACHE; use crate::integer::{CrtClientKey, IntegerKeyKind, RadixClientKey}; +use crate::shortint::parameters::ShortintKeySwitchingParameters; +use crate::shortint::prelude::{PARAM_MESSAGE_1_CARRY_1_KS_PBS, PARAM_MESSAGE_2_CARRY_2_KS_PBS}; #[test] fn gen_multi_keys_test_rdxinteger_to_rdxinteger_ci_run_filter() { diff --git a/tfhe/src/integer/keycache.rs b/tfhe/src/integer/keycache.rs index 2c275781f4..f8bda442f0 100644 --- a/tfhe/src/integer/keycache.rs +++ b/tfhe/src/integer/keycache.rs @@ -1,8 +1,7 @@ -use crate::shortint::{PBSParameters, WopbsParameters}; -use lazy_static::lazy_static; - use crate::integer::wopbs::WopbsKey; use crate::integer::{ClientKey, IntegerKeyKind, ServerKey}; +use crate::shortint::{PBSParameters, WopbsParameters}; +use lazy_static::lazy_static; #[derive(Default)] pub struct IntegerKeyCache; diff --git a/tfhe/src/integer/mod.rs b/tfhe/src/integer/mod.rs index cd552a89c2..30d0c832a7 100755 --- a/tfhe/src/integer/mod.rs +++ b/tfhe/src/integer/mod.rs @@ -46,11 +46,10 @@ //! Currently, the radix approach is only compatible with parameter sets such //! that the message and carry buffers have the same size. -#[cfg(test)] -#[macro_use] -mod tests; pub mod block_decomposition; pub(crate) mod encryption; +#[cfg(test)] +mod tests; pub mod bigint; pub mod ciphertext; diff --git a/tfhe/src/integer/parameters/mod.rs b/tfhe/src/integer/parameters/mod.rs index f70e6a317d..00d0e06153 100644 --- a/tfhe/src/integer/parameters/mod.rs +++ b/tfhe/src/integer/parameters/mod.rs @@ -1,8 +1,5 @@ #![allow(clippy::excessive_precision)] use crate::conformance::ListSizeConstraint; -use crate::shortint::PBSParameters; -pub use crate::shortint::{CiphertextModulus, ClassicPBSParameters, WopbsParameters}; - use crate::shortint::parameters::{ CarryModulus, CiphertextConformanceParams, CiphertextListConformanceParams, EncryptionKeyChoice, MessageModulus, @@ -11,6 +8,8 @@ pub use crate::shortint::parameters::{ DecompositionBaseLog, DecompositionLevelCount, DynamicDistribution, GlweDimension, LweDimension, PolynomialSize, StandardDev, }; +use crate::shortint::PBSParameters; +pub use crate::shortint::{CiphertextModulus, ClassicPBSParameters, WopbsParameters}; pub const ALL_PARAMETER_VEC_INTEGER_16_BITS: [WopbsParameters; 2] = [ PARAM_MESSAGE_4_CARRY_4_KS_PBS_16_BITS, diff --git a/tfhe/src/integer/public_key/compact.rs b/tfhe/src/integer/public_key/compact.rs index 62a1b98115..5472c68e0d 100644 --- a/tfhe/src/integer/public_key/compact.rs +++ b/tfhe/src/integer/public_key/compact.rs @@ -1,6 +1,4 @@ use crate::core_crypto::prelude::{SignedNumeric, UnsignedNumeric}; -use serde::{Deserialize, Serialize}; - use crate::integer::block_decomposition::DecomposableInto; use crate::integer::ciphertext::{CompactCiphertextList, RadixCiphertext}; use crate::integer::encryption::{create_clear_radix_block_iterator, encrypt_words_radix_impl}; @@ -9,6 +7,7 @@ use crate::shortint::{ CompactPublicKey as ShortintCompactPublicKey, CompressedCompactPublicKey as ShortintCompressedCompactPublicKey, }; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct CompactPublicKey { diff --git a/tfhe/src/integer/public_key/standard.rs b/tfhe/src/integer/public_key/standard.rs index 56ef89cef6..3ef1f02dae 100644 --- a/tfhe/src/integer/public_key/standard.rs +++ b/tfhe/src/integer/public_key/standard.rs @@ -110,6 +110,7 @@ impl From for PublicKey { #[cfg(test)] mod tests { use crate::integer::keycache::KEY_CACHE; + use crate::integer::tests::create_parametrized_test; use crate::integer::IntegerKeyKind; use crate::shortint::parameters::*; diff --git a/tfhe/src/integer/public_key/tests.rs b/tfhe/src/integer/public_key/tests.rs index e8515c67ee..34d6a0285a 100644 --- a/tfhe/src/integer/public_key/tests.rs +++ b/tfhe/src/integer/public_key/tests.rs @@ -1,11 +1,10 @@ -use rand::Rng; - +use crate::integer::keycache::KEY_CACHE; +use crate::integer::tests::create_parametrized_test; use crate::integer::{gen_keys, CompressedPublicKey, IntegerKeyKind, PublicKey}; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; use crate::shortint::parameters::*; - -use crate::integer::keycache::KEY_CACHE; +use rand::Rng; create_parametrized_test!(big_radix_encrypt_decrypt_128_bits { @@ -63,19 +62,15 @@ fn big_radix_encrypt_decrypt_128_bits(param: ClassicPBSParameters) { let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); let public_key = PublicKey::new(&cks); - // RNG let mut rng = rand::thread_rng(); let num_block = (128f64 / (param.message_modulus.0 as f64).log(2.0)).ceil() as usize; let clear = rng.gen::(); - //encryption let ct = public_key.encrypt_radix(clear, num_block); - // decryption let dec: u128 = cks.decrypt_radix(&ct); - // assert assert_eq!(clear, dec); } @@ -83,19 +78,15 @@ fn radix_encrypt_decrypt_compressed_128_bits(param: ClassicPBSParameters) { let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); let public_key = CompressedPublicKey::new(&cks); - // RNG let mut rng = rand::thread_rng(); let num_block = (128f64 / (param.message_modulus.0 as f64).log(2.0)).ceil() as usize; let clear = rng.gen::(); - //encryption let ct = public_key.encrypt_radix(clear, num_block); - // decryption let dec: u128 = cks.decrypt_radix(&ct); - // assert assert_eq!(clear, dec); } diff --git a/tfhe/src/integer/server_key/comparator.rs b/tfhe/src/integer/server_key/comparator.rs index 5798165539..2c617f8a5a 100644 --- a/tfhe/src/integer/server_key/comparator.rs +++ b/tfhe/src/integer/server_key/comparator.rs @@ -1,5 +1,3 @@ -use rayon::prelude::*; - use super::ServerKey; use crate::core_crypto::prelude::Plaintext; use crate::integer::block_decomposition::{BlockDecomposer, DecomposableInto}; @@ -7,6 +5,7 @@ use crate::integer::ciphertext::boolean_value::BooleanBlock; use crate::integer::ciphertext::IntegerRadixCiphertext; use crate::shortint::server_key::LookupTableOwned; use crate::shortint::Ciphertext; +use rayon::prelude::*; /// Used for compare_blocks_with_zero #[derive(Clone, Copy)] diff --git a/tfhe/src/integer/server_key/crt/scalar_add_crt.rs b/tfhe/src/integer/server_key/crt/scalar_add_crt.rs index c368c7a7e0..2994c0844c 100644 --- a/tfhe/src/integer/server_key/crt/scalar_add_crt.rs +++ b/tfhe/src/integer/server_key/crt/scalar_add_crt.rs @@ -1,5 +1,4 @@ use crate::integer::server_key::CheckError; - use crate::integer::{CrtCiphertext, ServerKey}; impl ServerKey { diff --git a/tfhe/src/integer/server_key/crt/tests.rs b/tfhe/src/integer/server_key/crt/tests.rs index 21aa0c49df..4206e6857f 100644 --- a/tfhe/src/integer/server_key/crt/tests.rs +++ b/tfhe/src/integer/server_key/crt/tests.rs @@ -1,4 +1,5 @@ use crate::integer::keycache::KEY_CACHE; +use crate::integer::tests::create_parametrized_test; use crate::integer::IntegerKeyKind; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; @@ -60,16 +61,13 @@ fn integer_unchecked_crt_add_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_one = cks.encrypt_crt(clear_1 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_add(&ct_zero, &ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((clear_0 + clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -91,16 +89,13 @@ fn integer_unchecked_crt_mul_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_one = cks.encrypt_crt(clear_1 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_mul(&ct_zero, &ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((clear_0 * clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -121,15 +116,12 @@ fn integer_unchecked_crt_neg_32_bits() { for _ in 0..NB_TESTS { let clear_0 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_neg(&ct_zero); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!((modulus - clear_0) as u64, dec_res % modulus as u64); } } @@ -148,16 +140,13 @@ fn integer_unchecked_crt_sub_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_one = cks.encrypt_crt(clear_1 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_sub(&ct_zero, &ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((modulus + clear_0 - clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -179,15 +168,12 @@ fn integer_unchecked_crt_scalar_add_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_scalar_add(&ct_zero, clear_1 as u64); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((clear_0 + clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -209,15 +195,12 @@ fn integer_unchecked_crt_scalar_mul_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_scalar_mul(&ct_zero, clear_1 as u64); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((clear_0 * clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -239,15 +222,12 @@ fn integer_unchecked_crt_scalar_sub_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_scalar_sub(&ct_zero, clear_1 as u64); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((modulus + clear_0 - clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -259,7 +239,6 @@ fn integer_unchecked_crt_mul(param: ClassicPBSParameters) { // generate the server-client key set let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT); - //RNG let mut rng = rand::thread_rng(); // Define CRT basis, and global modulus @@ -270,17 +249,14 @@ fn integer_unchecked_crt_mul(param: ClassicPBSParameters) { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ct_zero = cks.encrypt_crt(clear_0, basis.clone()); let ct_one = cks.encrypt_crt(clear_1, basis.clone()); // add the two ciphertexts sks.unchecked_crt_mul_assign(&mut ct_zero, &ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_zero); - // assert assert_eq!((clear_0 * clear_1) % modulus, dec_res % modulus); } } @@ -292,13 +268,11 @@ fn integer_smart_crt_add(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT); - //RNG let mut rng = rand::thread_rng(); let mut clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ct_zero = cks.encrypt_crt(clear_0, basis.clone()); let mut ct_one = cks.encrypt_crt(clear_1, basis); @@ -306,10 +280,8 @@ fn integer_smart_crt_add(param: ClassicPBSParameters) { // add the two ciphertexts sks.smart_crt_add_assign(&mut ct_zero, &mut ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_zero); - // assert clear_0 += clear_1; assert_eq!(clear_0 % modulus, dec_res % modulus); } @@ -325,13 +297,11 @@ fn integer_smart_crt_mul(param: ClassicPBSParameters) { println!("BASIS = {basis:?}"); - //RNG let mut rng = rand::thread_rng(); let mut clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ct_zero = cks.encrypt_crt(clear_0, basis.clone()); let mut ct_one = cks.encrypt_crt(clear_1, basis); @@ -339,7 +309,6 @@ fn integer_smart_crt_mul(param: ClassicPBSParameters) { // mul the two ciphertexts sks.smart_crt_mul_assign(&mut ct_zero, &mut ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_zero); clear_0 = (clear_0 * clear_1) % modulus; @@ -354,25 +323,21 @@ fn integer_smart_crt_neg(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT); - //RNG let mut rng = rand::thread_rng(); let mut clear_0 = rng.gen::() % modulus; - // encryption of an integer let mut ct_zero = cks.encrypt_crt(clear_0, basis); for _ in 0..NB_TESTS { // add the two ciphertexts sks.smart_crt_neg_assign(&mut ct_zero); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_zero); clear_0 = (modulus - clear_0) % modulus; // println!("clear = {}", clear_0); - // assert assert_eq!(clear_0, dec_res); } } @@ -384,23 +349,19 @@ fn integer_smart_crt_scalar_add(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT); - //RNG let mut rng = rand::thread_rng(); for _ in 0..NB_TESTS { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ct_zero = cks.encrypt_crt(clear_0, basis.clone()); // add the two ciphertexts sks.smart_crt_scalar_add_assign(&mut ct_zero, clear_1); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_zero); - // assert assert_eq!((clear_0 + clear_1) % modulus, dec_res % modulus); } } @@ -412,23 +373,19 @@ fn integer_smart_crt_scalar_mul(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT); - //RNG let mut rng = rand::thread_rng(); for _ in 0..NB_TESTS { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ct_zero = cks.encrypt_crt(clear_0, basis.clone()); // add the two ciphertexts sks.smart_crt_scalar_mul_assign(&mut ct_zero, clear_1); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_zero); - // assert assert_eq!((clear_0 * clear_1) % modulus, dec_res % modulus); } } @@ -440,25 +397,21 @@ fn integer_smart_crt_scalar_sub(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT); - //RNG let mut rng = rand::thread_rng(); let mut clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ct_zero = cks.encrypt_crt(clear_0, basis); for _ in 0..NB_TESTS { // add the two ciphertexts sks.smart_crt_scalar_sub_assign(&mut ct_zero, clear_1); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_zero); // println!("clear_0 = {}, clear_1 = {}, modulus = {}", clear_0, clear_1, modulus); - // assert clear_0 = (clear_0 + modulus - clear_1) % modulus; assert_eq!(clear_0, dec_res % modulus); } @@ -471,13 +424,11 @@ fn integer_smart_crt_sub(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT); - //RNG let mut rng = rand::thread_rng(); let mut clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ct_zero = cks.encrypt_crt(clear_0, basis.clone()); let mut ct_one = cks.encrypt_crt(clear_1, basis); @@ -485,12 +436,10 @@ fn integer_smart_crt_sub(param: ClassicPBSParameters) { // sub the two ciphertexts sks.smart_crt_sub_assign(&mut ct_zero, &mut ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_zero); // println!("clear_0 = {}, clear_1 = {}, modulus = {}", clear_0, clear_1, modulus); - // assert clear_0 = (clear_0 + modulus - clear_1) % modulus; assert_eq!(clear_0, dec_res); } diff --git a/tfhe/src/integer/server_key/crt_parallel/tests.rs b/tfhe/src/integer/server_key/crt_parallel/tests.rs index 080d022ac2..e6e5f65c96 100644 --- a/tfhe/src/integer/server_key/crt_parallel/tests.rs +++ b/tfhe/src/integer/server_key/crt_parallel/tests.rs @@ -32,16 +32,13 @@ fn integer_unchecked_crt_add_parallelized_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_one = cks.encrypt_crt(clear_1 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_add_parallelized(&ct_zero, &ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((clear_0 + clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -63,17 +60,14 @@ fn integer_unchecked_crt_mul_parallelized_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_one = cks.encrypt_crt(clear_1 as u64, basis.to_vec()); // multiply the two ciphertexts let ct_res = sks.unchecked_crt_mul_parallelized(&ct_zero, &ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((clear_0 * clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -94,15 +88,12 @@ fn integer_unchecked_crt_neg_parallelized_32_bits() { for _ in 0..NB_TESTS { let clear_0 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_neg_parallelized(&ct_zero); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!((modulus - clear_0) as u64, dec_res % modulus as u64); } } @@ -121,16 +112,13 @@ fn integer_unchecked_crt_sub_parallelized_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_one = cks.encrypt_crt(clear_1 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_sub_parallelized(&ct_zero, &ct_one); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((modulus + clear_0 - clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -152,15 +140,12 @@ fn integer_unchecked_crt_scalar_add_parallelized_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_scalar_add_parallelized(&ct_zero, clear_1 as u64); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((clear_0 + clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -182,15 +167,12 @@ fn integer_unchecked_crt_scalar_mul_parallelized_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_scalar_mul_parallelized(&ct_zero, clear_1 as u64); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((clear_0 * clear_1) % modulus) as u64, dec_res % modulus as u64 @@ -212,15 +194,12 @@ fn integer_unchecked_crt_scalar_sub_parallelized_32_bits() { let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ct_zero = cks.encrypt_crt(clear_0 as u64, basis.to_vec()); let ct_res = sks.unchecked_crt_scalar_sub_parallelized(&ct_zero, clear_1 as u64); - // decryption of ct_res let dec_res = cks.decrypt_crt(&ct_res); - // assert assert_eq!( ((modulus + clear_0 - clear_1) % modulus) as u64, dec_res % modulus as u64 diff --git a/tfhe/src/integer/server_key/radix/bitwise_op.rs b/tfhe/src/integer/server_key/radix/bitwise_op.rs index 145ddd131a..8506827d2e 100644 --- a/tfhe/src/integer/server_key/radix/bitwise_op.rs +++ b/tfhe/src/integer/server_key/radix/bitwise_op.rs @@ -748,6 +748,7 @@ impl ServerKey { #[cfg(test)] mod tests { use crate::integer::keycache::KEY_CACHE; + use crate::integer::tests::create_parametrized_test; use crate::integer::{BooleanBlock, IntegerKeyKind}; use crate::shortint::ciphertext::Degree; #[cfg(tarpaulin)] diff --git a/tfhe/src/integer/server_key/radix/comparison.rs b/tfhe/src/integer/server_key/radix/comparison.rs index da6e034625..bf570567d1 100644 --- a/tfhe/src/integer/server_key/radix/comparison.rs +++ b/tfhe/src/integer/server_key/radix/comparison.rs @@ -1,6 +1,5 @@ use super::ServerKey; use crate::integer::ciphertext::boolean_value::BooleanBlock; - use crate::integer::ciphertext::IntegerRadixCiphertext; use crate::integer::server_key::comparator::Comparator; diff --git a/tfhe/src/integer/server_key/radix/mod.rs b/tfhe/src/integer/server_key/radix/mod.rs index d431ede3cf..12743132db 100644 --- a/tfhe/src/integer/server_key/radix/mod.rs +++ b/tfhe/src/integer/server_key/radix/mod.rs @@ -10,7 +10,6 @@ mod shift; mod sub; use super::ServerKey; - use crate::integer::block_decomposition::DecomposableInto; use crate::integer::ciphertext::{IntegerCiphertext, IntegerRadixCiphertext, RadixCiphertext}; use crate::integer::encryption::encrypt_words_radix_impl; diff --git a/tfhe/src/integer/server_key/radix/shift.rs b/tfhe/src/integer/server_key/radix/shift.rs index 439d1b21e6..0921ecf811 100644 --- a/tfhe/src/integer/server_key/radix/shift.rs +++ b/tfhe/src/integer/server_key/radix/shift.rs @@ -1,9 +1,8 @@ -use std::ops::Rem; - use crate::core_crypto::commons::utils::izip; use crate::core_crypto::prelude::CastFrom; use crate::integer::ciphertext::RadixCiphertext; use crate::integer::ServerKey; +use std::ops::Rem; impl ServerKey { /// Shifts the blocks to the right. diff --git a/tfhe/src/integer/server_key/radix/tests.rs b/tfhe/src/integer/server_key/radix/tests.rs index 57a3f2a1d7..9f6e68a558 100644 --- a/tfhe/src/integer/server_key/radix/tests.rs +++ b/tfhe/src/integer/server_key/radix/tests.rs @@ -6,6 +6,7 @@ use crate::integer::server_key::radix_parallel::tests_unsigned::test_sub::{ default_overflowing_sub_test, smart_sub_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::{IntegerKeyKind, RadixCiphertext, ServerKey, SignedRadixCiphertext, U256}; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; @@ -166,10 +167,8 @@ fn integer_encrypt_decrypt_128_bits_specific_values(param: ClassicPBSParameters) let mut ct2 = cks.encrypt_radix(clear_1, num_block); let ct = sks.smart_add(&mut ct, &mut ct2); - // decryption let dec: u128 = cks.decrypt_radix(&ct); - // assert assert_eq!(clear_0.wrapping_add(clear_1), dec); } @@ -181,10 +180,8 @@ fn integer_encrypt_decrypt_128_bits_specific_values(param: ClassicPBSParameters) let mut ct2 = cks.encrypt_radix(clear_1, num_block); let ct = sks.smart_add(&mut ct, &mut ct2); - // decryption let dec: u128 = cks.decrypt_radix(&ct); - // assert assert_eq!(clear_0.wrapping_add(clear_1), dec); } } @@ -216,7 +213,6 @@ fn integer_encrypt_decrypt_256_bits_specific_values(param: ClassicPBSParameters) fn integer_encrypt_decrypt_256_bits(param: ClassicPBSParameters) { let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - // RNG let mut rng = rand::thread_rng(); let num_block = (256f64 / (param.message_modulus.0 as f64).log(2.0)).ceil() as usize; @@ -226,13 +222,10 @@ fn integer_encrypt_decrypt_256_bits(param: ClassicPBSParameters) { let clear = crate::integer::U256::from((clear0, clear1)); - //encryption let ct = cks.encrypt_radix(clear, num_block); - // decryption let dec: U256 = cks.decrypt_radix(&ct); - // assert assert_eq!(clear, dec); } } @@ -250,10 +243,8 @@ fn integer_smart_add_128_bits(param: ClassicPBSParameters) { println!("{clear_0} {clear_1}"); - // encryption of an integer let mut ctxt_0 = cks.encrypt_radix(clear_0, num_block); - // encryption of an integer let mut ctxt_1 = cks.encrypt_radix(clear_1, num_block); // add the two ciphertexts @@ -267,7 +258,6 @@ fn integer_smart_add_128_bits(param: ClassicPBSParameters) { ct_res = sks.smart_add(&mut ct_res, &mut ctxt_0); clear_result += clear_0; - // decryption of ct_res let dec_res: u128 = cks.decrypt_radix(&ct_res); // println!("clear = {}, dec_res = {}", clear, dec_res); assert_eq!(clear_result, dec_res); @@ -288,7 +278,6 @@ fn integer_smart_add(param: ClassicPBSParameters) { fn integer_unchecked_bitand(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -299,19 +288,15 @@ fn integer_unchecked_bitand(param: ClassicPBSParameters) { let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ctxt_0 = cks.encrypt_radix(clear_0, NB_CTXT); - // encryption of an integer let ctxt_1 = cks.encrypt_radix(clear_1, NB_CTXT); // add the two ciphertexts let ct_res = sks.unchecked_bitand(&ctxt_0, &ctxt_1); - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!(clear_0 & clear_1, dec_res); } } @@ -319,7 +304,6 @@ fn integer_unchecked_bitand(param: ClassicPBSParameters) { fn integer_unchecked_bitor(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -330,19 +314,15 @@ fn integer_unchecked_bitor(param: ClassicPBSParameters) { let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ctxt_0 = cks.encrypt_radix(clear_0, NB_CTXT); - // encryption of an integer let ctxt_1 = cks.encrypt_radix(clear_1, NB_CTXT); // add the two ciphertexts let ct_res = sks.unchecked_bitor(&ctxt_0, &ctxt_1); - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!(clear_0 | clear_1, dec_res); } } @@ -350,7 +330,6 @@ fn integer_unchecked_bitor(param: ClassicPBSParameters) { fn integer_unchecked_bitxor(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -361,19 +340,15 @@ fn integer_unchecked_bitxor(param: ClassicPBSParameters) { let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ctxt_0 = cks.encrypt_radix(clear_0, NB_CTXT); - // encryption of an integer let ctxt_1 = cks.encrypt_radix(clear_1, NB_CTXT); // add the two ciphertexts let ct_res = sks.unchecked_bitxor(&ctxt_0, &ctxt_1); - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!(clear_0 ^ clear_1, dec_res); } } @@ -381,7 +356,6 @@ fn integer_unchecked_bitxor(param: ClassicPBSParameters) { fn integer_smart_bitand(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -394,10 +368,8 @@ fn integer_smart_bitand(param: ClassicPBSParameters) { let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ctxt_0 = cks.encrypt_radix(clear_0, NB_CTXT); - // encryption of an integer let mut ctxt_1 = cks.encrypt_radix(clear_1, NB_CTXT); // add the two ciphertexts @@ -408,16 +380,13 @@ fn integer_smart_bitand(param: ClassicPBSParameters) { for _ in 0..NB_TESTS_SMALLER { let clear_2 = rng.gen::() % modulus; - // encryption of an integer let mut ctxt_2 = cks.encrypt_radix(clear_2, NB_CTXT); ct_res = sks.smart_bitand(&mut ct_res, &mut ctxt_2); clear &= clear_2; - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!(clear, dec_res); } } @@ -426,7 +395,6 @@ fn integer_smart_bitand(param: ClassicPBSParameters) { fn integer_smart_bitor(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -439,10 +407,8 @@ fn integer_smart_bitor(param: ClassicPBSParameters) { let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ctxt_0 = cks.encrypt_radix(clear_0, NB_CTXT); - // encryption of an integer let mut ctxt_1 = cks.encrypt_radix(clear_1, NB_CTXT); // add the two ciphertexts @@ -453,16 +419,13 @@ fn integer_smart_bitor(param: ClassicPBSParameters) { for _ in 0..1 { let clear_2 = rng.gen::() % modulus; - // encryption of an integer let mut ctxt_2 = cks.encrypt_radix(clear_2, NB_CTXT); ct_res = sks.smart_bitor(&mut ct_res, &mut ctxt_2); clear = (clear | clear_2) % modulus; - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!(clear, dec_res); } } @@ -471,7 +434,6 @@ fn integer_smart_bitor(param: ClassicPBSParameters) { fn integer_smart_bitxor(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -484,10 +446,8 @@ fn integer_smart_bitxor(param: ClassicPBSParameters) { let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ctxt_0 = cks.encrypt_radix(clear_0, NB_CTXT); - // encryption of an integer let mut ctxt_1 = cks.encrypt_radix(clear_1, NB_CTXT); // add the two ciphertexts @@ -498,16 +458,13 @@ fn integer_smart_bitxor(param: ClassicPBSParameters) { for _ in 0..NB_TESTS_SMALLER { let clear_2 = rng.gen::() % modulus; - // encryption of an integer let mut ctxt_2 = cks.encrypt_radix(clear_2, NB_CTXT); ct_res = sks.smart_bitxor(&mut ct_res, &mut ctxt_2); clear = (clear ^ clear_2) % modulus; - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!(clear, dec_res); } } @@ -516,7 +473,6 @@ fn integer_smart_bitxor(param: ClassicPBSParameters) { fn integer_unchecked_small_scalar_mul(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -529,16 +485,13 @@ fn integer_unchecked_small_scalar_mul(param: ClassicPBSParameters) { let scalar = rng.gen::() % scalar_modulus; - // encryption of an integer let ct = cks.encrypt_radix(clear, NB_CTXT); // add the two ciphertexts let ct_res = sks.unchecked_small_scalar_mul(&ct, scalar); - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!((clear * scalar) % modulus, dec_res); } } @@ -546,7 +499,6 @@ fn integer_unchecked_small_scalar_mul(param: ClassicPBSParameters) { fn integer_smart_small_scalar_mul(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -560,7 +512,6 @@ fn integer_smart_small_scalar_mul(param: ClassicPBSParameters) { let scalar = rng.gen::() % scalar_modulus; - // encryption of an integer let mut ct = cks.encrypt_radix(clear, NB_CTXT); let mut ct_res = sks.smart_small_scalar_mul(&mut ct, scalar); @@ -572,10 +523,8 @@ fn integer_smart_small_scalar_mul(param: ClassicPBSParameters) { clear_res *= scalar; } - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!(clear_res % modulus, dec_res); } } @@ -583,7 +532,6 @@ fn integer_smart_small_scalar_mul(param: ClassicPBSParameters) { fn integer_blockshift(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -594,16 +542,13 @@ fn integer_blockshift(param: ClassicPBSParameters) { let power = rng.gen::() % NB_CTXT as u64; - // encryption of an integer let ct = cks.encrypt_radix(clear, NB_CTXT); // add the two ciphertexts let ct_res = sks.blockshift(&ct, power as usize); - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!( (clear * param.message_modulus.0.pow(power as u32) as u64) % modulus, dec_res @@ -614,7 +559,6 @@ fn integer_blockshift(param: ClassicPBSParameters) { fn integer_blockshift_right(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -625,16 +569,13 @@ fn integer_blockshift_right(param: ClassicPBSParameters) { let power = rng.gen::() % NB_CTXT as u64; - // encryption of an integer let ct = cks.encrypt_radix(clear, NB_CTXT); // add the two ciphertexts let ct_res = sks.blockshift_right(&ct, power as usize); - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!( (clear / param.message_modulus.0.pow(power as u32) as u64) % modulus, dec_res @@ -645,7 +586,6 @@ fn integer_blockshift_right(param: ClassicPBSParameters) { fn integer_smart_scalar_mul(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -656,16 +596,13 @@ fn integer_smart_scalar_mul(param: ClassicPBSParameters) { let scalar = rng.gen::() % modulus; - // encryption of an integer let mut ct = cks.encrypt_radix(clear, NB_CTXT); // scalar mul let ct_res = sks.smart_scalar_mul(&mut ct, scalar); - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!((clear * scalar) % modulus, dec_res); } } @@ -707,7 +644,6 @@ fn integer_unchecked_scalar_left_shift(param: ClassicPBSParameters) { fn integer_unchecked_scalar_right_shift(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -768,7 +704,6 @@ fn integer_smart_sub(param: ClassicPBSParameters) { fn integer_unchecked_block_mul(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -781,19 +716,15 @@ fn integer_unchecked_block_mul(param: ClassicPBSParameters) { let clear_1 = rng.gen::() % block_modulus; - // encryption of an integer let ct_zero = cks.encrypt_radix(clear_0, NB_CTXT); - // encryption of an integer let ct_one = cks.encrypt_one_block(clear_1); // add the two ciphertexts let ct_res = sks.unchecked_block_mul(&ct_zero, &ct_one, 0); - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); - // assert assert_eq!((clear_0 * clear_1) % modulus, dec_res); } } @@ -801,7 +732,6 @@ fn integer_unchecked_block_mul(param: ClassicPBSParameters) { fn integer_smart_block_mul(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -838,7 +768,6 @@ fn integer_smart_block_mul(param: ClassicPBSParameters) { fn integer_unchecked_mul(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -867,7 +796,6 @@ fn integer_unchecked_mul(param: ClassicPBSParameters) { fn integer_smart_mul(param: ClassicPBSParameters) { let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -918,7 +846,6 @@ fn integer_smart_scalar_add(param: ClassicPBSParameters) { let mut clear; - // RNG let mut rng = rand::thread_rng(); for _ in 0..NB_TESTS_SMALLER { @@ -926,7 +853,6 @@ fn integer_smart_scalar_add(param: ClassicPBSParameters) { let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ctxt_0 = cks.encrypt_radix(clear_0, NB_CTXT); // add the two ciphertexts @@ -940,11 +866,9 @@ fn integer_smart_scalar_add(param: ClassicPBSParameters) { ct_res = sks.smart_scalar_add(&mut ct_res, clear_1); clear = (clear + clear_1) % modulus; - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); // println!("clear = {}, dec_res = {}", clear, dec_res); - // assert assert_eq!(clear, dec_res); } } @@ -967,7 +891,6 @@ fn integer_smart_scalar_sub(param: ClassicPBSParameters) { let mut clear; - // RNG let mut rng = rand::thread_rng(); for _ in 0..NB_TESTS_SMALLER { @@ -975,7 +898,6 @@ fn integer_smart_scalar_sub(param: ClassicPBSParameters) { let clear_1 = rng.gen::() % modulus; - // encryption of an integer let mut ctxt_0 = cks.encrypt_radix(clear_0, NB_CTXT); // add the two ciphertexts @@ -989,11 +911,9 @@ fn integer_smart_scalar_sub(param: ClassicPBSParameters) { ct_res = sks.smart_scalar_sub(&mut ct_res, clear_1); clear = (clear - clear_1) % modulus; - // decryption of ct_res let dec_res: u64 = cks.decrypt_radix(&ct_res); // println!("clear = {}, dec_res = {}", clear, dec_res); - // assert assert_eq!(clear, dec_res); } } @@ -1018,7 +938,6 @@ fn integer_unchecked_scalar_decomposition_overflow(param: ClassicPBSParameters) let ct_0 = cks.encrypt_radix(clear_0, num_block); let ct_res = sks.unchecked_scalar_add(&ct_0, scalar); - // decryption of ct_res let dec_res = cks.decrypt_radix(&ct_res); assert_eq!((clear_0 + scalar as u128), dec_res); @@ -1043,7 +962,6 @@ fn integer_smart_scalar_mul_decomposition_overflow() { // Since smart_scalar_mul is a slow operation, we test against only one parameters set. // If overflow occurs the test case will panic. - // RNG let mut rng = rand::thread_rng(); let param = PARAM_MESSAGE_2_CARRY_2_KS_PBS; diff --git a/tfhe/src/integer/server_key/radix_parallel/add.rs b/tfhe/src/integer/server_key/radix_parallel/add.rs index c57866f5ee..d9f041eb1d 100644 --- a/tfhe/src/integer/server_key/radix_parallel/add.rs +++ b/tfhe/src/integer/server_key/radix_parallel/add.rs @@ -1,14 +1,13 @@ +use crate::core_crypto::commons::numeric::UnsignedInteger; use crate::integer::ciphertext::IntegerRadixCiphertext; +use crate::integer::server_key::radix_parallel::sub::SignedOperation; use crate::integer::{ BooleanBlock, IntegerCiphertext, RadixCiphertext, ServerKey, SignedRadixCiphertext, }; -use crate::shortint::Ciphertext; -use std::ops::RangeInclusive; - -use crate::core_crypto::commons::numeric::UnsignedInteger; -use crate::integer::server_key::radix_parallel::sub::SignedOperation; use crate::shortint::ciphertext::Degree; +use crate::shortint::Ciphertext; use rayon::prelude::*; +use std::ops::RangeInclusive; #[repr(u64)] #[derive(PartialEq, Eq)] diff --git a/tfhe/src/integer/server_key/radix_parallel/comparison.rs b/tfhe/src/integer/server_key/radix_parallel/comparison.rs index dd36a26c39..2f3e416ff1 100644 --- a/tfhe/src/integer/server_key/radix_parallel/comparison.rs +++ b/tfhe/src/integer/server_key/radix_parallel/comparison.rs @@ -1,9 +1,7 @@ use super::ServerKey; - +use crate::integer::ciphertext::boolean_value::BooleanBlock; use crate::integer::ciphertext::IntegerRadixCiphertext; use crate::integer::server_key::comparator::Comparator; - -use crate::integer::ciphertext::boolean_value::BooleanBlock; use rayon::prelude::*; impl ServerKey { diff --git a/tfhe/src/integer/server_key/radix_parallel/div_mod.rs b/tfhe/src/integer/server_key/radix_parallel/div_mod.rs index d42a5c324f..b1cfb87f2e 100644 --- a/tfhe/src/integer/server_key/radix_parallel/div_mod.rs +++ b/tfhe/src/integer/server_key/radix_parallel/div_mod.rs @@ -1,7 +1,6 @@ use crate::integer::ciphertext::{IntegerRadixCiphertext, RadixCiphertext, SignedRadixCiphertext}; use crate::integer::server_key::comparator::ZeroComparisonType; use crate::integer::{BooleanBlock, IntegerCiphertext, ServerKey}; - use crate::shortint::MessageModulus; use rayon::prelude::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/mod.rs b/tfhe/src/integer/server_key/radix_parallel/mod.rs index 7cdd3e0526..f323555be4 100644 --- a/tfhe/src/integer/server_key/radix_parallel/mod.rs +++ b/tfhe/src/integer/server_key/radix_parallel/mod.rs @@ -31,12 +31,10 @@ pub(crate) mod tests_signed; #[cfg(test)] pub(crate) mod tests_unsigned; -use crate::integer::ciphertext::IntegerRadixCiphertext; - use super::ServerKey; -pub use scalar_div_mod::{MiniUnsignedInteger, Reciprocable}; - +use crate::integer::ciphertext::IntegerRadixCiphertext; use rayon::prelude::*; +pub use scalar_div_mod::{MiniUnsignedInteger, Reciprocable}; // parallelized versions impl ServerKey { diff --git a/tfhe/src/integer/server_key/radix_parallel/rotate.rs b/tfhe/src/integer/server_key/radix_parallel/rotate.rs index ff6850365e..9f921036a8 100644 --- a/tfhe/src/integer/server_key/radix_parallel/rotate.rs +++ b/tfhe/src/integer/server_key/radix_parallel/rotate.rs @@ -1,8 +1,7 @@ +use super::shift::BarrelShifterOperation; use crate::integer::ciphertext::{IntegerRadixCiphertext, RadixCiphertext}; use crate::integer::ServerKey; -use super::shift::BarrelShifterOperation; - impl ServerKey { //====================================================================== // Rotate Right diff --git a/tfhe/src/integer/server_key/radix_parallel/scalar_comparison.rs b/tfhe/src/integer/server_key/radix_parallel/scalar_comparison.rs index 737c0eb09e..dba0cd6aa6 100644 --- a/tfhe/src/integer/server_key/radix_parallel/scalar_comparison.rs +++ b/tfhe/src/integer/server_key/radix_parallel/scalar_comparison.rs @@ -1,12 +1,10 @@ use super::ServerKey; - use crate::integer::block_decomposition::{BlockDecomposer, DecomposableInto}; +use crate::integer::ciphertext::boolean_value::BooleanBlock; use crate::integer::ciphertext::IntegerRadixCiphertext; use crate::integer::server_key::comparator::{Comparator, ZeroComparisonType}; use crate::shortint::server_key::LookupTableOwned; use crate::shortint::Ciphertext; - -use crate::integer::ciphertext::boolean_value::BooleanBlock; use rayon::prelude::*; impl ServerKey { diff --git a/tfhe/src/integer/server_key/radix_parallel/scalar_div_mod.rs b/tfhe/src/integer/server_key/radix_parallel/scalar_div_mod.rs index 2f1277c077..064a1672ee 100644 --- a/tfhe/src/integer/server_key/radix_parallel/scalar_div_mod.rs +++ b/tfhe/src/integer/server_key/radix_parallel/scalar_div_mod.rs @@ -10,13 +10,12 @@ //! In this case, the constant is a clear value at runtime, however, //! due to the huge difference between clear computation and FHE computation //! it is absolutely worth to compute the approximation of the inverse. -use std::ops::{Add, AddAssign, BitAnd, Div, Mul, Neg, Shl, Shr, Sub}; - use crate::core_crypto::prelude::{CastFrom, CastInto, Numeric, SignedNumeric, UnsignedInteger}; use crate::integer::block_decomposition::DecomposableInto; use crate::integer::ciphertext::{RadixCiphertext, SignedRadixCiphertext}; use crate::integer::server_key::radix::scalar_mul::ScalarMultiplier; use crate::integer::{IntegerCiphertext, ServerKey, I256, I512, U256, U512}; +use std::ops::{Add, AddAssign, BitAnd, Div, Mul, Neg, Shl, Shr, Sub}; #[inline(always)] fn is_even(d: T) -> bool diff --git a/tfhe/src/integer/server_key/radix_parallel/scalar_rotate.rs b/tfhe/src/integer/server_key/radix_parallel/scalar_rotate.rs index 11dd74eaef..af3579a2bb 100644 --- a/tfhe/src/integer/server_key/radix_parallel/scalar_rotate.rs +++ b/tfhe/src/integer/server_key/radix_parallel/scalar_rotate.rs @@ -1,7 +1,6 @@ use crate::core_crypto::prelude::CastFrom; use crate::integer::ciphertext::IntegerRadixCiphertext; use crate::integer::ServerKey; - use rayon::prelude::*; impl ServerKey { diff --git a/tfhe/src/integer/server_key/radix_parallel/scalar_shift.rs b/tfhe/src/integer/server_key/radix_parallel/scalar_shift.rs index 6cd60f7944..1c4688413f 100644 --- a/tfhe/src/integer/server_key/radix_parallel/scalar_shift.rs +++ b/tfhe/src/integer/server_key/radix_parallel/scalar_shift.rs @@ -2,7 +2,6 @@ use crate::core_crypto::commons::utils::izip; use crate::core_crypto::prelude::CastFrom; use crate::integer::ciphertext::IntegerRadixCiphertext; use crate::integer::ServerKey; - use rayon::prelude::*; impl ServerKey { diff --git a/tfhe/src/integer/server_key/radix_parallel/shift.rs b/tfhe/src/integer/server_key/radix_parallel/shift.rs index 76e9a34cf1..f9c9e317fe 100644 --- a/tfhe/src/integer/server_key/radix_parallel/shift.rs +++ b/tfhe/src/integer/server_key/radix_parallel/shift.rs @@ -1,7 +1,6 @@ use crate::integer::ciphertext::{IntegerRadixCiphertext, RadixCiphertext}; use crate::integer::server_key::radix_parallel::bit_extractor::BitExtractor; use crate::integer::ServerKey; - use rayon::prelude::*; #[derive(Clone, Copy)] diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_cases_comparisons.rs b/tfhe/src/integer/server_key/radix_parallel/tests_cases_comparisons.rs index 72ef96c58f..189857cc53 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_cases_comparisons.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_cases_comparisons.rs @@ -3,6 +3,7 @@ use crate::integer::block_decomposition::{DecomposableInto, RecomposableFrom}; use crate::integer::ciphertext::{RadixCiphertext, SignedRadixCiphertext}; use crate::integer::client_key::RecomposableSignedInteger; use crate::integer::keycache::KEY_CACHE; +use crate::integer::tests::create_parametrized_test; use crate::integer::{IntegerKeyKind, ServerKey, I256, U256}; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; @@ -244,7 +245,7 @@ fn test_default_function( /// the 5 variants described above macro_rules! define_comparison_test_functions { ($comparison_name:ident, $clear_type:ty) => { - paste::paste!{ + ::paste::paste!{ fn [](params: crate::shortint::ClassicPBSParameters) { let num_tests = 1; test_unchecked_function( @@ -627,7 +628,7 @@ fn test_signed_default_function( /// the 5 variants described above macro_rules! define_signed_comparison_test_functions { ($comparison_name:ident, $clear_type:ty) => { - paste::paste!{ + ::paste::paste!{ // Fist we "specialialize" the test_signed fns fn [](params: crate::shortint::ClassicPBSParameters) { @@ -942,7 +943,7 @@ fn test_default_scalar_function( /// this macro will generate the tests for the 3 variants described above macro_rules! define_scalar_comparison_test_functions { ($comparison_name:ident, $clear_type:ty) => { - paste::paste!{ + ::paste::paste!{ fn [](params: crate::shortint::ClassicPBSParameters) { let num_tests = 1; @@ -1398,7 +1399,7 @@ fn test_signed_default_scalar_function( /// this macro will generate the tests for the 3 variants described above macro_rules! define_signed_scalar_comparison_test_functions { ($comparison_name:ident, $clear_type:ty) => { - paste::paste!{ + ::paste::paste!{ fn [](params: crate::shortint::ClassicPBSParameters) { let num_tests = 2; test_signed_unchecked_scalar_function( diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_cases_unsigned.rs b/tfhe/src/integer/server_key/radix_parallel/tests_cases_unsigned.rs index 7c305fa1dd..ad95e9d3ab 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_cases_unsigned.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_cases_unsigned.rs @@ -1440,7 +1440,6 @@ where let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); let cks = RadixClientKey::from((cks, NB_CTXT)); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1452,7 +1451,6 @@ where .map(|_| rng.gen::() % modulus) .collect::>(); - // encryption of integers let ctxts = clears .iter() .copied() @@ -1498,7 +1496,6 @@ where .map(|_| rng.gen::() % modulus) .collect::>(); - // encryption of integers let ctxts = clears .iter() .copied() @@ -1735,7 +1732,6 @@ where let cks = RadixClientKey::from((cks, NB_CTXT)); let sks = Arc::new(sks); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1768,7 +1764,6 @@ where let cks = RadixClientKey::from((cks, NB_CTXT)); let sks = Arc::new(sks); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1813,7 +1808,6 @@ where let cks = RadixClientKey::from((cks, NB_CTXT)); let sks = Arc::new(sks); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -1857,7 +1851,6 @@ where let cks = RadixClientKey::from((cks, NB_CTXT)); let sks = Arc::new(sks); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -2378,7 +2371,6 @@ where let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ctxt_0 = cks.encrypt(clear_0); let mut ct_res = executor.execute((&ctxt_0, clear_1)); @@ -2822,7 +2814,6 @@ where sks.set_deterministic_pbs_execution(true); let sks = Arc::new(sks); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -2913,7 +2904,6 @@ where let clear_0 = rng.gen::() % modulus; let clear_1 = rng.gen::() % modulus; - // encryption of an integer let ctxt_0 = cks.encrypt(clear_0); // Do with a small clear to check the way we avoid @@ -3651,7 +3641,6 @@ where )); let sks = Arc::new(sks); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length @@ -3670,7 +3659,6 @@ where .map(|_| rng.gen::() % modulus) .collect::>(); - // encryption of integers let ctxts = clears .iter() .copied() diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_signed/mod.rs b/tfhe/src/integer/server_key/radix_parallel/tests_signed/mod.rs index 6358b6ddb1..109ee8851b 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_signed/mod.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_signed/mod.rs @@ -18,7 +18,6 @@ use crate::integer::{ use crate::shortint::parameters::coverage_parameters::*; use crate::shortint::parameters::*; use itertools::iproduct; -use paste::paste; use rand::Rng; use std::sync::Arc; @@ -29,7 +28,7 @@ macro_rules! create_parametrized_test{ $(,)? } ) => { - paste! { + ::paste::paste! { $( #[test] $(#[$cfg])* diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_add.rs b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_add.rs index 9f17acc612..0221645e2e 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_add.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_add.rs @@ -8,6 +8,7 @@ use crate::integer::server_key::radix_parallel::tests_signed::{ NB_CTXT, NB_TESTS, NB_TESTS_SMALLER, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::{ BooleanBlock, IntegerKeyKind, RadixClientKey, ServerKey, SignedRadixCiphertext, }; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_bitwise_op.rs b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_bitwise_op.rs index fbfdf9e5fc..2761deb731 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_bitwise_op.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_bitwise_op.rs @@ -4,6 +4,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_signed::{ signed_unchecked_bitxor_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_mul.rs b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_mul.rs index 7fd0784dff..f71d7fd8b5 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_mul.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_mul.rs @@ -5,6 +5,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_signed::{ }; use crate::integer::server_key::radix_parallel::tests_signed::{NB_CTXT, NB_TESTS_SMALLER}; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::{IntegerKeyKind, RadixClientKey, ServerKey, SignedRadixCiphertext}; use crate::shortint::ciphertext::NoiseLevel; #[cfg(tarpaulin)] diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_neg.rs b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_neg.rs index 2403b5268e..c3608ad4f1 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_neg.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_neg.rs @@ -2,6 +2,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_signed::{ signed_default_neg_test, signed_smart_neg_test, signed_unchecked_neg_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_add.rs b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_add.rs index 08744ad14a..44095dbcea 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_add.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_add.rs @@ -3,6 +3,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_signed::{ signed_unchecked_scalar_add_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_bitwise_op.rs b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_bitwise_op.rs index c67661f0ea..25d178966c 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_bitwise_op.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_bitwise_op.rs @@ -3,6 +3,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_signed::{ signed_default_scalar_bitxor_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_sub.rs b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_sub.rs index 979db8cc9d..649f3b3de6 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_sub.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_scalar_sub.rs @@ -2,6 +2,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_signed::{ signed_default_overflowing_scalar_sub_test, signed_unchecked_scalar_sub_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_sub.rs b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_sub.rs index 1761c4289b..5ab530bb7c 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_sub.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_signed/test_sub.rs @@ -1,6 +1,7 @@ use crate::integer::keycache::KEY_CACHE; use crate::integer::server_key::radix_parallel::tests_cases_signed::*; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::{ BooleanBlock, IntegerKeyKind, RadixClientKey, ServerKey, SignedRadixCiphertext, }; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/mod.rs b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/mod.rs index 5273a9b24b..c8769d7a16 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/mod.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/mod.rs @@ -14,7 +14,6 @@ use crate::shortint::ciphertext::{Degree, MaxDegree, MaxNoiseLevel, NoiseLevel}; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; use crate::shortint::parameters::*; -use paste::paste; use rand::prelude::ThreadRng; use rand::Rng; use std::sync::Arc; @@ -301,7 +300,7 @@ macro_rules! create_parametrized_test { $(,)? } ) => { - paste! { + ::paste::paste! { $( #[test] $(#[$cfg])* @@ -888,7 +887,6 @@ where let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); let cks = RadixClientKey::from((cks, NB_CTXT)); - //RNG let mut rng = rand::thread_rng(); // message_modulus^vec_length diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_add.rs b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_add.rs index cee7e564b6..76529a3fe4 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_add.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_add.rs @@ -8,6 +8,7 @@ use crate::integer::keycache::KEY_CACHE; use crate::integer::server_key::radix_parallel::tests_cases_unsigned::{ default_sum_ciphertexts_vec_test, FunctionExecutor, }; +use crate::integer::tests::create_parametrized_test; use crate::integer::{BooleanBlock, IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey}; use crate::shortint::ciphertext::{Degree, NoiseLevel}; #[cfg(tarpaulin)] diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_bitwise_op.rs b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_bitwise_op.rs index 2dc8511e6e..8757d175c4 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_bitwise_op.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_bitwise_op.rs @@ -4,6 +4,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_unsigned::{ unchecked_bitnot_test, unchecked_bitor_test, unchecked_bitxor_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_mul.rs b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_mul.rs index 80b244428c..acc54eb4bb 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_mul.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_mul.rs @@ -4,6 +4,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_unsigned::{ unchecked_mul_corner_cases_test, unchecked_mul_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_neg.rs b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_neg.rs index 6e0833da12..8789ad6d33 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_neg.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_neg.rs @@ -8,6 +8,7 @@ use crate::integer::server_key::radix_parallel::tests_unsigned::{ panic_if_any_block_values_exceeds_its_degree, unsigned_modulus, CpuFunctionExecutor, ExpectedDegrees, ExpectedNoiseLevels, }; +use crate::integer::tests::create_parametrized_test; use crate::integer::{IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey}; use crate::shortint::ciphertext::{Degree, NoiseLevel}; #[cfg(tarpaulin)] diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_add.rs b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_add.rs index af3c5ac0c6..74e48e179d 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_add.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_add.rs @@ -2,6 +2,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_unsigned::{ default_overflowing_scalar_add_test, default_scalar_add_test, smart_scalar_add_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_bitwise_op.rs b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_bitwise_op.rs index d188ab8e89..bc675b43cc 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_bitwise_op.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_bitwise_op.rs @@ -2,6 +2,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_unsigned::{ default_scalar_bitand_test, default_scalar_bitor_test, default_scalar_bitxor_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_sub.rs b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_sub.rs index df0a7412f4..0e2b69d9c8 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_sub.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_scalar_sub.rs @@ -2,6 +2,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_unsigned::{ default_overflowing_scalar_sub_test, default_scalar_sub_test, smart_scalar_sub_test, }; use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor; +use crate::integer::tests::create_parametrized_test; use crate::integer::ServerKey; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; diff --git a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_sub.rs b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_sub.rs index 3c34b04ee3..89d230957d 100644 --- a/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_sub.rs +++ b/tfhe/src/integer/server_key/radix_parallel/tests_unsigned/test_sub.rs @@ -9,6 +9,7 @@ use crate::integer::server_key::radix_parallel::tests_unsigned::{ random_non_zero_value, unsigned_modulus, CpuFunctionExecutor, ExpectedDegrees, ExpectedNoiseLevels, }; +use crate::integer::tests::create_parametrized_test; use crate::integer::{BooleanBlock, IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey}; use crate::shortint::ciphertext::{Degree, NoiseLevel}; #[cfg(tarpaulin)] diff --git a/tfhe/src/integer/tests.rs b/tfhe/src/integer/tests.rs index 9fba46149a..55dbef5383 100644 --- a/tfhe/src/integer/tests.rs +++ b/tfhe/src/integer/tests.rs @@ -50,3 +50,5 @@ macro_rules! create_parametrized_test{ } }; } + +pub(crate) use create_parametrized_test; diff --git a/tfhe/src/integer/wopbs/test.rs b/tfhe/src/integer/wopbs/test.rs index 29641b3a93..0cc34ee513 100644 --- a/tfhe/src/integer/wopbs/test.rs +++ b/tfhe/src/integer/wopbs/test.rs @@ -1,5 +1,6 @@ #![allow(unused)] +use crate::integer::keycache::{KEY_CACHE, KEY_CACHE_WOPBS}; use crate::integer::parameters::*; use crate::integer::wopbs::{encode_radix, WopbsKey}; use crate::integer::{gen_keys, IntegerKeyKind}; @@ -7,12 +8,10 @@ use crate::shortint::ciphertext::Degree; use crate::shortint::parameters::parameters_wopbs::*; use crate::shortint::parameters::parameters_wopbs_message_carry::*; use crate::shortint::parameters::*; +use paste::paste; use rand::Rng; use std::cmp::max; -use crate::integer::keycache::{KEY_CACHE, KEY_CACHE_WOPBS}; -use paste::paste; - #[cfg(not(tarpaulin))] const NB_TESTS: usize = 10; // Use lower numbers for coverage to ensure fast tests to counter balance slowdown due to code diff --git a/tfhe/src/js_on_wasm_api/boolean.rs b/tfhe/src/js_on_wasm_api/boolean.rs index 95f120ae11..bf3e1f4649 100644 --- a/tfhe/src/js_on_wasm_api/boolean.rs +++ b/tfhe/src/js_on_wasm_api/boolean.rs @@ -1,10 +1,8 @@ -use crate::core_crypto::commons::math::random::Seed; -use wasm_bindgen::prelude::*; - use crate::core_crypto::commons::generators::DeterministicSeeder; +use crate::core_crypto::commons::math::random::Seed; use crate::core_crypto::prelude::ActivatedRandomGenerator; - use std::panic::set_hook; +use wasm_bindgen::prelude::*; #[wasm_bindgen] pub struct BooleanCiphertext(pub(crate) crate::boolean::ciphertext::Ciphertext); diff --git a/tfhe/src/js_on_wasm_api/js_high_level_api/config.rs b/tfhe/src/js_on_wasm_api/js_high_level_api/config.rs index b8aba91599..d9a6bf48ed 100644 --- a/tfhe/src/js_on_wasm_api/js_high_level_api/config.rs +++ b/tfhe/src/js_on_wasm_api/js_high_level_api/config.rs @@ -1,6 +1,5 @@ -use wasm_bindgen::prelude::*; - use crate::high_level_api as hlapi; +use wasm_bindgen::prelude::*; #[wasm_bindgen] pub struct TfheConfig(pub(crate) hlapi::Config); diff --git a/tfhe/src/js_on_wasm_api/js_high_level_api/integers.rs b/tfhe/src/js_on_wasm_api/js_high_level_api/integers.rs index 644bec19c9..c2adf2e46f 100644 --- a/tfhe/src/js_on_wasm_api/js_high_level_api/integers.rs +++ b/tfhe/src/js_on_wasm_api/js_high_level_api/integers.rs @@ -1,8 +1,7 @@ -use wasm_bindgen::prelude::*; - use crate::high_level_api::prelude::*; use crate::integer::{I256, U256}; use crate::js_on_wasm_api::js_high_level_api::{catch_panic, catch_panic_result, into_js_error}; +use wasm_bindgen::prelude::*; const U128_MAX_AS_STR: &str = "340282366920938463463374607431768211455"; diff --git a/tfhe/src/js_on_wasm_api/js_high_level_api/keys.rs b/tfhe/src/js_on_wasm_api/js_high_level_api/keys.rs index 2505c50ecf..be92af6172 100644 --- a/tfhe/src/js_on_wasm_api/js_high_level_api/keys.rs +++ b/tfhe/src/js_on_wasm_api/js_high_level_api/keys.rs @@ -1,9 +1,7 @@ -use wasm_bindgen::prelude::*; - use crate::high_level_api as hlapi; - use crate::js_on_wasm_api::js_high_level_api::config::TfheConfig; use crate::js_on_wasm_api::js_high_level_api::{catch_panic, catch_panic_result, into_js_error}; +use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn init_panic_hook() { diff --git a/tfhe/src/js_on_wasm_api/shortint.rs b/tfhe/src/js_on_wasm_api/shortint.rs index b4164d7023..4f051974e2 100644 --- a/tfhe/src/js_on_wasm_api/shortint.rs +++ b/tfhe/src/js_on_wasm_api/shortint.rs @@ -3,9 +3,8 @@ use crate::core_crypto::commons::math::random::Seed; use crate::core_crypto::prelude::ActivatedRandomGenerator; use crate::shortint::parameters::parameters_compact_pk::*; use crate::shortint::parameters::*; -use wasm_bindgen::prelude::*; - use std::panic::set_hook; +use wasm_bindgen::prelude::*; #[wasm_bindgen] pub struct ShortintCiphertext(pub(crate) crate::shortint::Ciphertext); diff --git a/tfhe/src/keycache/mod.rs b/tfhe/src/keycache/mod.rs index ba56c799da..58bd6369b1 100644 --- a/tfhe/src/keycache/mod.rs +++ b/tfhe/src/keycache/mod.rs @@ -3,7 +3,6 @@ pub use utils::{ SharedKey as GenericSharedKey, }; -#[macro_use] pub mod utils { use fs2::FileExt; use serde::de::DeserializeOwned; @@ -23,11 +22,10 @@ pub mod utils { fn name(&self) -> String; } - #[macro_export] macro_rules! named_params_impl( (expose $($const_param:ident),* $(,)? ) => { $( - paste::paste! { + ::paste::paste! { pub const [<$const_param _NAME>]: &'static str = stringify!($const_param); } )* @@ -42,7 +40,7 @@ pub mod utils { impl NamedParam for $param_type { fn name(&self) -> String { $( - $(#[$cfg])? + $(#[$cfg])? named_params_impl!({*self; $param_type} == ( $const_param )); )* panic!("Unnamed parameters"); @@ -52,7 +50,7 @@ pub mod utils { ({$thing:expr; $param_type:ty} == ( $($const_param:ident),* $(,)? )) => { $( - paste::paste! { + ::paste::paste! { if $thing == <$param_type>::from($const_param) { return [<$const_param _NAME>].to_string(); } @@ -61,6 +59,8 @@ pub mod utils { } ); + pub(crate) use named_params_impl; + pub struct FileStorage { prefix: String, } diff --git a/tfhe/src/shortint/ciphertext/common.rs b/tfhe/src/shortint/ciphertext/common.rs new file mode 100644 index 0000000000..b60a7dd23c --- /dev/null +++ b/tfhe/src/shortint/ciphertext/common.rs @@ -0,0 +1,362 @@ +use super::super::CheckError; +pub use crate::core_crypto::commons::parameters::PBSOrder; +use crate::shortint::parameters::{CarryModulus, MessageModulus}; +use serde::{Deserialize, Serialize}; +use std::cmp; +use std::fmt::Debug; + +/// Error for when a non trivial ciphertext was used when a trivial was expected +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct NotTrivialCiphertextError; + +impl std::fmt::Display for NotTrivialCiphertextError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "The ciphertext is a not a trivial ciphertext") + } +} + +impl std::error::Error for NotTrivialCiphertextError {} + +/// This tracks the maximal amount of noise of a [super::Ciphertext] +/// that guarantees the target p-error when doing a PBS on it +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] +pub struct MaxNoiseLevel(usize); + +impl MaxNoiseLevel { + pub fn new(value: usize) -> Self { + Self(value) + } + + pub fn get(&self) -> usize { + self.0 + } + + // This function is valid for current parameters as they guarantee the p-error for a norm2 noise + // limit equal to the norm2 limit which guarantees a clean padding bit + // + // TODO: remove this functions once noise norm2 constraint is decorrelated and stored in + // parameter sets + pub fn from_msg_carry_modulus( + msg_modulus: MessageModulus, + carry_modulus: CarryModulus, + ) -> Self { + Self((carry_modulus.0 * msg_modulus.0 - 1) / (msg_modulus.0 - 1)) + } + + pub fn validate(&self, noise_level: NoiseLevel) -> Result<(), CheckError> { + if noise_level.0 > self.0 { + return Err(CheckError::NoiseTooBig { + noise_level, + max_noise_level: *self, + }); + } + Ok(()) + } +} + +/// This tracks the amount of noise in a ciphertext. +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] +pub struct NoiseLevel(usize); + +impl NoiseLevel { + pub const NOMINAL: Self = Self(1); + pub const ZERO: Self = Self(0); + // To force a refresh no matter the tolerance of the server key, useful for serialization update + // for formats which did not have noise levels saved + pub const MAX: Self = Self(usize::MAX); + // As a safety measure the unknown noise level is set to the max value + pub const UNKNOWN: Self = Self::MAX; +} + +impl NoiseLevel { + pub fn get(&self) -> usize { + self.0 + } +} + +impl std::ops::AddAssign for NoiseLevel { + fn add_assign(&mut self, rhs: Self) { + self.0 = self.0.saturating_add(rhs.0); + } +} + +impl std::ops::Add for NoiseLevel { + type Output = Self; + + fn add(mut self, rhs: Self) -> Self { + self += rhs; + self + } +} + +impl std::ops::MulAssign for NoiseLevel { + fn mul_assign(&mut self, rhs: usize) { + self.0 = self.0.saturating_mul(rhs); + } +} + +impl std::ops::Mul for NoiseLevel { + type Output = Self; + + fn mul(mut self, rhs: usize) -> Self::Output { + self *= rhs; + + self + } +} + +/// Maximum value that the degree can reach. +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] +pub struct MaxDegree(usize); + +impl MaxDegree { + pub fn new(value: usize) -> Self { + Self(value) + } + + pub fn get(&self) -> usize { + self.0 + } + + pub fn from_msg_carry_modulus( + msg_modulus: MessageModulus, + carry_modulus: CarryModulus, + ) -> Self { + Self(carry_modulus.0 * msg_modulus.0 - 1) + } + + pub fn validate(&self, degree: Degree) -> Result<(), CheckError> { + if degree.get() > self.0 { + return Err(CheckError::CarryFull { + degree, + max_degree: *self, + }); + } + Ok(()) + } +} + +/// This tracks the number of operations that has been done. +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] +pub struct Degree(pub(super) usize); + +impl Degree { + pub fn new(degree: usize) -> Self { + Self(degree) + } + + pub fn get(self) -> usize { + self.0 + } +} + +#[cfg(test)] +impl AsMut for Degree { + fn as_mut(&mut self) -> &mut usize { + &mut self.0 + } +} + +impl Degree { + pub(crate) fn after_bitxor(self, other: Self) -> Self { + let max = cmp::max(self.0, other.0); + let min = cmp::min(self.0, other.0); + let mut result = max; + + //Try every possibility to find the worst case + for i in 0..min + 1 { + if max ^ i > result { + result = max ^ i; + } + } + + Self(result) + } + + pub(crate) fn after_bitor(self, other: Self) -> Self { + let max = cmp::max(self.0, other.0); + let min = cmp::min(self.0, other.0); + let mut result = max; + + for i in 0..min + 1 { + if max | i > result { + result = max | i; + } + } + + Self(result) + } + + pub(crate) fn after_bitand(self, other: Self) -> Self { + Self(cmp::min(self.0, other.0)) + } + + pub(crate) fn after_left_shift(self, shift: u8, modulus: usize) -> Self { + let mut result = 0; + + for i in 0..self.0 + 1 { + let tmp = (i << shift) % modulus; + if tmp > result { + result = tmp; + } + } + + Self(result) + } + + #[allow(dead_code)] + pub(crate) fn after_pbs(self, f: F) -> Self + where + F: Fn(usize) -> usize, + { + let mut result = 0; + + for i in 0..self.0 + 1 { + let tmp = f(i); + if tmp > result { + result = tmp; + } + } + + Self(result) + } +} + +impl std::ops::AddAssign for Degree { + fn add_assign(&mut self, rhs: Self) { + self.0 = self.0.saturating_add(rhs.0); + } +} + +impl std::ops::Add for Degree { + type Output = Self; + + fn add(mut self, rhs: Self) -> Self { + self += rhs; + self + } +} + +impl std::ops::MulAssign for Degree { + fn mul_assign(&mut self, rhs: usize) { + self.0 = self.0.saturating_mul(rhs); + } +} + +impl std::ops::Mul for Degree { + type Output = Self; + + fn mul(mut self, rhs: usize) -> Self::Output { + self *= rhs; + + self + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_noise_level_ci_run_filter() { + use rand::{thread_rng, Rng}; + + let mut rng = thread_rng(); + + assert_eq!(NoiseLevel::UNKNOWN, NoiseLevel::MAX); + + let max_noise_level = NoiseLevel::MAX; + let random_addend = rng.gen::(); + let add = max_noise_level + NoiseLevel(random_addend); + assert_eq!(add, NoiseLevel::MAX); + + let random_positive_multiplier = rng.gen_range(1usize..=usize::MAX); + let mul = max_noise_level * random_positive_multiplier; + assert_eq!(mul, NoiseLevel::MAX); + } + + #[test] + fn test_max_noise_level_from_msg_carry_modulus() { + let max_noise_level = + MaxNoiseLevel::from_msg_carry_modulus(MessageModulus(4), CarryModulus(4)); + + assert_eq!(max_noise_level.0, 5); + } + + #[test] + fn degree_after_bitxor_ci_run_filter() { + let data = [ + (Degree(3), Degree(3), Degree(3)), + (Degree(3), Degree(1), Degree(3)), + (Degree(1), Degree(3), Degree(3)), + (Degree(3), Degree(2), Degree(3)), + (Degree(2), Degree(3), Degree(3)), + (Degree(2), Degree(2), Degree(3)), + (Degree(2), Degree(1), Degree(3)), + (Degree(1), Degree(2), Degree(3)), + (Degree(1), Degree(1), Degree(1)), + (Degree(0), Degree(1), Degree(1)), + (Degree(0), Degree(1), Degree(1)), + ]; + + for (lhs, rhs, expected) in data { + let result = lhs.after_bitxor(rhs); + assert_eq!( + result, expected, + "For a bitxor between variables of degree {lhs:?} and {rhs:?},\ + expected resulting degree: {expected:?}, got {result:?}" + ); + } + } + #[test] + fn degree_after_bitor_ci_run_filter() { + let data = [ + (Degree(3), Degree(3), Degree(3)), + (Degree(3), Degree(1), Degree(3)), + (Degree(1), Degree(3), Degree(3)), + (Degree(3), Degree(2), Degree(3)), + (Degree(2), Degree(3), Degree(3)), + (Degree(2), Degree(2), Degree(3)), + (Degree(2), Degree(1), Degree(3)), + (Degree(1), Degree(2), Degree(3)), + (Degree(1), Degree(1), Degree(1)), + (Degree(0), Degree(1), Degree(1)), + (Degree(0), Degree(1), Degree(1)), + ]; + + for (lhs, rhs, expected) in data { + let result = lhs.after_bitor(rhs); + assert_eq!( + result, expected, + "For a bitor between variables of degree {lhs:?} and {rhs:?},\ + expected resulting degree: {expected:?}, got {result:?}" + ); + } + } + + #[test] + fn degree_after_bitand_ci_run_filter() { + let data = [ + (Degree(3), Degree(3), Degree(3)), + (Degree(3), Degree(1), Degree(1)), + (Degree(1), Degree(3), Degree(1)), + (Degree(3), Degree(2), Degree(2)), + (Degree(2), Degree(3), Degree(2)), + (Degree(2), Degree(2), Degree(2)), + (Degree(2), Degree(1), Degree(1)), + (Degree(1), Degree(2), Degree(1)), + (Degree(1), Degree(1), Degree(1)), + (Degree(0), Degree(1), Degree(0)), + (Degree(0), Degree(1), Degree(0)), + ]; + + for (lhs, rhs, expected) in data { + let result = lhs.after_bitand(rhs); + assert_eq!( + result, expected, + "For a bitand between variables of degree {lhs:?} and {rhs:?},\ + expected resulting degree: {expected:?}, got {result:?}" + ); + } + } +} diff --git a/tfhe/src/shortint/ciphertext/compact_list.rs b/tfhe/src/shortint/ciphertext/compact_list.rs new file mode 100644 index 0000000000..90f4c74716 --- /dev/null +++ b/tfhe/src/shortint/ciphertext/compact_list.rs @@ -0,0 +1,133 @@ +//! Module with the definition of the Ciphertext. +use super::super::parameters::CiphertextListConformanceParams; +use super::common::*; +use super::standard::Ciphertext; +use crate::conformance::ParameterSetConformant; +use crate::core_crypto::entities::*; +use crate::shortint::parameters::{CarryModulus, MessageModulus}; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct CompactCiphertextList { + pub ct_list: LweCompactCiphertextListOwned, + pub degree: Degree, + pub message_modulus: MessageModulus, + pub carry_modulus: CarryModulus, + pub pbs_order: PBSOrder, + pub noise_level: NoiseLevel, +} + +impl ParameterSetConformant for CompactCiphertextList { + type ParameterSet = CiphertextListConformanceParams; + + fn is_conformant(&self, param: &CiphertextListConformanceParams) -> bool { + self.ct_list.is_conformant(¶m.ct_list_params) + && self.message_modulus == param.message_modulus + && self.carry_modulus == param.carry_modulus + && self.pbs_order == param.pbs_order + && self.degree == param.degree + && self.noise_level == param.noise_level + } +} + +impl CompactCiphertextList { + pub fn expand(&self) -> Vec { + let mut output_lwe_ciphertext_list = LweCiphertextList::new( + 0u64, + self.ct_list.lwe_size(), + self.ct_list.lwe_ciphertext_count(), + self.ct_list.ciphertext_modulus(), + ); + + // No parallelism allowed + #[cfg(all(feature = "__wasm_api", not(feature = "parallel-wasm-api")))] + { + use crate::core_crypto::prelude::expand_lwe_compact_ciphertext_list; + expand_lwe_compact_ciphertext_list(&mut output_lwe_ciphertext_list, &self.ct_list); + } + + // Parallelism allowed + #[cfg(any(not(feature = "__wasm_api"), feature = "parallel-wasm-api"))] + { + use crate::core_crypto::prelude::par_expand_lwe_compact_ciphertext_list; + par_expand_lwe_compact_ciphertext_list(&mut output_lwe_ciphertext_list, &self.ct_list); + } + + output_lwe_ciphertext_list + .as_ref() + .chunks_exact(self.ct_list.lwe_size().0) + .map(|lwe_data| { + let ct = LweCiphertext::from_container( + lwe_data.to_vec(), + self.ct_list.ciphertext_modulus(), + ); + Ciphertext { + ct, + degree: self.degree, + message_modulus: self.message_modulus, + carry_modulus: self.carry_modulus, + pbs_order: self.pbs_order, + noise_level: self.noise_level, + } + }) + .collect::>() + } + + /// Deconstruct a [`CompactCiphertextList`] into its constituents. + pub fn into_raw_parts( + self, + ) -> ( + LweCompactCiphertextListOwned, + Degree, + MessageModulus, + CarryModulus, + PBSOrder, + NoiseLevel, + ) { + let Self { + ct_list, + degree, + message_modulus, + carry_modulus, + pbs_order, + noise_level, + } = self; + + ( + ct_list, + degree, + message_modulus, + carry_modulus, + pbs_order, + noise_level, + ) + } + + /// Construct a [`CompactCiphertextList`] from its constituents. + pub fn from_raw_parts( + ct_list: LweCompactCiphertextListOwned, + degree: Degree, + message_modulus: MessageModulus, + carry_modulus: CarryModulus, + pbs_order: PBSOrder, + noise_level: NoiseLevel, + ) -> Self { + Self { + ct_list, + degree, + message_modulus, + carry_modulus, + pbs_order, + noise_level, + } + } + + pub fn size_elements(&self) -> usize { + self.ct_list.size_elements() + } + + pub fn size_bytes(&self) -> usize { + self.ct_list.size_bytes() + } +} diff --git a/tfhe/src/shortint/ciphertext/compressed.rs b/tfhe/src/shortint/ciphertext/compressed.rs new file mode 100644 index 0000000000..5f1f2e4a0a --- /dev/null +++ b/tfhe/src/shortint/ciphertext/compressed.rs @@ -0,0 +1,111 @@ +//! Module with the definition of the Ciphertext. +use super::super::parameters::CiphertextConformanceParams; +use super::common::*; +use super::standard::Ciphertext; +use crate::conformance::ParameterSetConformant; +use crate::core_crypto::entities::*; +use crate::shortint::parameters::{CarryModulus, MessageModulus}; +use serde::{Deserialize, Serialize}; + +/// A structure representing a compressed shortint ciphertext. +/// It is used to homomorphically evaluate a shortint circuits. +/// Internally, it uses a LWE ciphertext. +#[derive(Clone, Serialize, Deserialize)] +pub struct CompressedCiphertext { + pub ct: SeededLweCiphertext, + pub degree: Degree, + pub message_modulus: MessageModulus, + pub carry_modulus: CarryModulus, + pub pbs_order: PBSOrder, + pub noise_level: NoiseLevel, +} + +impl ParameterSetConformant for CompressedCiphertext { + type ParameterSet = CiphertextConformanceParams; + + fn is_conformant(&self, param: &CiphertextConformanceParams) -> bool { + self.ct.is_conformant(¶m.ct_params) + && self.message_modulus == param.message_modulus + && self.carry_modulus == param.carry_modulus + && self.pbs_order == param.pbs_order + && self.degree == param.degree + && self.noise_level == param.noise_level + } +} + +impl CompressedCiphertext { + pub fn decompress(self) -> Ciphertext { + let Self { + ct, + degree, + message_modulus, + carry_modulus, + pbs_order, + noise_level, + } = self; + + Ciphertext { + ct: ct.decompress_into_lwe_ciphertext(), + degree, + message_modulus, + carry_modulus, + pbs_order, + noise_level, + } + } + + /// Deconstruct a [`CompressedCiphertext`] into its constituents. + pub fn into_raw_parts( + self, + ) -> ( + SeededLweCiphertext, + Degree, + MessageModulus, + CarryModulus, + PBSOrder, + NoiseLevel, + ) { + let Self { + ct, + degree, + message_modulus, + carry_modulus, + pbs_order, + noise_level, + } = self; + + ( + ct, + degree, + message_modulus, + carry_modulus, + pbs_order, + noise_level, + ) + } + + /// Construct a [`CompressedCiphertext`] from its constituents. + pub fn from_raw_parts( + ct: SeededLweCiphertext, + degree: Degree, + message_modulus: MessageModulus, + carry_modulus: CarryModulus, + pbs_order: PBSOrder, + noise_level: NoiseLevel, + ) -> Self { + Self { + ct, + degree, + message_modulus, + carry_modulus, + pbs_order, + noise_level, + } + } +} + +impl From for Ciphertext { + fn from(value: CompressedCiphertext) -> Self { + value.decompress() + } +} diff --git a/tfhe/src/shortint/ciphertext/mod.rs b/tfhe/src/shortint/ciphertext/mod.rs index 8038d23627..72ff19b095 100644 --- a/tfhe/src/shortint/ciphertext/mod.rs +++ b/tfhe/src/shortint/ciphertext/mod.rs @@ -1,897 +1,9 @@ -//! Module with the definition of the Ciphertext. -use crate::conformance::ParameterSetConformant; -pub use crate::core_crypto::commons::parameters::PBSOrder; -use crate::core_crypto::entities::*; -use crate::shortint::parameters::{CarryModulus, MessageModulus}; -use serde::{Deserialize, Serialize}; -use std::cmp; -use std::fmt::Debug; - -use super::parameters::{CiphertextConformanceParams, CiphertextListConformanceParams}; -use super::CheckError; - -/// Error for when a non trivial ciphertext was used when a trivial was expected -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct NotTrivialCiphertextError; - -impl std::fmt::Display for NotTrivialCiphertextError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "The ciphertext is a not a trivial ciphertext") - } -} - -impl std::error::Error for NotTrivialCiphertextError {} - -/// This tracks the maximal amount of noise of a [Ciphertext] -/// that guarantees the target p-error when doing a PBS on it -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] -pub struct MaxNoiseLevel(usize); - -impl MaxNoiseLevel { - pub fn new(value: usize) -> Self { - Self(value) - } - - pub fn get(&self) -> usize { - self.0 - } - - // This function is valid for current parameters as they guarantee the p-error for a norm2 noise - // limit equal to the norm2 limit which guarantees a clean padding bit - // - // TODO: remove this functions once noise norm2 constraint is decorrelated and stored in - // parameter sets - pub fn from_msg_carry_modulus( - msg_modulus: MessageModulus, - carry_modulus: CarryModulus, - ) -> Self { - Self((carry_modulus.0 * msg_modulus.0 - 1) / (msg_modulus.0 - 1)) - } - - pub fn validate(&self, noise_level: NoiseLevel) -> Result<(), CheckError> { - if noise_level.0 > self.0 { - return Err(CheckError::NoiseTooBig { - noise_level, - max_noise_level: *self, - }); - } - Ok(()) - } -} - -/// This tracks the amount of noise in a ciphertext. -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] -pub struct NoiseLevel(usize); - -impl NoiseLevel { - pub const NOMINAL: Self = Self(1); - pub const ZERO: Self = Self(0); - // To force a refresh no matter the tolerance of the server key, useful for serialization update - // for formats which did not have noise levels saved - pub const MAX: Self = Self(usize::MAX); - // As a safety measure the unknown noise level is set to the max value - pub const UNKNOWN: Self = Self::MAX; -} - -impl NoiseLevel { - pub fn get(&self) -> usize { - self.0 - } -} - -impl std::ops::AddAssign for NoiseLevel { - fn add_assign(&mut self, rhs: Self) { - self.0 = self.0.saturating_add(rhs.0); - } -} - -impl std::ops::Add for NoiseLevel { - type Output = Self; - - fn add(mut self, rhs: Self) -> Self { - self += rhs; - self - } -} - -impl std::ops::MulAssign for NoiseLevel { - fn mul_assign(&mut self, rhs: usize) { - self.0 = self.0.saturating_mul(rhs); - } -} - -impl std::ops::Mul for NoiseLevel { - type Output = Self; - - fn mul(mut self, rhs: usize) -> Self::Output { - self *= rhs; - - self - } -} - -/// Maximum value that the degree can reach. -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] -pub struct MaxDegree(usize); - -impl MaxDegree { - pub fn new(value: usize) -> Self { - Self(value) - } - - pub fn get(&self) -> usize { - self.0 - } - - pub fn from_msg_carry_modulus( - msg_modulus: MessageModulus, - carry_modulus: CarryModulus, - ) -> Self { - Self(carry_modulus.0 * msg_modulus.0 - 1) - } - - pub fn validate(&self, degree: Degree) -> Result<(), CheckError> { - if degree.get() > self.0 { - return Err(CheckError::CarryFull { - degree, - max_degree: *self, - }); - } - Ok(()) - } -} - -/// This tracks the number of operations that has been done. -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] -pub struct Degree(usize); - -impl Degree { - pub fn new(degree: usize) -> Self { - Self(degree) - } - - pub fn get(self) -> usize { - self.0 - } -} - -#[cfg(test)] -impl AsMut for Degree { - fn as_mut(&mut self) -> &mut usize { - &mut self.0 - } -} - -impl Degree { - pub(crate) fn after_bitxor(self, other: Self) -> Self { - let max = cmp::max(self.0, other.0); - let min = cmp::min(self.0, other.0); - let mut result = max; - - //Try every possibility to find the worst case - for i in 0..min + 1 { - if max ^ i > result { - result = max ^ i; - } - } - - Self(result) - } - - pub(crate) fn after_bitor(self, other: Self) -> Self { - let max = cmp::max(self.0, other.0); - let min = cmp::min(self.0, other.0); - let mut result = max; - - for i in 0..min + 1 { - if max | i > result { - result = max | i; - } - } - - Self(result) - } - - pub(crate) fn after_bitand(self, other: Self) -> Self { - Self(cmp::min(self.0, other.0)) - } - - pub(crate) fn after_left_shift(self, shift: u8, modulus: usize) -> Self { - let mut result = 0; - - for i in 0..self.0 + 1 { - let tmp = (i << shift) % modulus; - if tmp > result { - result = tmp; - } - } - - Self(result) - } - - #[allow(dead_code)] - pub(crate) fn after_pbs(self, f: F) -> Self - where - F: Fn(usize) -> usize, - { - let mut result = 0; - - for i in 0..self.0 + 1 { - let tmp = f(i); - if tmp > result { - result = tmp; - } - } - - Self(result) - } -} - -impl std::ops::AddAssign for Degree { - fn add_assign(&mut self, rhs: Self) { - self.0 = self.0.saturating_add(rhs.0); - } -} - -impl std::ops::Add for Degree { - type Output = Self; - - fn add(mut self, rhs: Self) -> Self { - self += rhs; - self - } -} - -impl std::ops::MulAssign for Degree { - fn mul_assign(&mut self, rhs: usize) { - self.0 = self.0.saturating_mul(rhs); - } -} - -impl std::ops::Mul for Degree { - type Output = Self; - - fn mul(mut self, rhs: usize) -> Self::Output { - self *= rhs; - - self - } -} - -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] -#[must_use] -pub struct Ciphertext { - pub ct: LweCiphertextOwned, - pub degree: Degree, - pub(crate) noise_level: NoiseLevel, - pub message_modulus: MessageModulus, - pub carry_modulus: CarryModulus, - pub pbs_order: PBSOrder, -} - -impl crate::named::Named for Ciphertext { - const NAME: &'static str = "shortint::Ciphertext"; -} - -impl ParameterSetConformant for Ciphertext { - type ParameterSet = CiphertextConformanceParams; - - fn is_conformant(&self, param: &CiphertextConformanceParams) -> bool { - self.ct.is_conformant(¶m.ct_params) - && self.message_modulus == param.message_modulus - && self.carry_modulus == param.carry_modulus - && self.pbs_order == param.pbs_order - && self.degree == param.degree - && self.noise_level == param.noise_level - } -} - -// Use destructuring to also have a compile error -// if ever a new member is added to Ciphertext -// and is not handled here. -// -// And a warning if a member is destructured but not used. -impl Clone for Ciphertext { - fn clone(&self) -> Self { - let Self { - ct: src_ct, - degree: src_degree, - message_modulus: src_message_modulus, - carry_modulus: src_carry_modulus, - pbs_order: src_pbs_order, - noise_level: src_noise_level, - } = self; - - Self { - ct: src_ct.clone(), - degree: *src_degree, - message_modulus: *src_message_modulus, - carry_modulus: *src_carry_modulus, - pbs_order: *src_pbs_order, - noise_level: *src_noise_level, - } - } - - fn clone_from(&mut self, source: &Self) { - let Self { - ct: dst_ct, - degree: dst_degree, - message_modulus: dst_message_modulus, - carry_modulus: dst_carry_modulus, - pbs_order: dst_pbs_order, - noise_level: dst_noise_level, - } = self; - - let Self { - ct: src_ct, - degree: src_degree, - message_modulus: src_message_modulus, - carry_modulus: src_carry_modulus, - pbs_order: src_pbs_order, - noise_level: src_noise_level, - } = source; - - if dst_ct.ciphertext_modulus() != src_ct.ciphertext_modulus() - || dst_ct.lwe_size() != src_ct.lwe_size() - { - *dst_ct = src_ct.clone(); - } else { - dst_ct.as_mut().copy_from_slice(src_ct.as_ref()); - } - *dst_degree = *src_degree; - *dst_message_modulus = *src_message_modulus; - *dst_carry_modulus = *src_carry_modulus; - *dst_pbs_order = *src_pbs_order; - *dst_noise_level = *src_noise_level; - } -} - -impl Ciphertext { - pub fn new( - ct: LweCiphertextOwned, - degree: Degree, - noise_level: NoiseLevel, - message_modulus: MessageModulus, - carry_modulus: CarryModulus, - pbs_order: PBSOrder, - ) -> Self { - Self { - ct, - degree, - noise_level, - message_modulus, - carry_modulus, - pbs_order, - } - } - pub fn carry_is_empty(&self) -> bool { - self.degree.get() < self.message_modulus.0 - } - - pub fn is_trivial(&self) -> bool { - self.noise_level() == NoiseLevel::ZERO - && self.ct.get_mask().as_ref().iter().all(|&x| x == 0u64) - } - - pub fn noise_level(&self) -> NoiseLevel { - self.noise_level - } - - pub fn set_noise_level(&mut self, noise_level: NoiseLevel) { - self.noise_level = noise_level; - } - - /// Decrypts a trivial ciphertext - /// - /// Trivial ciphertexts are ciphertexts which are not encrypted - /// meaning they can be decrypted by any key, or even without a key. - /// - /// For debugging it can be useful to use trivial ciphertext to speed up - /// execution, and use [Self::decrypt_trivial] to decrypt temporary values - /// and debug. - /// - /// - /// # Example - /// - /// ```rust - /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; - /// use tfhe::shortint::{gen_keys, Ciphertext}; - /// - /// // Generate the client key and the server key: - /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS); - /// - /// let msg = 1; - /// let msg2 = 2; - /// - /// // Trivial encryption - /// let trivial_ct = sks.create_trivial(msg); - /// let non_trivial_ct = cks.encrypt(msg2); - /// - /// let res = trivial_ct.decrypt_trivial(); - /// assert_eq!(Ok(1), res); - /// - /// let res = non_trivial_ct.decrypt_trivial(); - /// matches!(res, Err(_)); - /// - /// // Doing operations that mixes trivial and non trivial - /// // will always return a non trivial - /// let ct_res = sks.add(&trivial_ct, &non_trivial_ct); - /// let res = ct_res.decrypt_trivial(); - /// matches!(res, Err(_)); - /// - /// // Doing operations using only trivial ciphertexts - /// // will return a trivial - /// let ct_res = sks.add(&trivial_ct, &trivial_ct); - /// let res = ct_res.decrypt_trivial(); - /// assert_eq!(Ok(2), res); - /// ``` - pub fn decrypt_trivial(&self) -> Result { - self.decrypt_trivial_message_and_carry() - .map(|x| x % self.message_modulus.0 as u64) - } - - /// See [Self::decrypt_trivial]. - /// # Example - /// - /// ```rust - /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; - /// use tfhe::shortint::{gen_keys, Ciphertext}; - /// - /// // Generate the client key and the server key: - /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS); - /// - /// let msg = 2u64; - /// let clear = 3u64; - /// - /// let mut trivial_ct = sks.create_trivial(msg); - /// - /// sks.unchecked_scalar_add_assign(&mut trivial_ct, clear as u8); - /// - /// let res = trivial_ct.decrypt_trivial(); - /// let expected = (msg + clear) % PARAM_MESSAGE_2_CARRY_2_KS_PBS.message_modulus.0 as u64; - /// assert_eq!(Ok(expected), res); - /// - /// let res = trivial_ct.decrypt_trivial_message_and_carry(); - /// assert_eq!(Ok(msg + clear), res); - /// ``` - pub fn decrypt_trivial_message_and_carry(&self) -> Result { - if self.is_trivial() { - let delta = (1u64 << 63) / (self.message_modulus.0 * self.carry_modulus.0) as u64; - Ok(self.ct.get_body().data / delta) - } else { - Err(NotTrivialCiphertextError) - } - } -} - -/// A structure representing a compressed shortint ciphertext. -/// It is used to homomorphically evaluate a shortint circuits. -/// Internally, it uses a LWE ciphertext. -#[derive(Clone, Serialize, Deserialize)] -pub struct CompressedCiphertext { - pub ct: SeededLweCiphertext, - pub degree: Degree, - pub message_modulus: MessageModulus, - pub carry_modulus: CarryModulus, - pub pbs_order: PBSOrder, - pub noise_level: NoiseLevel, -} - -impl ParameterSetConformant for CompressedCiphertext { - type ParameterSet = CiphertextConformanceParams; - - fn is_conformant(&self, param: &CiphertextConformanceParams) -> bool { - self.ct.is_conformant(¶m.ct_params) - && self.message_modulus == param.message_modulus - && self.carry_modulus == param.carry_modulus - && self.pbs_order == param.pbs_order - && self.degree == param.degree - && self.noise_level == param.noise_level - } -} - -impl CompressedCiphertext { - pub fn decompress(self) -> Ciphertext { - let Self { - ct, - degree, - message_modulus, - carry_modulus, - pbs_order, - noise_level, - } = self; - - Ciphertext { - ct: ct.decompress_into_lwe_ciphertext(), - degree, - message_modulus, - carry_modulus, - pbs_order, - noise_level, - } - } - - /// Deconstruct a [`CompressedCiphertext`] into its constituents. - pub fn into_raw_parts( - self, - ) -> ( - SeededLweCiphertext, - Degree, - MessageModulus, - CarryModulus, - PBSOrder, - NoiseLevel, - ) { - let Self { - ct, - degree, - message_modulus, - carry_modulus, - pbs_order, - noise_level, - } = self; - - ( - ct, - degree, - message_modulus, - carry_modulus, - pbs_order, - noise_level, - ) - } - - /// Construct a [`CompressedCiphertext`] from its constituents. - pub fn from_raw_parts( - ct: SeededLweCiphertext, - degree: Degree, - message_modulus: MessageModulus, - carry_modulus: CarryModulus, - pbs_order: PBSOrder, - noise_level: NoiseLevel, - ) -> Self { - Self { - ct, - degree, - message_modulus, - carry_modulus, - pbs_order, - noise_level, - } - } -} - -impl From for Ciphertext { - fn from(value: CompressedCiphertext) -> Self { - value.decompress() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct CompactCiphertextList { - pub ct_list: LweCompactCiphertextListOwned, - pub degree: Degree, - pub message_modulus: MessageModulus, - pub carry_modulus: CarryModulus, - pub pbs_order: PBSOrder, - pub noise_level: NoiseLevel, -} - -impl ParameterSetConformant for CompactCiphertextList { - type ParameterSet = CiphertextListConformanceParams; - - fn is_conformant(&self, param: &CiphertextListConformanceParams) -> bool { - self.ct_list.is_conformant(¶m.ct_list_params) - && self.message_modulus == param.message_modulus - && self.carry_modulus == param.carry_modulus - && self.pbs_order == param.pbs_order - && self.degree == param.degree - && self.noise_level == param.noise_level - } -} - -impl CompactCiphertextList { - pub fn expand(&self) -> Vec { - let mut output_lwe_ciphertext_list = LweCiphertextList::new( - 0u64, - self.ct_list.lwe_size(), - self.ct_list.lwe_ciphertext_count(), - self.ct_list.ciphertext_modulus(), - ); - - // No parallelism allowed - #[cfg(all(feature = "__wasm_api", not(feature = "parallel-wasm-api")))] - { - use crate::core_crypto::prelude::expand_lwe_compact_ciphertext_list; - expand_lwe_compact_ciphertext_list(&mut output_lwe_ciphertext_list, &self.ct_list); - } - - // Parallelism allowed - #[cfg(any(not(feature = "__wasm_api"), feature = "parallel-wasm-api"))] - { - use crate::core_crypto::prelude::par_expand_lwe_compact_ciphertext_list; - par_expand_lwe_compact_ciphertext_list(&mut output_lwe_ciphertext_list, &self.ct_list); - } - - output_lwe_ciphertext_list - .as_ref() - .chunks_exact(self.ct_list.lwe_size().0) - .map(|lwe_data| { - let ct = LweCiphertext::from_container( - lwe_data.to_vec(), - self.ct_list.ciphertext_modulus(), - ); - Ciphertext { - ct, - degree: self.degree, - message_modulus: self.message_modulus, - carry_modulus: self.carry_modulus, - pbs_order: self.pbs_order, - noise_level: self.noise_level, - } - }) - .collect::>() - } - - /// Deconstruct a [`CompactCiphertextList`] into its constituents. - pub fn into_raw_parts( - self, - ) -> ( - LweCompactCiphertextListOwned, - Degree, - MessageModulus, - CarryModulus, - PBSOrder, - NoiseLevel, - ) { - let Self { - ct_list, - degree, - message_modulus, - carry_modulus, - pbs_order, - noise_level, - } = self; - - ( - ct_list, - degree, - message_modulus, - carry_modulus, - pbs_order, - noise_level, - ) - } - - /// Construct a [`CompactCiphertextList`] from its constituents. - pub fn from_raw_parts( - ct_list: LweCompactCiphertextListOwned, - degree: Degree, - message_modulus: MessageModulus, - carry_modulus: CarryModulus, - pbs_order: PBSOrder, - noise_level: NoiseLevel, - ) -> Self { - Self { - ct_list, - degree, - message_modulus, - carry_modulus, - pbs_order, - noise_level, - } - } - - pub fn size_elements(&self) -> usize { - self.ct_list.size_elements() - } - - pub fn size_bytes(&self) -> usize { - self.ct_list.size_bytes() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::shortint::CiphertextModulus; - - #[test] - fn test_clone_from_same_lwe_size_and_modulus_ci_run_filter() { - let mut c1 = Ciphertext { - ct: LweCiphertextOwned::from_container( - vec![1u64; 256], - CiphertextModulus::new_native(), - ), - degree: Degree::new(1), - message_modulus: MessageModulus(1), - carry_modulus: CarryModulus(1), - pbs_order: PBSOrder::KeyswitchBootstrap, - noise_level: NoiseLevel::NOMINAL, - }; - - let c2 = Ciphertext { - ct: LweCiphertextOwned::from_container( - vec![2323858949u64; 256], - CiphertextModulus::new_native(), - ), - degree: Degree::new(42), - message_modulus: MessageModulus(2), - carry_modulus: CarryModulus(2), - pbs_order: PBSOrder::BootstrapKeyswitch, - noise_level: NoiseLevel::NOMINAL, - }; - - assert_ne!(c1, c2); - - c1.clone_from(&c2); - assert_eq!(c1, c2); - } - - #[test] - fn test_clone_from_same_lwe_size_different_modulus_ci_run_filter() { - let mut c1 = Ciphertext { - ct: LweCiphertextOwned::from_container( - vec![1u64; 256], - CiphertextModulus::try_new_power_of_2(32).unwrap(), - ), - degree: Degree::new(1), - message_modulus: MessageModulus(1), - carry_modulus: CarryModulus(1), - pbs_order: PBSOrder::KeyswitchBootstrap, - noise_level: NoiseLevel::NOMINAL, - }; - - let c2 = Ciphertext { - ct: LweCiphertextOwned::from_container( - vec![2323858949u64; 256], - CiphertextModulus::new_native(), - ), - degree: Degree::new(42), - message_modulus: MessageModulus(2), - carry_modulus: CarryModulus(2), - pbs_order: PBSOrder::BootstrapKeyswitch, - noise_level: NoiseLevel::NOMINAL, - }; - - assert_ne!(c1, c2); - - c1.clone_from(&c2); - assert_eq!(c1, c2); - } - - #[test] - fn test_clone_from_different_lwe_size_same_modulus_ci_run_filter() { - let mut c1 = Ciphertext { - ct: LweCiphertextOwned::from_container( - vec![1u64; 512], - CiphertextModulus::new_native(), - ), - degree: Degree::new(1), - message_modulus: MessageModulus(1), - carry_modulus: CarryModulus(1), - pbs_order: PBSOrder::KeyswitchBootstrap, - noise_level: NoiseLevel::NOMINAL, - }; - - let c2 = Ciphertext { - ct: LweCiphertextOwned::from_container( - vec![2323858949u64; 256], - CiphertextModulus::new_native(), - ), - degree: Degree::new(42), - message_modulus: MessageModulus(2), - carry_modulus: CarryModulus(2), - pbs_order: PBSOrder::BootstrapKeyswitch, - noise_level: NoiseLevel::NOMINAL, - }; - - assert_ne!(c1, c2); - - c1.clone_from(&c2); - assert_eq!(c1, c2); - } - - #[test] - fn test_noise_level_ci_run_filter() { - use rand::{thread_rng, Rng}; - - let mut rng = thread_rng(); - - assert_eq!(NoiseLevel::UNKNOWN, NoiseLevel::MAX); - - let max_noise_level = NoiseLevel::MAX; - let random_addend = rng.gen::(); - let add = max_noise_level + NoiseLevel(random_addend); - assert_eq!(add, NoiseLevel::MAX); - - let random_positive_multiplier = rng.gen_range(1usize..=usize::MAX); - let mul = max_noise_level * random_positive_multiplier; - assert_eq!(mul, NoiseLevel::MAX); - } - - #[test] - fn test_max_noise_level_from_msg_carry_modulus() { - let max_noise_level = - MaxNoiseLevel::from_msg_carry_modulus(MessageModulus(4), CarryModulus(4)); - - assert_eq!(max_noise_level.0, 5); - } - - #[test] - fn degree_after_bitxor_ci_run_filter() { - let data = [ - (Degree(3), Degree(3), Degree(3)), - (Degree(3), Degree(1), Degree(3)), - (Degree(1), Degree(3), Degree(3)), - (Degree(3), Degree(2), Degree(3)), - (Degree(2), Degree(3), Degree(3)), - (Degree(2), Degree(2), Degree(3)), - (Degree(2), Degree(1), Degree(3)), - (Degree(1), Degree(2), Degree(3)), - (Degree(1), Degree(1), Degree(1)), - (Degree(0), Degree(1), Degree(1)), - (Degree(0), Degree(1), Degree(1)), - ]; - - for (lhs, rhs, expected) in data { - let result = lhs.after_bitxor(rhs); - assert_eq!( - result, expected, - "For a bitxor between variables of degree {lhs:?} and {rhs:?},\ - expected resulting degree: {expected:?}, got {result:?}" - ); - } - } - #[test] - fn degree_after_bitor_ci_run_filter() { - let data = [ - (Degree(3), Degree(3), Degree(3)), - (Degree(3), Degree(1), Degree(3)), - (Degree(1), Degree(3), Degree(3)), - (Degree(3), Degree(2), Degree(3)), - (Degree(2), Degree(3), Degree(3)), - (Degree(2), Degree(2), Degree(3)), - (Degree(2), Degree(1), Degree(3)), - (Degree(1), Degree(2), Degree(3)), - (Degree(1), Degree(1), Degree(1)), - (Degree(0), Degree(1), Degree(1)), - (Degree(0), Degree(1), Degree(1)), - ]; - - for (lhs, rhs, expected) in data { - let result = lhs.after_bitor(rhs); - assert_eq!( - result, expected, - "For a bitor between variables of degree {lhs:?} and {rhs:?},\ - expected resulting degree: {expected:?}, got {result:?}" - ); - } - } - - #[test] - fn degree_after_bitand_ci_run_filter() { - let data = [ - (Degree(3), Degree(3), Degree(3)), - (Degree(3), Degree(1), Degree(1)), - (Degree(1), Degree(3), Degree(1)), - (Degree(3), Degree(2), Degree(2)), - (Degree(2), Degree(3), Degree(2)), - (Degree(2), Degree(2), Degree(2)), - (Degree(2), Degree(1), Degree(1)), - (Degree(1), Degree(2), Degree(1)), - (Degree(1), Degree(1), Degree(1)), - (Degree(0), Degree(1), Degree(0)), - (Degree(0), Degree(1), Degree(0)), - ]; - - for (lhs, rhs, expected) in data { - let result = lhs.after_bitand(rhs); - assert_eq!( - result, expected, - "For a bitand between variables of degree {lhs:?} and {rhs:?},\ - expected resulting degree: {expected:?}, got {result:?}" - ); - } - } -} +mod common; +mod compact_list; +mod compressed; +mod standard; + +pub use common::*; +pub use compact_list::*; +pub use compressed::*; +pub use standard::*; diff --git a/tfhe/src/shortint/ciphertext/standard.rs b/tfhe/src/shortint/ciphertext/standard.rs new file mode 100644 index 0000000000..200c5f1e5c --- /dev/null +++ b/tfhe/src/shortint/ciphertext/standard.rs @@ -0,0 +1,316 @@ +//! Module with the definition of the Ciphertext. +use super::super::parameters::CiphertextConformanceParams; +use super::common::*; +use crate::conformance::ParameterSetConformant; +use crate::core_crypto::entities::*; +use crate::shortint::parameters::{CarryModulus, MessageModulus}; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +#[must_use] +pub struct Ciphertext { + pub ct: LweCiphertextOwned, + pub degree: Degree, + pub(crate) noise_level: NoiseLevel, + pub message_modulus: MessageModulus, + pub carry_modulus: CarryModulus, + pub pbs_order: PBSOrder, +} + +impl crate::named::Named for Ciphertext { + const NAME: &'static str = "shortint::Ciphertext"; +} + +impl ParameterSetConformant for Ciphertext { + type ParameterSet = CiphertextConformanceParams; + + fn is_conformant(&self, param: &CiphertextConformanceParams) -> bool { + self.ct.is_conformant(¶m.ct_params) + && self.message_modulus == param.message_modulus + && self.carry_modulus == param.carry_modulus + && self.pbs_order == param.pbs_order + && self.degree == param.degree + && self.noise_level == param.noise_level + } +} + +// Use destructuring to also have a compile error +// if ever a new member is added to Ciphertext +// and is not handled here. +// +// And a warning if a member is destructured but not used. +impl Clone for Ciphertext { + fn clone(&self) -> Self { + let Self { + ct: src_ct, + degree: src_degree, + message_modulus: src_message_modulus, + carry_modulus: src_carry_modulus, + pbs_order: src_pbs_order, + noise_level: src_noise_level, + } = self; + + Self { + ct: src_ct.clone(), + degree: *src_degree, + message_modulus: *src_message_modulus, + carry_modulus: *src_carry_modulus, + pbs_order: *src_pbs_order, + noise_level: *src_noise_level, + } + } + + fn clone_from(&mut self, source: &Self) { + let Self { + ct: dst_ct, + degree: dst_degree, + message_modulus: dst_message_modulus, + carry_modulus: dst_carry_modulus, + pbs_order: dst_pbs_order, + noise_level: dst_noise_level, + } = self; + + let Self { + ct: src_ct, + degree: src_degree, + message_modulus: src_message_modulus, + carry_modulus: src_carry_modulus, + pbs_order: src_pbs_order, + noise_level: src_noise_level, + } = source; + + if dst_ct.ciphertext_modulus() != src_ct.ciphertext_modulus() + || dst_ct.lwe_size() != src_ct.lwe_size() + { + *dst_ct = src_ct.clone(); + } else { + dst_ct.as_mut().copy_from_slice(src_ct.as_ref()); + } + *dst_degree = *src_degree; + *dst_message_modulus = *src_message_modulus; + *dst_carry_modulus = *src_carry_modulus; + *dst_pbs_order = *src_pbs_order; + *dst_noise_level = *src_noise_level; + } +} + +impl Ciphertext { + pub fn new( + ct: LweCiphertextOwned, + degree: Degree, + noise_level: NoiseLevel, + message_modulus: MessageModulus, + carry_modulus: CarryModulus, + pbs_order: PBSOrder, + ) -> Self { + Self { + ct, + degree, + noise_level, + message_modulus, + carry_modulus, + pbs_order, + } + } + pub fn carry_is_empty(&self) -> bool { + self.degree.get() < self.message_modulus.0 + } + + pub fn is_trivial(&self) -> bool { + self.noise_level() == NoiseLevel::ZERO + && self.ct.get_mask().as_ref().iter().all(|&x| x == 0u64) + } + + pub fn noise_level(&self) -> NoiseLevel { + self.noise_level + } + + pub fn set_noise_level(&mut self, noise_level: NoiseLevel) { + self.noise_level = noise_level; + } + + /// Decrypts a trivial ciphertext + /// + /// Trivial ciphertexts are ciphertexts which are not encrypted + /// meaning they can be decrypted by any key, or even without a key. + /// + /// For debugging it can be useful to use trivial ciphertext to speed up + /// execution, and use [Self::decrypt_trivial] to decrypt temporary values + /// and debug. + /// + /// + /// # Example + /// + /// ```rust + /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; + /// use tfhe::shortint::{gen_keys, Ciphertext}; + /// + /// // Generate the client key and the server key: + /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS); + /// + /// let msg = 1; + /// let msg2 = 2; + /// + /// // Trivial encryption + /// let trivial_ct = sks.create_trivial(msg); + /// let non_trivial_ct = cks.encrypt(msg2); + /// + /// let res = trivial_ct.decrypt_trivial(); + /// assert_eq!(Ok(1), res); + /// + /// let res = non_trivial_ct.decrypt_trivial(); + /// matches!(res, Err(_)); + /// + /// // Doing operations that mixes trivial and non trivial + /// // will always return a non trivial + /// let ct_res = sks.add(&trivial_ct, &non_trivial_ct); + /// let res = ct_res.decrypt_trivial(); + /// matches!(res, Err(_)); + /// + /// // Doing operations using only trivial ciphertexts + /// // will return a trivial + /// let ct_res = sks.add(&trivial_ct, &trivial_ct); + /// let res = ct_res.decrypt_trivial(); + /// assert_eq!(Ok(2), res); + /// ``` + pub fn decrypt_trivial(&self) -> Result { + self.decrypt_trivial_message_and_carry() + .map(|x| x % self.message_modulus.0 as u64) + } + + /// See [Self::decrypt_trivial]. + /// # Example + /// + /// ```rust + /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; + /// use tfhe::shortint::{gen_keys, Ciphertext}; + /// + /// // Generate the client key and the server key: + /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS); + /// + /// let msg = 2u64; + /// let clear = 3u64; + /// + /// let mut trivial_ct = sks.create_trivial(msg); + /// + /// sks.unchecked_scalar_add_assign(&mut trivial_ct, clear as u8); + /// + /// let res = trivial_ct.decrypt_trivial(); + /// let expected = (msg + clear) % PARAM_MESSAGE_2_CARRY_2_KS_PBS.message_modulus.0 as u64; + /// assert_eq!(Ok(expected), res); + /// + /// let res = trivial_ct.decrypt_trivial_message_and_carry(); + /// assert_eq!(Ok(msg + clear), res); + /// ``` + pub fn decrypt_trivial_message_and_carry(&self) -> Result { + if self.is_trivial() { + let delta = (1u64 << 63) / (self.message_modulus.0 * self.carry_modulus.0) as u64; + Ok(self.ct.get_body().data / delta) + } else { + Err(NotTrivialCiphertextError) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::shortint::CiphertextModulus; + + #[test] + fn test_clone_from_same_lwe_size_and_modulus_ci_run_filter() { + let mut c1 = Ciphertext { + ct: LweCiphertextOwned::from_container( + vec![1u64; 256], + CiphertextModulus::new_native(), + ), + degree: Degree::new(1), + message_modulus: MessageModulus(1), + carry_modulus: CarryModulus(1), + pbs_order: PBSOrder::KeyswitchBootstrap, + noise_level: NoiseLevel::NOMINAL, + }; + + let c2 = Ciphertext { + ct: LweCiphertextOwned::from_container( + vec![2323858949u64; 256], + CiphertextModulus::new_native(), + ), + degree: Degree::new(42), + message_modulus: MessageModulus(2), + carry_modulus: CarryModulus(2), + pbs_order: PBSOrder::BootstrapKeyswitch, + noise_level: NoiseLevel::NOMINAL, + }; + + assert_ne!(c1, c2); + + c1.clone_from(&c2); + assert_eq!(c1, c2); + } + + #[test] + fn test_clone_from_same_lwe_size_different_modulus_ci_run_filter() { + let mut c1 = Ciphertext { + ct: LweCiphertextOwned::from_container( + vec![1u64; 256], + CiphertextModulus::try_new_power_of_2(32).unwrap(), + ), + degree: Degree::new(1), + message_modulus: MessageModulus(1), + carry_modulus: CarryModulus(1), + pbs_order: PBSOrder::KeyswitchBootstrap, + noise_level: NoiseLevel::NOMINAL, + }; + + let c2 = Ciphertext { + ct: LweCiphertextOwned::from_container( + vec![2323858949u64; 256], + CiphertextModulus::new_native(), + ), + degree: Degree::new(42), + message_modulus: MessageModulus(2), + carry_modulus: CarryModulus(2), + pbs_order: PBSOrder::BootstrapKeyswitch, + noise_level: NoiseLevel::NOMINAL, + }; + + assert_ne!(c1, c2); + + c1.clone_from(&c2); + assert_eq!(c1, c2); + } + + #[test] + fn test_clone_from_different_lwe_size_same_modulus_ci_run_filter() { + let mut c1 = Ciphertext { + ct: LweCiphertextOwned::from_container( + vec![1u64; 512], + CiphertextModulus::new_native(), + ), + degree: Degree::new(1), + message_modulus: MessageModulus(1), + carry_modulus: CarryModulus(1), + pbs_order: PBSOrder::KeyswitchBootstrap, + noise_level: NoiseLevel::NOMINAL, + }; + + let c2 = Ciphertext { + ct: LweCiphertextOwned::from_container( + vec![2323858949u64; 256], + CiphertextModulus::new_native(), + ), + degree: Degree::new(42), + message_modulus: MessageModulus(2), + carry_modulus: CarryModulus(2), + pbs_order: PBSOrder::BootstrapKeyswitch, + noise_level: NoiseLevel::NOMINAL, + }; + + assert_ne!(c1, c2); + + c1.clone_from(&c2); + assert_eq!(c1, c2); + } +} diff --git a/tfhe/src/shortint/client_key/mod.rs b/tfhe/src/shortint/client_key/mod.rs index ffd9236393..3cb52c5dcf 100644 --- a/tfhe/src/shortint/client_key/mod.rs +++ b/tfhe/src/shortint/client_key/mod.rs @@ -1,5 +1,6 @@ //! Module with the definition of the ClientKey. +use super::PBSOrder; use crate::core_crypto::entities::*; use crate::core_crypto::prelude::decrypt_lwe_ciphertext; use crate::shortint::ciphertext::{Ciphertext, CompressedCiphertext}; @@ -9,8 +10,6 @@ use crate::shortint::CarryModulus; use serde::{Deserialize, Serialize}; use std::fmt::Debug; -use super::PBSOrder; - /// A structure containing the client key, which must be kept secret. /// /// In more details, it contains: diff --git a/tfhe/src/shortint/engine/public_side.rs b/tfhe/src/shortint/engine/public_side.rs index c83a978963..a927f5e474 100644 --- a/tfhe/src/shortint/engine/public_side.rs +++ b/tfhe/src/shortint/engine/public_side.rs @@ -213,7 +213,6 @@ impl ShortintEngine { public_key.lwe_public_key.ciphertext_modulus(), ); - // encryption encrypt_lwe_ciphertext_with_seeded_public_key( &public_key.lwe_public_key, &mut encrypted_ct, @@ -253,7 +252,6 @@ impl ShortintEngine { public_key.lwe_public_key.ciphertext_modulus(), ); - // encryption encrypt_lwe_ciphertext_with_public_key( &public_key.lwe_public_key, &mut encrypted_ct, @@ -293,7 +291,6 @@ impl ShortintEngine { public_key.lwe_public_key.ciphertext_modulus(), ); - // encryption encrypt_lwe_ciphertext_with_seeded_public_key( &public_key.lwe_public_key, &mut encrypted_ct, diff --git a/tfhe/src/shortint/key_switching_key/mod.rs b/tfhe/src/shortint/key_switching_key/mod.rs index 3b72922a2c..d373707e04 100644 --- a/tfhe/src/shortint/key_switching_key/mod.rs +++ b/tfhe/src/shortint/key_switching_key/mod.rs @@ -2,12 +2,10 @@ //! //! - [KeySwitchingKey] allows switching the keys of a ciphertext, from a cleitn key to another. +use crate::core_crypto::prelude::{keyswitch_lwe_ciphertext, LweKeyswitchKeyOwned}; use crate::shortint::engine::ShortintEngine; use crate::shortint::parameters::ShortintKeySwitchingParameters; use crate::shortint::{Ciphertext, ClientKey, ServerKey}; - -use crate::core_crypto::prelude::{keyswitch_lwe_ciphertext, LweKeyswitchKeyOwned}; - use serde::{Deserialize, Serialize}; #[cfg(test)] diff --git a/tfhe/src/shortint/keycache.rs b/tfhe/src/shortint/keycache.rs index a9bb698398..01a0961a21 100644 --- a/tfhe/src/shortint/keycache.rs +++ b/tfhe/src/shortint/keycache.rs @@ -1,5 +1,5 @@ +use crate::keycache::utils::named_params_impl; use crate::keycache::*; -use crate::named_params_impl; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; use crate::shortint::parameters::key_switching::*; diff --git a/tfhe/src/shortint/parameters/key_switching.rs b/tfhe/src/shortint/parameters/key_switching.rs index 7cf84f0bae..400826822d 100644 --- a/tfhe/src/shortint/parameters/key_switching.rs +++ b/tfhe/src/shortint/parameters/key_switching.rs @@ -1,5 +1,4 @@ use crate::shortint::parameters::{DecompositionBaseLog, DecompositionLevelCount}; - use serde::{Deserialize, Serialize}; /// A set of cryptographic parameters for homomorphic Shortint key switching. diff --git a/tfhe/src/shortint/parameters/mod.rs b/tfhe/src/shortint/parameters/mod.rs index 9bf2b010d3..41bc5972b1 100644 --- a/tfhe/src/shortint/parameters/mod.rs +++ b/tfhe/src/shortint/parameters/mod.rs @@ -23,15 +23,14 @@ pub mod parameters_wopbs; pub mod parameters_wopbs_message_carry; pub(crate) mod parameters_wopbs_prime_moduli; +use super::ciphertext::{Degree, NoiseLevel}; +use super::PBSOrder; pub use crate::core_crypto::commons::parameters::EncryptionKeyChoice; pub use key_switching::ShortintKeySwitchingParameters; pub use multi_bit::*; pub use parameters_compact_pk::*; pub use parameters_wopbs::WopbsParameters; -use super::ciphertext::{Degree, NoiseLevel}; -use super::PBSOrder; - /// The modulus of the message space. For a given plaintext $p$ we have the message $m$ defined as /// $m = p\bmod{MessageModulus}$ and so $0 <= m < MessageModulus$. /// diff --git a/tfhe/src/shortint/public_key/compact.rs b/tfhe/src/shortint/public_key/compact.rs index 93e4a13417..e19f8976f0 100644 --- a/tfhe/src/shortint/public_key/compact.rs +++ b/tfhe/src/shortint/public_key/compact.rs @@ -1,19 +1,14 @@ -use std::iter::once; - -use serde::{Deserialize, Serialize}; - use crate::core_crypto::prelude::{ - allocate_and_generate_new_seeded_lwe_compact_public_key, generate_lwe_compact_public_key, + allocate_and_generate_new_seeded_lwe_compact_public_key, + encrypt_lwe_ciphertext_with_compact_public_key, generate_lwe_compact_public_key, LweCiphertextCount, LweCiphertextOwned, LweCompactCiphertextListOwned, LweCompactPublicKeyOwned, Plaintext, PlaintextList, SeededLweCompactPublicKeyOwned, }; - -use crate::core_crypto::prelude::encrypt_lwe_ciphertext_with_compact_public_key; - use crate::shortint::ciphertext::{CompactCiphertextList, Degree, NoiseLevel}; -use crate::shortint::{Ciphertext, ClientKey, PBSOrder, ShortintParameterSet}; - use crate::shortint::engine::ShortintEngine; +use crate::shortint::{Ciphertext, ClientKey, PBSOrder, ShortintParameterSet}; +use serde::{Deserialize, Serialize}; +use std::iter::once; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct CompactPublicKey { diff --git a/tfhe/src/shortint/server_key/mod.rs b/tfhe/src/shortint/server_key/mod.rs index 236b008174..56d70386d9 100644 --- a/tfhe/src/shortint/server_key/mod.rs +++ b/tfhe/src/shortint/server_key/mod.rs @@ -23,7 +23,7 @@ pub use bivariate_pbs::{ pub use compressed::{CompressedServerKey, ShortintCompressedBootstrappingKey}; #[cfg(test)] -mod tests; +pub(crate) mod tests; use crate::core_crypto::algorithms::*; use crate::core_crypto::commons::parameters::{ @@ -33,6 +33,7 @@ use crate::core_crypto::commons::parameters::{ use crate::core_crypto::commons::traits::*; use crate::core_crypto::entities::*; use crate::core_crypto::fft_impl::fft64::math::fft::Fft; +use crate::core_crypto::prelude::ComputationBuffers; use crate::shortint::ciphertext::{Ciphertext, Degree, MaxDegree, MaxNoiseLevel, NoiseLevel}; use crate::shortint::client_key::ClientKey; use crate::shortint::engine::{ @@ -738,16 +739,49 @@ impl ServerKey { } pub fn apply_lookup_table_assign(&self, ct: &mut Ciphertext, acc: &LookupTableOwned) { - match self.pbs_order { - PBSOrder::KeyswitchBootstrap => { - // This updates the ciphertext degree - self.keyswitch_programmable_bootstrap_assign(ct, acc); - } - PBSOrder::BootstrapKeyswitch => { - // This updates the ciphertext degree - self.programmable_bootstrap_keyswitch_assign(ct, acc); + if ct.is_trivial() { + self.trivial_pbs_assign(ct, acc); + return; + } + + ShortintEngine::with_thread_local_mut(|engine| { + let (mut ciphertext_buffers, buffers) = engine.get_buffers(self); + match self.pbs_order { + PBSOrder::KeyswitchBootstrap => { + keyswitch_lwe_ciphertext( + &self.key_switching_key, + &ct.ct, + &mut ciphertext_buffers.buffer_lwe_after_ks, + ); + + apply_programmable_bootstrap( + &self.bootstrapping_key, + &ciphertext_buffers.buffer_lwe_after_ks, + &mut ct.ct, + acc, + buffers, + ); + } + PBSOrder::BootstrapKeyswitch => { + apply_programmable_bootstrap( + &self.bootstrapping_key, + &ct.ct, + &mut ciphertext_buffers.buffer_lwe_after_pbs, + acc, + buffers, + ); + + keyswitch_lwe_ciphertext( + &self.key_switching_key, + &ciphertext_buffers.buffer_lwe_after_pbs, + &mut ct.ct, + ); + } } - }; + }); + + ct.degree = acc.degree; + ct.set_noise_level(NoiseLevel::NOMINAL); } /// Compute a keyswitch and programmable bootstrap applying several functions on an input @@ -1111,6 +1145,11 @@ impl ServerKey { } fn trivial_pbs_assign(&self, ct: &mut Ciphertext, acc: &LookupTableOwned) { + #[cfg(feature = "pbs-stats")] + // We want to count trivial PBS in simulator mode + // In the non trivial case, this increment is done in the `apply_blind_rotate` function + let _ = PBS_COUNT.fetch_add(1, Ordering::Relaxed); + assert_eq!(ct.noise_level(), NoiseLevel::ZERO); let modulus_sup = self.message_modulus.0 * self.carry_modulus.0; let delta = (1_u64 << 63) / (self.message_modulus.0 * self.carry_modulus.0) as u64; @@ -1183,163 +1222,6 @@ impl ServerKey { outputs } - pub(crate) fn keyswitch_programmable_bootstrap_assign( - &self, - ct: &mut Ciphertext, - acc: &LookupTableOwned, - ) { - #[cfg(feature = "pbs-stats")] - let _ = PBS_COUNT.fetch_add(1, Ordering::Relaxed); - - if ct.is_trivial() { - self.trivial_pbs_assign(ct, acc); - return; - } - - ShortintEngine::with_thread_local_mut(|engine| { - // Compute the programmable bootstrapping with fixed test polynomial - let (mut ciphertext_buffers, buffers) = engine.get_buffers(self); - - // Compute a key switch - keyswitch_lwe_ciphertext( - &self.key_switching_key, - &ct.ct, - &mut ciphertext_buffers.buffer_lwe_after_ks, - ); - - match &self.bootstrapping_key { - ShortintBootstrappingKey::Classic(fourier_bsk) => { - let fft = Fft::new(fourier_bsk.polynomial_size()); - let fft = fft.as_view(); - buffers.resize( - programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement::( - fourier_bsk.glwe_size(), - fourier_bsk.polynomial_size(), - fft, - ) - .unwrap() - .unaligned_bytes_required(), - ); - let stack = buffers.stack(); - - // Compute a bootstrap - programmable_bootstrap_lwe_ciphertext_mem_optimized( - &ciphertext_buffers.buffer_lwe_after_ks, - &mut ct.ct, - &acc.acc, - fourier_bsk, - fft, - stack, - ); - } - ShortintBootstrappingKey::MultiBit { - fourier_bsk, - thread_count, - deterministic_execution, - } => { - if *deterministic_execution { - multi_bit_deterministic_programmable_bootstrap_lwe_ciphertext( - &ciphertext_buffers.buffer_lwe_after_ks, - &mut ct.ct, - &acc.acc, - fourier_bsk, - *thread_count, - ); - } else { - multi_bit_programmable_bootstrap_lwe_ciphertext( - &ciphertext_buffers.buffer_lwe_after_ks, - &mut ct.ct, - &acc.acc, - fourier_bsk, - *thread_count, - ); - } - } - }; - }); - - ct.degree = acc.degree; - ct.set_noise_level(NoiseLevel::NOMINAL); - } - - pub(crate) fn programmable_bootstrap_keyswitch_assign( - &self, - ct: &mut Ciphertext, - acc: &LookupTableOwned, - ) { - #[cfg(feature = "pbs-stats")] - let _ = PBS_COUNT.fetch_add(1, Ordering::Relaxed); - - if ct.is_trivial() { - self.trivial_pbs_assign(ct, acc); - return; - } - - ShortintEngine::with_thread_local_mut(|engine| { - let (mut ciphertext_buffers, buffers) = engine.get_buffers(self); - - match &self.bootstrapping_key { - ShortintBootstrappingKey::Classic(fourier_bsk) => { - let fft = Fft::new(fourier_bsk.polynomial_size()); - let fft = fft.as_view(); - buffers.resize( - programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement::( - fourier_bsk.glwe_size(), - fourier_bsk.polynomial_size(), - fft, - ) - .unwrap() - .unaligned_bytes_required(), - ); - let stack = buffers.stack(); - - // Compute a bootstrap - programmable_bootstrap_lwe_ciphertext_mem_optimized( - &ct.ct, - &mut ciphertext_buffers.buffer_lwe_after_pbs, - &acc.acc, - fourier_bsk, - fft, - stack, - ); - } - ShortintBootstrappingKey::MultiBit { - fourier_bsk, - thread_count, - deterministic_execution, - } => { - if *deterministic_execution { - multi_bit_deterministic_programmable_bootstrap_lwe_ciphertext( - &ct.ct, - &mut ciphertext_buffers.buffer_lwe_after_pbs, - &acc.acc, - fourier_bsk, - *thread_count, - ); - } else { - multi_bit_programmable_bootstrap_lwe_ciphertext( - &ct.ct, - &mut ciphertext_buffers.buffer_lwe_after_pbs, - &acc.acc, - fourier_bsk, - *thread_count, - ); - } - } - }; - - // Compute a key switch - keyswitch_lwe_ciphertext( - &self.key_switching_key, - &ciphertext_buffers.buffer_lwe_after_pbs, - &mut ct.ct, - ); - }); - - ct.degree = acc.degree; - ct.set_noise_level(NoiseLevel::NOMINAL); - } - pub(crate) fn keyswitch_programmable_bootstrap_many_lut( &self, ct: &Ciphertext, @@ -1362,52 +1244,12 @@ impl ServerKey { &mut ciphertext_buffers.buffer_lwe_after_ks, ); - match &self.bootstrapping_key { - ShortintBootstrappingKey::Classic(fourier_bsk) => { - let fft = Fft::new(fourier_bsk.polynomial_size()); - let fft = fft.as_view(); - buffers.resize( - programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement::( - fourier_bsk.glwe_size(), - fourier_bsk.polynomial_size(), - fft, - ) - .unwrap() - .unaligned_bytes_required(), - ); - let stack = buffers.stack(); - - // Compute the blind rotation - blind_rotate_assign_mem_optimized( - &ciphertext_buffers.buffer_lwe_after_ks, - &mut acc, - fourier_bsk, - fft, - stack, - ); - } - ShortintBootstrappingKey::MultiBit { - fourier_bsk, - thread_count, - deterministic_execution, - } => { - if *deterministic_execution { - multi_bit_deterministic_blind_rotate_assign( - &ciphertext_buffers.buffer_lwe_after_ks, - &mut acc, - fourier_bsk, - *thread_count, - ); - } else { - multi_bit_blind_rotate_assign( - &ciphertext_buffers.buffer_lwe_after_ks, - &mut acc, - fourier_bsk, - *thread_count, - ); - } - } - }; + apply_blind_rotate( + &self.bootstrapping_key, + &ciphertext_buffers.buffer_lwe_after_ks.as_view(), + &mut acc, + buffers, + ); }); // The accumulator has been rotated, we can now proceed with the various sample extractions @@ -1447,41 +1289,7 @@ impl ServerKey { // Compute the programmable bootstrapping with fixed test polynomial let (_, buffers) = engine.get_buffers(self); - match &self.bootstrapping_key { - ShortintBootstrappingKey::Classic(fourier_bsk) => { - let fft = Fft::new(fourier_bsk.polynomial_size()); - let fft = fft.as_view(); - buffers.resize( - programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement::( - fourier_bsk.glwe_size(), - fourier_bsk.polynomial_size(), - fft, - ) - .unwrap() - .unaligned_bytes_required(), - ); - let stack = buffers.stack(); - - // Compute the blind rotation - blind_rotate_assign_mem_optimized(&ct.ct, &mut acc, fourier_bsk, fft, stack); - } - ShortintBootstrappingKey::MultiBit { - fourier_bsk, - thread_count, - deterministic_execution, - } => { - if *deterministic_execution { - multi_bit_deterministic_blind_rotate_assign( - &ct.ct, - &mut acc, - fourier_bsk, - *thread_count, - ); - } else { - multi_bit_blind_rotate_assign(&ct.ct, &mut acc, fourier_bsk, *thread_count); - } - } - }; + apply_blind_rotate(&self.bootstrapping_key, &ct.ct, &mut acc, buffers); }); // The accumulator has been rotated, we can now proceed with the various sample extractions @@ -1685,3 +1493,70 @@ impl ServerKey { .min_by_key(|op| op.number_of_pbs()) } } + +pub(crate) fn apply_blind_rotate( + bootstrapping_key: &ShortintBootstrappingKey, + in_buffer: &LweCiphertext, + acc: &mut GlweCiphertext, + buffers: &mut ComputationBuffers, +) where + Scalar: UnsignedTorus + CastInto + CastFrom + Sync, + InputCont: Container, + OutputCont: ContainerMut, +{ + #[cfg(feature = "pbs-stats")] + let _ = PBS_COUNT.fetch_add(1, Ordering::Relaxed); + + match bootstrapping_key { + ShortintBootstrappingKey::Classic(fourier_bsk) => { + let fft = Fft::new(fourier_bsk.polynomial_size()); + let fft = fft.as_view(); + buffers.resize( + programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement::( + fourier_bsk.glwe_size(), + fourier_bsk.polynomial_size(), + fft, + ) + .unwrap() + .unaligned_bytes_required(), + ); + let stack = buffers.stack(); + + // Compute the blind rotation + blind_rotate_assign_mem_optimized(in_buffer, acc, fourier_bsk, fft, stack); + } + ShortintBootstrappingKey::MultiBit { + fourier_bsk, + thread_count, + deterministic_execution, + } => { + if *deterministic_execution { + multi_bit_deterministic_blind_rotate_assign( + in_buffer, + acc, + fourier_bsk, + *thread_count, + ); + } else { + multi_bit_blind_rotate_assign(in_buffer, acc, fourier_bsk, *thread_count); + } + } + }; +} + +pub(crate) fn apply_programmable_bootstrap( + bootstrapping_key: &ShortintBootstrappingKey, + in_buffer: &LweCiphertext, + out_buffer: &mut LweCiphertext, + acc: &LookupTableOwned, + buffers: &mut ComputationBuffers, +) where + InputCont: Container, + OutputCont: ContainerMut, +{ + let mut glwe_out = acc.acc.clone(); + + apply_blind_rotate(bootstrapping_key, in_buffer, &mut glwe_out, buffers); + + extract_lwe_sample_from_glwe_ciphertext(&glwe_out, out_buffer, MonomialDegree(0)); +} diff --git a/tfhe/src/shortint/server_key/mul.rs b/tfhe/src/shortint/server_key/mul.rs index 1f7ce82e58..a8b1b4e46a 100644 --- a/tfhe/src/shortint/server_key/mul.rs +++ b/tfhe/src/shortint/server_key/mul.rs @@ -2,7 +2,6 @@ use super::add::unchecked_add_assign; use super::{CiphertextNoiseDegree, ServerKey}; use crate::shortint::ciphertext::Degree; use crate::shortint::server_key::CheckError; - use crate::shortint::Ciphertext; impl ServerKey { diff --git a/tfhe/src/shortint/server_key/scalar_sub.rs b/tfhe/src/shortint/server_key/scalar_sub.rs index 50b7447a82..da62f90eda 100644 --- a/tfhe/src/shortint/server_key/scalar_sub.rs +++ b/tfhe/src/shortint/server_key/scalar_sub.rs @@ -1,5 +1,4 @@ use super::CiphertextNoiseDegree; - use crate::core_crypto::algorithms::*; use crate::core_crypto::entities::*; use crate::shortint::ciphertext::Degree; diff --git a/tfhe/src/shortint/server_key/tests/mod.rs b/tfhe/src/shortint/server_key/tests/mod.rs index a8f569b360..21febd51a1 100644 --- a/tfhe/src/shortint/server_key/tests/mod.rs +++ b/tfhe/src/shortint/server_key/tests/mod.rs @@ -1,3 +1,4 @@ pub mod noise_level; -pub mod shortint; +pub mod parametrized_test; +pub mod parametrized_test_bivariate_pbs_compliant; pub mod shortint_compact_pk; diff --git a/tfhe/src/shortint/server_key/tests/parametrized_test.rs b/tfhe/src/shortint/server_key/tests/parametrized_test.rs new file mode 100644 index 0000000000..499119273e --- /dev/null +++ b/tfhe/src/shortint/server_key/tests/parametrized_test.rs @@ -0,0 +1,1763 @@ +use crate::shortint::ciphertext::{Degree, NoiseLevel}; +use crate::shortint::keycache::KEY_CACHE; +use crate::shortint::parameters::*; +use crate::shortint::server_key::{LookupTableOwned, ManyLookupTableOwned}; +use rand::Rng; + +/// Number of assert in randomized tests +#[cfg(not(tarpaulin))] +const NB_TESTS: usize = 200; +/// Number of iterations in randomized tests for smart operations +#[cfg(not(tarpaulin))] +const NB_TESTS_SMART: usize = 10; +/// Number of sub tests used to increase degree of ciphertexts +#[cfg(not(tarpaulin))] +const NB_SUB_TEST_SMART: usize = 40; + +// Use lower numbers for coverage to ensure fast tests to counter balance slowdown due to code +// instrumentation +#[cfg(tarpaulin)] +const NB_TESTS: usize = 1; +/// Number of iterations in randomized tests for smart operations +#[cfg(tarpaulin)] +const NB_TESTS_SMART: usize = 1; +// This constant is tailored to trigger a message extract during operation processing. +// It's applicable for PARAM_MESSAGE_2_CARRY_2_KS_PBS parameters set. +#[cfg(tarpaulin)] +const NB_SUB_TEST_SMART: usize = 5; + +// Macro to generate tests for all parameter sets +#[cfg(not(tarpaulin))] +macro_rules! create_parametrized_test{ + ($name:ident { $($param:ident),* }) => { + ::paste::paste! { + $( + #[test] + fn []() { + $name($param) + } + )* + } + }; + ($name:ident)=> { + create_parametrized_test!($name + { + PARAM_MESSAGE_1_CARRY_1_KS_PBS, + PARAM_MESSAGE_1_CARRY_2_KS_PBS, + PARAM_MESSAGE_1_CARRY_3_KS_PBS, + PARAM_MESSAGE_1_CARRY_4_KS_PBS, + PARAM_MESSAGE_1_CARRY_5_KS_PBS, + PARAM_MESSAGE_1_CARRY_6_KS_PBS, + PARAM_MESSAGE_1_CARRY_7_KS_PBS, + PARAM_MESSAGE_2_CARRY_1_KS_PBS, + PARAM_MESSAGE_2_CARRY_2_KS_PBS, + PARAM_MESSAGE_2_CARRY_3_KS_PBS, + PARAM_MESSAGE_2_CARRY_4_KS_PBS, + PARAM_MESSAGE_2_CARRY_5_KS_PBS, + PARAM_MESSAGE_2_CARRY_6_KS_PBS, + PARAM_MESSAGE_3_CARRY_1_KS_PBS, + PARAM_MESSAGE_3_CARRY_2_KS_PBS, + PARAM_MESSAGE_3_CARRY_3_KS_PBS, + PARAM_MESSAGE_3_CARRY_4_KS_PBS, + PARAM_MESSAGE_3_CARRY_5_KS_PBS, + PARAM_MESSAGE_4_CARRY_1_KS_PBS, + PARAM_MESSAGE_4_CARRY_2_KS_PBS, + PARAM_MESSAGE_4_CARRY_3_KS_PBS, + PARAM_MESSAGE_4_CARRY_4_KS_PBS, + PARAM_MESSAGE_5_CARRY_1_KS_PBS, + PARAM_MESSAGE_5_CARRY_2_KS_PBS, + PARAM_MESSAGE_5_CARRY_3_KS_PBS, + PARAM_MESSAGE_6_CARRY_1_KS_PBS, + PARAM_MESSAGE_6_CARRY_2_KS_PBS, + PARAM_MESSAGE_7_CARRY_1_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_1_CARRY_1_GROUP_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_3_CARRY_3_GROUP_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_1_CARRY_1_GROUP_3_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_3_CARRY_3_GROUP_3_KS_PBS + }); + }; +} + +// Test against a small subset of parameters to speed up coverage tests +#[cfg(tarpaulin)] +macro_rules! create_parametrized_test{ + ($name:ident { $($param:ident),* }) => { + ::paste::paste! { + $( + #[test] + fn []() { + $name($param) + } + )* + } + }; + ($name:ident)=> { + create_parametrized_test!($name + { + PARAM_MESSAGE_2_CARRY_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS + }); + }; +} + +pub(crate) use create_parametrized_test; + +//These functions are compatible with all parameter sets. +create_parametrized_test!(shortint_encrypt_decrypt); +create_parametrized_test!(shortint_encrypt_with_message_modulus_decrypt); +create_parametrized_test!(shortint_encrypt_decrypt_without_padding); +create_parametrized_test!(shortint_keyswitch_bootstrap); +create_parametrized_test!(shortint_keyswitch_programmable_bootstrap); +create_parametrized_test!(shortint_keyswitch_programmable_bootstrap_many_lut); +create_parametrized_test!(shortint_carry_extract); +create_parametrized_test!(shortint_message_extract); +create_parametrized_test!(shortint_generate_lookup_table); +create_parametrized_test!(shortint_unchecked_add); +create_parametrized_test!(shortint_smart_add); +create_parametrized_test!(shortint_default_add); +create_parametrized_test!(shortint_smart_mul_lsb); +create_parametrized_test!(shortint_default_mul_lsb); +create_parametrized_test!(shortint_unchecked_neg); +create_parametrized_test!(shortint_smart_neg); +create_parametrized_test!(shortint_default_neg); +create_parametrized_test!(shortint_unchecked_scalar_add); +create_parametrized_test!(shortint_smart_scalar_add); +create_parametrized_test!(shortint_default_scalar_add); +create_parametrized_test!(shortint_unchecked_scalar_sub); +create_parametrized_test!(shortint_smart_scalar_sub); +create_parametrized_test!(shortint_default_scalar_sub); +create_parametrized_test!(shortint_unchecked_scalar_mul); +create_parametrized_test!(shortint_smart_scalar_mul); +create_parametrized_test!(shortint_default_scalar_mul); +create_parametrized_test!(shortint_unchecked_right_shift); +create_parametrized_test!(shortint_default_right_shift); +create_parametrized_test!(shortint_unchecked_left_shift); +create_parametrized_test!(shortint_default_left_shift); +create_parametrized_test!(shortint_unchecked_sub); +create_parametrized_test!(shortint_smart_sub); +create_parametrized_test!(shortint_default_sub); +create_parametrized_test!(shortint_mul_small_carry); +create_parametrized_test!(shortint_mux); +create_parametrized_test!(shortint_unchecked_scalar_bitand); +create_parametrized_test!(shortint_unchecked_scalar_bitor); +create_parametrized_test!(shortint_unchecked_scalar_bitxor); +create_parametrized_test!(shortint_smart_scalar_bitand); +create_parametrized_test!(shortint_smart_scalar_bitor); +create_parametrized_test!(shortint_smart_scalar_bitxor); +create_parametrized_test!(shortint_default_scalar_bitand); +create_parametrized_test!(shortint_default_scalar_bitor); +create_parametrized_test!(shortint_default_scalar_bitxor); +create_parametrized_test!(shortint_trivial_pbs); +create_parametrized_test!(shortint_trivial_pbs_many_lut); +create_parametrized_test!( + shortint_encrypt_with_message_modulus_unchecked_mul_lsb_small_carry_and_add +); +create_parametrized_test!( + shortint_encrypt_with_message_and_carry_modulus_unchecked_mul_lsb_small_carry_and_add +); + +// Public key tests are limited to small parameter sets to avoid blowing up memory and large testing +// times. Compressed keygen takes 20 minutes for params 2_2 and for encryption as well. +// 2_2 uncompressed keys take ~2 GB and 3_3 about ~34 GB, hence why we stop at 2_2. +#[cfg(not(tarpaulin))] +#[test] +fn test_shortint_compressed_public_key_smart_add_param_message_1_carry_1_ks_pbs() { + shortint_compressed_public_key_smart_add(PARAM_MESSAGE_1_CARRY_1_KS_PBS); +} + +#[cfg(not(tarpaulin))] +#[test] +fn test_shortint_public_key_smart_add_param_message_1_carry_1_ks_pbs() { + shortint_public_key_smart_add(PARAM_MESSAGE_1_CARRY_1_KS_PBS); +} + +#[cfg(not(tarpaulin))] +#[test] +fn test_shortint_public_key_smart_add_param_message_2_carry_2_ks_pbs() { + shortint_public_key_smart_add(PARAM_MESSAGE_2_CARRY_2_KS_PBS); +} + +fn shortint_encrypt_decrypt

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let cks = keys.client_key(); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % modulus; + + let ct = cks.encrypt(clear); + + let dec = cks.decrypt(&ct); + + assert_eq!(clear, dec); + } +} + +fn shortint_encrypt_with_message_modulus_decrypt

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let cks = keys.client_key(); + + let mut rng = rand::thread_rng(); + + for _ in 0..NB_TESTS { + let mut modulus = rng.gen::() % cks.parameters.message_modulus().0 as u64; + while modulus == 0 { + modulus = rng.gen::() % cks.parameters.message_modulus().0 as u64; + } + + let clear = rng.gen::() % modulus; + + let ct = cks.encrypt_with_message_modulus(clear, MessageModulus(modulus as usize)); + + let dec = cks.decrypt(&ct); + + assert_eq!(clear, dec); + } +} + +fn shortint_encrypt_decrypt_without_padding

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let cks = keys.client_key(); + + let mut rng = rand::thread_rng(); + + // We assume that the modulus is the largest possible without padding bit + let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % modulus; + + let ct = cks.encrypt_without_padding(clear); + + let dec = cks.decrypt_message_and_carry_without_padding(&ct); + + assert_eq!(clear, dec); + } +} + +fn shortint_keyswitch_bootstrap

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mut failures = 0; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.message_extract(&ctxt_0); + + let dec_res = cks.decrypt(&ct_res); + + if clear_0 != dec_res { + failures += 1; + } + } + + println!("fail_rate = {failures}/{NB_TESTS}"); + assert_eq!(0, failures); +} + +fn shortint_keyswitch_programmable_bootstrap

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let acc = sks.generate_msg_lookup_table(|n| n, cks.parameters.message_modulus()); + + let ct_res = sks.apply_lookup_table(&ctxt_0, &acc); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0, dec_res); + } +} + +fn shortint_keyswitch_programmable_bootstrap_many_lut

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let msg_modulus = cks.parameters.message_modulus().0 as u64; + let carry_modulus = cks.parameters.carry_modulus().0 as u64; + let modulus_sup = msg_modulus * carry_modulus; + + let f1 = |x: u64| x * x % msg_modulus; + let f2 = |x: u64| (x.count_ones() as u64) % msg_modulus; + let f3 = |x: u64| (x.wrapping_add(1)) % msg_modulus; + let f4 = |x: u64| (x.wrapping_sub(1)) % msg_modulus; + let f5 = |x: u64| (x * 2) % msg_modulus; + let f6 = |x: u64| (x * 3) % msg_modulus; + let f7 = |x: u64| (x / 2) % msg_modulus; + let f8 = |x: u64| (x / 3) % msg_modulus; + + let functions: &[&dyn Fn(u64) -> u64] = &[&f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8]; + let max_fn_count = functions.len().min(modulus_sup as usize / 2); + let per_fn_tests = (NB_TESTS / max_fn_count).max(1); + for fn_count in 1..=max_fn_count { + let functions = &functions[..fn_count]; + + // Depending on how many functions we are evaluating the maximum valid message modulus is + // lower than what the parameters support + let effective_msg_modulus = msg_modulus.min(modulus_sup / fn_count as u64); + + // Generate the many lut once for the current set of functions + let acc = sks.generate_many_lookup_table(functions); + for _ in 0..per_fn_tests { + let clear_0 = rng.gen::() % effective_msg_modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let vec_res = sks.apply_many_lookup_table(&ctxt_0, &acc); + + for (fn_idx, (res, function)) in vec_res.iter().zip(functions).enumerate() { + let dec = cks.decrypt(res); + let function_eval = function(clear_0); + + assert_eq!( + dec, function_eval, + "Evaluation of function #{fn_idx} on {clear_0} failed, \ + got {dec}, expected {function_eval}", + ); + } + } + } +} + +fn shortint_carry_extract

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let full_modulus = + (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; + + let msg_modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % full_modulus; + + let ctxt = cks.unchecked_encrypt(clear); + + let ct_carry = sks.carry_extract(&ctxt); + + let dec = cks.decrypt_message_and_carry(&ct_carry); + + println!( + "msg = {clear}, modulus = {msg_modulus}, msg/modulus = {}", + clear / msg_modulus + ); + assert_eq!(clear / msg_modulus, dec); + } +} + +fn shortint_message_extract

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let full_modulus = + (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; + + let msg_modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % full_modulus; + + let ctxt = cks.unchecked_encrypt(clear); + + let ct_msg = sks.message_extract(&ctxt); + + let dec = cks.decrypt(&ct_msg); + + assert_eq!(clear % msg_modulus, dec); + } +} + +fn shortint_generate_lookup_table

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let double = |x| (2 * x) % sks.message_modulus.0 as u64; + let acc = sks.generate_lookup_table(double); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % modulus; + + let ct = cks.encrypt(clear); + + let ct_res = sks.apply_lookup_table(&ct, &acc); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear * 2) % modulus, dec_res); + } +} + +fn shortint_unchecked_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_add(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + println!( + "The parameters set is CARRY_{}_MESSAGE_{}", + cks.parameters.carry_modulus().0, + cks.parameters.message_modulus().0 + ); + assert_eq!((clear_0 + clear_1) % modulus, dec_res); + } +} + +fn shortint_smart_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS_SMART { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + let mut ct_res = sks.smart_add(&mut ctxt_0, &mut ctxt_1); + let mut clear = clear_0 + clear_1; + + for _ in 0..NB_SUB_TEST_SMART { + println!("SUB TEST"); + ct_res = sks.smart_add(&mut ct_res, &mut ctxt_0); + clear += clear_0; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + } + } +} + +fn shortint_default_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.add(&ctxt_0, &ctxt_1); + let clear_res = clear_0 + clear_1; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_res % modulus, dec_res); + } +} + +fn shortint_compressed_public_key_smart_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let pk = crate::shortint::CompressedPublicKey::new(cks); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS_SMART { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = pk.encrypt(clear_0); + + let mut ctxt_1 = pk.encrypt(clear_1); + + let mut ct_res = sks.smart_add(&mut ctxt_0, &mut ctxt_1); + let mut clear = clear_0 + clear_1; + + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_add(&mut ct_res, &mut ctxt_0); + clear += clear_0; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + } + } +} + +fn shortint_public_key_smart_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let pk = crate::shortint::PublicKey::new(cks); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS_SMART { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = pk.encrypt(clear_0); + + let mut ctxt_1 = pk.encrypt(clear_1); + + let mut ct_res = sks.smart_add(&mut ctxt_0, &mut ctxt_1); + let mut clear = clear_0 + clear_1; + + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_add(&mut ct_res, &mut ctxt_0); + clear += clear_0; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + } + } +} + +fn shortint_unchecked_scalar_bitxor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.unchecked_scalar_bitxor(&ctxt_0, clear_1 as u8); + assert_eq!( + ct_res.degree, + ctxt_0.degree.after_bitxor(Degree::new(clear_1 as usize)) + ); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 ^ clear_1, dec_res); + } +} + +fn shortint_unchecked_scalar_bitor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.unchecked_scalar_bitor(&ctxt_0, clear_1 as u8); + assert_eq!( + ct_res.degree, + ctxt_0.degree.after_bitor(Degree::new(clear_1 as usize)) + ); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 | clear_1, dec_res); + } +} + +fn shortint_unchecked_scalar_bitand

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.unchecked_scalar_bitand(&ctxt_0, clear_1 as u8); + assert_eq!( + ct_res.degree, + ctxt_0.degree.after_bitand(Degree::new(clear_1 as usize)) + ); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 & clear_1, dec_res); + } +} + +fn shortint_smart_scalar_bitand

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + + clear_0 *= scalar as u64; + + let ct_res = sks.smart_scalar_bitand(&mut ctxt_0, clear_1 as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 & clear_1, dec_res); + } +} + +fn shortint_default_scalar_bitand

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + + clear_0 *= scalar as u64; + + let ct_res = sks.scalar_bitand(&ctxt_0, clear_1 as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 & clear_1, dec_res); + } +} + +fn shortint_smart_scalar_bitor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + + clear_0 *= scalar as u64; + + let ct_res = sks.smart_scalar_bitor(&mut ctxt_0, clear_1 as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 | clear_1) % modulus, dec_res); + } +} + +fn shortint_default_scalar_bitor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + + clear_0 *= scalar as u64; + + let ct_res = sks.scalar_bitor(&ctxt_0, clear_1 as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 | clear_1) % modulus, dec_res); + } +} + +fn shortint_smart_scalar_bitxor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + + clear_0 *= scalar as u64; + + let ct_res = sks.smart_scalar_bitxor(&mut ctxt_0, clear_1 as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 ^ clear_1) % modulus, dec_res); + } +} + +fn shortint_default_scalar_bitxor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + + clear_0 *= scalar as u64; + + let ct_res = sks.scalar_bitxor(&ctxt_0, clear_1 as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 ^ clear_1) % modulus, dec_res); + } +} + +fn shortint_smart_mul_lsb

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS_SMART { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + let mut ct_res = sks.smart_mul_lsb(&mut ctxt_0, &mut ctxt_1); + + let mut clear = clear_0 * clear_1; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_mul_lsb(&mut ct_res, &mut ctxt_0); + clear = (clear * clear_0) % modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear, dec_res); + } + } +} + +fn shortint_default_mul_lsb

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.mul_lsb(&ctxt_0, &ctxt_1); + + let clear = clear_0 * clear_1; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + } +} + +fn shortint_unchecked_neg

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % modulus; + + let ctxt = cks.encrypt(clear); + + let ct_tmp = sks.unchecked_neg(&ctxt); + + let dec = cks.decrypt(&ct_tmp); + + let clear_result = clear.wrapping_neg() % modulus; + + assert_eq!(clear_result, dec); + } +} + +fn shortint_smart_neg

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS_SMART { + let clear1 = rng.gen::() % modulus; + + let mut ct1 = cks.encrypt(clear1); + + let mut ct_res = sks.smart_neg(&mut ct1); + + let mut clear_result = clear1.wrapping_neg() % modulus; + + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_neg(&mut ct_res); + + clear_result = clear_result.wrapping_neg() % modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_result, dec_res); + } + } +} + +fn shortint_default_neg

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear1 = rng.gen::() % modulus; + + let ct1 = cks.encrypt(clear1); + + let ct_res = sks.neg(&ct1); + + let clear_result = clear1.wrapping_neg() % modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_result, dec_res); + } +} + +fn shortint_unchecked_scalar_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let message_modulus = cks.parameters.message_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % message_modulus; + + let scalar = rng.gen::() % message_modulus; + + let ct = cks.encrypt(clear as u64); + + let ct_res = sks.unchecked_scalar_add(&ct, scalar); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear + scalar) % message_modulus, dec_res as u8); + } +} + +fn shortint_smart_scalar_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u8; + + for _ in 0..NB_TESTS_SMART { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = cks.encrypt(clear_0 as u64); + + let mut ct_res = sks.smart_scalar_add(&mut ctxt_0, clear_1); + + let mut clear = (clear_0 + clear_1) % modulus; + + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_scalar_add(&mut ct_res, clear_1); + clear = (clear + clear_1) % modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear, dec_res as u8); + } + } +} + +fn shortint_default_scalar_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0 as u64); + + let ct_res = sks.scalar_add(&ctxt_0, clear_1); + + let clear = (clear_0 + clear_1) % modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear, dec_res as u8); + } +} + +fn shortint_unchecked_scalar_sub

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let message_modulus = cks.parameters.message_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % message_modulus; + + let scalar = rng.gen::() % message_modulus; + + let ct = cks.encrypt(clear as u64); + + let ct_res = sks.unchecked_scalar_sub(&ct, scalar); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear - scalar) % message_modulus, dec_res as u8); + } +} + +fn shortint_smart_scalar_sub

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u8; + + for _ in 0..NB_TESTS_SMART { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = cks.encrypt(clear_0 as u64); + + let mut ct_res = sks.smart_scalar_sub(&mut ctxt_0, clear_1); + + let mut clear = (clear_0 - clear_1) % modulus; + + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_scalar_sub(&mut ct_res, clear_1); + clear = (clear - clear_1) % modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear, dec_res as u8); + } + } +} + +fn shortint_default_scalar_sub

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0 as u64); + + let ct_res = sks.scalar_sub(&ctxt_0, clear_1); + + let clear = (clear_0.wrapping_sub(clear_1)) % modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear, dec_res as u8); + } +} + +fn shortint_unchecked_scalar_mul

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let message_modulus = cks.parameters.message_modulus().0 as u8; + let carry_modulus = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % message_modulus; + + let scalar = rng.gen::() % carry_modulus; + + let ct = cks.encrypt(clear as u64); + + let ct_res = sks.unchecked_scalar_mul(&ct, scalar); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear * scalar) % message_modulus, dec_res as u8); + } +} + +fn shortint_smart_scalar_mul

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u8; + + let scalar_modulus = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS_SMART { + let clear = rng.gen::() % modulus; + + let scalar = rng.gen::() % scalar_modulus; + + let mut ct = cks.encrypt(clear as u64); + + let mut ct_res = sks.smart_scalar_mul(&mut ct, scalar); + + let mut clear_res = clear * scalar; + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_scalar_mul(&mut ct_res, scalar); + clear_res = (clear_res * scalar) % modulus; + } + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_res, dec_res as u8); + } +} + +fn shortint_default_scalar_mul

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u8; + + let scalar_modulus = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % modulus; + + let scalar = rng.gen::() % scalar_modulus; + + let ct = cks.encrypt(clear as u64); + + let ct_res = sks.scalar_mul(&ct, scalar); + + let clear_res = (clear * scalar) % modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_res, dec_res as u8); + } +} + +fn shortint_unchecked_right_shift

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let shift = rng.gen::() % 2; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.unchecked_scalar_right_shift(&ctxt_0, shift as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 >> shift, dec_res); + } +} + +fn shortint_default_right_shift

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let shift = rng.gen::() % 2; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.scalar_right_shift(&ctxt_0, shift as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 >> shift, dec_res); + } +} + +fn shortint_unchecked_left_shift

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let shift = rng.gen::() % 2; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.unchecked_scalar_left_shift(&ctxt_0, shift as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 << shift) % modulus, dec_res); + } +} + +fn shortint_default_left_shift

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let shift = rng.gen::() % 2; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.scalar_left_shift(&ctxt_0, shift as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 << shift) % modulus, dec_res); + } +} + +fn shortint_unchecked_sub

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + for _ in 0..NB_TESTS { + let clear1 = rng.gen::() % modulus; + let clear2 = rng.gen::() % modulus; + + let ctxt_1 = cks.encrypt(clear1); + let ctxt_2 = cks.encrypt(clear2); + + let ct_tmp = sks.unchecked_sub(&ctxt_1, &ctxt_2); + + let dec = cks.decrypt(&ct_tmp); + + let clear_result = (clear1 - clear2) % modulus; + assert_eq!(clear_result, dec % modulus); + } +} + +fn shortint_smart_sub

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS_SMART { + let clear1 = rng.gen::() % modulus; + let clear2 = rng.gen::() % modulus; + + let mut ct1 = cks.encrypt(clear1); + let mut ct2 = cks.encrypt(clear2); + + let mut ct_res = sks.smart_sub(&mut ct1, &mut ct2); + + let mut clear_res = (clear1 - clear2) % modulus; + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_sub(&mut ct_res, &mut ct2); + clear_res = (clear_res - clear2) % modulus; + } + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_res, dec_res); + } +} + +fn shortint_default_sub

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear1 = rng.gen::() % modulus; + let clear2 = rng.gen::() % modulus; + + let ct1 = cks.encrypt(clear1); + let ct2 = cks.encrypt(clear2); + + let ct_res = sks.sub(&ct1, &ct2); + + let clear_res = (clear1.wrapping_sub(clear2)) % modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_res, dec_res); + } +} + +fn shortint_mul_small_carry

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..50 { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let ctxt_zero = cks.encrypt(clear_0); + + let ctxt_one = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_mul_lsb_small_carry(&ctxt_zero, &ctxt_one); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 * clear_1) % modulus, dec_res % modulus); + } +} + +fn shortint_encrypt_with_message_modulus_unchecked_mul_lsb_small_carry_and_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + let full_mod = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; + + for _ in 0..NB_TESTS { + let modulus = rng.gen_range(1..full_mod / 2); + + let clear1 = rng.gen::() % modulus; + let clear2 = rng.gen::() % modulus; + + let ct1 = cks.encrypt_with_message_modulus(clear1, MessageModulus(modulus as usize)); + let ct2 = cks.encrypt_with_message_modulus(clear2, MessageModulus(modulus as usize)); + + println!("MUL SMALL CARRY:: clear1 = {clear1}, clear2 = {clear2}, mod = {modulus}"); + let ct_res = sks.unchecked_mul_lsb_small_carry(&ct1, &ct2); + assert_eq!( + (clear1 * clear2) % modulus, + cks.decrypt_message_and_carry(&ct_res) % modulus + ); + + println!("ADD:: clear1 = {clear1}, clear2 = {clear2}, mod = {modulus}"); + let ct_res = sks.unchecked_add(&ct1, &ct2); + assert_eq!((clear1 + clear2), cks.decrypt_message_and_carry(&ct_res)); + } +} + +fn shortint_encrypt_with_message_and_carry_modulus_unchecked_mul_lsb_small_carry_and_add

( + param: P, +) where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let param_msg_mod = cks.parameters.message_modulus().0; + let param_carry_mod = cks.parameters.carry_modulus().0; + + for _ in 0..NB_TESTS { + let msg_modulus = rng.gen_range(2u64..=param_msg_mod as u64); + let carry_modulus = rng.gen_range(2u64..=param_carry_mod as u64); + + let modulus = msg_modulus * carry_modulus; + + let clear1 = rng.gen::() % msg_modulus; + let clear2 = rng.gen::() % msg_modulus; + + let ct1 = cks.encrypt_with_message_and_carry_modulus( + clear1, + MessageModulus(msg_modulus as usize), + CarryModulus(carry_modulus as usize), + ); + let ct2 = cks.encrypt_with_message_and_carry_modulus( + clear2, + MessageModulus(msg_modulus as usize), + CarryModulus(carry_modulus as usize), + ); + + println!("MUL SMALL CARRY:: clear1 = {clear1}, clear2 = {clear2}, msg_mod = {msg_modulus}, carry_mod = {carry_modulus}"); + let ct_res = sks.unchecked_mul_lsb_small_carry(&ct1, &ct2); + assert_eq!( + (clear1 * clear2) % msg_modulus, + cks.decrypt_message_and_carry(&ct_res) % msg_modulus + ); + + println!("ADD:: clear1 = {clear1}, clear2 = {clear2}, msg_mod = {msg_modulus}, carry_mod = {carry_modulus}"); + let ct_res = sks.unchecked_add(&ct1, &ct2); + assert_eq!( + (clear1 + clear2) % modulus, + cks.decrypt_message_and_carry(&ct_res) % modulus + ); + } +} + +fn shortint_mux

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + let modulus = cks.parameters.message_modulus().0 as u64; + + let msg_true = rng.gen::() % modulus; + let msg_false = rng.gen::() % modulus; + let control_bit = rng.gen::() % 2; + + let mut ct_true = cks.encrypt(msg_true); + let mut ct_false = cks.encrypt(msg_false); + let mut ct_control = cks.encrypt(control_bit); + + let mut res = sks.smart_sub(&mut ct_true, &mut ct_false); + sks.smart_mul_lsb_assign(&mut res, &mut ct_control); + sks.smart_add_assign(&mut res, &mut ct_false); + + let dec_res = cks.decrypt(&res); + + let clear_mux = (msg_true - msg_false) * control_bit + msg_false; + println!("(msg_true - msg_false) * control_bit + msg_false = {clear_mux}, res = {dec_res}"); + assert_eq!(clear_mux, dec_res); +} + +fn shortint_trivial_pbs

(param: P) +where + P: Into, +{ + let param = param.into(); + let full_modulus = param.message_modulus().0 as u64 * param.carry_modulus().0 as u64; + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let check_trivial_bootstrap = |clear, lut: &LookupTableOwned| { + let trivial_ct = sks.unchecked_create_trivial(clear); + let non_trivial_ct = cks.unchecked_encrypt(clear); + + let trivial_res = sks.apply_lookup_table(&trivial_ct, lut); + let non_trivial_res = sks.apply_lookup_table(&non_trivial_ct, lut); + assert!(trivial_res.is_trivial()); + assert!(!non_trivial_res.is_trivial()); + assert_eq!(non_trivial_res.noise_level(), NoiseLevel::NOMINAL); + + let trivial_res = cks.decrypt_message_and_carry(&trivial_res); + let non_trivial_res = cks.decrypt_message_and_carry(&non_trivial_res); + assert_eq!( + trivial_res, non_trivial_res, + "Invalid trivial PBS result expected '{non_trivial_res}', got '{trivial_res}'" + ); + }; + + let functions = [ + Box::new(|x| x) as Box u64>, + Box::new(|x| x % sks.message_modulus.0 as u64) as Box u64>, + Box::new(|x| x / sks.message_modulus.0 as u64) as Box u64>, + ]; + + if full_modulus >= 64 { + let mut rng = rand::thread_rng(); + + for _ in 0..(NB_TESTS / functions.len()).max(1) { + for f in &functions { + let lut = sks.generate_lookup_table(f); + + let clear_with_clean_padding_bit = rng.gen_range(0..full_modulus); + check_trivial_bootstrap(clear_with_clean_padding_bit, &lut); + + let clear_with_dirty_padding_bit = rng.gen_range(full_modulus..2 * full_modulus); + check_trivial_bootstrap(clear_with_dirty_padding_bit, &lut); + } + } + } else { + for f in functions { + let lut = sks.generate_lookup_table(f); + + for clear_with_clean_padding_bit in 0..full_modulus { + check_trivial_bootstrap(clear_with_clean_padding_bit, &lut); + } + + for clear_with_dirty_padding_bit in full_modulus..(full_modulus * 2) { + check_trivial_bootstrap(clear_with_dirty_padding_bit, &lut); + } + } + } +} + +fn shortint_trivial_pbs_many_lut

(param: P) +where + P: Into, +{ + let param = param.into(); + let msg_modulus = param.message_modulus().0 as u64; + let full_modulus = param.message_modulus().0 as u64 * param.carry_modulus().0 as u64; + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let check_trivial_bootstrap = |clear, lut: &ManyLookupTableOwned| { + let trivial_ct = sks.unchecked_create_trivial(clear); + let non_trivial_ct = cks.unchecked_encrypt(clear); + + let trivial_res = sks.apply_many_lookup_table(&trivial_ct, lut); + let non_trivial_res = sks.apply_many_lookup_table(&non_trivial_ct, lut); + assert!(trivial_res + .iter() + .all(crate::shortint::ciphertext::Ciphertext::is_trivial)); + assert!(non_trivial_res + .iter() + .all(|ct| !ct.is_trivial() && ct.noise_level() == NoiseLevel::NOMINAL)); + + for (fn_idx, (trivial, non_trivial)) in + trivial_res.iter().zip(non_trivial_res.iter()).enumerate() + { + let trivial = cks.decrypt_message_and_carry(trivial); + let non_trivial = cks.decrypt_message_and_carry(non_trivial); + assert_eq!( + trivial, non_trivial, + "Invalid trivial PBS result got '{trivial}', got non trivial '{non_trivial}' \ + for input {clear} evaluating function #{fn_idx}" + ); + } + }; + + let f1 = |x: u64| x * x % msg_modulus; + let f2 = |x: u64| (x.count_ones() as u64) % msg_modulus; + let f3 = |x: u64| (x.wrapping_add(1)) % msg_modulus; + let f4 = |x: u64| (x.wrapping_sub(1)) % msg_modulus; + let f5 = |x: u64| (x * 2) % msg_modulus; + let f6 = |x: u64| (x * 3) % msg_modulus; + let f7 = |x: u64| (x / 2) % msg_modulus; + let f8 = |x: u64| (x / 3) % msg_modulus; + + let functions: &[&dyn Fn(u64) -> u64] = &[&f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8]; + let max_fn_count = functions.len().min(full_modulus as usize / 2); + + if full_modulus >= 64 { + let mut rng = rand::thread_rng(); + + for _ in 0..(NB_TESTS / max_fn_count).max(1) { + for fn_count in 1..=max_fn_count { + let functions = &functions[..fn_count]; + let lut = sks.generate_many_lookup_table(functions); + + let clear_with_clean_padding_bit = rng.gen_range(0..full_modulus); + check_trivial_bootstrap(clear_with_clean_padding_bit, &lut); + + let clear_with_dirty_padding_bit = rng.gen_range(full_modulus..2 * full_modulus); + check_trivial_bootstrap(clear_with_dirty_padding_bit, &lut); + } + } + } else { + for fn_count in 1..=max_fn_count { + let functions = &functions[..fn_count]; + let lut = sks.generate_many_lookup_table(functions); + + for clear_with_clean_padding_bit in 0..full_modulus { + check_trivial_bootstrap(clear_with_clean_padding_bit, &lut); + } + + for clear_with_dirty_padding_bit in full_modulus..(full_modulus * 2) { + check_trivial_bootstrap(clear_with_dirty_padding_bit, &lut); + } + } + } +} diff --git a/tfhe/src/shortint/server_key/tests/parametrized_test_bivariate_pbs_compliant.rs b/tfhe/src/shortint/server_key/tests/parametrized_test_bivariate_pbs_compliant.rs new file mode 100644 index 0000000000..f50ebfddc4 --- /dev/null +++ b/tfhe/src/shortint/server_key/tests/parametrized_test_bivariate_pbs_compliant.rs @@ -0,0 +1,1391 @@ +use crate::shortint::keycache::KEY_CACHE; +use crate::shortint::parameters::*; +use crate::shortint::server_key::tests::parametrized_test::create_parametrized_test; +use rand::Rng; + +/// Number of assert in randomized tests +#[cfg(not(tarpaulin))] +const NB_TESTS: usize = 200; +/// Number of iterations in randomized tests for smart operations +#[cfg(not(tarpaulin))] +const NB_TESTS_SMART: usize = 10; +/// Number of sub tests used to increase degree of ciphertexts +#[cfg(not(tarpaulin))] +const NB_SUB_TEST_SMART: usize = 40; + +// Use lower numbers for coverage to ensure fast tests to counter balance slowdown due to code +// instrumentation +#[cfg(tarpaulin)] +const NB_TESTS: usize = 1; +/// Number of iterations in randomized tests for smart operations +#[cfg(tarpaulin)] +const NB_TESTS_SMART: usize = 1; +// This constant is tailored to trigger a message extract during operation processing. +// It's applicable for PARAM_MESSAGE_2_CARRY_2_KS_PBS parameters set. +#[cfg(tarpaulin)] +const NB_SUB_TEST_SMART: usize = 5; + +//Macro to generate tests for parameters sets compatible with the bivariate pbs +#[cfg(not(tarpaulin))] +macro_rules! create_parametrized_test_bivariate_pbs_compliant{ + ($name:ident { $($param:ident),* }) => { + ::paste::paste! { + $( + #[test] + fn []() { + $name($param) + } + )* + } + }; + ($name:ident)=> { + create_parametrized_test!($name + { + PARAM_MESSAGE_1_CARRY_1_KS_PBS, + PARAM_MESSAGE_1_CARRY_2_KS_PBS, + PARAM_MESSAGE_1_CARRY_3_KS_PBS, + PARAM_MESSAGE_1_CARRY_4_KS_PBS, + PARAM_MESSAGE_1_CARRY_5_KS_PBS, + PARAM_MESSAGE_1_CARRY_6_KS_PBS, + PARAM_MESSAGE_1_CARRY_7_KS_PBS, + PARAM_MESSAGE_2_CARRY_2_KS_PBS, + PARAM_MESSAGE_2_CARRY_3_KS_PBS, + PARAM_MESSAGE_2_CARRY_4_KS_PBS, + PARAM_MESSAGE_2_CARRY_5_KS_PBS, + PARAM_MESSAGE_2_CARRY_6_KS_PBS, + PARAM_MESSAGE_3_CARRY_3_KS_PBS, + PARAM_MESSAGE_3_CARRY_4_KS_PBS, + PARAM_MESSAGE_3_CARRY_5_KS_PBS, + PARAM_MESSAGE_4_CARRY_4_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_1_CARRY_1_GROUP_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_3_CARRY_3_GROUP_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_1_CARRY_1_GROUP_3_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_3_CARRY_3_GROUP_3_KS_PBS + }); + }; +} + +// Test against a small subset of parameters to speed up coverage tests +#[cfg(tarpaulin)] +macro_rules! create_parametrized_test_bivariate_pbs_compliant{ + ($name:ident { $($param:ident),* }) => { + ::paste::paste! { + $( + #[test] + fn []() { + $name($param) + } + )* + } + }; + ($name:ident)=> { + create_parametrized_test!($name + { + PARAM_MESSAGE_2_CARRY_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS, + PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS + }); + }; +} + +// Public key tests are limited to small parameter sets to avoid blowing up memory and large testing +// times. Compressed keygen takes 20 minutes for params 2_2 and for encryption as well. +// 2_2 uncompressed keys take ~2 GB and 3_3 about ~34 GB, hence why we stop at 2_2. +#[cfg(not(tarpaulin))] +#[test] +fn test_shortint_compressed_public_key_smart_add_param_message_1_carry_1_ks_pbs() { + shortint_compressed_public_key_smart_add(PARAM_MESSAGE_1_CARRY_1_KS_PBS); +} + +#[cfg(not(tarpaulin))] +#[test] +fn test_shortint_public_key_smart_add_param_message_1_carry_1_ks_pbs() { + shortint_public_key_smart_add(PARAM_MESSAGE_1_CARRY_1_KS_PBS); +} + +#[cfg(not(tarpaulin))] +#[test] +fn test_shortint_public_key_smart_add_param_message_2_carry_2_ks_pbs() { + shortint_public_key_smart_add(PARAM_MESSAGE_2_CARRY_2_KS_PBS); +} + +//These functions are compatible with some parameter sets where the carry modulus is larger than +// the message modulus. +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_bitand); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_bitor); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_bitxor); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_greater); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_greater_or_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_less); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_less_or_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_bitand); +create_parametrized_test_bivariate_pbs_compliant!(shortint_default_bitand); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_bitor); +create_parametrized_test_bivariate_pbs_compliant!(shortint_default_bitor); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_bitxor); +create_parametrized_test_bivariate_pbs_compliant!(shortint_default_bitxor); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_greater); +create_parametrized_test_bivariate_pbs_compliant!(shortint_default_greater); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_greater_or_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_default_greater_or_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_less); +create_parametrized_test_bivariate_pbs_compliant!(shortint_default_less); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_less_or_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_default_less_or_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_default_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_less); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_less_or_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_greater); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_greater_or_equal); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_div); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_scalar_div); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_mod); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_mul_lsb); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_mul_msb); +create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_mul_msb); +create_parametrized_test_bivariate_pbs_compliant!(shortint_default_mul_msb); +create_parametrized_test_bivariate_pbs_compliant!( + shortint_keyswitch_bivariate_programmable_bootstrap +); +create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_less_or_equal_trivial); + +fn shortint_keyswitch_bivariate_programmable_bootstrap

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + let ctxt_1 = cks.encrypt(clear_1); + + let acc = sks.generate_lookup_table_bivariate(|x, y| (x * 2 * y) % modulus); + + let ct_res = sks.unchecked_apply_lookup_table_bivariate(&ctxt_0, &ctxt_1, &acc); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((2 * clear_0 * clear_1) % modulus, dec_res); + } +} + +fn shortint_compressed_public_key_smart_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let pk = crate::shortint::CompressedPublicKey::new(cks); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS_SMART { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = pk.encrypt(clear_0); + + let mut ctxt_1 = pk.encrypt(clear_1); + + let mut ct_res = sks.smart_add(&mut ctxt_0, &mut ctxt_1); + let mut clear = clear_0 + clear_1; + + // add multiple times to raise the degree and test the smart operation + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_add(&mut ct_res, &mut ctxt_0); + clear += clear_0; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + } + } +} + +fn shortint_public_key_smart_add

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let pk = crate::shortint::PublicKey::new(cks); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS_SMART { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = pk.encrypt(clear_0); + + let mut ctxt_1 = pk.encrypt(clear_1); + + let mut ct_res = sks.smart_add(&mut ctxt_0, &mut ctxt_1); + let mut clear = clear_0 + clear_1; + + // add multiple times to raise the degree and test the smart operation + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_add(&mut ct_res, &mut ctxt_0); + clear += clear_0; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + } + } +} + +fn shortint_unchecked_bitand

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_bitand(&ctxt_0, &ctxt_1); + assert_eq!(ct_res.degree, ctxt_0.degree.after_bitand(ctxt_1.degree)); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 & clear_1, dec_res); + } +} + +fn shortint_unchecked_bitor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_bitor(&ctxt_0, &ctxt_1); + assert_eq!(ct_res.degree, ctxt_0.degree.after_bitor(ctxt_1.degree)); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 | clear_1, dec_res); + } +} + +fn shortint_unchecked_bitxor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_bitxor(&ctxt_0, &ctxt_1); + assert_eq!(ct_res.degree, ctxt_0.degree.after_bitxor(ctxt_1.degree)); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 ^ clear_1, dec_res); + } +} + +fn shortint_smart_bitand

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.smart_bitand(&mut ctxt_0, &mut ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 & clear_1) % modulus, dec_res); + } +} + +fn shortint_default_bitand

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.bitand(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 & clear_1) % modulus, dec_res); + } +} + +fn shortint_smart_bitor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.smart_bitor(&mut ctxt_0, &mut ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 | clear_1) % modulus, dec_res); + } +} + +fn shortint_default_bitor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.bitor(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 | clear_1) % modulus, dec_res); + } +} + +fn shortint_smart_bitxor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.smart_bitxor(&mut ctxt_0, &mut ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 ^ clear_1) % modulus, dec_res); + } +} + +fn shortint_default_bitxor

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.bitxor(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 ^ clear_1) % modulus, dec_res); + } +} + +fn shortint_unchecked_greater

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_greater(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 > clear_1) as u64, dec_res); + } +} + +fn shortint_smart_greater

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.smart_greater(&mut ctxt_0, &mut ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 > clear_1) as u64, dec_res); + } +} + +fn shortint_default_greater

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.greater(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 > clear_1) as u64, dec_res); + } +} + +fn shortint_unchecked_greater_or_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_greater_or_equal(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 >= clear_1) as u64, dec_res); + } +} + +fn shortint_smart_greater_or_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 = (clear_0 * scalar as u64) % modulus; + clear_1 = (clear_1 * scalar as u64) % modulus; + + let ct_res = sks.smart_greater_or_equal(&mut ctxt_0, &mut ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 >= clear_1) as u64, dec_res); + } +} + +fn shortint_default_greater_or_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 = (clear_0 * scalar as u64) % modulus; + clear_1 = (clear_1 * scalar as u64) % modulus; + + let ct_res = sks.greater_or_equal(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 >= clear_1) as u64, dec_res); + } +} + +fn shortint_unchecked_less

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_less(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 < clear_1) as u64, dec_res); + } +} + +fn shortint_smart_less

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 = (clear_0 * scalar as u64) % modulus; + clear_1 = (clear_1 * scalar as u64) % modulus; + + let ct_res = sks.smart_less(&mut ctxt_0, &mut ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 < clear_1) as u64, dec_res); + } +} + +fn shortint_default_less

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 = (clear_0 * scalar as u64) % modulus; + clear_1 = (clear_1 * scalar as u64) % modulus; + + let ct_res = sks.less(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 < clear_1) as u64, dec_res); + } +} + +fn shortint_unchecked_less_or_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_less_or_equal(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 <= clear_1) as u64, dec_res); + } +} + +fn shortint_unchecked_less_or_equal_trivial

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = sks.create_trivial(clear_0); + + let ctxt_1 = sks.create_trivial(clear_1); + + let ct_res = sks.unchecked_less_or_equal(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 <= clear_1) as u64, dec_res); + } +} + +fn shortint_smart_less_or_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.smart_less_or_equal(&mut ctxt_0, &mut ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(((clear_0 % modulus) <= (clear_1 % modulus)) as u64, dec_res); + } +} + +fn shortint_default_less_or_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.less_or_equal(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(((clear_0 % modulus) <= (clear_1 % modulus)) as u64, dec_res); + } +} + +fn shortint_unchecked_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_equal(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 == clear_1) as u64, dec_res); + } +} + +fn shortint_smart_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.smart_equal(&mut ctxt_0, &mut ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(((clear_0 % modulus) == (clear_1 % modulus)) as u64, dec_res); + } +} + +fn shortint_default_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + let mod_scalar = cks.parameters.carry_modulus().0 as u8; + + for _ in 0..NB_TESTS { + let mut clear_0 = rng.gen::() % modulus; + let mut clear_1 = rng.gen::() % modulus; + let scalar = rng.gen::() % mod_scalar; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); + sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); + + clear_0 *= scalar as u64; + clear_1 *= scalar as u64; + + let ct_res = sks.equal(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(((clear_0 % modulus) == (clear_1 % modulus)) as u64, dec_res); + } +} + +fn shortint_smart_scalar_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let msg_modulus = cks.parameters.message_modulus().0 as u64; + let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % msg_modulus; + + let scalar = (rng.gen::() % modulus as u16) as u8; + + let mut ctxt = cks.encrypt(clear); + + let ct_res = sks.smart_scalar_equal(&mut ctxt, scalar); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear == scalar as u64) as u64, dec_res); + } +} + +fn shortint_smart_scalar_less

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let msg_modulus = cks.parameters.message_modulus().0 as u64; + let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % msg_modulus; + + let scalar = (rng.gen::() % modulus as u16) as u8; + + let mut ctxt = cks.encrypt(clear); + + let ct_res = sks.smart_scalar_less(&mut ctxt, scalar); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear < scalar as u64) as u64, dec_res); + } +} + +fn shortint_smart_scalar_less_or_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let msg_modulus = cks.parameters.message_modulus().0 as u64; + let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % msg_modulus; + + let scalar = (rng.gen::() % modulus as u16) as u8; + + let mut ctxt = cks.encrypt(clear); + + let ct_res = sks.smart_scalar_less_or_equal(&mut ctxt, scalar); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear <= scalar as u64) as u64, dec_res); + } +} + +fn shortint_smart_scalar_greater

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let msg_modulus = cks.parameters.message_modulus().0 as u64; + let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % msg_modulus; + + let scalar = (rng.gen::() % modulus as u16) as u8; + + let mut ctxt = cks.encrypt(clear); + + let ct_res = sks.smart_scalar_greater(&mut ctxt, scalar); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear > scalar as u64) as u64, dec_res); + } +} + +fn shortint_smart_scalar_greater_or_equal

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let msg_modulus = cks.parameters.message_modulus().0 as u64; + let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; + + for _ in 0..NB_TESTS { + let clear = rng.gen::() % msg_modulus; + + let scalar = (rng.gen::() % modulus as u16) as u8; + + let mut ctxt = cks.encrypt(clear); + + let ct_res = sks.smart_scalar_greater_or_equal(&mut ctxt, scalar); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear >= scalar as u64) as u64, dec_res); + } +} + +fn shortint_unchecked_div

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + { + let numerator = 1u64; + let denominator = 0u64; + + let ct_num = cks.encrypt(numerator); + let ct_denom = cks.encrypt(denominator); + let ct_res = sks.unchecked_div(&ct_num, &ct_denom); + + let res = cks.decrypt(&ct_res); + assert_eq!(res, (ct_num.message_modulus.0 - 1) as u64); + } + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = (rng.gen::() % (modulus - 1)) + 1; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_div(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 / clear_1, dec_res); + } +} + +fn shortint_unchecked_scalar_div

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = (rng.gen::() % (modulus - 1)) + 1; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.unchecked_scalar_div(&ctxt_0, clear_1 as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 / clear_1, dec_res); + } +} + +fn shortint_unchecked_mod

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = (rng.gen::() % (modulus - 1)) + 1; + + let ctxt_0 = cks.encrypt(clear_0); + + let ct_res = sks.unchecked_scalar_mod(&ctxt_0, clear_1 as u8); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear_0 % clear_1, dec_res); + } +} + +fn shortint_unchecked_mul_lsb

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_mul_lsb(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 * clear_1) % modulus, dec_res); + } +} + +fn shortint_unchecked_mul_msb

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.unchecked_mul_msb(&ctxt_0, &ctxt_1); + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!((clear_0 * clear_1) / modulus, dec_res); + } +} + +fn shortint_smart_mul_msb

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS_SMART { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let mut ctxt_0 = cks.encrypt(clear_0); + + let mut ctxt_1 = cks.encrypt(clear_1); + + let mut ct_res = sks.smart_mul_msb(&mut ctxt_0, &mut ctxt_1); + + let mut clear = (clear_0 * clear_1) / modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + + for _ in 0..NB_SUB_TEST_SMART { + ct_res = sks.smart_mul_msb(&mut ct_res, &mut ctxt_0); + clear = (clear * clear_0) / modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + } + } +} + +fn shortint_default_mul_msb

(param: P) +where + P: Into, +{ + let keys = KEY_CACHE.get_from_param(param); + let (cks, sks) = (keys.client_key(), keys.server_key()); + + let mut rng = rand::thread_rng(); + + let modulus = cks.parameters.message_modulus().0 as u64; + + for _ in 0..NB_TESTS { + let clear_0 = rng.gen::() % modulus; + + let clear_1 = rng.gen::() % modulus; + + let ctxt_0 = cks.encrypt(clear_0); + + let ctxt_1 = cks.encrypt(clear_1); + + let ct_res = sks.mul_msb(&ctxt_0, &ctxt_1); + + let clear = (clear_0 * clear_1) / modulus; + + let dec_res = cks.decrypt(&ct_res); + + assert_eq!(clear % modulus, dec_res); + } +} diff --git a/tfhe/src/shortint/server_key/tests/shortint.rs b/tfhe/src/shortint/server_key/tests/shortint.rs deleted file mode 100644 index 03a4c7c581..0000000000 --- a/tfhe/src/shortint/server_key/tests/shortint.rs +++ /dev/null @@ -1,3452 +0,0 @@ -use crate::shortint::ciphertext::{Degree, NoiseLevel}; -use crate::shortint::keycache::KEY_CACHE; -use crate::shortint::parameters::*; -use crate::shortint::server_key::{LookupTableOwned, ManyLookupTableOwned}; -use paste::paste; -use rand::Rng; - -/// Number of assert in randomized tests -#[cfg(not(tarpaulin))] -const NB_TESTS: usize = 200; -/// Number of iterations in randomized tests for smart operations -#[cfg(not(tarpaulin))] -const NB_TESTS_SMART: usize = 10; -/// Number of sub tests used to increase degree of ciphertexts -#[cfg(not(tarpaulin))] -const NB_SUB_TEST_SMART: usize = 40; - -// Use lower numbers for coverage to ensure fast tests to counter balance slowdown due to code -// instrumentation -#[cfg(tarpaulin)] -const NB_TESTS: usize = 1; -/// Number of iterations in randomized tests for smart operations -#[cfg(tarpaulin)] -const NB_TESTS_SMART: usize = 1; -// This constant is tailored to trigger a message extract during operation processing. -// It's applicable for PARAM_MESSAGE_2_CARRY_2_KS_PBS parameters set. -#[cfg(tarpaulin)] -const NB_SUB_TEST_SMART: usize = 5; - -// Macro to generate tests for all parameter sets -#[cfg(not(tarpaulin))] -macro_rules! create_parametrized_test{ - ($name:ident { $($param:ident),* }) => { - paste! { - $( - #[test] - fn []() { - $name($param) - } - )* - } - }; - ($name:ident)=> { - create_parametrized_test!($name - { - PARAM_MESSAGE_1_CARRY_1_KS_PBS, - PARAM_MESSAGE_1_CARRY_2_KS_PBS, - PARAM_MESSAGE_1_CARRY_3_KS_PBS, - PARAM_MESSAGE_1_CARRY_4_KS_PBS, - PARAM_MESSAGE_1_CARRY_5_KS_PBS, - PARAM_MESSAGE_1_CARRY_6_KS_PBS, - PARAM_MESSAGE_1_CARRY_7_KS_PBS, - PARAM_MESSAGE_2_CARRY_1_KS_PBS, - PARAM_MESSAGE_2_CARRY_2_KS_PBS, - PARAM_MESSAGE_2_CARRY_3_KS_PBS, - PARAM_MESSAGE_2_CARRY_4_KS_PBS, - PARAM_MESSAGE_2_CARRY_5_KS_PBS, - PARAM_MESSAGE_2_CARRY_6_KS_PBS, - PARAM_MESSAGE_3_CARRY_1_KS_PBS, - PARAM_MESSAGE_3_CARRY_2_KS_PBS, - PARAM_MESSAGE_3_CARRY_3_KS_PBS, - PARAM_MESSAGE_3_CARRY_4_KS_PBS, - PARAM_MESSAGE_3_CARRY_5_KS_PBS, - PARAM_MESSAGE_4_CARRY_1_KS_PBS, - PARAM_MESSAGE_4_CARRY_2_KS_PBS, - PARAM_MESSAGE_4_CARRY_3_KS_PBS, - PARAM_MESSAGE_4_CARRY_4_KS_PBS, - PARAM_MESSAGE_5_CARRY_1_KS_PBS, - PARAM_MESSAGE_5_CARRY_2_KS_PBS, - PARAM_MESSAGE_5_CARRY_3_KS_PBS, - PARAM_MESSAGE_6_CARRY_1_KS_PBS, - PARAM_MESSAGE_6_CARRY_2_KS_PBS, - PARAM_MESSAGE_7_CARRY_1_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_1_CARRY_1_GROUP_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_3_CARRY_3_GROUP_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_1_CARRY_1_GROUP_3_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_3_CARRY_3_GROUP_3_KS_PBS - }); - }; -} - -// Test against a small subset of parameters to speed up coverage tests -#[cfg(tarpaulin)] -macro_rules! create_parametrized_test{ - ($name:ident { $($param:ident),* }) => { - paste! { - $( - #[test] - fn []() { - $name($param) - } - )* - } - }; - ($name:ident)=> { - create_parametrized_test!($name - { - PARAM_MESSAGE_2_CARRY_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS - }); - }; -} - -//Macro to generate tests for parameters sets compatible with the bivariate pbs -#[cfg(not(tarpaulin))] -macro_rules! create_parametrized_test_bivariate_pbs_compliant{ - ($name:ident { $($param:ident),* }) => { - paste! { - $( - #[test] - fn []() { - $name($param) - } - )* - } - }; - ($name:ident)=> { - create_parametrized_test!($name - { - PARAM_MESSAGE_1_CARRY_1_KS_PBS, - PARAM_MESSAGE_1_CARRY_2_KS_PBS, - PARAM_MESSAGE_1_CARRY_3_KS_PBS, - PARAM_MESSAGE_1_CARRY_4_KS_PBS, - PARAM_MESSAGE_1_CARRY_5_KS_PBS, - PARAM_MESSAGE_1_CARRY_6_KS_PBS, - PARAM_MESSAGE_1_CARRY_7_KS_PBS, - PARAM_MESSAGE_2_CARRY_2_KS_PBS, - PARAM_MESSAGE_2_CARRY_3_KS_PBS, - PARAM_MESSAGE_2_CARRY_4_KS_PBS, - PARAM_MESSAGE_2_CARRY_5_KS_PBS, - PARAM_MESSAGE_2_CARRY_6_KS_PBS, - PARAM_MESSAGE_3_CARRY_3_KS_PBS, - PARAM_MESSAGE_3_CARRY_4_KS_PBS, - PARAM_MESSAGE_3_CARRY_5_KS_PBS, - PARAM_MESSAGE_4_CARRY_4_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_1_CARRY_1_GROUP_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_3_CARRY_3_GROUP_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_1_CARRY_1_GROUP_3_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_3_CARRY_3_GROUP_3_KS_PBS - }); - }; -} - -// Test against a small subset of parameters to speed up coverage tests -#[cfg(tarpaulin)] -macro_rules! create_parametrized_test_bivariate_pbs_compliant{ - ($name:ident { $($param:ident),* }) => { - paste! { - $( - #[test] - fn []() { - $name($param) - } - )* - } - }; - ($name:ident)=> { - create_parametrized_test!($name - { - PARAM_MESSAGE_2_CARRY_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS, - PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS - }); - }; -} - -//These functions are compatible with all parameter sets. -create_parametrized_test!(shortint_encrypt_decrypt); -create_parametrized_test!(shortint_encrypt_with_message_modulus_decrypt); -create_parametrized_test!(shortint_encrypt_decrypt_without_padding); -create_parametrized_test!(shortint_keyswitch_bootstrap); -create_parametrized_test!(shortint_keyswitch_programmable_bootstrap); -create_parametrized_test!(shortint_keyswitch_programmable_bootstrap_many_lut); -create_parametrized_test!(shortint_carry_extract); -create_parametrized_test!(shortint_message_extract); -create_parametrized_test!(shortint_generate_lookup_table); -create_parametrized_test!(shortint_unchecked_add); -create_parametrized_test!(shortint_smart_add); -create_parametrized_test!(shortint_default_add); -create_parametrized_test!(shortint_smart_mul_lsb); -create_parametrized_test!(shortint_default_mul_lsb); -create_parametrized_test!(shortint_unchecked_neg); -create_parametrized_test!(shortint_smart_neg); -create_parametrized_test!(shortint_default_neg); -create_parametrized_test!(shortint_unchecked_scalar_add); -create_parametrized_test!(shortint_smart_scalar_add); -create_parametrized_test!(shortint_default_scalar_add); -create_parametrized_test!(shortint_unchecked_scalar_sub); -create_parametrized_test!(shortint_smart_scalar_sub); -create_parametrized_test!(shortint_default_scalar_sub); -create_parametrized_test!(shortint_unchecked_scalar_mul); -create_parametrized_test!(shortint_smart_scalar_mul); -create_parametrized_test!(shortint_default_scalar_mul); -create_parametrized_test!(shortint_unchecked_right_shift); -create_parametrized_test!(shortint_default_right_shift); -create_parametrized_test!(shortint_unchecked_left_shift); -create_parametrized_test!(shortint_default_left_shift); -create_parametrized_test!(shortint_unchecked_sub); -create_parametrized_test!(shortint_smart_sub); -create_parametrized_test!(shortint_default_sub); -create_parametrized_test!(shortint_mul_small_carry); -create_parametrized_test!(shortint_mux); -create_parametrized_test!(shortint_unchecked_scalar_bitand); -create_parametrized_test!(shortint_unchecked_scalar_bitor); -create_parametrized_test!(shortint_unchecked_scalar_bitxor); -create_parametrized_test!(shortint_smart_scalar_bitand); -create_parametrized_test!(shortint_smart_scalar_bitor); -create_parametrized_test!(shortint_smart_scalar_bitxor); -create_parametrized_test!(shortint_default_scalar_bitand); -create_parametrized_test!(shortint_default_scalar_bitor); -create_parametrized_test!(shortint_default_scalar_bitxor); -create_parametrized_test!(shortint_trivial_pbs); -create_parametrized_test!(shortint_trivial_pbs_many_lut); - -// Public key tests are limited to small parameter sets to avoid blowing up memory and large testing -// times. Compressed keygen takes 20 minutes for params 2_2 and for encryption as well. -// 2_2 uncompressed keys take ~2 GB and 3_3 about ~34 GB, hence why we stop at 2_2. -#[cfg(not(tarpaulin))] -#[test] -fn test_shortint_compressed_public_key_smart_add_param_message_1_carry_1_ks_pbs() { - shortint_compressed_public_key_smart_add(PARAM_MESSAGE_1_CARRY_1_KS_PBS); -} - -#[cfg(not(tarpaulin))] -#[test] -fn test_shortint_public_key_smart_add_param_message_1_carry_1_ks_pbs() { - shortint_public_key_smart_add(PARAM_MESSAGE_1_CARRY_1_KS_PBS); -} - -#[cfg(not(tarpaulin))] -#[test] -fn test_shortint_public_key_smart_add_param_message_2_carry_2_ks_pbs() { - shortint_public_key_smart_add(PARAM_MESSAGE_2_CARRY_2_KS_PBS); -} - -//These functions are compatible with some parameter sets where the carry modulus is larger than -// the message modulus. -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_bitand); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_bitor); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_bitxor); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_greater); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_greater_or_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_less); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_less_or_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_bitand); -create_parametrized_test_bivariate_pbs_compliant!(shortint_default_bitand); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_bitor); -create_parametrized_test_bivariate_pbs_compliant!(shortint_default_bitor); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_bitxor); -create_parametrized_test_bivariate_pbs_compliant!(shortint_default_bitxor); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_greater); -create_parametrized_test_bivariate_pbs_compliant!(shortint_default_greater); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_greater_or_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_default_greater_or_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_less); -create_parametrized_test_bivariate_pbs_compliant!(shortint_default_less); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_less_or_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_default_less_or_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_default_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_less); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_less_or_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_greater); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_scalar_greater_or_equal); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_div); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_scalar_div); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_mod); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_mul_lsb); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_mul_msb); -create_parametrized_test_bivariate_pbs_compliant!(shortint_smart_mul_msb); -create_parametrized_test_bivariate_pbs_compliant!(shortint_default_mul_msb); -create_parametrized_test_bivariate_pbs_compliant!( - shortint_keyswitch_bivariate_programmable_bootstrap -); -create_parametrized_test_bivariate_pbs_compliant!( - shortint_encrypt_with_message_modulus_smart_add_and_mul -); -create_parametrized_test_bivariate_pbs_compliant!( - shortint_encrypt_with_message_and_carry_modulus_smart_add_and_mul -); -create_parametrized_test_bivariate_pbs_compliant!(shortint_unchecked_less_or_equal_trivial); - -/// test encryption and decryption with the LWE client key -fn shortint_encrypt_decrypt

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let cks = keys.client_key(); - - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % modulus; - - let ct = cks.encrypt(clear); - - // decryption of ct - let dec = cks.decrypt(&ct); - - // assert - assert_eq!(clear, dec); - } -} - -/// test encryption and decryption with the LWE client key -fn shortint_encrypt_with_message_modulus_decrypt

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let cks = keys.client_key(); - - let mut rng = rand::thread_rng(); - - for _ in 0..NB_TESTS { - let mut modulus = rng.gen::() % cks.parameters.message_modulus().0 as u64; - while modulus == 0 { - modulus = rng.gen::() % cks.parameters.message_modulus().0 as u64; - } - - let clear = rng.gen::() % modulus; - - let ct = cks.encrypt_with_message_modulus(clear, MessageModulus(modulus as usize)); - - // decryption of ct_zero - let dec = cks.decrypt(&ct); - - // assert - assert_eq!(clear, dec); - } -} - -fn shortint_encrypt_decrypt_without_padding

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let cks = keys.client_key(); - - let mut rng = rand::thread_rng(); - - // We assume that the modulus is the largest possible without padding bit - let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % modulus; - - let ct = cks.encrypt_without_padding(clear); - - // decryption of ct_zero - let dec = cks.decrypt_message_and_carry_without_padding(&ct); - - // assert - assert_eq!(clear, dec); - } -} - -fn shortint_keyswitch_bootstrap

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mut failures = 0; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // keyswitch and bootstrap - let ct_res = sks.message_extract(&ctxt_0); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - if clear_0 != dec_res { - failures += 1; - } - // assert - // assert_eq!(clear_0, dec_res); - } - - println!("fail_rate = {failures}/{NB_TESTS}"); - assert_eq!(0, failures); -} - -fn shortint_keyswitch_programmable_bootstrap

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - //define the lookup_table as identity - let acc = sks.generate_msg_lookup_table(|n| n, cks.parameters.message_modulus()); - // add the two ciphertexts - let ct_res = sks.apply_lookup_table(&ctxt_0, &acc); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0, dec_res); - } -} - -fn shortint_keyswitch_programmable_bootstrap_many_lut

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let msg_modulus = cks.parameters.message_modulus().0 as u64; - let carry_modulus = cks.parameters.carry_modulus().0 as u64; - let modulus_sup = msg_modulus * carry_modulus; - - let f1 = |x: u64| x * x % msg_modulus; - let f2 = |x: u64| (x.count_ones() as u64) % msg_modulus; - let f3 = |x: u64| (x.wrapping_add(1)) % msg_modulus; - let f4 = |x: u64| (x.wrapping_sub(1)) % msg_modulus; - let f5 = |x: u64| (x * 2) % msg_modulus; - let f6 = |x: u64| (x * 3) % msg_modulus; - let f7 = |x: u64| (x / 2) % msg_modulus; - let f8 = |x: u64| (x / 3) % msg_modulus; - - let functions: &[&dyn Fn(u64) -> u64] = &[&f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8]; - let max_fn_count = functions.len().min(modulus_sup as usize / 2); - let per_fn_tests = (NB_TESTS / max_fn_count).max(1); - for fn_count in 1..=max_fn_count { - let functions = &functions[..fn_count]; - - // Depending on how many functions we are evaluating the maximum valid message modulus is - // lower than what the parameters support - let effective_msg_modulus = msg_modulus.min(modulus_sup / fn_count as u64); - - // Generate the many lut once for the current set of functions - let acc = sks.generate_many_lookup_table(functions); - for _ in 0..per_fn_tests { - let clear_0 = rng.gen::() % effective_msg_modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // Apply the many luts - let vec_res = sks.apply_many_lookup_table(&ctxt_0, &acc); - - for (fn_idx, (res, function)) in vec_res.iter().zip(functions).enumerate() { - let dec = cks.decrypt(res); - let function_eval = function(clear_0); - - assert_eq!( - dec, function_eval, - "Evaluation of function #{fn_idx} on {clear_0} failed, \ - got {dec}, expected {function_eval}", - ); - } - } - } -} - -fn shortint_keyswitch_bivariate_programmable_bootstrap

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - let ctxt_1 = cks.encrypt(clear_1); - //define the lookup_table as identity - let acc = sks.generate_lookup_table_bivariate(|x, y| (x * 2 * y) % modulus); - // add the two ciphertexts - let ct_res = sks.unchecked_apply_lookup_table_bivariate(&ctxt_0, &ctxt_1, &acc); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((2 * clear_0 * clear_1) % modulus, dec_res); - } -} - -/// test extraction of a carry -fn shortint_carry_extract

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let full_modulus = - cks.parameters.message_modulus().0 as u64 + cks.parameters.carry_modulus().0 as u64; - let msg_modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - // shift to the carry bits - let clear = rng.gen::() % full_modulus; - - // unchecked encryption of the message to have a larger message encrypted. - let ctxt = cks.unchecked_encrypt(clear); - - // extract the carry - let ct_carry = sks.carry_extract(&ctxt); - - // decryption of message and carry - let dec = cks.decrypt_message_and_carry(&ct_carry); - - // assert - println!( - "msg = {clear}, modulus = {msg_modulus}, msg/modulus = {}", - clear / msg_modulus - ); - assert_eq!(clear / msg_modulus, dec); - } -} - -/// test extraction of a message -fn shortint_message_extract

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus_sup = - (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % modulus_sup; - - // encryption of an integer - let ctxt = cks.unchecked_encrypt(clear); - - // message extraction - let ct_msg = sks.message_extract(&ctxt); - - // decryption of ct_msg - let dec = cks.decrypt(&ct_msg); - - // assert - assert_eq!(clear % modulus, dec); - } -} - -/// test multiplication with the LWE server key -fn shortint_generate_lookup_table

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - let double = |x| (2 * x) % sks.message_modulus.0 as u64; - let acc = sks.generate_lookup_table(double); - - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % modulus; - - // encryption of an integer - let ct = cks.encrypt(clear); - - let ct_res = sks.apply_lookup_table(&ct, &acc); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear * 2) % modulus, dec_res); - } -} - -/// test addition with the LWE server key -fn shortint_unchecked_add

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_add(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - println!( - "The parameters set is CARRY_{}_MESSAGE_{}", - cks.parameters.carry_modulus().0, - cks.parameters.message_modulus().0 - ); - assert_eq!((clear_0 + clear_1) % modulus, dec_res); - } -} - -/// test addition with the LWE server key -fn shortint_smart_add

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS_SMART { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let mut ct_res = sks.smart_add(&mut ctxt_0, &mut ctxt_1); - let mut clear = clear_0 + clear_1; - - // add multiple times to raise the degree and test the smart operation - for _ in 0..NB_SUB_TEST_SMART { - println!("SUB TEST"); - ct_res = sks.smart_add(&mut ct_res, &mut ctxt_0); - clear += clear_0; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear % modulus, dec_res); - } - } -} - -/// test default addition with the LWE server key -fn shortint_default_add

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.add(&ctxt_0, &ctxt_1); - let clear_res = clear_0 + clear_1; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear_res % modulus, dec_res); - } -} - -/// test addition with the LWE server key using the a public key for encryption -fn shortint_compressed_public_key_smart_add

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - let pk = crate::shortint::CompressedPublicKey::new(cks); - - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS_SMART { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let mut ctxt_0 = pk.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = pk.encrypt(clear_1); - - // add the two ciphertexts - let mut ct_res = sks.smart_add(&mut ctxt_0, &mut ctxt_1); - let mut clear = clear_0 + clear_1; - - // add multiple times to raise the degree and test the smart operation - for _ in 0..NB_SUB_TEST_SMART { - ct_res = sks.smart_add(&mut ct_res, &mut ctxt_0); - clear += clear_0; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear % modulus, dec_res); - } - } -} - -/// test addition with the LWE server key using the a public key for encryption -fn shortint_public_key_smart_add

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - let pk = crate::shortint::PublicKey::new(cks); - - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS_SMART { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let mut ctxt_0 = pk.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = pk.encrypt(clear_1); - - // add the two ciphertexts - let mut ct_res = sks.smart_add(&mut ctxt_0, &mut ctxt_1); - let mut clear = clear_0 + clear_1; - - // add multiple times to raise the degree and test the smart operation - for _ in 0..NB_SUB_TEST_SMART { - ct_res = sks.smart_add(&mut ct_res, &mut ctxt_0); - clear += clear_0; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear % modulus, dec_res); - } - } -} - -/// test bitwise 'and' with the LWE server key -fn shortint_unchecked_bitand

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_bitand(&ctxt_0, &ctxt_1); - assert_eq!(ct_res.degree, ctxt_0.degree.after_bitand(ctxt_1.degree)); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0 & clear_1, dec_res); - } -} - -/// test bitwise 'or' with the LWE server key -fn shortint_unchecked_bitor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_bitor(&ctxt_0, &ctxt_1); - assert_eq!(ct_res.degree, ctxt_0.degree.after_bitor(ctxt_1.degree)); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0 | clear_1, dec_res); - } -} - -/// test bitwise 'xor' with the LWE server key -fn shortint_unchecked_bitxor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_bitxor(&ctxt_0, &ctxt_1); - assert_eq!(ct_res.degree, ctxt_0.degree.after_bitxor(ctxt_1.degree)); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0 ^ clear_1, dec_res); - } -} - -/// test scalar bitwise 'xor' with the LWE server key -fn shortint_unchecked_scalar_bitxor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - let ctxt_0 = cks.encrypt(clear_0); - - let ct_res = sks.unchecked_scalar_bitxor(&ctxt_0, clear_1 as u8); - assert_eq!( - ct_res.degree, - ctxt_0.degree.after_bitxor(Degree::new(clear_1 as usize)) - ); - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear_0 ^ clear_1, dec_res); - } -} - -/// test scalar bitwise 'or' with the LWE server key -fn shortint_unchecked_scalar_bitor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - let ctxt_0 = cks.encrypt(clear_0); - - let ct_res = sks.unchecked_scalar_bitor(&ctxt_0, clear_1 as u8); - assert_eq!( - ct_res.degree, - ctxt_0.degree.after_bitor(Degree::new(clear_1 as usize)) - ); - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear_0 | clear_1, dec_res); - } -} - -/// test scalar bitwise 'and' with the LWE server key -fn shortint_unchecked_scalar_bitand

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - let ctxt_0 = cks.encrypt(clear_0); - - let ct_res = sks.unchecked_scalar_bitand(&ctxt_0, clear_1 as u8); - assert_eq!( - ct_res.degree, - ctxt_0.degree.after_bitand(Degree::new(clear_1 as usize)) - ); - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear_0 & clear_1, dec_res); - } -} - -/// test bitwise 'and' with the LWE server key -fn shortint_smart_bitand

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.smart_bitand(&mut ctxt_0, &mut ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 & clear_1) % modulus, dec_res); - } -} - -fn shortint_smart_scalar_bitand

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - let mut ctxt_0 = cks.encrypt(clear_0); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - - clear_0 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.smart_scalar_bitand(&mut ctxt_0, clear_1 as u8); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0 & clear_1, dec_res); - } -} - -/// test default bitwise 'and' with the LWE server key -fn shortint_default_bitand

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.bitand(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 & clear_1) % modulus, dec_res); - } -} - -fn shortint_default_scalar_bitand

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - - clear_0 *= scalar as u64; - - let ct_res = sks.scalar_bitand(&ctxt_0, clear_1 as u8); - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear_0 & clear_1, dec_res); - } -} - -/// test bitwise 'or' with the LWE server key -fn shortint_smart_bitor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.smart_bitor(&mut ctxt_0, &mut ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 | clear_1) % modulus, dec_res); - } -} - -fn shortint_smart_scalar_bitor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - let mut ctxt_0 = cks.encrypt(clear_0); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - - clear_0 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.smart_scalar_bitor(&mut ctxt_0, clear_1 as u8); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 | clear_1) % modulus, dec_res); - } -} - -/// test default bitwise 'or' with the LWE server key -fn shortint_default_bitor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.bitor(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 | clear_1) % modulus, dec_res); - } -} - -fn shortint_default_scalar_bitor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - - clear_0 *= scalar as u64; - - let ct_res = sks.scalar_bitor(&ctxt_0, clear_1 as u8); - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!((clear_0 | clear_1) % modulus, dec_res); - } -} - -/// test bitwise 'xor' with the LWE server key -fn shortint_smart_bitxor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.smart_bitxor(&mut ctxt_0, &mut ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 ^ clear_1) % modulus, dec_res); - } -} - -fn shortint_smart_scalar_bitxor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - let mut ctxt_0 = cks.encrypt(clear_0); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - - clear_0 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.smart_scalar_bitxor(&mut ctxt_0, clear_1 as u8); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 ^ clear_1) % modulus, dec_res); - } -} - -/// test default bitwise 'xor' with the LWE server key -fn shortint_default_bitxor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.bitxor(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 ^ clear_1) % modulus, dec_res); - } -} - -fn shortint_default_scalar_bitxor

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - - clear_0 *= scalar as u64; - - let ct_res = sks.scalar_bitxor(&ctxt_0, clear_1 as u8); - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!((clear_0 ^ clear_1) % modulus, dec_res); - } -} - -/// test '>' with the LWE server key -fn shortint_unchecked_greater

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_greater(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 > clear_1) as u64, dec_res); - } -} - -/// test '>' with the LWE server key -fn shortint_smart_greater

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.smart_greater(&mut ctxt_0, &mut ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 > clear_1) as u64, dec_res); - } -} - -/// test default '>' with the LWE server key -fn shortint_default_greater

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.greater(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 > clear_1) as u64, dec_res); - } -} - -/// test '>=' with the LWE server key -fn shortint_unchecked_greater_or_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_greater_or_equal(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 >= clear_1) as u64, dec_res); - } -} - -/// test '>=' with the LWE server key -fn shortint_smart_greater_or_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 = (clear_0 * scalar as u64) % modulus; - clear_1 = (clear_1 * scalar as u64) % modulus; - - // add the two ciphertexts - let ct_res = sks.smart_greater_or_equal(&mut ctxt_0, &mut ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 >= clear_1) as u64, dec_res); - } -} - -/// test default '>=' with the LWE server key -fn shortint_default_greater_or_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 = (clear_0 * scalar as u64) % modulus; - clear_1 = (clear_1 * scalar as u64) % modulus; - - // add the two ciphertexts - let ct_res = sks.greater_or_equal(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 >= clear_1) as u64, dec_res); - } -} - -/// test '<' with the LWE server key -fn shortint_unchecked_less

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_less(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 < clear_1) as u64, dec_res); - } -} - -/// test '<' with the LWE server key -fn shortint_smart_less

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 = (clear_0 * scalar as u64) % modulus; - clear_1 = (clear_1 * scalar as u64) % modulus; - - // add the two ciphertexts - let ct_res = sks.smart_less(&mut ctxt_0, &mut ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 < clear_1) as u64, dec_res); - } -} - -/// test default '<' with the LWE server key -fn shortint_default_less

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 = (clear_0 * scalar as u64) % modulus; - clear_1 = (clear_1 * scalar as u64) % modulus; - - // add the two ciphertexts - let ct_res = sks.less(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 < clear_1) as u64, dec_res); - } -} - -/// test '<=' with the LWE server key -fn shortint_unchecked_less_or_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_less_or_equal(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 <= clear_1) as u64, dec_res); - } -} - -/// test '<=' with the LWE server key -fn shortint_unchecked_less_or_equal_trivial

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = sks.create_trivial(clear_0); - - // encryption of an integer - let ctxt_1 = sks.create_trivial(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_less_or_equal(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 <= clear_1) as u64, dec_res); - } -} - -/// test '<=' with the LWE server key -fn shortint_smart_less_or_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.smart_less_or_equal(&mut ctxt_0, &mut ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(((clear_0 % modulus) <= (clear_1 % modulus)) as u64, dec_res); - } -} - -/// test default '<=' with the LWE server key -fn shortint_default_less_or_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.less_or_equal(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(((clear_0 % modulus) <= (clear_1 % modulus)) as u64, dec_res); - } -} - -fn shortint_unchecked_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_equal(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 == clear_1) as u64, dec_res); - } -} - -/// test '==' with the LWE server key -fn shortint_smart_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.smart_equal(&mut ctxt_0, &mut ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(((clear_0 % modulus) == (clear_1 % modulus)) as u64, dec_res); - } -} - -/// test default '==' with the LWE server key -fn shortint_default_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - let mod_scalar = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let mut clear_0 = rng.gen::() % modulus; - let mut clear_1 = rng.gen::() % modulus; - let scalar = rng.gen::() % mod_scalar; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - sks.unchecked_scalar_mul_assign(&mut ctxt_0, scalar); - sks.unchecked_scalar_mul_assign(&mut ctxt_1, scalar); - - clear_0 *= scalar as u64; - clear_1 *= scalar as u64; - - // add the two ciphertexts - let ct_res = sks.equal(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(((clear_0 % modulus) == (clear_1 % modulus)) as u64, dec_res); - } -} - -/// test '==' with the LWE server key -fn shortint_smart_scalar_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let msg_modulus = cks.parameters.message_modulus().0 as u64; - let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % msg_modulus; - - let scalar = (rng.gen::() % modulus as u16) as u8; - - // encryption of an integer - let mut ctxt = cks.encrypt(clear); - - // add the two ciphertexts - let ct_res = sks.smart_scalar_equal(&mut ctxt, scalar); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear == scalar as u64) as u64, dec_res); - } -} - -/// test '<' with the LWE server key -fn shortint_smart_scalar_less

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let msg_modulus = cks.parameters.message_modulus().0 as u64; - let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % msg_modulus; - - let scalar = (rng.gen::() % modulus as u16) as u8; - - // encryption of an integer - let mut ctxt = cks.encrypt(clear); - - // add the two ciphertexts - let ct_res = sks.smart_scalar_less(&mut ctxt, scalar); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear < scalar as u64) as u64, dec_res); - } -} - -/// test '<=' with the LWE server key -fn shortint_smart_scalar_less_or_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let msg_modulus = cks.parameters.message_modulus().0 as u64; - let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % msg_modulus; - - let scalar = (rng.gen::() % modulus as u16) as u8; - - // encryption of an integer - let mut ctxt = cks.encrypt(clear); - - // add the two ciphertexts - let ct_res = sks.smart_scalar_less_or_equal(&mut ctxt, scalar); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear <= scalar as u64) as u64, dec_res); - } -} - -/// test '>' with the LWE server key -fn shortint_smart_scalar_greater

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let msg_modulus = cks.parameters.message_modulus().0 as u64; - let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % msg_modulus; - - let scalar = (rng.gen::() % modulus as u16) as u8; - - // encryption of an integer - let mut ctxt = cks.encrypt(clear); - - // add the two ciphertexts - let ct_res = sks.smart_scalar_greater(&mut ctxt, scalar); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear > scalar as u64) as u64, dec_res); - } -} - -/// test '>' with the LWE server key -fn shortint_smart_scalar_greater_or_equal

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let msg_modulus = cks.parameters.message_modulus().0 as u64; - let modulus = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) as u64; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % msg_modulus; - - let scalar = (rng.gen::() % modulus as u16) as u8; - - // encryption of an integer - let mut ctxt = cks.encrypt(clear); - - // add the two ciphertexts - let ct_res = sks.smart_scalar_greater_or_equal(&mut ctxt, scalar); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear >= scalar as u64) as u64, dec_res); - } -} - -/// test division with the LWE server key -fn shortint_unchecked_div

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - // check div by 0 result - { - let numerator = 1u64; - let denominator = 0u64; - - let ct_num = cks.encrypt(numerator); - let ct_denom = cks.encrypt(denominator); - let ct_res = sks.unchecked_div(&ct_num, &ct_denom); - - let res = cks.decrypt(&ct_res); - assert_eq!(res, (ct_num.message_modulus.0 - 1) as u64); - } - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = (rng.gen::() % (modulus - 1)) + 1; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_div(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0 / clear_1, dec_res); - } -} - -/// test scalar division with the LWE server key -fn shortint_unchecked_scalar_div

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = (rng.gen::() % (modulus - 1)) + 1; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // add the two ciphertexts - let ct_res = sks.unchecked_scalar_div(&ctxt_0, clear_1 as u8); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0 / clear_1, dec_res); - } -} - -/// test modulus with the LWE server key -fn shortint_unchecked_mod

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = (rng.gen::() % (modulus - 1)) + 1; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // add the two ciphertexts - let ct_res = sks.unchecked_scalar_mod(&ctxt_0, clear_1 as u8); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0 % clear_1, dec_res); - } -} - -/// test LSB multiplication with the LWE server key -fn shortint_unchecked_mul_lsb

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_mul_lsb(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 * clear_1) % modulus, dec_res); - } -} - -/// test MSB multiplication with the LWE server key -fn shortint_unchecked_mul_msb

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.unchecked_mul_msb(&ctxt_0, &ctxt_1); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 * clear_1) / modulus, dec_res); - } -} - -/// test LSB multiplication with the LWE server key -fn shortint_smart_mul_lsb

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS_SMART { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let mut ct_res = sks.smart_mul_lsb(&mut ctxt_0, &mut ctxt_1); - - let mut clear = clear_0 * clear_1; - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear % modulus, dec_res); - - // multiply several times to raise the degree - for _ in 0..NB_SUB_TEST_SMART { - ct_res = sks.smart_mul_lsb(&mut ct_res, &mut ctxt_0); - clear = (clear * clear_0) % modulus; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear, dec_res); - } - } -} - -/// test default LSB multiplication with the LWE server key -fn shortint_default_mul_lsb

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.mul_lsb(&ctxt_0, &ctxt_1); - - let clear = clear_0 * clear_1; - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear % modulus, dec_res); - } -} - -/// test MSB multiplication with the LWE server key -fn shortint_smart_mul_msb

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS_SMART { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let mut ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let mut ct_res = sks.smart_mul_msb(&mut ctxt_0, &mut ctxt_1); - - let mut clear = (clear_0 * clear_1) / modulus; - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear % modulus, dec_res); - - // multiply several times to raise the degree - for _ in 0..NB_SUB_TEST_SMART { - ct_res = sks.smart_mul_msb(&mut ct_res, &mut ctxt_0); - clear = (clear * clear_0) / modulus; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear % modulus, dec_res); - } - } -} - -/// test default MSB multiplication with the LWE server key -fn shortint_default_mul_msb

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_1 = cks.encrypt(clear_1); - - // add the two ciphertexts - let ct_res = sks.mul_msb(&ctxt_0, &ctxt_1); - - let clear = (clear_0 * clear_1) / modulus; - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear % modulus, dec_res); - } -} - -/// test unchecked negation -fn shortint_unchecked_neg

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - // Define the cleartexts - let clear = rng.gen::() % modulus; - - // Encrypt the integers - let ctxt = cks.encrypt(clear); - - // Negates the ctxt - let ct_tmp = sks.unchecked_neg(&ctxt); - - // Decrypt the result - let dec = cks.decrypt(&ct_tmp); - - // Check the correctness - let clear_result = clear.wrapping_neg() % modulus; - - assert_eq!(clear_result, dec); - } -} - -/// test smart negation -fn shortint_smart_neg

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS_SMART { - let clear1 = rng.gen::() % modulus; - - let mut ct1 = cks.encrypt(clear1); - - let mut ct_res = sks.smart_neg(&mut ct1); - - let mut clear_result = clear1.wrapping_neg() % modulus; - - for _ in 0..NB_SUB_TEST_SMART { - // scalar multiplication - ct_res = sks.smart_neg(&mut ct_res); - - clear_result = clear_result.wrapping_neg() % modulus; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_result, dec_res); - } - } -} - -/// test default negation -fn shortint_default_neg

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear1 = rng.gen::() % modulus; - - let ct1 = cks.encrypt(clear1); - - let ct_res = sks.neg(&ct1); - - let clear_result = clear1.wrapping_neg() % modulus; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_result, dec_res); - } -} - -/// test scalar add -fn shortint_unchecked_scalar_add

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - let mut rng = rand::thread_rng(); - - let message_modulus = cks.parameters.message_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % message_modulus; - - let scalar = rng.gen::() % message_modulus; - - // encryption of an integer - let ct = cks.encrypt(clear as u64); - - // add the two ciphertexts - let ct_res = sks.unchecked_scalar_add(&ct, scalar); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear + scalar) % message_modulus, dec_res as u8); - } -} - -/// test smart scalar add -fn shortint_smart_scalar_add

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u8; - - for _ in 0..NB_TESTS_SMART { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0 as u64); - - // add the two ciphertexts - let mut ct_res = sks.smart_scalar_add(&mut ctxt_0, clear_1); - - let mut clear = (clear_0 + clear_1) % modulus; - - // add multiple times to raise the degree - for _ in 0..NB_SUB_TEST_SMART { - ct_res = sks.smart_scalar_add(&mut ct_res, clear_1); - clear = (clear + clear_1) % modulus; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear, dec_res as u8); - } - } -} - -/// test default smart scalar add -fn shortint_default_scalar_add

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0 as u64); - - // add the two ciphertexts - let ct_res = sks.scalar_add(&ctxt_0, clear_1); - - let clear = (clear_0 + clear_1) % modulus; - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear, dec_res as u8); - } -} - -/// test unchecked scalar sub -fn shortint_unchecked_scalar_sub

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - let mut rng = rand::thread_rng(); - - let message_modulus = cks.parameters.message_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % message_modulus; - - let scalar = rng.gen::() % message_modulus; - - // encryption of an integer - let ct = cks.encrypt(clear as u64); - - // add the two ciphertexts - let ct_res = sks.unchecked_scalar_sub(&ct, scalar); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear - scalar) % message_modulus, dec_res as u8); - } -} - -fn shortint_smart_scalar_sub

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u8; - - for _ in 0..NB_TESTS_SMART { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let mut ctxt_0 = cks.encrypt(clear_0 as u64); - - // add the two ciphertexts - let mut ct_res = sks.smart_scalar_sub(&mut ctxt_0, clear_1); - - let mut clear = (clear_0 - clear_1) % modulus; - - // let dec_res = cks.decrypt(&ct_res); - // println!("clear_0 = {}, clear_1 = {}, dec = {}, clear = {}", clear_0, clear_1, dec_res, - // clear); - - // subtract multiple times to raise the degree - for _ in 0..NB_SUB_TEST_SMART { - ct_res = sks.smart_scalar_sub(&mut ct_res, clear_1); - clear = (clear - clear_1) % modulus; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // println!("clear_1 = {}, dec = {}, clear = {}", clear_1, dec_res, clear); - // assert - assert_eq!(clear, dec_res as u8); - } - } -} - -fn shortint_default_scalar_sub

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0 as u64); - - // add the two ciphertexts - let ct_res = sks.scalar_sub(&ctxt_0, clear_1); - - let clear = (clear_0.wrapping_sub(clear_1)) % modulus; - - let dec_res = cks.decrypt(&ct_res); - - assert_eq!(clear, dec_res as u8); - } -} - -/// test scalar multiplication with the LWE server key -fn shortint_unchecked_scalar_mul

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - let mut rng = rand::thread_rng(); - - let message_modulus = cks.parameters.message_modulus().0 as u8; - let carry_modulus = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % message_modulus; - - let scalar = rng.gen::() % carry_modulus; - - // encryption of an integer - let ct = cks.encrypt(clear as u64); - - // add the two ciphertexts - let ct_res = sks.unchecked_scalar_mul(&ct, scalar); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear * scalar) % message_modulus, dec_res as u8); - } -} - -/// test default smart scalar multiplication with the LWE server key -fn shortint_smart_scalar_mul

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u8; - - let scalar_modulus = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS_SMART { - let clear = rng.gen::() % modulus; - - let scalar = rng.gen::() % scalar_modulus; - - // encryption of an integer - let mut ct = cks.encrypt(clear as u64); - - let mut ct_res = sks.smart_scalar_mul(&mut ct, scalar); - - let mut clear_res = clear * scalar; - for _ in 0..NB_SUB_TEST_SMART { - // scalar multiplication - ct_res = sks.smart_scalar_mul(&mut ct_res, scalar); - clear_res = (clear_res * scalar) % modulus; - } - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_res, dec_res as u8); - } -} - -/// test default smart scalar multiplication with the LWE server key -fn shortint_default_scalar_mul

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u8; - - let scalar_modulus = cks.parameters.carry_modulus().0 as u8; - - for _ in 0..NB_TESTS { - let clear = rng.gen::() % modulus; - - let scalar = rng.gen::() % scalar_modulus; - - // encryption of an integer - let ct = cks.encrypt(clear as u64); - - let ct_res = sks.scalar_mul(&ct, scalar); - - let clear_res = (clear * scalar) % modulus; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_res, dec_res as u8); - } -} - -/// test unchecked '>>' operation -fn shortint_unchecked_right_shift

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let shift = rng.gen::() % 2; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // add the two ciphertexts - let ct_res = sks.unchecked_scalar_right_shift(&ctxt_0, shift as u8); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0 >> shift, dec_res); - } -} - -/// test default unchecked '>>' operation -fn shortint_default_right_shift

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let shift = rng.gen::() % 2; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // add the two ciphertexts - let ct_res = sks.scalar_right_shift(&ctxt_0, shift as u8); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_0 >> shift, dec_res); - } -} - -/// test '<<' operation -fn shortint_unchecked_left_shift

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let shift = rng.gen::() % 2; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // add the two ciphertexts - let ct_res = sks.unchecked_scalar_left_shift(&ctxt_0, shift as u8); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 << shift) % modulus, dec_res); - } -} - -/// test default '<<' operation -fn shortint_default_left_shift

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear_0 = rng.gen::() % modulus; - let shift = rng.gen::() % 2; - - // encryption of an integer - let ctxt_0 = cks.encrypt(clear_0); - - // add the two ciphertexts - let ct_res = sks.scalar_left_shift(&ctxt_0, shift as u8); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 << shift) % modulus, dec_res); - } -} - -/// test unchecked subtraction -fn shortint_unchecked_sub

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - for _ in 0..NB_TESTS { - // Define the cleartexts - let clear1 = rng.gen::() % modulus; - let clear2 = rng.gen::() % modulus; - - // Encrypt the integers - let ctxt_1 = cks.encrypt(clear1); - let ctxt_2 = cks.encrypt(clear2); - - // Add the ciphertext 1 and 2 - let ct_tmp = sks.unchecked_sub(&ctxt_1, &ctxt_2); - - // Decrypt the result - let dec = cks.decrypt(&ct_tmp); - - // Check the correctness - let clear_result = (clear1 - clear2) % modulus; - assert_eq!(clear_result, dec % modulus); - } -} - -fn shortint_smart_sub

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS_SMART { - let clear1 = rng.gen::() % modulus; - let clear2 = rng.gen::() % modulus; - - let mut ct1 = cks.encrypt(clear1); - let mut ct2 = cks.encrypt(clear2); - - let mut ct_res = sks.smart_sub(&mut ct1, &mut ct2); - - let mut clear_res = (clear1 - clear2) % modulus; - for _ in 0..NB_SUB_TEST_SMART { - // scalar multiplication - ct_res = sks.smart_sub(&mut ct_res, &mut ct2); - clear_res = (clear_res - clear2) % modulus; - } - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_res, dec_res); - } -} - -fn shortint_default_sub

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..NB_TESTS { - let clear1 = rng.gen::() % modulus; - let clear2 = rng.gen::() % modulus; - - let ct1 = cks.encrypt(clear1); - let ct2 = cks.encrypt(clear2); - - let ct_res = sks.sub(&ct1, &ct2); - - let clear_res = (clear1.wrapping_sub(clear2)) % modulus; - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!(clear_res, dec_res); - } -} - -/// test multiplication -fn shortint_mul_small_carry

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - //RNG - let mut rng = rand::thread_rng(); - - let modulus = cks.parameters.message_modulus().0 as u64; - - for _ in 0..50 { - let clear_0 = rng.gen::() % modulus; - - let clear_1 = rng.gen::() % modulus; - - // encryption of an integer - let ctxt_zero = cks.encrypt(clear_0); - - // encryption of an integer - let ctxt_one = cks.encrypt(clear_1); - - // multiply together the two ciphertexts - let ct_res = sks.unchecked_mul_lsb_small_carry(&ctxt_zero, &ctxt_one); - - // decryption of ct_res - let dec_res = cks.decrypt(&ct_res); - - // assert - assert_eq!((clear_0 * clear_1) % modulus, dec_res % modulus); - } -} - -/// test encryption and decryption with the LWE client key -fn shortint_encrypt_with_message_modulus_smart_add_and_mul

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - let mut rng = rand::thread_rng(); - let full_mod = (cks.parameters.message_modulus().0 * cks.parameters.carry_modulus().0) / 3; - - for _ in 0..NB_TESTS { - let mut modulus = rng.gen::() % full_mod as u64; - while modulus == 0 { - modulus = rng.gen::() % full_mod as u64; - } - - let clear1 = rng.gen::() % modulus; - let clear2 = rng.gen::() % modulus; - - let ct1 = cks.encrypt_with_message_modulus(clear1, MessageModulus(modulus as usize)); - let ct2 = cks.encrypt_with_message_modulus(clear2, MessageModulus(modulus as usize)); - - println!("MUL SMALL CARRY:: clear1 = {clear1}, clear2 = {clear2}, mod = {modulus}"); - let ct_res = sks.unchecked_mul_lsb_small_carry(&ct1, &ct2); - assert_eq!( - (clear1 * clear2) % modulus, - cks.decrypt_message_and_carry(&ct_res) % modulus - ); - - println!("ADD:: clear1 = {clear1}, clear2 = {clear2}, mod = {modulus}"); - let ct_res = sks.unchecked_add(&ct1, &ct2); - assert_eq!((clear1 + clear2), cks.decrypt_message_and_carry(&ct_res)); - } -} - -/// test encryption and decryption with the LWE client key -fn shortint_encrypt_with_message_and_carry_modulus_smart_add_and_mul

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - let mut rng = rand::thread_rng(); - - let param_msg_mod = cks.parameters.message_modulus().0; - let param_carry_mod = cks.parameters.carry_modulus().0; - - for _ in 0..NB_TESTS { - let msg_modulus = rng.gen_range(2u64..param_msg_mod as u64); - let carry_modulus = rng.gen_range(2u64..param_carry_mod as u64); - - let modulus = msg_modulus * carry_modulus; - - let clear1 = rng.gen::() % msg_modulus; - let clear2 = rng.gen::() % msg_modulus; - - let ct1 = cks.encrypt_with_message_and_carry_modulus( - clear1, - MessageModulus(msg_modulus as usize), - CarryModulus(carry_modulus as usize), - ); - let ct2 = cks.encrypt_with_message_and_carry_modulus( - clear2, - MessageModulus(msg_modulus as usize), - CarryModulus(carry_modulus as usize), - ); - - println!("MUL SMALL CARRY:: clear1 = {clear1}, clear2 = {clear2}, msg_mod = {msg_modulus}, carry_mod = {carry_modulus}"); - let ct_res = sks.unchecked_mul_lsb_small_carry(&ct1, &ct2); - assert_eq!( - (clear1 * clear2) % msg_modulus, - cks.decrypt_message_and_carry(&ct_res) % msg_modulus - ); - - println!("ADD:: clear1 = {clear1}, clear2 = {clear2}, msg_mod = {msg_modulus}, carry_mod = {carry_modulus}"); - let ct_res = sks.unchecked_add(&ct1, &ct2); - assert_eq!( - (clear1 + clear2) % modulus, - cks.decrypt_message_and_carry(&ct_res) % modulus - ); - } -} - -/// test simulating a MUX -fn shortint_mux

(param: P) -where - P: Into, -{ - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - let mut rng = rand::thread_rng(); - let modulus = cks.parameters.message_modulus().0 as u64; - - let msg_true = rng.gen::() % modulus; - let msg_false = rng.gen::() % modulus; - let control_bit = rng.gen::() % 2; - - let mut ct_true = cks.encrypt(msg_true); - let mut ct_false = cks.encrypt(msg_false); - let mut ct_control = cks.encrypt(control_bit); - - let mut res = sks.smart_sub(&mut ct_true, &mut ct_false); - sks.smart_mul_lsb_assign(&mut res, &mut ct_control); - sks.smart_add_assign(&mut res, &mut ct_false); - - let dec_res = cks.decrypt(&res); - - let clear_mux = (msg_true - msg_false) * control_bit + msg_false; - println!("(msg_true - msg_false) * control_bit + msg_false = {clear_mux}, res = {dec_res}"); - assert_eq!(clear_mux, dec_res); -} - -fn shortint_trivial_pbs

(param: P) -where - P: Into, -{ - let param = param.into(); - let full_modulus = param.message_modulus().0 as u64 * param.carry_modulus().0 as u64; - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - let check_trivial_bootstrap = |clear, lut: &LookupTableOwned| { - let trivial_ct = sks.unchecked_create_trivial(clear); - let non_trivial_ct = cks.unchecked_encrypt(clear); - - let trivial_res = sks.apply_lookup_table(&trivial_ct, lut); - let non_trivial_res = sks.apply_lookup_table(&non_trivial_ct, lut); - assert!(trivial_res.is_trivial()); - assert!(!non_trivial_res.is_trivial()); - assert_eq!(non_trivial_res.noise_level(), NoiseLevel::NOMINAL); - - let trivial_res = cks.decrypt_message_and_carry(&trivial_res); - let non_trivial_res = cks.decrypt_message_and_carry(&non_trivial_res); - assert_eq!( - trivial_res, non_trivial_res, - "Invalid trivial PBS result expected '{non_trivial_res}', got '{trivial_res}'" - ); - }; - - let functions = [ - Box::new(|x| x) as Box u64>, - Box::new(|x| x % sks.message_modulus.0 as u64) as Box u64>, - Box::new(|x| x / sks.message_modulus.0 as u64) as Box u64>, - ]; - - // Test will be too expensive - if full_modulus >= 64 { - let mut rng = rand::thread_rng(); - // at least do one test - for _ in 0..(NB_TESTS / functions.len()).max(1) { - for f in &functions { - let lut = sks.generate_lookup_table(f); - - let clear_with_clean_padding_bit = rng.gen_range(0..full_modulus); - check_trivial_bootstrap(clear_with_clean_padding_bit, &lut); - - let clear_with_dirty_padding_bit = rng.gen_range(full_modulus..2 * full_modulus); - check_trivial_bootstrap(clear_with_dirty_padding_bit, &lut); - } - } - } else { - for f in functions { - let lut = sks.generate_lookup_table(f); - - // Test 'normal' behaviour (i.e. padding bit set to 0) - for clear_with_clean_padding_bit in 0..full_modulus { - check_trivial_bootstrap(clear_with_clean_padding_bit, &lut); - } - - // Test behaviour when padding bit set to 1 - for clear_with_dirty_padding_bit in full_modulus..(full_modulus * 2) { - check_trivial_bootstrap(clear_with_dirty_padding_bit, &lut); - } - } - } -} - -fn shortint_trivial_pbs_many_lut

(param: P) -where - P: Into, -{ - let param = param.into(); - let msg_modulus = param.message_modulus().0 as u64; - let full_modulus = param.message_modulus().0 as u64 * param.carry_modulus().0 as u64; - let keys = KEY_CACHE.get_from_param(param); - let (cks, sks) = (keys.client_key(), keys.server_key()); - - let check_trivial_bootstrap = |clear, lut: &ManyLookupTableOwned| { - let trivial_ct = sks.unchecked_create_trivial(clear); - let non_trivial_ct = cks.unchecked_encrypt(clear); - - let trivial_res = sks.apply_many_lookup_table(&trivial_ct, lut); - let non_trivial_res = sks.apply_many_lookup_table(&non_trivial_ct, lut); - assert!(trivial_res - .iter() - .all(crate::shortint::ciphertext::Ciphertext::is_trivial)); - assert!(non_trivial_res - .iter() - .all(|ct| !ct.is_trivial() && ct.noise_level() == NoiseLevel::NOMINAL)); - - for (fn_idx, (trivial, non_trivial)) in - trivial_res.iter().zip(non_trivial_res.iter()).enumerate() - { - let trivial = cks.decrypt_message_and_carry(trivial); - let non_trivial = cks.decrypt_message_and_carry(non_trivial); - assert_eq!( - trivial, non_trivial, - "Invalid trivial PBS result got '{trivial}', got non trivial '{non_trivial}' \ - for input {clear} evaluating function #{fn_idx}" - ); - } - }; - - let f1 = |x: u64| x * x % msg_modulus; - let f2 = |x: u64| (x.count_ones() as u64) % msg_modulus; - let f3 = |x: u64| (x.wrapping_add(1)) % msg_modulus; - let f4 = |x: u64| (x.wrapping_sub(1)) % msg_modulus; - let f5 = |x: u64| (x * 2) % msg_modulus; - let f6 = |x: u64| (x * 3) % msg_modulus; - let f7 = |x: u64| (x / 2) % msg_modulus; - let f8 = |x: u64| (x / 3) % msg_modulus; - - let functions: &[&dyn Fn(u64) -> u64] = &[&f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8]; - let max_fn_count = functions.len().min(full_modulus as usize / 2); - - // Test will be too expensive - if full_modulus >= 64 { - let mut rng = rand::thread_rng(); - // at least do one test - for _ in 0..(NB_TESTS / max_fn_count).max(1) { - for fn_count in 1..=max_fn_count { - let functions = &functions[..fn_count]; - let lut = sks.generate_many_lookup_table(functions); - - let clear_with_clean_padding_bit = rng.gen_range(0..full_modulus); - check_trivial_bootstrap(clear_with_clean_padding_bit, &lut); - - let clear_with_dirty_padding_bit = rng.gen_range(full_modulus..2 * full_modulus); - check_trivial_bootstrap(clear_with_dirty_padding_bit, &lut); - } - } - } else { - for fn_count in 1..=max_fn_count { - let functions = &functions[..fn_count]; - let lut = sks.generate_many_lookup_table(functions); - - // Test 'normal' behaviour (i.e. padding bit set to 0) - for clear_with_clean_padding_bit in 0..full_modulus { - check_trivial_bootstrap(clear_with_clean_padding_bit, &lut); - } - - // Test behaviour when padding bit set to 1 - for clear_with_dirty_padding_bit in full_modulus..(full_modulus * 2) { - check_trivial_bootstrap(clear_with_dirty_padding_bit, &lut); - } - } - } -} diff --git a/tfhe/src/shortint/server_key/tests/shortint_compact_pk.rs b/tfhe/src/shortint/server_key/tests/shortint_compact_pk.rs index 7eda5409ca..a13172ced3 100644 --- a/tfhe/src/shortint/server_key/tests/shortint_compact_pk.rs +++ b/tfhe/src/shortint/server_key/tests/shortint_compact_pk.rs @@ -1,7 +1,6 @@ use crate::shortint::keycache::KEY_CACHE; use crate::shortint::parameters::parameters_compact_pk::*; use crate::shortint::parameters::*; -use paste::paste; use rand::Rng; /// Number of assert in randomized tests @@ -24,7 +23,7 @@ const NB_SUB_TEST: usize = 5; #[cfg(not(tarpaulin))] macro_rules! create_parametrized_test{ ($name:ident { $($param:ident),* }) => { - paste! { + ::paste::paste! { $( #[test] fn []() { @@ -100,7 +99,7 @@ macro_rules! create_parametrized_test{ #[cfg(tarpaulin)] macro_rules! create_parametrized_test{ ($name:ident { $($param:ident),* }) => { - paste! { + ::paste::paste! { $( #[test] fn []() { @@ -153,10 +152,8 @@ fn shortint_compact_public_key_base_smart_add(params: ClassicPBSParameters) { sks.smart_add_assign(&mut ct_res, &mut ctxt_0); clear += clear_0; - // decryption of ct_res let dec_res = cks.decrypt(&ct_res); - // assert assert_eq!(clear % modulus, dec_res); } } diff --git a/tfhe/src/shortint/wopbs/mod.rs b/tfhe/src/shortint/wopbs/mod.rs index f7429ee101..02123ba33f 100644 --- a/tfhe/src/shortint/wopbs/mod.rs +++ b/tfhe/src/shortint/wopbs/mod.rs @@ -891,11 +891,8 @@ impl WopbsKey { ) -> Ciphertext { let extracted_bits = self.extract_bits(delta_log, ct_in, nb_bit_to_extract); - let ciphertext_list = self.circuit_bootstrap_with_bits( - &extracted_bits.as_view(), - &lut.lut(), - LweCiphertextCount(1), - ); + let ciphertext_list = + self.circuit_bootstrap_with_bits(&extracted_bits, &lut.lut(), LweCiphertextCount(1)); // Here the output list contains a single ciphertext, we can consume the container to // convert it to a single ciphertext diff --git a/tfhe/src/shortint/wopbs/test.rs b/tfhe/src/shortint/wopbs/test.rs index 0d99e499a9..6adff9c407 100644 --- a/tfhe/src/shortint/wopbs/test.rs +++ b/tfhe/src/shortint/wopbs/test.rs @@ -6,7 +6,6 @@ use crate::shortint::parameters::{ }; use crate::shortint::wopbs::WopbsKey; use crate::shortint::{gen_keys, ClassicPBSParameters, WopbsParameters}; -use paste::paste; use rand::Rng; const NB_TESTS: usize = 1; @@ -14,7 +13,7 @@ const NB_TESTS: usize = 1; #[cfg(not(tarpaulin))] macro_rules! create_parametrized_test{ ($name:ident { $( ($sks_param:ident, $wopbs_param:ident) ),* }) => { - paste! { + ::paste::paste! { $( #[test] fn []() { @@ -37,7 +36,7 @@ macro_rules! create_parametrized_test{ #[cfg(not(tarpaulin))] macro_rules! create_parametrized_wopbs_only_test{ ($name:ident { $( $wopbs_param:ident ),* }) => { - paste! { + ::paste::paste! { $( #[test] fn []() { @@ -61,7 +60,7 @@ macro_rules! create_parametrized_wopbs_only_test{ #[cfg(tarpaulin)] macro_rules! create_parametrized_test{ ($name:ident { $( ($sks_param:ident, $wopbs_param:ident) ),* }) => { - paste! { + ::paste::paste! { $( #[test] fn []() { @@ -81,7 +80,7 @@ macro_rules! create_parametrized_test{ #[cfg(tarpaulin)] macro_rules! create_parametrized_wopbs_only_test{ ($name:ident { $( $wopbs_param:ident ),* }) => { - paste! { + ::paste::paste! { $( #[test] fn []() {