lightphe 0.0.7__tar.gz → 0.0.9__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.7 → lightphe-0.0.9}/PKG-INFO +115 -82
- {lightphe-0.0.7 → lightphe-0.0.9}/README.md +114 -81
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/__init__.py +16 -46
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/Benaloh.py +3 -2
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/DamgardJurik.py +2 -2
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/ElGamal.py +2 -2
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/EllipticCurveElGamal.py +24 -13
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/GoldwasserMicali.py +3 -2
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/NaccacheStern.py +3 -2
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/OkamotoUchiyama.py +2 -2
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/Paillier.py +2 -2
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/RSA.py +2 -2
- lightphe-0.0.9/lightphe/elliptic_curve_forms/edwards.py +61 -0
- lightphe-0.0.9/lightphe/elliptic_curve_forms/weierstrass.py +75 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/Ciphertext.py +3 -3
- lightphe-0.0.9/lightphe/models/EllipticCurve.py +45 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/Tensor.py +9 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/PKG-INFO +115 -82
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/SOURCES.txt +3 -2
- {lightphe-0.0.7 → lightphe-0.0.9}/setup.py +1 -1
- lightphe-0.0.9/tests/__init__.py +0 -0
- lightphe-0.0.9/tests/test_ellipticcurveelgamal.py +69 -0
- lightphe-0.0.7/lightphe/elliptic/Weierstrass.py +0 -98
- lightphe-0.0.7/lightphe/models/EllipticCurve.py +0 -18
- lightphe-0.0.7/tests/__init__.py +0 -219
- lightphe-0.0.7/tests/test_ellipticcurveelgamal.py +0 -64
- {lightphe-0.0.7 → lightphe-0.0.9}/LICENSE +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/commons/__init__.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/commons/logger.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/commons/phe_utils.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/__init__.py +0 -0
- {lightphe-0.0.7/lightphe/elliptic → lightphe-0.0.9/lightphe/elliptic_curve_forms}/__init__.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/Algorithm.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/Homomorphic.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/__init__.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/dependency_links.txt +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/requires.txt +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/top_level.txt +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/requirements.txt +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/setup.cfg +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_benaloh.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_cloud.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_damgard.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_elgamal.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_exporting_keys.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_goldwasser.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_naccache.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_okamoto.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_paillier.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_rsa.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_salary.py +0 -0
- {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_tensors.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lightphe
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
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
|
|
@@ -18,22 +18,25 @@ License-File: LICENSE
|
|
|
18
18
|
|
|
19
19
|
<div align="center">
|
|
20
20
|
|
|
21
|
-
[](https://pepy.tech/project/lightphe)
|
|
22
22
|
[](https://github.com/serengil/LightPHE/stargazers)
|
|
23
23
|
[](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
|
|
24
24
|
[](https://github.com/serengil/LightPHE/blob/master/LICENSE)
|
|
25
|
-
[](https://github.com/sponsors/serengil)
|
|
25
|
+
[](https://arxiv.org/abs/2408.05219)
|
|
27
26
|
|
|
28
27
|
[](https://sefiks.com)
|
|
29
28
|
[](https://www.youtube.com/@sefiks?sub_confirmation=1)
|
|
30
|
-
[](https://twitter.com/intent/user?screen_name=serengil)
|
|
30
|
+
|
|
31
|
+
[](https://www.patreon.com/serengil?repo=lightphe)
|
|
32
|
+
[](https://github.com/sponsors/serengil)
|
|
33
|
+
[](https://buymeacoffee.com/serengil)
|
|
31
34
|
|
|
32
35
|
</div>
|
|
33
36
|
|
|
34
37
|
<p align="center"><img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/phi.png" width="200" height="240"></p>
|
|
35
38
|
|
|
36
|
-
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/)
|
|
39
|
+
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/) ([`Weierstrass`](https://sefiks.com/2016/03/13/the-math-behind-elliptic-curve-cryptography/) and [`Edwards`](https://sefiks.com/2018/12/19/a-gentle-introduction-to-edwards-curves/) forms) [`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/).
|
|
37
40
|
|
|
38
41
|
# Partially vs Fully Homomorphic Encryption
|
|
39
42
|
|
|
@@ -95,7 +98,7 @@ algorithms = [
|
|
|
95
98
|
"EllipticCurve-ElGamal"
|
|
96
99
|
]
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
phe = LightPHE(algorithm_name = algorithms[0])
|
|
99
102
|
```
|
|
100
103
|
|
|
101
104
|
# Encryption & Decryption
|
|
@@ -107,59 +110,127 @@ Once you built your cryptosystem, you will be able to encrypt and decrypt messag
|
|
|
107
110
|
m = 17
|
|
108
111
|
|
|
109
112
|
# calculate ciphertext
|
|
110
|
-
c =
|
|
113
|
+
c = phe.encrypt(m)
|
|
111
114
|
|
|
112
|
-
|
|
115
|
+
# proof of work
|
|
116
|
+
assert phe.decrypt(c) == m
|
|
113
117
|
```
|
|
114
118
|
|
|
115
119
|
# Homomorphic Operations
|
|
116
120
|
|
|
117
|
-
Once you have the ciphertext, you will be able to perform homomorphic operations on encrypted data. For instance, Paillier is homomorphic with respect to the addition. In other words, decryption of the addition of two ciphertexts is equivalent to addition of plaintexts.
|
|
121
|
+
Once you have the ciphertext, you will be able to perform homomorphic operations on encrypted data without holding private key. For instance, Paillier is homomorphic with respect to the addition. In other words, decryption of the addition of two ciphertexts is equivalent to addition of plaintexts.
|
|
122
|
+
|
|
123
|
+
### On-Prem Encryption
|
|
124
|
+
|
|
125
|
+
This code snippet illustrates how to generate a random public-private key pair using the Paillier and encrypt a plaintext pair. The resulting ciphertext pair, c1 and c2, along with the public key, is then sent from the on-premises environment to the cloud.
|
|
118
126
|
|
|
119
127
|
```python
|
|
120
|
-
|
|
128
|
+
def on_premise() -> Tuple[int, int, dict]:
|
|
129
|
+
"""
|
|
130
|
+
Executes on-premise operations: initializes a cryptosystem by generating
|
|
131
|
+
a random public-private key pair, then encrypts two plaintext values.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
result (tuple): A tuple containing:
|
|
135
|
+
- c1 (int): The first ciphertext
|
|
136
|
+
- c2 (int): The second ciphertext
|
|
137
|
+
- public_key (dict): The public key for the cryptosystem
|
|
138
|
+
"""
|
|
139
|
+
# generate a random private-public key pair
|
|
140
|
+
phe = LightPHE(algorithm_name = "Paillier")
|
|
141
|
+
|
|
142
|
+
# define plaintexts
|
|
143
|
+
m1 = 10000 # base salary in usd
|
|
144
|
+
m2 = 500 # wage increase in usd
|
|
145
|
+
|
|
146
|
+
# calculate ciphertexts
|
|
147
|
+
c1 = phe.encrypt(m1).value
|
|
148
|
+
c2 = phe.encrypt(m2).value
|
|
149
|
+
|
|
150
|
+
return (c1, c2, phe.cs.public_key)
|
|
151
|
+
```
|
|
121
152
|
|
|
122
|
-
|
|
123
|
-
m1 = 17
|
|
124
|
-
m2 = 23
|
|
153
|
+
### Homomorphic Operations on Cloud
|
|
125
154
|
|
|
126
|
-
|
|
127
|
-
c1 = cs.encrypt(m1)
|
|
128
|
-
c2 = cs.encrypt(m2)
|
|
155
|
+
This code snippet demonstrates how to perform homomorphic addition on the cloud side without using the private key. However, the cloud is unable to decrypt c3 itself, even though it is the one that calculated it.
|
|
129
156
|
|
|
130
|
-
|
|
131
|
-
|
|
157
|
+
```python
|
|
158
|
+
def cloud(c1: int, c2: int, public_key: dict) -> int:
|
|
159
|
+
"""
|
|
160
|
+
Performs cloud-side operations: reconstructs a cryptosystem using the
|
|
161
|
+
provided public key and executes a homomorphic addition on two ciphertexts.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
c1 (int): The first ciphertext
|
|
165
|
+
c2 (int): The second ciphertext
|
|
166
|
+
public_key (dict): The public key of an existing cryptosystem
|
|
167
|
+
Retunrs:
|
|
168
|
+
c3 (int): The resulting ciphertext after homomorphic addition
|
|
169
|
+
"""
|
|
170
|
+
# restore cryptosystem with just the public key
|
|
171
|
+
phe = LightPHE(algorithm_name = "Paillier", keys = public_key)
|
|
172
|
+
|
|
173
|
+
# cast c1 and c2 to ciphertext objects
|
|
174
|
+
c1 = phe.create_ciphertext_obj(c1)
|
|
175
|
+
c2 = phe.create_ciphertext_obj(c2)
|
|
176
|
+
|
|
177
|
+
# confirm that cloud cannot decrypt c1
|
|
178
|
+
with pytest.raises(ValueError, match="You must have private key"):
|
|
179
|
+
phe.decrypt(c1)
|
|
180
|
+
|
|
181
|
+
# confirm that cloud cannot decrypt c2
|
|
182
|
+
with pytest.raises(ValueError, match="You must have private key"):
|
|
183
|
+
phe.decrypt(c2)
|
|
184
|
+
|
|
185
|
+
# perform homomorphic addition
|
|
186
|
+
c3 = c1 + c2
|
|
187
|
+
|
|
188
|
+
# confirm that cloud cannot decrypt c3
|
|
189
|
+
with pytest.raises(ValueError, match="You must have private key"):
|
|
190
|
+
phe.decrypt(c3)
|
|
191
|
+
|
|
192
|
+
return c3.value
|
|
193
|
+
```
|
|
132
194
|
|
|
133
|
-
|
|
134
|
-
|
|
195
|
+
### On-Prem Decryption And Proof of Work
|
|
196
|
+
|
|
197
|
+
This code snippet demonstrates the proof of work. Even though c3 was calculated in the cloud by adding c1 and c2, on-premises can validate that its decryption must be equal to the addition of plaintexts m1 and m2.
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
# proof of work - private key required
|
|
201
|
+
assert phe.decrypt(c3) == m1 + m2
|
|
135
202
|
```
|
|
136
203
|
|
|
137
|
-
|
|
204
|
+
In this homomorphic pipeline, the cloud's computational power was utilized to calculate c3, but it can only be decrypted by the on-premises side. Additionally, while we performed the encryption on the on-premises side, this is not strictly necessary; only the public key is required for encryption. Therefore, encryption can also be performed on the non-premises side. This approach is particularly convenient when collecting data from multiple edge devices and storing all of it in the cloud simultaneously.
|
|
205
|
+
|
|
206
|
+
### Scalar Multiplication
|
|
138
207
|
|
|
139
|
-
Besides, Paillier is supporting multiplying ciphertexts by a known plain constant.
|
|
208
|
+
Besides, Paillier is supporting multiplying ciphertexts by a known plain constant. This code snippet demonstrates how to perform scalar multiplication on encrypted data using Paillier homomorphic encryption with the LightPHE library.
|
|
140
209
|
|
|
141
210
|
```python
|
|
142
211
|
# increasing something 5%
|
|
143
212
|
k = 1.05
|
|
144
213
|
|
|
145
|
-
# scalar multiplication - private key is not required
|
|
214
|
+
# scalar multiplication - cloud (private key is not required)
|
|
146
215
|
c4 = k * c1
|
|
147
216
|
|
|
148
|
-
# proof of work
|
|
149
|
-
assert
|
|
217
|
+
# proof of work on-prem - private key is required
|
|
218
|
+
assert phe.decrypt(c4) == k * m1
|
|
150
219
|
```
|
|
151
220
|
|
|
152
|
-
|
|
221
|
+
### Ciphertext Regeneration
|
|
153
222
|
|
|
154
223
|
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.
|
|
155
224
|
|
|
156
225
|
```python
|
|
157
|
-
c1_prime =
|
|
226
|
+
c1_prime = phe.regenerate_ciphertext(c1)
|
|
158
227
|
assert c1_prime.value != c1.value
|
|
159
|
-
assert
|
|
160
|
-
assert
|
|
228
|
+
assert phe.decrypt(c1_prime) == m1
|
|
229
|
+
assert phe.decrypt(c1) == m1
|
|
161
230
|
```
|
|
162
231
|
|
|
232
|
+
### Unsupported Operations
|
|
233
|
+
|
|
163
234
|
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.
|
|
164
235
|
|
|
165
236
|
```python
|
|
@@ -174,51 +245,6 @@ with pytest.raises(ValueError, match="Paillier is not homomorphic with respect t
|
|
|
174
245
|
|
|
175
246
|
However, if you tried to multiply ciphertexts with RSA, or xor ciphertexts with Goldwasser-Micali, these will be succeeded because those cryptosystems support those homomorphic operations.
|
|
176
247
|
|
|
177
|
-
# Working with vectors
|
|
178
|
-
|
|
179
|
-
You can encrypt the output vectors of machine learning models with LightPHE. These encrypted tensors come with homomorphic operation support including homomorphic addition, element-wise multiplication and scalar multiplication.
|
|
180
|
-
|
|
181
|
-
```python
|
|
182
|
-
# build an additively homomorphic cryptosystem
|
|
183
|
-
cs = LightPHE(algorithm_name="Paillier")
|
|
184
|
-
|
|
185
|
-
# define plain tensors
|
|
186
|
-
t1 = [1.005, 2.05, 3.5, 4]
|
|
187
|
-
t2 = [5, 6.2, 7.002, 8.02]
|
|
188
|
-
|
|
189
|
-
# encrypt tensors
|
|
190
|
-
c1 = cs.encrypt(t1)
|
|
191
|
-
c2 = cs.encrypt(t2)
|
|
192
|
-
|
|
193
|
-
# perform homomorphic addition
|
|
194
|
-
c3 = c1 + c2
|
|
195
|
-
|
|
196
|
-
# perform homomorphic element-wise multiplication
|
|
197
|
-
c4 = c1 * c2
|
|
198
|
-
|
|
199
|
-
# perform homomorphic scalar multiplication
|
|
200
|
-
k = 5
|
|
201
|
-
c5 = k * c1
|
|
202
|
-
|
|
203
|
-
# decrypt the addition tensor
|
|
204
|
-
t3 = cs.decrypt(c3)
|
|
205
|
-
|
|
206
|
-
# decrypt the element-wise multiplied tensor
|
|
207
|
-
t4 = cs.decrypt(c4)
|
|
208
|
-
|
|
209
|
-
# decrypt the scalar multiplied tensor
|
|
210
|
-
t5 = cs.decrypt(c5)
|
|
211
|
-
|
|
212
|
-
# data validations
|
|
213
|
-
threshold = 0.5
|
|
214
|
-
for i in range(0, len(t1)):
|
|
215
|
-
assert abs((t1[i] + t2[i]) - t3[i]) < threshold
|
|
216
|
-
assert abs((t1[i] * t2[i]) - t4[i]) < threshold
|
|
217
|
-
assert abs((t1[i] * k) - t5[i]) < threshold
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Unfortunately, vector multiplication (dot product) requires both homomorphic addition and homomorphic multiplication and this cannot be done with partially homomorphic encryption algorithms.
|
|
221
|
-
|
|
222
248
|
# Contributing
|
|
223
249
|
|
|
224
250
|
All PRs are more than welcome! If you are planning to contribute a large patch, please create an issue first to get any upfront questions or design decisions out of the way first.
|
|
@@ -229,23 +255,30 @@ You should be able run `make test` and `make lint` commands successfully before
|
|
|
229
255
|
|
|
230
256
|
There are many ways to support a project - starring⭐️ the GitHub repo is just one 🙏
|
|
231
257
|
|
|
232
|
-
You can also support this work on [Patreon](https://www.patreon.com/serengil?repo=lightphe)
|
|
258
|
+
You can also support this work on [Patreon](https://www.patreon.com/serengil?repo=lightphe), [GitHub Sponsors](https://github.com/sponsors/serengil) or [Buy Me a Coffee](https://buymeacoffee.com/serengil).
|
|
233
259
|
|
|
234
260
|
<a href="https://www.patreon.com/serengil?repo=lightphe">
|
|
235
261
|
<img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/patreon.png" width="30%" height="30%">
|
|
236
262
|
</a>
|
|
237
263
|
|
|
264
|
+
<a href="https://buymeacoffee.com/serengil">
|
|
265
|
+
<img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/bmc-button.png" width="25%" height="25%">
|
|
266
|
+
</a>
|
|
267
|
+
|
|
268
|
+
Also, your company's logo will be shown on README on GitHub if you become sponsor in gold, silver or bronze tiers.
|
|
269
|
+
|
|
238
270
|
# Citation
|
|
239
271
|
|
|
240
272
|
Please cite LightPHE in your publications if it helps your research. Here is its BibTex entry:
|
|
241
273
|
|
|
242
274
|
```BibTeX
|
|
243
|
-
@misc{
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
275
|
+
@misc{serengil2024lightphe,
|
|
276
|
+
title = {LightPHE: Integrating Partially Homomorphic Encryption into Python with Extensive Cloud Environment Evaluations},
|
|
277
|
+
author = {Serengil, Sefik Ilkin and Ozpinar, Alper},
|
|
278
|
+
year = {2024},
|
|
279
|
+
publisher = {arXiv},
|
|
280
|
+
url = {https://arxiv.org/abs/2408.05219},
|
|
281
|
+
doi = {10.48550/arXiv.2408.05219}
|
|
249
282
|
}
|
|
250
283
|
```
|
|
251
284
|
|
|
@@ -2,22 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
|
|
5
|
-
[](https://pepy.tech/project/lightphe)
|
|
6
6
|
[](https://github.com/serengil/LightPHE/stargazers)
|
|
7
7
|
[](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
|
|
8
8
|
[](https://github.com/serengil/LightPHE/blob/master/LICENSE)
|
|
9
|
-
[](https://github.com/sponsors/serengil)
|
|
9
|
+
[](https://arxiv.org/abs/2408.05219)
|
|
11
10
|
|
|
12
11
|
[](https://sefiks.com)
|
|
13
12
|
[](https://www.youtube.com/@sefiks?sub_confirmation=1)
|
|
14
|
-
[](https://twitter.com/intent/user?screen_name=serengil)
|
|
14
|
+
|
|
15
|
+
[](https://www.patreon.com/serengil?repo=lightphe)
|
|
16
|
+
[](https://github.com/sponsors/serengil)
|
|
17
|
+
[](https://buymeacoffee.com/serengil)
|
|
15
18
|
|
|
16
19
|
</div>
|
|
17
20
|
|
|
18
21
|
<p align="center"><img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/phi.png" width="200" height="240"></p>
|
|
19
22
|
|
|
20
|
-
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/)
|
|
23
|
+
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/) ([`Weierstrass`](https://sefiks.com/2016/03/13/the-math-behind-elliptic-curve-cryptography/) and [`Edwards`](https://sefiks.com/2018/12/19/a-gentle-introduction-to-edwards-curves/) forms) [`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/).
|
|
21
24
|
|
|
22
25
|
# Partially vs Fully Homomorphic Encryption
|
|
23
26
|
|
|
@@ -79,7 +82,7 @@ algorithms = [
|
|
|
79
82
|
"EllipticCurve-ElGamal"
|
|
80
83
|
]
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
phe = LightPHE(algorithm_name = algorithms[0])
|
|
83
86
|
```
|
|
84
87
|
|
|
85
88
|
# Encryption & Decryption
|
|
@@ -91,59 +94,127 @@ Once you built your cryptosystem, you will be able to encrypt and decrypt messag
|
|
|
91
94
|
m = 17
|
|
92
95
|
|
|
93
96
|
# calculate ciphertext
|
|
94
|
-
c =
|
|
97
|
+
c = phe.encrypt(m)
|
|
95
98
|
|
|
96
|
-
|
|
99
|
+
# proof of work
|
|
100
|
+
assert phe.decrypt(c) == m
|
|
97
101
|
```
|
|
98
102
|
|
|
99
103
|
# Homomorphic Operations
|
|
100
104
|
|
|
101
|
-
Once you have the ciphertext, you will be able to perform homomorphic operations on encrypted data. For instance, Paillier is homomorphic with respect to the addition. In other words, decryption of the addition of two ciphertexts is equivalent to addition of plaintexts.
|
|
105
|
+
Once you have the ciphertext, you will be able to perform homomorphic operations on encrypted data without holding private key. For instance, Paillier is homomorphic with respect to the addition. In other words, decryption of the addition of two ciphertexts is equivalent to addition of plaintexts.
|
|
106
|
+
|
|
107
|
+
### On-Prem Encryption
|
|
108
|
+
|
|
109
|
+
This code snippet illustrates how to generate a random public-private key pair using the Paillier and encrypt a plaintext pair. The resulting ciphertext pair, c1 and c2, along with the public key, is then sent from the on-premises environment to the cloud.
|
|
102
110
|
|
|
103
111
|
```python
|
|
104
|
-
|
|
112
|
+
def on_premise() -> Tuple[int, int, dict]:
|
|
113
|
+
"""
|
|
114
|
+
Executes on-premise operations: initializes a cryptosystem by generating
|
|
115
|
+
a random public-private key pair, then encrypts two plaintext values.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
result (tuple): A tuple containing:
|
|
119
|
+
- c1 (int): The first ciphertext
|
|
120
|
+
- c2 (int): The second ciphertext
|
|
121
|
+
- public_key (dict): The public key for the cryptosystem
|
|
122
|
+
"""
|
|
123
|
+
# generate a random private-public key pair
|
|
124
|
+
phe = LightPHE(algorithm_name = "Paillier")
|
|
125
|
+
|
|
126
|
+
# define plaintexts
|
|
127
|
+
m1 = 10000 # base salary in usd
|
|
128
|
+
m2 = 500 # wage increase in usd
|
|
129
|
+
|
|
130
|
+
# calculate ciphertexts
|
|
131
|
+
c1 = phe.encrypt(m1).value
|
|
132
|
+
c2 = phe.encrypt(m2).value
|
|
133
|
+
|
|
134
|
+
return (c1, c2, phe.cs.public_key)
|
|
135
|
+
```
|
|
105
136
|
|
|
106
|
-
|
|
107
|
-
m1 = 17
|
|
108
|
-
m2 = 23
|
|
137
|
+
### Homomorphic Operations on Cloud
|
|
109
138
|
|
|
110
|
-
|
|
111
|
-
c1 = cs.encrypt(m1)
|
|
112
|
-
c2 = cs.encrypt(m2)
|
|
139
|
+
This code snippet demonstrates how to perform homomorphic addition on the cloud side without using the private key. However, the cloud is unable to decrypt c3 itself, even though it is the one that calculated it.
|
|
113
140
|
|
|
114
|
-
|
|
115
|
-
|
|
141
|
+
```python
|
|
142
|
+
def cloud(c1: int, c2: int, public_key: dict) -> int:
|
|
143
|
+
"""
|
|
144
|
+
Performs cloud-side operations: reconstructs a cryptosystem using the
|
|
145
|
+
provided public key and executes a homomorphic addition on two ciphertexts.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
c1 (int): The first ciphertext
|
|
149
|
+
c2 (int): The second ciphertext
|
|
150
|
+
public_key (dict): The public key of an existing cryptosystem
|
|
151
|
+
Retunrs:
|
|
152
|
+
c3 (int): The resulting ciphertext after homomorphic addition
|
|
153
|
+
"""
|
|
154
|
+
# restore cryptosystem with just the public key
|
|
155
|
+
phe = LightPHE(algorithm_name = "Paillier", keys = public_key)
|
|
156
|
+
|
|
157
|
+
# cast c1 and c2 to ciphertext objects
|
|
158
|
+
c1 = phe.create_ciphertext_obj(c1)
|
|
159
|
+
c2 = phe.create_ciphertext_obj(c2)
|
|
160
|
+
|
|
161
|
+
# confirm that cloud cannot decrypt c1
|
|
162
|
+
with pytest.raises(ValueError, match="You must have private key"):
|
|
163
|
+
phe.decrypt(c1)
|
|
164
|
+
|
|
165
|
+
# confirm that cloud cannot decrypt c2
|
|
166
|
+
with pytest.raises(ValueError, match="You must have private key"):
|
|
167
|
+
phe.decrypt(c2)
|
|
168
|
+
|
|
169
|
+
# perform homomorphic addition
|
|
170
|
+
c3 = c1 + c2
|
|
171
|
+
|
|
172
|
+
# confirm that cloud cannot decrypt c3
|
|
173
|
+
with pytest.raises(ValueError, match="You must have private key"):
|
|
174
|
+
phe.decrypt(c3)
|
|
175
|
+
|
|
176
|
+
return c3.value
|
|
177
|
+
```
|
|
116
178
|
|
|
117
|
-
|
|
118
|
-
|
|
179
|
+
### On-Prem Decryption And Proof of Work
|
|
180
|
+
|
|
181
|
+
This code snippet demonstrates the proof of work. Even though c3 was calculated in the cloud by adding c1 and c2, on-premises can validate that its decryption must be equal to the addition of plaintexts m1 and m2.
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
# proof of work - private key required
|
|
185
|
+
assert phe.decrypt(c3) == m1 + m2
|
|
119
186
|
```
|
|
120
187
|
|
|
121
|
-
|
|
188
|
+
In this homomorphic pipeline, the cloud's computational power was utilized to calculate c3, but it can only be decrypted by the on-premises side. Additionally, while we performed the encryption on the on-premises side, this is not strictly necessary; only the public key is required for encryption. Therefore, encryption can also be performed on the non-premises side. This approach is particularly convenient when collecting data from multiple edge devices and storing all of it in the cloud simultaneously.
|
|
189
|
+
|
|
190
|
+
### Scalar Multiplication
|
|
122
191
|
|
|
123
|
-
Besides, Paillier is supporting multiplying ciphertexts by a known plain constant.
|
|
192
|
+
Besides, Paillier is supporting multiplying ciphertexts by a known plain constant. This code snippet demonstrates how to perform scalar multiplication on encrypted data using Paillier homomorphic encryption with the LightPHE library.
|
|
124
193
|
|
|
125
194
|
```python
|
|
126
195
|
# increasing something 5%
|
|
127
196
|
k = 1.05
|
|
128
197
|
|
|
129
|
-
# scalar multiplication - private key is not required
|
|
198
|
+
# scalar multiplication - cloud (private key is not required)
|
|
130
199
|
c4 = k * c1
|
|
131
200
|
|
|
132
|
-
# proof of work
|
|
133
|
-
assert
|
|
201
|
+
# proof of work on-prem - private key is required
|
|
202
|
+
assert phe.decrypt(c4) == k * m1
|
|
134
203
|
```
|
|
135
204
|
|
|
136
|
-
|
|
205
|
+
### Ciphertext Regeneration
|
|
137
206
|
|
|
138
207
|
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.
|
|
139
208
|
|
|
140
209
|
```python
|
|
141
|
-
c1_prime =
|
|
210
|
+
c1_prime = phe.regenerate_ciphertext(c1)
|
|
142
211
|
assert c1_prime.value != c1.value
|
|
143
|
-
assert
|
|
144
|
-
assert
|
|
212
|
+
assert phe.decrypt(c1_prime) == m1
|
|
213
|
+
assert phe.decrypt(c1) == m1
|
|
145
214
|
```
|
|
146
215
|
|
|
216
|
+
### Unsupported Operations
|
|
217
|
+
|
|
147
218
|
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.
|
|
148
219
|
|
|
149
220
|
```python
|
|
@@ -158,51 +229,6 @@ with pytest.raises(ValueError, match="Paillier is not homomorphic with respect t
|
|
|
158
229
|
|
|
159
230
|
However, if you tried to multiply ciphertexts with RSA, or xor ciphertexts with Goldwasser-Micali, these will be succeeded because those cryptosystems support those homomorphic operations.
|
|
160
231
|
|
|
161
|
-
# Working with vectors
|
|
162
|
-
|
|
163
|
-
You can encrypt the output vectors of machine learning models with LightPHE. These encrypted tensors come with homomorphic operation support including homomorphic addition, element-wise multiplication and scalar multiplication.
|
|
164
|
-
|
|
165
|
-
```python
|
|
166
|
-
# build an additively homomorphic cryptosystem
|
|
167
|
-
cs = LightPHE(algorithm_name="Paillier")
|
|
168
|
-
|
|
169
|
-
# define plain tensors
|
|
170
|
-
t1 = [1.005, 2.05, 3.5, 4]
|
|
171
|
-
t2 = [5, 6.2, 7.002, 8.02]
|
|
172
|
-
|
|
173
|
-
# encrypt tensors
|
|
174
|
-
c1 = cs.encrypt(t1)
|
|
175
|
-
c2 = cs.encrypt(t2)
|
|
176
|
-
|
|
177
|
-
# perform homomorphic addition
|
|
178
|
-
c3 = c1 + c2
|
|
179
|
-
|
|
180
|
-
# perform homomorphic element-wise multiplication
|
|
181
|
-
c4 = c1 * c2
|
|
182
|
-
|
|
183
|
-
# perform homomorphic scalar multiplication
|
|
184
|
-
k = 5
|
|
185
|
-
c5 = k * c1
|
|
186
|
-
|
|
187
|
-
# decrypt the addition tensor
|
|
188
|
-
t3 = cs.decrypt(c3)
|
|
189
|
-
|
|
190
|
-
# decrypt the element-wise multiplied tensor
|
|
191
|
-
t4 = cs.decrypt(c4)
|
|
192
|
-
|
|
193
|
-
# decrypt the scalar multiplied tensor
|
|
194
|
-
t5 = cs.decrypt(c5)
|
|
195
|
-
|
|
196
|
-
# data validations
|
|
197
|
-
threshold = 0.5
|
|
198
|
-
for i in range(0, len(t1)):
|
|
199
|
-
assert abs((t1[i] + t2[i]) - t3[i]) < threshold
|
|
200
|
-
assert abs((t1[i] * t2[i]) - t4[i]) < threshold
|
|
201
|
-
assert abs((t1[i] * k) - t5[i]) < threshold
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Unfortunately, vector multiplication (dot product) requires both homomorphic addition and homomorphic multiplication and this cannot be done with partially homomorphic encryption algorithms.
|
|
205
|
-
|
|
206
232
|
# Contributing
|
|
207
233
|
|
|
208
234
|
All PRs are more than welcome! If you are planning to contribute a large patch, please create an issue first to get any upfront questions or design decisions out of the way first.
|
|
@@ -213,23 +239,30 @@ You should be able run `make test` and `make lint` commands successfully before
|
|
|
213
239
|
|
|
214
240
|
There are many ways to support a project - starring⭐️ the GitHub repo is just one 🙏
|
|
215
241
|
|
|
216
|
-
You can also support this work on [Patreon](https://www.patreon.com/serengil?repo=lightphe)
|
|
242
|
+
You can also support this work on [Patreon](https://www.patreon.com/serengil?repo=lightphe), [GitHub Sponsors](https://github.com/sponsors/serengil) or [Buy Me a Coffee](https://buymeacoffee.com/serengil).
|
|
217
243
|
|
|
218
244
|
<a href="https://www.patreon.com/serengil?repo=lightphe">
|
|
219
245
|
<img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/patreon.png" width="30%" height="30%">
|
|
220
246
|
</a>
|
|
221
247
|
|
|
248
|
+
<a href="https://buymeacoffee.com/serengil">
|
|
249
|
+
<img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/bmc-button.png" width="25%" height="25%">
|
|
250
|
+
</a>
|
|
251
|
+
|
|
252
|
+
Also, your company's logo will be shown on README on GitHub if you become sponsor in gold, silver or bronze tiers.
|
|
253
|
+
|
|
222
254
|
# Citation
|
|
223
255
|
|
|
224
256
|
Please cite LightPHE in your publications if it helps your research. Here is its BibTex entry:
|
|
225
257
|
|
|
226
258
|
```BibTeX
|
|
227
|
-
@misc{
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
259
|
+
@misc{serengil2024lightphe,
|
|
260
|
+
title = {LightPHE: Integrating Partially Homomorphic Encryption into Python with Extensive Cloud Environment Evaluations},
|
|
261
|
+
author = {Serengil, Sefik Ilkin and Ozpinar, Alper},
|
|
262
|
+
year = {2024},
|
|
263
|
+
publisher = {arXiv},
|
|
264
|
+
url = {https://arxiv.org/abs/2408.05219},
|
|
265
|
+
doi = {10.48550/arXiv.2408.05219}
|
|
233
266
|
}
|
|
234
267
|
```
|
|
235
268
|
|