|
|
@@ -0,0 +1,103 @@
|
|
|
+import logging
|
|
|
+import random
|
|
|
+
|
|
|
+import pytest
|
|
|
+import openfhe as fhe
|
|
|
+
|
|
|
+
|
|
|
+LOGGER = logging.getLogger("test_bgv")
|
|
|
+
|
|
|
+
|
|
|
+@pytest.fixture(scope="module")
|
|
|
+def bgv_context():
|
|
|
+ """
|
|
|
+ This fixture creates a small CKKS context, with its paramters and keys.
|
|
|
+ We make it because context creation can be slow.
|
|
|
+ """
|
|
|
+ parameters = fhe.CCParamsBGVRNS()
|
|
|
+ parameters.SetPlaintextModulus(65537)
|
|
|
+ parameters.SetMultiplicativeDepth(2)
|
|
|
+
|
|
|
+ crypto_context = fhe.GenCryptoContext(parameters)
|
|
|
+ crypto_context.Enable(fhe.PKESchemeFeature.PKE)
|
|
|
+ crypto_context.Enable(fhe.PKESchemeFeature.KEYSWITCH)
|
|
|
+ crypto_context.Enable(fhe.PKESchemeFeature.LEVELEDSHE)
|
|
|
+ key_pair = crypto_context.KeyGen()
|
|
|
+ # Generate the relinearization key
|
|
|
+ crypto_context.EvalMultKeyGen(key_pair.secretKey)
|
|
|
+ # Generate the rotation evaluation keys
|
|
|
+ crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2])
|
|
|
+ return parameters, crypto_context, key_pair
|
|
|
+
|
|
|
+
|
|
|
+def bgv_equal(raw, ciphertext, cc, keys):
|
|
|
+ """Compare an unencrypted list of values with encrypted values"""
|
|
|
+ pt = cc.Decrypt(ciphertext, keys.secretKey)
|
|
|
+ pt.SetLength(len(raw))
|
|
|
+ compare = pt.GetPackedValue()
|
|
|
+ success = all([a == b for (a, b) in zip(raw, compare)])
|
|
|
+ if not success:
|
|
|
+ LOGGER.info("Mismatch between %s %s", raw, compare)
|
|
|
+ return success
|
|
|
+
|
|
|
+
|
|
|
+def roll(a, n):
|
|
|
+ """Circularly rotate a list, like numpy.roll but without numpy."""
|
|
|
+ return [a[i % len(a)] for i in range(-n, len(a) - n)]
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.parametrize("n,final", [
|
|
|
+ (0, [0, 1, 2, 3, 4, 5, 6, 7]),
|
|
|
+ (2, [6, 7, 0, 1, 2, 3, 4, 5]),
|
|
|
+ (3, [5, 6, 7, 0, 1, 2, 3, 4]),
|
|
|
+ (-1, [1, 2, 3, 4, 5, 6, 7, 0]),
|
|
|
+ ])
|
|
|
+def test_roll(n, final):
|
|
|
+ assert roll(list(range(8)), n) == final
|
|
|
+
|
|
|
+
|
|
|
+def shift(a, n):
|
|
|
+ """Rotate a list with infill of 0."""
|
|
|
+ return [(a[i] if 0 <= i < len(a) else 0) for i in range(-n, len(a) - n)]
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.parametrize("n,final", [
|
|
|
+ (0, [1, 2, 3, 4, 5, 6, 7, 8]),
|
|
|
+ (2, [0, 0, 1, 2, 3, 4, 5, 6]),
|
|
|
+ (3, [0, 0, 0, 1, 2, 3, 4, 5]),
|
|
|
+ (-1, [2, 3, 4, 5, 6, 7, 8, 0]),
|
|
|
+ ])
|
|
|
+def test_shift(n, final):
|
|
|
+ assert shift(list(range(1, 9)), n) == final
|
|
|
+
|
|
|
+
|
|
|
+def test_simple_integers(bgv_context):
|
|
|
+ parameters, crypto_context, key_pair = bgv_context
|
|
|
+ rng = random.Random(342342)
|
|
|
+ cnt = 12
|
|
|
+ raw = [[rng.randint(1, 12) for _ in range(cnt)] for _ in range(3)]
|
|
|
+ plaintext = [crypto_context.MakePackedPlaintext(r) for r in raw]
|
|
|
+ ciphertext = [crypto_context.Encrypt(key_pair.publicKey, pt) for pt in plaintext]
|
|
|
+ assert bgv_equal(raw[0], ciphertext[0], crypto_context, key_pair)
|
|
|
+
|
|
|
+ # Homomorphic additions
|
|
|
+ ciphertext_add12 = crypto_context.EvalAdd(ciphertext[0], ciphertext[1])
|
|
|
+ ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext[2])
|
|
|
+ assert bgv_equal(
|
|
|
+ [a + b + c for (a, b, c) in zip(*raw)],
|
|
|
+ ciphertext_add_result, crypto_context, key_pair
|
|
|
+ )
|
|
|
+
|
|
|
+ # Homomorphic Multiplication
|
|
|
+ ciphertext_mult12 = crypto_context.EvalMult(ciphertext[0], ciphertext[1])
|
|
|
+ ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext[2])
|
|
|
+ assert bgv_equal(
|
|
|
+ [a * b * c for (a, b, c) in zip(*raw)],
|
|
|
+ ciphertext_mult_result, crypto_context, key_pair
|
|
|
+ )
|
|
|
+
|
|
|
+ # Homomorphic Rotations. These values must be initialized with EvalRotateKeyGen.
|
|
|
+ for rotation in [1, 2, -1, -2]:
|
|
|
+ ciphertext_rot1 = crypto_context.EvalRotate(ciphertext[0], rotation)
|
|
|
+ # This is a rotation with infill of 0, NOT a circular rotation.
|
|
|
+ assert bgv_equal(shift(raw[0], -rotation), ciphertext_rot1, crypto_context, key_pair)
|