lightphe 0.0.17__tar.gz → 0.0.18__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {lightphe-0.0.17 → lightphe-0.0.18}/PKG-INFO +1 -1
  2. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/__init__.py +9 -8
  3. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/Benaloh.py +26 -10
  4. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/GoldwasserMicali.py +5 -1
  5. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/Homomorphic.py +5 -1
  6. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/PKG-INFO +1 -1
  7. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/SOURCES.txt +1 -0
  8. {lightphe-0.0.17 → lightphe-0.0.18}/setup.py +1 -1
  9. lightphe-0.0.18/tests/test_large_keys.py +76 -0
  10. {lightphe-0.0.17 → lightphe-0.0.18}/LICENSE +0 -0
  11. {lightphe-0.0.17 → lightphe-0.0.18}/README.md +0 -0
  12. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/commons/__init__.py +0 -0
  13. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/commons/logger.py +0 -0
  14. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/commons/phe_utils.py +0 -0
  15. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/DamgardJurik.py +0 -0
  16. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/ElGamal.py +0 -0
  17. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/EllipticCurveElGamal.py +0 -0
  18. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/NaccacheStern.py +0 -0
  19. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/OkamotoUchiyama.py +0 -0
  20. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/Paillier.py +0 -0
  21. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/RSA.py +0 -0
  22. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/__init__.py +0 -0
  23. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/Algorithm.py +0 -0
  24. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/Ciphertext.py +0 -0
  25. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/Tensor.py +0 -0
  26. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/__init__.py +0 -0
  27. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/dependency_links.txt +0 -0
  28. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/requires.txt +0 -0
  29. {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/top_level.txt +0 -0
  30. {lightphe-0.0.17 → lightphe-0.0.18}/requirements.txt +0 -0
  31. {lightphe-0.0.17 → lightphe-0.0.18}/setup.cfg +0 -0
  32. {lightphe-0.0.17 → lightphe-0.0.18}/tests/__init__.py +0 -0
  33. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_benaloh.py +0 -0
  34. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_ciphertexts.py +0 -0
  35. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_cloud.py +0 -0
  36. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_damgard.py +0 -0
  37. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_elgamal.py +0 -0
  38. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_ellipticcurveelgamal.py +0 -0
  39. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_exporting_keys.py +0 -0
  40. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_goldwasser.py +0 -0
  41. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_keys.py +0 -0
  42. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_naccache.py +0 -0
  43. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_okamoto.py +0 -0
  44. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_paillier.py +0 -0
  45. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_rsa.py +0 -0
  46. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_salary.py +0 -0
  47. {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_tensors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightphe
3
- Version: 0.0.17
3
+ Version: 0.0.18
4
4
  Summary: A Lightweight Partially Homomorphic Encryption Library for Python
5
5
  Home-page: https://github.com/serengil/LightPHE
6
6
  Author: Sefik Ilkin Serengil
@@ -9,10 +9,6 @@ import copy
9
9
 
10
10
  # 3rd party dependencies
11
11
  from tqdm import tqdm
12
- from lightecc.interfaces.elliptic_curve import EllipticCurvePoint
13
- from lightecc.forms.weierstrass import Weierstrass
14
- from lightecc.forms.edwards import TwistedEdwards
15
- from lightecc.forms.koblitz import Koblitz
16
12
 
17
13
  # project dependencies
18
14
  from lightphe.models.Homomorphic import Homomorphic
@@ -38,7 +34,7 @@ from lightphe.cryptosystems.EllipticCurveElGamal import EllipticCurveElGamal
38
34
 
39
35
  logger = Logger(module="lightphe/__init__.py")
40
36
 
41
- VERSION = "0.0.17"
37
+ VERSION = "0.0.18"
42
38
 
43
39
 
44
40
  class LightPHE:
@@ -53,6 +49,7 @@ class LightPHE:
53
49
  precision: int = 5,
54
50
  form: Optional[str] = None,
55
51
  curve: Optional[str] = None,
52
+ plaintext_limit: Optional[int] = None,
56
53
  ):
57
54
  """
58
55
  Build LightPHE class
@@ -61,7 +58,7 @@ class LightPHE:
61
58
  | Paillier | Damgard-Jurik | Okamoto-Uchiyama | Benaloh | Naccache-Stern
62
59
  | Goldwasser-Micali
63
60
  keys (dict): optional private-public key pair
64
- key_file (str): if keys are exported, you can load them into cryptosystem
61
+ key_file (str): if keys were exported already, you can load them into cryptosystem
65
62
  key_size (int): key size in bits
66
63
  precision (int): precision for homomorphic operations on tensors
67
64
  form (str): specifies the form of the elliptic curve.
@@ -73,8 +70,10 @@ class LightPHE:
73
70
  - e.g. secp256k1 for weierstrass form
74
71
  - e.g. k-409 for koblitz form
75
72
  List of all available curves:
76
- github.com/serengil/LightPHE/blob/master/lightphe/elliptic_curve_forms/README.md
73
+ https://github.com/serengil/LightECC?tab=readme-ov-file#supported-curves
77
74
  This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
75
+ plaintext_limit (int, optional): Upper bound for plaintext values.
76
+ This parameter is only used if `algorithm_name` is 'Benaloh'.
78
77
  """
79
78
  self.algorithm_name = algorithm_name
80
79
  self.precision = precision
@@ -90,6 +89,7 @@ class LightPHE:
90
89
  key_size=key_size,
91
90
  form=form,
92
91
  curve=curve,
92
+ plaintext_limit=plaintext_limit,
93
93
  )
