lightphe 0.0.9__tar.gz → 0.0.11__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.9 → lightphe-0.0.11}/PKG-INFO +46 -3
- {lightphe-0.0.9 → lightphe-0.0.11}/README.md +45 -2
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/__init__.py +106 -16
- lightphe-0.0.11/lightphe/commons/binary_operations.py +147 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/commons/phe_utils.py +22 -4
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/EllipticCurveElGamal.py +77 -45
- lightphe-0.0.11/lightphe/elliptic_curve_forms/edwards.py +89 -0
- lightphe-0.0.11/lightphe/elliptic_curve_forms/koblitz.py +166 -0
- lightphe-0.0.11/lightphe/elliptic_curve_forms/weierstrass.py +120 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/models/Ciphertext.py +27 -8
- lightphe-0.0.11/lightphe/models/Curve.py +29 -0
- lightphe-0.0.11/lightphe/models/EllipticCurve.py +160 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/models/Tensor.py +13 -5
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe.egg-info/PKG-INFO +46 -3
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe.egg-info/SOURCES.txt +4 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/setup.py +1 -1
- lightphe-0.0.11/tests/test_ellipticcurve.py +75 -0
- lightphe-0.0.11/tests/test_ellipticcurveelgamal.py +263 -0
- lightphe-0.0.9/lightphe/elliptic_curve_forms/edwards.py +0 -61
- lightphe-0.0.9/lightphe/elliptic_curve_forms/weierstrass.py +0 -75
- lightphe-0.0.9/lightphe/models/EllipticCurve.py +0 -45
- lightphe-0.0.9/tests/test_ellipticcurveelgamal.py +0 -69
- {lightphe-0.0.9 → lightphe-0.0.11}/LICENSE +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/commons/__init__.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/commons/logger.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/Benaloh.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/DamgardJurik.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/ElGamal.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/GoldwasserMicali.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/NaccacheStern.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/OkamotoUchiyama.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/Paillier.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/RSA.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/cryptosystems/__init__.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/elliptic_curve_forms/__init__.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/models/Algorithm.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/models/Homomorphic.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe/models/__init__.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe.egg-info/dependency_links.txt +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe.egg-info/requires.txt +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/lightphe.egg-info/top_level.txt +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/requirements.txt +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/setup.cfg +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/__init__.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_benaloh.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_cloud.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_damgard.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_elgamal.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_exporting_keys.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_goldwasser.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_naccache.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_okamoto.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_paillier.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_rsa.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/tests/test_salary.py +0 -0
- {lightphe-0.0.9 → lightphe-0.0.11}/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.11
|
|
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
|
|
@@ -22,7 +22,8 @@ License-File: LICENSE
|
|
|
22
22
|
[](https://github.com/serengil/LightPHE/stargazers)
|
|
23
23
|
[](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
|
|
24
24
|
[](https://github.com/serengil/LightPHE/blob/master/LICENSE)
|
|
25
|
-
[](https://arxiv.org/abs/2408.05219)
|
|
26
|
+
<!-- [](https://arxiv.org/abs/2408.05219) -->
|
|
26
27
|
|
|
27
28
|
[](https://sefiks.com)
|
|
28
29
|
[](https://www.youtube.com/@sefiks?sub_confirmation=1)
|
|
@@ -36,7 +37,7 @@ License-File: LICENSE
|
|
|
36
37
|
|
|
37
38
|
<p align="center"><img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/phi.png" width="200" height="240"></p>
|
|
38
39
|
|
|
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/).
|
|
40
|
+
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/), [`Koblitz`](sefiks.com/2016/03/13/the-math-behind-elliptic-curves-over-binary-field/) 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/).
|
|
40
41
|
|
|
41
42
|
# Partially vs Fully Homomorphic Encryption
|
|
42
43
|
|
|
@@ -245,6 +246,48 @@ with pytest.raises(ValueError, match="Paillier is not homomorphic with respect t
|
|
|
245
246
|
|
|
246
247
|
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.
|
|
247
248
|
|
|
249
|
+
### Elliptic Curve Cryptography
|
|
250
|
+
|
|
251
|
+
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.
|
|
252
|
+
|
|
253
|
+
Building an elliptic curve with LightPHE is very straightforward. Once the curve is initialized, you can perform operations such as point addition and scalar multiplication.
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
from lightphe import ECC
|
|
257
|
+
|
|
258
|
+
forms = ["weierstrass", "edwards", "koblitz"]
|
|
259
|
+
|
|
260
|
+
# construct an elliptic curve
|
|
261
|
+
ed = ECC(form_name="edwards")
|
|
262
|
+
|
|
263
|
+
# Base Point
|
|
264
|
+
G = ed.G
|
|
265
|
+
|
|
266
|
+
_2G = G + G
|
|
267
|
+
_3G = _2G + G
|
|
268
|
+
_5G = _3G + _2G
|
|
269
|
+
|
|
270
|
+
_20G = 4 * G
|
|
271
|
+
_19G = _20G - G
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
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.
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
forms = ["weierstass", "edwards", "koblitz"]
|
|
278
|
+
|
|
279
|
+
phe = LightPHE(
|
|
280
|
+
algorithm_name="EllipticCurve-ElGamal",
|
|
281
|
+
form=forms[1],
|
|
282
|
+
)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
One of the crucial factors that define the security level of an elliptic curve cryptosystem is the order of the curve. The order of a curve is the number of points on the curve, and it directly influences the strength of the encryption. A higher order typically corresponds to a stronger cryptosystem, making it more resistant to cryptographic attacks.
|
|
286
|
+
|
|
287
|
+
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.
|
|
288
|
+
|
|
289
|
+
See [`curves`](https://github.com/serengil/LightPHE/tree/master/lightphe/elliptic_curve_forms) page for a list of all supported forms, curves and their details.
|
|
290
|
+
|
|
248
291
|
# Contributing
|
|
249
292
|
|
|
250
293
|
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.
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
[](https://github.com/serengil/LightPHE/stargazers)
|
|
7
7
|
[](https://github.com/serengil/LightPHE/actions/workflows/tests.yml)
|
|
8
8
|
[](https://github.com/serengil/LightPHE/blob/master/LICENSE)
|
|
9
|
-
[](https://arxiv.org/abs/2408.05219)
|
|
10
|
+
<!-- [](https://arxiv.org/abs/2408.05219) -->
|
|
10
11
|
|
|
11
12
|
[](https://sefiks.com)
|
|
12
13
|
[](https://www.youtube.com/@sefiks?sub_confirmation=1)
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
|
|
21
22
|
<p align="center"><img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/phi.png" width="200" height="240"></p>
|
|
22
23
|
|
|
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/).
|
|
24
|
+
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/), [`Koblitz`](sefiks.com/2016/03/13/the-math-behind-elliptic-curves-over-binary-field/) 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/).
|
|
24
25
|
|
|
25
26
|
# Partially vs Fully Homomorphic Encryption
|
|
26
27
|
|
|
@@ -229,6 +230,48 @@ with pytest.raises(ValueError, match="Paillier is not homomorphic with respect t
|
|
|
229
230
|
|
|
230
231
|
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.
|
|
231
232
|
|
|
233
|
+
### Elliptic Curve Cryptography
|
|
234
|
+
|
|
235
|
+
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.
|
|
236
|
+
|
|
237
|
+
Building an elliptic curve with LightPHE is very straightforward. Once the curve is initialized, you can perform operations such as point addition and scalar multiplication.
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from lightphe import ECC
|
|
241
|
+
|
|
242
|
+
forms = ["weierstrass", "edwards", "koblitz"]
|
|
243
|
+
|
|
244
|
+
# construct an elliptic curve
|
|
245
|
+
ed = ECC(form_name="edwards")
|
|
246
|
+
|
|
247
|
+
# Base Point
|
|
248
|
+
G = ed.G
|
|
249
|
+
|
|
250
|
+
_2G = G + G
|
|
251
|
+
_3G = _2G + G
|
|
252
|
+
_5G = _3G + _2G
|
|
253
|
+
|
|
254
|
+
_20G = 4 * G
|
|
255
|
+
_19G = _20G - G
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
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.
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
forms = ["weierstass", "edwards", "koblitz"]
|
|
262
|
+
|
|
263
|
+
phe = LightPHE(
|
|
264
|
+
algorithm_name="EllipticCurve-ElGamal",
|
|
265
|
+
form=forms[1],
|
|
266
|
+
)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
One of the crucial factors that define the security level of an elliptic curve cryptosystem is the order of the curve. The order of a curve is the number of points on the curve, and it directly influences the strength of the encryption. A higher order typically corresponds to a stronger cryptosystem, making it more resistant to cryptographic attacks.
|
|
270
|
+
|
|
271
|
+
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.
|
|
272
|
+
|
|
273
|
+
See [`curves`](https://github.com/serengil/LightPHE/tree/master/lightphe/elliptic_curve_forms) page for a list of all supported forms, curves and their details.
|
|
274
|
+
|
|
232
275
|
# Contributing
|
|
233
276
|
|
|
234
277
|
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.
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
# built-in dependencies
|
|
1
2
|
import json
|
|
2
3
|
from typing import Optional, Union, List
|
|
3
4
|
|
|
5
|
+
# project dependencies
|
|
4
6
|
from lightphe.models.Homomorphic import Homomorphic
|
|
5
7
|
from lightphe.models.Ciphertext import Ciphertext
|
|
6
8
|
from lightphe.models.Algorithm import Algorithm
|
|
7
9
|
from lightphe.models.Tensor import Fraction, EncryptedTensor
|
|
10
|
+
from lightphe.models.EllipticCurve import EllipticCurvePoint
|
|
11
|
+
from lightphe.commons import phe_utils
|
|
12
|
+
from lightphe.commons.logger import Logger
|
|
13
|
+
|
|
14
|
+
# cryptosystems
|
|
8
15
|
from lightphe.cryptosystems.RSA import RSA
|
|
9
16
|
from lightphe.cryptosystems.ElGamal import ElGamal
|
|
10
17
|
from lightphe.cryptosystems.Paillier import Paillier
|
|
@@ -14,16 +21,21 @@ from lightphe.cryptosystems.Benaloh import Benaloh
|
|
|
14
21
|
from lightphe.cryptosystems.NaccacheStern import NaccacheStern
|
|
15
22
|
from lightphe.cryptosystems.GoldwasserMicali import GoldwasserMicali
|
|
16
23
|
from lightphe.cryptosystems.EllipticCurveElGamal import EllipticCurveElGamal
|
|
17
|
-
from lightphe.
|
|
18
|
-
from lightphe.
|
|
24
|
+
from lightphe.elliptic_curve_forms.weierstrass import Weierstrass
|
|
25
|
+
from lightphe.elliptic_curve_forms.edwards import TwistedEdwards
|
|
26
|
+
from lightphe.elliptic_curve_forms.koblitz import Koblitz
|
|
27
|
+
|
|
19
28
|
|
|
20
|
-
# pylint: disable=eval-used, simplifiable-if-expression
|
|
29
|
+
# pylint: disable=eval-used, simplifiable-if-expression, too-few-public-methods
|
|
21
30
|
|
|
22
31
|
logger = Logger(module="lightphe/__init__.py")
|
|
23
32
|
|
|
33
|
+
VERSION = "0.0.11"
|
|
34
|
+
|
|
24
35
|
|
|
25
36
|
class LightPHE:
|
|
26
|
-
__version__ =
|
|
37
|
+
__version__ = VERSION
|
|
38
|
+
|
|
27
39
|
def __init__(
|
|
28
40
|
self,
|
|
29
41
|
algorithm_name: str,
|
|
@@ -31,7 +43,8 @@ class LightPHE:
|
|
|
31
43
|
key_file: Optional[str] = None,
|
|
32
44
|
key_size: Optional[int] = None,
|
|
33
45
|
precision: int = 5,
|
|
34
|
-
form: str =
|
|
46
|
+
form: Optional[str] = None,
|
|
47
|
+
curve: Optional[str] = None,
|
|
35
48
|
):
|
|
36
49
|
"""
|
|
37
50
|
Build LightPHE class
|
|
@@ -43,19 +56,32 @@ class LightPHE:
|
|
|
43
56
|
key_file (str): if keys are exported, you can load them into cryptosystem
|
|
44
57
|
key_size (int): key size in bits
|
|
45
58
|
precision (int): precision for homomorphic operations on tensors
|
|
46
|
-
form (str): specifies the form of the elliptic curve.
|
|
47
|
-
Options: 'weierstrass' (default), 'edwards'.
|
|
59
|
+
form (str): specifies the form of the elliptic curve.
|
|
60
|
+
Options: 'weierstrass' (default), 'edwards', 'koblitz'.
|
|
61
|
+
This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
|
|
62
|
+
curve (str): specifies the elliptic curve to use.
|
|
63
|
+
Options:
|
|
64
|
+
- e.g. ed25519, ed448 for edwards form
|
|
65
|
+
- e.g. secp256k1 for weierstrass form
|
|
66
|
+
- e.g. k-409 for koblitz form
|
|
67
|
+
List of all available curves:
|
|
68
|
+
github.com/serengil/LightPHE/blob/master/lightphe/elliptic_curve_forms/README.md
|
|
48
69
|
This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
|
|
49
70
|
"""
|
|
50
71
|
self.algorithm_name = algorithm_name
|
|
51
72
|
self.precision = precision
|
|
52
73
|
self.form = form
|
|
74
|
+
self.curve = curve
|
|
53
75
|
|
|
54
76
|
if key_file is not None:
|
|
55
77
|
keys = self.restore_keys(target_file=key_file)
|
|
56
78
|
|
|
57
79
|
self.cs: Homomorphic = self.__build_cryptosystem(
|
|
58
|
-
algorithm_name=algorithm_name,
|
|
80
|
+
algorithm_name=algorithm_name,
|
|
81
|
+
keys=keys,
|
|
82
|
+
key_size=key_size,
|
|
83
|
+
form=form,
|
|
84
|
+
curve=curve,
|
|
59
85
|
)
|
|
60
86
|
|
|
61
87
|
def __build_cryptosystem(
|
|
@@ -64,6 +90,7 @@ class LightPHE:
|
|
|
64
90
|
keys: Optional[dict] = None,
|
|
65
91
|
key_size: Optional[int] = None,
|
|
66
92
|
form: Optional[str] = None,
|
|
93
|
+
curve: Optional[str] = None,
|
|
67
94
|
) -> Union[
|
|
68
95
|
RSA,
|
|
69
96
|
ElGamal,
|
|
@@ -83,9 +110,14 @@ class LightPHE:
|
|
|
83
110
|
keys (dict): optional private-public key pair
|
|
84
111
|
key_file (str): if keys are exported, you can load them into cryptosystem
|
|
85
112
|
key_size (int): key size in bits
|
|
86
|
-
form (str): specifies the form of the elliptic curve.
|
|
113
|
+
form (str): specifies the form of the elliptic curve.
|
|
87
114
|
Options: 'weierstrass' (default), 'edwards'.
|
|
88
115
|
This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
|
|
116
|
+
curve (str): specifies the elliptic curve to use.
|
|
117
|
+
Options:
|
|
118
|
+
- ed25519, ed448 for edwards form
|
|
119
|
+
- secp256k1 for weierstrass form
|
|
120
|
+
This parameter is only used if `algorithm_name` is 'EllipticCurve-ElGamal'.
|
|
89
121
|
Returns
|
|
90
122
|
cryptosystem
|
|
91
123
|
"""
|
|
@@ -97,7 +129,9 @@ class LightPHE:
|
|
|
97
129
|
elif algorithm_name == Algorithm.ExponentialElGamal:
|
|
98
130
|
cs = ElGamal(keys=keys, key_size=key_size, exponential=True)
|
|
99
131
|
elif algorithm_name == Algorithm.EllipticCurveElGamal:
|
|
100
|
-
cs = EllipticCurveElGamal(
|
|
132
|
+
cs = EllipticCurveElGamal(
|
|
133
|
+
keys=keys, key_size=key_size, form=form, curve=curve
|
|
134
|
+
)
|
|
101
135
|
elif algorithm_name == Algorithm.Paillier:
|
|
102
136
|
cs = Paillier(keys=keys, key_size=key_size)
|
|
103
137
|
elif algorithm_name == Algorithm.DamgardJurik:
|
|
@@ -114,7 +148,9 @@ class LightPHE:
|
|
|
114
148
|
raise ValueError(f"unimplemented algorithm - {algorithm_name}")
|
|
115
149
|
return cs
|
|
116
150
|
|
|
117
|
-
def encrypt(
|
|
151
|
+
def encrypt(
|
|
152
|
+
self, plaintext: Union[int, float, list]
|
|
153
|
+
) -> Union[Ciphertext, EncryptedTensor]:
|
|
118
154
|
"""
|
|
119
155
|
Encrypt a plaintext with a built cryptosystem
|
|
120
156
|
Args:
|
|
@@ -130,9 +166,17 @@ class LightPHE:
|
|
|
130
166
|
return self.__encrypt_tensors(tensor=plaintext)
|
|
131
167
|
|
|
132
168
|
ciphertext = self.cs.encrypt(
|
|
133
|
-
plaintext=phe_utils.
|
|
169
|
+
plaintext=phe_utils.normalize_input(
|
|
170
|
+
value=plaintext, modulo=self.cs.plaintext_modulo
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
return Ciphertext(
|
|
174
|
+
algorithm_name=self.algorithm_name,
|
|
175
|
+
keys=self.cs.keys,
|
|
176
|
+
value=ciphertext,
|
|
177
|
+
form=self.form,
|
|
178
|
+
curve=self.curve,
|
|
134
179
|
)
|
|
135
|
-
return Ciphertext(algorithm_name=self.algorithm_name, keys=self.cs.keys, value=ciphertext, form=self.form)
|
|
136
180
|
|
|
137
181
|
def decrypt(
|
|
138
182
|
self, ciphertext: Union[Ciphertext, EncryptedTensor]
|
|
@@ -171,7 +215,8 @@ class LightPHE:
|
|
|
171
215
|
plaintext=(m % self.cs.plaintext_modulo) * pow(10, self.precision)
|
|
172
216
|
)
|
|
173
217
|
abs_dividend_encrypted = self.cs.encrypt(
|
|
174
|
-
plaintext=(abs(m) % self.cs.plaintext_modulo)
|
|
218
|
+
plaintext=(abs(m) % self.cs.plaintext_modulo)
|
|
219
|
+
* pow(10, self.precision)
|
|
175
220
|
)
|
|
176
221
|
divisor_encrypted = self.cs.encrypt(plaintext=pow(10, self.precision))
|
|
177
222
|
c = Fraction(
|
|
@@ -205,7 +250,9 @@ class LightPHE:
|
|
|
205
250
|
encrypted_tensor.append(c)
|
|
206
251
|
return EncryptedTensor(fractions=encrypted_tensor, cs=self.cs)
|
|
207
252
|
|
|
208
|
-
def __decrypt_tensors(
|
|
253
|
+
def __decrypt_tensors(
|
|
254
|
+
self, encrypted_tensor: EncryptedTensor
|
|
255
|
+
) -> Union[List[int], List[float]]:
|
|
209
256
|
"""
|
|
210
257
|
Decrypt a given encrypted tensor
|
|
211
258
|
Args:
|
|
@@ -304,4 +351,47 @@ class LightPHE:
|
|
|
304
351
|
Returns:
|
|
305
352
|
Ciphertext
|
|
306
353
|
"""
|
|
307
|
-
return Ciphertext(
|
|
354
|
+
return Ciphertext(
|
|
355
|
+
algorithm_name=self.algorithm_name, keys=self.cs.keys, value=ciphertext
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
class ECC:
|
|
360
|
+
__version__ = VERSION
|
|
361
|
+
|
|
362
|
+
def __init__(
|
|
363
|
+
self, form_name: Optional[str] = None, curve_name: Optional[str] = None
|
|
364
|
+
):
|
|
365
|
+
"""
|
|
366
|
+
Construct an Elliptic Curve over a finite field (prime or binary)
|
|
367
|
+
Args:
|
|
368
|
+
form_name (str): specifies the form of the elliptic curve.
|
|
369
|
+
Options: 'weierstrass' (default), 'edwards', 'koblitz'.
|
|
370
|
+
curve_name (str): specifies the elliptic curve to use.
|
|
371
|
+
Options:
|
|
372
|
+
- e.g. ed25519, ed448 for edwards form
|
|
373
|
+
- e.g. secp256k1 for weierstrass form
|
|
374
|
+
- e.g. k-409 for koblitz form
|
|
375
|
+
List of all available curves:
|
|
376
|
+
github.com/serengil/LightPHE/blob/master/lightphe/elliptic_curve_forms/README.md
|
|
377
|
+
"""
|
|
378
|
+
if form_name is None or form_name == "weierstrass":
|
|
379
|
+
self.curve = Weierstrass(curve=curve_name)
|
|
380
|
+
elif form_name in "edwards":
|
|
381
|
+
self.curve = TwistedEdwards(curve=curve_name)
|
|
382
|
+
elif form_name in "koblitz":
|
|
383
|
+
self.curve = Koblitz(curve=curve_name)
|
|
384
|
+
else:
|
|
385
|
+
raise ValueError(f"unimplemented curve form - {form_name}")
|
|
386
|
+
|
|
387
|
+
# base point
|
|
388
|
+
self.G = EllipticCurvePoint(self.curve.G[0], self.curve.G[1], self.curve)
|
|
389
|
+
|
|
390
|
+
# order of the curve
|
|
391
|
+
self.n = self.curve.n
|
|
392
|
+
|
|
393
|
+
# point at infinity or neutral / identity element
|
|
394
|
+
self.O = EllipticCurvePoint(self.curve.O[0], self.curve.O[1], self.curve)
|
|
395
|
+
|
|
396
|
+
# modulo
|
|
397
|
+
self.modulo = self.curve.modulo
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module is heavily inspired by repo github.com/dimitrijray/ecc-binary-field/blob/master/binop.py
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def divide(a: int, b: int, p: int) -> int:
|
|
7
|
+
"""
|
|
8
|
+
Returns a_bin * (b_bin)^-1 (mod p)
|
|
9
|
+
Args:
|
|
10
|
+
a (int): nominator
|
|
11
|
+
b (int): denominator
|
|
12
|
+
p (int): modulo
|
|
13
|
+
Returns:
|
|
14
|
+
result (int): (a_bin * (b_bin)^-1 (mod p)) mod p
|
|
15
|
+
"""
|
|
16
|
+
result = mod(multi(a, inverse(b, p)), p)
|
|
17
|
+
return result
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def multi(a: int, b: int) -> int:
|
|
21
|
+
"""
|
|
22
|
+
Multiply two binary numbers in GF(2).
|
|
23
|
+
Args:
|
|
24
|
+
a (int): first number
|
|
25
|
+
b (int): second number
|
|
26
|
+
Returns:
|
|
27
|
+
result (int): carry-less multiplication between a and b
|
|
28
|
+
"""
|
|
29
|
+
result = 0
|
|
30
|
+
shift = 0
|
|
31
|
+
|
|
32
|
+
while b > 0:
|
|
33
|
+
if b & 1: # Check if the least significant bit of b is 1
|
|
34
|
+
result ^= a << shift
|
|
35
|
+
shift += 1
|
|
36
|
+
b >>= 1 # Shift b to the right by 1
|
|
37
|
+
|
|
38
|
+
return result
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def power_mod(num: int, exp: int, modulo: int) -> int:
|
|
42
|
+
"""
|
|
43
|
+
Calculate num^exp (mod m) in GF(2).
|
|
44
|
+
Args:
|
|
45
|
+
num (int): base
|
|
46
|
+
exp (int): exponent
|
|
47
|
+
modulo (int): modulo
|
|
48
|
+
Returns:
|
|
49
|
+
result (int): num^exp (mod m)
|
|
50
|
+
"""
|
|
51
|
+
result = 1
|
|
52
|
+
base = num % modulo
|
|
53
|
+
|
|
54
|
+
while exp > 0:
|
|
55
|
+
if exp & 1: # Check if the least significant bit of exp is 1
|
|
56
|
+
result = multi(base, result) # multiply result by base
|
|
57
|
+
result = mod(result, modulo) # apply modulo
|
|
58
|
+
|
|
59
|
+
base = square(base) # square the base
|
|
60
|
+
exp >>= 1 # right shift exp by 1
|
|
61
|
+
|
|
62
|
+
return result
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def square(num: int) -> int:
|
|
66
|
+
"""
|
|
67
|
+
Square a binary number in GF(2).
|
|
68
|
+
Args:
|
|
69
|
+
num (int): number
|
|
70
|
+
Returns:
|
|
71
|
+
result (int): square of num
|
|
72
|
+
"""
|
|
73
|
+
result = 0
|
|
74
|
+
shift = 0
|
|
75
|
+
|
|
76
|
+
while num > 0:
|
|
77
|
+
if num & 1: # Check if the least significant bit of num is 1
|
|
78
|
+
result ^= 1 << (2 * shift) # Set the appropriate bit in the result
|
|
79
|
+
|
|
80
|
+
num >>= 1 # Right shift num by 1
|
|
81
|
+
shift += 1
|
|
82
|
+
|
|
83
|
+
return result
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def mod(num: int, modulo: int) -> int:
|
|
87
|
+
"""
|
|
88
|
+
Perform modulo operation for binary numbers in GF(2).
|
|
89
|
+
Args:
|
|
90
|
+
num (int): number
|
|
91
|
+
modulo (int): modulo
|
|
92
|
+
Returns:
|
|
93
|
+
result (int): num mod modulo
|
|
94
|
+
"""
|
|
95
|
+
degP = num.bit_length() - 1
|
|
96
|
+
degR = modulo.bit_length() - 1
|
|
97
|
+
|
|
98
|
+
while degP >= degR and degR != 0:
|
|
99
|
+
shift = degP - degR
|
|
100
|
+
num ^= modulo << shift # Perform XOR to reduce the degree of num
|
|
101
|
+
degP = num.bit_length() - 1 # Update the degree of num
|
|
102
|
+
|
|
103
|
+
return num
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def div(num: int, modulo: int) -> int:
|
|
107
|
+
"""
|
|
108
|
+
Return the quotient of the polynomial division num / modulo in GF(2).
|
|
109
|
+
Args:
|
|
110
|
+
num (int): numerator
|
|
111
|
+
modulo (int): denominator
|
|
112
|
+
Returns:
|
|
113
|
+
result (int): quotient
|
|
114
|
+
"""
|
|
115
|
+
deg_p = num.bit_length() - 1
|
|
116
|
+
deg_r = modulo.bit_length() - 1
|
|
117
|
+
q = 0
|
|
118
|
+
|
|
119
|
+
while deg_p >= deg_r:
|
|
120
|
+
shift = deg_p - deg_r
|
|
121
|
+
q |= 1 << shift # Set the corresponding bit in the quotient
|
|
122
|
+
num ^= modulo << shift # Perform XOR to reduce the degree of num
|
|
123
|
+
deg_p = num.bit_length() - 1 # Update the degree of num
|
|
124
|
+
|
|
125
|
+
return q
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def inverse(num: int, modulo: int) -> int:
|
|
129
|
+
"""
|
|
130
|
+
Calculate the inverse of a binary number modulo a polynomial in GF(2).
|
|
131
|
+
Args:
|
|
132
|
+
num (int): number
|
|
133
|
+
modulo (int): modulo
|
|
134
|
+
Returns:
|
|
135
|
+
result (int): inverse of num mod modulo
|
|
136
|
+
"""
|
|
137
|
+
a, b = num, modulo
|
|
138
|
+
p1, p2 = 1, 0
|
|
139
|
+
|
|
140
|
+
while b != 1:
|
|
141
|
+
q = div(a, b)
|
|
142
|
+
r = mod(a, b)
|
|
143
|
+
a, b = b, r
|
|
144
|
+
p_a = p1 ^ multi(q, p2)
|
|
145
|
+
p1, p2 = p2, p_a
|
|
146
|
+
|
|
147
|
+
return p2
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
# built-in dependencies
|
|
1
2
|
from typing import Union, Tuple, Optional
|
|
2
3
|
from decimal import Decimal, getcontext
|
|
4
|
+
|
|
5
|
+
# project dependencies
|
|
3
6
|
from lightphe.commons.logger import Logger
|
|
4
7
|
|
|
5
8
|
logger = Logger(module="lightphe/commons/phe_utils.py")
|
|
@@ -7,8 +10,19 @@ logger = Logger(module="lightphe/commons/phe_utils.py")
|
|
|
7
10
|
# pylint: disable=no-else-return, no-else-break
|
|
8
11
|
|
|
9
12
|
|
|
10
|
-
def
|
|
11
|
-
|
|
13
|
+
def normalize_input(value: Union[int, float], modulo: Union[int, str]) -> int:
|
|
14
|
+
"""
|
|
15
|
+
Normaliz given value to be in the range of modulo
|
|
16
|
+
Args:
|
|
17
|
+
value (int, float): the value to be normalized
|
|
18
|
+
modulo (int): the modulo value
|
|
19
|
+
Returns:
|
|
20
|
+
result (int, str): the normalized value
|
|
21
|
+
"""
|
|
22
|
+
if isinstance(value, int) and isinstance(modulo, str):
|
|
23
|
+
# elliptic curve elgamal & koblitz curves
|
|
24
|
+
result = value % int(modulo, 2)
|
|
25
|
+
elif isinstance(value, int) and isinstance(modulo, int):
|
|
12
26
|
result = value % modulo
|
|
13
27
|
elif isinstance(value, float) and value >= 0:
|
|
14
28
|
dividend, divisor = fractionize(value=value, modulo=modulo)
|
|
@@ -23,7 +37,9 @@ def parse_int(value: Union[int, float], modulo: int) -> int:
|
|
|
23
37
|
return result
|
|
24
38
|
|
|
25
39
|
|
|
26
|
-
def fractionize(
|
|
40
|
+
def fractionize(
|
|
41
|
+
value: float, modulo: int, precision: Optional[int] = None
|
|
42
|
+
) -> Tuple[int, int]:
|
|
27
43
|
getcontext().prec = 50
|
|
28
44
|
|
|
29
45
|
if precision is None:
|
|
@@ -40,7 +56,9 @@ def fractionize(value: float, modulo: int, precision: Optional[int] = None) -> T
|
|
|
40
56
|
|
|
41
57
|
if scaling_factor > 10**precision:
|
|
42
58
|
# If scaling factor is too large, discard excess part of integer value
|
|
43
|
-
integer_value = int(
|
|
59
|
+
integer_value = int(
|
|
60
|
+
integer_value / (10 ** (scaling_factor - 10**precision))
|
|
61
|
+
)
|
|
44
62
|
break
|
|
45
63
|
elif scaling_factor < 10 ** (precision - 1):
|
|
46
64
|
# If scaling factor is too small, multiply dividend and divisor 10 times
|