diff --git a/.github/workflows/code_coverage.yml b/.github/workflows/code_coverage.yml index e407ba7c9..6084dc251 100644 --- a/.github/workflows/code_coverage.yml +++ b/.github/workflows/code_coverage.yml @@ -38,6 +38,7 @@ jobs: group: ${{ github.workflow }}_${{ github.ref }}_${{ inputs.instance_image_id }}_${{ inputs.instance_type }} cancel-in-progress: true runs-on: ${{ inputs.runner_name }} + timeout-minutes: 1080 steps: # Step used for log purpose. - name: Instance configuration used @@ -79,6 +80,12 @@ jobs: if: steps.changed-files.outputs.tfhe_any_changed == 'true' run: | make GEN_KEY_CACHE_COVERAGE_ONLY=TRUE gen_key_cache + make gen_key_cache_core_crypto + + - name: Run coverage for core_crypto + if: steps.changed-files.outputs.tfhe_any_changed == 'true' + run: | + make test_core_crypto_cov AVX512_SUPPORT=ON - name: Run coverage for boolean if: steps.changed-files.outputs.tfhe_any_changed == 'true' @@ -97,7 +104,7 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} directory: ./coverage/ fail_ci_if_error: true - files: shortint/cobertura.xml,boolean/cobertura.xml + files: shortint/cobertura.xml,boolean/cobertura.xml,core_crypto/cobertura.xml,core_crypto_avx512/cobertura.xml - name: Slack Notification if: ${{ failure() }} diff --git a/Makefile b/Makefile index 115a880ba..34707fb5f 100644 --- a/Makefile +++ b/Makefile @@ -225,13 +225,6 @@ clippy_js_wasm_api clippy_tasks clippy_core clippy_concrete_csprng clippy_triviu clippy_fast: clippy clippy_all_targets clippy_c_api clippy_js_wasm_api clippy_tasks clippy_core \ clippy_concrete_csprng -.PHONY: gen_key_cache # Run the script to generate keys and cache them for shortint tests -gen_key_cache: install_rs_build_toolchain - RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) run --profile $(CARGO_PROFILE) \ - --example generates_test_keys \ - --features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache -- \ - $(MULTI_BIT_ONLY) $(COVERAGE_ONLY) - .PHONY: build_core # Build core_crypto without experimental features build_core: install_rs_build_toolchain install_rs_check_toolchain RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) build --profile $(CARGO_PROFILE) \ @@ -319,6 +312,21 @@ test_core_crypto: install_rs_build_toolchain install_rs_check_toolchain --features=$(TARGET_ARCH_FEATURE),experimental,$(AVX512_FEATURE) -p $(TFHE_SPEC) -- core_crypto::; \ fi +.PHONY: test_core_crypto_cov # Run the tests of the core_crypto module with code coverage +test_core_crypto_cov: install_rs_build_toolchain install_rs_check_toolchain install_tarpaulin + RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) tarpaulin --profile $(CARGO_PROFILE) \ + --out xml --output-dir coverage/core_crypto --line --engine llvm --timeout 500 \ + --implicit-test-threads $(COVERAGE_EXCLUDED_FILES) \ + --features=$(TARGET_ARCH_FEATURE),experimental,internal-keycache,__coverage \ + -p tfhe -- core_crypto:: + @if [[ "$(AVX512_SUPPORT)" == "ON" ]]; then \ + RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) tarpaulin --profile $(CARGO_PROFILE) \ + --out xml --output-dir coverage/core_crypto_avx512 --line --engine llvm --timeout 500 \ + --implicit-test-threads $(COVERAGE_EXCLUDED_FILES) \ + --features=$(TARGET_ARCH_FEATURE),experimental,internal-keycache,__coverage,$(AVX512_FEATURE) \ + -p tfhe -- core_crypto::; \ + fi + .PHONY: test_boolean # Run the tests of the boolean module test_boolean: install_rs_build_toolchain RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \ @@ -627,6 +635,18 @@ ci_bench_web_js_api_parallel: build_web_js_api_parallel # # Utility tools # +.PHONY: gen_key_cache # Run the script to generate keys and cache them for shortint tests +gen_key_cache: install_rs_build_toolchain + RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) run --profile $(CARGO_PROFILE) \ + --example generates_test_keys \ + --features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache -- \ + $(MULTI_BIT_ONLY) $(COVERAGE_ONLY) + +.PHONY: gen_key_cache_core_crypto # Run function to generate keys and cache them for core_crypto tests +gen_key_cache_core_crypto: install_rs_build_toolchain + RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --tests --profile $(CARGO_PROFILE) \ + --features=$(TARGET_ARCH_FEATURE),experimental,internal-keycache -p tfhe -- --nocapture \ + core_crypto::keycache::generate_keys .PHONY: measure_hlapi_compact_pk_ct_sizes # Measure sizes of public keys and ciphertext for high-level API measure_hlapi_compact_pk_ct_sizes: install_rs_check_toolchain diff --git a/tfhe/src/core_crypto/algorithms/mod.rs b/tfhe/src/core_crypto/algorithms/mod.rs index 8a27a5913..1d0436e4f 100644 --- a/tfhe/src/core_crypto/algorithms/mod.rs +++ b/tfhe/src/core_crypto/algorithms/mod.rs @@ -44,7 +44,7 @@ pub mod seeded_lwe_public_key_decompression; pub mod slice_algorithms; #[cfg(test)] -mod test; +pub(crate) mod test; // No pub use for slice and polynomial algorithms which would not interest higher level users // They can still be used via `use crate::core_crypto::algorithms::slice_algorithms::*;` diff --git a/tfhe/src/core_crypto/algorithms/test/ggsw_encryption.rs b/tfhe/src/core_crypto/algorithms/test/ggsw_encryption.rs index e6fd75c37..ec20e6295 100644 --- a/tfhe/src/core_crypto/algorithms/test/ggsw_encryption.rs +++ b/tfhe/src/core_crypto/algorithms/test/ggsw_encryption.rs @@ -6,6 +6,11 @@ use crate::core_crypto::commons::generators::{ use crate::core_crypto::commons::math::random::{ActivatedRandomGenerator, CompressionSeed}; use crate::core_crypto::commons::test_tools; +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + fn test_parallel_and_seeded_ggsw_encryption_equivalence( ciphertext_modulus: CiphertextModulus, ) where @@ -27,8 +32,6 @@ fn test_parallel_and_seeded_ggsw_encryption_equivalence( let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - const NB_TESTS: usize = 10; - for _ in 0..NB_TESTS { // Create the GlweSecretKey let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( @@ -174,7 +177,7 @@ fn test_parallel_and_seeded_ggsw_encryption_equivalence_u64_custom_mod() { ); } -fn ggsw_encrypt_decrypt_custom_mod(params: TestParams) { +fn ggsw_encrypt_decrypt_custom_mod(params: ClassicTestParams) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -184,8 +187,6 @@ fn ggsw_encrypt_decrypt_custom_mod(params: TestParams(params: TestParams( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -249,8 +255,6 @@ fn ggsw_par_encrypt_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; - let mut msg = Scalar::ONE << decomposition_base_log.0; while msg != Scalar::ZERO { @@ -297,12 +301,19 @@ fn ggsw_par_encrypt_decrypt_custom_mod( assert!(decoded.0 == msg); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(ggsw_par_encrypt_decrypt_custom_mod); -fn ggsw_seeded_encrypt_decrypt_custom_mod(params: TestParams) { +fn ggsw_seeded_encrypt_decrypt_custom_mod( + params: ClassicTestParams, +) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -312,8 +323,6 @@ fn ggsw_seeded_encrypt_decrypt_custom_mod(params: TestPar let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; - let mut msg = Scalar::ONE << decomposition_base_log.0; while msg != Scalar::ZERO { @@ -363,13 +372,18 @@ fn ggsw_seeded_encrypt_decrypt_custom_mod(params: TestPar assert!(decoded.0 == msg); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(ggsw_seeded_encrypt_decrypt_custom_mod); fn ggsw_seeded_par_encrypt_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -380,8 +394,6 @@ fn ggsw_seeded_par_encrypt_decrypt_custom_mod(params: TestParams) { +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + +fn glwe_encrypt_assign_decrypt_custom_mod( + params: ClassicTestParams, +) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -10,7 +17,6 @@ fn glwe_encrypt_assign_decrypt_custom_mod(params: TestPar let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -57,12 +63,17 @@ fn glwe_encrypt_assign_decrypt_custom_mod(params: TestPar assert!(decoded.iter().all(|&x| x == msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_encrypt_assign_decrypt_custom_mod); -fn glwe_encrypt_decrypt_custom_mod(params: TestParams) { +fn glwe_encrypt_decrypt_custom_mod(params: ClassicTestParams) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -72,7 +83,6 @@ fn glwe_encrypt_decrypt_custom_mod(params: TestParams(params: TestParams(params: TestParams) { +fn glwe_list_encrypt_decrypt_custom_mod(params: ClassicTestParams) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -139,7 +154,6 @@ fn glwe_list_encrypt_decrypt_custom_mod(params: TestParam let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -195,12 +209,19 @@ fn glwe_list_encrypt_decrypt_custom_mod(params: TestParam assert!(decoded.iter().all(|&x| x == msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_list_encrypt_decrypt_custom_mod); -fn glwe_trivial_encrypt_decrypt_custom_mod(params: TestParams) { +fn glwe_trivial_encrypt_decrypt_custom_mod( + params: ClassicTestParams, +) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let ciphertext_modulus = params.ciphertext_modulus; @@ -209,7 +230,6 @@ fn glwe_trivial_encrypt_decrypt_custom_mod(params: TestPa let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -254,13 +274,18 @@ fn glwe_trivial_encrypt_decrypt_custom_mod(params: TestPa assert!(decoded.iter().all(|&x| x == msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_trivial_encrypt_decrypt_custom_mod); fn glwe_allocate_trivial_encrypt_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -270,7 +295,6 @@ fn glwe_allocate_trivial_encrypt_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -308,12 +332,19 @@ fn glwe_allocate_trivial_encrypt_decrypt_custom_mod( assert!(output_plaintext_list.iter().all(|x| *x.0 == msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_allocate_trivial_encrypt_decrypt_custom_mod); -fn glwe_seeded_encrypt_decrypt_custom_mod(params: TestParams) { +fn glwe_seeded_encrypt_decrypt_custom_mod( + params: ClassicTestParams, +) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -323,7 +354,6 @@ fn glwe_seeded_encrypt_decrypt_custom_mod(params: TestPar let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -384,12 +414,19 @@ fn glwe_seeded_encrypt_decrypt_custom_mod(params: TestPar assert!(decoded.iter().all(|&x| x == msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_seeded_encrypt_decrypt_custom_mod); -fn glwe_seeded_list_encrypt_decrypt_custom_mod(params: TestParams) { +fn glwe_seeded_list_encrypt_decrypt_custom_mod( + params: ClassicTestParams, +) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -400,7 +437,6 @@ fn glwe_seeded_list_encrypt_decrypt_custom_mod(params: Te let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -459,6 +495,11 @@ fn glwe_seeded_list_encrypt_decrypt_custom_mod(params: Te assert!(decoded.iter().all(|&x| x == msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } diff --git a/tfhe/src/core_crypto/algorithms/test/glwe_linear_algebra.rs b/tfhe/src/core_crypto/algorithms/test/glwe_linear_algebra.rs index b277a3fa5..2b29015ac 100644 --- a/tfhe/src/core_crypto/algorithms/test/glwe_linear_algebra.rs +++ b/tfhe/src/core_crypto/algorithms/test/glwe_linear_algebra.rs @@ -1,6 +1,13 @@ use super::*; -fn glwe_encrypt_add_assign_decrypt_custom_mod(params: TestParams) { +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + +fn glwe_encrypt_add_assign_decrypt_custom_mod( + params: ClassicTestParams, +) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -10,7 +17,6 @@ fn glwe_encrypt_add_assign_decrypt_custom_mod(params: Tes let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -70,12 +76,17 @@ fn glwe_encrypt_add_assign_decrypt_custom_mod(params: Tes assert!(decoded.iter().all(|&x| x == (msg + msg) % msg_modulus)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_encrypt_add_assign_decrypt_custom_mod); -fn glwe_encrypt_add_decrypt_custom_mod(params: TestParams) { +fn glwe_encrypt_add_decrypt_custom_mod(params: ClassicTestParams) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -85,7 +96,6 @@ fn glwe_encrypt_add_decrypt_custom_mod(params: TestParams let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -147,13 +157,18 @@ fn glwe_encrypt_add_decrypt_custom_mod(params: TestParams assert!(decoded.iter().all(|&x| x == (msg + msg) % msg_modulus)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_encrypt_add_decrypt_custom_mod); fn glwe_encrypt_plaintext_list_add_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -164,7 +179,6 @@ fn glwe_encrypt_plaintext_list_add_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -239,7 +258,6 @@ fn glwe_encrypt_plaintext_list_sub_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -314,7 +337,6 @@ fn glwe_encrypt_plaintext_add_assign_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -373,13 +395,18 @@ fn glwe_encrypt_plaintext_add_assign_decrypt_custom_mod( assert!(decoded.iter().all(|&x| x == (msg + msg) % msg_modulus)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_encrypt_plaintext_add_assign_decrypt_custom_mod); fn glwe_encrypt_plaintext_sub_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -390,7 +417,6 @@ fn glwe_encrypt_plaintext_sub_assign_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -449,13 +475,18 @@ fn glwe_encrypt_plaintext_sub_assign_decrypt_custom_mod( assert!(decoded.iter().all(|&x| x == Scalar::ZERO)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_encrypt_plaintext_sub_assign_decrypt_custom_mod); fn glwe_encrypt_opposite_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -466,7 +497,6 @@ fn glwe_encrypt_opposite_assign_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -526,13 +556,18 @@ fn glwe_encrypt_opposite_assign_decrypt_custom_mod( .iter() .all(|&x| x == msg.wrapping_neg() % msg_modulus)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_encrypt_opposite_assign_decrypt_custom_mod); fn glwe_encrypt_cleartext_mul_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -543,7 +578,6 @@ fn glwe_encrypt_cleartext_mul_assign_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -604,13 +638,18 @@ fn glwe_encrypt_cleartext_mul_assign_decrypt_custom_mod( .iter() .all(|&x| x == (msg * cleartext.0) % msg_modulus)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_encrypt_cleartext_mul_assign_decrypt_custom_mod); fn glwe_encrypt_cleartext_mul_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -621,7 +660,6 @@ fn glwe_encrypt_cleartext_mul_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -684,12 +722,19 @@ fn glwe_encrypt_cleartext_mul_decrypt_custom_mod( .iter() .all(|&x| x == (msg * cleartext.0) % msg_modulus)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_encrypt_cleartext_mul_decrypt_custom_mod); -fn glwe_encrypt_sub_assign_decrypt_custom_mod(params: TestParams) { +fn glwe_encrypt_sub_assign_decrypt_custom_mod( + params: ClassicTestParams, +) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -699,7 +744,6 @@ fn glwe_encrypt_sub_assign_decrypt_custom_mod(params: Tes let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -759,12 +803,17 @@ fn glwe_encrypt_sub_assign_decrypt_custom_mod(params: Tes assert!(decoded.iter().all(|&x| x == Scalar::ZERO)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(glwe_encrypt_sub_assign_decrypt_custom_mod); -fn glwe_encrypt_sub_decrypt_custom_mod(params: TestParams) { +fn glwe_encrypt_sub_decrypt_custom_mod(params: ClassicTestParams) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -774,7 +823,6 @@ fn glwe_encrypt_sub_decrypt_custom_mod(params: TestParams let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -836,6 +884,11 @@ fn glwe_encrypt_sub_decrypt_custom_mod(params: TestParams assert!(decoded.iter().all(|&x| x == Scalar::ZERO)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } diff --git a/tfhe/src/core_crypto/algorithms/test/glwe_sample_extraction.rs b/tfhe/src/core_crypto/algorithms/test/glwe_sample_extraction.rs index d9aeba7e6..bae42f5ea 100644 --- a/tfhe/src/core_crypto/algorithms/test/glwe_sample_extraction.rs +++ b/tfhe/src/core_crypto/algorithms/test/glwe_sample_extraction.rs @@ -1,7 +1,11 @@ use super::*; +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; fn glwe_encrypt_sample_extract_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; @@ -12,7 +16,6 @@ fn glwe_encrypt_sample_extract_decrypt_custom_mod( ciphertext_modulus: CiphertextModulus, ) { - for _ in 0..10 { + for _ in 0..NB_TESTS { let lwe_dim = LweDimension(crate::core_crypto::commons::test_tools::random_usize_between(5..10)); let glwe_dim = diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_compact_public_key_generation.rs b/tfhe/src/core_crypto/algorithms/test/lwe_compact_public_key_generation.rs index 79c8f982f..f61baa6fd 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_compact_public_key_generation.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_compact_public_key_generation.rs @@ -5,6 +5,11 @@ use crate::core_crypto::commons::generators::{ }; use crate::core_crypto::commons::math::random::ActivatedRandomGenerator; +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + fn test_seeded_lwe_cpk_gen_equivalence( ciphertext_modulus: CiphertextModulus, ) { @@ -22,9 +27,7 @@ fn test_seeded_lwe_cpk_gen_equivalence( let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - const NB_TEST: usize = 10; - - for _ in 0..NB_TEST { + for _ in 0..NB_TESTS { // Create the LweSecretKey let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key(lwe_dimension, &mut secret_generator); diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs b/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs index 1892e698b..5d8cec716 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs @@ -2,8 +2,13 @@ use super::*; use crate::core_crypto::commons::generators::DeterministicSeeder; use crate::core_crypto::commons::test_tools; +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + fn test_parallel_and_seeded_lwe_list_encryption_equivalence( - params: TestParams, + params: ClassicTestParams, ) { // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct // computations @@ -21,8 +26,6 @@ fn test_parallel_and_seeded_lwe_list_encryption_equivalence::new(seeder.seed()); - const NB_TESTS: usize = 10; - for _ in 0..NB_TESTS { // Create the LweSecretKey let lwe_secret_key = @@ -148,7 +151,7 @@ fn test_parallel_and_seeded_lwe_list_encryption_equivalence_non_native_power_of_ test_parallel_and_seeded_lwe_list_encryption_equivalence(DUMMY_31_U32); } -fn lwe_encrypt_decrypt_custom_mod(params: TestParams) { +fn lwe_encrypt_decrypt_custom_mod(params: ClassicTestParams) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -157,7 +160,6 @@ fn lwe_encrypt_decrypt_custom_mod(params: TestParams(params: TestParams(params: TestParams) { +fn lwe_allocate_encrypt_decrypt_custom_mod( + params: ClassicTestParams, +) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -211,7 +220,6 @@ fn lwe_allocate_encrypt_decrypt_custom_mod(params: TestPa let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -245,12 +253,19 @@ fn lwe_allocate_encrypt_decrypt_custom_mod(params: TestPa assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_allocate_encrypt_decrypt_custom_mod); -fn lwe_trivial_encrypt_decrypt_custom_mod(params: TestParams) { +fn lwe_trivial_encrypt_decrypt_custom_mod( + params: ClassicTestParams, +) { let lwe_dimension = params.lwe_dimension; let ciphertext_modulus = params.ciphertext_modulus; let message_modulus_log = params.message_modulus_log; @@ -258,7 +273,6 @@ fn lwe_trivial_encrypt_decrypt_custom_mod(params: TestPar let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -292,12 +306,17 @@ fn lwe_trivial_encrypt_decrypt_custom_mod(params: TestPar assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_trivial_encrypt_decrypt_custom_mod); fn lwe_allocate_trivial_encrypt_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let ciphertext_modulus = params.ciphertext_modulus; @@ -306,7 +325,6 @@ fn lwe_allocate_trivial_encrypt_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -338,12 +356,17 @@ fn lwe_allocate_trivial_encrypt_decrypt_custom_mod( assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_allocate_trivial_encrypt_decrypt_custom_mod); -fn lwe_list_encrypt_decrypt_custom_mod(params: TestParams) { +fn lwe_list_encrypt_decrypt_custom_mod(params: ClassicTestParams) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -353,7 +376,6 @@ fn lwe_list_encrypt_decrypt_custom_mod(params: TestParams let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -403,13 +425,18 @@ fn lwe_list_encrypt_decrypt_custom_mod(params: TestParams assert!(decoded.iter().all(|&x| x == msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_list_encrypt_decrypt_custom_mod); fn lwe_list_par_encrypt_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; @@ -420,7 +447,6 @@ fn lwe_list_par_encrypt_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -470,12 +496,17 @@ fn lwe_list_par_encrypt_decrypt_custom_mod( assert!(decoded.iter().all(|&x| x == msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_list_par_encrypt_decrypt_custom_mod); -fn lwe_public_encrypt_decrypt_custom_mod(params: TestParams) { +fn lwe_public_encrypt_decrypt_custom_mod(params: ClassicTestParams) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -485,7 +516,6 @@ fn lwe_public_encrypt_decrypt_custom_mod(params: TestPara let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -532,12 +562,19 @@ fn lwe_public_encrypt_decrypt_custom_mod(params: TestPara assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_public_encrypt_decrypt_custom_mod); -fn lwe_seeded_public_encrypt_decrypt_custom_mod(params: TestParams) { +fn lwe_seeded_public_encrypt_decrypt_custom_mod( + params: ClassicTestParams, +) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -547,7 +584,6 @@ fn lwe_seeded_public_encrypt_decrypt_custom_mod(params: T let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -601,13 +637,18 @@ fn lwe_seeded_public_encrypt_decrypt_custom_mod(params: T assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_seeded_public_encrypt_decrypt_custom_mod); fn lwe_seeded_list_par_encrypt_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; @@ -618,7 +659,6 @@ fn lwe_seeded_list_par_encrypt_decrypt_custom_mod(params: TestParams) { +fn lwe_seeded_encrypt_decrypt_custom_mod(params: ClassicTestParams) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -694,7 +739,6 @@ fn lwe_seeded_encrypt_decrypt_custom_mod(params: TestPara let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -742,13 +786,18 @@ fn lwe_seeded_encrypt_decrypt_custom_mod(params: TestPara assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_seeded_encrypt_decrypt_custom_mod); fn lwe_seeded_allocate_encrypt_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; @@ -758,7 +807,6 @@ fn lwe_seeded_allocate_encrypt_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -799,6 +847,11 @@ fn lwe_seeded_allocate_encrypt_decrypt_custom_mod( assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } @@ -820,7 +873,6 @@ fn test_u128_encryption() { let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - const NB_TESTS: usize = 10; const MSG_BITS: u32 = 4; for _ in 0..NB_TESTS { @@ -870,7 +922,7 @@ fn test_u128_encryption() { } fn lwe_compact_public_encrypt_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = LweDimension(params.polynomial_size.0); let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -880,7 +932,6 @@ fn lwe_compact_public_encrypt_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -929,6 +980,11 @@ fn lwe_compact_public_encrypt_decrypt_custom_mod( assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_keyswitch.rs b/tfhe/src/core_crypto/algorithms/test/lwe_keyswitch.rs index c172a4dbd..b70b8f7a8 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_keyswitch.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_keyswitch.rs @@ -1,7 +1,12 @@ use super::*; +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + fn lwe_encrypt_ks_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; @@ -15,7 +20,6 @@ fn lwe_encrypt_ks_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -94,6 +98,11 @@ fn lwe_encrypt_ks_decrypt_custom_mod( assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_keyswitch_key_generation.rs b/tfhe/src/core_crypto/algorithms/test/lwe_keyswitch_key_generation.rs index 54042ac83..d45126793 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_keyswitch_key_generation.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_keyswitch_key_generation.rs @@ -5,6 +5,11 @@ use crate::core_crypto::commons::generators::{ }; use crate::core_crypto::commons::math::random::ActivatedRandomGenerator; +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + fn test_seeded_lwe_ksk_gen_equivalence( ciphertext_modulus: CiphertextModulus, ) { @@ -25,9 +30,7 @@ fn test_seeded_lwe_ksk_gen_equivalence( let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - const NB_TEST: usize = 10; - - for _ in 0..NB_TEST { + for _ in 0..NB_TESTS { // Create the LweSecretKey let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( input_lwe_dimension, diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_linear_algebra.rs b/tfhe/src/core_crypto/algorithms/test/lwe_linear_algebra.rs index aa1b95b1b..8205743e8 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_linear_algebra.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_linear_algebra.rs @@ -1,6 +1,13 @@ use super::*; -fn lwe_encrypt_add_assign_decrypt_custom_mod(params: TestParams) { +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + +fn lwe_encrypt_add_assign_decrypt_custom_mod( + params: ClassicTestParams, +) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -9,7 +16,6 @@ fn lwe_encrypt_add_assign_decrypt_custom_mod(params: Test let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -58,12 +64,17 @@ fn lwe_encrypt_add_assign_decrypt_custom_mod(params: Test assert_eq!((msg + msg) % msg_modulus, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_encrypt_add_assign_decrypt_custom_mod); -fn lwe_encrypt_add_decrypt_custom_mod(params: TestParams) { +fn lwe_encrypt_add_decrypt_custom_mod(params: ClassicTestParams) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -72,7 +83,6 @@ fn lwe_encrypt_add_decrypt_custom_mod(params: TestParams< let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -121,13 +131,18 @@ fn lwe_encrypt_add_decrypt_custom_mod(params: TestParams< assert_eq!((msg + msg) % msg_modulus, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_encrypt_add_decrypt_custom_mod); fn lwe_encrypt_plaintext_add_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; @@ -137,7 +152,6 @@ fn lwe_encrypt_plaintext_add_assign_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -184,13 +198,18 @@ fn lwe_encrypt_plaintext_add_assign_decrypt_custom_mod( assert_eq!((msg + msg) % msg_modulus, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_encrypt_plaintext_add_assign_decrypt_custom_mod); fn lwe_encrypt_plaintext_sub_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; @@ -200,7 +219,6 @@ fn lwe_encrypt_plaintext_sub_assign_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -247,13 +265,18 @@ fn lwe_encrypt_plaintext_sub_assign_decrypt_custom_mod( assert_eq!(Scalar::ZERO, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_encrypt_plaintext_sub_assign_decrypt_custom_mod); fn lwe_encrypt_opposite_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; @@ -263,7 +286,6 @@ fn lwe_encrypt_opposite_assign_decrypt_custom_mod( let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -310,13 +332,18 @@ fn lwe_encrypt_opposite_assign_decrypt_custom_mod( assert_eq!(msg.wrapping_neg() % msg_modulus, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_encrypt_opposite_assign_decrypt_custom_mod); fn lwe_encrypt_ciphertext_cleartext_mul_assign_decrypt_custom_mod( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; @@ -326,7 +353,6 @@ fn lwe_encrypt_ciphertext_cleartext_mul_assign_decrypt_custom_mod(params: TestParams) { +fn lwe_encrypt_cleartext_mul_decrypt_custom_mod( + params: ClassicTestParams, +) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -388,7 +421,6 @@ fn lwe_encrypt_cleartext_mul_decrypt_custom_mod(params: T let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -438,12 +470,19 @@ fn lwe_encrypt_cleartext_mul_decrypt_custom_mod(params: T assert_eq!((msg * cleartext.0) % msg_modulus, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_encrypt_cleartext_mul_decrypt_custom_mod); -fn lwe_encrypt_sub_assign_decrypt_custom_mod(params: TestParams) { +fn lwe_encrypt_sub_assign_decrypt_custom_mod( + params: ClassicTestParams, +) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -452,7 +491,6 @@ fn lwe_encrypt_sub_assign_decrypt_custom_mod(params: Test let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -521,12 +559,17 @@ fn lwe_encrypt_sub_assign_decrypt_custom_mod(params: Test assert_eq!(Scalar::ONE, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_encrypt_sub_assign_decrypt_custom_mod); -fn lwe_encrypt_sub_decrypt_custom_mod(params: TestParams) { +fn lwe_encrypt_sub_decrypt_custom_mod(params: ClassicTestParams) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; @@ -535,7 +578,6 @@ fn lwe_encrypt_sub_decrypt_custom_mod(params: TestParams< let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -606,6 +648,11 @@ fn lwe_encrypt_sub_decrypt_custom_mod(params: TestParams< assert_eq!(Scalar::ONE, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_multi_bit_bootstrap_key_generation.rs b/tfhe/src/core_crypto/algorithms/test/lwe_multi_bit_bootstrap_key_generation.rs index 8ce24eb8a..b218cc47c 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_multi_bit_bootstrap_key_generation.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_multi_bit_bootstrap_key_generation.rs @@ -11,12 +11,17 @@ use crate::core_crypto::commons::test_tools::new_secret_random_generator; use crate::core_crypto::entities::*; use crate::core_crypto::prelude::CastFrom; +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + fn test_parallel_and_seeded_multi_bit_bsk_gen_equivalence< T: UnsignedTorus + CastFrom + Sync + Send, >( ciphertext_modulus: CiphertextModulus, ) { - for _ in 0..10 { + for _ in 0..NB_TESTS { let mut lwe_dim = LweDimension(crate::core_crypto::commons::test_tools::random_usize_between(5..10)); let glwe_dim = diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_multi_bit_programmable_bootstrapping.rs b/tfhe/src/core_crypto/algorithms/test/lwe_multi_bit_programmable_bootstrapping.rs index d7f241b24..7472c10a8 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_multi_bit_programmable_bootstrapping.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_multi_bit_programmable_bootstrapping.rs @@ -1,36 +1,94 @@ use super::*; +use crate::core_crypto::keycache::KeyCacheAccess; +use serde::de::DeserializeOwned; +use serde::Serialize; -pub struct MultiBitParams { - pub input_lwe_dimension: LweDimension, - pub lwe_modular_std_dev: StandardDev, - pub decomp_base_log: DecompositionBaseLog, - pub decomp_level_count: DecompositionLevelCount, - pub glwe_dimension: GlweDimension, - pub polynomial_size: PolynomialSize, - pub glwe_modular_std_dev: StandardDev, - pub message_modulus_log: CiphertextModulusLog, - pub ciphertext_modulus: CiphertextModulus, - pub grouping_factor: LweBskGroupingFactor, - pub thread_count: ThreadCount, +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(not(feature = "__coverage"))] +// Divided by two compared to other tests, we are running the algorithm twice for determinism +const NB_TESTS_LIGHT: usize = 5; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; +#[cfg(feature = "__coverage")] +const NB_TESTS_LIGHT: usize = 1; + +pub fn generate_keys< + Scalar: UnsignedTorus + Sync + Send + CastFrom + CastInto + Serialize + DeserializeOwned, +>( + params: MultiBitTestParams, + rsc: &mut TestResources, +) -> MultiBitBootstrapKeys { + // Keygen is a bit slow on this one so we keep it out of the testing loop + + // Create the LweSecretKey + let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( + params.input_lwe_dimension, + &mut rsc.secret_random_generator, + ); + let output_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( + params.glwe_dimension, + params.polynomial_size, + &mut rsc.secret_random_generator, + ); + let output_lwe_secret_key = output_glwe_secret_key.clone().into_lwe_secret_key(); + + let mut bsk = LweMultiBitBootstrapKey::new( + Scalar::ZERO, + params.glwe_dimension.to_glwe_size(), + params.polynomial_size, + params.decomp_base_log, + params.decomp_level_count, + params.input_lwe_dimension, + params.grouping_factor, + params.ciphertext_modulus, + ); + + par_generate_lwe_multi_bit_bootstrap_key( + &input_lwe_secret_key, + &output_glwe_secret_key, + &mut bsk, + params.glwe_modular_std_dev, + &mut rsc.encryption_random_generator, + ); + + let mut fbsk = FourierLweMultiBitBootstrapKey::new( + params.input_lwe_dimension, + params.glwe_dimension.to_glwe_size(), + params.polynomial_size, + params.decomp_base_log, + params.decomp_level_count, + params.grouping_factor, + ); + + par_convert_standard_lwe_multi_bit_bootstrap_key_to_fourier(&bsk, &mut fbsk); + + MultiBitBootstrapKeys { + small_lwe_sk: input_lwe_secret_key, + big_lwe_sk: output_lwe_secret_key, + bsk, + fbsk, + } } -fn lwe_encrypt_multi_bit_pbs_decrypt_custom_mod< - Scalar: UnsignedTorus + Sync + Send + CastFrom + CastInto, ->( - params: MultiBitParams, -) { - let input_lwe_dimension = params.input_lwe_dimension; +fn lwe_encrypt_multi_bit_pbs_decrypt_custom_mod(params: MultiBitTestParams) +where + Scalar: UnsignedTorus + + Sync + + Send + + CastFrom + + CastInto + + Serialize + + DeserializeOwned, + MultiBitTestParams: KeyCacheAccess>, +{ let lwe_modular_std_dev = params.lwe_modular_std_dev; - let glwe_modular_std_dev = params.glwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; let message_modulus_log = params.message_modulus_log; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus); let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; - let decomp_base_log = params.decomp_base_log; - let decomp_level_count = params.decomp_level_count; - let grouping_factor = params.grouping_factor; let thread_count = params.thread_count; let mut rsc = TestResources::new(); @@ -43,7 +101,6 @@ fn lwe_encrypt_multi_bit_pbs_decrypt_custom_mod< let delta: Scalar = encoding_with_padding / msg_modulus; let mut msg = msg_modulus; - const NB_TESTS: usize = 10; let accumulator = generate_accumulator( polynomial_size, @@ -59,56 +116,17 @@ fn lwe_encrypt_multi_bit_pbs_decrypt_custom_mod< ciphertext_modulus )); - // Keygen is a bit slow on this one so we keep it out of the testing loop - // Create the LweSecretKey - let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( - input_lwe_dimension, - &mut rsc.secret_random_generator, - ); - let output_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( - glwe_dimension, - polynomial_size, - &mut rsc.secret_random_generator, - ); - let output_lwe_secret_key = output_glwe_secret_key.clone().into_lwe_secret_key(); + let mut keys_gen = |params| generate_keys(params, &mut rsc); - let mut bsk = LweMultiBitBootstrapKey::new( - Scalar::ZERO, - glwe_dimension.to_glwe_size(), - polynomial_size, - decomp_base_log, - decomp_level_count, - input_lwe_dimension, - grouping_factor, - ciphertext_modulus, - ); - - par_generate_lwe_multi_bit_bootstrap_key( - &input_lwe_secret_key, - &output_glwe_secret_key, - &mut bsk, - glwe_modular_std_dev, - &mut rsc.encryption_random_generator, - ); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (input_lwe_secret_key, output_lwe_secret_key, bsk, fbsk) = + (keys.small_lwe_sk, keys.big_lwe_sk, keys.bsk, keys.fbsk); assert!(check_encrypted_content_respects_mod( &*bsk, ciphertext_modulus )); - let mut fbsk = FourierLweMultiBitBootstrapKey::new( - input_lwe_dimension, - glwe_dimension.to_glwe_size(), - polynomial_size, - decomp_base_log, - decomp_level_count, - grouping_factor, - ); - - par_convert_standard_lwe_multi_bit_bootstrap_key_to_fourier(&bsk, &mut fbsk); - - drop(bsk); - while msg != Scalar::ZERO { msg = msg.wrapping_sub(Scalar::ONE); for _ in 0..NB_TESTS { @@ -152,26 +170,33 @@ fn lwe_encrypt_multi_bit_pbs_decrypt_custom_mod< assert_eq!(decoded, f(msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } -fn lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod< - Scalar: UnsignedTorus + Sync + Send + CastFrom + CastInto, ->( - params: MultiBitParams, -) { - let input_lwe_dimension = params.input_lwe_dimension; +fn lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod( + params: MultiBitTestParams, +) where + Scalar: UnsignedTorus + + Sync + + Send + + CastFrom + + CastInto + + Serialize + + DeserializeOwned, + MultiBitTestParams: KeyCacheAccess>, +{ let lwe_modular_std_dev = params.lwe_modular_std_dev; - let glwe_modular_std_dev = params.glwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; let message_modulus_log = params.message_modulus_log; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus); let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; - let decomp_base_log = params.decomp_base_log; - let decomp_level_count = params.decomp_level_count; - let grouping_factor = params.grouping_factor; let thread_count = params.thread_count; let mut rsc = TestResources::new(); @@ -184,8 +209,6 @@ fn lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod< let delta: Scalar = encoding_with_padding / msg_modulus; let mut msg = msg_modulus; - // Divided by two compared to other tests, we are running the algorithm twice for determinism - const NB_TESTS: usize = 5; let accumulator = generate_accumulator( polynomial_size, @@ -201,59 +224,20 @@ fn lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod< ciphertext_modulus )); - // Keygen is a bit slow on this one so we keep it out of the testing loop - // Create the LweSecretKey - let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( - input_lwe_dimension, - &mut rsc.secret_random_generator, - ); - let output_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( - glwe_dimension, - polynomial_size, - &mut rsc.secret_random_generator, - ); - let output_lwe_secret_key = output_glwe_secret_key.clone().into_lwe_secret_key(); + let mut keys_gen = |params| generate_keys(params, &mut rsc); - let mut bsk = LweMultiBitBootstrapKey::new( - Scalar::ZERO, - glwe_dimension.to_glwe_size(), - polynomial_size, - decomp_base_log, - decomp_level_count, - input_lwe_dimension, - grouping_factor, - ciphertext_modulus, - ); - - par_generate_lwe_multi_bit_bootstrap_key( - &input_lwe_secret_key, - &output_glwe_secret_key, - &mut bsk, - glwe_modular_std_dev, - &mut rsc.encryption_random_generator, - ); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (input_lwe_secret_key, output_lwe_secret_key, bsk, fbsk) = + (keys.small_lwe_sk, keys.big_lwe_sk, keys.bsk, keys.fbsk); assert!(check_encrypted_content_respects_mod( &*bsk, ciphertext_modulus )); - let mut fbsk = FourierLweMultiBitBootstrapKey::new( - input_lwe_dimension, - glwe_dimension.to_glwe_size(), - polynomial_size, - decomp_base_log, - decomp_level_count, - grouping_factor, - ); - - par_convert_standard_lwe_multi_bit_bootstrap_key_to_fourier(&bsk, &mut fbsk); - - drop(bsk); - while msg != Scalar::ZERO { msg = msg.wrapping_sub(Scalar::ONE); - for _ in 0..NB_TESTS { + for _ in 0..NB_TESTS_LIGHT { let plaintext = Plaintext(msg * delta); let lwe_ciphertext_in = allocate_and_encrypt_new_lwe_ciphertext( @@ -318,26 +302,32 @@ fn lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod< assert_eq!(out_pbs_ct_other, out_pbs_ct); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } -fn lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod< - Scalar: UnsignedTorus + Sync + Send + CastFrom + CastInto, ->( - params: MultiBitParams, -) { - let input_lwe_dimension = params.input_lwe_dimension; +fn lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod(params: MultiBitTestParams) +where + Scalar: UnsignedTorus + + Sync + + Send + + CastFrom + + CastInto + + Serialize + + DeserializeOwned, + MultiBitTestParams: KeyCacheAccess>, +{ let lwe_modular_std_dev = params.lwe_modular_std_dev; - let glwe_modular_std_dev = params.glwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; let message_modulus_log = params.message_modulus_log; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus); let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; - let decomp_base_log = params.decomp_base_log; - let decomp_level_count = params.decomp_level_count; - let grouping_factor = params.grouping_factor; let thread_count = params.thread_count; let mut rsc = TestResources::new(); @@ -350,7 +340,6 @@ fn lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod< let delta: Scalar = encoding_with_padding / msg_modulus; let mut msg = msg_modulus; - const NB_TESTS: usize = 10; let accumulator = generate_accumulator( polynomial_size, @@ -366,37 +355,11 @@ fn lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod< ciphertext_modulus )); - // Keygen is a bit slow on this one so we keep it out of the testing loop - // Create the LweSecretKey - let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( - input_lwe_dimension, - &mut rsc.secret_random_generator, - ); - let output_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( - glwe_dimension, - polynomial_size, - &mut rsc.secret_random_generator, - ); - let output_lwe_secret_key = output_glwe_secret_key.clone().into_lwe_secret_key(); + let mut keys_gen = |params| generate_keys(params, &mut rsc); - let mut bsk = LweMultiBitBootstrapKey::new( - Scalar::ZERO, - glwe_dimension.to_glwe_size(), - polynomial_size, - decomp_base_log, - decomp_level_count, - input_lwe_dimension, - grouping_factor, - ciphertext_modulus, - ); - - par_generate_lwe_multi_bit_bootstrap_key( - &input_lwe_secret_key, - &output_glwe_secret_key, - &mut bsk, - glwe_modular_std_dev, - &mut rsc.encryption_random_generator, - ); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (input_lwe_secret_key, output_lwe_secret_key, bsk) = + (keys.small_lwe_sk, keys.big_lwe_sk, keys.bsk); assert!(check_encrypted_content_respects_mod( &*bsk, @@ -446,26 +409,33 @@ fn lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod< assert_eq!(decoded, f(msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } -fn std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod< - Scalar: UnsignedTorus + Sync + Send + CastFrom + CastInto, ->( - params: MultiBitParams, -) { - let input_lwe_dimension = params.input_lwe_dimension; +fn std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod( + params: MultiBitTestParams, +) where + Scalar: UnsignedTorus + + Sync + + Send + + CastFrom + + CastInto + + Serialize + + DeserializeOwned, + MultiBitTestParams: KeyCacheAccess>, +{ let lwe_modular_std_dev = params.lwe_modular_std_dev; - let glwe_modular_std_dev = params.glwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; let message_modulus_log = params.message_modulus_log; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus); let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; - let decomp_base_log = params.decomp_base_log; - let decomp_level_count = params.decomp_level_count; - let grouping_factor = params.grouping_factor; let thread_count = params.thread_count; let mut rsc = TestResources::new(); @@ -478,8 +448,6 @@ fn std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod< let delta: Scalar = encoding_with_padding / msg_modulus; let mut msg = msg_modulus; - // Divided by two compared to other tests, we are running the algorithm twice for determinism - const NB_TESTS: usize = 5; let accumulator = generate_accumulator( polynomial_size, @@ -495,37 +463,11 @@ fn std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod< ciphertext_modulus )); - // Keygen is a bit slow on this one so we keep it out of the testing loop - // Create the LweSecretKey - let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( - input_lwe_dimension, - &mut rsc.secret_random_generator, - ); - let output_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( - glwe_dimension, - polynomial_size, - &mut rsc.secret_random_generator, - ); - let output_lwe_secret_key = output_glwe_secret_key.clone().into_lwe_secret_key(); + let mut keys_gen = |params| generate_keys(params, &mut rsc); - let mut bsk = LweMultiBitBootstrapKey::new( - Scalar::ZERO, - glwe_dimension.to_glwe_size(), - polynomial_size, - decomp_base_log, - decomp_level_count, - input_lwe_dimension, - grouping_factor, - ciphertext_modulus, - ); - - par_generate_lwe_multi_bit_bootstrap_key( - &input_lwe_secret_key, - &output_glwe_secret_key, - &mut bsk, - glwe_modular_std_dev, - &mut rsc.encryption_random_generator, - ); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (input_lwe_secret_key, output_lwe_secret_key, bsk) = + (keys.small_lwe_sk, keys.big_lwe_sk, keys.bsk); assert!(check_encrypted_content_respects_mod( &*bsk, @@ -599,179 +541,98 @@ fn std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod< assert_eq!(out_pbs_ct_other, out_pbs_ct); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } -// DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield -// correct computations -const MULTI_BIT_2_2_2_PARAMS: MultiBitParams = MultiBitParams { - input_lwe_dimension: LweDimension(818), - lwe_modular_std_dev: StandardDev(0.000002226459789930014), - decomp_base_log: DecompositionBaseLog(22), - decomp_level_count: DecompositionLevelCount(1), - glwe_dimension: GlweDimension(1), - polynomial_size: PolynomialSize(2048), - glwe_modular_std_dev: StandardDev(0.0000000000000003152931493498455), - message_modulus_log: CiphertextModulusLog(4), - ciphertext_modulus: CiphertextModulus::new_native(), - grouping_factor: LweBskGroupingFactor(2), - thread_count: ThreadCount(5), -}; - -const MULTI_BIT_2_2_3_PARAMS: MultiBitParams = MultiBitParams { - input_lwe_dimension: LweDimension(888), - lwe_modular_std_dev: StandardDev(0.0000006125031601933181), - decomp_base_log: DecompositionBaseLog(21), - decomp_level_count: DecompositionLevelCount(1), - glwe_dimension: GlweDimension(1), - polynomial_size: PolynomialSize(2048), - glwe_modular_std_dev: StandardDev(0.0000000000000003152931493498455), - message_modulus_log: CiphertextModulusLog(4), - ciphertext_modulus: CiphertextModulus::new_native(), - grouping_factor: LweBskGroupingFactor(3), - thread_count: ThreadCount(12), -}; - #[test] pub fn test_lwe_encrypt_multi_bit_pbs_decrypt_factor_2_thread_5_native_mod() { - lwe_encrypt_multi_bit_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(5), - ..MULTI_BIT_2_2_2_PARAMS - }); + lwe_encrypt_multi_bit_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_2_PARAMS); } #[test] pub fn test_lwe_encrypt_multi_bit_pbs_decrypt_factor_3_thread_12_native_mod() { - lwe_encrypt_multi_bit_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(12), - ..MULTI_BIT_2_2_3_PARAMS - }); + lwe_encrypt_multi_bit_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_3_PARAMS); } #[test] pub fn test_lwe_encrypt_multi_bit_pbs_decrypt_factor_2_thread_5_custom_mod() { - lwe_encrypt_multi_bit_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(5), - message_modulus_log: CiphertextModulusLog(3), - ciphertext_modulus: CiphertextModulus::try_new_power_of_2(63).unwrap(), - ..MULTI_BIT_2_2_2_PARAMS - }); + lwe_encrypt_multi_bit_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_2_CUSTOM_MOD_PARAMS); } #[test] pub fn test_lwe_encrypt_multi_bit_pbs_decrypt_factor_3_thread_12_custom_mod() { - lwe_encrypt_multi_bit_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(12), - message_modulus_log: CiphertextModulusLog(3), - ciphertext_modulus: CiphertextModulus::try_new_power_of_2(63).unwrap(), - ..MULTI_BIT_2_2_3_PARAMS - }); + lwe_encrypt_multi_bit_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_3_CUSTOM_MOD_PARAMS); } #[test] pub fn test_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_factor_2_thread_5_native_mod() { - lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(5), - ..MULTI_BIT_2_2_2_PARAMS - }); + lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_2_PARAMS); } #[test] pub fn test_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_factor_3_thread_12_native_mod() { - lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(12), - ..MULTI_BIT_2_2_3_PARAMS - }); + lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_3_PARAMS); } #[test] pub fn test_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_factor_2_thread_5_custom_mod() { - lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(5), - message_modulus_log: CiphertextModulusLog(3), - ciphertext_modulus: CiphertextModulus::try_new_power_of_2(63).unwrap(), - ..MULTI_BIT_2_2_2_PARAMS - }); + lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::( + MULTI_BIT_2_2_2_CUSTOM_MOD_PARAMS, + ); } #[test] pub fn test_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_factor_3_thread_12_custom_mod() { - lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(12), - message_modulus_log: CiphertextModulusLog(3), - ciphertext_modulus: CiphertextModulus::try_new_power_of_2(63).unwrap(), - ..MULTI_BIT_2_2_3_PARAMS - }); + lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::( + MULTI_BIT_2_2_3_CUSTOM_MOD_PARAMS, + ); } #[test] pub fn test_lwe_encrypt_std_multi_bit_pbs_decrypt_factor_2_thread_5_native_mod() { - lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(5), - ..MULTI_BIT_2_2_2_PARAMS - }); + lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_2_PARAMS); } #[test] pub fn test_lwe_encrypt_std_multi_bit_pbs_decrypt_factor_3_thread_12_native_mod() { - lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(12), - ..MULTI_BIT_2_2_3_PARAMS - }); + lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_3_PARAMS); } #[test] pub fn test_lwe_encrypt_std_multi_bit_pbs_decrypt_factor_2_thread_5_custom_mod() { - lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(5), - message_modulus_log: CiphertextModulusLog(3), - ciphertext_modulus: CiphertextModulus::try_new_power_of_2(63).unwrap(), - ..MULTI_BIT_2_2_2_PARAMS - }); + lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_2_CUSTOM_MOD_PARAMS); } #[test] pub fn test_lwe_encrypt_std_multi_bit_pbs_decrypt_factor_3_thread_12_custom_mod() { - lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(12), - message_modulus_log: CiphertextModulusLog(3), - ciphertext_modulus: CiphertextModulus::try_new_power_of_2(63).unwrap(), - ..MULTI_BIT_2_2_3_PARAMS - }); + lwe_encrypt_std_multi_bit_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_3_CUSTOM_MOD_PARAMS); } #[test] pub fn std_test_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_factor_2_thread_5_native_mod() { - std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(5), - ..MULTI_BIT_2_2_2_PARAMS - }); + std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_2_PARAMS); } #[test] pub fn std_test_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_factor_3_thread_12_native_mod() { - std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(12), - ..MULTI_BIT_2_2_3_PARAMS - }); + std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MULTI_BIT_2_2_3_PARAMS); } #[test] pub fn std_test_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_factor_2_thread_5_custom_mod() { - std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(5), - message_modulus_log: CiphertextModulusLog(3), - ciphertext_modulus: CiphertextModulus::try_new_power_of_2(63).unwrap(), - ..MULTI_BIT_2_2_2_PARAMS - }); + std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::( + MULTI_BIT_2_2_2_CUSTOM_MOD_PARAMS, + ); } #[test] pub fn std_test_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_factor_3_thread_12_custom_mod() { - std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::(MultiBitParams { - thread_count: ThreadCount(12), - message_modulus_log: CiphertextModulusLog(3), - ciphertext_modulus: CiphertextModulus::try_new_power_of_2(63).unwrap(), - ..MULTI_BIT_2_2_3_PARAMS - }); + std_lwe_encrypt_multi_bit_deterministic_pbs_decrypt_custom_mod::( + MULTI_BIT_2_2_3_CUSTOM_MOD_PARAMS, + ); } diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_packing_keyswitch.rs b/tfhe/src/core_crypto/algorithms/test/lwe_packing_keyswitch.rs index 6fec83fed..9a274634c 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_packing_keyswitch.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_packing_keyswitch.rs @@ -1,20 +1,64 @@ use super::*; +use crate::core_crypto::keycache::KeyCacheAccess; +use serde::de::DeserializeOwned; +use serde::Serialize; + +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + +fn generate_keys( + params: PackingKeySwitchTestParams, + rsc: &mut TestResources, +) -> PackingKeySwitchKeys { + let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key( + params.lwe_dimension, + &mut rsc.secret_random_generator, + ); + + let glwe_sk = allocate_and_generate_new_binary_glwe_secret_key( + params.glwe_dimension, + params.polynomial_size, + &mut rsc.secret_random_generator, + ); + + let pksk = allocate_and_generate_new_lwe_packing_keyswitch_key( + &lwe_sk, + &glwe_sk, + params.pbs_base_log, + params.pbs_level, + params.glwe_modular_std_dev, + params.ciphertext_modulus, + &mut rsc.encryption_random_generator, + ); + + assert!(check_encrypted_content_respects_mod( + &pksk, + params.ciphertext_modulus + )); + + PackingKeySwitchKeys { + lwe_sk, + glwe_sk, + pksk, + } +} +fn lwe_encrypt_pks_to_glwe_decrypt_custom_mod(params: P) +where + Scalar: UnsignedTorus + Serialize + DeserializeOwned, + P: Into>, + PackingKeySwitchTestParams: KeyCacheAccess>, +{ + let params = params.into(); -fn lwe_encrypt_pks_to_glwe_decrypt_custom_mod(params: TestParams) { - let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; - let glwe_modular_std_dev = params.glwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; let message_modulus_log = params.message_modulus_log; let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus); - let glwe_dimension = params.glwe_dimension; - let polynomial_size = params.polynomial_size; - let decomp_base_log = params.pbs_base_log; - let decomp_level_count = params.pbs_level; let mut rsc = TestResources::new(); - const NB_TESTS: usize = 10; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -22,31 +66,9 @@ fn lwe_encrypt_pks_to_glwe_decrypt_custom_mod(params: Tes while msg != Scalar::ZERO { msg = msg.wrapping_sub(Scalar::ONE); for _ in 0..NB_TESTS { - let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key( - lwe_dimension, - &mut rsc.secret_random_generator, - ); - - let glwe_sk = allocate_and_generate_new_binary_glwe_secret_key( - glwe_dimension, - polynomial_size, - &mut rsc.secret_random_generator, - ); - - let pksk = allocate_and_generate_new_lwe_packing_keyswitch_key( - &lwe_sk, - &glwe_sk, - decomp_base_log, - decomp_level_count, - glwe_modular_std_dev, - ciphertext_modulus, - &mut rsc.encryption_random_generator, - ); - - assert!(check_encrypted_content_respects_mod( - &pksk, - ciphertext_modulus - )); + let mut keys_gen = |params| generate_keys(params, &mut rsc); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (pksk, lwe_sk, glwe_sk) = (keys.pksk, keys.lwe_sk, keys.glwe_sk); let plaintext = Plaintext(msg * delta); @@ -86,29 +108,31 @@ fn lwe_encrypt_pks_to_glwe_decrypt_custom_mod(params: Tes assert_eq!(msg, decoded); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_encrypt_pks_to_glwe_decrypt_custom_mod); -fn lwe_list_encrypt_pks_to_glwe_decrypt_custom_mod( - params: TestParams, -) { - let lwe_dimension = params.lwe_dimension; +fn lwe_list_encrypt_pks_to_glwe_decrypt_custom_mod(params: P) +where + Scalar: UnsignedTorus + Serialize + DeserializeOwned, + P: Into>, + PackingKeySwitchTestParams: KeyCacheAccess>, +{ + let params = params.into(); + let lwe_modular_std_dev = params.lwe_modular_std_dev; - let glwe_modular_std_dev = params.glwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; let message_modulus_log = params.message_modulus_log; let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus); - let glwe_dimension = params.glwe_dimension; - let polynomial_size = params.polynomial_size; - let decomp_base_log = params.pbs_base_log; - let decomp_level_count = params.pbs_level; let mut rsc = TestResources::new(); - // These tests are pretty heavy, cut down a bit - const NB_TESTS: usize = 5; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; @@ -116,31 +140,9 @@ fn lwe_list_encrypt_pks_to_glwe_decrypt_custom_mod( ciphertext_modulus: CiphertextModulus, ) { @@ -26,9 +31,7 @@ fn test_seeded_lwe_pksk_gen_equivalence( let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - const NB_TEST: usize = 10; - - for _ in 0..NB_TEST { + for _ in 0..NB_TESTS { // Create the LweSecretKey let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( input_lwe_dimension, diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_private_functional_packing_keyswitch.rs b/tfhe/src/core_crypto/algorithms/test/lwe_private_functional_packing_keyswitch.rs index 6992b1e1b..39622b690 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_private_functional_packing_keyswitch.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_private_functional_packing_keyswitch.rs @@ -1,5 +1,10 @@ use super::*; +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + fn test_parallel_pfpks_equivalence( ciphertext_modulus: CiphertextModulus, ) { @@ -26,7 +31,7 @@ fn test_parallel_pfpks_equivalence( ciphertext_modulus, ); - for _ in 0..10 { + for _ in 0..NB_TESTS { let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( input_key_lwe_dimension, &mut rsc.secret_random_generator, @@ -98,7 +103,7 @@ fn test_parallel_pfpks_equivalence( // Small sizes { - for _ in 0..10 { + for _ in 0..NB_TESTS { let decomp_base_log = DecompositionBaseLog( crate::core_crypto::commons::test_tools::random_usize_between(2..5), ); @@ -128,7 +133,7 @@ fn test_parallel_pfpks_equivalence( ciphertext_modulus, ); - for _ in 0..10 { + for _ in 0..NB_TESTS { let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( input_key_lwe_dimension, &mut rsc.secret_random_generator, diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_programmable_bootstrapping.rs b/tfhe/src/core_crypto/algorithms/test/lwe_programmable_bootstrapping.rs index 20da308e1..da9c094a7 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_programmable_bootstrapping.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_programmable_bootstrapping.rs @@ -1,21 +1,90 @@ use super::*; +use crate::core_crypto::keycache::KeyCacheAccess; +use serde::de::DeserializeOwned; +use serde::Serialize; -fn lwe_encrypt_pbs_decrypt_custom_mod< - Scalar: UnsignedTorus + Sync + Send + CastFrom + CastInto, +#[cfg(not(feature = "__coverage"))] +const NB_TESTS: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; + +pub fn generate_keys< + Scalar: UnsignedTorus + Sync + Send + CastFrom + CastInto + Serialize + DeserializeOwned, >( - params: TestParams, -) { - let input_lwe_dimension = params.lwe_dimension; + params: ClassicTestParams, + rsc: &mut TestResources, +) -> ClassicBootstrapKeys { + // Create the LweSecretKey + let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( + params.lwe_dimension, + &mut rsc.secret_random_generator, + ); + let output_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( + params.glwe_dimension, + params.polynomial_size, + &mut rsc.secret_random_generator, + ); + let output_lwe_secret_key = output_glwe_secret_key.clone().into_lwe_secret_key(); + + let mut bsk = LweBootstrapKey::new( + Scalar::ZERO, + params.glwe_dimension.to_glwe_size(), + params.polynomial_size, + params.pbs_base_log, + params.pbs_level, + params.lwe_dimension, + params.ciphertext_modulus, + ); + + par_generate_lwe_bootstrap_key( + &input_lwe_secret_key, + &output_glwe_secret_key, + &mut bsk, + params.glwe_modular_std_dev, + &mut rsc.encryption_random_generator, + ); + + assert!(check_encrypted_content_respects_mod( + &*bsk, + params.ciphertext_modulus + )); + + let mut fbsk = FourierLweBootstrapKey::new( + params.lwe_dimension, + params.glwe_dimension.to_glwe_size(), + params.polynomial_size, + params.pbs_base_log, + params.pbs_level, + ); + + par_convert_standard_lwe_bootstrap_key_to_fourier(&bsk, &mut fbsk); + + ClassicBootstrapKeys { + small_lwe_sk: input_lwe_secret_key, + big_lwe_sk: output_lwe_secret_key, + bsk, + fbsk, + } +} + +fn lwe_encrypt_pbs_decrypt_custom_mod(params: ClassicTestParams) +where + Scalar: UnsignedTorus + + Sync + + Send + + CastFrom + + CastInto + + Serialize + + DeserializeOwned, + ClassicTestParams: KeyCacheAccess>, +{ let lwe_modular_std_dev = params.lwe_modular_std_dev; - let glwe_modular_std_dev = params.glwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; let message_modulus_log = params.message_modulus_log; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus); let glwe_dimension = params.glwe_dimension; let polynomial_size = params.polynomial_size; - let decomp_base_log = params.pbs_base_log; - let decomp_level_count = params.pbs_level; let mut rsc = TestResources::new(); @@ -27,7 +96,6 @@ fn lwe_encrypt_pbs_decrypt_custom_mod< let delta: Scalar = encoding_with_padding / msg_modulus; let mut msg = msg_modulus; - const NB_TESTS: usize = 10; let accumulator = generate_accumulator( polynomial_size, @@ -45,52 +113,11 @@ fn lwe_encrypt_pbs_decrypt_custom_mod< while msg != Scalar::ZERO { msg = msg.wrapping_sub(Scalar::ONE); - // Create the LweSecretKey - let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( - input_lwe_dimension, - &mut rsc.secret_random_generator, - ); - let output_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( - glwe_dimension, - polynomial_size, - &mut rsc.secret_random_generator, - ); - let output_lwe_secret_key = output_glwe_secret_key.clone().into_lwe_secret_key(); - let mut bsk = LweBootstrapKey::new( - Scalar::ZERO, - glwe_dimension.to_glwe_size(), - polynomial_size, - decomp_base_log, - decomp_level_count, - input_lwe_dimension, - ciphertext_modulus, - ); - - par_generate_lwe_bootstrap_key( - &input_lwe_secret_key, - &output_glwe_secret_key, - &mut bsk, - glwe_modular_std_dev, - &mut rsc.encryption_random_generator, - ); - - assert!(check_encrypted_content_respects_mod( - &*bsk, - ciphertext_modulus - )); - - let mut fbsk = FourierLweBootstrapKey::new( - input_lwe_dimension, - glwe_dimension.to_glwe_size(), - polynomial_size, - decomp_base_log, - decomp_level_count, - ); - - par_convert_standard_lwe_bootstrap_key_to_fourier(&bsk, &mut fbsk); - - drop(bsk); + let mut keys_gen = |params| generate_keys(params, &mut rsc); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (input_lwe_secret_key, output_lwe_secret_key, fbsk) = + (keys.small_lwe_sk, keys.big_lwe_sk, keys.fbsk); for _ in 0..NB_TESTS { let plaintext = Plaintext(msg * delta); @@ -132,13 +159,18 @@ fn lwe_encrypt_pbs_decrypt_custom_mod< assert_eq!(decoded, f(msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } create_parametrized_test!(lwe_encrypt_pbs_decrypt_custom_mod); // DISCLAIMER: all parameters here are not guaranteed to be secure or yield correct computations -pub const TEST_PARAMS_4_BITS_NATIVE_U128: TestParams = TestParams { +pub const TEST_PARAMS_4_BITS_NATIVE_U128: ClassicTestParams = ClassicTestParams { lwe_dimension: LweDimension(742), glwe_dimension: GlweDimension(1), polynomial_size: PolynomialSize(2048), @@ -157,7 +189,7 @@ pub const TEST_PARAMS_4_BITS_NATIVE_U128: TestParams = TestParams { ciphertext_modulus: CiphertextModulus::new_native(), }; -pub const TEST_PARAMS_3_BITS_127_U128: TestParams = TestParams { +pub const TEST_PARAMS_3_BITS_127_U128: ClassicTestParams = ClassicTestParams { lwe_dimension: LweDimension(742), glwe_dimension: GlweDimension(1), polynomial_size: PolynomialSize(2048), @@ -176,14 +208,19 @@ pub const TEST_PARAMS_3_BITS_127_U128: TestParams = TestParams { ciphertext_modulus: CiphertextModulus::new(1 << 127), }; -fn lwe_encrypt_pbs_f128_decrypt_custom_mod< - Scalar: UnsignedTorus + Sync + Send + CastFrom + CastInto, ->( - params: TestParams, -) { +fn lwe_encrypt_pbs_f128_decrypt_custom_mod(params: ClassicTestParams) +where + Scalar: UnsignedTorus + + Sync + + Send + + CastFrom + + CastInto + + Serialize + + DeserializeOwned, + ClassicTestParams: KeyCacheAccess>, +{ let input_lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; - let glwe_modular_std_dev = params.glwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; let message_modulus_log = params.message_modulus_log; let msg_modulus = Scalar::ONE.shl(message_modulus_log.0); @@ -203,7 +240,6 @@ fn lwe_encrypt_pbs_f128_decrypt_custom_mod< let delta: Scalar = encoding_with_padding / msg_modulus; let mut msg = msg_modulus; - const NB_TESTS: usize = 10; let accumulator = generate_accumulator( polynomial_size, @@ -221,40 +257,12 @@ fn lwe_encrypt_pbs_f128_decrypt_custom_mod< while msg != Scalar::ZERO { msg = msg.wrapping_sub(Scalar::ONE); - // Create the LweSecretKey - let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key( - input_lwe_dimension, - &mut rsc.secret_random_generator, - ); - let output_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key( - glwe_dimension, - polynomial_size, - &mut rsc.secret_random_generator, - ); - let output_lwe_secret_key = output_glwe_secret_key.clone().into_lwe_secret_key(); - let mut bsk = LweBootstrapKey::new( - Scalar::ZERO, - glwe_dimension.to_glwe_size(), - polynomial_size, - decomp_base_log, - decomp_level_count, - input_lwe_dimension, - ciphertext_modulus, - ); + let mut keys_gen = |params| generate_keys(params, &mut rsc); - par_generate_lwe_bootstrap_key( - &input_lwe_secret_key, - &output_glwe_secret_key, - &mut bsk, - glwe_modular_std_dev, - &mut rsc.encryption_random_generator, - ); - - assert!(check_encrypted_content_respects_mod( - &*bsk, - ciphertext_modulus - )); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (input_lwe_secret_key, output_lwe_secret_key, bsk) = + (keys.small_lwe_sk, keys.big_lwe_sk, keys.bsk); let mut fbsk = Fourier128LweBootstrapKey::new( input_lwe_dimension, @@ -308,6 +316,11 @@ fn lwe_encrypt_pbs_f128_decrypt_custom_mod< assert_eq!(decoded, f(msg)); } + + // In coverage, we break after one while loop iteration, changing message values does not + // yield higher coverage + #[cfg(feature = "__coverage")] + break; } } diff --git a/tfhe/src/core_crypto/algorithms/test/mod.rs b/tfhe/src/core_crypto/algorithms/test/mod.rs index 4f9ff4dcd..9dd4d29fc 100644 --- a/tfhe/src/core_crypto/algorithms/test/mod.rs +++ b/tfhe/src/core_crypto/algorithms/test/mod.rs @@ -1,6 +1,11 @@ +pub mod params; +pub(crate) use params::*; + pub use super::misc::check_encrypted_content_respects_mod; +use crate::core_crypto::keycache::KeyCacheAccess; use crate::core_crypto::prelude::*; use paste::paste; +use std::fmt::Debug; mod ggsw_encryption; mod glwe_encryption; @@ -13,11 +18,11 @@ mod lwe_keyswitch; mod lwe_keyswitch_key_generation; mod lwe_linear_algebra; mod lwe_multi_bit_bootstrap_key_generation; -mod lwe_multi_bit_programmable_bootstrapping; +pub(crate) mod lwe_multi_bit_programmable_bootstrapping; mod lwe_packing_keyswitch; mod lwe_packing_keyswitch_key_generation; mod lwe_private_functional_packing_keyswitch; -mod lwe_programmable_bootstrapping; +pub(crate) mod lwe_programmable_bootstrapping; mod noise_distribution; pub struct TestResources { @@ -40,28 +45,14 @@ impl TestResources { } } -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct TestParams { - pub lwe_dimension: LweDimension, - pub glwe_dimension: GlweDimension, - pub polynomial_size: PolynomialSize, - pub lwe_modular_std_dev: StandardDev, - pub glwe_modular_std_dev: StandardDev, - pub pbs_base_log: DecompositionBaseLog, - pub pbs_level: DecompositionLevelCount, - pub ks_base_log: DecompositionBaseLog, - pub ks_level: DecompositionLevelCount, - pub pfks_level: DecompositionLevelCount, - pub pfks_base_log: DecompositionBaseLog, - pub pfks_modular_std_dev: StandardDev, - pub cbs_level: DecompositionLevelCount, - pub cbs_base_log: DecompositionBaseLog, - pub message_modulus_log: CiphertextModulusLog, - pub ciphertext_modulus: CiphertextModulus, +impl Default for TestResources { + fn default() -> Self { + Self::new() + } } // DISCLAIMER: all parameters here are not guaranteed to be secure or yield correct computations -pub const TEST_PARAMS_4_BITS_NATIVE_U64: TestParams = TestParams { +pub const TEST_PARAMS_4_BITS_NATIVE_U64: ClassicTestParams = ClassicTestParams { lwe_dimension: LweDimension(742), glwe_dimension: GlweDimension(1), polynomial_size: PolynomialSize(2048), @@ -80,7 +71,7 @@ pub const TEST_PARAMS_4_BITS_NATIVE_U64: TestParams = TestParams { ciphertext_modulus: CiphertextModulus::new_native(), }; -pub const TEST_PARAMS_3_BITS_63_U64: TestParams = TestParams { +pub const TEST_PARAMS_3_BITS_63_U64: ClassicTestParams = ClassicTestParams { lwe_dimension: LweDimension(742), glwe_dimension: GlweDimension(1), polynomial_size: PolynomialSize(2048), @@ -99,7 +90,26 @@ pub const TEST_PARAMS_3_BITS_63_U64: TestParams = TestParams { ciphertext_modulus: CiphertextModulus::new(1 << 63), }; -pub const DUMMY_NATIVE_U32: TestParams = TestParams { +pub const TEST_PARAMS_3_BITS_SOLINAS_U64: ClassicTestParams = ClassicTestParams { + lwe_dimension: LweDimension(742), + glwe_dimension: GlweDimension(1), + polynomial_size: PolynomialSize(2048), + lwe_modular_std_dev: StandardDev(0.000007069849454709433), + glwe_modular_std_dev: StandardDev(0.00000000000000029403601535432533), + pbs_base_log: DecompositionBaseLog(23), + pbs_level: DecompositionLevelCount(1), + ks_level: DecompositionLevelCount(5), + ks_base_log: DecompositionBaseLog(3), + pfks_level: DecompositionLevelCount(1), + pfks_base_log: DecompositionBaseLog(23), + pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533), + cbs_level: DecompositionLevelCount(0), + cbs_base_log: DecompositionBaseLog(0), + message_modulus_log: CiphertextModulusLog(3), + ciphertext_modulus: CiphertextModulus::new((1 << 64) - (1 << 32) + 1), +}; + +pub const DUMMY_NATIVE_U32: ClassicTestParams = ClassicTestParams { lwe_dimension: LweDimension(742), glwe_dimension: GlweDimension(1), polynomial_size: PolynomialSize(2048), @@ -118,7 +128,7 @@ pub const DUMMY_NATIVE_U32: TestParams = TestParams { ciphertext_modulus: CiphertextModulus::new_native(), }; -pub const DUMMY_31_U32: TestParams = TestParams { +pub const DUMMY_31_U32: ClassicTestParams = ClassicTestParams { lwe_dimension: LweDimension(742), glwe_dimension: GlweDimension(1), polynomial_size: PolynomialSize(2048), @@ -137,23 +147,173 @@ pub const DUMMY_31_U32: TestParams = TestParams { ciphertext_modulus: CiphertextModulus::new(1 << 31), }; -pub const TEST_PARAMS_3_BITS_SOLINAS_U64: TestParams = TestParams { +pub const MULTI_BIT_2_2_2_PARAMS: MultiBitTestParams = MultiBitTestParams { + input_lwe_dimension: LweDimension(818), + lwe_modular_std_dev: StandardDev(0.000002226459789930014), + decomp_base_log: DecompositionBaseLog(22), + decomp_level_count: DecompositionLevelCount(1), + glwe_dimension: GlweDimension(1), + polynomial_size: PolynomialSize(2048), + glwe_modular_std_dev: StandardDev(0.0000000000000003152931493498455), + message_modulus_log: CiphertextModulusLog(4), + ciphertext_modulus: CiphertextModulus::new_native(), + grouping_factor: LweBskGroupingFactor(2), + thread_count: ThreadCount(5), +}; + +pub const MULTI_BIT_2_2_2_CUSTOM_MOD_PARAMS: MultiBitTestParams = MultiBitTestParams { + input_lwe_dimension: LweDimension(818), + lwe_modular_std_dev: StandardDev(0.000002226459789930014), + decomp_base_log: DecompositionBaseLog(22), + decomp_level_count: DecompositionLevelCount(1), + glwe_dimension: GlweDimension(1), + polynomial_size: PolynomialSize(2048), + glwe_modular_std_dev: StandardDev(0.0000000000000003152931493498455), + message_modulus_log: CiphertextModulusLog(3), + ciphertext_modulus: CiphertextModulus::new(1 << 63), + grouping_factor: LweBskGroupingFactor(2), + thread_count: ThreadCount(5), +}; + +pub const MULTI_BIT_2_2_3_PARAMS: MultiBitTestParams = MultiBitTestParams { + input_lwe_dimension: LweDimension(888), + lwe_modular_std_dev: StandardDev(0.0000006125031601933181), + decomp_base_log: DecompositionBaseLog(21), + decomp_level_count: DecompositionLevelCount(1), + glwe_dimension: GlweDimension(1), + polynomial_size: PolynomialSize(2048), + glwe_modular_std_dev: StandardDev(0.0000000000000003152931493498455), + message_modulus_log: CiphertextModulusLog(4), + ciphertext_modulus: CiphertextModulus::new_native(), + grouping_factor: LweBskGroupingFactor(3), + thread_count: ThreadCount(12), +}; + +pub const MULTI_BIT_2_2_3_CUSTOM_MOD_PARAMS: MultiBitTestParams = MultiBitTestParams { + input_lwe_dimension: LweDimension(888), + lwe_modular_std_dev: StandardDev(0.0000006125031601933181), + decomp_base_log: DecompositionBaseLog(21), + decomp_level_count: DecompositionLevelCount(1), + glwe_dimension: GlweDimension(1), + polynomial_size: PolynomialSize(2048), + glwe_modular_std_dev: StandardDev(0.0000000000000003152931493498455), + message_modulus_log: CiphertextModulusLog(3), + ciphertext_modulus: CiphertextModulus::new(1 << 63), + grouping_factor: LweBskGroupingFactor(3), + thread_count: ThreadCount(12), +}; + +// DISCLAIMER: example parameters tailored for FFT implementation tests. There are not guaranteed +// to be secure or yield correct computations. +// Define the parameters for a 4 bits message able to hold the doubled 2 bits message. +pub const FFT_U32_PARAMS: FftTestParams = FftTestParams { lwe_dimension: LweDimension(742), glwe_dimension: GlweDimension(1), polynomial_size: PolynomialSize(2048), - lwe_modular_std_dev: StandardDev(0.000007069849454709433), - glwe_modular_std_dev: StandardDev(0.00000000000000029403601535432533), + lwe_modular_std_dev: StandardDev(0.00000000004998277131225527), + glwe_modular_std_dev: StandardDev(0.00000000000000000000000000000008645717832544903), pbs_base_log: DecompositionBaseLog(23), pbs_level: DecompositionLevelCount(1), - ks_level: DecompositionLevelCount(5), - ks_base_log: DecompositionBaseLog(3), - pfks_level: DecompositionLevelCount(1), - pfks_base_log: DecompositionBaseLog(23), - pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533), - cbs_level: DecompositionLevelCount(0), - cbs_base_log: DecompositionBaseLog(0), - message_modulus_log: CiphertextModulusLog(3), - ciphertext_modulus: CiphertextModulus::new((1 << 64) - (1 << 32) + 1), + ciphertext_modulus: CiphertextModulus::new_native(), +}; + +pub const FFT_U64_PARAMS: FftTestParams = FftTestParams { + lwe_dimension: LweDimension(742), + glwe_dimension: GlweDimension(1), + polynomial_size: PolynomialSize(2048), + lwe_modular_std_dev: StandardDev(0.00000000004998277131225527), + glwe_modular_std_dev: StandardDev(0.00000000000000000000000000000008645717832544903), + pbs_base_log: DecompositionBaseLog(23), + pbs_level: DecompositionLevelCount(1), + ciphertext_modulus: CiphertextModulus::new_native(), +}; + +pub const FFT_U128_PARAMS: FftTestParams = FftTestParams { + lwe_dimension: LweDimension(742), + glwe_dimension: GlweDimension(1), + polynomial_size: PolynomialSize(2048), + lwe_modular_std_dev: StandardDev(0.00000000004998277131225527), + glwe_modular_std_dev: StandardDev(0.00000000000000000000000000000008645717832544903), + pbs_base_log: DecompositionBaseLog(23), + pbs_level: DecompositionLevelCount(1), + ciphertext_modulus: CiphertextModulus::new_native(), +}; + +pub const FFT128_U128_PARAMS: FftTestParams = FftTestParams { + lwe_dimension: LweDimension(742), + glwe_dimension: GlweDimension(1), + polynomial_size: PolynomialSize(2048), + lwe_modular_std_dev: StandardDev(0.12345), + glwe_modular_std_dev: StandardDev(0.00000000000000000000000000000008645717832544903), + pbs_base_log: DecompositionBaseLog(23), + pbs_level: DecompositionLevelCount(1), + ciphertext_modulus: CiphertextModulus::::new_native(), +}; + +pub const FFT_WOPBS_PARAMS: FftWopPbsTestParams = FftWopPbsTestParams { + lwe_dimension: LweDimension(481), + glwe_dimension: GlweDimension(1), + polynomial_size: PolynomialSize(1024), + // Value was 0.000_000_000_000_000_221_486_881_160_055_68_513645324585951 + // But rust indicates it gets truncated anyways to + // 0.000_000_000_000_000_221_486_881_160_055_68 + lwe_modular_std_dev: StandardDev(0.000_000_000_000_000_221_486_881_160_055_68), + // Value was 0.000_061_200_133_780_220_371_345 + // But rust indicates it gets truncated anyways to + // 0.000_061_200_133_780_220_36 + glwe_modular_std_dev: StandardDev(0.000_061_200_133_780_220_36), + pbs_base_log: DecompositionBaseLog(4), + pbs_level: DecompositionLevelCount(9), + pfks_level: DecompositionLevelCount(9), + pfks_base_log: DecompositionBaseLog(4), + cbs_level: DecompositionLevelCount(4), + cbs_base_log: DecompositionBaseLog(6), + ciphertext_modulus: CiphertextModulus::new_native(), +}; + +pub const FFT_WOPBS_N512_PARAMS: FftWopPbsTestParams = FftWopPbsTestParams { + lwe_dimension: LweDimension(4), + glwe_dimension: GlweDimension(2), + polynomial_size: PolynomialSize(512), + lwe_modular_std_dev: StandardDev(0.000_000_000_000_000_221_486_881_160_055_68), + glwe_modular_std_dev: StandardDev(0.000_061_200_133_780_220_36), + pbs_base_log: DecompositionBaseLog(9), + pbs_level: DecompositionLevelCount(4), + pfks_level: DecompositionLevelCount(2), + pfks_base_log: DecompositionBaseLog(15), + cbs_level: DecompositionLevelCount(4), + cbs_base_log: DecompositionBaseLog(6), + ciphertext_modulus: CiphertextModulus::new_native(), +}; + +pub const FFT_WOPBS_N1024_PARAMS: FftWopPbsTestParams = FftWopPbsTestParams { + lwe_dimension: LweDimension(4), + glwe_dimension: GlweDimension(2), + polynomial_size: PolynomialSize(1024), + lwe_modular_std_dev: StandardDev(0.000_000_000_000_000_221_486_881_160_055_68), + glwe_modular_std_dev: StandardDev(0.000_061_200_133_780_220_36), + pbs_base_log: DecompositionBaseLog(9), + pbs_level: DecompositionLevelCount(4), + pfks_level: DecompositionLevelCount(2), + pfks_base_log: DecompositionBaseLog(15), + cbs_level: DecompositionLevelCount(4), + cbs_base_log: DecompositionBaseLog(6), + ciphertext_modulus: CiphertextModulus::new_native(), +}; + +pub const FFT_WOPBS_N2048_PARAMS: FftWopPbsTestParams = FftWopPbsTestParams { + lwe_dimension: LweDimension(4), + glwe_dimension: GlweDimension(2), + polynomial_size: PolynomialSize(2048), + lwe_modular_std_dev: StandardDev(0.000_000_000_000_000_221_486_881_160_055_68), + glwe_modular_std_dev: StandardDev(0.000_061_200_133_780_220_36), + pbs_base_log: DecompositionBaseLog(9), + pbs_level: DecompositionLevelCount(4), + pfks_level: DecompositionLevelCount(2), + pfks_base_log: DecompositionBaseLog(15), + cbs_level: DecompositionLevelCount(4), + cbs_base_log: DecompositionBaseLog(6), + ciphertext_modulus: CiphertextModulus::new_native(), }; pub fn get_encoding_with_padding( @@ -223,6 +383,23 @@ where ) } +pub(crate) fn gen_keys_or_get_from_cache_if_enabled< + P: Debug + KeyCacheAccess + serde::Serialize + serde::de::DeserializeOwned, + K: serde::de::DeserializeOwned + serde::Serialize + Clone, +>( + params: P, + keygen_func: &mut dyn FnMut(P) -> K, +) -> K { + #[cfg(feature = "internal-keycache")] + { + crate::core_crypto::keycache::KEY_CACHE.get_key_with_closure(params, keygen_func) + } + #[cfg(not(feature = "internal-keycache"))] + { + keygen_func(params) + } +} + // Macro to generate tests for all parameter sets macro_rules! create_parametrized_test{ ($name:ident { $($param:ident),* }) => { diff --git a/tfhe/src/core_crypto/algorithms/test/noise_distribution/lwe_encryption_noise.rs b/tfhe/src/core_crypto/algorithms/test/noise_distribution/lwe_encryption_noise.rs index 4dd494730..9a2de6338 100644 --- a/tfhe/src/core_crypto/algorithms/test/noise_distribution/lwe_encryption_noise.rs +++ b/tfhe/src/core_crypto/algorithms/test/noise_distribution/lwe_encryption_noise.rs @@ -9,7 +9,7 @@ use crate::core_crypto::commons::test_tools::{ const RELATIVE_TOLERANCE: f64 = 0.0625; fn lwe_encrypt_decrypt_noise_distribution_custom_mod>( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = params.lwe_dimension; let lwe_modular_std_dev = params.lwe_modular_std_dev; @@ -109,7 +109,7 @@ fn test_variance_increase_cpk_formula() { fn lwe_compact_public_encrypt_noise_distribution_custom_mod< Scalar: UnsignedTorus + CastInto, >( - params: TestParams, + params: ClassicTestParams, ) { let lwe_dimension = LweDimension(params.polynomial_size.0); let glwe_modular_std_dev = params.glwe_modular_std_dev; @@ -194,7 +194,9 @@ create_parametrized_test!(lwe_compact_public_encrypt_noise_distribution_custom_m TEST_PARAMS_4_BITS_NATIVE_U64 }); -fn random_noise_roundtrip>(params: TestParams) { +fn random_noise_roundtrip>( + params: ClassicTestParams, +) { let mut rsc = TestResources::new(); let noise = params.glwe_modular_std_dev; let ciphertext_modulus = params.ciphertext_modulus; diff --git a/tfhe/src/core_crypto/algorithms/test/params.rs b/tfhe/src/core_crypto/algorithms/test/params.rs new file mode 100644 index 000000000..32d7927d7 --- /dev/null +++ b/tfhe/src/core_crypto/algorithms/test/params.rs @@ -0,0 +1,217 @@ +use crate::core_crypto::commons::dispersion::*; +use crate::core_crypto::commons::parameters::*; +use crate::core_crypto::entities::*; +use crate::core_crypto::prelude::{CastFrom, CastInto, UnsignedInteger}; +use crate::keycache::NamedParam; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ClassicBootstrapKeys { + pub small_lwe_sk: LweSecretKey>, + pub big_lwe_sk: LweSecretKey>, + pub bsk: LweBootstrapKeyOwned, + + pub fbsk: FourierLweBootstrapKeyOwned, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MultiBitBootstrapKeys { + pub small_lwe_sk: LweSecretKey>, + pub big_lwe_sk: LweSecretKey>, + pub bsk: LweMultiBitBootstrapKeyOwned, + pub fbsk: FourierLweMultiBitBootstrapKeyOwned, +} + +// Fourier key is generated afterward in order to use generic test function +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct FftBootstrapKeys { + pub small_lwe_sk: LweSecretKey>, + pub big_lwe_sk: LweSecretKey>, + pub bsk: LweBootstrapKeyOwned, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct FftWopPbsKeys { + pub small_lwe_sk: LweSecretKey>, + pub big_lwe_sk: LweSecretKey>, + pub fbsk: FourierLweBootstrapKeyOwned, + pub lwe_pfpksk: LwePrivateFunctionalPackingKeyswitchKeyListOwned, +} + +// Fourier key is generated afterward in order to use generic test function +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct PackingKeySwitchKeys { + pub lwe_sk: LweSecretKey>, + pub glwe_sk: GlweSecretKey>, + pub pksk: LwePackingKeyswitchKeyOwned, +} + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ClassicTestParams { + pub lwe_dimension: LweDimension, + pub glwe_dimension: GlweDimension, + pub polynomial_size: PolynomialSize, + pub lwe_modular_std_dev: StandardDev, + pub glwe_modular_std_dev: StandardDev, + pub pbs_base_log: DecompositionBaseLog, + pub pbs_level: DecompositionLevelCount, + pub ks_base_log: DecompositionBaseLog, + pub ks_level: DecompositionLevelCount, + pub pfks_level: DecompositionLevelCount, + pub pfks_base_log: DecompositionBaseLog, + pub pfks_modular_std_dev: StandardDev, + pub cbs_level: DecompositionLevelCount, + pub cbs_base_log: DecompositionBaseLog, + pub message_modulus_log: CiphertextModulusLog, + pub ciphertext_modulus: CiphertextModulus, +} + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct MultiBitTestParams { + pub input_lwe_dimension: LweDimension, + pub lwe_modular_std_dev: StandardDev, + pub decomp_base_log: DecompositionBaseLog, + pub decomp_level_count: DecompositionLevelCount, + pub glwe_dimension: GlweDimension, + pub polynomial_size: PolynomialSize, + pub glwe_modular_std_dev: StandardDev, + pub message_modulus_log: CiphertextModulusLog, + pub ciphertext_modulus: CiphertextModulus, + pub grouping_factor: LweBskGroupingFactor, + pub thread_count: ThreadCount, +} + +// PartialEq is implemented manually because thread_count doesn't affect key generation and we want +// to change its value in test without the need of regenerating keys in the key cache. +impl PartialEq for MultiBitTestParams { + fn eq(&self, other: &Self) -> bool { + self.input_lwe_dimension == other.input_lwe_dimension + && self.lwe_modular_std_dev == other.lwe_modular_std_dev + && self.decomp_base_log == other.decomp_base_log + && self.decomp_level_count == other.decomp_level_count + && self.glwe_dimension == other.glwe_dimension + && self.polynomial_size == other.polynomial_size + && self.glwe_modular_std_dev == other.glwe_modular_std_dev + && self.message_modulus_log == other.message_modulus_log + && self.ciphertext_modulus == other.ciphertext_modulus + && self.grouping_factor == other.grouping_factor + } +} + +// Parameters to test FFT implementation +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +pub struct FftTestParams { + pub lwe_dimension: LweDimension, + pub glwe_dimension: GlweDimension, + pub polynomial_size: PolynomialSize, + pub lwe_modular_std_dev: StandardDev, + pub glwe_modular_std_dev: StandardDev, + pub pbs_base_log: DecompositionBaseLog, + pub pbs_level: DecompositionLevelCount, + pub ciphertext_modulus: CiphertextModulus, +} + +// Parameters to test FFT implementation on wopPBS +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct FftWopPbsTestParams { + pub lwe_dimension: LweDimension, + pub glwe_dimension: GlweDimension, + pub polynomial_size: PolynomialSize, + pub lwe_modular_std_dev: StandardDev, + pub glwe_modular_std_dev: StandardDev, + pub pbs_base_log: DecompositionBaseLog, + pub pbs_level: DecompositionLevelCount, + pub pfks_level: DecompositionLevelCount, + pub pfks_base_log: DecompositionBaseLog, + pub cbs_level: DecompositionLevelCount, + pub cbs_base_log: DecompositionBaseLog, + pub ciphertext_modulus: CiphertextModulus, +} + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct PackingKeySwitchTestParams { + pub lwe_dimension: LweDimension, + pub glwe_dimension: GlweDimension, + pub polynomial_size: PolynomialSize, + pub lwe_modular_std_dev: StandardDev, + pub glwe_modular_std_dev: StandardDev, + pub pbs_base_log: DecompositionBaseLog, + pub pbs_level: DecompositionLevelCount, + pub message_modulus_log: CiphertextModulusLog, + pub ciphertext_modulus: CiphertextModulus, +} + +impl + CastInto> From> + for PackingKeySwitchTestParams +{ + fn from(params: ClassicTestParams) -> Self { + Self { + lwe_dimension: params.lwe_dimension, + glwe_dimension: params.glwe_dimension, + polynomial_size: params.polynomial_size, + lwe_modular_std_dev: params.lwe_modular_std_dev, + glwe_modular_std_dev: params.glwe_modular_std_dev, + pbs_base_log: params.pbs_base_log, + pbs_level: params.pbs_level, + message_modulus_log: params.message_modulus_log, + ciphertext_modulus: params.ciphertext_modulus, + } + } +} + +impl NamedParam for ClassicTestParams { + fn name(&self) -> String { + format!( + "PARAM_LWE_BOOTSTRAP_glwe_{}_poly_{}_decomp_base_log_{}_decomp_level_{}_lwe_dim_{}_ct_modulus_{}_msg_modulus_{}", + self.glwe_dimension.0, self.polynomial_size.0, self.pbs_base_log.0, self.pbs_level.0, + self.lwe_dimension.0, self.ciphertext_modulus, self.message_modulus_log.0 + ) + } +} + +impl NamedParam for MultiBitTestParams { + fn name(&self) -> String { + format!( + "PARAM_LWE_MULTI_BIT_BOOTSTRAP_glwe_{}_poly_{}_decomp_base_log_{}_decomp_level_{}_input_dim_{}_ct_modulus_{}_msg_modulus_log_{}_group_factor_{}", + self.glwe_dimension.0, self.polynomial_size.0, self.decomp_base_log.0, + self.decomp_level_count.0, self.input_lwe_dimension.0, self.ciphertext_modulus, self.message_modulus_log.0, + self.grouping_factor.0, + ) + } +} + +impl NamedParam for FftTestParams { + fn name(&self) -> String { + format!( + "PARAM_FFT_BOOTSTRAP_glwe_{}_poly_{}_decomp_base_log_{}_decomp_level_{}_lwe_dim_{}_ct_modulus_{}_lwe_std_dev_{}_glwe_std_dev_{}", + self.glwe_dimension.0, self.polynomial_size.0, self.pbs_base_log.0, + self.pbs_level.0, + self.lwe_dimension.0, self.ciphertext_modulus, self.lwe_modular_std_dev.0.to_string().replace('.', "-"), + self.glwe_modular_std_dev.0.to_string().replace('.', "-"), + ) + } +} + +impl NamedParam for FftWopPbsTestParams { + fn name(&self) -> String { + format!( + "PARAM_FFT_WOPBS_BOOTSTRAP_glwe_{}_poly_{}_decomp_base_log_{}_decomp_level_{}_lwe_dim_{}_ct_modulus_{}_pfks_level_{}_pfks_base_log_{}_cbs_level_{}_cbs_base_log_{}", + self.glwe_dimension.0, self.polynomial_size.0, self.pbs_base_log.0, + self.pbs_level.0, + self.lwe_dimension.0, self.ciphertext_modulus, self.pfks_level.0, self.pfks_base_log.0, + self.cbs_level.0, self.cbs_base_log.0, + ) + } +} + +impl NamedParam for PackingKeySwitchTestParams { + fn name(&self) -> String { + format!( + "PARAM_PKS_glwe_{}_poly_{}_decomp_base_log_{}_decomp_level_{}_lwe_dim_{}_ct_modulus_{}_lwe_std_dev_{}_glwe_std_dev_{}", + self.glwe_dimension.0, self.polynomial_size.0, self.pbs_base_log.0, + self.pbs_level.0, + self.lwe_dimension.0, self.ciphertext_modulus, self.lwe_modular_std_dev.0.to_string().replace('.', "-"), + self.glwe_modular_std_dev.0.to_string().replace('.', "-"), + ) + } +} diff --git a/tfhe/src/core_crypto/fft_impl/common.rs b/tfhe/src/core_crypto/fft_impl/common.rs index cb96e9998..ebf278924 100644 --- a/tfhe/src/core_crypto/fft_impl/common.rs +++ b/tfhe/src/core_crypto/fft_impl/common.rs @@ -86,70 +86,89 @@ pub trait FourierBootstrapKey { #[cfg(test)] pub mod tests { + pub(crate) use crate::core_crypto::algorithms::test::gen_keys_or_get_from_cache_if_enabled; + + use crate::core_crypto::algorithms::test::{FftBootstrapKeys, FftTestParams, TestResources}; use crate::core_crypto::commons::numeric::Numeric; use crate::core_crypto::fft_impl::common::FourierBootstrapKey; + use crate::core_crypto::keycache::KeyCacheAccess; use crate::core_crypto::prelude::*; use dyn_stack::{GlobalPodBuffer, PodStack}; + use serde::de::DeserializeOwned; + use serde::Serialize; - pub fn test_bootstrap_generic< - Scalar: Numeric + UnsignedTorus + CastFrom + CastInto + Send + Sync, - K: FourierBootstrapKey, + pub fn generate_keys< + Scalar: UnsignedTorus + + Sync + + Send + + CastFrom + + CastInto + + Serialize + + DeserializeOwned, >( - lwe_modular_std_dev: StandardDev, - glwe_modular_std_dev: StandardDev, - ) { - // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct - // computations - // Define the parameters for a 4 bits message able to hold the doubled 2 bits message - let small_lwe_dimension = LweDimension(742); - let glwe_dimension = GlweDimension(1); - let polynomial_size = PolynomialSize(2048); - let pbs_base_log = DecompositionBaseLog(23); - let pbs_level = DecompositionLevelCount(1); - let ciphertext_modulus = CiphertextModulus::new_native(); - - // Request the best seeder possible, starting with hardware entropy sources and falling back - // to /dev/random on Unix systems if enabled via cargo features - let mut boxed_seeder = new_seeder(); - // Get a mutable reference to the seeder as a trait object from the Box returned by - // new_seeder - let seeder = boxed_seeder.as_mut(); - - // Create a generator which uses a CSPRNG to generate secret keys - let mut secret_generator = - SecretRandomGenerator::::new(seeder.seed()); - - // Create a generator which uses two CSPRNGs to generate public masks and secret encryption - // noise - let mut encryption_generator = - EncryptionRandomGenerator::::new(seeder.seed(), seeder); - - println!("Generating keys..."); - + params: FftTestParams, + rsc: &mut TestResources, + ) -> FftBootstrapKeys { // Generate an LweSecretKey with binary coefficients - let small_lwe_sk = - LweSecretKey::generate_new_binary(small_lwe_dimension, &mut secret_generator); + let small_lwe_sk = LweSecretKey::generate_new_binary( + params.lwe_dimension, + &mut rsc.secret_random_generator, + ); // Generate a GlweSecretKey with binary coefficients let glwe_sk = GlweSecretKey::generate_new_binary( - glwe_dimension, - polynomial_size, - &mut secret_generator, + params.glwe_dimension, + params.polynomial_size, + &mut rsc.secret_random_generator, ); // Create a copy of the GlweSecretKey re-interpreted as an LweSecretKey let big_lwe_sk = glwe_sk.clone().into_lwe_secret_key(); - let std_bootstrapping_key = par_allocate_and_generate_new_lwe_bootstrap_key( + let bsk = par_allocate_and_generate_new_lwe_bootstrap_key( &small_lwe_sk, &glwe_sk, - pbs_base_log, - pbs_level, - glwe_modular_std_dev, - ciphertext_modulus, - &mut encryption_generator, + params.pbs_base_log, + params.pbs_level, + params.glwe_modular_std_dev, + params.ciphertext_modulus, + &mut rsc.encryption_random_generator, ); + FftBootstrapKeys { + small_lwe_sk, + big_lwe_sk, + bsk, + } + } + + pub fn test_bootstrap_generic(params: FftTestParams) + where + Scalar: Numeric + + UnsignedTorus + + CastFrom + + CastInto + + Send + + Sync + + Serialize + + DeserializeOwned, + K: FourierBootstrapKey, + FftTestParams: KeyCacheAccess>, + { + let lwe_modular_std_dev = params.lwe_modular_std_dev; + let glwe_dimension = params.glwe_dimension; + let polynomial_size = params.polynomial_size; + let ciphertext_modulus = params.ciphertext_modulus; + + let mut rsc = TestResources::new(); + + let fft = K::new_fft(polynomial_size); + + let mut keys_gen = |params| generate_keys(params, &mut rsc); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (std_bootstrapping_key, small_lwe_sk, big_lwe_sk) = + (keys.bsk, keys.small_lwe_sk, keys.big_lwe_sk); + // Create the empty bootstrapping key in the Fourier domain let mut fourier_bsk = K::new( std_bootstrapping_key.input_lwe_dimension(), @@ -159,7 +178,6 @@ pub mod tests { std_bootstrapping_key.decomposition_level_count(), ); - let fft = K::new_fft(polynomial_size); fourier_bsk.fill_with_forward_fourier( &std_bootstrapping_key, &fft, @@ -186,7 +204,7 @@ pub mod tests { plaintext, lwe_modular_std_dev, ciphertext_modulus, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); // Now we will use a PBS to compute a multiplication by 2, it is NOT the recommended way of diff --git a/tfhe/src/core_crypto/fft_impl/fft128/crypto/tests.rs b/tfhe/src/core_crypto/fft_impl/fft128/crypto/tests.rs index bbe861f5c..b026fadc3 100644 --- a/tfhe/src/core_crypto/fft_impl/fft128/crypto/tests.rs +++ b/tfhe/src/core_crypto/fft_impl/fft128/crypto/tests.rs @@ -1,31 +1,18 @@ use crate::core_crypto::fft_impl::common::tests::test_bootstrap_generic; use crate::core_crypto::fft_impl::fft128::crypto::bootstrap::Fourier128LweBootstrapKeyOwned; -use crate::core_crypto::prelude::*; - -fn sqr(x: f64) -> f64 { - x * x -} +use crate::core_crypto::prelude::test::{FFT_U128_PARAMS, FFT_U32_PARAMS, FFT_U64_PARAMS}; #[test] fn test_bootstrap_u128() { - test_bootstrap_generic::( - StandardDev(sqr(0.000007069849454709433)), - StandardDev(sqr(0.00000000000000029403601535432533)), - ); + test_bootstrap_generic::(FFT_U128_PARAMS); } #[test] fn test_bootstrap_u64() { - test_bootstrap_generic::( - StandardDev(sqr(0.000007069849454709433)), - StandardDev(sqr(0.00000000000000029403601535432533)), - ); + test_bootstrap_generic::(FFT_U64_PARAMS); } #[test] fn test_bootstrap_u32() { - test_bootstrap_generic::( - StandardDev(sqr(0.000007069849454709433)), - StandardDev(sqr(0.00000000000000029403601535432533)), - ); + test_bootstrap_generic::(FFT_U32_PARAMS); } 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 128bd54de..e53f0b5ba 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 @@ -2,24 +2,24 @@ use dyn_stack::{GlobalPodBuffer, PodStack, ReborrowMut}; use super::super::super::{fft128, fft128_u128}; use super::super::math::fft::{Fft128, Fft128View}; +use crate::core_crypto::fft_impl::common::tests::{ + gen_keys_or_get_from_cache_if_enabled, generate_keys, +}; +use crate::core_crypto::prelude::test::{TestResources, FFT128_U128_PARAMS}; use crate::core_crypto::prelude::*; use aligned_vec::CACHELINE_ALIGN; -fn sqr(x: f64) -> f64 { - x * x -} - #[test] fn test_split_external_product() { - let small_lwe_dimension = LweDimension(742); - let glwe_dimension = GlweDimension(1); - let polynomial_size = PolynomialSize(2048); - let pbs_base_log = DecompositionBaseLog(23); - let pbs_level = DecompositionLevelCount(1); - let glwe_modular_std_dev = StandardDev(sqr(0.00000000000000029403601535432533)); - let ciphertext_modulus = CiphertextModulus::::new_native(); + let params = FFT128_U128_PARAMS; + + let glwe_dimension = params.glwe_dimension; + let polynomial_size = params.polynomial_size; + let ciphertext_modulus = params.ciphertext_modulus; let ciphertext_modulus_split = CiphertextModulus::::new_native(); + let mut rsc = TestResources::new(); + let mut glwe = GlweCiphertext::new( 0u128, glwe_dimension.to_glwe_size(), @@ -31,27 +31,9 @@ fn test_split_external_product() { *x = rand::random(); } - let mut boxed_seeder = new_seeder(); - let seeder = boxed_seeder.as_mut(); - let mut secret_generator = - SecretRandomGenerator::::new(seeder.seed()); - let mut encryption_generator = - EncryptionRandomGenerator::::new(seeder.seed(), seeder); - - let small_lwe_sk = - LweSecretKey::generate_new_binary(small_lwe_dimension, &mut secret_generator); - let glwe_sk = - GlweSecretKey::generate_new_binary(glwe_dimension, polynomial_size, &mut secret_generator); - - let std_bootstrapping_key = par_allocate_and_generate_new_lwe_bootstrap_key( - &small_lwe_sk, - &glwe_sk, - pbs_base_log, - pbs_level, - glwe_modular_std_dev, - ciphertext_modulus, - &mut encryption_generator, - ); + let mut keys_gen = |params| generate_keys(params, &mut rsc); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let std_bootstrapping_key = keys.bsk; let mut fourier_bsk = Fourier128LweBootstrapKey::new( std_bootstrapping_key.input_lwe_dimension(), @@ -154,35 +136,18 @@ fn test_split_external_product() { #[test] fn test_split_pbs() { - let small_lwe_dimension = LweDimension(742); - let glwe_dimension = GlweDimension(1); - let polynomial_size = PolynomialSize(2048); - let pbs_base_log = DecompositionBaseLog(23); - let pbs_level = DecompositionLevelCount(1); - let glwe_modular_std_dev = StandardDev(sqr(0.00000000000000029403601535432533)); - let ciphertext_modulus = CiphertextModulus::::new_native(); + let params = FFT128_U128_PARAMS; - let mut boxed_seeder = new_seeder(); - let seeder = boxed_seeder.as_mut(); - let mut secret_generator = - SecretRandomGenerator::::new(seeder.seed()); - let mut encryption_generator = - EncryptionRandomGenerator::::new(seeder.seed(), seeder); + let small_lwe_dimension = params.lwe_dimension; + let glwe_dimension = params.glwe_dimension; + let polynomial_size = params.polynomial_size; + let ciphertext_modulus = params.ciphertext_modulus; - let small_lwe_sk = - LweSecretKey::generate_new_binary(small_lwe_dimension, &mut secret_generator); - let glwe_sk = - GlweSecretKey::generate_new_binary(glwe_dimension, polynomial_size, &mut secret_generator); + let mut rsc = TestResources::new(); - let std_bootstrapping_key = par_allocate_and_generate_new_lwe_bootstrap_key( - &small_lwe_sk, - &glwe_sk, - pbs_base_log, - pbs_level, - glwe_modular_std_dev, - ciphertext_modulus, - &mut encryption_generator, - ); + let mut keys_gen = |params| generate_keys(params, &mut rsc); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let std_bootstrapping_key = keys.bsk; let mut fourier_bsk = Fourier128LweBootstrapKey::new( std_bootstrapping_key.input_lwe_dimension(), diff --git a/tfhe/src/core_crypto/fft_impl/fft64/crypto/tests.rs b/tfhe/src/core_crypto/fft_impl/fft64/crypto/tests.rs index b46b14b09..a78a0a405 100644 --- a/tfhe/src/core_crypto/fft_impl/fft64/crypto/tests.rs +++ b/tfhe/src/core_crypto/fft_impl/fft64/crypto/tests.rs @@ -1,19 +1,13 @@ use crate::core_crypto::fft_impl::common::tests::test_bootstrap_generic; use crate::core_crypto::fft_impl::fft64::crypto::bootstrap::FourierLweBootstrapKeyOwned; -use crate::core_crypto::prelude::*; +use crate::core_crypto::prelude::test::{FFT_U32_PARAMS, FFT_U64_PARAMS}; #[test] fn test_bootstrap_u64() { - test_bootstrap_generic::( - StandardDev(0.000007069849454709433), - StandardDev(0.00000000000000029403601535432533), - ); + test_bootstrap_generic::(FFT_U64_PARAMS); } #[test] fn test_bootstrap_u32() { - test_bootstrap_generic::( - StandardDev(0.000007069849454709433), - StandardDev(0.00000000000000029403601535432533), - ); + test_bootstrap_generic::(FFT_U32_PARAMS); } 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 0e93b0921..0aa7fe9a9 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 @@ -892,4 +892,4 @@ pub fn blind_rotate_assign>( } #[cfg(test)] -mod tests; +pub mod tests; 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 9949a6fa3..91833625e 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 @@ -1,21 +1,100 @@ use super::*; use crate::core_crypto::algorithms::slice_algorithms::*; -use crate::core_crypto::commons::dispersion::{LogStandardDev, StandardDev}; -use crate::core_crypto::commons::generators::{EncryptionRandomGenerator, SecretRandomGenerator}; +use crate::core_crypto::algorithms::test::{FftWopPbsKeys, FftWopPbsTestParams}; +use crate::core_crypto::commons::dispersion::LogStandardDev; use crate::core_crypto::commons::math::decomposition::SignedDecomposer; use crate::core_crypto::commons::parameters::{ DecompositionBaseLog, DecompositionLevelCount, DeltaLog, ExtractedBitsCount, GlweDimension, LweDimension, PlaintextCount, PolynomialCount, PolynomialSize, }; use crate::core_crypto::commons::test_tools; +use crate::core_crypto::fft_impl::common::tests::gen_keys_or_get_from_cache_if_enabled; use crate::core_crypto::fft_impl::fft64::crypto::bootstrap::{ fill_with_forward_fourier_scratch, FourierLweBootstrapKey, }; use crate::core_crypto::fft_impl::fft64::math::fft::Fft; -use crate::core_crypto::seeders::new_seeder; -use concrete_csprng::generators::SoftwareRandomGenerator; +use crate::core_crypto::prelude::test::{ + TestResources, FFT_WOPBS_N1024_PARAMS, FFT_WOPBS_N2048_PARAMS, FFT_WOPBS_N512_PARAMS, + FFT_WOPBS_PARAMS, +}; use concrete_fft::c64; use dyn_stack::{GlobalPodBuffer, PodStack, ReborrowMut, StackReq}; +use serde::de::DeserializeOwned; +use serde::Serialize; + +#[cfg(not(feature = "__coverage"))] +// Tests take about 2-3 seconds on a laptop with this number +const NB_TESTS: usize = 32; +#[cfg(not(feature = "__coverage"))] +const NB_TESTS_LIGHT: usize = 10; +#[cfg(feature = "__coverage")] +const NB_TESTS: usize = 1; +#[cfg(feature = "__coverage")] +const NB_TESTS_LIGHT: usize = 1; + +pub fn generate_keys< + Scalar: UnsignedTorus + Sync + Send + CastFrom + CastInto + Serialize + DeserializeOwned, +>( + params: FftWopPbsTestParams, + rsc: &mut TestResources, +) -> FftWopPbsKeys { + //create GLWE and LWE secret key + let glwe_sk = allocate_and_generate_new_binary_glwe_secret_key( + params.glwe_dimension, + params.polynomial_size, + &mut rsc.secret_random_generator, + ); + let small_lwe_sk = allocate_and_generate_new_binary_lwe_secret_key( + params.lwe_dimension, + &mut rsc.secret_random_generator, + ); + + let big_lwe_sk = glwe_sk.clone().into_lwe_secret_key(); + + // allocation and generation of the key in coef domain: + let std_bsk = allocate_and_generate_new_lwe_bootstrap_key( + &small_lwe_sk, + &glwe_sk, + params.pbs_base_log, + params.pbs_level, + params.lwe_modular_std_dev, + params.ciphertext_modulus, + &mut rsc.encryption_random_generator, + ); + + // allocation for the bootstrapping key + let mut fourier_bsk = FourierLweBootstrapKey::new( + params.lwe_dimension, + params.glwe_dimension.to_glwe_size(), + params.polynomial_size, + params.pbs_base_log, + params.pbs_level, + ); + + let fft = Fft::new(params.polynomial_size); + let fft = fft.as_view(); + + fourier_bsk + .as_mut_view() + .par_fill_with_forward_fourier(std_bsk.as_view(), fft); + + // Creation of all the pfksk for the circuit bootstrapping + let vec_pfpksk = par_allocate_and_generate_new_circuit_bootstrap_lwe_pfpksk_list( + &big_lwe_sk, + &glwe_sk, + params.pfks_base_log, + params.pfks_level, + params.lwe_modular_std_dev, + params.ciphertext_modulus, + &mut rsc.encryption_random_generator, + ); + FftWopPbsKeys { + small_lwe_sk, + big_lwe_sk, + fbsk: fourier_bsk, + lwe_pfpksk: vec_pfpksk, + } +} // Extract all the bits of a LWE #[test] @@ -36,24 +115,19 @@ pub fn test_extract_bits() { let ciphertext_modulus = CiphertextModulus::new_native(); let number_of_bits_of_message_including_padding = 5_usize; - // Tests take about 2-3 seconds on a laptop with this number - let number_of_test_runs = 32; - let mut seeder = new_seeder(); - let seeder = seeder.as_mut(); - - let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - let mut encryption_generator = - EncryptionRandomGenerator::::new(seeder.seed(), seeder); + let mut rsc = TestResources::new(); // allocation and generation of the key in coef domain: let glwe_sk: GlweSecretKeyOwned = allocate_and_generate_new_binary_glwe_secret_key( glwe_dimension, polynomial_size, - &mut secret_generator, + &mut rsc.secret_random_generator, + ); + let lwe_small_sk: LweSecretKeyOwned = allocate_and_generate_new_binary_lwe_secret_key( + small_lwe_dimension, + &mut rsc.secret_random_generator, ); - let lwe_small_sk: LweSecretKeyOwned = - allocate_and_generate_new_binary_lwe_secret_key(small_lwe_dimension, &mut secret_generator); let std_bsk: LweBootstrapKeyOwned = allocate_and_generate_new_lwe_bootstrap_key( &lwe_small_sk, @@ -62,7 +136,7 @@ pub fn test_extract_bits() { level_bsk, std, ciphertext_modulus, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); let mut fourier_bsk = FourierLweBootstrapKey::new( @@ -85,7 +159,7 @@ pub fn test_extract_bits() { level_ksk, std, ciphertext_modulus, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); let input_lwe_dimension = lwe_big_sk.lwe_dimension(); @@ -116,7 +190,7 @@ pub fn test_extract_bits() { //////////////////////////////////////////////////////////////////////////////////////////////// - for _ in 0..number_of_test_runs { + for _ in 0..NB_TESTS { // Generate a random plaintext in [0; 2^{number_of_bits_of_message_including_padding}[ let val = test_tools::random_uint_between( 0..2u64.pow(number_of_bits_of_message_including_padding as u32), @@ -135,7 +209,7 @@ pub fn test_extract_bits() { &mut lwe_in, message, std, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); // Bit extraction @@ -202,21 +276,18 @@ fn test_circuit_bootstrapping_binary() { let ciphertext_modulus = CiphertextModulus::new_native(); - let mut seeder = new_seeder(); - let seeder = seeder.as_mut(); - - let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - let mut encryption_generator = - EncryptionRandomGenerator::::new(seeder.seed(), seeder); + let mut rsc = TestResources::new(); // Create GLWE and LWE secret key let glwe_sk: GlweSecretKeyOwned = allocate_and_generate_new_binary_glwe_secret_key( glwe_dimension, polynomial_size, - &mut secret_generator, + &mut rsc.secret_random_generator, + ); + let lwe_sk: LweSecretKeyOwned = allocate_and_generate_new_binary_lwe_secret_key( + small_lwe_dimension, + &mut rsc.secret_random_generator, ); - let lwe_sk: LweSecretKeyOwned = - allocate_and_generate_new_binary_lwe_secret_key(small_lwe_dimension, &mut secret_generator); // Allocation and generation of the bootstrap key in standard domain: let std_bsk: LweBootstrapKeyOwned = allocate_and_generate_new_lwe_bootstrap_key( @@ -226,7 +297,7 @@ fn test_circuit_bootstrapping_binary() { level_bsk, std, ciphertext_modulus, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); let mut fourier_bsk = FourierLweBootstrapKey::new( @@ -254,14 +325,12 @@ fn test_circuit_bootstrapping_binary() { level_pksk, std, ciphertext_modulus, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); let delta_log = DeltaLog(60); - let number_of_test_runs = 32; - - for _ in 0..number_of_test_runs { + 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' @@ -273,7 +342,7 @@ fn test_circuit_bootstrapping_binary() { &mut lwe_in, message, std, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); let mut cbs_res = GgswCiphertextOwned::new( @@ -386,12 +455,6 @@ fn test_circuit_bootstrapping_binary() { #[test] pub fn test_cmux_tree() { // Define settings for an insecure toy example - let mut seeder = new_seeder(); - let seeder = seeder.as_mut(); - - let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - let mut encryption_generator = - EncryptionRandomGenerator::::new(seeder.seed(), seeder); let polynomial_size = PolynomialSize(512); let glwe_dimension = GlweDimension(1); let std = LogStandardDev::from_log_standard_dev(-60.); @@ -403,11 +466,13 @@ pub fn test_cmux_tree() { let nb_ggsw = 10; let delta_log = 60; + let mut rsc = TestResources::new(); + // Allocation and generation of the key in coef domain: let glwe_sk: GlweSecretKeyOwned = allocate_and_generate_new_binary_glwe_secret_key( glwe_dimension, polynomial_size, - &mut secret_generator, + &mut rsc.secret_random_generator, ); let glwe_size = glwe_sk.glwe_dimension().to_glwe_size(); @@ -428,9 +493,7 @@ pub fn test_cmux_tree() { // Decomposer to manage the rounding after decrypting let decomposer = SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1)); - let number_of_test_runs = 32; - - for _ in 0..number_of_test_runs { + for _ in 0..NB_TESTS { let mut value = test_tools::random_uint_between(0..2u64.pow(number_of_bits_for_payload as u32)); println!("value: {value}"); @@ -478,7 +541,7 @@ pub fn test_cmux_tree() { &mut ggsw, single_bit_msg, std, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); let mut mem = GlobalPodBuffer::new(fill_with_forward_fourier_scratch(fft).unwrap()); @@ -517,83 +580,35 @@ pub fn test_cmux_tree() { } } -// Circuit bootstrap + vecrtical packing applying an identity lut +// Circuit bootstrap + vertical packing applying an identity lut #[test] pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() { - // define settings - let polynomial_size = PolynomialSize(1024); - let glwe_dimension = GlweDimension(1); - let small_lwe_dimension = LweDimension(481); - - let level_bsk = DecompositionLevelCount(9); - let base_log_bsk = DecompositionBaseLog(4); - - let level_pksk = DecompositionLevelCount(9); - let base_log_pksk = DecompositionBaseLog(4); + let params = FFT_WOPBS_PARAMS; + let polynomial_size = params.polynomial_size; + let glwe_dimension = params.glwe_dimension; + let ciphertext_modulus = params.ciphertext_modulus; + let level_cbs = params.cbs_level; + let base_log_cbs = params.cbs_base_log; let level_ksk = DecompositionLevelCount(9); let base_log_ksk = DecompositionBaseLog(1); + let std_big = params.glwe_modular_std_dev; - let level_cbs = DecompositionLevelCount(4); - let base_log_cbs = DecompositionBaseLog(6); - - let ciphertext_modulus = CiphertextModulus::new_native(); - - // Value was 0.000_000_000_000_000_221_486_881_160_055_68_513645324585951 - // But rust indicates it gets truncated anyways to - // 0.000_000_000_000_000_221_486_881_160_055_68 - let std_small = StandardDev::from_standard_dev(0.000_000_000_000_000_221_486_881_160_055_68); - // Value was 0.000_061_200_133_780_220_371_345 - // But rust indicates it gets truncated anyways to - // 0.000_061_200_133_780_220_36 - let std_big = StandardDev::from_standard_dev(0.000_061_200_133_780_220_36); - - let mut seeder = new_seeder(); - let seeder = seeder.as_mut(); - - let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - let mut encryption_generator = - EncryptionRandomGenerator::::new(seeder.seed(), seeder); - - //create GLWE and LWE secret key - let glwe_sk: GlweSecretKeyOwned = allocate_and_generate_new_binary_glwe_secret_key( - glwe_dimension, - polynomial_size, - &mut secret_generator, - ); - let lwe_small_sk: LweSecretKeyOwned = - allocate_and_generate_new_binary_lwe_secret_key(small_lwe_dimension, &mut secret_generator); - - let lwe_big_sk = glwe_sk.clone().into_lwe_secret_key(); - - let input_lwe_dimension = lwe_big_sk.lwe_dimension(); - - // allocation and generation of the key in coef domain: - let std_bsk: LweBootstrapKeyOwned = allocate_and_generate_new_lwe_bootstrap_key( - &lwe_small_sk, - &glwe_sk, - base_log_bsk, - level_bsk, - std_small, - ciphertext_modulus, - &mut encryption_generator, - ); - - // allocation for the bootstrapping key - let mut fourier_bsk = FourierLweBootstrapKey::new( - small_lwe_dimension, - glwe_dimension.to_glwe_size(), - polynomial_size, - base_log_bsk, - level_bsk, - ); + let mut rsc = TestResources::new(); let fft = Fft::new(polynomial_size); let fft = fft.as_view(); - fourier_bsk - .as_mut_view() - .par_fill_with_forward_fourier(std_bsk.as_view(), fft); + let mut keys_gen = |params| generate_keys(params, &mut rsc); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (fourier_bsk, lwe_small_sk, lwe_big_sk, vec_pfpksk) = ( + keys.fbsk, + keys.small_lwe_sk, + keys.big_lwe_sk, + keys.lwe_pfpksk, + ); + + let input_lwe_dimension = lwe_big_sk.lwe_dimension(); let ksk_lwe_big_to_small: LweKeyswitchKeyOwned = allocate_and_generate_new_lwe_keyswitch_key( @@ -603,20 +618,9 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() { level_ksk, std_big, ciphertext_modulus, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); - // Creation of all the pfksk for the circuit bootstrapping - let vec_pfpksk = par_allocate_and_generate_new_circuit_bootstrap_lwe_pfpksk_list( - &lwe_big_sk, - &glwe_sk, - base_log_pksk, - level_pksk, - std_small, - ciphertext_modulus, - &mut encryption_generator, - ); - let number_of_bits_in_input_lwe = 10; let number_of_values_to_extract = ExtractedBitsCount(number_of_bits_in_input_lwe); @@ -627,9 +631,7 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() { let delta_log = DeltaLog(64 - number_of_values_to_extract.0); let delta_lut = DeltaLog(64 - number_of_values_to_extract.0); - let number_of_test_runs = 10; - - for run_number in 0..number_of_test_runs { + for run_number in 0..NB_TESTS_LIGHT { let cleartext = test_tools::random_uint_between(0..2u64.pow(number_of_bits_in_input_lwe as u32)); @@ -649,7 +651,7 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() { &mut lwe_in, message, std_big, - &mut encryption_generator, + &mut rsc.encryption_random_generator, ); let mut extracted_bits_lwe_list = LweCiphertextListOwned::new( @@ -762,8 +764,7 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() { let result_ct = vertical_packing_lwe_list_out.iter().next().unwrap(); // decrypt result - let lwe_sk = glwe_sk.clone().into_lwe_secret_key(); - let decrypted_message = decrypt_lwe_ciphertext(&lwe_sk, &result_ct); + let decrypted_message = decrypt_lwe_ciphertext(&lwe_big_sk, &result_ct); let decoded_message = decomposer.closest_representable(decrypted_message.0) >> delta_log.0; // print information if the result is wrong @@ -776,83 +777,42 @@ pub fn test_extract_bit_circuit_bootstrapping_vertical_packing() { } } -fn test_wop_add_one(polynomial_size: PolynomialSize) { - // DISCLAIMER: these are toy parameters and are not guaranteed to be secure - let glwe_dim = GlweDimension(1); - let small_dim = LweDimension(4); - let level_bsk = DecompositionLevelCount(4); - let base_log_bsk = DecompositionBaseLog(9); - let level_pksk = DecompositionLevelCount(2); - let base_log_pksk = DecompositionBaseLog(15); - let level_cbs = DecompositionLevelCount(4); - let base_log_cbs = DecompositionBaseLog(6); - let ciphertext_modulus = CiphertextModulus::new_native(); - let variance = crate::core_crypto::commons::dispersion::Variance(0.0); +fn test_wop_add_one(params: FftWopPbsTestParams) { + let polynomial_size = params.polynomial_size; + let small_dim = params.lwe_dimension; + let level_cbs = params.cbs_level; + let base_log_cbs = params.cbs_base_log; + let ciphertext_modulus = params.ciphertext_modulus; + let std_small = params.lwe_modular_std_dev; - let mut seeder = new_seeder(); - let seeder = seeder.as_mut(); - - let mut secret_generator = SecretRandomGenerator::::new(seeder.seed()); - let mut encryption_generator = - EncryptionRandomGenerator::::new(seeder.seed(), seeder); - - let small_sk = - allocate_and_generate_new_binary_lwe_secret_key::(small_dim, &mut secret_generator); - - let big_sk = allocate_and_generate_new_binary_glwe_secret_key( - glwe_dim, - polynomial_size, - &mut secret_generator, - ); - - let big_lwe_sk = big_sk.clone().into_lwe_secret_key(); - - // allocation and generation of the key in coef domain: - let std_bsk: LweBootstrapKeyOwned = allocate_and_generate_new_lwe_bootstrap_key( - &small_sk, - &big_sk, - base_log_bsk, - level_bsk, - variance, - ciphertext_modulus, - &mut encryption_generator, - ); - - // allocation for the bootstrapping key - let mut fourier_bsk = FourierLweBootstrapKey::new( - small_dim, - glwe_dim.to_glwe_size(), - polynomial_size, - base_log_bsk, - level_bsk, - ); + let mut rsc = TestResources::new(); let fft = Fft::new(polynomial_size); let fft = fft.as_view(); - fourier_bsk - .as_mut_view() - .par_fill_with_forward_fourier(std_bsk.as_view(), fft); - - // Creation of all the pfksk for the circuit bootstrapping - let cbs_pfpksk = par_allocate_and_generate_new_circuit_bootstrap_lwe_pfpksk_list( - &big_lwe_sk, - &big_sk, - base_log_pksk, - level_pksk, - variance, - ciphertext_modulus, - &mut encryption_generator, + let mut keys_gen = |params| generate_keys(params, &mut rsc); + let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen); + let (fourier_bsk, small_sk, big_lwe_sk, cbs_pfpksk) = ( + keys.fbsk, + keys.small_lwe_sk, + keys.big_lwe_sk, + keys.lwe_pfpksk, ); // We are going to encrypt 10 bits let number_of_input_bits: usize = 10; + #[cfg(not(feature = "__coverage"))] + const SIZE: usize = 10; + #[cfg(feature = "__coverage")] + const SIZE: usize = 1; + // Test on 610, binary representation 10011 00010 - let mut vals = [0u64; 10]; + let mut vals = [0u64; SIZE]; vals[0] = 610; // Use our generator to have more random values - encryption_generator.fill_slice_with_random_mask(&mut vals[1..]); + rsc.encryption_random_generator + .fill_slice_with_random_mask(&mut vals[1..]); // Apply our modulus to be sure we can represent the test values vals.iter_mut() .for_each(|x| *x %= 1 << number_of_input_bits); @@ -871,8 +831,8 @@ fn test_wop_add_one(polynomial_size: PolynomialSize) { &small_sk, &mut extracted_bits.get_mut(number_of_input_bits - i - 1), Plaintext(((val >> i) & 1) << 63), - variance, - &mut encryption_generator, + std_small, + &mut rsc.encryption_random_generator, ) } @@ -957,17 +917,17 @@ fn test_wop_add_one(polynomial_size: PolynomialSize) { //CMUX tree #[test] fn test_wop_add_one_cmux_tree() { - test_wop_add_one(PolynomialSize(512)) + test_wop_add_one(FFT_WOPBS_N512_PARAMS) } //No CMUX tree #[test] fn test_wop_add_one_no_cmux_tree() { - test_wop_add_one(PolynomialSize(1024)) + test_wop_add_one(FFT_WOPBS_N1024_PARAMS) } //Expanded lut #[test] fn test_wop_add_one_expanded_lut() { - test_wop_add_one(PolynomialSize(2048)) + test_wop_add_one(FFT_WOPBS_N2048_PARAMS) } diff --git a/tfhe/src/core_crypto/keycache.rs b/tfhe/src/core_crypto/keycache.rs new file mode 100644 index 000000000..2ddc8b89f --- /dev/null +++ b/tfhe/src/core_crypto/keycache.rs @@ -0,0 +1,273 @@ +use crate::core_crypto::algorithms::test::{ + ClassicBootstrapKeys, ClassicTestParams, FftBootstrapKeys, FftTestParams, FftWopPbsKeys, + FftWopPbsTestParams, MultiBitBootstrapKeys, MultiBitTestParams, PackingKeySwitchKeys, + PackingKeySwitchTestParams, +}; +use crate::keycache::*; +use lazy_static::*; +use serde::de::DeserializeOwned; +use serde::Serialize; +#[cfg(feature = "internal-keycache")] +use std::fmt::Debug; + +pub struct KeyCacheCoreImpl +where + P: Copy + NamedParam + DeserializeOwned + Serialize + PartialEq, + K: DeserializeOwned + Serialize, +{ + inner: ImplKeyCache, +} + +impl< + P: Copy + NamedParam + DeserializeOwned + Serialize + PartialEq, + K: DeserializeOwned + Serialize, + > Default for KeyCacheCoreImpl +{ + fn default() -> Self { + Self { + inner: ImplKeyCache::new(FileStorage::new( + "../keys/core_crypto/bootstrap".to_string(), + )), + } + } +} + +impl KeyCacheCoreImpl +where + P: Copy + NamedParam + DeserializeOwned + Serialize + PartialEq, + K: DeserializeOwned + Serialize + Clone, +{ + pub fn get_key_with_closure(&self, params: P, mut c: C) -> K + where + C: FnMut(P) -> K, + { + (*self.inner.get_with_closure(params, &mut c)).clone() + } + + pub fn clear_in_memory_cache(&self) { + self.inner.clear_in_memory_cache(); + } +} + +#[derive(Default)] +pub struct KeyCache { + u32_multi_bit_cache: KeyCacheCoreImpl, MultiBitBootstrapKeys>, + u64_multi_bit_cache: KeyCacheCoreImpl, MultiBitBootstrapKeys>, + u32_classic_cache: KeyCacheCoreImpl, ClassicBootstrapKeys>, + u64_classic_cache: KeyCacheCoreImpl, ClassicBootstrapKeys>, + u128_classic_cache: KeyCacheCoreImpl, ClassicBootstrapKeys>, + u32_fft_cache: KeyCacheCoreImpl, FftBootstrapKeys>, + u64_fft_cache: KeyCacheCoreImpl, FftBootstrapKeys>, + u128_fft_cache: KeyCacheCoreImpl, FftBootstrapKeys>, + u64_fft_wopbs_cache: KeyCacheCoreImpl, FftWopPbsKeys>, + u32_pksk_cache: KeyCacheCoreImpl, PackingKeySwitchKeys>, + u64_pksk_cache: KeyCacheCoreImpl, PackingKeySwitchKeys>, +} + +impl KeyCache { + pub fn get_key_with_closure(&self, params: P, c: C) -> K + where + C: FnMut(P) -> K, + P: KeyCacheAccess + Serialize + DeserializeOwned + Copy + PartialEq + NamedParam, + K: DeserializeOwned + Serialize + Clone, + { + P::access(self).get_key_with_closure(params, c) + } + + pub fn clear_in_memory_cache(&self) + where + P: KeyCacheAccess + Serialize + DeserializeOwned + Copy + PartialEq + NamedParam, + K: DeserializeOwned + Serialize + Clone, + { + P::access(self).clear_in_memory_cache(); + } +} + +pub trait KeyCacheAccess: Serialize + DeserializeOwned + Copy + PartialEq + NamedParam { + type Keys: DeserializeOwned + Serialize; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl; +} + +impl KeyCacheAccess for MultiBitTestParams { + type Keys = MultiBitBootstrapKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u32_multi_bit_cache + } +} + +impl KeyCacheAccess for MultiBitTestParams { + type Keys = MultiBitBootstrapKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u64_multi_bit_cache + } +} + +impl KeyCacheAccess for ClassicTestParams { + type Keys = ClassicBootstrapKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u32_classic_cache + } +} + +impl KeyCacheAccess for ClassicTestParams { + type Keys = ClassicBootstrapKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u64_classic_cache + } +} + +impl KeyCacheAccess for ClassicTestParams { + type Keys = ClassicBootstrapKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u128_classic_cache + } +} + +impl KeyCacheAccess for FftTestParams { + type Keys = FftBootstrapKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u32_fft_cache + } +} + +impl KeyCacheAccess for FftTestParams { + type Keys = FftBootstrapKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u64_fft_cache + } +} + +impl KeyCacheAccess for FftTestParams { + type Keys = FftBootstrapKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u128_fft_cache + } +} + +impl KeyCacheAccess for FftWopPbsTestParams { + type Keys = FftWopPbsKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u64_fft_wopbs_cache + } +} + +impl KeyCacheAccess for PackingKeySwitchTestParams { + type Keys = PackingKeySwitchKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u32_pksk_cache + } +} + +impl KeyCacheAccess for PackingKeySwitchTestParams { + type Keys = PackingKeySwitchKeys; + + fn access(keycache: &KeyCache) -> &KeyCacheCoreImpl { + &keycache.u64_pksk_cache + } +} + +lazy_static! { + pub static ref KEY_CACHE: KeyCache = Default::default(); +} + +#[cfg(feature = "internal-keycache")] +#[test] +pub fn generate_keys() { + use crate::core_crypto::algorithms::test::{ + lwe_multi_bit_programmable_bootstrapping, lwe_programmable_bootstrapping, TestResources, + DUMMY_31_U32, DUMMY_NATIVE_U32, FFT128_U128_PARAMS, FFT_U128_PARAMS, FFT_U32_PARAMS, + FFT_U64_PARAMS, FFT_WOPBS_N1024_PARAMS, FFT_WOPBS_N2048_PARAMS, FFT_WOPBS_N512_PARAMS, + FFT_WOPBS_PARAMS, MULTI_BIT_2_2_2_CUSTOM_MOD_PARAMS, MULTI_BIT_2_2_2_PARAMS, + MULTI_BIT_2_2_3_CUSTOM_MOD_PARAMS, MULTI_BIT_2_2_3_PARAMS, TEST_PARAMS_3_BITS_63_U64, + TEST_PARAMS_4_BITS_NATIVE_U64, + }; + use crate::core_crypto::fft_impl; + use crate::core_crypto::fft_impl::fft64::crypto::wop_pbs; + + fn generate_and_store< + P: Debug + KeyCacheAccess + serde::Serialize + serde::de::DeserializeOwned, + K: serde::de::DeserializeOwned + serde::Serialize + Clone, + >( + params: P, + keygen_func: &mut dyn FnMut(P) -> K, + ) { + println!("Generating : {}", params.name()); + + let start = std::time::Instant::now(); + + let _ = KEY_CACHE.get_key_with_closure(params, keygen_func); + + let stop = start.elapsed().as_secs(); + + println!("Generation took {stop} seconds"); + + // Clear keys as we go to avoid filling the RAM + KEY_CACHE.clear_in_memory_cache::() + } + + let mut rsc = TestResources::new(); + + println!("Generating keys for core_crypto"); + + let classical_u32_params = vec![DUMMY_31_U32, DUMMY_NATIVE_U32]; + for param in classical_u32_params.iter().copied() { + let mut keys_gen = |_| lwe_programmable_bootstrapping::generate_keys(param, &mut rsc); + generate_and_store(param, &mut keys_gen); + } + + let multi_bit_params = [ + MULTI_BIT_2_2_2_PARAMS, + MULTI_BIT_2_2_3_PARAMS, + MULTI_BIT_2_2_2_CUSTOM_MOD_PARAMS, + MULTI_BIT_2_2_3_CUSTOM_MOD_PARAMS, + ]; + for param in multi_bit_params.iter().copied() { + let mut keys_gen = + |_| lwe_multi_bit_programmable_bootstrapping::generate_keys(param, &mut rsc); + generate_and_store(param, &mut keys_gen); + } + + let classical_u64_params = [TEST_PARAMS_4_BITS_NATIVE_U64, TEST_PARAMS_3_BITS_63_U64]; + for param in classical_u64_params.iter().copied() { + let mut keys_gen = |_| lwe_programmable_bootstrapping::generate_keys(param, &mut rsc); + generate_and_store(param, &mut keys_gen); + } + + generate_and_store(FFT_U32_PARAMS, &mut |_| { + fft_impl::common::tests::generate_keys(FFT_U32_PARAMS, &mut rsc) + }); + generate_and_store(FFT_U64_PARAMS, &mut |_| { + fft_impl::common::tests::generate_keys(FFT_U64_PARAMS, &mut rsc) + }); + generate_and_store(FFT_U128_PARAMS, &mut |_| { + fft_impl::common::tests::generate_keys(FFT_U128_PARAMS, &mut rsc) + }); + + generate_and_store(FFT128_U128_PARAMS, &mut |_| { + fft_impl::common::tests::generate_keys(FFT128_U128_PARAMS, &mut rsc) + }); + + generate_and_store(FFT_WOPBS_PARAMS, &mut |_| { + wop_pbs::tests::generate_keys(FFT_WOPBS_PARAMS, &mut rsc) + }); + generate_and_store(FFT_WOPBS_N512_PARAMS, &mut |_| { + wop_pbs::tests::generate_keys(FFT_WOPBS_N512_PARAMS, &mut rsc) + }); + generate_and_store(FFT_WOPBS_N1024_PARAMS, &mut |_| { + wop_pbs::tests::generate_keys(FFT_WOPBS_N1024_PARAMS, &mut rsc) + }); + generate_and_store(FFT_WOPBS_N2048_PARAMS, &mut |_| { + wop_pbs::tests::generate_keys(FFT_WOPBS_N2048_PARAMS, &mut rsc) + }); +} diff --git a/tfhe/src/core_crypto/mod.rs b/tfhe/src/core_crypto/mod.rs index 2c251539d..d2f0b1160 100644 --- a/tfhe/src/core_crypto/mod.rs +++ b/tfhe/src/core_crypto/mod.rs @@ -17,3 +17,6 @@ pub mod prelude; pub mod seeders; pub mod fft_impl; + +#[cfg(test)] +pub mod keycache; diff --git a/tfhe/src/keycache/mod.rs b/tfhe/src/keycache/mod.rs index 935f5aa60..153d64b4b 100644 --- a/tfhe/src/keycache/mod.rs +++ b/tfhe/src/keycache/mod.rs @@ -155,12 +155,26 @@ pub mod utils { K: From

