lightphe 0.0.1__tar.gz → 0.0.3__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 (44) hide show
  1. {lightphe-0.0.1 → lightphe-0.0.3}/PKG-INFO +44 -14
  2. {lightphe-0.0.1 → lightphe-0.0.3}/README.md +43 -13
  3. lightphe-0.0.3/lightphe/__init__.py +230 -0
  4. lightphe-0.0.3/lightphe/commons/__init__.py +0 -0
  5. lightphe-0.0.3/lightphe/commons/logger.py +39 -0
  6. lightphe-0.0.3/lightphe/cryptosystems/Benaloh.py +208 -0
  7. lightphe-0.0.3/lightphe/cryptosystems/DamgardJurik.py +177 -0
  8. lightphe-0.0.3/lightphe/cryptosystems/ElGamal.py +202 -0
  9. lightphe-0.0.3/lightphe/cryptosystems/EllipticCurveElGamal.py +168 -0
  10. lightphe-0.0.3/lightphe/cryptosystems/GoldwasserMicali.py +166 -0
  11. lightphe-0.0.3/lightphe/cryptosystems/NaccacheStern.py +301 -0
  12. lightphe-0.0.3/lightphe/cryptosystems/OkamotoUchiyama.py +180 -0
  13. lightphe-0.0.3/lightphe/cryptosystems/Paillier.py +166 -0
  14. lightphe-0.0.3/lightphe/cryptosystems/RSA.py +142 -0
  15. lightphe-0.0.3/lightphe/cryptosystems/__init__.py +0 -0
  16. lightphe-0.0.3/lightphe/elliptic/Weierstrass.py +97 -0
  17. lightphe-0.0.3/lightphe/elliptic/__init__.py +0 -0
  18. lightphe-0.0.3/lightphe/models/Algorithm.py +12 -0
  19. lightphe-0.0.3/lightphe/models/Ciphertext.py +141 -0
  20. lightphe-0.0.3/lightphe/models/EllipticCurve.py +18 -0
  21. lightphe-0.0.3/lightphe/models/Homomorphic.py +53 -0
  22. lightphe-0.0.3/lightphe/models/__init__.py +0 -0
  23. {lightphe-0.0.1 → lightphe-0.0.3}/lightphe.egg-info/PKG-INFO +44 -14
  24. lightphe-0.0.3/lightphe.egg-info/SOURCES.txt +40 -0
  25. lightphe-0.0.3/lightphe.egg-info/top_level.txt +2 -0
  26. {lightphe-0.0.1 → lightphe-0.0.3}/setup.py +1 -1
  27. lightphe-0.0.3/tests/__init__.py +219 -0
  28. lightphe-0.0.3/tests/test_benaloh.py +63 -0
  29. lightphe-0.0.3/tests/test_cloud.py +44 -0
  30. lightphe-0.0.3/tests/test_damgard.py +63 -0
  31. lightphe-0.0.3/tests/test_elgamal.py +139 -0
  32. lightphe-0.0.3/tests/test_ellipticcurveelgamal.py +64 -0
  33. lightphe-0.0.3/tests/test_goldwasser.py +64 -0
  34. lightphe-0.0.3/tests/test_naccache.py +94 -0
  35. lightphe-0.0.3/tests/test_okamoto.py +61 -0
  36. lightphe-0.0.3/tests/test_paillier.py +97 -0
  37. lightphe-0.0.3/tests/test_rsa.py +65 -0
  38. lightphe-0.0.3/tests/test_salary.py +53 -0
  39. lightphe-0.0.1/lightphe.egg-info/SOURCES.txt +0 -8
  40. lightphe-0.0.1/lightphe.egg-info/top_level.txt +0 -1
  41. {lightphe-0.0.1 → lightphe-0.0.3}/LICENSE +0 -0
  42. {lightphe-0.0.1 → lightphe-0.0.3}/lightphe.egg-info/dependency_links.txt +0 -0
  43. {lightphe-0.0.1 → lightphe-0.0.3}/lightphe.egg-info/requires.txt +0 -0
  44. {lightphe-0.0.1 → lightphe-0.0.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightphe
3
- Version: 0.0.1
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
@@ -31,13 +31,21 @@ License-File: LICENSE
31
31
 
32
32
  </div>
33
33
 
34
- <p align="center"><img src="icons/phi.png" width="200" height="240"></p>
34
+ <p align="center"><img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/phi.png" width="200" height="240"></p>
35
35
 
36
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/).
37
37
 
