81 lines
2.6 KiB
Python
81 lines
2.6 KiB
Python
# built-in dependencies
|
|
from typing import Union, Tuple, Optional
|
|
from decimal import Decimal, getcontext
|
|
|
|
# project dependencies
|
|
from lightphe.commons.logger import Logger
|
|
|
|
logger = Logger(module="lightphe/commons/phe_utils.py")
|
|
|
|
# pylint: disable=no-else-return, no-else-break
|
|
|
|
|
|
def normalize_input(value: Union[int, float], modulo: Union[int, str]) -> int:
|
|
"""
|
|
Normaliz given value to be in the range of modulo
|
|
Args:
|
|
value (int, float): the value to be normalized
|
|
modulo (int): the modulo value
|
|
Returns:
|
|
result (int, str): the normalized value
|
|
"""
|
|
if isinstance(value, int) and isinstance(modulo, str):
|
|
# elliptic curve elgamal & koblitz curves
|
|
result = value % int(modulo, 2)
|
|
elif isinstance(value, int) and isinstance(modulo, int):
|
|
if value > modulo:
|
|
logger.warn(
|
|
f"Value {value} is greater than modulo {modulo}. Normalizing it to be in the range of modulo."
|
|
)
|
|
result = value % modulo
|
|
elif isinstance(value, float) and value >= 0:
|
|
dividend, divisor = fractionize(value=value, modulo=modulo)
|
|
logger.debug(f"{dividend}*{divisor}^-1 mod {modulo}")
|
|
result = (dividend * pow(divisor, -1, modulo)) % modulo
|
|
elif isinstance(value, float) and value < 0:
|
|
# TODO: think and implement this later
|
|
raise ValueError("Case constant float and negative not implemented yet")
|
|
else:
|
|
raise ValueError(f"Unimplemented case for constant type {type(value)}")
|
|
|
|
return result
|
|
|
|
|
|
def fractionize(
|
|
value: float, modulo: int, precision: Optional[int] = None
|
|
) -> Tuple[int, int]:
|
|
getcontext().prec = 50
|
|
|
|
if precision is None:
|
|
decimal_places = len(str(value).split(".")[1])
|
|
scaling_factor = 10**decimal_places
|
|
else:
|
|
scaling_factor = 10**precision
|
|
|
|
while True:
|
|
integer_value = int(Decimal(value) * Decimal(scaling_factor)) % modulo
|
|
|
|
if precision is None:
|
|
break
|
|
|
|
if scaling_factor > 10**precision:
|
|
# If scaling factor is too large, discard excess part of integer value
|
|
integer_value = int(
|
|
integer_value / (10 ** (scaling_factor - 10**precision))
|
|
)
|
|
break
|
|
elif scaling_factor < 10 ** (precision - 1):
|
|
# If scaling factor is too small, multiply dividend and divisor 10 times
|
|
value *= 10
|
|
scaling_factor *= 10
|
|
else:
|
|
break
|
|
|
|
logger.debug(f"{integer_value}*{scaling_factor}^-1 mod {modulo}")
|
|
return integer_value, scaling_factor
|
|
|
|
|
|
def solve_dlp():
|
|
# TODO: implement this later
|
|
pass
|