lightphe 0.0.19__tar.gz → 0.0.21__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.19 → lightphe-0.0.21}/PKG-INFO +19 -15
- {lightphe-0.0.19 → lightphe-0.0.21}/README.md +18 -14
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/__init__.py +13 -3
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/commons/phe_utils.py +4 -0
- lightphe-0.0.21/lightphe/cryptosystems/BonehGohNissim.py +327 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/EllipticCurveElGamal.py +22 -2
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/GoldwasserMicali.py +18 -10
- lightphe-0.0.21/lightphe/cryptosystems/SanderYoungYung.py +225 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/models/Algorithm.py +2 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/models/Ciphertext.py +24 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/models/Homomorphic.py +33 -10
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe.egg-info/PKG-INFO +19 -15
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe.egg-info/SOURCES.txt +4 -0
- lightphe-0.0.21/lightphe.egg-info/requires.txt +3 -0
- lightphe-0.0.21/requirements.txt +3 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/setup.py +1 -1
- lightphe-0.0.21/tests/test_bonehgohnissim.py +143 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_ellipticcurveelgamal.py +13 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_goldwasser.py +9 -0
- lightphe-0.0.21/tests/test_sanderyoungyung.py +71 -0
- lightphe-0.0.19/lightphe.egg-info/requires.txt +0 -4
- lightphe-0.0.19/requirements.txt +0 -4
- {lightphe-0.0.19 → lightphe-0.0.21}/LICENSE +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/commons/__init__.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/commons/logger.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/Benaloh.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/DamgardJurik.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/ElGamal.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/NaccacheStern.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/OkamotoUchiyama.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/Paillier.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/RSA.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/cryptosystems/__init__.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/models/Tensor.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe/models/__init__.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe.egg-info/dependency_links.txt +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/lightphe.egg-info/top_level.txt +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/setup.cfg +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/__init__.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_benaloh.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_ciphertexts.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_cloud.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_damgard.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_elgamal.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_exporting_keys.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_keys.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_large_keys.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_naccache.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_okamoto.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_paillier.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_rsa.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/tests/test_salary.py +0 -0
- {lightphe-0.0.19 → lightphe-0.0.21}/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.21
|
|
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
|
|
@@ -36,7 +36,7 @@ License-File: LICENSE
|
|
|
36
36
|
|
|
37
37
|
<p align="center"><img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/phi.png" width="200" height="240"></p>
|
|
38
38
|
|
|
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/), [`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/)
|
|
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/), [`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/), `Sander-Young-Yung`, `Boneh-Goh-Nissim`.
|
|
40
40
|
|
|
41
41
|
# Partially vs Fully Homomorphic Encryption
|
|
42
42
|
|
|
@@ -67,18 +67,20 @@ from lightphe import LightPHE
|
|
|
67
67
|
|
|
68
68
|
In summary, LightPHE is covering following algorithms and these are partially homomorphic with respect to the operations mentioned in the following table.
|
|
69
69
|
|
|
70
|
-
| Algorithm | Multiplicatively<br>Homomorphic | Additively<br>Homomorphic | Scalar Multiplication |
|
|
71
|
-
| --- | --- | --- | --- | --- | --- |
|
|
72
|
-
| RSA | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
73
|
-
| ElGamal | ✅ | ❌ | ❌ | ❌ | ✅ |
|
|
74
|
-
| Exponential ElGamal | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
75
|
-
| Elliptic Curve ElGamal | ❌ | ✅ | ✅ | ❌ | ❌ |
|
|
76
|
-
| Paillier | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
77
|
-
| Damgard-Jurik | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
78
|
-
| Benaloh | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
79
|
-
| Naccache-Stern | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
80
|
-
| Okamoto-Uchiyama | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
81
|
-
| Goldwasser-Micali | ❌ | ❌ | ❌ | ✅ | ❌ |
|
|
70
|
+
| Algorithm | Multiplicatively<br>Homomorphic | Additively<br>Homomorphic | Scalar Multiplication | Bitwise-XOR Homomorphic | Bitwise-AND Homomorphic | Regeneration<br>of Ciphertext |
|
|
71
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
72
|
+
| RSA | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
|
73
|
+
| ElGamal | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
|
74
|
+
| Exponential ElGamal | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
75
|
+
| Elliptic Curve ElGamal | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
76
|
+
| Paillier | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
77
|
+
| Damgard-Jurik | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
78
|
+
| Benaloh | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
79
|
+
| Naccache-Stern | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
80
|
+
| Okamoto-Uchiyama | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
81
|
+
| Goldwasser-Micali | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ |
|
|
82
|
+
| Sander-Young-Yung | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
|
|
83
|
+
| Boneh-Goh-Nissim | 1️⃣ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
82
84
|
|
|
83
85
|
# Building cryptosystem
|
|
84
86
|
|
|
@@ -95,7 +97,9 @@ algorithms = [
|
|
|
95
97
|
"Benaloh",
|
|
96
98
|
"Naccache-Stern",
|
|
97
99
|
"Goldwasser-Micali",
|
|
98
|
-
"EllipticCurve-ElGamal"
|
|
100
|
+
"EllipticCurve-ElGamal",
|
|
101
|
+
"Sander-Young-Yung",
|
|
102
|
+
"Boneh-Goh-Nissim",
|
|
99
103
|
]
|
|
100
104
|
|
|
101
105
|
cs = LightPHE(algorithm_name = algorithms[0])
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
<p align="center"><img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/phi.png" width="200" height="240"></p>
|
|
22
22
|
|
|
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/), [`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/)
|
|
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/), [`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/), `Sander-Young-Yung`, `Boneh-Goh-Nissim`.
|
|
24
24
|
|
|
25
25
|
# Partially vs Fully Homomorphic Encryption
|
|
26
26
|
|
|
@@ -51,18 +51,20 @@ from lightphe import LightPHE
|
|
|
51
51
|
|
|
52
52
|
In summary, LightPHE is covering following algorithms and these are partially homomorphic with respect to the operations mentioned in the following table.
|
|
53
53
|
|
|
54
|
-
| Algorithm | Multiplicatively<br>Homomorphic | Additively<br>Homomorphic | Scalar Multiplication |
|
|
55
|
-
| --- | --- | --- | --- | --- | --- |
|
|
56
|
-
| RSA | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
57
|
-
| ElGamal | ✅ | ❌ | ❌ | ❌ | ✅ |
|
|
58
|
-
| Exponential ElGamal | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
59
|
-
| Elliptic Curve ElGamal | ❌ | ✅ | ✅ | ❌ | ❌ |
|
|
60
|
-
| Paillier | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
61
|
-
| Damgard-Jurik | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
62
|
-
| Benaloh | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
63
|
-
| Naccache-Stern | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
64
|
-
| Okamoto-Uchiyama | ❌ | ✅ | ✅ | ❌ | ✅ |
|
|
65
|
-
| Goldwasser-Micali | ❌ | ❌ | ❌ | ✅ | ❌ |
|
|
54
|
+
| Algorithm | Multiplicatively<br>Homomorphic | Additively<br>Homomorphic | Scalar Multiplication | Bitwise-XOR Homomorphic | Bitwise-AND Homomorphic | Regeneration<br>of Ciphertext |
|
|
55
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
56
|
+
| RSA | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
|
57
|
+
| ElGamal | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
|
58
|
+
| Exponential ElGamal | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
59
|
+
| Elliptic Curve ElGamal | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
60
|
+
| Paillier | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
61
|
+
| Damgard-Jurik | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
62
|
+
| Benaloh | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
63
|
+
| Naccache-Stern | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
64
|
+
| Okamoto-Uchiyama | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
65
|
+
| Goldwasser-Micali | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ |
|
|
66
|
+
| Sander-Young-Yung | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
|
|
67
|
+
| Boneh-Goh-Nissim | 1️⃣ | ✅ | ✅ | ❌ | ❌ | ✅ |
|
|
66
68
|
|
|
67
69
|
# Building cryptosystem
|
|
68
70
|
|
|
@@ -79,7 +81,9 @@ algorithms = [
|
|
|
79
81
|
"Benaloh",
|
|
80
82
|
"Naccache-Stern",
|
|
81
83
|
"Goldwasser-Micali",
|
|
82
|
-
"EllipticCurve-ElGamal"
|
|
84
|
+
"EllipticCurve-ElGamal",
|
|
85
|
+
"Sander-Young-Yung",
|
|
86
|
+
"Boneh-Goh-Nissim",
|
|
83
87
|
]
|
|
84
88
|
|
|
85
89
|
cs = LightPHE(algorithm_name = algorithms[0])
|
|
@@ -28,13 +28,15 @@ from lightphe.cryptosystems.Benaloh import Benaloh
|
|
|
28
28
|
from lightphe.cryptosystems.NaccacheStern import NaccacheStern
|
|
29
29
|
from lightphe.cryptosystems.GoldwasserMicali import GoldwasserMicali
|
|
30
30
|
from lightphe.cryptosystems.EllipticCurveElGamal import EllipticCurveElGamal
|
|
31
|
+
from lightphe.cryptosystems.SanderYoungYung import SanderYoungYung
|
|
32
|
+
from lightphe.cryptosystems.BonehGohNissim import BonehGohNissim
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
# pylint: disable=eval-used, simplifiable-if-expression, too-few-public-methods
|
|
34
36
|
|
|
35
37
|
logger = Logger(module="lightphe/__init__.py")
|
|
36
38
|
|
|
37
|
-
VERSION = "0.0.
|
|
39
|
+
VERSION = "0.0.21"
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
class LightPHE:
|
|
@@ -57,7 +59,7 @@ class LightPHE:
|
|
|
57
59
|
Args:
|
|
58
60
|
algorithm_name (str): RSA | ElGamal | Exponential-ElGamal | EllipticCurve-ElGamal
|
|
59
61
|
| Paillier | Damgard-Jurik | Okamoto-Uchiyama | Benaloh | Naccache-Stern
|
|
60
|
-
| Goldwasser-Micali
|
|
62
|
+
| Goldwasser-Micali | Sander-Young-Yung | Boneh-Goh-Nissim
|
|
61
63
|
keys (dict): optional private-public key pair
|
|
62
64
|
key_file (str): if keys were exported already, you can load them into cryptosystem
|
|
63
65
|
key_size (int): key size in bits
|
|
@@ -116,13 +118,15 @@ class LightPHE:
|
|
|
116
118
|
Benaloh,
|
|
117
119
|
NaccacheStern,
|
|
118
120
|
EllipticCurveElGamal,
|
|
121
|
+
SanderYoungYung,
|
|
122
|
+
BonehGohNissim,
|
|
119
123
|
]:
|
|
120
124
|
"""
|
|
121
125
|
Build a cryptosystem among partially homomorphic algorithms
|
|
122
126
|
Args:
|
|
123
127
|
algorithm_name (str): RSA | ElGamal | Exponential-ElGamal | EllipticCurve-ElGamal
|
|
124
128
|
| Paillier | Damgard-Jurik | Okamoto-Uchiyama | Benaloh | Naccache-Stern
|
|
125
|
-
| Goldwasser-Micali | Edwards-ElGamal
|
|
129
|
+
| Goldwasser-Micali | Edwards-ElGamal | Sander-Young-Yung | Boneh-Goh-Nissim
|
|
126
130
|
Default is Paillier.
|
|
127
131
|
keys (dict): optional private-public key pair
|
|
128
132
|
key_file (str): if keys are exported, you can load them into cryptosystem
|
|
@@ -172,6 +176,12 @@ class LightPHE:
|
|
|
172
176
|
cs = NaccacheStern(keys=keys, key_size=key_size, max_tries=max_tries)
|
|
173
177
|
elif algorithm_name == Algorithm.GoldwasserMicali:
|
|
174
178
|
cs = GoldwasserMicali(keys=keys, key_size=key_size, max_tries=max_tries)
|
|
179
|
+
elif algorithm_name == Algorithm.SanderYoungYung:
|
|
180
|
+
cs = SanderYoungYung(
|
|
181
|
+
keys=keys, key_size=key_size, plaintext_limit=plaintext_limit
|
|
182
|
+
)
|
|
183
|
+
elif algorithm_name == Algorithm.BonehGohNissim:
|
|
184
|
+
cs = BonehGohNissim(keys=keys, key_size=key_size, max_tries=max_tries)
|
|
175
185
|
else:
|
|
176
186
|
raise ValueError(f"unimplemented algorithm - {algorithm_name}")
|
|
177
187
|
return cs
|
|
@@ -23,6 +23,10 @@ def normalize_input(value: Union[int, float], modulo: Union[int, str]) -> int:
|
|
|
23
23
|
# elliptic curve elgamal & koblitz curves
|
|
24
24
|
result = value % int(modulo, 2)
|
|
25
25
|
elif isinstance(value, int) and isinstance(modulo, int):
|
|
26
|
+
if value > modulo:
|
|
27
|
+
logger.warn(
|
|
28
|
+
f"Value {value} is greater than modulo {modulo}. Normalizing it to be in the range of modulo."
|
|
29
|
+
)
|
|
26
30
|
result = value % modulo
|
|
27
31
|
elif isinstance(value, float) and value >= 0:
|
|
28
32
|
dividend, divisor = fractionize(value=value, modulo=modulo)
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# built-in dependencies
|
|
2
|
+
import random
|
|
3
|
+
import math
|
|
4
|
+
from typing import Optional, Tuple, Union
|
|
5
|
+
|
|
6
|
+
# third-party dependencies
|
|
7
|
+
from lightecc import LightECC
|
|
8
|
+
from lightecc.interfaces.elliptic_curve import EllipticCurvePoint
|
|
9
|
+
from lightecc.commons.pairing import _fp2_pow, _fp2_mul
|
|
10
|
+
import sympy
|
|
11
|
+
from sympy.ntheory.residue_ntheory import sqrt_mod
|
|
12
|
+
|
|
13
|
+
# project dependencies
|
|
14
|
+
from lightphe.models.Homomorphic import Homomorphic
|
|
15
|
+
from lightphe.commons.logger import Logger
|
|
16
|
+
|
|
17
|
+
logger = Logger(module="lightphe/cryptosystems/BonehGohNissim.py")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BonehGohNissim(Homomorphic):
|
|
21
|
+
"""
|
|
22
|
+
Boneh-Goh-Nissim algorithm is homomorphic with respect to the addition.
|
|
23
|
+
It's also somehow homomorphic with respect to the multiplication
|
|
24
|
+
only for one multiplication per ciphertext
|
|
25
|
+
TODO: add a tutorial for this algorithm
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
keys: Optional[dict] = None,
|
|
31
|
+
key_size: Optional[int] = None,
|
|
32
|
+
max_tries: int = 10000,
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Args:
|
|
36
|
+
keys (dict): private - public key pair.
|
|
37
|
+
set this to None if you want to generate random keys.
|
|
38
|
+
key_size (int): size of the keys to generate in bits. Default is 1024.
|
|
39
|
+
"""
|
|
40
|
+
self.keys = keys or self.generate_keys(
|
|
41
|
+
key_size=key_size or 1024,
|
|
42
|
+
max_tries=max_tries,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
self.ec = LightECC(
|
|
46
|
+
form_name="weierstrass",
|
|
47
|
+
curve_name="custom",
|
|
48
|
+
config={
|
|
49
|
+
"a": self.keys["public_key"]["curve"]["a"],
|
|
50
|
+
"b": self.keys["public_key"]["curve"]["b"],
|
|
51
|
+
"p": self.keys["public_key"]["curve"]["p"],
|
|
52
|
+
"G": self.keys["public_key"]["curve"]["G"],
|
|
53
|
+
"n": self.keys["public_key"]["curve"]["n"],
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
self.plaintext_modulo = self.ec.modulo
|
|
58
|
+
self.ciphertext_modulo = self.ec.modulo
|
|
59
|
+
|
|
60
|
+
def generate_keys(
|
|
61
|
+
self,
|
|
62
|
+
key_size: int,
|
|
63
|
+
max_tries: int = 10000,
|
|
64
|
+
):
|
|
65
|
+
"""
|
|
66
|
+
Generate public and private keys of Boneh-Goh-Nissim cryptosystem
|
|
67
|
+
Returns:
|
|
68
|
+
keys (dict): having private_key and public_key keys
|
|
69
|
+
"""
|
|
70
|
+
keys = {}
|
|
71
|
+
keys["private_key"] = {}
|
|
72
|
+
keys["public_key"] = {}
|
|
73
|
+
|
|
74
|
+
for key_attempt in range(max_tries):
|
|
75
|
+
# choose large odd distinct primes q1 and q2
|
|
76
|
+
q1 = sympy.randprime(2 ** (key_size // 2), 2 ** (key_size // 2 + 1))
|
|
77
|
+
q2 = sympy.randprime(2 ** (key_size // 2), 2 ** (key_size // 2 + 1))
|
|
78
|
+
while q1 == q2:
|
|
79
|
+
q2 = sympy.randprime(2 ** (key_size // 2), 2 ** (key_size // 2 + 1))
|
|
80
|
+
|
|
81
|
+
n = q1 * q2
|
|
82
|
+
|
|
83
|
+
# Find l such that p = n*l - 1 is prime and p ≡ 3 (mod 4).
|
|
84
|
+
# Supersingularity of y² = x³ + x requires p ≡ 3 (mod 4).
|
|
85
|
+
# Since n is odd (product of two odd primes), n*l ≡ 0 (mod 4)
|
|
86
|
+
# iff l ≡ 0 (mod 4). So we iterate multiples of 4 systematically.
|
|
87
|
+
l = None
|
|
88
|
+
for l_candidate in range(4, max_tries * 4 + 4, 4):
|
|
89
|
+
p_candidate = n * l_candidate - 1
|
|
90
|
+
if sympy.isprime(p_candidate):
|
|
91
|
+
l = l_candidate
|
|
92
|
+
break
|
|
93
|
+
|
|
94
|
+
if l is None:
|
|
95
|
+
logger.debug(
|
|
96
|
+
f"No valid l found for attempt {key_attempt + 1}, retrying"
|
|
97
|
+
)
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
p = n * l - 1
|
|
101
|
+
a = 1
|
|
102
|
+
b = 0
|
|
103
|
+
|
|
104
|
+
G = self.__find_generator(p, max_tries=max_tries)
|
|
105
|
+
|
|
106
|
+
# order of the curve may not be exactly n, but it should be
|
|
107
|
+
self.ec = LightECC(
|
|
108
|
+
form_name="weierstrass",
|
|
109
|
+
curve_name="custom",
|
|
110
|
+
config={"a": a, "b": b, "p": p, "G": G, "n": None},
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
nG = n * self.ec.G
|
|
114
|
+
if (
|
|
115
|
+
nG == self.ec.O
|
|
116
|
+
): # check if nG is the point at infinity / identity element / neutral element
|
|
117
|
+
logger.debug("nG is the point at infinity, as expected.")
|
|
118
|
+
logger.debug(f"q1 = {q1}, q2 = {q2}, n = {n}, p = {p}, l = {l}")
|
|
119
|
+
break
|
|
120
|
+
|
|
121
|
+
logger.debug(f"nG not infinity, retrying (attempt {key_attempt + 1})")
|
|
122
|
+
else:
|
|
123
|
+
raise Exception(f"Failed to generate keys after {max_tries} attempts")
|
|
124
|
+
|
|
125
|
+
while True:
|
|
126
|
+
r = random.randint(2, n - 1)
|
|
127
|
+
if math.gcd(r, n) == 1:
|
|
128
|
+
break
|
|
129
|
+
|
|
130
|
+
u = r * self.ec.G
|
|
131
|
+
h = u * q2
|
|
132
|
+
|
|
133
|
+
keys["public_key"]["curve"] = {
|
|
134
|
+
"a": a,
|
|
135
|
+
"b": b,
|
|
136
|
+
"p": p,
|
|
137
|
+
"G": G,
|
|
138
|
+
"n": n,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
keys["private_key"]["q1"] = q1
|
|
142
|
+
keys["private_key"]["q2"] = q2
|
|
143
|
+
keys["public_key"]["G"] = G
|
|
144
|
+
keys["public_key"]["u"] = u.get_point()
|
|
145
|
+
keys["public_key"]["h"] = h.get_point()
|
|
146
|
+
keys["public_key"]["l"] = l
|
|
147
|
+
return keys
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def __find_generator(p, max_tries=10000) -> Tuple[int, int]:
|
|
151
|
+
if not sympy.isprime(p):
|
|
152
|
+
raise ValueError("p must be prime")
|
|
153
|
+
|
|
154
|
+
for _ in range(max_tries):
|
|
155
|
+
x = random.randint(0, p - 1)
|
|
156
|
+
rhs = (pow(x, 3, p) + x) % p
|
|
157
|
+
y_list = sqrt_mod(rhs, p, all_roots=True) # get all square roots
|
|
158
|
+
if y_list: # if there is at least one solution
|
|
159
|
+
return x, y_list[0] # just return the first one
|
|
160
|
+
|
|
161
|
+
raise Exception(f"Failed to find a generator after {max_tries} attempts")
|
|
162
|
+
|
|
163
|
+
def generate_random_key(self) -> int:
|
|
164
|
+
"""
|
|
165
|
+
Boneh-Goh-Nissim requires to generate one-time random key per encryption
|
|
166
|
+
Returns:
|
|
167
|
+
random key (int): one time random key for encryption
|
|
168
|
+
"""
|
|
169
|
+
q2 = self.keys["private_key"]["q2"]
|
|
170
|
+
return random.randint(1, q2 - 1)
|
|
171
|
+
|
|
172
|
+
def encrypt(
|
|
173
|
+
self, plaintext: int, random_key: Optional[int] = None
|
|
174
|
+
) -> EllipticCurvePoint:
|
|
175
|
+
"""
|
|
176
|
+
Encrypt a given plaintext for optionally given random key with Boneh-Goh-Nissim
|
|
177
|
+
Args:
|
|
178
|
+
plaintext (int): message to encrypt
|
|
179
|
+
random_key (int): one time random key for encryption
|
|
180
|
+
Returns:
|
|
181
|
+
ciphertext (EllipticCurvePoint): encrypted message as a point on the elliptic curve
|
|
182
|
+
"""
|
|
183
|
+
r = random_key or self.generate_random_key()
|
|
184
|
+
G = self.ec.G
|
|
185
|
+
h = self.keys["public_key"]["h"]
|
|
186
|
+
h = EllipticCurvePoint(x=h[0], y=h[1], curve=self.ec.curve)
|
|
187
|
+
c = (G * plaintext) + (h * r)
|
|
188
|
+
return c
|
|
189
|
+
|
|
190
|
+
def decrypt(self, ciphertext: Union[EllipticCurvePoint, Tuple[int, int]]) -> int:
|
|
191
|
+
"""
|
|
192
|
+
Decrypt a given ciphertext with Boneh-Goh-Nissim.
|
|
193
|
+
Handles both G1 ciphertexts (EllipticCurvePoint, from encryption/addition)
|
|
194
|
+
and G_T ciphertexts (tuple in F_{p^2}, from homomorphic multiplication).
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
ciphertext: encrypted message — either an EllipticCurvePoint or
|
|
198
|
+
a tuple (a, b) representing a + b*i in F_{p^2}
|
|
199
|
+
Returns:
|
|
200
|
+
plaintext (int): restored message
|
|
201
|
+
"""
|
|
202
|
+
q1 = self.keys["private_key"]["q1"]
|
|
203
|
+
|
|
204
|
+
if isinstance(ciphertext, tuple):
|
|
205
|
+
return self._decrypt_gt(ciphertext, q1)
|
|
206
|
+
|
|
207
|
+
G = self.ec.G
|
|
208
|
+
|
|
209
|
+
mP = ciphertext * q1
|
|
210
|
+
P = G * q1
|
|
211
|
+
|
|
212
|
+
for i in range(1, q1 + 1):
|
|
213
|
+
iP = P * i
|
|
214
|
+
if iP == mP:
|
|
215
|
+
return i
|
|
216
|
+
|
|
217
|
+
raise Exception("Decryption failed")
|
|
218
|
+
|
|
219
|
+
def _decrypt_gt(self, ciphertext: tuple, q1: int) -> int:
|
|
220
|
+
"""
|
|
221
|
+
Decrypt a G_T ciphertext (result of homomorphic multiplication).
|
|
222
|
+
|
|
223
|
+
e(C1, C2)^q1 = e(G, G)^(q1 * m1 * m2)
|
|
224
|
+
Solve DLP: find m such that base^m == target, where
|
|
225
|
+
base = e(G, G)^q1
|
|
226
|
+
target = e(C1, C2)^q1
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
ciphertext: pairing value (a, b) in F_{p^2}
|
|
230
|
+
q1: private key component
|
|
231
|
+
Returns:
|
|
232
|
+
plaintext product m1 * m2
|
|
233
|
+
"""
|
|
234
|
+
p = self.ec.modulo
|
|
235
|
+
G = self.ec.G
|
|
236
|
+
|
|
237
|
+
# e(G, G) — pairing of generator with itself via distortion map
|
|
238
|
+
e_gg = self.ec.pairing(G, G)
|
|
239
|
+
|
|
240
|
+
# base = e(G, G)^q1, target = e(C1, C2)^q1
|
|
241
|
+
base = _fp2_pow(e_gg, q1, p)
|
|
242
|
+
target = _fp2_pow(ciphertext, q1, p)
|
|
243
|
+
|
|
244
|
+
# brute-force DLP in G_T
|
|
245
|
+
acc = (1, 0)
|
|
246
|
+
for i in range(1, q1 + 1):
|
|
247
|
+
acc = _fp2_mul(acc, base, p)
|
|
248
|
+
if acc == target:
|
|
249
|
+
return i
|
|
250
|
+
|
|
251
|
+
raise Exception("Decryption of G_T ciphertext failed")
|
|
252
|
+
|
|
253
|
+
def add(
|
|
254
|
+
self, ciphertext1: EllipticCurvePoint, ciphertext2: EllipticCurvePoint
|
|
255
|
+
) -> EllipticCurvePoint:
|
|
256
|
+
"""
|
|
257
|
+
Add two ciphertexts with Boneh-Goh-Nissim
|
|
258
|
+
Args:
|
|
259
|
+
ciphertext1 (EllipticCurvePoint): first encrypted message as a point on the elliptic curve
|
|
260
|
+
ciphertext2 (EllipticCurvePoint): second encrypted message as a point on the elliptic curve
|
|
261
|
+
Returns:
|
|
262
|
+
result (tuple): resulting ciphertext after addition
|
|
263
|
+
"""
|
|
264
|
+
return ciphertext1 + ciphertext2
|
|
265
|
+
|
|
266
|
+
def multiply(
|
|
267
|
+
self,
|
|
268
|
+
ciphertext1: EllipticCurvePoint,
|
|
269
|
+
ciphertext2: EllipticCurvePoint,
|
|
270
|
+
) -> Tuple[int, int]:
|
|
271
|
+
"""
|
|
272
|
+
Homomorphic multiplication of two ciphertexts using the bilinear pairing.
|
|
273
|
+
The result is an element of F_{p^2} (the pairing target group G_T),
|
|
274
|
+
not a point on the elliptic curve. BGN supports only one multiplication
|
|
275
|
+
per ciphertext — the result cannot be multiplied again.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
ciphertext1: first encrypted message (point on E(F_p))
|
|
279
|
+
ciphertext2: second encrypted message (point on E(F_p))
|
|
280
|
+
Returns:
|
|
281
|
+
result (tuple): pairing value (a, b) representing a + b*i in F_{p^2}
|
|
282
|
+
"""
|
|
283
|
+
# The tuple (a, b) represents a + b·i where i² = -1 mod p
|
|
284
|
+
if isinstance(ciphertext1, tuple) or isinstance(ciphertext2, tuple):
|
|
285
|
+
raise ValueError(
|
|
286
|
+
"Boneh-Goh-Nissim only supports multiplication ciphertexts once!"
|
|
287
|
+
)
|
|
288
|
+
result = self.ec.pairing(ciphertext1, ciphertext2)
|
|
289
|
+
if not isinstance(result, tuple):
|
|
290
|
+
raise ValueError(
|
|
291
|
+
"Boneh-Goh-Nissim requires a supersingular curve with embedding degree 2. "
|
|
292
|
+
"The pairing returned an F_p element instead of an F_{p^2} element."
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# the pairing result is an element of F_{p²}, not a point on the curve.
|
|
296
|
+
# In BGN, the pairing maps two curve points to a field element
|
|
297
|
+
# (in the multiplicative group G_T). The result of e(C1, C2) lives
|
|
298
|
+
# in F_{p²}*, not on the elliptic curve. The homomorphic multiplication
|
|
299
|
+
# works in G_T (the target group of the pairing), not back on the curve.
|
|
300
|
+
return result
|
|
301
|
+
|
|
302
|
+
def multiply_by_constant(
|
|
303
|
+
self, ciphertext: EllipticCurvePoint, constant: int
|
|
304
|
+
) -> EllipticCurvePoint:
|
|
305
|
+
"""
|
|
306
|
+
Multiply a ciphertext by a constant with Boneh-Goh-Nissim
|
|
307
|
+
Args:
|
|
308
|
+
ciphertext (tuple): encrypted message as a tuple of two points on the elliptic curve
|
|
309
|
+
constant (int): constant to multiply with the ciphertext
|
|
310
|
+
Returns:
|
|
311
|
+
result (tuple): resulting ciphertext after multiplication
|
|
312
|
+
"""
|
|
313
|
+
return ciphertext * constant
|
|
314
|
+
|
|
315
|
+
def reencrypt(self, ciphertext: EllipticCurvePoint) -> EllipticCurvePoint:
|
|
316
|
+
"""
|
|
317
|
+
Re-encrypt a given ciphertext with Boneh-Goh-Nissim
|
|
318
|
+
Args:
|
|
319
|
+
ciphertext (tuple): encrypted message as a tuple of two points on the elliptic curve
|
|
320
|
+
Returns:
|
|
321
|
+
reencrypted_ciphertext (tuple): re-encrypted message as a tuple of two points on the elliptic curve
|
|
322
|
+
"""
|
|
323
|
+
h = self.keys["public_key"]["h"]
|
|
324
|
+
h = EllipticCurvePoint(x=h[0], y=h[1], curve=self.ec.curve)
|
|
325
|
+
r = self.generate_random_key()
|
|
326
|
+
c_prime = ciphertext + (r * h)
|
|
327
|
+
return c_prime
|
|
@@ -166,8 +166,6 @@ class EllipticCurveElGamal(Homomorphic):
|
|
|
166
166
|
|
|
167
167
|
return a.get_point(), b.get_point()
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
|
|
171
169
|
def multiply_by_constant(self, ciphertext: tuple, constant: int) -> tuple:
|
|
172
170
|
"""
|
|
173
171
|
Multiply a ciphertext with a plain constant.
|
|
@@ -190,3 +188,25 @@ class EllipticCurveElGamal(Homomorphic):
|
|
|
190
188
|
Q_prime = Q * constant
|
|
191
189
|
|
|
192
190
|
return P_prime.get_point(), Q_prime.get_point()
|
|
191
|
+
|
|
192
|
+
def reencrypt(self, ciphertext: tuple) -> tuple:
|
|
193
|
+
"""
|
|
194
|
+
Re-encrypt a ciphertext with a new random key
|
|
195
|
+
Args:
|
|
196
|
+
ciphertext (tuple): c1 and c2
|
|
197
|
+
Returns:
|
|
198
|
+
ciphertext (tuple): new c1 and c2
|
|
199
|
+
"""
|
|
200
|
+
r_prime = self.generate_random_key()
|
|
201
|
+
|
|
202
|
+
x, y = self.keys["public_key"]["Qa"]
|
|
203
|
+
Qa = EllipticCurvePoint(x=x, y=y, curve=self.ecc.curve)
|
|
204
|
+
|
|
205
|
+
# c1 and c2 as tuple of integers
|
|
206
|
+
c1, c2 = ciphertext
|
|
207
|
+
c1 = EllipticCurvePoint(x=c1[0], y=c1[1], curve=self.ecc.curve)
|
|
208
|
+
c2 = EllipticCurvePoint(x=c2[0], y=c2[1], curve=self.ecc.curve)
|
|
209
|
+
|
|
210
|
+
c1_prime = c1 + r_prime * self.ecc.G
|
|
211
|
+
c2_prime = c2 + r_prime * Qa
|
|
212
|
+
return c1_prime.get_point(), c2_prime.get_point()
|
|
@@ -171,16 +171,6 @@ class GoldwasserMicali(Homomorphic):
|
|
|
171
171
|
m_binary = "".join(m_binaries)
|
|
172
172
|
return int(m_binary, 2)
|
|
173
173
|
|
|
174
|
-
def add(self, ciphertext1: list, ciphertext2: list) -> list:
|
|
175
|
-
raise ValueError(
|
|
176
|
-
"Goldwasser-Micali is not homomorphic with respect to the addition"
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
def multiply(self, ciphertext1: int, ciphertext2: int) -> int:
|
|
180
|
-
raise ValueError(
|
|
181
|
-
"Goldwasser-Micali is not homomorphic with respect to the multiplication"
|
|
182
|
-
)
|
|
183
|
-
|
|
184
174
|
def xor(self, ciphertext1: List[int], ciphertext2: List[int]) -> List[int]:
|
|
185
175
|
"""
|
|
186
176
|
Perform homomorphic xor on encrypted data.
|
|
@@ -211,3 +201,21 @@ class GoldwasserMicali(Homomorphic):
|
|
|
211
201
|
ciphertext3.append((c1 * c2) % self.ciphertext_modulo)
|
|
212
202
|
|
|
213
203
|
return ciphertext3
|
|
204
|
+
|
|
205
|
+
def reencrypt(self, ciphertext: List[int]) -> List[int]:
|
|
206
|
+
"""
|
|
207
|
+
Re-encrypt a given ciphertext with Goldwasser-Micali
|
|
208
|
+
Args:
|
|
209
|
+
ciphertext (int): encrypted message
|
|
210
|
+
Returns:
|
|
211
|
+
ciphertext (int): re-encrypted message
|
|
212
|
+
"""
|
|
213
|
+
n = self.keys["public_key"]["n"]
|
|
214
|
+
|
|
215
|
+
c_reencrypted = []
|
|
216
|
+
for ci in ciphertext:
|
|
217
|
+
ri = self.generate_random_key()
|
|
218
|
+
ci_reencrypted = (pow(ri, 2, n) * ci) % n
|
|
219
|
+
c_reencrypted.append(ci_reencrypted)
|
|
220
|
+
|
|
221
|
+
return c_reencrypted
|