38
- 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. LightPHE is notably faster and demands fewer computational resources compared to FHE. Besides, it generates smaller ciphertexts, making it well-suited for memory-constrained environments. Finally, LightPHE strikes a favorable balance between security and efficiency for practical use cases.
38
+ # Partially vs Fully Homomorphic Encryption
39
39
 
40
- # Installation
40
+ 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.
41
+
42
+ - 🏎️ Notably faster
43
+ - 💻 Demands fewer computational resources
44
+ - 📏 Generating smaller ciphertexts
45
+ - 🧠 Well-suited for memory-constrained environments
46
+ - ⚖️ Strikes a favorable balance for practical use cases
47
+
48
+ # Installation [![PyPI](https://img.shields.io/pypi/v/lightphe.svg)](https://pypi.org/project/lightphe/)
41
49
 
42
50
  The easiest way to install the LightPHE package is to install it from python package index (PyPI).
43
51
 
@@ -118,18 +126,30 @@ m2 = 23
118
126
  c1 = cs.encrypt(m1)
119
127
  c2 = cs.encrypt(m2)
120
128
 
121
- # performing homomorphic addition on ciphertexts
122
- assert cs.decrypt(c1 + c2) == m1 + m2
129
+ # homomorphic addition - private key is not required!
130
+ c3 = c1 + c2
131
+
132
+ # proof of work
133
+ assert cs.decrypt(c3) == m1 + m2
123
134
  ```
124
135
 
125
- 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.
136
+ ⚡ 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.
137
+
138
+ 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.
126
139
 
127
140
  ```python
128
- # scalar multiplication
129
- k = 5
130
- assert cs.decrypt(k * c1) == k * m1
141
+ # increasing something 5%
142
+ k = 1.05
143
+
144
+ # scalar multiplication - private key is not required!
145
+ c4 = k * c1
146
+
147
+ # proof of work
148
+ assert cs.decrypt(c4) == k * m1
131
149
  ```
132
150
 
151
+ ⚡ Herein, `k * c1` operation can be performed by anyone without holding private key.
152
+
133
153
  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.
134
154
 
135
155
  ```python
@@ -142,11 +162,11 @@ assert cs.decrypt(c1) == m1
142
162
  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.
143
163
 
144
164
  ```python
145
- # pailier is not homomorphic with respect to the multiplication
165
+ # pailier is not multiplicatively homomorphic
146
166
  with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the multiplication"):
147
167
  c1 * c2
148
168
 
149
- # pailier is not homomorphic with respect to the xor
169
+ # pailier is not exclusively homomorphic
150
170
  with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the exclusive or"):
151
171
  c1 ^ c2
152
172
  ```
@@ -159,6 +179,16 @@ All PRs are more than welcome! If you are planning to contribute a large patch,
159
179
 
