diff --git a/lightphe/__init__.py b/lightphe/__init__.py index b665f7b..f55edef 100644 --- a/lightphe/__init__.py +++ b/lightphe/__init__.py @@ -161,10 +161,15 @@ def __encrypt_tensors(self, tensor: list) -> EncryptedTensor: dividend_encrypted = self.cs.encrypt( plaintext=(m % self.cs.plaintext_modulo) * pow(10, self.precision) ) + abs_dividend_encrypted = self.cs.encrypt( + plaintext=(abs(m) % self.cs.plaintext_modulo) * pow(10, self.precision) + ) divisor_encrypted = self.cs.encrypt(plaintext=pow(10, self.precision)) c = Fraction( dividend=dividend_encrypted, divisor=divisor_encrypted, + abs_dividend=abs_dividend_encrypted, + sign=1 if m >= 0 else -1, ) elif isinstance(m, float): dividend, divisor = phe_utils.fractionize( @@ -172,13 +177,19 @@ def __encrypt_tensors(self, tensor: list) -> EncryptedTensor: modulo=self.cs.plaintext_modulo, precision=self.precision, ) - # print(f"{m} mod n = {(m % self.cs.plaintext_modulo)} = {dividend} / {divisor}") - # print(f" = {dividend / divisor}") + abs_dividend, _ = phe_utils.fractionize( + value=(abs(m) % self.cs.plaintext_modulo), + modulo=self.cs.plaintext_modulo, + precision=self.precision, + ) dividend_encrypted = self.cs.encrypt(plaintext=dividend) + abs_dividend_encrypted = self.cs.encrypt(plaintext=abs_dividend) divisor_encrypted = self.cs.encrypt(plaintext=divisor) c = Fraction( dividend=dividend_encrypted, divisor=divisor_encrypted, + abs_dividend=abs_dividend_encrypted, + sign=1 if m >= 0 else -1, ) else: raise ValueError(f"unimplemented type - {type(m)}") @@ -198,9 +209,14 @@ def __decrypt_tensors(self, encrypted_tensor: EncryptedTensor) -> Union[List[int if isinstance(c, Fraction) is False: raise ValueError("Ciphertext items must be type of Fraction") + sign = c.sign dividend = self.cs.decrypt(ciphertext=c.dividend) divisor = self.cs.decrypt(ciphertext=c.divisor) - m = dividend / divisor + if c.abs_dividend is not None and sign == -1: + abs_dividend = self.cs.decrypt(ciphertext=c.abs_dividend) + m = -1 * abs_dividend / divisor + else: + m = dividend / divisor plain_tensor.append(m) return plain_tensor diff --git a/lightphe/models/Tensor.py b/lightphe/models/Tensor.py index 0b3d075..151f2ca 100644 --- a/lightphe/models/Tensor.py +++ b/lightphe/models/Tensor.py @@ -1,4 +1,4 @@ -from typing import Union, List +from typing import Union, List, Optional from lightphe.models.Homomorphic import Homomorphic from lightphe.commons import phe_utils @@ -13,9 +13,13 @@ def __init__( self, dividend: Union[int, tuple, list], divisor: Union[int, tuple, list], + sign: int = 1, + abs_dividend: Optional[Union[int, tuple, list]] = None, ): self.dividend = dividend self.divisor = divisor + self.sign = sign + self.abs_dividend = abs_dividend def __str__(self): """ diff --git a/tests/test_tensors.py b/tests/test_tensors.py index 7e13385..0a8c2eb 100644 --- a/tests/test_tensors.py +++ b/tests/test_tensors.py @@ -31,13 +31,7 @@ def test_tensor_encryption(): for i, decrypted_tensor in enumerate(decrypted_tensors): expected_tensor = tensor[i] - if expected_tensor >= 0: - assert abs(expected_tensor - decrypted_tensor) <= THRESHOLD - else: - expected_tensor_int = convert_negative_float_to_int( - expected_tensor, cs.cs.plaintext_modulo - ) - assert abs(expected_tensor_int - decrypted_tensor) <= THRESHOLD + assert abs(expected_tensor - decrypted_tensor) <= THRESHOLD logger.info("✅ Tensor tests succeeded") @@ -45,8 +39,8 @@ def test_tensor_encryption(): def test_homomorphic_multiplication(): cs = LightPHE(algorithm_name="RSA") - t1 = [1.005, 2.05, 3.5, 3.1, 4] - t2 = [5, 6.2, 7.002, 7.1, 8.02] + t1 = [1.005, 2.05, -3.5, 3.1, -4] + t2 = [5, 6.2, -7.002, -7.1, 8.02] c1: EncryptedTensor = cs.encrypt(t1) c2: EncryptedTensor = cs.encrypt(t2) @@ -56,7 +50,7 @@ def test_homomorphic_multiplication(): restored_tensors = cs.decrypt(c3) for i, restored_tensor in enumerate(restored_tensors): - if (t1[i] > 0 and t2[i] > 0) or (t1[i] < 0 and t2[i] < 0): + if t1[i] > 0 and t2[i] > 0: assert abs((t1[i] * t2[i]) - restored_tensor) < THRESHOLD with pytest.raises(ValueError): @@ -122,8 +116,8 @@ def test_homomorphic_multiply_with_float_constant(): def test_homomorphic_addition(): cs = LightPHE(algorithm_name="Paillier", key_size=30) - t1 = [1.005, 2.05, 3.5, 4, 3.5] - t2 = [5, 6.2, 7.002, 8.02, 4.5] + t1 = [1.005, 2.05, 3.6, -4, -3.5] + t2 = [5, 6.2, -7.5, 8.02, -4.5] c1: EncryptedTensor = cs.encrypt(t1) c2: EncryptedTensor = cs.encrypt(t2) @@ -133,7 +127,11 @@ def test_homomorphic_addition(): restored_tensors = cs.decrypt(c3) for i, restored_tensor in enumerate(restored_tensors): - assert abs((t1[i] + t2[i]) - restored_tensor) < THRESHOLD + if t1[i] + t2[i] >= 0: + assert abs((t1[i] + t2[i]) - restored_tensor) < THRESHOLD + else: + expected = convert_negative_float_to_int(t1[i] + t2[i], cs.cs.plaintext_modulo) + assert abs(expected - restored_tensor) < THRESHOLD * 2 with pytest.raises(ValueError): _ = c1 * c2