163 lines
6.2 KiB
Python
163 lines
6.2 KiB
Python
from typing import Union, Optional
|
|
from lightphe.models.Homomorphic import Homomorphic
|
|
from lightphe.models.Algorithm import Algorithm
|
|
from lightphe.cryptosystems.RSA import RSA
|
|
from lightphe.cryptosystems.ElGamal import ElGamal
|
|
from lightphe.cryptosystems.Paillier import Paillier
|
|
from lightphe.cryptosystems.DamgardJurik import DamgardJurik
|
|
from lightphe.cryptosystems.OkamotoUchiyama import OkamotoUchiyama
|
|
from lightphe.cryptosystems.Benaloh import Benaloh
|
|
from lightphe.cryptosystems.NaccacheStern import NaccacheStern
|
|
from lightphe.cryptosystems.GoldwasserMicali import GoldwasserMicali
|
|
from lightphe.cryptosystems.EllipticCurveElGamal import EllipticCurveElGamal
|
|
from lightphe.cryptosystems.SanderYoungYung import SanderYoungYung
|
|
from lightphe.cryptosystems.BonehGohNissim import BonehGohNissim
|
|
from lightphe.commons import phe_utils
|
|
from lightphe.commons.logger import Logger
|
|
|
|
logger = Logger(module="lightphe/models/Ciphertext.py")
|
|
|
|
# pylint: disable=too-few-public-methods, no-else-return
|
|
|
|
|
|
class Ciphertext:
|
|
def __init__(
|
|
self,
|
|
algorithm_name: str,
|
|
keys: dict,
|
|
value: Union[int, tuple, list],
|
|
form: Optional[str] = None,
|
|
curve: Optional[str] = None,
|
|
):
|
|
self.algorithm_name = algorithm_name
|
|
self.keys = keys
|
|
self.value = value
|
|
|
|
if algorithm_name == Algorithm.RSA:
|
|
cs = RSA(keys=keys)
|
|
elif algorithm_name == Algorithm.ElGamal:
|
|
cs = ElGamal(keys=keys)
|
|
elif algorithm_name == Algorithm.ExponentialElGamal:
|
|
cs = ElGamal(keys=keys, exponential=True)
|
|
elif algorithm_name == Algorithm.EllipticCurveElGamal:
|
|
cs = EllipticCurveElGamal(keys=keys, form=form, curve=curve)
|
|
elif algorithm_name == Algorithm.Paillier:
|
|
cs = Paillier(keys=keys)
|
|
elif algorithm_name == Algorithm.DamgardJurik:
|
|
cs = DamgardJurik(keys=keys)
|
|
elif algorithm_name == Algorithm.OkamotoUchiyama:
|
|
cs = OkamotoUchiyama(keys=keys)
|
|
elif algorithm_name == Algorithm.Benaloh:
|
|
cs = Benaloh(keys=keys)
|
|
elif algorithm_name == Algorithm.NaccacheStern:
|
|
cs = NaccacheStern(keys=keys)
|
|
elif algorithm_name == Algorithm.GoldwasserMicali:
|
|
cs = GoldwasserMicali(keys=keys)
|
|
elif algorithm_name == Algorithm.SanderYoungYung:
|
|
cs = SanderYoungYung(keys=keys)
|
|
elif algorithm_name == Algorithm.BonehGohNissim:
|
|
cs = BonehGohNissim(keys=keys)
|
|
else:
|
|
raise ValueError(f"unimplemented algorithm - {algorithm_name}")
|
|
|
|
self.cs: Homomorphic = cs
|
|
|
|
def __str__(self) -> str:
|
|
return f"Ciphertext({self.value})"
|
|
|
|
def __repr__(self) -> str:
|
|
return f"Ciphertext({self.value})"
|
|
|
|
def __add__(self, other: "Ciphertext") -> "Ciphertext":
|
|
"""
|
|
Perform homomorphic addition methods
|
|
Args:
|
|
other (Ciperhtext): some other ciphertext
|
|
Returns:
|
|
ciphertext (Ciphertext): homomorphic addition of ciphertext
|
|
"""
|
|
if self.cs.keys.get("public_key") is None:
|
|
raise ValueError("You must have public key to perform homomorphic addition")
|
|
|
|
result = self.cs.add(ciphertext1=self.value, ciphertext2=other.value)
|
|
return Ciphertext(
|
|
algorithm_name=self.algorithm_name, keys=self.keys, value=result
|
|
)
|
|
|
|
def __mul__(self, other: Union["Ciphertext", int, float]) -> "Ciphertext":
|
|
"""
|
|
Perform homomorphic multiplication or multiply a ciphertext with a known constant
|
|
Args:
|
|
other (int | float | Ciphertext): a known plain constant of some other ciphertext
|
|
Returns
|
|
homomorphic multiplication of ciphertexts | scalar multiplication of ciphertext
|
|
"""
|
|
if self.cs.keys.get("public_key") is None:
|
|
raise ValueError(
|
|
"You must have public key to perform homomorphic multiplication"
|
|
)
|
|
|
|
if isinstance(other, Ciphertext):
|
|
# Handle multiplication with another EncryptedObject
|
|
result = self.cs.multiply(ciphertext1=self.value, ciphertext2=other.value)
|
|
elif isinstance(other, int):
|
|
result = self.cs.multiply_by_constant(ciphertext=self.value, constant=other)
|
|
elif isinstance(other, float):
|
|
constant = phe_utils.normalize_input(
|
|
value=other, modulo=self.cs.plaintext_modulo
|
|
)
|
|
result = self.cs.multiply_by_constant(
|
|
ciphertext=self.value, constant=constant
|
|
)
|
|
else:
|
|
raise ValueError(
|
|
f"A ciphertext can be multiplied by either ciphertext itself or a scalar but it is {type(other)}"
|
|
)
|
|
return Ciphertext(
|
|
algorithm_name=self.algorithm_name, keys=self.keys, value=result
|
|
)
|
|
|
|
def __rmul__(self, constant: Union[int, float]) -> "Ciphertext":
|
|
"""
|
|
Multiply a ciphertext with a known constant
|
|
Args:
|
|
constant (int | float): a known plain constant
|
|
Returns
|
|
scalar multiplication of ciphertext
|
|
"""
|
|
return self.__mul__(other=constant)
|
|
|
|
def __xor__(self, other: "Ciphertext") -> "Ciphertext":
|
|
"""
|
|
Perform homomorphic xor
|
|
Args:
|
|
other (| Ciphertext): some other ciphertext
|
|
Returns
|
|
homomorphic xor of ciphertexts
|
|
"""
|
|
if self.cs.keys.get("public_key") is None:
|
|
raise ValueError("You must have public key to perform homomorphic xor")
|
|
|
|
result = self.cs.xor(ciphertext1=self.value, ciphertext2=other.value)
|
|
return Ciphertext(
|
|
algorithm_name=self.algorithm_name, keys=self.keys, value=result
|
|
)
|
|
|
|
def __and__(self, other: "Ciphertext") -> "Ciphertext":
|
|
"""
|
|
Perform homomorphic and
|
|
Args:
|
|
other (| Ciphertext): some other ciphertext
|
|
Returns
|
|
homomorphic and of ciphertexts
|
|
"""
|
|
if self.cs.keys.get("public_key") is None:
|
|
raise ValueError("You must have public key to perform homomorphic and")
|
|
|
|
result = self.cs.homomorphic_and(
|
|
ciphertext1=self.value, ciphertext2=other.value
|
|
)
|
|
return Ciphertext(
|
|
algorithm_name=self.algorithm_name, keys=self.keys, value=result
|
|
)
|