160
180
  You should be able run `make test` and `make lint` commands successfully before committing. Once a PR is created, GitHub test workflow will be run automatically and unit test results will be available in [GitHub actions](https://github.com/serengil/LightPHE/actions/workflows/tests.yml) before approval. Besides, workflow will evaluate the code with pylint as well.
161
181
 
182
+ # Support
183
+
184
+ There are many ways to support a project - starring⭐️ the GitHub repo is just one 🙏
185
+
186
+ You can also support this work on [Patreon](https://www.patreon.com/serengil?repo=lightphe) or [GitHub Sponsors](https://github.com/sponsors/serengil).
187
+
188
+ <a href="https://www.patreon.com/serengil?repo=lightphe">
189
+ <img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/patreon.png" width="30%" height="30%">
190
+ </a>
191
+
162
192
  # Citation
163
193
 
164
194
  Please cite LightPHE in your publications if it helps your research. Here is its BibTex entry:
@@ -173,10 +203,10 @@ Please cite LightPHE in your publications if it helps your research. Here is its
173
203
  }
174
204
  ```
175
205
 
176
- Also, if you use LightPHE in your projects, please add `LightPHE` in the `requirements.txt`.
206
+ Also, if you use LightPHE in your projects, please add `lightphe` in the `requirements.txt`.
177
207
 
178
208
  # License
179
209
 
180
- LightPHE is licensed under the MIT License - see [`LICENSE`](LICENSE) for more details.
210
+ LightPHE is licensed under the MIT License - see [`LICENSE`](https://github.com/serengil/LightPHE/blob/master/LICENSE) for more details.
181
211
 
182
212
 
@@ -15,13 +15,21 @@
15
15
 
16
16
  </div>
17
17
 
18
- <p align="center"><img src="icons/phi.png" width="200" height="240"></p>
18
+ <p align="center"><img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/phi.png" width="200" height="240"></p>
19
19
 
20
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/).
21
21
 
22
- 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. LightPHE is notably faster and demands fewer computational resources compared to FHE. Besides, it generates smaller ciphertexts, making it well-suited for memory-constrained environments. Finally, LightPHE strikes a favorable balance between security and efficiency for practical use cases.
22
+ # Partially vs Fully Homomorphic Encryption
23
23
 
24
- # Installation
24
+ 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.
25
+
26
+ - 🏎️ Notably faster
27
+ - 💻 Demands fewer computational resources
28
+ - 📏 Generating smaller ciphertexts
29
+ - 🧠 Well-suited for memory-constrained environments
30
+ - ⚖️ Strikes a favorable balance for practical use cases
31
+
32
+ # Installation [![PyPI](https://img.shields.io/pypi/v/lightphe.svg)](https://pypi.org/project/lightphe/)
25
33
 
26
34
  The easiest way to install the LightPHE package is to install it from python package index (PyPI).
27
35
 
@@ -102,18 +110,30 @@ m2 = 23
102
110
  c1 = cs.encrypt(m1)
103
111
  c2 = cs.encrypt(m2)
104
112
 
105
- # performing homomorphic addition on ciphertexts
106
- assert cs.decrypt(c1 + c2) == m1 + m2
113
+ # homomorphic addition - private key is not required!
114
+ c3 = c1 + c2
115
+
116
+ # proof of work
117
+ assert cs.decrypt(c3) == m1 + m2
107
118
  ```
108
119
 
109
- 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.
120
+ ⚡ 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.
121
+
122
+ 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.
110
123
 
111
124
  ```python
112
- # scalar multiplication
113
- k = 5
114
- assert cs.decrypt(k * c1) == k * m1
125
+ # increasing something 5%
126
+ k = 1.05
127
+
128
+ # scalar multiplication - private key is not required!
129
+ c4 = k * c1
130
+
131
+ # proof of work
132
+ assert cs.decrypt(c4) == k * m1
115
133
  ```
116
134
 
135
+ ⚡ Herein, `k * c1` operation can be performed by anyone without holding private key.
136
+
117
137
  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.
118
138
 
119
139
  ```python
@@ -126,11 +146,11 @@ assert cs.decrypt(c1) == m1
126
146
  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.
127
147
 
128
148
  ```python
129
- # pailier is not homomorphic with respect to the multiplication
149
+ # pailier is not multiplicatively homomorphic
130
150
  with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the multiplication"):
131
151
  c1 * c2
132
152
 
133
- # pailier is not homomorphic with respect to the xor
153
+ # pailier is not exclusively homomorphic
134
154
  with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the exclusive or"):
135
155
  c1 ^ c2
136
156
  ```
@@ -143,6 +163,16 @@ All PRs are more than welcome! If you are planning to contribute a large patch,
143
163
 
144
164
  You should be able run `make test` and `make lint` commands successfully before committing. Once a PR is created, GitHub test workflow will be run automatically and unit test results will be available in [GitHub actions](https://github.com/serengil/LightPHE/actions/workflows/tests.yml) before approval. Besides, workflow will evaluate the code with pylint as well.
145
165
 
166
+ # Support
167
+
168
+ There are many ways to support a project - starring⭐️ the GitHub repo is just one 🙏
169
+
170
+ You can also support this work on [Patreon](https://www.patreon.com/serengil?repo=lightphe) or [GitHub Sponsors](https://github.com/sponsors/serengil).
171
+
172
+ <a href="https://www.patreon.com/serengil?repo=lightphe">
173
+ <img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/patreon.png" width="30%" height="30%">
174
+ </a>
175
+
146
176
  # Citation
147
177
 
148
178
  Please cite LightPHE in your publications if it helps your research. Here is its BibTex entry:
@@ -157,8 +187,8 @@ Please cite LightPHE in your publications if it helps your research. Here is its
157
187
  }
158
188
  ```
159
189
 
160
- Also, if you use LightPHE in your projects, please add `LightPHE` in the `requirements.txt`.
190
+ Also, if you use LightPHE in your projects, please add `lightphe` in the `requirements.txt`.
161
191
 
162
192
  # License
163
193
 
164
- LightPHE is licensed under the MIT License - see [`LICENSE`](LICENSE) for more details.
194
+ LightPHE is licensed under the MIT License - see [`LICENSE`](https://github.com/serengil/LightPHE/blob/master/LICENSE) for more details.
@@ -0,0 +1,230 @@
1
+ import json
2
+ from typing import Optional, Union
3
+
4
+ from lightphe.models.Ciphertext import Ciphertext
5
+ from lightphe.models.Algorithm import Algorithm
6
+ from lightphe.cryptosystems.RSA import RSA
7
+ from lightphe.cryptosystems.ElGamal import ElGamal
8
+ from lightphe.cryptosystems.Paillier import Paillier
9
+ from lightphe.cryptosystems.DamgardJurik import DamgardJurik
10
+ from lightphe.cryptosystems.OkamotoUchiyama import OkamotoUchiyama
11
+ from lightphe.cryptosystems.Benaloh import Benaloh
12
+ from lightphe.cryptosystems.NaccacheStern import NaccacheStern
13
+ from lightphe.cryptosystems.GoldwasserMicali import GoldwasserMicali
14
+ from lightphe.cryptosystems.EllipticCurveElGamal import EllipticCurveElGamal
15
+ from lightphe.commons.logger import Logger
16
+
17
+ # pylint: disable=eval-used
18
+
19
+ logger = Logger()
20
+
21
+
22
+ class LightPHE:
23
+ def __init__(
24
+ self,
25
+ algorithm_name: str,
26
+ keys: Optional[dict] = None,
27
+ key_file: Optional[str] = None,
28
+ key_size: Optional[int] = None,
29
+ ):
30
+ """
31
+ Build LightPHE class
32
+ Args:
33
+ algorithm_name (str): RSA | ElGamal | Exponential-ElGamal | EllipticCurve-ElGamal
34
+ | Paillier | Damgard-Jurik | Okamoto-Uchiyama | Benaloh | Naccache-Stern
35
+ | Goldwasser-Micali
36
+ keys (dict): optional private-public key pair
37
+ key_file (str): if keys are exported, you can load them into cryptosystem
38
+ key_size (int): key size in bits
39
+ """
40
+ self.algorithm_name = algorithm_name
41
+
42
+ if key_file is not None:
43
+ keys = self.restore_keys(target_file=key_file)
44
+
45
+ self.cs = self.build_cryptosystem(
46
+ algorithm_name=algorithm_name, keys=keys, key_size=key_size
47
+ )
48
+
49
+ def build_cryptosystem(
50
+ self,
51
+ algorithm_name: str,
52
+ keys: Optional[dict] = None,
53
+ key_size: Optional[int] = None,
54
+ ) -> Union[
55
+ RSA,
56
+ ElGamal,
57
+ Paillier,
58
+ DamgardJurik,
59
+ OkamotoUchiyama,
60
+ Benaloh,
61
+ NaccacheStern,
62
+ EllipticCurveElGamal,
63
+ ]:
64
+ """
65
+ Build a cryptosystem among partially homomorphic algorithms
66
+ Args:
67
+ algorithm_name (str): RSA | ElGamal | Exponential-ElGamal | EllipticCurve-ElGamal
68
+ | Paillier | Damgard-Jurik | Okamoto-Uchiyama | Benaloh | Naccache-Stern
69
+ | Goldwasser-Micali
70
+ keys (dict): optional private-public key pair
71
+ key_file (str): if keys are exported, you can load them into cryptosystem
72
+ key_size (int): key size in bits
73
+ Returns
74
+ cryptosystem
75
+ """
76
+
77
+ if key_size is None:
78
+ key_size = self.recommend_key_size(algorithm_name=algorithm_name)
79
+
80
+ # build cryptosystem
81
+ if algorithm_name == Algorithm.RSA:
82
+ cs = RSA(keys=keys, key_size=key_size)
83
+ elif algorithm_name == Algorithm.ElGamal:
84
+ cs = ElGamal(keys=keys, key_size=key_size)
85
+ elif algorithm_name == Algorithm.ExponentialElGamal:
86
+ cs = ElGamal(keys=keys, key_size=key_size, exponential=True)
87
+ elif algorithm_name == Algorithm.EllipticCurveElGamal:
88
+ cs = EllipticCurveElGamal(keys=keys, key_size=key_size)
89
+ elif algorithm_name == Algorithm.Paillier:
90
+ cs = Paillier(keys=keys, key_size=key_size)
91
+ elif algorithm_name == Algorithm.DamgardJurik:
92
+ cs = DamgardJurik(keys=keys, key_size=key_size)
93
+ elif algorithm_name == Algorithm.OkamotoUchiyama:
94
+ cs = OkamotoUchiyama(keys=keys, key_size=key_size)
95
+ elif algorithm_name == Algorithm.Benaloh:
96
+ cs = Benaloh(keys=keys, key_size=key_size)
97
+ elif algorithm_name == Algorithm.NaccacheStern:
98
+ cs = NaccacheStern(keys=keys, key_size=key_size)
99
+ elif algorithm_name == Algorithm.GoldwasserMicali:
100
+ cs = GoldwasserMicali(keys=keys, key_size=key_size)
101
+ else:
102
+ raise ValueError(f"unimplemented algorithm - {algorithm_name}")
103
+ return cs
104
+
105
+ def encrypt(self, plaintext: int) -> Ciphertext:
106
+ """
107
+ Encrypt a plaintext with a built cryptosystem
108
+ Args:
109
+ plaintext (int): message
110
+ Returns
111
+ ciphertext (from lightphe.models.Ciphertext import Ciphertext): encrypted message
112
+ """
113
+ ciphertext = self.cs.encrypt(plaintext=plaintext)
114
+ return Ciphertext(algorithm_name=self.algorithm_name, keys=self.cs.keys, value=ciphertext)
115
+
116
+ def decrypt(self, ciphertext: Ciphertext) -> int:
117
+ """
118
+ Decrypt a ciphertext with a buit cryptosystem
119
+ Args:
120
+ ciphertext (from lightphe.models.Ciphertext import Ciphertext): encrypted message
121
+ Returns:
122
+ plaintext (int): restored message
123
+ """
124
+ return self.cs.decrypt(ciphertext=ciphertext.value)
125
+
126
+ def regenerate_ciphertext(self, ciphertext: Ciphertext) -> Ciphertext:
127
+ """
128
+ Generate a different ciphertext belonging to same plaintext
129
+ Args:
130
+ ciphertext (from lightphe.models.Ciphertext import Ciphertext): encrypted message
131
+ Returns:
132
+ ciphertext (from lightphe.models.Ciphertext import Ciphertext): encrypted message
133
+ """
134
+ ciphertext_new = self.cs.reencrypt(ciphertext=ciphertext.value)
135
+ return Ciphertext(
136
+ algorithm_name=self.algorithm_name, keys=self.cs.keys, value=ciphertext_new
137
+ )
138
+
139
+ def export_keys(self, target_file: str, public: bool = False) -> None:
140
+ """
141
+ Export keys to a file
142
+ Args:
143
+ target_file (str): target file name
144
+ public (bool): set this to True if you will publish this
145
+ to publicly.
146
+ """
147
+ keys = self.cs.keys
148
+ if public is True and keys.get("private_key") is not None:
149
+ del keys["private_key"]
150
+
151
+ if public is False:
152
+ logger.warn(
153
+ "You did not set public arg to True. So, exported key has private key information."
154
+ "Do not share this to anyone"
155
+ )
156
+
157
+ with open(target_file, "w", encoding="UTF-8") as file:
158
+ file.write(json.dumps(keys))
159
+
160
+ def restore_keys(self, target_file: str) -> dict:
161
+ """
162
+ Restore keys from a file
163
+ Args:
164
+ target_file (str): target file name
165
+ Returns:
166
+ keys (dict): private public key pair
167
+ """
168
+ with open(target_file, "r", encoding="UTF-8") as file:
169
+ dict_str = file.read()
170
+
171
+ keys = eval(dict_str)
172
+ if not isinstance(keys, dict):
173
+ raise ValueError(
174
+ f"The content of the file {target_file} does not represent a valid dictionary."
175
+ )
176
+
177
+ if "private_key" in keys.keys():
178
+ logger.info(f"private-public key pair is restored from {target_file}")
179
+ elif "public_key" in keys.keys():
180
+ logger.info(f"public key is restored from {target_file}")
181
+ else:
182
+ raise ValueError(f"File {target_file} must have public_key key")
183
+ return keys
184
+
185
+ def recommend_key_size(self, algorithm_name: str) -> int:
186
+ """
187
+ Recommend a key size in bits if it is not mentioned by the user
188
+ Args:
189
+ algorithm_name (str): algorithm name
190
+ Returns
191
+ key_size (int)
192
+ """
193
+ if algorithm_name == Algorithm.RSA:
194
+ key_size = 1024
195
+ elif algorithm_name == Algorithm.ElGamal:
196
+ key_size = 1024
197
+ elif algorithm_name == Algorithm.ExponentialElGamal:
198
+ key_size = 1024
199
+ # 160-bit ECC is equivalent to 1024-bit RSA
200
+ elif algorithm_name == Algorithm.EllipticCurveElGamal:
201
+ key_size = 160
202
+ elif algorithm_name == Algorithm.Paillier:
203
+ key_size = 1024
204
+ elif algorithm_name == Algorithm.DamgardJurik:
205
+ key_size = 1024
206
+ elif algorithm_name == Algorithm.OkamotoUchiyama:
207
+ key_size = 1024
208
+ # n should be several hundred bits or more
209
+ elif algorithm_name == Algorithm.GoldwasserMicali:
210
+ key_size = 100
211
+ # Benaloh and Naccache-Stern require to solve DLP in decryption
212
+ # so small key is recommended
213
+ elif algorithm_name == Algorithm.Benaloh:
214
+ key_size = 50
215
+ elif algorithm_name == Algorithm.NaccacheStern:
216
+ key_size = 37
217
+ else:
218
+ raise ValueError(f"unimplemented algorithm - {algorithm_name}")
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)
File without changes
@@ -0,0 +1,39 @@
1
+ import os
2
+ import logging
3
+ from datetime import datetime
4
+
5
+
6
+ class Logger:
7
+ def __init__(self):
8
+ log_level = os.environ.get("LIGHTPHE_LOG_LEVEL", str(logging.INFO))
9
+ try:
10
+ self.log_level = int(log_level)
11
+ except Exception as err:
12
+ self.dump_log(
13
+ f"Exception while parsing $LIGHTPHE_LOG_LEVEL."
14
+ f"Expected int but it is {log_level} ({str(err)})"
15
+ )
16
+ self.log_level = logging.INFO
17
+
18
+ def debug(self, message):
19
+ if self.log_level <= logging.DEBUG:
20
+ self.dump_log(message)
21
+
22
+ def info(self, message):
23
+ if self.log_level <= logging.INFO:
24
+ self.dump_log(message)
25
+
26
+ def warn(self, message):
27
+ if self.log_level <= logging.WARNING:
28
+ self.dump_log(message)
29
+
30
+ def error(self, message):
31
+ if self.log_level <= logging.ERROR:
32
+ self.dump_log(message)
33
+
34
+ def critical(self, message):
35
+ if self.log_level <= logging.CRITICAL:
36
+ self.dump_log(message)
37
+
38
+ def dump_log(self, message):
39
+ print(f"{str(datetime.now())[2:-7]} - {message}")