lightphe 0.0.13__tar.gz → 0.0.15__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.13 → lightphe-0.0.15}/PKG-INFO +46 -23
- {lightphe-0.0.13 → lightphe-0.0.15}/README.md +45 -22
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/__init__.py +7 -47
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/Benaloh.py +0 -6
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/DamgardJurik.py +0 -6
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/ElGamal.py +0 -3
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/EllipticCurveElGamal.py +5 -18
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/GoldwasserMicali.py +0 -6
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/NaccacheStern.py +0 -6
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/OkamotoUchiyama.py +0 -10
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/Paillier.py +0 -6
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/RSA.py +0 -12
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/models/Homomorphic.py +15 -10
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe.egg-info/PKG-INFO +46 -23
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe.egg-info/SOURCES.txt +0 -8
- lightphe-0.0.13/requirements.txt → lightphe-0.0.15/lightphe.egg-info/requires.txt +2 -1
- lightphe-0.0.13/lightphe.egg-info/requires.txt → lightphe-0.0.15/requirements.txt +1 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/setup.py +1 -1
- lightphe-0.0.15/tests/test_ellipticcurveelgamal.py +134 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_okamoto.py +1 -1
- lightphe-0.0.13/lightphe/commons/binary_operations.py +0 -147
- lightphe-0.0.13/lightphe/elliptic_curve_forms/edwards.py +0 -89
- lightphe-0.0.13/lightphe/elliptic_curve_forms/koblitz.py +0 -166
- lightphe-0.0.13/lightphe/elliptic_curve_forms/weierstrass.py +0 -120
- lightphe-0.0.13/lightphe/models/Curve.py +0 -29
- lightphe-0.0.13/lightphe/models/EllipticCurve.py +0 -196
- lightphe-0.0.13/tests/__init__.py +0 -0
- lightphe-0.0.13/tests/test_ellipticcurve.py +0 -75
- lightphe-0.0.13/tests/test_ellipticcurveelgamal.py +0 -263
- {lightphe-0.0.13 → lightphe-0.0.15}/LICENSE +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/commons/__init__.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/commons/logger.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/commons/phe_utils.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/cryptosystems/__init__.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/models/Algorithm.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/models/Ciphertext.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe/models/Tensor.py +0 -0
- {lightphe-0.0.13/lightphe/elliptic_curve_forms → lightphe-0.0.15/lightphe/models}/__init__.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe.egg-info/dependency_links.txt +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/lightphe.egg-info/top_level.txt +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/setup.cfg +0 -0
- {lightphe-0.0.13/lightphe/models → lightphe-0.0.15/tests}/__init__.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_benaloh.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_ciphertexts.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_cloud.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_damgard.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_elgamal.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_exporting_keys.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_goldwasser.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_keys.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_naccache.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_paillier.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_rsa.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/tests/test_salary.py +0 -0
- {lightphe-0.0.13 → lightphe-0.0.15}/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.15
|
|
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
|
|
@@ -23,8 +23,6 @@ License-File: LICENSE
|
|
|
23
23
|
[](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
|
|
24
24
|
[](https://github.com/serengil/LightPHE/blob/master/LICENSE)
|
|
25
25
|
[](https://arxiv.org/abs/2408.05219)
|
|
26
|
-
[](https://news.ycombinator.com/item?id=43024283)
|
|
27
|
-
<!-- [](https://arxiv.org/abs/2408.05219) -->
|
|
28
26
|
|
|
29
27
|
[](https://sefiks.com)
|
|
30
28
|
[](https://www.youtube.com/@sefiks?sub_confirmation=1)
|
|
@@ -254,11 +252,9 @@ ECC is a powerful public-key cryptosystem based on the algebraic structure of el
|
|
|
254
252
|
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.
|
|
255
253
|
|
|
256
254
|
```python
|
|
257
|
-
forms = ["weierstass", "edwards", "koblitz"]
|
|
258
|
-
|
|
259
255
|
phe = LightPHE(
|
|
260
256
|
algorithm_name="EllipticCurve-ElGamal",
|
|
261
|
-
form=
|
|
257
|
+
form="edwards", # or weierstrass, koblitz
|
|
262
258
|
)
|
|
263
259
|
```
|
|
264
260
|
|
|
@@ -266,7 +262,7 @@ One of the crucial factors that define the security level of an elliptic curve c
|
|
|
266
262
|
|
|
267
263
|
Each curve in LightPHE has a specific order, which is carefully chosen to balance performance and security. By selecting an elliptic curve with a larger order, you increase the security of your cryptographic system, but this may come with a trade-off in computational efficiency. Therefore, choosing the appropriate curve order is a crucial decision based on your application’s security and performance requirements.
|
|
268
264
|
|
|
269
|
-
See [`curves`](https://github.com/serengil/
|
|
265
|
+
See [`curves`](https://github.com/serengil/LightECC) page for a list of all supported forms, curves and their details.
|
|
270
266
|
|
|
271
267
|
### Vector Embeddings and Tensors
|
|
272
268
|
|
|
@@ -345,24 +341,42 @@ Many machine learning models rely on a two-tower architecture, including facial
|
|
|
345
341
|
For example, suppose all facial embeddings in your database are encrypted on-prem in advance. When verifying an identity, the attempted facial embedding is generated on an edge device or in the cloud. You can compute the encrypted similarity by performing a dot product between the encrypted vector and the plain vector, ensuring secure comparison without decrypting sensitive data. Only additively homomorphic cryptosystems offer encrypted similarity calculation.
|
|
346
342
|
|
|
347
343
|
```python
|
|
348
|
-
#
|
|
349
|
-
cs = LightPHE("Paillier")
|
|
350
|
-
|
|
351
|
-
# define plain vectors - suppose those are l2 normalized already
|
|
344
|
+
# define a plain vectors for source and target
|
|
352
345
|
alpha = [7.1, 5.2, 5.3, 2.4, 3.5, 4.6] # On-prem vector (user tower)
|
|
353
346
|
beta = [5.6, 3.7, 2.8, 4, 0, 5.9] # Cloud vector (item tower)
|
|
347
|
+
expected_similarity = sum(x * y for x, y in zip(alpha, beta))
|
|
354
348
|
|
|
355
|
-
#
|
|
349
|
+
# build an additively homomorphic cryptosystem (e.g. Paillier) on-prem
|
|
350
|
+
cs = LightPHE(algorithm_name = "Paillier", precision = 19)
|
|
351
|
+
|
|
352
|
+
# export keys
|
|
353
|
+
cs.export_keys("secret.txt")
|
|
354
|
+
cs.export_keys("public.txt", public=True)
|
|
355
|
+
|
|
356
|
+
# encrypt source embedding
|
|
356
357
|
encrypted_alpha = cs.encrypt(alpha)
|
|
357
358
|
|
|
358
|
-
#
|
|
359
|
+
# remove cryptosystem and plain alpha not to be leaked in cloud
|
|
360
|
+
del cs, alpha
|
|
361
|
+
|
|
362
|
+
# restore the cryptosystem in cloud with only public key
|
|
363
|
+
cloud_cs = LightPHE(algorithm_name = "Paillier", precision = 19, key_file = "public.txt")
|
|
364
|
+
|
|
365
|
+
# dot product of encrypted and plain embedding pair
|
|
359
366
|
encrypted_cosine_similarity = encrypted_alpha @ beta
|
|
360
367
|
|
|
361
|
-
# decrypt
|
|
362
|
-
|
|
368
|
+
# computed by the cloud but cloud cannot decrypt it
|
|
369
|
+
with pytest.raises(ValueError, match="must have private key"):
|
|
370
|
+
cloud_cs.decrypt(encrypted_cosine_similarity)
|
|
371
|
+
|
|
372
|
+
# restore the cryptosystem on-prem with secret key
|
|
373
|
+
cs = LightPHE(algorithm_name = "Paillier", precision = 19, key_file = "secret.txt")
|
|
374
|
+
|
|
375
|
+
# decrypt similarity (on prem)
|
|
376
|
+
calculated_similarity = cs.decrypt(encrypted_cosine_similarity)[0]
|
|
363
377
|
|
|
364
378
|
# proof of work
|
|
365
|
-
assert abs(
|
|
379
|
+
assert abs(calculated_similarity - expected_similarity) < 1e-2
|
|
366
380
|
```
|
|
367
381
|
|
|
368
382
|
# Contributing
|
|
@@ -392,13 +406,22 @@ Also, your company's logo will be shown on README on GitHub if you become sponso
|
|
|
392
406
|
Please cite LightPHE in your publications if it helps your research. Here is its BibTex entry:
|
|
393
407
|
|
|
394
408
|
```BibTeX
|
|
395
|
-
@
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
409
|
+
@article{serengil2024lightphe,
|
|
410
|
+
title={LightPHE: Integrating Partially Homomorphic Encryption into Python with Extensive Cloud Environment Evaluations},
|
|
411
|
+
author={Serengil, Sefik Ilkin and Ozpinar, Alper},
|
|
412
|
+
journal={arXiv preprint arXiv:2408.05219},
|
|
413
|
+
note={doi: 10.48550/arXiv.2408.05219. [Online]. Available: \url{https://arxiv.org/abs/2408.05219}},
|
|
414
|
+
year={2025}
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
```BibTeX
|
|
419
|
+
@article{serengil2025vectorsimilarity,
|
|
420
|
+
title={Encrypted Vector Similarity Computations Using Partially Homomorphic Encryption: Applications and Performance Analysis},
|
|
421
|
+
author={Serengil, Sefik and Ozpinar, Alper},
|
|
422
|
+
journal={arXiv preprint arXiv:2503.05850},
|
|
423
|
+
note={doi: 10.48550/arXiv.2503.05850. [Online]. Available: \url{https://arxiv.org/abs/2503.05850}},
|
|
424
|
+
year={2025}
|
|
402
425
|
}
|
|
403
426
|
```
|
|
404
427
|
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
[](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
|
|
8
8
|
[](https://github.com/serengil/LightPHE/blob/master/LICENSE)
|
|
9
9
|
[](https://arxiv.org/abs/2408.05219)
|
|
10
|
-
[](https://news.ycombinator.com/item?id=43024283)
|
|
11
|
-
<!-- [](https://arxiv.org/abs/2408.05219) -->
|
|
12
10
|
|
|
13
11
|
[](https://sefiks.com)
|
|
14
12
|
[](https://www.youtube.com/@sefiks?sub_confirmation=1)
|
|
@@ -238,11 +236,9 @@ ECC is a powerful public-key cryptosystem based on the algebraic structure of el
|
|
|
238
236
|
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.
|
|
239
237
|
|
|
240
238
|
```python
|
|
241
|
-
forms = ["weierstass", "edwards", "koblitz"]
|
|
242
|
-
|
|
243
239
|
phe = LightPHE(
|
|
244
240
|
algorithm_name="EllipticCurve-ElGamal",
|
|
245
|
-
form=
|
|
241
|
+
form="edwards", # or weierstrass, koblitz
|
|
246
242
|
)
|
|
247
243
|
```
|
|
248
244
|
|
|
@@ -250,7 +246,7 @@ One of the crucial factors that define the security level of an elliptic curve c
|
|
|
250
246
|
|
|
251
247
|
Each curve in LightPHE has a specific order, which is carefully chosen to balance performance and security. By selecting an elliptic curve with a larger order, you increase the security of your cryptographic system, but this may come with a trade-off in computational efficiency. Therefore, choosing the appropriate curve order is a crucial decision based on your application’s security and performance requirements.
|
|
252
248
|
|
|
253
|
-
See [`curves`](https://github.com/serengil/
|
|
249
|
+
See [`curves`](https://github.com/serengil/LightECC) page for a list of all supported forms, curves and their details.
|
|
254
250
|
|
|
255
251
|
### Vector Embeddings and Tensors
|
|
256
252
|
|
|
@@ -329,24 +325,42 @@ Many machine learning models rely on a two-tower architecture, including facial
|
|
|
329
325
|
For example, suppose all facial embeddings in your database are encrypted on-prem in advance. When verifying an identity, the attempted facial embedding is generated on an edge device or in the cloud. You can compute the encrypted similarity by performing a dot product between the encrypted vector and the plain vector, ensuring secure comparison without decrypting sensitive data. Only additively homomorphic cryptosystems offer encrypted similarity calculation.
|
|
330
326
|
|
|
331
327
|
```python
|
|
332
|
-
#
|
|
333
|
-
cs = LightPHE("Paillier")
|
|
334
|
-
|
|
335
|
-
# define plain vectors - suppose those are l2 normalized already
|
|
328
|
+
# define a plain vectors for source and target
|
|
336
329
|
alpha = [7.1, 5.2, 5.3, 2.4, 3.5, 4.6] # On-prem vector (user tower)
|
|
337
330
|
beta = [5.6, 3.7, 2.8, 4, 0, 5.9] # Cloud vector (item tower)
|
|
331
|
+
expected_similarity = sum(x * y for x, y in zip(alpha, beta))
|
|
338
332
|
|
|
339
|
-
#
|
|
333
|
+
# build an additively homomorphic cryptosystem (e.g. Paillier) on-prem
|
|
334
|
+
cs = LightPHE(algorithm_name = "Paillier", precision = 19)
|
|
335
|
+
|
|
336
|
+
# export keys
|
|
337
|
+
cs.export_keys("secret.txt")
|
|
338
|
+
cs.export_keys("public.txt", public=True)
|
|
339
|
+
|
|
340
|
+
# encrypt source embedding
|
|
340
341
|
encrypted_alpha = cs.encrypt(alpha)
|
|
341
342
|
|
|
342
|
-
#
|
|
343
|
+
# remove cryptosystem and plain alpha not to be leaked in cloud
|
|
344
|
+
del cs, alpha
|
|
345
|
+
|
|
346
|
+
# restore the cryptosystem in cloud with only public key
|
|
347
|
+
cloud_cs = LightPHE(algorithm_name = "Paillier", precision = 19, key_file = "public.txt")
|
|
348
|
+
|
|
349
|
+
# dot product of encrypted and plain embedding pair
|
|
343
350
|
encrypted_cosine_similarity = encrypted_alpha @ beta
|
|
344
351
|
|
|
345
|
-
# decrypt
|
|
346
|
-
|
|
352
|
+
# computed by the cloud but cloud cannot decrypt it
|
|
353
|
+
with pytest.raises(ValueError, match="must have private key"):
|
|
354
|
+
cloud_cs.decrypt(encrypted_cosine_similarity)
|
|
355
|
+
|
|
356
|
+
# restore the cryptosystem on-prem with secret key
|
|
357
|
+
cs = LightPHE(algorithm_name = "Paillier", precision = 19, key_file = "secret.txt")
|
|
358
|
+
|
|
359
|
+
# decrypt similarity (on prem)
|
|
360
|
+
calculated_similarity = cs.decrypt(encrypted_cosine_similarity)[0]
|
|
347
361
|
|
|
348
362
|
# proof of work
|
|
349
|
-
assert abs(
|
|
363
|
+
assert abs(calculated_similarity - expected_similarity) < 1e-2
|
|
350
364
|
```
|
|
351
365
|
|
|
352
366
|
# Contributing
|
|
@@ -376,13 +390,22 @@ Also, your company's logo will be shown on README on GitHub if you become sponso
|
|
|
376
390
|
Please cite LightPHE in your publications if it helps your research. Here is its BibTex entry:
|
|
377
391
|
|
|
378
392
|
```BibTeX
|
|
379
|
-
@
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
393
|
+
@article{serengil2024lightphe,
|
|
394
|
+
title={LightPHE: Integrating Partially Homomorphic Encryption into Python with Extensive Cloud Environment Evaluations},
|
|
395
|
+
author={Serengil, Sefik Ilkin and Ozpinar, Alper},
|
|
396
|
+
journal={arXiv preprint arXiv:2408.05219},
|
|
397
|
+
note={doi: 10.48550/arXiv.2408.05219. [Online]. Available: \url{https://arxiv.org/abs/2408.05219}},
|
|
398
|
+
year={2025}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
```BibTeX
|
|
403
|
+
@article{serengil2025vectorsimilarity,
|
|
404
|
+
title={Encrypted Vector Similarity Computations Using Partially Homomorphic Encryption: Applications and Performance Analysis},
|
|
405
|
+
author={Serengil, Sefik and Ozpinar, Alper},
|
|
406
|
+
journal={arXiv preprint arXiv:2503.05850},
|
|
407
|
+
note={doi: 10.48550/arXiv.2503.05850. [Online]. Available: \url{https://arxiv.org/abs/2503.05850}},
|
|
408
|
+
year={2025}
|
|
386
409
|
}
|
|
387
410
|
```
|
|
388
411
|
|
|
@@ -9,13 +9,16 @@ import copy
|
|
|
9
9
|
|
|
10
10
|
# 3rd party dependencies
|
|
11
11
|
from tqdm import tqdm
|
|
12
|
+
from lightecc.interfaces.elliptic_curve import EllipticCurvePoint
|
|
13
|
+
from lightecc.forms.weierstrass import Weierstrass
|
|
14
|
+
from lightecc.forms.edwards import TwistedEdwards
|
|
15
|
+
from lightecc.forms.koblitz import Koblitz
|
|
12
16
|
|
|
13
17
|
# project dependencies
|
|
14
18
|
from lightphe.models.Homomorphic import Homomorphic
|
|
15
19
|
from lightphe.models.Ciphertext import Ciphertext
|
|
16
20
|
from lightphe.models.Algorithm import Algorithm
|
|
17
21
|
from lightphe.models.Tensor import Fraction, EncryptedTensor
|
|
18
|
-
from lightphe.models.EllipticCurve import EllipticCurvePoint
|
|
19
22
|
from lightphe.commons import phe_utils
|
|
20
23
|
from lightphe.commons.logger import Logger
|
|
21
24
|
|
|
@@ -29,16 +32,13 @@ from lightphe.cryptosystems.Benaloh import Benaloh
|
|
|
29
32
|
from lightphe.cryptosystems.NaccacheStern import NaccacheStern
|
|
30
33
|
from lightphe.cryptosystems.GoldwasserMicali import GoldwasserMicali
|
|
31
34
|
from lightphe.cryptosystems.EllipticCurveElGamal import EllipticCurveElGamal
|
|
32
|
-
from lightphe.elliptic_curve_forms.weierstrass import Weierstrass
|
|
33
|
-
from lightphe.elliptic_curve_forms.edwards import TwistedEdwards
|
|
34
|
-
from lightphe.elliptic_curve_forms.koblitz import Koblitz
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
# pylint: disable=eval-used, simplifiable-if-expression, too-few-public-methods
|
|
38
38
|
|
|
39
39
|
logger = Logger(module="lightphe/__init__.py")
|
|
40
40
|
|
|
41
|
-
VERSION = "0.0.
|
|
41
|
+
VERSION = "0.0.15"
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
class LightPHE:
|
|
@@ -94,7 +94,7 @@ class LightPHE:
|
|
|
94
94
|
|
|
95
95
|
def __build_cryptosystem(
|
|
96
96
|
self,
|
|
97
|
-
algorithm_name: str,
|
|
97
|
+
algorithm_name: str = "Paillier",
|
|
98
98
|
keys: Optional[dict] = None,
|
|
99
99
|
key_size: Optional[int] = None,
|
|
100
100
|
form: Optional[str] = None,
|
|
@@ -115,6 +115,7 @@ class LightPHE:
|
|
|
115
115
|
algorithm_name (str): RSA | ElGamal | Exponential-ElGamal | EllipticCurve-ElGamal
|
|
116
116
|
| Paillier | Damgard-Jurik | Okamoto-Uchiyama | Benaloh | Naccache-Stern
|
|
117
117
|
| Goldwasser-Micali | Edwards-ElGamal
|
|
118
|
+
Default is Paillier.
|
|
118
119
|
keys (dict): optional private-public key pair
|
|
119
120
|
key_file (str): if keys are exported, you can load them into cryptosystem
|
|
120
121
|
key_size (int): key size in bits
|
|
@@ -464,44 +465,3 @@ def encrypt_float(
|
|
|
464
465
|
logger.error(f"Exception while running encrypt_float: {str(err)}")
|
|
465
466
|
logger.error(traceback.format_exc())
|
|
466
467
|
raise err
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
class ECC:
|
|
470
|
-
__version__ = VERSION
|
|
471
|
-
|
|
472
|
-
def __init__(
|
|
473
|
-
self, form_name: Optional[str] = None, curve_name: Optional[str] = None
|
|
474
|
-
):
|
|
475
|
-
"""
|
|
476
|
-
Construct an Elliptic Curve over a finite field (prime or binary)
|
|
477
|
-
Args:
|
|
478
|
-
form_name (str): specifies the form of the elliptic curve.
|
|
479
|
-
Options: 'weierstrass' (default), 'edwards', 'koblitz'.
|
|
480
|
-
curve_name (str): specifies the elliptic curve to use.
|
|
481
|
-
Options:
|
|
482
|
-
- e.g. ed25519, ed448 for edwards form
|
|
483
|
-
- e.g. secp256k1 for weierstrass form
|
|
484
|
-
- e.g. k-409 for koblitz form
|
|
485
|
-
List of all available curves:
|
|
486
|
-
github.com/serengil/LightPHE/blob/master/lightphe/elliptic_curve_forms/README.md
|
|
487
|
-
"""
|
|
488
|
-
if form_name is None or form_name == "weierstrass":
|
|
489
|
-
self.curve = Weierstrass(curve=curve_name)
|
|
490
|
-
elif form_name in "edwards":
|
|
491
|
-
self.curve = TwistedEdwards(curve=curve_name)
|
|
492
|
-
elif form_name in "koblitz":
|
|
493
|
-
self.curve = Koblitz(curve=curve_name)
|
|
494
|
-
else:
|
|
495
|
-
raise ValueError(f"unimplemented curve form - {form_name}")
|
|
496
|
-
|
|
497
|
-
# base point
|
|
498
|
-
self.G = EllipticCurvePoint(self.curve.G[0], self.curve.G[1], self.curve)
|
|
499
|
-
|
|
500
|
-
# order of the curve
|
|
501
|
-
self.n = self.curve.n
|
|
502
|
-
|
|
503
|
-
# point at infinity or neutral / identity element
|
|
504
|
-
self.O = EllipticCurvePoint(self.curve.O[0], self.curve.O[1], self.curve)
|
|
505
|
-
|
|
506
|
-
# modulo
|
|
507
|
-
self.modulo = self.curve.modulo
|
|
@@ -169,12 +169,6 @@ class Benaloh(Homomorphic):
|
|
|
169
169
|
n = self.keys["public_key"]["n"]
|
|
170
170
|
return (ciphertext1 * ciphertext2) % n
|
|
171
171
|
|
|
172
|
-
def multiply(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
173
|
-
raise ValueError("Benaloh is not homomorphic with respect to the multiplication")
|
|
174
|
-
|
|
175
|
-
def xor(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
176
|
-
raise ValueError("Benaloh is not homomorphic with respect to the exclusive or")
|
|
177
|
-
|
|
178
172
|
def multiply_by_contant(self, ciphertext: int, constant: int) -> int:
|
|
179
173
|
"""
|
|
180
174
|
Multiply a ciphertext with a plain constant.
|
|
@@ -125,12 +125,6 @@ class DamgardJurik(Homomorphic):
|
|
|
125
125
|
modulo = pow(n, s + 1)
|
|
126
126
|
return (ciphertext1 * ciphertext2) % modulo
|
|
127
127
|
|
|
128
|
-
def multiply(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
129
|
-
raise ValueError("Damgard-Jurik is not homomorphic with respect to the multiplication")
|
|
130
|
-
|
|
131
|
-
def xor(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
132
|
-
raise ValueError("Damgard-Jurik is not homomorphic with respect to the exclusive or")
|
|
133
|
-
|
|
134
128
|
def multiply_by_contant(self, ciphertext: int, constant: int) -> int:
|
|
135
129
|
"""
|
|
136
130
|
Multiply a ciphertext by a known plain constant
|
|
@@ -169,9 +169,6 @@ class ElGamal(Homomorphic):
|
|
|
169
169
|
p = self.keys["public_key"]["p"]
|
|
170
170
|
return (ciphertext1[0] * ciphertext2[0]) % p, (ciphertext1[1] * ciphertext2[1]) % p
|
|
171
171
|
|
|
172
|
-
def xor(self, ciphertext1: tuple, ciphertext2: tuple) -> int:
|
|
173
|
-
raise ValueError("ElGamal is not homomorphic with respect to the exclusive or")
|
|
174
|
-
|
|
175
172
|
def multiply_by_contant(self, ciphertext: tuple, constant: int) -> tuple:
|
|
176
173
|
if self.exponential is False:
|
|
177
174
|
raise ValueError("ElGamal is not supporting multiplying ciphertext by a known constant")
|
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
import random
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
|
+
# 3rd party dependencies
|
|
6
|
+
from lightecc import LightECC as ECC
|
|
7
|
+
from lightecc.interfaces.elliptic_curve import EllipticCurvePoint
|
|
8
|
+
|
|
5
9
|
# project dependencies
|
|
6
10
|
from lightphe.models.Homomorphic import Homomorphic
|
|
7
|
-
from lightphe.models.EllipticCurve import EllipticCurvePoint
|
|
8
11
|
from lightphe.commons.logger import Logger
|
|
9
12
|
|
|
10
13
|
logger = Logger(module="lightphe/cryptosystems/EllipticCurveElGamal.py")
|
|
@@ -40,9 +43,6 @@ class EllipticCurveElGamal(Homomorphic):
|
|
|
40
43
|
- secp256k1 for weierstrass form
|
|
41
44
|
This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
|
|
42
45
|
"""
|
|
43
|
-
# to avoid circular import, import ECC class here
|
|
44
|
-
from lightphe import ECC
|
|
45
|
-
|
|
46
46
|
self.ecc = ECC(form_name=form, curve_name=curve)
|
|
47
47
|
|
|
48
48
|
self.keys = keys or self.generate_keys(key_size or self.ecc.n.bit_length())
|
|
@@ -142,11 +142,6 @@ class EllipticCurveElGamal(Homomorphic):
|
|
|
142
142
|
|
|
143
143
|
return s_prime / self.ecc.G
|
|
144
144
|
|
|
145
|
-
def multiply(self, ciphertext1: tuple, ciphertext2: tuple) -> tuple:
|
|
146
|
-
raise ValueError(
|
|
147
|
-
"Elliptic Curve ElGamal is not homomorphic with respect to the multiplication"
|
|
148
|
-
)
|
|
149
|
-
|
|
150
145
|
def add(self, ciphertext1: tuple, ciphertext2: tuple) -> tuple:
|
|
151
146
|
"""
|
|
152
147
|
Perform homomorphic addition on encrypted data
|
|
@@ -171,10 +166,7 @@ class EllipticCurveElGamal(Homomorphic):
|
|
|
171
166
|
|
|
172
167
|
return a.get_point(), b.get_point()
|
|
173
168
|
|
|
174
|
-
|
|
175
|
-
raise ValueError(
|
|
176
|
-
"Elliptic Curve ElGamal is not homomorphic with respect to the exclusive or"
|
|
177
|
-
)
|
|
169
|
+
|
|
178
170
|
|
|
179
171
|
def multiply_by_contant(self, ciphertext: tuple, constant: int) -> tuple:
|
|
180
172
|
"""
|
|
@@ -198,8 +190,3 @@ class EllipticCurveElGamal(Homomorphic):
|
|
|
198
190
|
Q_prime = Q * constant
|
|
199
191
|
|
|
200
192
|
return P_prime.get_point(), Q_prime.get_point()
|
|
201
|
-
|
|
202
|
-
def reencrypt(self, ciphertext: tuple) -> tuple:
|
|
203
|
-
raise ValueError(
|
|
204
|
-
"Elliptic Curve ElGamal does not support regeneration of ciphertext"
|
|
205
|
-
)
|
|
@@ -193,9 +193,3 @@ class GoldwasserMicali(Homomorphic):
|
|
|
193
193
|
ciphertext3.append((c1 * c2) % self.ciphertext_modulo)
|
|
194
194
|
|
|
195
195
|
return ciphertext3
|
|
196
|
-
|
|
197
|
-
def multiply_by_contant(self, ciphertext: int, constant: int):
|
|
198
|
-
raise ValueError("Goldwasser-Micali does not support multiplying with constant")
|
|
199
|
-
|
|
200
|
-
def reencrypt(self, ciphertext: int):
|
|
201
|
-
raise ValueError("Goldwasser-Micali does not support re-encryption")
|
|
@@ -257,12 +257,6 @@ class NaccacheStern(Homomorphic):
|
|
|
257
257
|
"""
|
|
258
258
|
return (ciphertext1 * ciphertext2) % self.ciphertext_modulo
|
|
259
259
|
|
|
260
|
-
def multiply(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
261
|
-
raise ValueError("Naccache-Stern is not homomorphic with respect to the multiplication")
|
|
262
|
-
|
|
263
|
-
def xor(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
264
|
-
raise ValueError("Naccache-Stern is not homomorphic with respect to the exclusive or")
|
|
265
|
-
|
|
266
260
|
def multiply_by_contant(self, ciphertext: int, constant: int) -> int:
|
|
267
261
|
"""
|
|
268
262
|
Multiply a ciphertext with a plain constant.
|
|
@@ -127,16 +127,6 @@ class OkamotoUchiyama(Homomorphic):
|
|
|
127
127
|
n = self.keys["public_key"]["n"]
|
|
128
128
|
return (ciphertext1 * ciphertext2) % n
|
|
129
129
|
|
|
130
|
-
def multiply(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
131
|
-
raise ValueError(
|
|
132
|
-
"Okamoto-Uchiyama is not homomorphic with respect to the multiplication"
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
def xor(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
136
|
-
raise ValueError(
|
|
137
|
-
"Okamoto-Uchiyama is not homomorphic with respect to the exclusive or"
|
|
138
|
-
)
|
|
139
|
-
|
|
140
130
|
def multiply_by_contant(self, ciphertext: int, constant: int) -> int:
|
|
141
131
|
"""
|
|
142
132
|
Multiply a ciphertext with a plain constant.
|
|
@@ -112,12 +112,6 @@ class Paillier(Homomorphic):
|
|
|
112
112
|
n = self.keys["public_key"]["n"]
|
|
113
113
|
return (ciphertext1 * ciphertext2) % (n * n)
|
|
114
114
|
|
|
115
|
-
def multiply(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
116
|
-
raise ValueError("Paillier is not homomorphic with respect to the multiplication")
|
|
117
|
-
|
|
118
|
-
def xor(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
119
|
-
raise ValueError("Paillier is not homomorphic with respect to the exclusive or")
|
|
120
|
-
|
|
121
115
|
def multiply_by_contant(self, ciphertext: int, constant: int) -> int:
|
|
122
116
|
"""
|
|
123
117
|
Multiply a ciphertext with a plain constant.
|
|
@@ -129,15 +129,3 @@ class RSA(Homomorphic):
|
|
|
129
129
|
"""
|
|
130
130
|
n = self.keys["public_key"]["n"]
|
|
131
131
|
return (ciphertext1 * ciphertext2) % n
|
|
132
|
-
|
|
133
|
-
def add(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
134
|
-
raise ValueError("RSA is not homomorphic with respect to the addition")
|
|
135
|
-
|
|
136
|
-
def xor(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
137
|
-
raise ValueError("RSA is not homomorphic with respect to the exclusive or")
|
|
138
|
-
|
|
139
|
-
def multiply_by_contant(self, ciphertext: int, constant: int) -> int:
|
|
140
|
-
raise ValueError("RSA is not supporting multiplying ciphertext by a known constant")
|
|
141
|
-
|
|
142
|
-
def reencrypt(self, ciphertext: int) -> int:
|
|
143
|
-
raise ValueError("RSA does not support re-encryption")
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
# built-in dependencies
|
|
1
2
|
from typing import Optional, Union
|
|
2
3
|
from abc import ABC, abstractmethod
|
|
3
4
|
|
|
5
|
+
# project dependencies
|
|
6
|
+
from lightphe.models.Algorithm import Algorithm
|
|
7
|
+
|
|
4
8
|
# Signature for supported cryptosystems
|
|
5
9
|
|
|
6
10
|
|
|
@@ -27,26 +31,27 @@ class Homomorphic(ABC):
|
|
|
27
31
|
def decrypt(self, ciphertext: Union[int, tuple, list]) -> int:
|
|
28
32
|
pass
|
|
29
33
|
|
|
30
|
-
@abstractmethod
|
|
31
34
|
def add(
|
|
32
35
|
self, ciphertext1: Union[int, tuple, list], ciphertext2: Union[int, tuple, list]
|
|
33
36
|
) -> Union[int, tuple, list]:
|
|
34
|
-
|
|
37
|
+
raise ValueError(f"{self.get_algorithm_name()} is not homomorphic with respect to the addition")
|
|
35
38
|
|
|
36
|
-
@abstractmethod
|
|
37
39
|
def multiply(
|
|
38
40
|
self, ciphertext1: Union[int, tuple, list], ciphertext2: Union[int, tuple, list]
|
|
39
41
|
) -> Union[int, tuple]:
|
|
40
|
-
|
|
42
|
+
raise ValueError(f"{self.get_algorithm_name()} is not homomorphic with respect to the multiplication")
|
|
41
43
|
|
|
42
|
-
@abstractmethod
|
|
43
44
|
def xor(self, ciphertext1: list, ciphertext2: list) -> list:
|
|
44
|
-
|
|
45
|
+
raise ValueError(f"{self.get_algorithm_name()} is not homomorphic with respect to the exclusive or")
|
|
45
46
|
|
|
46
|
-
@abstractmethod
|
|
47
47
|
def multiply_by_contant(self, ciphertext: Union[int, tuple, list], constant: int) -> int:
|
|
48
|
-
|
|
48
|
+
raise ValueError(f"{self.get_algorithm_name()} is not supporting multiplying ciphertext by a known constant")
|
|
49
49
|
|
|
50
|
-
@abstractmethod
|
|
51
50
|
def reencrypt(self, ciphertext: Union[int, tuple, list]) -> Union[int, tuple, list]:
|
|
52
|
-
|
|
51
|
+
raise ValueError(f"{self.get_algorithm_name()} does not support re-encryption")
|
|
52
|
+
|
|
53
|
+
def get_algorithm_name(self) -> str:
|
|
54
|
+
class_name = self.__class__.__name__
|
|
55
|
+
algorithm_name = getattr(Algorithm, class_name, None)
|
|
56
|
+
assert isinstance(algorithm_name, str), f"Algorithm name for {class_name} is not defined"
|
|
57
|
+
return algorithm_name
|