lightphe 0.0.18__tar.gz → 0.0.20__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.18 → lightphe-0.0.20}/PKG-INFO +11 -6
- {lightphe-0.0.18 → lightphe-0.0.20}/README.md +10 -5
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/__init__.py +23 -5
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/Benaloh.py +5 -1
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/GoldwasserMicali.py +10 -2
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/NaccacheStern.py +5 -1
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/RSA.py +41 -25
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/PKG-INFO +11 -6
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/requires.txt +0 -1
- lightphe-0.0.20/requirements.txt +3 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/setup.py +1 -1
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_large_keys.py +5 -4
- lightphe-0.0.18/requirements.txt +0 -4
- {lightphe-0.0.18 → lightphe-0.0.20}/LICENSE +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/commons/__init__.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/commons/logger.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/commons/phe_utils.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/DamgardJurik.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/ElGamal.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/EllipticCurveElGamal.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/OkamotoUchiyama.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/Paillier.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/cryptosystems/__init__.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/Algorithm.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/Ciphertext.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/Homomorphic.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/Tensor.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe/models/__init__.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/SOURCES.txt +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/dependency_links.txt +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/lightphe.egg-info/top_level.txt +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/setup.cfg +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/__init__.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_benaloh.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_ciphertexts.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_cloud.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_damgard.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_elgamal.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_ellipticcurveelgamal.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_exporting_keys.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_goldwasser.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_keys.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_naccache.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_okamoto.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_paillier.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_rsa.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/tests/test_salary.py +0 -0
- {lightphe-0.0.18 → lightphe-0.0.20}/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.20
|
|
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
|
|
@@ -129,7 +129,7 @@ assert cs.decrypt(c3) == m1 + m2
|
|
|
129
129
|
assert cs.decrypt(c4) == k * m1
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
On the other hand, if you adopt a multiplicatively homomorphic
|
|
132
|
+
On the other hand, if you adopt a multiplicatively homomorphic cryptosystem (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
|
|
133
133
|
|
|
134
134
|
```python
|
|
135
135
|
# build a multiplicatively homomorphic cryptosystem
|
|
@@ -152,7 +152,7 @@ assert cs.decrypt(c3) == m1 * m2
|
|
|
152
152
|
|
|
153
153
|
### Ciphertext Regeneration
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
The most of additively homomorphic algorithms allow 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.
|
|
156
156
|
|
|
157
157
|
```python
|
|
158
158
|
c1_prime = cs.regenerate_ciphertext(c1)
|
|
@@ -163,7 +163,7 @@ assert cs.decrypt(c1) == m1
|
|
|
163
163
|
|
|
164
164
|
### Elliptic Curve Cryptography
|
|
165
165
|
|
|
166
|
-
ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass, edwards and koblitz) and 100+ standard elliptic curve configurations.
|
|
166
|
+
ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass (default), edwards and koblitz) and 100+ standard elliptic curve configurations.
|
|
167
167
|
|
|
168
168
|
In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic-curve-elgamal-encryption/) scheme is implemented, offering a secure and efficient homomorphic encryption option.
|
|
169
169
|
|
|
@@ -171,7 +171,8 @@ In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic
|
|
|
171
171
|
forms = ["weierstrass", "edwards", "koblitz"]
|
|
172
172
|
phe = LightPHE(
|
|
173
173
|
algorithm_name="EllipticCurve-ElGamal",
|
|
174
|
-
form=
|
|
174
|
+
form="edwards",
|
|
175
|
+
# curve="ed448", # optinally you can specify the curve for given form
|
|
175
176
|
)
|
|
176
177
|
```
|
|
177
178
|
|
|
@@ -204,12 +205,16 @@ c4 = c1 + c2
|
|
|
204
205
|
c5 = 3 * c1
|
|
205
206
|
|
|
206
207
|
# perform element-wise multiplication between an encrypted embedding and plain embedding
|
|
207
|
-
c6 = c1 * t3
|
|
208
|
+
c6 = c1 * t3
|
|
209
|
+
|
|
210
|
+
# encrypted dot product (likewise cosine similarity)
|
|
211
|
+
c7 = c1 @ t3
|
|
208
212
|
|
|
209
213
|
# proof of work
|
|
210
214
|
assert np.allclose(cs.decrypt(c4), [a + b for a, b in zip(t1, t2)], rtol=1e-2)
|
|
211
215
|
assert np.allclose(cs.decrypt(c5), [a * 3 for a in t1], rtol=1e-2)
|
|
212
216
|
assert np.allclose(cs.decrypt(c6), [a * b for a, b in zip(t1, t3)], rtol=1e-2)
|
|
217
|
+
assert np.allclose(cs.decrypt(c7)[0], sum([a * b for a, b in zip(t1, t3)]), rtol=1e-2)
|
|
213
218
|
```
|
|
214
219
|
|
|
215
220
|
# Contributing
|
|
@@ -113,7 +113,7 @@ assert cs.decrypt(c3) == m1 + m2
|
|
|
113
113
|
assert cs.decrypt(c4) == k * m1
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
-
On the other hand, if you adopt a multiplicatively homomorphic
|
|
116
|
+
On the other hand, if you adopt a multiplicatively homomorphic cryptosystem (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
|
|
117
117
|
|
|
118
118
|
```python
|
|
119
119
|
# build a multiplicatively homomorphic cryptosystem
|
|
@@ -136,7 +136,7 @@ assert cs.decrypt(c3) == m1 * m2
|
|
|
136
136
|
|
|
137
137
|
### Ciphertext Regeneration
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
The most of additively homomorphic algorithms allow 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.
|
|
140
140
|
|
|
141
141
|
```python
|
|
142
142
|
c1_prime = cs.regenerate_ciphertext(c1)
|
|
@@ -147,7 +147,7 @@ assert cs.decrypt(c1) == m1
|
|
|
147
147
|
|
|
148
148
|
### Elliptic Curve Cryptography
|
|
149
149
|
|
|
150
|
-
ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass, edwards and koblitz) and 100+ standard elliptic curve configurations.
|
|
150
|
+
ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass (default), edwards and koblitz) and 100+ standard elliptic curve configurations.
|
|
151
151
|
|
|
152
152
|
In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic-curve-elgamal-encryption/) scheme is implemented, offering a secure and efficient homomorphic encryption option.
|
|
153
153
|
|
|
@@ -155,7 +155,8 @@ In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic
|
|
|
155
155
|
forms = ["weierstrass", "edwards", "koblitz"]
|
|
156
156
|
phe = LightPHE(
|
|
157
157
|
algorithm_name="EllipticCurve-ElGamal",
|
|
158
|
-
form=
|
|
158
|
+
form="edwards",
|
|
159
|
+
# curve="ed448", # optinally you can specify the curve for given form
|
|
159
160
|
)
|
|
160
161
|
```
|
|
161
162
|
|
|
@@ -188,12 +189,16 @@ c4 = c1 + c2
|
|
|
188
189
|
c5 = 3 * c1
|
|
189
190
|
|
|
190
191
|
# perform element-wise multiplication between an encrypted embedding and plain embedding
|
|
191
|
-
c6 = c1 * t3
|
|
192
|
+
c6 = c1 * t3
|
|
193
|
+
|
|
194
|
+
# encrypted dot product (likewise cosine similarity)
|
|
195
|
+
c7 = c1 @ t3
|
|
192
196
|
|
|
193
197
|
# proof of work
|
|
194
198
|
assert np.allclose(cs.decrypt(c4), [a + b for a, b in zip(t1, t2)], rtol=1e-2)
|
|
195
199
|
assert np.allclose(cs.decrypt(c5), [a * 3 for a in t1], rtol=1e-2)
|
|
196
200
|
assert np.allclose(cs.decrypt(c6), [a * b for a, b in zip(t1, t3)], rtol=1e-2)
|
|
201
|
+
assert np.allclose(cs.decrypt(c7)[0], sum([a * b for a, b in zip(t1, t3)]), rtol=1e-2)
|
|
197
202
|
```
|
|
198
203
|
|
|
199
204
|
# Contributing
|
|
@@ -34,7 +34,7 @@ from lightphe.cryptosystems.EllipticCurveElGamal import EllipticCurveElGamal
|
|
|
34
34
|
|
|
35
35
|
logger = Logger(module="lightphe/__init__.py")
|
|
36
36
|
|
|
37
|
-
VERSION = "0.0.
|
|
37
|
+
VERSION = "0.0.20"
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class LightPHE:
|
|
@@ -50,6 +50,7 @@ class LightPHE:
|
|
|
50
50
|
form: Optional[str] = None,
|
|
51
51
|
curve: Optional[str] = None,
|
|
52
52
|
plaintext_limit: Optional[int] = None,
|
|
53
|
+
max_tries: int = 10000,
|
|
53
54
|
):
|
|
54
55
|
"""
|
|
55
56
|
Build LightPHE class
|
|
@@ -74,6 +75,10 @@ class LightPHE:
|
|
|
74
75
|
This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
|
|
75
76
|
plaintext_limit (int, optional): Upper bound for plaintext values.
|
|
76
77
|
This parameter is only used if `algorithm_name` is 'Benaloh'.
|
|
78
|
+
max_tries (int): maximum attempts to generate keys. Default is 10000.
|
|
79
|
+
RSA, Benaloh, Naccache-Stern and Goldwasser-Micali algorithms
|
|
80
|
+
need multiple attempts to generate valid keys. Will be discarded
|
|
81
|
+
for other algorithms.
|
|
77
82
|
"""
|
|
78
83
|
self.algorithm_name = algorithm_name
|
|
79
84
|
self.precision = precision
|
|
@@ -90,6 +95,7 @@ class LightPHE:
|
|
|
90
95
|
form=form,
|
|
91
96
|
curve=curve,
|
|
92
97
|
plaintext_limit=plaintext_limit,
|
|
98
|
+
max_tries=max_tries,
|
|
93
99
|
)
|
|
94
100
|
|
|
95
101
|
def __build_cryptosystem(
|
|
@@ -100,6 +106,7 @@ class LightPHE:
|
|
|
100
106
|
form: Optional[str] = None,
|
|
101
107
|
curve: Optional[str] = None,
|
|
102
108
|
plaintext_limit: Optional[int] = None,
|
|
109
|
+
max_tries: int = 10000,
|
|
103
110
|
) -> Union[
|
|
104
111
|
RSA,
|
|
105
112
|
ElGamal,
|
|
@@ -128,12 +135,18 @@ class LightPHE:
|
|
|
128
135
|
- ed25519, ed448 for edwards form
|
|
129
136
|
- secp256k1 for weierstrass form
|
|
130
137
|
This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
|
|
138
|
+
plaintext_limit (int, optional): Upper bound for plaintext values.
|
|
139
|
+
This parameter is only used if `algorithm_name` is 'Benaloh'.
|
|
140
|
+
max_tries (int): maximum attempts to generate keys. Default is 10000.
|
|
141
|
+
RSA, Benaloh, Naccache-Stern and Goldwasser-Micali algorithms
|
|
142
|
+
need multiple attempts to generate valid keys. Will be discarded
|
|
143
|
+
for other algorithms.
|
|
131
144
|
Returns
|
|
132
145
|
cryptosystem
|
|
133
146
|
"""
|
|
134
147
|
# build cryptosystem
|
|
135
148
|
if algorithm_name == Algorithm.RSA:
|
|
136
|
-
cs = RSA(keys=keys, key_size=key_size)
|
|
149
|
+
cs = RSA(keys=keys, key_size=key_size, max_tries=max_tries)
|
|
137
150
|
elif algorithm_name == Algorithm.ElGamal:
|
|
138
151
|
cs = ElGamal(keys=keys, key_size=key_size)
|
|
139
152
|
elif algorithm_name == Algorithm.ExponentialElGamal:
|
|
@@ -149,11 +162,16 @@ class LightPHE:
|
|
|
149
162
|
elif algorithm_name == Algorithm.OkamotoUchiyama:
|
|
150
163
|
cs = OkamotoUchiyama(keys=keys, key_size=key_size)
|
|
151
164
|
elif algorithm_name == Algorithm.Benaloh:
|
|
152
|
-
cs = Benaloh(
|
|
165
|
+
cs = Benaloh(
|
|
166
|
+
keys=keys,
|
|
167
|
+
key_size=key_size,
|
|
168
|
+
plaintext_limit=plaintext_limit,
|
|
169
|
+
max_tries=max_tries,
|
|
170
|
+
)
|
|
153
171
|
elif algorithm_name == Algorithm.NaccacheStern:
|
|
154
|
-
cs = NaccacheStern(keys=keys, key_size=key_size)
|
|
172
|
+
cs = NaccacheStern(keys=keys, key_size=key_size, max_tries=max_tries)
|
|
155
173
|
elif algorithm_name == Algorithm.GoldwasserMicali:
|
|
156
|
-
cs = GoldwasserMicali(keys=keys, key_size=key_size)
|
|
174
|
+
cs = GoldwasserMicali(keys=keys, key_size=key_size, max_tries=max_tries)
|
|
157
175
|
else:
|
|
158
176
|
raise ValueError(f"unimplemented algorithm - {algorithm_name}")
|
|
159
177
|
return cs
|
|
@@ -20,6 +20,7 @@ class Benaloh(Homomorphic):
|
|
|
20
20
|
keys: Optional[dict] = None,
|
|
21
21
|
key_size: Optional[int] = None,
|
|
22
22
|
plaintext_limit: Optional[int] = None,
|
|
23
|
+
max_tries: int = 10000,
|
|
23
24
|
):
|
|
24
25
|
"""
|
|
25
26
|
Args:
|
|
@@ -29,9 +30,12 @@ class Benaloh(Homomorphic):
|
|
|
29
30
|
plaintext_limit (int, optional): Upper bound for plaintext values.
|
|
30
31
|
If provided, r is set to the next prime greater than this value;
|
|
31
32
|
otherwise, r is chosen randomly from a default range.
|
|
33
|
+
max_tries (int): maximum attempts to generate keys.
|
|
32
34
|
"""
|
|
33
35
|
self.keys = keys or self.generate_keys(
|
|
34
|
-
key_size=key_size or 1024,
|
|
36
|
+
key_size=key_size or 1024,
|
|
37
|
+
plaintext_limit=plaintext_limit,
|
|
38
|
+
max_tries=max_tries,
|
|
35
39
|
)
|
|
36
40
|
self.plaintext_modulo = self.keys["public_key"]["r"]
|
|
37
41
|
self.ciphertext_modulo = self.keys["public_key"]["n"]
|
|
@@ -23,15 +23,23 @@ class GoldwasserMicali(Homomorphic):
|
|
|
23
23
|
Ref: sefiks.com/2023/10/27/a-step-by-step-partially-homomorphic-encryption-example-with-goldwasser-micali-in-python/
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
|
-
def __init__(
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
keys: Optional[dict] = None,
|
|
29
|
+
key_size: Optional[int] = None,
|
|
30
|
+
max_tries: int = 10000,
|
|
31
|
+
):
|
|
27
32
|
"""
|
|
28
33
|
Args:
|
|
29
34
|
keys (dict): private - public key pair.
|
|
30
35
|
set this to None if you want to generate random keys.
|
|
31
36
|
key_size (int): key size in bits
|
|
37
|
+
max_tries (int): maximum attempts to generate keys
|
|
32
38
|
"""
|
|
33
39
|
|
|
34
|
-
self.keys = keys or self.generate_keys(
|
|
40
|
+
self.keys = keys or self.generate_keys(
|
|
41
|
+
key_size=key_size or 1024, max_tries=max_tries
|
|
42
|
+
)
|
|
35
43
|
self.ciphertext_modulo = self.keys["public_key"]["n"]
|
|
36
44
|
|
|
37
45
|
# Plaintext can be any integer (even larger than n) because it is internally
|
|
@@ -25,6 +25,7 @@ class NaccacheStern(Homomorphic):
|
|
|
25
25
|
keys: Optional[dict] = None,
|
|
26
26
|
key_size: Optional[int] = None,
|
|
27
27
|
deterministic: bool = False,
|
|
28
|
+
max_tries: int = 10000,
|
|
28
29
|
):
|
|
29
30
|
"""
|
|
30
31
|
Args:
|
|
@@ -34,9 +35,12 @@ class NaccacheStern(Homomorphic):
|
|
|
34
35
|
decryption requires to solve DLP.
|
|
35
36
|
deterministic (boolean): deterministic or probabilistic version of
|
|
36
37
|
cryptosystem
|
|
38
|
+
max_tries (int): maximum attempts to generate keys
|
|
37
39
|
"""
|
|
38
40
|
# Naccache-Stern requires to solve DLP in decryption, so small key is recommended
|
|
39
|
-
self.keys = keys or self.generate_keys(
|
|
41
|
+
self.keys = keys or self.generate_keys(
|
|
42
|
+
key_size=key_size or 1024, max_tries=max_tries
|
|
43
|
+
)
|
|
40
44
|
self.plaintext_modulo = self.keys["public_key"]["sigma"]
|
|
41
45
|
self.ciphertext_modulo = self.keys["public_key"]["n"]
|
|
42
46
|
self.deterministic = deterministic
|
|
@@ -14,7 +14,13 @@ class RSA(Homomorphic):
|
|
|
14
14
|
Ref: https://sefiks.com/2023/03/06/a-step-by-step-partially-homomorphic-encryption-example-with-rsa-in-python/
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
def __init__(
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
keys: Optional[dict] = None,
|
|
20
|
+
key_size: Optional[int] = None,
|
|
21
|
+
encrypt_with_public=True,
|
|
22
|
+
max_tries: int = 10000,
|
|
23
|
+
):
|
|
18
24
|
"""
|
|
19
25
|
Args:
|
|
20
26
|
keys (dict): private - public key pair.
|
|
@@ -26,17 +32,25 @@ class RSA(Homomorphic):
|
|
|
26
32
|
one can decrypt it with your public (digital signatures).
|
|
27
33
|
Set this arg to True if you want to do encryption with public key e,
|
|
28
34
|
and do decryption with private key d.
|
|
35
|
+
max_tries (int): maximum attempts to generate keys.
|
|
29
36
|
"""
|
|
30
|
-
self.keys = keys or self.generate_keys(
|
|
37
|
+
self.keys = keys or self.generate_keys(
|
|
38
|
+
key_size=key_size or 1024, max_tries=max_tries
|
|
39
|
+
)
|
|
31
40
|
self.plaintext_modulo = self.keys["public_key"]["n"]
|
|
32
41
|
self.ciphertext_modulo = self.keys["public_key"]["n"]
|
|
33
42
|
self.encrypt_with_public = encrypt_with_public
|
|
34
43
|
|
|
35
|
-
def generate_keys(
|
|
44
|
+
def generate_keys(
|
|
45
|
+
self,
|
|
46
|
+
key_size: int,
|
|
47
|
+
max_tries: int = 10000,
|
|
48
|
+
) -> dict:
|
|
36
49
|
"""
|
|
37
50
|
Generate public and private keys of RSA cryptosystem
|
|
38
51
|
Args:
|
|
39
52
|
key_size (int): key size in bits
|
|
53
|
+
max_tries (int): maximum number of tries to generate keys
|
|
40
54
|
Returns:
|
|
41
55
|
keys (dict): having private_key and public_key keys
|
|
42
56
|
"""
|
|
@@ -44,33 +58,35 @@ class RSA(Homomorphic):
|
|
|
44
58
|
keys["private_key"] = {}
|
|
45
59
|
keys["public_key"] = {}
|
|
46
60
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
q = sympy.randprime(200, 2 ** int(key_size / 2) - 1)
|
|
61
|
+
for _ in range(max_tries):
|
|
62
|
+
# picking a prime modulus p and q
|
|
63
|
+
p = sympy.randprime(2 ** (key_size // 2 - 300), 2 ** (key_size // 2) - 1)
|
|
64
|
+
q = sympy.randprime(2 ** (key_size // 2 - 300), 2 ** (key_size // 2) - 1)
|
|
52
65
|
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
if p == q:
|
|
67
|
+
continue
|
|
55
68
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
e = random.randint(1, phi - 1)
|
|
59
|
-
if math.gcd(e, n) == 1:
|
|
60
|
-
break
|
|
69
|
+
n = p * q
|
|
70
|
+
phi = (p - 1) * (q - 1)
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
# select public exponent e
|
|
73
|
+
for _ in range(1000): # try max 1000 random e
|
|
74
|
+
e = random.randint(2, phi - 1)
|
|
75
|
+
if math.gcd(e, phi) == 1:
|
|
76
|
+
d = pow(e, -1, phi)
|
|
77
|
+
return {
|
|
78
|
+
"public_key": {"n": n, "e": e},
|
|
79
|
+
"private_key": {"d": d},
|
|
80
|
+
}
|
|
81
|
+
raise ValueError(f"Failed to generate RSA keys after {max_tries} tries")
|
|
71
82
|
|
|
72
83
|
def generate_random_key(self) -> int:
|
|
73
|
-
|
|
84
|
+
"""
|
|
85
|
+
RSA does not require random key for encryption, still return one
|
|
86
|
+
Returns:
|
|
87
|
+
random key (int): one time random key for encryption
|
|
88
|
+
"""
|
|
89
|
+
return random.randint(1, self.keys["public_key"]["n"] - 1)
|
|
74
90
|
|
|
75
91
|
def encrypt(self, plaintext: int) -> int:
|
|
76
92
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lightphe
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.20
|
|
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
|
|
@@ -129,7 +129,7 @@ assert cs.decrypt(c3) == m1 + m2
|
|
|
129
129
|
assert cs.decrypt(c4) == k * m1
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
On the other hand, if you adopt a multiplicatively homomorphic
|
|
132
|
+
On the other hand, if you adopt a multiplicatively homomorphic cryptosystem (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
|
|
133
133
|
|
|
134
134
|
```python
|
|
135
135
|
# build a multiplicatively homomorphic cryptosystem
|
|
@@ -152,7 +152,7 @@ assert cs.decrypt(c3) == m1 * m2
|
|
|
152
152
|
|
|
153
153
|
### Ciphertext Regeneration
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
The most of additively homomorphic algorithms allow 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.
|
|
156
156
|
|
|
157
157
|
```python
|
|
158
158
|
c1_prime = cs.regenerate_ciphertext(c1)
|
|
@@ -163,7 +163,7 @@ assert cs.decrypt(c1) == m1
|
|
|
163
163
|
|
|
164
164
|
### Elliptic Curve Cryptography
|
|
165
165
|
|
|
166
|
-
ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass, edwards and koblitz) and 100+ standard elliptic curve configurations.
|
|
166
|
+
ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass (default), edwards and koblitz) and 100+ standard elliptic curve configurations.
|
|
167
167
|
|
|
168
168
|
In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic-curve-elgamal-encryption/) scheme is implemented, offering a secure and efficient homomorphic encryption option.
|
|
169
169
|
|
|
@@ -171,7 +171,8 @@ In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic
|
|
|
171
171
|
forms = ["weierstrass", "edwards", "koblitz"]
|
|
172
172
|
phe = LightPHE(
|
|
173
173
|
algorithm_name="EllipticCurve-ElGamal",
|
|
174
|
-
form=
|
|
174
|
+
form="edwards",
|
|
175
|
+
# curve="ed448", # optinally you can specify the curve for given form
|
|
175
176
|
)
|
|
176
177
|
```
|
|
177
178
|
|
|
@@ -204,12 +205,16 @@ c4 = c1 + c2
|
|
|
204
205
|
c5 = 3 * c1
|
|
205
206
|
|
|
206
207
|
# perform element-wise multiplication between an encrypted embedding and plain embedding
|
|
207
|
-
c6 = c1 * t3
|
|
208
|
+
c6 = c1 * t3
|
|
209
|
+
|
|
210
|
+
# encrypted dot product (likewise cosine similarity)
|
|
211
|
+
c7 = c1 @ t3
|
|
208
212
|
|
|
209
213
|
# proof of work
|
|
210
214
|
assert np.allclose(cs.decrypt(c4), [a + b for a, b in zip(t1, t2)], rtol=1e-2)
|
|
211
215
|
assert np.allclose(cs.decrypt(c5), [a * 3 for a in t1], rtol=1e-2)
|
|
212
216
|
assert np.allclose(cs.decrypt(c6), [a * b for a, b in zip(t1, t3)], rtol=1e-2)
|
|
217
|
+
assert np.allclose(cs.decrypt(c7)[0], sum([a * b for a, b in zip(t1, t3)]), rtol=1e-2)
|
|
213
218
|
```
|
|
214
219
|
|
|
215
220
|
# Contributing
|
|
@@ -8,7 +8,7 @@ with open("requirements.txt", "r", encoding="utf-8") as f:
|
|
|
8
8
|
|
|
9
9
|
setuptools.setup(
|
|
10
10
|
name="lightphe",
|
|
11
|
-
version="0.0.
|
|
11
|
+
version="0.0.20",
|
|
12
12
|
author="Sefik Ilkin Serengil",
|
|
13
13
|
author_email="serengil@gmail.com",
|
|
14
14
|
description="A Lightweight Partially Homomorphic Encryption Library for Python",
|
|
@@ -22,14 +22,15 @@ def test_large_keys():
|
|
|
22
22
|
Benaloh | 1024 | 4.91 | 0.00 | 0.00 |0.01
|
|
23
23
|
Benaloh | 2048 | 140.54 | 0.00 | 0.00 |0.03
|
|
24
24
|
Benaloh | 3072 | 439.46 | 0.00 | 0.00 |0.08
|
|
25
|
+
|
|
26
|
+
Naccache-Stern | 1024 | 19.97 | 0.00 | 0.00 |0.06
|
|
25
27
|
"""
|
|
26
28
|
algorithms = [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
"Naccache-Stern",
|
|
30
|
+
"Goldwasser-Micali",
|
|
29
31
|
"Benaloh",
|
|
30
32
|
]
|
|
31
|
-
|
|
32
|
-
key_sizes = [3072, 7680]
|
|
33
|
+
key_sizes = [1024, 2048, 3072, 7680]
|
|
33
34
|
|
|
34
35
|
for key_size in key_sizes:
|
|
35
36
|
for algorithm_name in algorithms:
|
lightphe-0.0.18/requirements.txt
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|