lightphe 0.0.2__py3-none-any.whl → 0.0.3__py3-none-any.whl
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/__init__.py +11 -0
- lightphe/models/Ciphertext.py +4 -1
- {lightphe-0.0.2.dist-info → lightphe-0.0.3.dist-info}/METADATA +29 -9
- {lightphe-0.0.2.dist-info → lightphe-0.0.3.dist-info}/RECORD +8 -7
- tests/test_cloud.py +44 -0
- {lightphe-0.0.2.dist-info → lightphe-0.0.3.dist-info}/LICENSE +0 -0
- {lightphe-0.0.2.dist-info → lightphe-0.0.3.dist-info}/WHEEL +0 -0
- {lightphe-0.0.2.dist-info → lightphe-0.0.3.dist-info}/top_level.txt +0 -0
lightphe/__init__.py
CHANGED
|
@@ -217,3 +217,14 @@ class LightPHE:
|
|
|
217
217
|
else:
|
|
218
218
|
raise ValueError(f"unimplemented algorithm - {algorithm_name}")
|
|
219
219
|
return key_size
|
|
220
|
+
|
|
221
|
+
def create_ciphertext_obj(self, ciphertext: Union[int, tuple, list]) -> Ciphertext:
|
|
222
|
+
"""
|
|
223
|
+
Ciphertext objects have keys in addition ciphertext itself to perform
|
|
224
|
+
homomorphic operations.
|
|
225
|
+
Args:
|
|
226
|
+
ciphertext (int or tuple or list): ciphertext content
|
|
227
|
+
Returns:
|
|
228
|
+
Ciphertext
|
|
229
|
+
"""
|
|
230
|
+
return Ciphertext(algorithm_name=self.algorithm_name, keys=self.cs.keys, value=ciphertext)
|
lightphe/models/Ciphertext.py
CHANGED
|
@@ -49,7 +49,10 @@ class Ciphertext:
|
|
|
49
49
|
self.cs: Homomorphic = cs
|
|
50
50
|
|
|
51
51
|
def __str__(self) -> str:
|
|
52
|
-
return
|
|
52
|
+
return f"Ciphertext({self.value})"
|
|
53
|
+
|
|
54
|
+
def __repr__(self) -> str:
|
|
55
|
+
return f"Ciphertext({self.value})"
|
|
53
56
|
|
|
54
57
|
def __add__(self, other: "Ciphertext") -> "Ciphertext":
|
|
55
58
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lightphe
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
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
|
|
@@ -37,7 +37,15 @@ Requires-Dist: pytest (==7.1.2)
|
|
|
37
37
|
|
|
38
38
|
LightPHE is a lightweight partially homomorphic encryption library for python. It is a hybrid homomoprhic encryption library wrapping many schemes such as [`RSA`](https://sefiks.com/2023/03/06/a-step-by-step-partially-homomorphic-encryption-example-with-rsa-in-python/), [`ElGamal`](https://sefiks.com/2023/03/27/a-step-by-step-partially-homomorphic-encryption-example-with-elgamal-in-python/), [`Exponential ElGamal`](https://sefiks.com/2023/03/27/a-step-by-step-partially-homomorphic-encryption-example-with-elgamal-in-python/), [`Elliptic Curve ElGamal`](https://sefiks.com/2018/08/21/elliptic-curve-elgamal-encryption/), [`Paillier`](https://sefiks.com/2023/04/03/a-step-by-step-partially-homomorphic-encryption-example-with-paillier-in-python/), [`Damgard-Jurik`](https://sefiks.com/2023/10/20/a-step-by-step-partially-homomorphic-encryption-example-with-damgard-jurik-in-python/), [`Okamoto–Uchiyama`](https://sefiks.com/2023/10/20/a-step-by-step-partially-homomorphic-encryption-example-with-okamoto-uchiyama-in-python/), [`Benaloh`](https://sefiks.com/2023/10/06/a-step-by-step-partially-homomorphic-encryption-example-with-benaloh-in-python-from-scratch/), [`Naccache–Stern`](https://sefiks.com/2023/10/26/a-step-by-step-partially-homomorphic-encryption-example-with-naccache-stern-in-python/), [`Goldwasser–Micali`](https://sefiks.com/2023/10/27/a-step-by-step-partially-homomorphic-encryption-example-with-goldwasser-micali-in-python/).
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
# Partially vs Fully Homomorphic Encryption
|
|
41
|
+
|
|
42
|
+
Even though fully homomorphic encryption (FHE) has become available in recent times, but when considering the trade-offs, LightPHE emerges as a more efficient and practical choice. If your specific task doesn't demand the full homomorphic capabilities, opting for partial homomorphism with LightPHE is the logical decision.
|
|
43
|
+
|
|
44
|
+
- 🏎️ Notably faster
|
|
45
|
+
- 💻 Demands fewer computational resources
|
|
46
|
+
- 📏 Generating smaller ciphertexts
|
|
47
|
+
- 🧠 Well-suited for memory-constrained environments
|
|
48
|
+
- ⚖️ Strikes a favorable balance for practical use cases
|
|
41
49
|
|
|
42
50
|
# Installation [](https://pypi.org/project/lightphe/)
|
|
43
51
|
|
|
@@ -120,18 +128,30 @@ m2 = 23
|
|
|
120
128
|
c1 = cs.encrypt(m1)
|
|
121
129
|
c2 = cs.encrypt(m2)
|
|
122
130
|
|
|
123
|
-
#
|
|
124
|
-
|
|
131
|
+
# homomorphic addition - private key is not required!
|
|
132
|
+
c3 = c1 + c2
|
|
133
|
+
|
|
134
|
+
# proof of work
|
|
135
|
+
assert cs.decrypt(c3) == m1 + m2
|
|
125
136
|
```
|
|
126
137
|
|
|
127
|
-
|
|
138
|
+
⚡ Notice that once can perform `c1 + c2` here without holding private key. However, just the data owner with private key can perform encryption and decryption. This is the basic definition of homomorphic encryption.
|
|
139
|
+
|
|
140
|
+
Besides, Paillier is supporting multiplying ciphertexts by a known plain constant. Simply put, decryption of scalar multiplication of ciphertext is equivalent to that constant times plaintext as well.
|
|
128
141
|
|
|
129
142
|
```python
|
|
130
|
-
#
|
|
143
|
+
# increasing something 5%
|
|
131
144
|
k = 1.05
|
|
132
|
-
|
|
145
|
+
|
|
146
|
+
# scalar multiplication - private key is not required!
|
|
147
|
+
c4 = k * c1
|
|
148
|
+
|
|
149
|
+
# proof of work
|
|
150
|
+
assert cs.decrypt(c4) == k * m1
|
|
133
151
|
```
|
|
134
152
|
|
|
153
|
+
⚡ Herein, `k * c1` operation can be performed by anyone without holding private key.
|
|
154
|
+
|
|
135
155
|
Similar to the most of additively homomorphic algorithms, Paillier lets you to regenerate ciphertext while you are not breaking its plaintext restoration. You may consider to do this re-generation many times to have stronger ciphertexts.
|
|
136
156
|
|
|
137
157
|
```python
|
|
@@ -144,11 +164,11 @@ assert cs.decrypt(c1) == m1
|
|
|
144
164
|
Finally, if you try to perform an operation that algorithm does not support, then an exception will be thrown. For instance, Paillier is not homomorphic with respect to the multiplication or xor. To put it simply, you cannot multiply two ciphertexts. If you enforce this calculation, you will have an exception.
|
|
145
165
|
|
|
146
166
|
```python
|
|
147
|
-
# pailier is not homomorphic
|
|
167
|
+
# pailier is not multiplicatively homomorphic
|
|
148
168
|
with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the multiplication"):
|
|
149
169
|
c1 * c2
|
|
150
170
|
|
|
151
|
-
# pailier is not homomorphic
|
|
171
|
+
# pailier is not exclusively homomorphic
|
|
152
172
|
with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the exclusive or"):
|
|
153
173
|
c1 ^ c2
|
|
154
174
|
```
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
lightphe/__init__.py,sha256=
|
|
1
|
+
lightphe/__init__.py,sha256=gi73bq3JA6KnIGYdtHB02awvfMw_4gpe0vDLDY-WXK4,8894
|
|
2
2
|
lightphe/commons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
lightphe/commons/logger.py,sha256=ci8TjKtNNSafe_G_E6L80WS-9nZfNhOerT1YRw3DnnM,1122
|
|
4
4
|
lightphe/cryptosystems/Benaloh.py,sha256=L8x2fi9wAtiuGIDLn7iuo2uVYuhYYyKXjgzg2nPA8DY,7162
|
|
@@ -14,12 +14,13 @@ lightphe/cryptosystems/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
14
14
|
lightphe/elliptic/Weierstrass.py,sha256=SutRA26XKRnJLgXl5qJVZyBo3okuKOkDW6v6SYd9xpE,3126
|
|
15
15
|
lightphe/elliptic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
lightphe/models/Algorithm.py,sha256=VAWIWMqJ2IeV-JsV7kCEVKIBkjY8PlKzm-ByIsEZ5MA,402
|
|
17
|
-
lightphe/models/Ciphertext.py,sha256=
|
|
17
|
+
lightphe/models/Ciphertext.py,sha256=LkDuFiBNZx5lGE_GhM1WEwZa3n72miY0XqHXt14gR-w,6239
|
|
18
18
|
lightphe/models/EllipticCurve.py,sha256=XjlDlInAUxY3IsDJJRI9JACGz2JQyKzfcWFed80tSRI,468
|
|
19
19
|
lightphe/models/Homomorphic.py,sha256=pkIK9Wd4an68mhnr-iRYHYQXFzibLMt5WW-er3-rOFM,1406
|
|
20
20
|
lightphe/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
21
|
tests/__init__.py,sha256=Q8b3_IWF9ZE8eNZLUw58JXCZE6UGoYSqwq6muXRb-LY,8452
|
|
22
22
|
tests/test_benaloh.py,sha256=yl0ZAak1WYE9OkFEAk44-yErXVTpJEFLOsMCSZJhkns,1516
|
|
23
|
+
tests/test_cloud.py,sha256=aykjgf0xGwIOrHvqrcZEnsRWtHMeByDhZHtklAyMi5I,1167
|
|
23
24
|
tests/test_damgard.py,sha256=45tNxDG-22TTmSSA28e6lO_IQD8SiaraUZOG5BTQ0Ig,1544
|
|
24
25
|
tests/test_elgamal.py,sha256=kOi121Pgii4iGaNm6urfiLudkzN6EkZHoHp9ZQXKMlY,3449
|
|
25
26
|
tests/test_ellipticcurveelgamal.py,sha256=WwS6ke7T2CCZ_51UrqG0Eo0bjtFvegiM9WKjq6S-0ZM,1492
|
|
@@ -29,8 +30,8 @@ tests/test_okamoto.py,sha256=ysavBNz9E9bAd521PE4YWaragr3l0sNaGc0OMWhL5AM,1545
|
|
|
29
30
|
tests/test_paillier.py,sha256=F56sLDX01begaSIbwBE-WDx62-2P8xgYv9dd9R531u0,2363
|
|
30
31
|
tests/test_rsa.py,sha256=tzgknMUF0UNCJq3kapg0I6fB5Xk6_EupuDd9ttPc1hs,1285
|
|
31
32
|
tests/test_salary.py,sha256=uFFMixNc5qxm_LG39gxGyqo8xfa1OEn7dmsHPUwoTns,1541
|
|
32
|
-
lightphe-0.0.
|
|
33
|
-
lightphe-0.0.
|
|
34
|
-
lightphe-0.0.
|
|
35
|
-
lightphe-0.0.
|
|
36
|
-
lightphe-0.0.
|
|
33
|
+
lightphe-0.0.3.dist-info/LICENSE,sha256=Yaij6BkJXa3d0E7bxi0kAbI2JF7OH_tpe7HFiaJLBwY,1076
|
|
34
|
+
lightphe-0.0.3.dist-info/METADATA,sha256=0f6AC-7vpdfIf6pW2fTChDRu_WktasgnHha8VkG4oCM,10234
|
|
35
|
+
lightphe-0.0.3.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92
|
|
36
|
+
lightphe-0.0.3.dist-info/top_level.txt,sha256=-xiT4F8yDH7SK2TyLnN7yxajFiaeyyQUYdsdDcXJf7s,15
|
|
37
|
+
lightphe-0.0.3.dist-info/RECORD,,
|
tests/test_cloud.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from lightphe.commons.logger import Logger
|
|
2
|
+
from lightphe import LightPHE
|
|
3
|
+
|
|
4
|
+
logger = Logger()
|
|
5
|
+
|
|
6
|
+
# pre-generated 20-bit RSA keys
|
|
7
|
+
PRIVATE = {"private_key": {"d": 30365}, "public_key": {"n": 175501, "e": 101753}}
|
|
8
|
+
PUBLIC = {"public_key": {"n": 175501, "e": 101753}}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_encryption():
|
|
12
|
+
cs = LightPHE(algorithm_name="RSA", keys=PRIVATE)
|
|
13
|
+
|
|
14
|
+
# plaintexts
|
|
15
|
+
m1 = 10000
|
|
16
|
+
c1 = cs.encrypt(m1)
|
|
17
|
+
|
|
18
|
+
# m2 = 1.05 # TODO: add support
|
|
19
|
+
m2 = 5
|
|
20
|
+
c2 = cs.encrypt(m2)
|
|
21
|
+
|
|
22
|
+
assert cs.decrypt(c1) == m1
|
|
23
|
+
assert cs.decrypt(c2) == m2
|
|
24
|
+
|
|
25
|
+
logger.info("✅ Cloud encryption tests done")
|
|
26
|
+
|
|
27
|
+
c3_val = homomorphic_operations(c1.value, c2.value)
|
|
28
|
+
c3 = cs.create_ciphertext_obj(c3_val)
|
|
29
|
+
|
|
30
|
+
assert cs.decrypt(c3) == m1 * m2
|
|
31
|
+
|
|
32
|
+
logger.info("✅ Cloud decryption tests done")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def homomorphic_operations(c1: int, c2: int):
|
|
36
|
+
"""
|
|
37
|
+
One can perform homomorphic operations while he/she does not hold the private key
|
|
38
|
+
"""
|
|
39
|
+
cs = LightPHE(algorithm_name="RSA", keys=PUBLIC)
|
|
40
|
+
c1_obj = cs.create_ciphertext_obj(c1)
|
|
41
|
+
c2_obj = cs.create_ciphertext_obj(c2)
|
|
42
|
+
c3 = c1_obj * c2_obj
|
|
43
|
+
logger.info("✅ Cloud homomorphic operation tests done")
|
|
44
|
+
return c3.value
|
|
File without changes
|
|
File without changes
|
|
File without changes
|