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.
Files changed (52) hide show
  1. {lightphe-0.0.7 → lightphe-0.0.9}/PKG-INFO +115 -82
  2. {lightphe-0.0.7 → lightphe-0.0.9}/README.md +114 -81
  3. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/__init__.py +16 -46
  4. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/Benaloh.py +3 -2
  5. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/DamgardJurik.py +2 -2
  6. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/ElGamal.py +2 -2
  7. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/EllipticCurveElGamal.py +24 -13
  8. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/GoldwasserMicali.py +3 -2
  9. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/NaccacheStern.py +3 -2
  10. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/OkamotoUchiyama.py +2 -2
  11. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/Paillier.py +2 -2
  12. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/RSA.py +2 -2
  13. lightphe-0.0.9/lightphe/elliptic_curve_forms/edwards.py +61 -0
  14. lightphe-0.0.9/lightphe/elliptic_curve_forms/weierstrass.py +75 -0
  15. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/Ciphertext.py +3 -3
  16. lightphe-0.0.9/lightphe/models/EllipticCurve.py +45 -0
  17. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/Tensor.py +9 -0
  18. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/PKG-INFO +115 -82
  19. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/SOURCES.txt +3 -2
  20. {lightphe-0.0.7 → lightphe-0.0.9}/setup.py +1 -1
  21. lightphe-0.0.9/tests/__init__.py +0 -0
  22. lightphe-0.0.9/tests/test_ellipticcurveelgamal.py +69 -0
  23. lightphe-0.0.7/lightphe/elliptic/Weierstrass.py +0 -98
  24. lightphe-0.0.7/lightphe/models/EllipticCurve.py +0 -18
  25. lightphe-0.0.7/tests/__init__.py +0 -219
  26. lightphe-0.0.7/tests/test_ellipticcurveelgamal.py +0 -64
  27. {lightphe-0.0.7 → lightphe-0.0.9}/LICENSE +0 -0
  28. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/commons/__init__.py +0 -0
  29. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/commons/logger.py +0 -0
  30. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/commons/phe_utils.py +0 -0
  31. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/cryptosystems/__init__.py +0 -0
  32. {lightphe-0.0.7/lightphe/elliptic → lightphe-0.0.9/lightphe/elliptic_curve_forms}/__init__.py +0 -0
  33. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/Algorithm.py +0 -0
  34. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/Homomorphic.py +0 -0
  35. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe/models/__init__.py +0 -0
  36. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/dependency_links.txt +0 -0
  37. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/requires.txt +0 -0
  38. {lightphe-0.0.7 → lightphe-0.0.9}/lightphe.egg-info/top_level.txt +0 -0
  39. {lightphe-0.0.7 → lightphe-0.0.9}/requirements.txt +0 -0
  40. {lightphe-0.0.7 → lightphe-0.0.9}/setup.cfg +0 -0
  41. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_benaloh.py +0 -0
  42. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_cloud.py +0 -0
  43. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_damgard.py +0 -0
  44. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_elgamal.py +0 -0
  45. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_exporting_keys.py +0 -0
  46. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_goldwasser.py +0 -0
  47. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_naccache.py +0 -0
  48. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_okamoto.py +0 -0
  49. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_paillier.py +0 -0
  50. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_rsa.py +0 -0
  51. {lightphe-0.0.7 → lightphe-0.0.9}/tests/test_salary.py +0 -0
  52. {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.7
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
- [![PyPI Downloads](https://static.pepy.tech/personalized-badge/lightphe?period=total&units=international_system&left_color=grey&right_color=blue&left_text=pypi%20downloads)](https://pepy.tech/project/lightphe)
21
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/lightphe?period=total&units=international_system&left_color=grey&right_color=blue&left_text=downloads)](https://pepy.tech/project/lightphe)
22
22
  [![Stars](https://img.shields.io/github/stars/serengil/LightPHE?color=yellow&style=flat&label=%E2%AD%90%20stars)](https://github.com/serengil/LightPHE/stargazers)
23
23
  [![Tests](https://github.com/serengil/LightPHE/actions/workflows/tests.yml/badge.svg)](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
24
24
  [![License](http://img.shields.io/:license-MIT-green.svg?style=flat)](https://github.com/serengil/LightPHE/blob/master/LICENSE)
25
- [![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dserengil%26type%3Dpatrons&style=flat)](https://www.patreon.com/serengil?repo=lightphe)
26
- [![GitHub Sponsors](https://img.shields.io/github/sponsors/serengil?logo=GitHub&color=lightgray)](https://github.com/sponsors/serengil)
25
+ [![DOI](http://img.shields.io/:DOI-10.48550/arXiv.2408.05219-blue.svg?style=flat)](https://arxiv.org/abs/2408.05219)
27
26
 
28
27
  [![Blog](https://img.shields.io/:blog-sefiks.com-blue.svg?style=flat&logo=wordpress)](https://sefiks.com)
29
28
  [![YouTube](https://img.shields.io/:youtube-@sefiks-red.svg?style=flat&logo=youtube)](https://www.youtube.com/@sefiks?sub_confirmation=1)
30
- [![Twitter](https://img.shields.io/:follow-@serengil-blue.svg?style=flat&logo=twitter)](https://twitter.com/intent/user?screen_name=serengil)
29
+ [![Twitter](https://img.shields.io/:follow-@serengil-blue.svg?style=flat&logo=x)](https://twitter.com/intent/user?screen_name=serengil)
30
+
31
+ [![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dserengil%26type%3Dpatrons&style=flat)](https://www.patreon.com/serengil?repo=lightphe)
32
+ [![GitHub Sponsors](https://img.shields.io/github/sponsors/serengil?logo=GitHub&color=lightgray)](https://github.com/sponsors/serengil)
33
+ [![Buy Me a Coffee](https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee)](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/), [`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
+ 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
- cs = LightPHE(algorithm_name = algorithms[0])
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 = cs.encrypt(m)
113
+ c = phe.encrypt(m)
111
114
 
112
- assert cs.decrypt(c) == m
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
- cs = LightPHE(algorithm_name = "Paillier")
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
- # define plaintexts
123
- m1 = 17
124
- m2 = 23
153
+ ### Homomorphic Operations on Cloud
125
154
 
126
- # calculate ciphertexts
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
- # homomorphic addition - private key is not required!
131
- c3 = c1 + c2
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
- # proof of work
134
- assert cs.decrypt(c3) == m1 + m2
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
- ⚡ 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.
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. Simply put, decryption of scalar multiplication of ciphertext is equivalent to that constant times plaintext as well.
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 cs.decrypt(c4) == k * m1
217
+ # proof of work on-prem - private key is required
218
+ assert phe.decrypt(c4) == k * m1
150
219
  ```
151
220
 
152
- ⚡ Herein, `k * c1` operation can be performed by anyone without holding private key.
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 = cs.regenerate_ciphertext(c1)
226
+ c1_prime = phe.regenerate_ciphertext(c1)
158
227
  assert c1_prime.value != c1.value
159
- assert cs.decrypt(c1_prime) == m1
160
- assert cs.decrypt(c1) == m1
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) or [GitHub Sponsors](https://github.com/sponsors/serengil).
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{serengil2023lightphe,
244
- abstract = {A Lightweight Partially Homomorphic Encryption Library for Python},
245
- author = {Serengil, Sefik Ilkin},
246
- title = {LightPHE},
247
- howpublished = {https://github.com/serengil/LightPHE},
248
- year = {2023}
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
- [![PyPI Downloads](https://static.pepy.tech/personalized-badge/lightphe?period=total&units=international_system&left_color=grey&right_color=blue&left_text=pypi%20downloads)](https://pepy.tech/project/lightphe)
5
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/lightphe?period=total&units=international_system&left_color=grey&right_color=blue&left_text=downloads)](https://pepy.tech/project/lightphe)
6
6
  [![Stars](https://img.shields.io/github/stars/serengil/LightPHE?color=yellow&style=flat&label=%E2%AD%90%20stars)](https://github.com/serengil/LightPHE/stargazers)
7
7
  [![Tests](https://github.com/serengil/LightPHE/actions/workflows/tests.yml/badge.svg)](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
8
8
  [![License](http://img.shields.io/:license-MIT-green.svg?style=flat)](https://github.com/serengil/LightPHE/blob/master/LICENSE)
9
- [![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dserengil%26type%3Dpatrons&style=flat)](https://www.patreon.com/serengil?repo=lightphe)
10
- [![GitHub Sponsors](https://img.shields.io/github/sponsors/serengil?logo=GitHub&color=lightgray)](https://github.com/sponsors/serengil)
9
+ [![DOI](http://img.shields.io/:DOI-10.48550/arXiv.2408.05219-blue.svg?style=flat)](https://arxiv.org/abs/2408.05219)
11
10
 
12
11
  [![Blog](https://img.shields.io/:blog-sefiks.com-blue.svg?style=flat&logo=wordpress)](https://sefiks.com)
13
12
  [![YouTube](https://img.shields.io/:youtube-@sefiks-red.svg?style=flat&logo=youtube)](https://www.youtube.com/@sefiks?sub_confirmation=1)
14
- [![Twitter](https://img.shields.io/:follow-@serengil-blue.svg?style=flat&logo=twitter)](https://twitter.com/intent/user?screen_name=serengil)
13
+ [![Twitter](https://img.shields.io/:follow-@serengil-blue.svg?style=flat&logo=x)](https://twitter.com/intent/user?screen_name=serengil)
14
+
15
+ [![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dserengil%26type%3Dpatrons&style=flat)](https://www.patreon.com/serengil?repo=lightphe)
16
+ [![GitHub Sponsors](https://img.shields.io/github/sponsors/serengil?logo=GitHub&color=lightgray)](https://github.com/sponsors/serengil)
17
+ [![Buy Me a Coffee](https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee)](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/), [`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/).
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
- cs = LightPHE(algorithm_name = algorithms[0])
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 = cs.encrypt(m)
97
+ c = phe.encrypt(m)
95
98
 
96
- assert cs.decrypt(c) == m
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
- cs = LightPHE(algorithm_name = "Paillier")
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
- # define plaintexts
107
- m1 = 17
108
- m2 = 23
137
+ ### Homomorphic Operations on Cloud
109
138
 
110
- # calculate ciphertexts
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
- # homomorphic addition - private key is not required!
115
- c3 = c1 + c2
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
- # proof of work
118
- assert cs.decrypt(c3) == m1 + m2
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
- ⚡ 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.
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. Simply put, decryption of scalar multiplication of ciphertext is equivalent to that constant times plaintext as well.
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 cs.decrypt(c4) == k * m1
201
+ # proof of work on-prem - private key is required
202
+ assert phe.decrypt(c4) == k * m1
134
203
  ```
135
204
 
136
- ⚡ Herein, `k * c1` operation can be performed by anyone without holding private key.
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 = cs.regenerate_ciphertext(c1)
210
+ c1_prime = phe.regenerate_ciphertext(c1)
142
211
  assert c1_prime.value != c1.value
143
- assert cs.decrypt(c1_prime) == m1
144
- assert cs.decrypt(c1) == m1
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) or [GitHub Sponsors](https://github.com/sponsors/serengil).
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{serengil2023lightphe,
228
- abstract = {A Lightweight Partially Homomorphic Encryption Library for Python},
229
- author = {Serengil, Sefik Ilkin},
230
- title = {LightPHE},
231
- howpublished = {https://github.com/serengil/LightPHE},
232
- year = {2023}
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