TKK_E32232028/.venv/lib/python3.10/site-packages/tests/test_bonehgohnissim.py

252 lines
6.0 KiB
Python

import time
import pytest
from lightphe import LightPHE
from lightphe.commons.logger import Logger
logger = Logger(module="tests/test_bonehgodnissim.py")
cs = LightPHE(
algorithm_name="Boneh-Goh-Nissim",
key_size=50,
max_tries=10000,
)
security_level = cs.cs.ec.n.bit_length()
def test_api():
tic = time.time()
m1 = 83
m2 = 31
c1 = cs.encrypt(plaintext=m1)
c2 = cs.encrypt(plaintext=m2)
# proof of decryption
assert cs.decrypt(c1) == m1
assert cs.decrypt(c2) == m2
# homomorphic addition
assert cs.decrypt(c1 + c2) == (m1 + m2) % cs.cs.plaintext_modulo
# homomorphic multiplication (once)
c1_times_c2 = c1 * c2
assert cs.decrypt(c1_times_c2) == (m1 * m2) % cs.cs.plaintext_modulo
# scalar multiplication
k = 2
assert cs.decrypt(c1 * k) == (m1 * k) % cs.cs.plaintext_modulo
# unsupported homomorphic operations
with pytest.raises(
ValueError,
match="Boneh-Goh-Nissim only supports multiplication ciphertexts once!",
):
_ = c1_times_c2 * c2
with pytest.raises(ValueError):
_ = c1 & c2
with pytest.raises(ValueError):
_ = c1 ^ c2
# re-randomization
c1_prime = cs.cs.reencrypt(c1.value)
c2_prime = cs.cs.reencrypt(c2.value)
# assert c1.value != c1_prime
# assert c2.value != c2_prime
assert cs.cs.decrypt(c1_prime) == m1
assert cs.cs.decrypt(c2_prime) == m2
logger.info(
f"✅ Boneh-God-Nissim test succeeded ({security_level} bit ECC security level)"
f" in {time.time() - tic:.2f} seconds"
)
def test_linear_regression():
tic = time.time()
x1 = 5
w1 = 7
x2 = 3
w2 = 4
x1_enc = cs.encrypt(plaintext=x1)
w1_enc = cs.encrypt(plaintext=w1)
x2_enc = cs.encrypt(plaintext=x2)
w2_enc = cs.encrypt(plaintext=w2)
x1w1_enc = x1_enc * w1_enc
x2w2_enc = x2_enc * w2_enc
sum_enc = x1w1_enc + x2w2_enc
sum_decrypted = cs.decrypt(sum_enc)
assert sum_decrypted == (x1 * w1 + x2 * w2)
# multiplication by constant
_5x1w1_enc = cs.decrypt(x1w1_enc * 5)
assert _5x1w1_enc == (5 * x1 * w1)
# unsupported homomorphic operations
with pytest.raises(
ValueError,
match="Boneh-Goh-Nissim only supports multiplication ciphertexts once!",
):
_ = x1w1_enc * w2_enc
logger.info(
f"✅ Boneh-God-Nissim linear regression test succeeded "
f"({security_level} bit ECC security level)"
f" in {time.time() - tic:.2f} seconds"
)
def test_cosine_similarity():
tic = time.time()
i1 = 5
i2 = 2
i3 = 8
# v2 = [1, 1, 2]
j1 = 1
j2 = 1
j3 = 2
i1_enc = cs.encrypt(i1)
i2_enc = cs.encrypt(i2)
i3_enc = cs.encrypt(i3)
j1_enc = cs.encrypt(j1)
j2_enc = cs.encrypt(j2)
j3_enc = cs.encrypt(j3)
# homomorphic operation
cosine_sim_enc = i1_enc * j1_enc + i2_enc * j2_enc + i3_enc * j3_enc
# proof of work
assert cs.decrypt(cosine_sim_enc) == i1 * j1 + i2 * j2 + i3 * j3
logger.info(
f"✅ Boneh-God-Nissim cosine similarity test succeeded "
f"({security_level} bit ECC security level)"
f" in {time.time() - tic:.2f} seconds"
)
def test_euclidean_distance():
tic = time.time()
# v1 = [5, 2, 3]
i1 = 5
i2 = 2
i3 = 8
# v2 = [1, 1, 2]
j1 = 1
j2 = 1
j3 = 2
i1_enc = cs.encrypt(i1)
i2_enc = cs.encrypt(i2)
i3_enc = cs.encrypt(i3)
j1_enc = cs.encrypt(-j1)
j2_enc = cs.encrypt(-j2)
j3_enc = cs.encrypt(-j3)
euclidean_sqrt_enc = (
(i1_enc + j1_enc) * (i1_enc + j1_enc)
+ (i2_enc + j2_enc) * (i2_enc + j2_enc)
+ (i3_enc + j3_enc) * (i3_enc + j3_enc)
)
assert (
cs.decrypt(euclidean_sqrt_enc)
== (i1 - j1) ** 2 + (i2 - j2) ** 2 + (i3 - j3) ** 2
)
logger.info(
f"✅ Boneh-God-Nissim euclidean distance test succeeded "
f"({security_level} bit ECC security level)"
f" in {time.time() - tic:.2f} seconds"
)
def test_api_with_predefined_keys():
keys = {
"private_key": {"q1": 1260048562698661, "q2": 1495813357973021},
"public_key": {
"curve": {
"a": 1,
"b": 0,
"p": 1477681217875020437035023206706703,
"G": (
404050258967758769169929337984186,
548422986186523785500578682099939,
),
"n": 1884797471779362802340590824881,
},
"G": (404050258967758769169929337984186, 548422986186523785500578682099939),
"u": (
496699107331579016081758964967239,
1209427529257066171815901459972102,
),
"h": (557434130026147587760748115479880, 109859910481881270030204038710204),
"l": 784,
},
}
bgn_cs = LightPHE(
algorithm_name="Boneh-Goh-Nissim",
keys=keys,
)
security_level = bgn_cs.cs.ec.n.bit_length()
m1 = 3
m2 = 2
c1 = bgn_cs.encrypt(plaintext=m1)
c2 = bgn_cs.encrypt(plaintext=m2)
# proof of decryption
assert bgn_cs.decrypt(c1) == m1
assert bgn_cs.decrypt(c2) == m2
# homomorphic addition
assert bgn_cs.decrypt(c1 + c2) == (m1 + m2) % bgn_cs.cs.plaintext_modulo
# homomorphic multiplication
c1_times_c2 = c1 * c2
assert bgn_cs.decrypt(c1_times_c2) == (m1 * m2) % bgn_cs.cs.plaintext_modulo
# scalar multiplication
k = 2
assert bgn_cs.decrypt(c1 * k) == (m1 * k) % bgn_cs.cs.plaintext_modulo
# unsupported homomorphic operations
with pytest.raises(ValueError):
_ = c1 & c2
with pytest.raises(ValueError):
_ = c1 ^ c2
# re-randomization
c1_prime = bgn_cs.cs.reencrypt(c1.value)
c2_prime = bgn_cs.cs.reencrypt(c2.value)
# assert c1.value != c1_prime
# assert c2.value != c2_prime
assert bgn_cs.cs.decrypt(c1_prime) == m1
assert bgn_cs.cs.decrypt(c2_prime) == m2
logger.info(
f"✅ Boneh-God-Nissim test succeeded ({security_level} bit ECC security level)"
)