use crate::ciphertext::Ciphertext;
use crate::client_key::ClientKey;
use crate::parameters::BooleanParameters;
use crate::server_key::{BinaryBooleanGates, ServerKey};
use crate::{random_boolean, random_integer};
const NB_TEST: usize = 128;
const NB_CT: usize = 8;
const NB_GATE: usize = 1 << 11;
#[cfg(not(feature = "cuda"))]
mod default_parameters_tests {
use super::*;
use crate::parameters::DEFAULT_PARAMETERS;
#[test]
fn test_encrypt_decrypt_lwe_secret_key_default_parameters() {
test_encrypt_decrypt_lwe_secret_key(DEFAULT_PARAMETERS);
}
#[test]
fn test_and_gate_default_parameters() {
test_and_gate(DEFAULT_PARAMETERS);
}
#[test]
fn test_nand_gate_default_parameters() {
test_nand_gate(DEFAULT_PARAMETERS);
}
#[test]
fn test_or_gate_default_parameters() {
test_or_gate(DEFAULT_PARAMETERS);
}
#[test]
fn test_nor_gate_default_parameters() {
test_nor_gate(DEFAULT_PARAMETERS);
}
#[test]
fn test_xor_gate_default_parameters() {
test_xor_gate(DEFAULT_PARAMETERS);
}
#[test]
fn test_xnor_gate_default_parameters() {
test_xnor_gate(DEFAULT_PARAMETERS);
}
#[test]
fn test_not_gate_default_parameters() {
test_not_gate(DEFAULT_PARAMETERS);
}
#[test]
fn test_mux_gate_default_parameters() {
test_mux_gate(DEFAULT_PARAMETERS);
}
#[test]
fn test_deep_circuit_default_parameters() {
test_deep_circuit(DEFAULT_PARAMETERS);
}
}
mod tfhe_lib_parameters_tests {
use super::*;
use crate::parameters::TFHE_LIB_PARAMETERS;
#[test]
fn test_encrypt_decrypt_lwe_secret_key_tfhe_lib_parameters() {
test_encrypt_decrypt_lwe_secret_key(TFHE_LIB_PARAMETERS);
}
#[test]
fn test_and_gate_tfhe_lib_parameters() {
test_and_gate(TFHE_LIB_PARAMETERS);
}
#[test]
fn test_nand_gate_tfhe_lib_parameters() {
test_nand_gate(TFHE_LIB_PARAMETERS);
}
#[test]
fn test_or_gate_tfhe_lib_parameters() {
test_or_gate(TFHE_LIB_PARAMETERS);
}
#[test]
fn test_nor_gate_tfhe_lib_parameters() {
test_nor_gate(TFHE_LIB_PARAMETERS);
}
#[test]
fn test_xor_gate_tfhe_lib_parameters() {
test_xor_gate(TFHE_LIB_PARAMETERS);
}
#[test]
fn test_xnor_gate_tfhe_lib_parameters() {
test_xnor_gate(TFHE_LIB_PARAMETERS);
}
#[test]
fn test_not_gate_tfhe_lib_parameters() {
test_not_gate(TFHE_LIB_PARAMETERS);
}
#[test]
fn test_mux_gate_tfhe_lib_parameters() {
test_mux_gate(TFHE_LIB_PARAMETERS);
}
#[test]
fn test_deep_circuit_tfhe_lib_parameters() {
test_deep_circuit(TFHE_LIB_PARAMETERS);
}
}
fn test_encrypt_decrypt_lwe_secret_key(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
for _ in 0..NB_TEST {
let ct_false = cks.encrypt(false);
let ct_true = cks.encrypt(true);
let dec_false = cks.decrypt(&ct_false);
let dec_true = cks.decrypt(&ct_true);
assert!(!dec_false);
assert!(dec_true);
let ct_false = sks.trivial_encrypt(false);
let ct_true = sks.trivial_encrypt(true);
let dec_false = cks.decrypt(&ct_false);
let dec_true = cks.decrypt(&ct_true);
assert!(!dec_false);
assert!(dec_true);
}
}
fn random_enum_encryption(cks: &ClientKey, sks: &ServerKey, message: bool) -> Ciphertext {
if random_boolean() {
cks.encrypt(message)
} else {
sks.trivial_encrypt(message)
}
}
fn test_and_gate(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
for _ in 0..NB_TEST {
let b1 = random_boolean();
let b2 = random_boolean();
let expected_result = b1 && b2;
let ct1 = random_enum_encryption(&cks, &sks, b1);
let ct2 = random_enum_encryption(&cks, &sks, b2);
let ct_res = sks.and(&ct1, &ct2);
let dec_and = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_and,
"left: {:?}, right: {:?}",
ct1, ct2
);
let ct_res = sks.and(&ct1, b2);
let dec_and = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_and, "left: {:?}, right: {:?}", ct1, b2);
let ct_res = sks.and(b1, &ct2);
let dec_and = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_and, "left: {:?}, right: {:?}", b1, ct2);
}
}
fn test_mux_gate(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
for _ in 0..NB_TEST {
let b1 = random_boolean();
let b2 = random_boolean();
let b3 = random_boolean();
let expected_result = if b1 { b2 } else { b3 };
let ct1 = random_enum_encryption(&cks, &sks, b1);
let ct2 = random_enum_encryption(&cks, &sks, b2);
let ct3 = random_enum_encryption(&cks, &sks, b3);
let ct_res = sks.mux(&ct1, &ct2, &ct3);
let dec_mux = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_mux,
"cond: {:?}, then: {:?}, else: {:?}",
ct1, ct2, ct3
);
}
}
fn test_nand_gate(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
for _ in 0..NB_TEST {
let b1 = random_boolean();
let b2 = random_boolean();
let expected_result = !(b1 && b2);
let ct1 = random_enum_encryption(&cks, &sks, b1);
let ct2 = random_enum_encryption(&cks, &sks, b2);
let ct_res = sks.nand(&ct1, &ct2);
let dec_nand = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_nand,
"left: {:?}, right: {:?}",
ct1, ct2
);
let ct_res = sks.nand(&ct1, b2);
let dec_nand = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_nand,
"left: {:?}, right: {:?}",
ct1, b2
);
let ct_res = sks.nand(b1, &ct2);
let dec_nand = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_nand,
"left: {:?}, right: {:?}",
b1, ct2
);
}
}
fn test_nor_gate(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
for _ in 0..NB_TEST {
let b1 = random_boolean();
let b2 = random_boolean();
let expected_result = !(b1 || b2);
let ct1 = random_enum_encryption(&cks, &sks, b1);
let ct2 = random_enum_encryption(&cks, &sks, b2);
let ct_res = sks.nor(&ct1, &ct2);
let dec_nor = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_nor,
"left: {:?}, right: {:?}",
ct1, ct2
);
let ct_res = sks.nor(&ct1, b2);
let dec_nor = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_nor, "left: {:?}, right: {:?}", ct1, b2);
let ct_res = sks.nor(b1, &ct2);
let dec_nor = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_nor, "left: {:?}, right: {:?}", b1, ct2);
}
}
fn test_not_gate(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
for _ in 0..NB_TEST {
let b1 = random_boolean();
let expected_result = !b1;
let ct1 = random_enum_encryption(&cks, &sks, b1);
let ct_res = sks.not(&ct1);
let dec_not = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_not);
}
}
fn test_or_gate(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
for _ in 0..NB_TEST {
let b1 = random_boolean();
let b2 = random_boolean();
let expected_result = b1 || b2;
let ct1 = random_enum_encryption(&cks, &sks, b1);
let ct2 = random_enum_encryption(&cks, &sks, b2);
let ct_res = sks.or(&ct1, &ct2);
let dec_or = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_or, "left: {:?}, right: {:?}", ct1, ct2);
let ct_res = sks.or(&ct1, b2);
let dec_or = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_or, "left: {:?}, right: {:?}", ct1, b2);
let ct_res = sks.or(b1, &ct2);
let dec_or = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_or, "left: {:?}, right: {:?}", b1, ct2);
}
}
fn test_xnor_gate(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
for _ in 0..NB_TEST {
let b1 = random_boolean();
let b2 = random_boolean();
let expected_result = b1 == b2;
let ct1 = random_enum_encryption(&cks, &sks, b1);
let ct2 = random_enum_encryption(&cks, &sks, b2);
let ct_res = sks.xnor(&ct1, &ct2);
let dec_xnor = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_xnor,
"left: {:?}, right: {:?}",
ct1, ct2
);
let ct_res = sks.xnor(&ct1, b2);
let dec_xnor = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_xnor,
"left: {:?}, right: {:?}",
ct1, b2
);
let ct_res = sks.xnor(b1, &ct2);
let dec_xnor = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_xnor,
"left: {:?}, right: {:?}",
b1, ct2
);
}
}
fn test_xor_gate(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
for _ in 0..NB_TEST {
let b1 = random_boolean();
let b2 = random_boolean();
let expected_result = b1 ^ b2;
let ct1 = random_enum_encryption(&cks, &sks, b1);
let ct2 = random_enum_encryption(&cks, &sks, b2);
let ct_res = sks.xor(&ct1, &ct2);
let dec_xor = cks.decrypt(&ct_res);
assert_eq!(
expected_result, dec_xor,
"left: {:?}, right: {:?}",
ct1, ct2
);
let ct_res = sks.xor(&ct1, b2);
let dec_xor = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_xor, "left: {:?}, right: {:?}", ct1, b2);
let ct_res = sks.xor(b1, &ct2);
let dec_xor = cks.decrypt(&ct_res);
assert_eq!(expected_result, dec_xor, "left: {:?}, right: {:?}", b1, ct2);
}
}
fn random_index() -> usize {
(random_integer() % (NB_CT as u32)) as usize
}
fn random_gate_all(ct_tab: &mut [Ciphertext], bool_tab: &mut [bool], sks: &ServerKey) {
let gate_id = random_integer() % 8;
let index_1: usize = random_index();
let index_2: usize = random_index();
if gate_id == 0 {
bool_tab[index_2] = !bool_tab[index_1];
ct_tab[index_2] = sks.not(&ct_tab[index_1]);
} else if gate_id == 1 {
let index_3: usize = random_index();
let index_4: usize = random_index();
bool_tab[index_4] = if bool_tab[index_1] {
bool_tab[index_2]
} else {
bool_tab[index_3]
};
ct_tab[index_4] = sks.mux(&ct_tab[index_1], &ct_tab[index_2], &ct_tab[index_3]);
} else {
let index_3: usize = random_index();
if gate_id == 2 {
bool_tab[index_3] = bool_tab[index_1] && bool_tab[index_2];
ct_tab[index_3] = sks.and(&ct_tab[index_1], &ct_tab[index_2]);
} else if gate_id == 3 {
bool_tab[index_3] = !(bool_tab[index_1] && bool_tab[index_2]);
ct_tab[index_3] = sks.nand(&ct_tab[index_1], &ct_tab[index_2]);
} else if gate_id == 4 {
bool_tab[index_3] = !(bool_tab[index_1] || bool_tab[index_2]);
ct_tab[index_3] = sks.nor(&ct_tab[index_1], &ct_tab[index_2]);
} else if gate_id == 5 {
bool_tab[index_3] = bool_tab[index_1] || bool_tab[index_2];
ct_tab[index_3] = sks.or(&ct_tab[index_1], &ct_tab[index_2]);
} else if gate_id == 6 {
bool_tab[index_3] = bool_tab[index_1] ^ bool_tab[index_2];
ct_tab[index_3] = sks.xor(&ct_tab[index_1], &ct_tab[index_2]);
} else {
bool_tab[index_3] = !(bool_tab[index_1] ^ bool_tab[index_2]);
ct_tab[index_3] = sks.xnor(&ct_tab[index_1], &ct_tab[index_2]);
}
}
}
fn test_deep_circuit(parameters: BooleanParameters) {
let cks = ClientKey::new(¶meters);
let sks = ServerKey::new(&cks);
let mut ct_tab: Vec<Ciphertext> = vec![cks.encrypt(true); NB_CT];
let mut bool_tab: Vec<bool> = vec![true; NB_CT];
for (ct, boolean) in ct_tab.iter_mut().zip(bool_tab.iter_mut()) {
*boolean = random_boolean();
*ct = cks.encrypt(*boolean);
}
for _ in 0..NB_GATE {
random_gate_all(&mut ct_tab, &mut bool_tab, &sks);
}
for (ct, boolean) in ct_tab.iter().zip(bool_tab.iter()) {
let dec = cks.decrypt(ct);
assert_eq!(*boolean, dec);
}
}