Compare commits

...

2 Commits

Author SHA1 Message Date
David Testé
146aaf662a chore(ci): spawn ec2 instance on-demand for code-coverage 2024-05-02 15:41:33 +02:00
David Testé
c28c8beb69 chore(ci): speed-up core_crypto code coverage execution duration 2024-05-02 15:40:09 +02:00
18 changed files with 556 additions and 73 deletions

View File

@@ -6,57 +6,45 @@ env:
RUSTFLAGS: "-C target-cpu=native"
RUST_BACKTRACE: "full"
RUST_MIN_STACK: "8388608"
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
on:
# Allows you to run this workflow manually from the Actions tab as an alternative.
workflow_dispatch:
# All the inputs are provided by Slab
inputs:
instance_id:
description: "AWS instance ID"
type: string
instance_image_id:
description: "AWS instance AMI ID"
type: string
instance_type:
description: "AWS instance product type"
type: string
runner_name:
description: "Action runner name"
type: string
request_id:
description: 'Slab request ID'
type: string
fork_repo:
description: 'Name of forked repo as user/repo'
type: string
fork_git_sha:
description: 'Git SHA to checkout from fork'
type: string
jobs:
setup-ec2:
name: Setup EC2 instance (code-coverage)
runs-on: ubuntu-latest
outputs:
runner-name: ${{ steps.start-instance.outputs.label }}
instance-id: ${{ steps.start-instance.outputs.ec2-instance-id }}
aws-region: ${{ steps.start-instance.outputs.aws-region }}
steps:
- name: Start instance
id: start-instance
uses: zama-ai/slab-github-runner@8562abbdc96b3619bd5debe1fb934db298f9a044
with:
mode: start
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
profile: cpu-small
code-coverage:
name: Code coverage
needs: setup-ec2
concurrency:
group: ${{ github.workflow }}_${{ github.ref }}_${{ inputs.instance_image_id }}_${{ inputs.instance_type }}
group: ${{ github.workflow }}_${{ github.ref }}
cancel-in-progress: true
runs-on: ${{ inputs.runner_name }}
runs-on: ${{ needs.setup-ec2.outputs.runner-name }}
timeout-minutes: 11520 # 8 days
steps:
# Step used for log purpose.
- name: Instance configuration used
run: |
echo "ID: ${{ inputs.instance_id }}"
echo "AMI: ${{ inputs.instance_image_id }}"
echo "Type: ${{ inputs.instance_type }}"
echo "Request ID: ${{ inputs.request_id }}"
echo "Fork repo: ${{ inputs.fork_repo }}"
echo "Fork git sha: ${{ inputs.fork_git_sha }}"
- name: Checkout tfhe-rs
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
with:
repository: ${{ inputs.fork_repo }}
ref: ${{ inputs.fork_git_sha }}
- name: Set up home
run: |
@@ -78,29 +66,29 @@ jobs:
- concrete-csprng/src/**
- name: Generate Keys
if: steps.changed-files.outputs.tfhe_any_changed == 'true'
# 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'
# 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'
# if: steps.changed-files.outputs.tfhe_any_changed == 'true'
run: |
make test_boolean_cov
- name: Run coverage for shortint
if: steps.changed-files.outputs.tfhe_any_changed == 'true'
# if: steps.changed-files.outputs.tfhe_any_changed == 'true'
run: |
make test_shortint_cov
- name: Upload tfhe coverage to Codecov
uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed
if: steps.changed-files.outputs.tfhe_any_changed == 'true'
# if: steps.changed-files.outputs.tfhe_any_changed == 'true'
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: ./coverage/
@@ -108,13 +96,13 @@ jobs:
files: shortint/cobertura.xml,boolean/cobertura.xml,core_crypto/cobertura.xml,core_crypto_avx512/cobertura.xml
- name: Run integer coverage
if: steps.changed-files.outputs.tfhe_any_changed == 'true'
# if: steps.changed-files.outputs.tfhe_any_changed == 'true'
run: |
make test_integer_cov
- name: Upload tfhe coverage to Codecov
uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed
if: steps.changed-files.outputs.tfhe_any_changed == 'true'
# if: steps.changed-files.outputs.tfhe_any_changed == 'true'
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: ./coverage/
@@ -127,8 +115,29 @@ jobs:
uses: rtCamp/action-slack-notify@4e5fb42d249be6a45a298f3c9543b111b02f7907
env:
SLACK_COLOR: ${{ job.status }}
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
SLACK_MESSAGE: "Code coverage finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"
SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
teardown-ec2:
name: Teardown EC2 instance (code-coverage)
if: ${{ always() && needs.setup-ec2.result != 'skipped' }}
needs: [ setup-ec2, code-coverage ]
runs-on: ubuntu-latest
steps:
- name: Stop instance
id: stop-instance
uses: zama-ai/slab-github-runner@8562abbdc96b3619bd5debe1fb934db298f9a044
with:
mode: stop
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
region: ${{ needs.setup-ec2.outputs.aws-region }}
label: ${{ needs.setup-ec2.outputs.runner-name }}
- name: Slack Notification
if: ${{ failure() }}
continue-on-error: true
uses: rtCamp/action-slack-notify@4e5fb42d249be6a45a298f3c9543b111b02f7907
env:
SLACK_COLOR: ${{ job.status }}
SLACK_MESSAGE: "EC2 teardown (code-coverage) finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"

View File

@@ -424,13 +424,6 @@ test_core_crypto_cov: install_rs_build_toolchain install_rs_check_toolchain inst
--implicit-test-threads $(COVERAGE_EXCLUDED_FILES) \
--features=$(TARGET_ARCH_FEATURE),experimental,internal-keycache \
-p $(TFHE_SPEC) -- 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,$(AVX512_FEATURE) \
-p $(TFHE_SPEC) -- -Z unstable-options --report-time core_crypto::; \
fi
.PHONY: test_cuda_backend # Run the internal tests of the CUDA backend
test_cuda_backend:

View File

@@ -3246,7 +3246,12 @@ mod test {
let mut thread_rng = rand::thread_rng();
for _ in 0..10_000 {
#[cfg(not(tarpaulin))]
let nb_tests = 10_000;
#[cfg(tarpaulin)]
let nb_tests = 1;
for _ in 0..nb_tests {
let lwe_sk =
LweSecretKey::generate_new_binary(lwe_dimension, &mut secret_random_generator);
@@ -3305,7 +3310,12 @@ mod test {
let mut thread_rng = rand::thread_rng();
for _ in 0..100 {
#[cfg(not(tarpaulin))]
let nb_tests = 100;
#[cfg(tarpaulin)]
let nb_tests = 1;
for _ in 0..nb_tests {
// We'll encrypt between 1 and 4 * lwe_dimension ciphertexts
let ct_count: usize = thread_rng.gen();
let ct_count = ct_count % (lwe_dimension.0 * 4) + 1;

View File

@@ -206,7 +206,10 @@ where
mod test {
use super::*;
#[cfg(not(tarpaulin))]
const NB_TESTS: usize = 1_000_000_000;
#[cfg(tarpaulin)]
const NB_TESTS: usize = 1;
#[test]
fn test_divide_funcs() {
@@ -295,7 +298,7 @@ mod test {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..1_000_000_000 {
for _ in 0..NB_TESTS {
let value: u64 = rng.gen();
// This is an easy case where we expect the values to match exactly, to cover other
// cases we would be re coding the algorithms here.

View File

@@ -993,7 +993,10 @@ fn lwe_compact_public_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
}
create_parametrized_test!(lwe_compact_public_encrypt_decrypt_custom_mod {
TEST_PARAMS_4_BITS_NATIVE_U64
#[cfg(not(tarpaulin))]
TEST_PARAMS_4_BITS_NATIVE_U64,
#[cfg(tarpaulin)]
COVERAGE_TEST_PARAMS_4_BITS_NATIVE_U64
});
#[cfg(feature = "zk-pok-experimental")]
@@ -1095,7 +1098,10 @@ fn lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod<Scalar>(
#[cfg(feature = "zk-pok-experimental")]
create_parametrized_test!(lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod {
TEST_PARAMS_4_BITS_NATIVE_U64
#[cfg(not(tarpaulin))]
TEST_PARAMS_4_BITS_NATIVE_U64,
#[cfg(tarpaulin)]
COVERAGE_TEST_PARAMS_4_BITS_NATIVE_U64
});
#[cfg(feature = "zk-pok-experimental")]
@@ -1316,3 +1322,219 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() {
assert_eq!(ser_lwe_ct_list, par_lwe_ct_list);
}
}
#[test]
fn test_compact_public_key_encryption() {
use rand::Rng;
#[cfg(not(tarpaulin))]
let nb_tests = 10_000;
#[cfg(tarpaulin)]
let nb_tests = 100;
#[cfg(not(tarpaulin))]
let lwe_dimension = LweDimension(2048);
#[cfg(tarpaulin)]
let lwe_dimension = LweDimension(1);
let glwe_noise_distribution =
Gaussian::from_dispersion_parameter(StandardDev(0.00000000000000029403601535432533), 0.0);
let ciphertext_modulus = CiphertextModulus::new_native();
let mut secret_random_generator = test_tools::new_secret_random_generator();
let mut encryption_random_generator = test_tools::new_encryption_random_generator();
let mut thread_rng = rand::thread_rng();
for _ in 0..nb_tests {
let lwe_sk = LweSecretKey::generate_new_binary(lwe_dimension, &mut secret_random_generator);
let mut compact_lwe_pk = LweCompactPublicKey::new(0u64, lwe_dimension, ciphertext_modulus);
generate_lwe_compact_public_key(
&lwe_sk,
&mut compact_lwe_pk,
glwe_noise_distribution,
&mut encryption_random_generator,
);
let msg: u64 = thread_rng.gen();
let msg = msg % 16;
let plaintext = Plaintext(msg << 60);
let mut output_ct = LweCiphertext::new(
0u64,
lwe_dimension.to_lwe_size(),
CiphertextModulus::new_native(),
);
encrypt_lwe_ciphertext_with_compact_public_key(
&compact_lwe_pk,
&mut output_ct,
plaintext,
glwe_noise_distribution,
glwe_noise_distribution,
&mut secret_random_generator,
&mut encryption_random_generator,
);
let decrypted_plaintext = decrypt_lwe_ciphertext(&lwe_sk, &output_ct);
let signed_decomposer =
SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
let cleartext = signed_decomposer.closest_representable(decrypted_plaintext.0) >> 60;
assert_eq!(cleartext, msg);
}
}
#[test]
fn test_par_compact_lwe_list_public_key_encryption_equivalence() {
use rand::Rng;
let lwe_dimension = LweDimension(2048);
let glwe_noise_distribution =
Gaussian::from_dispersion_parameter(StandardDev(0.00000000000000029403601535432533), 0.0);
let ciphertext_modulus = CiphertextModulus::new_native();
let mut thread_rng = rand::thread_rng();
for _ in 0..NB_TESTS {
// We'll encrypt between 1 and 4 * lwe_dimension ciphertexts
let ct_count: usize = thread_rng.gen();
let ct_count = ct_count % (lwe_dimension.0 * 4) + 1;
let lwe_ciphertext_count = LweCiphertextCount(ct_count);
let seed = test_tools::random_seed();
let mut input_plaintext_list =
PlaintextList::new(0u64, PlaintextCount(lwe_ciphertext_count.0));
input_plaintext_list.iter_mut().for_each(|x| {
let msg: u64 = thread_rng.gen();
*x.0 = (msg % 16) << 60;
});
let par_lwe_ct_list = {
let mut deterministic_seeder =
DeterministicSeeder::<ActivatedRandomGenerator>::new(seed);
let mut secret_random_generator =
SecretRandomGenerator::<ActivatedRandomGenerator>::new(deterministic_seeder.seed());
let mut encryption_random_generator =
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(
deterministic_seeder.seed(),
&mut deterministic_seeder,
);
let lwe_sk =
LweSecretKey::generate_new_binary(lwe_dimension, &mut secret_random_generator);
let mut compact_lwe_pk =
LweCompactPublicKey::new(0u64, lwe_dimension, ciphertext_modulus);
generate_lwe_compact_public_key(
&lwe_sk,
&mut compact_lwe_pk,
glwe_noise_distribution,
&mut encryption_random_generator,
);
let mut output_compact_ct_list = LweCompactCiphertextList::new(
0u64,
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
ciphertext_modulus,
);
par_encrypt_lwe_compact_ciphertext_list_with_compact_public_key(
&compact_lwe_pk,
&mut output_compact_ct_list,
&input_plaintext_list,
glwe_noise_distribution,
glwe_noise_distribution,
&mut secret_random_generator,
&mut encryption_random_generator,
);
let mut output_plaintext_list = input_plaintext_list.clone();
output_plaintext_list.as_mut().fill(0u64);
let lwe_ciphertext_list = output_compact_ct_list.par_expand_into_lwe_ciphertext_list();
decrypt_lwe_ciphertext_list(&lwe_sk, &lwe_ciphertext_list, &mut output_plaintext_list);
let signed_decomposer =
SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
output_plaintext_list
.iter_mut()
.for_each(|x| *x.0 = signed_decomposer.closest_representable(*x.0));
assert_eq!(input_plaintext_list, output_plaintext_list);
lwe_ciphertext_list
};
let ser_lwe_ct_list = {
let mut deterministic_seeder =
DeterministicSeeder::<ActivatedRandomGenerator>::new(seed);
let mut secret_random_generator =
SecretRandomGenerator::<ActivatedRandomGenerator>::new(deterministic_seeder.seed());
let mut encryption_random_generator =
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(
deterministic_seeder.seed(),
&mut deterministic_seeder,
);
let lwe_sk =
LweSecretKey::generate_new_binary(lwe_dimension, &mut secret_random_generator);
let mut compact_lwe_pk =
LweCompactPublicKey::new(0u64, lwe_dimension, ciphertext_modulus);
generate_lwe_compact_public_key(
&lwe_sk,
&mut compact_lwe_pk,
glwe_noise_distribution,
&mut encryption_random_generator,
);
let mut output_compact_ct_list = LweCompactCiphertextList::new(
0u64,
lwe_dimension.to_lwe_size(),
lwe_ciphertext_count,
ciphertext_modulus,
);
encrypt_lwe_compact_ciphertext_list_with_compact_public_key(
&compact_lwe_pk,
&mut output_compact_ct_list,
&input_plaintext_list,
glwe_noise_distribution,
glwe_noise_distribution,
&mut secret_random_generator,
&mut encryption_random_generator,
);
let mut output_plaintext_list = input_plaintext_list.clone();
output_plaintext_list.as_mut().fill(0u64);
let lwe_ciphertext_list = output_compact_ct_list.expand_into_lwe_ciphertext_list();
decrypt_lwe_ciphertext_list(&lwe_sk, &lwe_ciphertext_list, &mut output_plaintext_list);
let signed_decomposer =
SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
output_plaintext_list
.iter_mut()
.for_each(|x| *x.0 = signed_decomposer.closest_representable(*x.0));
assert_eq!(input_plaintext_list, output_plaintext_list);
lwe_ciphertext_list
};
assert_eq!(ser_lwe_ct_list, par_lwe_ct_list);
}
}

View File

@@ -212,7 +212,7 @@ fn test_lwe_encrypt_ks_switch_mod_decrypt_custom_mod() {
// In coverage, we break after one while loop iteration, changing message values does not
// yield higher coverage
#[cfg(feature = "__coverage")]
#[cfg(tarpaulin)]
break;
}
}

View File

@@ -12,10 +12,18 @@ fn test_seeded_lwe_ksk_gen_equivalence<Scalar: UnsignedTorus + Send + Sync>(
// DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
// computations
// Define parameters for LweKeyswitchKey creation
#[cfg(not(tarpaulin))]
let input_lwe_dimension = LweDimension(742);
#[cfg(tarpaulin)]
let input_lwe_dimension = LweDimension(1);
#[cfg(not(tarpaulin))]
let output_lwe_dimension = LweDimension(2048);
#[cfg(tarpaulin)]
let output_lwe_dimension = LweDimension(32);
let lwe_noise_distribution =
DynamicDistribution::new_gaussian_from_std_dev(StandardDev(0.000007069849454709433));
let output_lwe_dimension = LweDimension(2048);
let decomp_base_log = DecompositionBaseLog(3);
let decomp_level_count = DecompositionLevelCount(5);

View File

@@ -12,9 +12,17 @@ fn test_seeded_lwe_pksk_gen_equivalence<Scalar: UnsignedTorus>(
// DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
// computations
// Define parameters for LweKeyswitchKey creation
#[cfg(not(tarpaulin))]
let input_lwe_dimension = LweDimension(742);
let output_glwe_dimension = GlweDimension(1);
#[cfg(tarpaulin)]
let input_lwe_dimension = LweDimension(1);
#[cfg(not(tarpaulin))]
let output_polynomial_size = PolynomialSize(2048);
#[cfg(tarpaulin)]
let output_polynomial_size = PolynomialSize(32);
let output_glwe_dimension = GlweDimension(1);
let glwe_noise_distribution = DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000000000029403601535432533,
));

View File

@@ -398,6 +398,32 @@ pub const TEST_PARAMS_4_BITS_NATIVE_U128: ClassicTestParams<u128> = ClassicTestP
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[cfg(tarpaulin)]
pub const COVERAGE_TEST_PARAMS_4_BITS_NATIVE_U128: ClassicTestParams<u128> = ClassicTestParams {
lwe_dimension: LweDimension(1),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(64),
lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
4.9982771e-11,
)),
glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
8.6457178e-32,
)),
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_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000000000029403601535432533,
)),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: MessageModulusLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const TEST_PARAMS_3_BITS_127_U128: ClassicTestParams<u128> = ClassicTestParams {
lwe_dimension: LweDimension(742),
glwe_dimension: GlweDimension(1),
@@ -423,6 +449,32 @@ pub const TEST_PARAMS_3_BITS_127_U128: ClassicTestParams<u128> = ClassicTestPara
ciphertext_modulus: CiphertextModulus::new(1 << 127),
};
#[cfg(tarpaulin)]
pub const COVERAGE_TEST_PARAMS_3_BITS_127_U128: ClassicTestParams<u128> = ClassicTestParams {
lwe_dimension: LweDimension(1),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(64),
lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
4.9982771e-11,
)),
glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
8.6457178e-32,
)),
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_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000000000029403601535432533,
)),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: MessageModulusLog(3),
ciphertext_modulus: CiphertextModulus::new(1 << 127),
};
fn lwe_encrypt_pbs_f128_decrypt_custom_mod<Scalar>(params: ClassicTestParams<Scalar>)
where
Scalar: UnsignedTorus
@@ -537,9 +589,15 @@ where
#[test]
fn lwe_encrypt_pbs_f128_decrypt_custom_mod_test_params_4_bits_native_u128() {
#[cfg(not(tarpaulin))]
lwe_encrypt_pbs_f128_decrypt_custom_mod(TEST_PARAMS_4_BITS_NATIVE_U128);
#[cfg(tarpaulin)]
lwe_encrypt_pbs_f128_decrypt_custom_mod(COVERAGE_TEST_PARAMS_4_BITS_NATIVE_U128);
}
#[test]
fn lwe_encrypt_pbs_f128_decrypt_custom_mod_test_params_3_bits_127_u128() {
#[cfg(not(tarpaulin))]
lwe_encrypt_pbs_f128_decrypt_custom_mod(TEST_PARAMS_3_BITS_127_U128);
#[cfg(tarpaulin)]
lwe_encrypt_pbs_f128_decrypt_custom_mod(COVERAGE_TEST_PARAMS_3_BITS_127_U128);
}

View File

@@ -24,6 +24,7 @@ mod lwe_packing_keyswitch_key_generation;
mod lwe_private_functional_packing_keyswitch;
pub(crate) mod lwe_programmable_bootstrapping;
mod modulus_switch_compression;
#[cfg(not(tarpaulin))]
mod noise_distribution;
pub struct TestResources {
@@ -78,6 +79,32 @@ pub const TEST_PARAMS_4_BITS_NATIVE_U64: ClassicTestParams<u64> = ClassicTestPar
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[cfg(tarpaulin)]
pub const COVERAGE_TEST_PARAMS_4_BITS_NATIVE_U64: ClassicTestParams<u64> = ClassicTestParams {
lwe_dimension: LweDimension(1),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(32),
lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.000007069849454709433,
)),
glwe_noise_distribution: DynamicDistribution::new_gaussian_from_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_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000000000029403601535432533,
)),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: MessageModulusLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const TEST_PARAMS_3_BITS_63_U64: ClassicTestParams<u64> = ClassicTestParams {
lwe_dimension: LweDimension(742),
glwe_dimension: GlweDimension(1),
@@ -103,6 +130,32 @@ pub const TEST_PARAMS_3_BITS_63_U64: ClassicTestParams<u64> = ClassicTestParams
ciphertext_modulus: CiphertextModulus::new(1 << 63),
};
#[cfg(tarpaulin)]
pub const COVERAGE_TEST_PARAMS_3_BITS_63_U64: ClassicTestParams<u64> = ClassicTestParams {
lwe_dimension: LweDimension(1),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(32),
lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.000007069849454709433,
)),
glwe_noise_distribution: DynamicDistribution::new_gaussian_from_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_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000000000029403601535432533,
)),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: MessageModulusLog(3),
ciphertext_modulus: CiphertextModulus::new(1 << 63),
};
pub const TEST_PARAMS_3_BITS_SOLINAS_U64: ClassicTestParams<u64> = ClassicTestParams {
lwe_dimension: LweDimension(742),
glwe_dimension: GlweDimension(1),
@@ -347,6 +400,70 @@ pub const FFT128_U128_PARAMS: FftTestParams<u128> = FftTestParams {
ciphertext_modulus: CiphertextModulus::<u128>::new_native(),
};
// DISCLAIMER: example parameters tailored for coverage tests. There are not guaranteed
// to be secure or yield correct computations.
#[cfg(tarpaulin)]
pub const COVERAGE_FFT_U32_PARAMS: FftTestParams<u32> = FftTestParams {
lwe_dimension: LweDimension(1),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(64),
lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000004998277131225527,
)),
glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000000000000000000000000008645717832544903,
)),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[cfg(tarpaulin)]
pub const COVERAGE_FFT_U64_PARAMS: FftTestParams<u64> = FftTestParams {
lwe_dimension: LweDimension(1),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(64),
lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000004998277131225527,
)),
glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000000000000000000000000008645717832544903,
)),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[cfg(tarpaulin)]
pub const COVERAGE_FFT_U128_PARAMS: FftTestParams<u128> = FftTestParams {
lwe_dimension: LweDimension(1),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(64),
lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000004998277131225527,
)),
glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000000000000000000000000008645717832544903,
)),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[cfg(tarpaulin)]
pub const COVERAGE_FFT128_U128_PARAMS: FftTestParams<u128> = FftTestParams {
lwe_dimension: LweDimension(1),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(64),
lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(0.12345)),
glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
0.00000000000000000000000000000008645717832544903,
)),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ciphertext_modulus: CiphertextModulus::<u128>::new_native(),
};
pub const FFT_WOPBS_PARAMS: FftWopPbsTestParams<u64> = FftWopPbsTestParams {
lwe_dimension: LweDimension(481),
glwe_dimension: GlweDimension(1),
@@ -516,21 +633,33 @@ pub(crate) fn gen_keys_or_get_from_cache_if_enabled<
// Macro to generate tests for all parameter sets
macro_rules! create_parametrized_test{
($name:ident { $($param:ident),* $(,)? }) => {
(
$name:ident {
$($(#[$cfg:meta])* $param:ident),*
$(,)?
}
) => {
::paste::paste! {
$(
#[test]
fn [<test_ $name _ $param:lower>]() {
$name($param)
}
#[test]
$(#[$cfg])*
fn [<test_ $name _ $param:lower>]() {
$name($param)
}
)*
}
};
($name:ident)=> {
create_parametrized_test!($name
{
#[cfg(not(tarpaulin))]
TEST_PARAMS_4_BITS_NATIVE_U64,
TEST_PARAMS_3_BITS_63_U64
#[cfg(not(tarpaulin))]
TEST_PARAMS_3_BITS_63_U64,
#[cfg(tarpaulin)]
COVERAGE_TEST_PARAMS_4_BITS_NATIVE_U64,
#[cfg(tarpaulin)]
COVERAGE_TEST_PARAMS_3_BITS_63_U64
});
};
}

View File

@@ -2,6 +2,7 @@
pub(crate) mod mask_random_generator;
pub(crate) mod noise_random_generator;
#[cfg(not(tarpaulin))]
#[cfg(test)]
mod test;

View File

@@ -27,6 +27,7 @@ pub use uniform::*;
pub use uniform_binary::*;
pub use uniform_ternary::*;
#[cfg(not(tarpaulin))]
#[cfg(test)]
mod tests;

View File

@@ -264,7 +264,8 @@ implement!(u64, i64, 64);
implement!(u128, i128, 128);
implement!(usize, isize, usize::BITS as usize);
#[cfg(test)]
// In coverage mode these tests are slow and have 0 impact on the covered lines.
#[cfg(all(test, not(feature = "__coverage")))]
mod test {
use super::*;

View File

@@ -1,18 +1,31 @@
use crate::core_crypto::fft_impl::common::tests::test_bootstrap_generic;
use crate::core_crypto::fft_impl::fft128::crypto::bootstrap::Fourier128LweBootstrapKeyOwned;
#[cfg(tarpaulin)]
use crate::core_crypto::prelude::test::{
COVERAGE_FFT_U128_PARAMS, COVERAGE_FFT_U32_PARAMS, COVERAGE_FFT_U64_PARAMS,
};
use crate::core_crypto::prelude::test::{FFT_U128_PARAMS, FFT_U32_PARAMS, FFT_U64_PARAMS};
#[test]
fn test_bootstrap_u128() {
#[cfg(not(tarpaulin))]
test_bootstrap_generic::<u128, Fourier128LweBootstrapKeyOwned>(FFT_U128_PARAMS);
#[cfg(tarpaulin)]
test_bootstrap_generic::<u128, Fourier128LweBootstrapKeyOwned>(COVERAGE_FFT_U128_PARAMS);
}
#[test]
fn test_bootstrap_u64() {
#[cfg(not(tarpaulin))]
test_bootstrap_generic::<u64, Fourier128LweBootstrapKeyOwned>(FFT_U64_PARAMS);
#[cfg(tarpaulin)]
test_bootstrap_generic::<u64, Fourier128LweBootstrapKeyOwned>(COVERAGE_FFT_U64_PARAMS);
}
#[test]
fn test_bootstrap_u32() {
#[cfg(not(tarpaulin))]
test_bootstrap_generic::<u32, Fourier128LweBootstrapKeyOwned>(FFT_U32_PARAMS);
#[cfg(tarpaulin)]
test_bootstrap_generic::<u32, Fourier128LweBootstrapKeyOwned>(COVERAGE_FFT_U32_PARAMS);
}

View File

@@ -79,7 +79,12 @@ fn test_product<Scalar: UnsignedTorus>() {
let mut generator = new_random_generator();
for size_log in 6..=14 {
for _ in 0..10 {
#[cfg(not(tarpaulin))]
let nb_tests = 10;
#[cfg(tarpaulin)]
let nb_tests = 1;
for _ in 0..nb_tests {
let size = 1_usize << size_log;
let fourier_size = PolynomialSize(size).to_fourier_polynomial_size().0;

View File

@@ -3,14 +3,20 @@ use super::super::math::fft::Fft128View;
use crate::core_crypto::fft_impl::common::tests::{
gen_keys_or_get_from_cache_if_enabled, generate_keys,
};
#[cfg(tarpaulin)]
use crate::core_crypto::prelude::test::COVERAGE_FFT128_U128_PARAMS;
use crate::core_crypto::prelude::test::{TestResources, FFT128_U128_PARAMS};
use crate::core_crypto::prelude::*;
use aligned_vec::CACHELINE_ALIGN;
use dyn_stack::{GlobalPodBuffer, PodStack, ReborrowMut};
#[test]
fn test_split_external_product() {
#[cfg(not(tarpaulin))]
let params = FFT128_U128_PARAMS;
#[cfg(tarpaulin)]
let params = COVERAGE_FFT128_U128_PARAMS;
let glwe_dimension = params.glwe_dimension;
let polynomial_size = params.polynomial_size;
@@ -135,7 +141,10 @@ fn test_split_external_product() {
#[test]
fn test_split_pbs() {
#[cfg(not(tarpaulin))]
let params = FFT128_U128_PARAMS;
#[cfg(tarpaulin)]
let params = COVERAGE_FFT128_U128_PARAMS;
let small_lwe_dimension = params.lwe_dimension;
let glwe_dimension = params.glwe_dimension;

View File

@@ -1,13 +1,21 @@
use crate::core_crypto::fft_impl::common::tests::test_bootstrap_generic;
use crate::core_crypto::fft_impl::fft64::crypto::bootstrap::FourierLweBootstrapKeyOwned;
#[cfg(tarpaulin)]
use crate::core_crypto::prelude::test::{COVERAGE_FFT_U32_PARAMS, COVERAGE_FFT_U64_PARAMS};
use crate::core_crypto::prelude::test::{FFT_U32_PARAMS, FFT_U64_PARAMS};
#[test]
fn test_bootstrap_u64() {
#[cfg(not(tarpaulin))]
test_bootstrap_generic::<u64, FourierLweBootstrapKeyOwned>(FFT_U64_PARAMS);
#[cfg(tarpaulin)]
test_bootstrap_generic::<u64, FourierLweBootstrapKeyOwned>(COVERAGE_FFT_U64_PARAMS);
}
#[test]
fn test_bootstrap_u32() {
#[cfg(not(tarpaulin))]
test_bootstrap_generic::<u32, FourierLweBootstrapKeyOwned>(FFT_U32_PARAMS);
#[cfg(tarpaulin)]
test_bootstrap_generic::<u32, FourierLweBootstrapKeyOwned>(COVERAGE_FFT_U32_PARAMS);
}

View File

@@ -99,7 +99,12 @@ fn test_product<Scalar: UnsignedTorus>() {
let mut generator = new_random_generator();
// SIMD versions need size >= 32 in case of AVX512
for size_log in 5..=14 {
for _ in 0..100 {
#[cfg(not(tarpaulin))]
let nb_tests = 100;
#[cfg(tarpaulin)]
let nb_tests = 1;
for _ in 0..nb_tests {
let size = 1_usize << size_log;
let fft = Fft::new(PolynomialSize(size));