+ Clone, { pub fn get(&self, param: P) -> SharedKey { - self.with_key(param, |k| k.clone()) + self.get_with_closure(param, &mut K::from) + } + } + + impl KeyCache + where + P: Copy + PartialEq + NamedParam, + S: PersistentStorage, + { + pub fn get_with_closure K>( + &self, + param: P, + key_gen_closure: &mut C, + ) -> SharedKey { + self.with_closure(param, key_gen_closure) } - pub fn with_key(&self, param: P, f: F) -> R + pub fn with_closure(&self, param: P, key_gen_closure: &mut C) -> SharedKey where - F: FnOnce(&SharedKey) -> R, + C: FnMut(P) -> K, { let load_from_persistent_storage = || { // we check if we can load the key from persistent storage @@ -168,7 +182,7 @@ pub mod utils { let maybe_key = persistent_storage.load(param); maybe_key.map_or_else( || { - let key = K::from(param); + let key = key_gen_closure(param); persistent_storage.store(param, &key); key }, @@ -176,42 +190,40 @@ pub mod utils { ) }; - let try_load_from_memory_and_init = || { - // we only hold a read lock for a short duration to find the key - let maybe_shared_cell = { - let memory_storage = self.memory_storage.read().unwrap(); - memory_storage - .iter() - .find(|(p, _)| *p == param) - .map(|param_key| param_key.1.clone()) + let try_load_from_memory_and_init = || -> Result<_, ()> { + let maybe_shared_key = { + let mut res = None; + let lock = &*self.memory_storage.read().unwrap(); + for (p, key) in lock.iter() { + if *p == param { + res = Some(key.clone()); + break; + } + } + res }; - if let Some(shared_cell) = maybe_shared_cell { - shared_cell.inner.get_or_init(load_from_persistent_storage); - Ok(shared_cell) - } else { - Err(()) - } + maybe_shared_key.map_or_else( + || { + let shared_key = SharedKey { + inner: Arc::new(OnceLock::new()), + }; + shared_key.inner.get_or_init(load_from_persistent_storage); + { + // we only hold a write lock for a short duration to push the key + // if it doesn't already exists. + let mut memory_storage = self.memory_storage.write().unwrap(); + if memory_storage.iter().all(|(p, _)| *p != param) { + memory_storage.push((param, shared_key.clone())); + } + } + Ok(shared_key) + }, + Ok, + ) }; - if let Ok(result) = try_load_from_memory_and_init() { - f(&result) - } else { - { - // we only hold a write lock for a short duration to push the lazily - // evaluated key without actually evaluating the key - let mut memory_storage = self.memory_storage.write().unwrap(); - if !memory_storage.iter().any(|(p, _)| *p == param) { - memory_storage.push(( - param, - SharedKey { - inner: Arc::new(OnceLock::new()), - }, - )); - } - } - f(&try_load_from_memory_and_init().ok().unwrap()) - } + try_load_from_memory_and_init().ok().unwrap() } } } diff --git a/tfhe/src/shortint/keycache.rs b/tfhe/src/shortint/keycache.rs index e54284734..523d6f028 100644 --- a/tfhe/src/shortint/keycache.rs +++ b/tfhe/src/shortint/keycache.rs @@ -392,15 +392,6 @@ where } } -impl From for WopbsKey { - fn from(params: WopbsParamPair) -> Self { - // use with_key to avoid doing a temporary cloning - KEY_CACHE.inner.with_key(params.0, |keys| { - Self::new_wopbs_key(&keys.0, &keys.1, ¶ms.1) - }) - } -} - impl NamedParam for WopbsParamPair { fn name(&self) -> String { self.1.name() @@ -427,7 +418,9 @@ impl KeycacheWopbsV0 { pub fn get_from_param>(&self, params: T) -> SharedWopbsKey { let params = params.into(); let key = KEY_CACHE.get_from_param(params.0); - let wk = self.inner.get(params); + let wk = self.inner.get_with_closure(params, &mut |_| { + WopbsKey::new_wopbs_key(&key.inner.0, &key.inner.1, ¶ms.1) + }); SharedWopbsKey { inner: key.inner, wopbs: wk, @@ -455,17 +448,6 @@ where } } -impl From for KeySwitchingKey { - fn from(params: KeySwitchingKeyParams) -> Self { - // use with_key to avoid doing a temporary cloning - KEY_CACHE.inner.with_key(params.0, |keys_1| { - KEY_CACHE.inner.with_key(params.1, |keys_2| { - Self::new((&keys_1.0, &keys_1.1), (&keys_2.0, &keys_2.1), params.2) - }) - }) - } -} - impl NamedParam for KeySwitchingKeyParams { fn name(&self) -> String { format!("{}__{}__{}", self.0.name(), self.1.name(), self.2.name()) @@ -496,7 +478,13 @@ impl KeycacheKeySwitchingKey { let params = params.into(); let key_1 = KEY_CACHE.get_from_param(params.0); let key_2 = KEY_CACHE.get_from_param(params.1); - let ksk = self.inner.get(params); + let ksk = self.inner.get_with_closure(params, &mut |_| { + KeySwitchingKey::new( + (key_1.client_key(), key_1.server_key()), + (key_2.client_key(), key_2.server_key()), + params.2, + ) + }); SharedKeySwitchingKey { inner_1: key_1.inner, inner_2: key_2.inner, diff --git a/tfhe/src/shortint/server_key/tests/noise_level.rs b/tfhe/src/shortint/server_key/tests/noise_level.rs index 160600e96..4c7ee9306 100644 --- a/tfhe/src/shortint/server_key/tests/noise_level.rs +++ b/tfhe/src/shortint/server_key/tests/noise_level.rs @@ -253,6 +253,7 @@ fn test_ct_scalar_op_assign_noise_level_propagation(sk: &ServerKey, ct: &Ciphert }); } +#[cfg(not(feature = "__coverage"))] // This test is ignored in coverage, it takes around 4 hours to run otherwise. #[test] fn test_noise_level_propagation_ci_run_filter() { let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;