94
94
 
95
95
  def __build_cryptosystem(
@@ -99,6 +99,7 @@ class LightPHE:
99
99
  key_size: Optional[int] = None,
100
100
  form: Optional[str] = None,
101
101
  curve: Optional[str] = None,
102
+ plaintext_limit: Optional[int] = None,
102
103
  ) -> Union[
103
104
  RSA,
104
105
  ElGamal,
@@ -148,7 +149,7 @@ class LightPHE:
148
149
  elif algorithm_name == Algorithm.OkamotoUchiyama:
149
150
  cs = OkamotoUchiyama(keys=keys, key_size=key_size)
150
151
  elif algorithm_name == Algorithm.Benaloh:
151
- cs = Benaloh(keys=keys, key_size=key_size)
152
+ cs = Benaloh(keys=keys, key_size=key_size, plaintext_limit=plaintext_limit)
152
153
  elif algorithm_name == Algorithm.NaccacheStern:
153
154
  cs = NaccacheStern(keys=keys, key_size=key_size)
154
155
  elif algorithm_name == Algorithm.GoldwasserMicali:
@@ -15,19 +15,33 @@ logger = Logger(module="lightphe/cryptosystems/Benaloh.py")
15
15
 
16
16
 
17
17
  class Benaloh(Homomorphic):
18
- def __init__(self, keys: Optional[dict] = None, key_size: Optional[int] = None):
18
+ def __init__(
19
+ self,
20
+ keys: Optional[dict] = None,
21
+ key_size: Optional[int] = None,
22
+ plaintext_limit: Optional[int] = None,
23
+ ):
19
24
  """
20
25
  Args:
21
26
  keys (dict): private - public key pair.
22
27
  set this to None if you want to generate random keys.
23
- key_size (int): key size in bits. default is less than other cryptosystems
24
- because decryption of Benaloh requires to solve DLP :/
25
- """
26
- self.keys = keys or self.generate_keys(key_size or 1024)
28
+ key_size (int): key size in bits.
29
+ plaintext_limit (int, optional): Upper bound for plaintext values.
30
+ If provided, r is set to the next prime greater than this value;
31
+ otherwise, r is chosen randomly from a default range.
32
+ """
33
+ self.keys = keys or self.generate_keys(
34
+ key_size=key_size or 1024, plaintext_limit=plaintext_limit
35
+ )
27
36
  self.plaintext_modulo = self.keys["public_key"]["r"]
28
37
  self.ciphertext_modulo = self.keys["public_key"]["n"]
29
38
 
30
- def generate_keys(self, key_size: int, max_tries: int = 10000) -> dict:
39
+ def generate_keys(
40
+ self,
41
+ key_size: int,
42
+ max_tries: int = 10000,
43
+ plaintext_limit: Optional[int] = None,
44
+ ) -> dict:
31
45
  """
32
46
  Generate public and private keys of Paillier cryptosystem
33
47
  Args:
@@ -49,8 +63,10 @@ class Benaloh(Homomorphic):
49
63
  phi = (p - 1) * (q - 1)
50
64
 
51
65
  # generate block size r
52
- # TODO: consider to get limit from user
53
- r = sympy.randprime(1000, 2000)
66
+ if plaintext_limit is None:
67
+ r = sympy.randprime(1000, 2000)
68
+ else:
69
+ r = sympy.nextprime(plaintext_limit)
54
70
  # plaintexts will be allowed in [0, r-1]
55
71
 
56
72
  # block size r checks
@@ -58,7 +74,7 @@ class Benaloh(Homomorphic):
58
74
  # r should divide p-1 without remainder
59
75
  (p - 1) % r == 0
60
76
  # r and (p - 1) / r must be coprimes
61
- and gcd(r, int((p - 1) / r)) == 1
77
+ and gcd(r, int((p - 1) // r)) == 1
62
78
  # r and q-1 must be coprimes
63
79
  and gcd(r, q - 1) == 1
64
80
  ):
@@ -86,7 +102,7 @@ class Benaloh(Homomorphic):
86
102
  else:
87
103
  raise RuntimeError(
88
104
  f"Failed to generate Benaloh keys after {max_tries} attempts."
89
- "Please try to rerun."
105
+ f"Please try to rerun or consider to decrese {plaintext_limit=}."
90
106
  )
91
107
 
92
108
  keys["public_key"]["y"] = y
@@ -33,7 +33,11 @@ class GoldwasserMicali(Homomorphic):
33
33
 
34
34
  self.keys = keys or self.generate_keys(key_size or 1024)
35
35
  self.ciphertext_modulo = self.keys["public_key"]["n"]
36
- # TODO: not sure about the plaintext modulo
36
+
37
+ # Plaintext can be any integer (even larger than n) because it is internally
38
+ # encrypted bit by bit. Internally, each bit uses modulo 2, but LightPHE expects
39
+ # integers, not bits. The original integer can be fully restored after decryption
40
+ # even if it is larger than n.
37
41
  self.plaintext_modulo = self.keys["public_key"]["n"]
38
42
 
39
43
  def generate_keys(self, key_size: int, max_tries: int = 10000) -> dict:
@@ -15,7 +15,11 @@ class Homomorphic(ABC):
15
15
 
16
16
  @abstractmethod
17
17
  def generate_keys(
18
- self, key_size: int, s: Optional[int] = None, max_retries: Optional[int] = None
18
+ self,
19
+ key_size: int,
20
+ s: Optional[int] = None,
21
+ max_retries: Optional[int] = None,
22
+ plaintext_limit: Optional[int] = None,
19
23
  ) -> dict:
20
24
  pass
21
25
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightphe
3
- Version: 0.0.17
3
+ Version: 0.0.18
4
4
  Summary: A Lightweight Partially Homomorphic Encryption Library for Python
5
5
  Home-page: https://github.com/serengil/LightPHE
6
6
  Author: Sefik Ilkin Serengil
@@ -36,6 +36,7 @@ tests/test_ellipticcurveelgamal.py
36
36
  tests/test_exporting_keys.py
37
37
  tests/test_goldwasser.py
38
38
  tests/test_keys.py
39
+ tests/test_large_keys.py
39
40
  tests/test_naccache.py
40
41
  tests/test_okamoto.py
41
42
  tests/test_paillier.py
@@ -8,7 +8,7 @@ with open("requirements.txt", "r", encoding="utf-8") as f:
8
8
 
9
9
  setuptools.setup(
10
10
  name="lightphe",
11
- version="0.0.17",
11
+ version="0.0.18",
12
12
  author="Sefik Ilkin Serengil",
13
13
  author_email="serengil@gmail.com",
14
14
  description="A Lightweight Partially Homomorphic Encryption Library for Python",
@@ -0,0 +1,76 @@
1
+ import time
2
+ import unittest
3
+
4
+ from lightphe import LightPHE
5
+ from lightphe.commons.logger import Logger
6
+
7
+ logger = Logger(module="tests/test_large_keys.py")
8
+
9
+
10
+ @unittest.skip("This is an experimental test for large key sizes.")
11
+ def test_large_keys():
12
+ """
13
+ Use this test to see no problem for larger keys.
14
+
15
+ Algorithm| Key Size | Key Generation Time | Encryption Time | Homomorphic Time | Decryption Time
16
+ --- | --- | --- | --- | --- | ---
17
+ Goldwasser-Micali | 1024 | 0.01 | 0.00 | 0.00 |0.00
18
+ Goldwasser-Micali | 2048 | 0.08 | 0.00 | 0.00 |0.03
19
+ Goldwasser-Micali | 3072 | 0.45 | 0.00 | 0.00 |0.08
20
+ Goldwasser-Micali | 7680 | 11.30 | 0.00 | 0.00 |1.21
21
+
22
+ Benaloh | 1024 | 4.91 | 0.00 | 0.00 |0.01
23
+ Benaloh | 2048 | 140.54 | 0.00 | 0.00 |0.03
24
+ Benaloh | 3072 | 439.46 | 0.00 | 0.00 |0.08
25
+ """
26
+ algorithms = [
27
+ # "Naccache-Stern",
28
+ # "Goldwasser-Micali",
29
+ "Benaloh",
30
+ ]
31
+ # key_sizes = [1024, 2048, 3072, 7680]
32
+ key_sizes = [3072, 7680]
33
+
34
+ for key_size in key_sizes:
35
+ for algorithm_name in algorithms:
36
+ logger.debug(f"Testing {algorithm_name} with key size {key_size} bits")
37
+ tic = time.time()
38
+ cs = LightPHE(algorithm_name=algorithm_name, key_size=key_size)
39
+ toc = time.time()
40
+ keygen_time = toc - tic
41
+
42
+ m1 = 17
43
+ m2 = 23
44
+
45
+ tic = time.time()
46
+ c1 = cs.encrypt(m1)
47
+ c2 = cs.encrypt(m2)
48
+ toc = time.time()
49
+ encryption_time = toc - tic
50
+
51
+ if algorithm_name in ["Naccache-Stern", "Benaloh"]:
52
+ tic = time.time()
53
+ c3 = c1 + c2
54
+ toc = time.time()
55
+ homomorphic_time = toc - tic
56
+
57
+ tic = time.time()
58
+ result = cs.decrypt(c3)
59
+ toc = time.time()
60
+ decryption_time = toc - tic
61
+ assert result == m1 + m2
62
+ elif algorithm_name in ["Goldwasser-Micali"]:
63
+ tic = time.time()
64
+ c3 = c1 ^ c2
65
+ toc = time.time()
66
+ homomorphic_time = toc - tic
67
+
68
+ tic = time.time()
69
+ result = cs.decrypt(c3)
70
+ toc = time.time()
71
+ decryption_time = toc - tic
72
+ assert result == m1 ^ m2
73
+
74
+ logger.info(
75
+ f"{algorithm_name} | {key_size} | {keygen_time:.2f} | {encryption_time:.2f} | {homomorphic_time:.2f} |{decryption_time:.2f}"
76
+ )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes