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.
- {lightphe-0.0.17 → lightphe-0.0.18}/PKG-INFO +1 -1
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/__init__.py +9 -8
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/Benaloh.py +26 -10
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/GoldwasserMicali.py +5 -1
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/Homomorphic.py +5 -1
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/PKG-INFO +1 -1
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/SOURCES.txt +1 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/setup.py +1 -1
- lightphe-0.0.18/tests/test_large_keys.py +76 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/LICENSE +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/README.md +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/commons/__init__.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/commons/logger.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/commons/phe_utils.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/DamgardJurik.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/ElGamal.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/EllipticCurveElGamal.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/NaccacheStern.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/OkamotoUchiyama.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/Paillier.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/RSA.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/cryptosystems/__init__.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/Algorithm.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/Ciphertext.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/Tensor.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe/models/__init__.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/dependency_links.txt +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/requires.txt +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/lightphe.egg-info/top_level.txt +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/requirements.txt +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/setup.cfg +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/__init__.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_benaloh.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_ciphertexts.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_cloud.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_damgard.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_elgamal.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_ellipticcurveelgamal.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_exporting_keys.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_goldwasser.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_keys.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_naccache.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_okamoto.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_paillier.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_rsa.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_salary.py +0 -0
- {lightphe-0.0.17 → lightphe-0.0.18}/tests/test_tensors.py +0 -0
|
@@ -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.
|
|
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
|
|
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/
|
|
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__(
|
|
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.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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(
|
|
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
|
-
|
|
53
|
-
|
|
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)
|
|
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
|
-
|
|
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,
|
|
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
|
|
|
@@ -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.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|