def test_fresh_noise_budget(coeff_mod, plain_mod, expected_noise, poly_mod=2048, security=128, plain=1, base=2): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() cipher = cs.encrypt(pk, plain, base=base) # Noise budget in bits ~ log2(coeff_modulus/plain_modulus) assert abs(expected_noise - cipher.noise_budget(sk)) <= 1
def test_relinearize(dbc, expected_noise, poly_mod=8192, coeff_mod=0, plain_mod=1024, security=128, plain=700, base=2): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, ek, _ = cs.generate_keys(dbc=dbc) cipher_1 = cs.encrypt(pk, plain, base=base) cipher_2 = (cipher_1 * cipher_1).relinearize(ek) assert abs(expected_noise - cipher_2.noise_budget(sk)) <= 2
def test_fresh_size(coeff_mod, plain_mod, poly_mod=2048, security=128, plain=1, base=2): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() cipher = cs.encrypt(pk, plain, base=base) assert cipher.size() == 2
def test_neg_enc_dec(plain, poly_mod=2048, coeff_mod=0, plain_mod=256, security=128, base=2): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() cipher_1 = cs.encrypt(pk, plain, base=base) cipher_2 = -(-cipher_1) assert abs(plain - cipher_2.decrypt(sk)) <= 0.5
def test_neg_noise_budget(coeff_mod, plain_mod, expected_noise, poly_mod=2048, security=128, plain=1, base=2): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() cipher_1 = cs.encrypt(pk, plain, base=base) cipher_2 = -cipher_1 # Negation consumes ~ zero noise bits assert abs(cipher_1.noise_budget(sk) - cipher_2.noise_budget(sk)) <= 1
def test_pow_enc_dec(plain, power, expected, poly_mod=8192, coeff_mod=0, plain_mod=1024, security=128, base=2): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() cipher_1 = cs.encrypt(pk, plain, base=base) cipher_2 = cipher_1**power assert abs(expected - cipher_2.decrypt(sk)) <= 0.5
def test_pow_noise_budget(coeff_mod, plain_mod, expected_noise, poly_mod=4096, security=128, plain=1, base=2, power=3): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() cipher_1 = cs.encrypt(pk, plain, base=base) cipher_2 = cipher_1**power assert abs(expected_noise - cipher_2.noise_budget(sk)) <= 7
def test_add_plain_enc_dec(plain, poly_mod=2048, coeff_mod=0, plain_mod=256, security=128, base=2): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() cipher_1 = cs.encrypt(pk, plain, base=base) cipher_2 = plain + cipher_1 expected = plain + plain assert abs(expected - cipher_2.decrypt(sk)) <= 0.5
def test_mul_noise_budget(coeff_mod, plain_mod, expected_noise, poly_mod=2048, security=128, plain=1, base=2): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() cipher_1 = cs.encrypt(pk, plain, base=base) cipher_2 = cipher_1 * cipher_1 # Multiplication consumes ~ half the noise budget assert abs(cipher_1.noise_budget(sk) - (2 * cipher_2.noise_budget(sk))) <= 5
def test_encode_decode(plain, base, poly_mod=4096, plain_mod=40961): cs = CipherScheme(poly_mod, plain_mod) encoded, encoder = Encoder(plain, cs.context, base=base) if isinstance(plain, np.ndarray): assert (plain == encoder.decode(encoded)).all() else: assert plain == encoder.decode(encoded)
def test_rotation_enc_dec(shift, poly_mod=4096, coeff_mod=0, plain_mod=40961, security=128): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, gk = cs.generate_keys() plain = np.asarray(list(range(poly_mod))).reshape((2, 2048)) expected = np.roll(plain, shift, (0, 1)) cipher_1 = cs.encrypt(pk, plain) cipher_2 = cipher_1.roll(gk, shift) decrypted = cipher_2.decrypt(sk) assert np.linalg.norm(np.subtract(expected, decrypted), ord=1) <= 0.5 * poly_mod
def test_same_keygen_different_keys(plain=1): """ Repeated called to CipherScheme generate_key() generate matching keys """ cs = CipherScheme() # created from the same KeyGenerator pk_1, sk_1, _, _ = cs.generate_keys() pk_2, sk_2, _, _ = cs.generate_keys() cipher_1 = cs.encrypt(pk_1, plain) cipher_2 = cs.encrypt(pk_2, plain) # both sets of keys work assert plain == cipher_1.decrypt(sk_1) assert plain == cipher_1.decrypt(sk_2) assert plain == cipher_2.decrypt(sk_1) assert plain == cipher_2.decrypt(sk_2)
def test_add_enc_dec(mat_element, poly_mod=4096, coeff_mod=0, plain_mod=40961, security=128): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() plain = mat_element * np.ones((2, 2048), int) expected = np.add(plain, plain) cipher_1 = cs.encrypt(pk, plain) cipher_2 = cipher_1 + cipher_1 decrypted = cipher_2.decrypt(sk) assert np.linalg.norm(np.subtract(expected, decrypted), ord=1) <= 0.5 * poly_mod
def test_mul_by_encoded_plain_enc_dec(plain_1, plain_2, poly_mod=2048, coeff_mod=0, plain_mod=256, security=128, base=2): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() encoded, encoder = Encoder(plain_2, cs.context, base=base) cipher_1 = cs.encrypt(pk, plain_1, base=base) cipher_2 = cipher_1 * encoded expected = plain_1 * plain_2 assert abs(expected - cipher_2.decrypt(sk)) <= 0.5
def test_type_inconsistency(plain_1, kwargs_1, plain_2, kwargs_2, poly_mod=2048, coeff_mod=0, plain_mod=256, security=128): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() cipher_1 = cs.encrypt(pk, plain_1, **kwargs_1) cipher_2 = cs.encrypt(pk, plain_2, **kwargs_2) with pytest.raises(TypeError): _ = cipher_1 + cipher_2 with pytest.raises(TypeError): _ = cipher_1 - cipher_2 with pytest.raises(TypeError): _ = cipher_1 * cipher_2
def test_different_keygen_same_context(plain=1): """ Using two different KeyGenerators generate non-matching keys """ cs = CipherScheme() context = cs.context key_gen_1 = KeyGenerator(context) key_gen_2 = KeyGenerator(context) # created from a different KeyGenerator pk_1, sk_1 = key_gen_1.public_key(), key_gen_1.secret_key() pk_2, sk_2 = key_gen_2.public_key(), key_gen_2.secret_key() cipher_1 = cs.encrypt(pk_1, plain) cipher_2 = cs.encrypt(pk_2, plain) # using same KeyGen generated keys works assert plain == cipher_1.decrypt(sk_1) assert plain == cipher_2.decrypt(sk_2) # using keys from a different KeyGen doesn't work assert plain != cipher_2.decrypt(sk_1) assert plain != cipher_1.decrypt(sk_2)
def test_float_coeff_allocation(kwargs, encoder_type=float): cs = CipherScheme() _ = Encoder(encoder_type, cs.context, **kwargs)
def different_context(second_context, plain=1): cs_1 = CipherScheme() if second_context == "from_pickle": cs_2 = pickle.loads(pickle.dumps(cs_1)) elif second_context == "regenerate": cs_2 = CipherScheme() elif second_context == "from_cipher": # steal context from CipherText pk, _, _, _ = cs_1.generate_keys() cipher = cs_1.encrypt(pk, plain) context = cipher._context cs_2 = CipherScheme() cs_2.context = context cs_2._keygen = KeyGenerator(context) cs_2._evl = Evaluator(context) elif second_context == "from_encoder": # steal context from Encoder pk, _, _, _ = cs_1.generate_keys() cipher = cs_1.encrypt(pk, plain) context = cipher._encoder._context cs_2 = CipherScheme() cs_2.context = context cs_2._keygen = KeyGenerator(context) cs_2._evl = Evaluator(context) else: return pk_1, sk_1, _, _ = cs_1.generate_keys() pk_2, sk_2, _, _ = cs_2.generate_keys() cipher_1 = cs_1.encrypt(pk_1, plain) cipher_2 = cs_2.encrypt(pk_2, plain) # different CipherSchemes can be used, but not only with keys generated from the original CipherScheme assert plain == cipher_1.decrypt(sk_1) assert plain == cipher_2.decrypt(sk_2) # keys generated by another CipherScheme won't work assert plain != cipher_1.decrypt(sk_2) assert plain != cipher_2.decrypt(sk_1) # keys generated by another CipherScheme won't work, even when using the CipherScheme that generated them assert plain != cipher_1.decrypt(sk_2) assert plain != cipher_2.decrypt(sk_1)
def test_str(poly_mod, coeff_mod, plain_mod, security): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) _ = str(cs)
def test_key_generation(poly_mod, coeff_mod, plain_mod, security): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) assert cs.generate_keys() != cs.generate_keys()
def test_eq(encoder_type, base, poly_mod=4096, plain_mod=40961): cs = CipherScheme(poly_mod, plain_mod) _, encoder1 = Encoder(encoder_type, cs.context, base=base) _, encoder2 = Encoder(encoder_type, cs.context, base=base) assert encoder1 == encoder2
def test_enc_dec(poly_mod, coeff_mod, plain_mod, security, plain, base): cs = CipherScheme(poly_mod, plain_mod, coeff_mod, security) pk, sk, _, _ = cs.generate_keys() assert abs(plain - cs.encrypt(pk, plain, base=base).decrypt(sk)) <= 0.5
def test_eq(poly_mod, coeff_mod, plain_mod, security): cs1 = CipherScheme(poly_mod, plain_mod, coeff_mod, security) cs2 = CipherScheme(poly_mod, plain_mod, coeff_mod, security) assert cs1 == cs2
def test_encoding_type(plain, encoder_type, poly_mod=4096, plain_mod=40961): cs = CipherScheme(poly_mod, plain_mod) _, encoder = Encoder(plain, cs.context) assert isinstance(encoder, encoder_type)