lightphe 0.0.22__tar.gz → 0.0.23__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.22 → lightphe-0.0.23}/PKG-INFO +2 -2
- {lightphe-0.0.22 → lightphe-0.0.23}/README.md +1 -1
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/__init__.py +1 -1
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/BonehGohNissim.py +33 -8
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe.egg-info/PKG-INFO +2 -2
- {lightphe-0.0.22 → lightphe-0.0.23}/setup.py +1 -1
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_bonehgohnissim.py +71 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/LICENSE +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/commons/__init__.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/commons/logger.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/commons/phe_utils.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/Benaloh.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/DamgardJurik.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/ElGamal.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/EllipticCurveElGamal.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/GoldwasserMicali.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/NaccacheStern.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/OkamotoUchiyama.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/Paillier.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/RSA.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/SanderYoungYung.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/cryptosystems/__init__.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/models/Algorithm.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/models/Ciphertext.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/models/Homomorphic.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/models/Tensor.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe/models/__init__.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe.egg-info/SOURCES.txt +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe.egg-info/dependency_links.txt +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe.egg-info/requires.txt +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/lightphe.egg-info/top_level.txt +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/requirements.txt +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/setup.cfg +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/__init__.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_benaloh.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_ciphertexts.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_cloud.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_damgard.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_elgamal.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_ellipticcurveelgamal.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_exporting_keys.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_goldwasser.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_keys.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_large_keys.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_naccache.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_okamoto.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_paillier.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_rsa.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_salary.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/tests/test_sanderyoungyung.py +0 -0
- {lightphe-0.0.22 → lightphe-0.0.23}/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.23
|
|
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
|
|
39
|
+
LightPHE is a lightweight homomorphic encryption library for python supporting various partially and somewhat homomorphic encryptions 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`](https://sefiks.com/2026/04/02/a-step-by-step-partially-homomorphic-sander-young-yung-example-in-python/), [`Boneh-Goh-Nissim`](https://sefiks.com/2026/04/02/a-step-by-step-somewhat-homomorphic-encryption-example-with-boneh-goh-nissim-in-python/).
|
|
40
40
|
|
|
41
41
|
# Partially vs Fully Homomorphic Encryption
|
|
42
42
|
|
|
@@ -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
|
|
23
|
+
LightPHE is a lightweight homomorphic encryption library for python supporting various partially and somewhat homomorphic encryptions 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`](https://sefiks.com/2026/04/02/a-step-by-step-partially-homomorphic-sander-young-yung-example-in-python/), [`Boneh-Goh-Nissim`](https://sefiks.com/2026/04/02/a-step-by-step-somewhat-homomorphic-encryption-example-with-boneh-goh-nissim-in-python/).
|
|
24
24
|
|
|
25
25
|
# Partially vs Fully Homomorphic Encryption
|
|
26
26
|
|
|
@@ -54,7 +54,10 @@ class BonehGohNissim(Homomorphic):
|
|
|
54
54
|
},
|
|
55
55
|
)
|
|
56
56
|
|
|
57
|
-
self.
|
|
57
|
+
if "private_key" in self.keys and "q2" in self.keys["private_key"]:
|
|
58
|
+
self.plaintext_modulo = self.keys["private_key"]["q2"]
|
|
59
|
+
else:
|
|
60
|
+
self.plaintext_modulo = self.keys["public_key"]["curve"]["n"]
|
|
58
61
|
self.ciphertext_modulo = self.ec.modulo
|
|
59
62
|
|
|
60
63
|
def generate_keys(
|
|
@@ -160,14 +163,28 @@ class BonehGohNissim(Homomorphic):
|
|
|
160
163
|
|
|
161
164
|
raise Exception(f"Failed to find a generator after {max_tries} attempts")
|
|
162
165
|
|
|
166
|
+
def _has_private_key(self) -> bool:
|
|
167
|
+
return "private_key" in self.keys and "q2" in self.keys["private_key"]
|
|
168
|
+
|
|
163
169
|
def generate_random_key(self) -> int:
|
|
164
170
|
"""
|
|
165
171
|
Boneh-Goh-Nissim requires to generate one-time random key per encryption
|
|
166
172
|
Returns:
|
|
167
173
|
random key (int): one time random key for encryption
|
|
168
174
|
"""
|
|
169
|
-
|
|
170
|
-
|
|
175
|
+
if self._has_private_key():
|
|
176
|
+
q2 = self.keys["private_key"]["q2"]
|
|
177
|
+
return random.randint(1, q2 - 1)
|
|
178
|
+
|
|
179
|
+
n = self.keys["public_key"]["curve"]["n"]
|
|
180
|
+
logger.warn(
|
|
181
|
+
"Private key is not available. Random key will be bounded by n"
|
|
182
|
+
" instead of q2. Encryption will work for small plaintexts,"
|
|
183
|
+
" but negative number encoding via plaintext_modulo will not"
|
|
184
|
+
" round-trip correctly because plaintext_modulo is set to n"
|
|
185
|
+
" (public) instead of q2 (private)."
|
|
186
|
+
)
|
|
187
|
+
return random.randint(1, n - 1)
|
|
171
188
|
|
|
172
189
|
def encrypt(
|
|
173
190
|
self, plaintext: int, random_key: Optional[int] = None
|
|
@@ -200,23 +217,28 @@ class BonehGohNissim(Homomorphic):
|
|
|
200
217
|
plaintext (int): restored message
|
|
201
218
|
"""
|
|
202
219
|
q1 = self.keys["private_key"]["q1"]
|
|
220
|
+
q2 = self.keys["private_key"]["q2"]
|
|
203
221
|
|
|
204
222
|
if isinstance(ciphertext, tuple):
|
|
205
|
-
return self._decrypt_gt(ciphertext, q1)
|
|
223
|
+
return self._decrypt_gt(ciphertext, q1, q2)
|
|
206
224
|
|
|
207
225
|
G = self.ec.G
|
|
208
226
|
|
|
209
227
|
mP = ciphertext * q1
|
|
210
228
|
P = G * q1
|
|
211
229
|
|
|
212
|
-
|
|
230
|
+
# P has order q2, so DLP result is in [0, q2)
|
|
231
|
+
if mP == self.ec.O:
|
|
232
|
+
return 0
|
|
233
|
+
|
|
234
|
+
for i in range(1, q2):
|
|
213
235
|
iP = P * i
|
|
214
236
|
if iP == mP:
|
|
215
237
|
return i
|
|
216
238
|
|
|
217
239
|
raise Exception("Decryption failed")
|
|
218
240
|
|
|
219
|
-
def _decrypt_gt(self, ciphertext: tuple, q1: int) -> int:
|
|
241
|
+
def _decrypt_gt(self, ciphertext: tuple, q1: int, q2: int) -> int:
|
|
220
242
|
"""
|
|
221
243
|
Decrypt a G_T ciphertext (result of homomorphic multiplication).
|
|
222
244
|
|
|
@@ -241,9 +263,12 @@ class BonehGohNissim(Homomorphic):
|
|
|
241
263
|
base = _fp2_pow(e_gg, q1, p)
|
|
242
264
|
target = _fp2_pow(ciphertext, q1, p)
|
|
243
265
|
|
|
244
|
-
# brute-force DLP in G_T
|
|
266
|
+
# brute-force DLP in G_T — result is in [0, q2)
|
|
267
|
+
if target == (1, 0):
|
|
268
|
+
return 0
|
|
269
|
+
|
|
245
270
|
acc = (1, 0)
|
|
246
|
-
for i in range(1,
|
|
271
|
+
for i in range(1, q2):
|
|
247
272
|
acc = _fp2_mul(acc, base, p)
|
|
248
273
|
if acc == target:
|
|
249
274
|
return i
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lightphe
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.23
|
|
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
|
|
39
|
+
LightPHE is a lightweight homomorphic encryption library for python supporting various partially and somewhat homomorphic encryptions 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`](https://sefiks.com/2026/04/02/a-step-by-step-partially-homomorphic-sander-young-yung-example-in-python/), [`Boneh-Goh-Nissim`](https://sefiks.com/2026/04/02/a-step-by-step-somewhat-homomorphic-encryption-example-with-boneh-goh-nissim-in-python/).
|
|
40
40
|
|
|
41
41
|
# Partially vs Fully Homomorphic Encryption
|
|
42
42
|
|
|
@@ -8,7 +8,7 @@ with open("requirements.txt", "r", encoding="utf-8") as f:
|
|
|
8
8
|
|
|
9
9
|
setuptools.setup(
|
|
10
10
|
name="lightphe",
|
|
11
|
-
version="0.0.
|
|
11
|
+
version="0.0.23",
|
|
12
12
|
author="Sefik Ilkin Serengil",
|
|
13
13
|
author_email="serengil@gmail.com",
|
|
14
14
|
description="A Lightweight Partially Homomorphic Encryption Library for Python",
|
|
@@ -108,6 +108,77 @@ def test_linear_regression():
|
|
|
108
108
|
)
|
|
109
109
|
|
|
110
110
|
|
|
111
|
+
def test_cosine_similarity():
|
|
112
|
+
tic = time.time()
|
|
113
|
+
i1 = 5
|
|
114
|
+
i2 = 2
|
|
115
|
+
i3 = 8
|
|
116
|
+
|
|
117
|
+
# v2 = [1, 1, 2]
|
|
118
|
+
j1 = 1
|
|
119
|
+
j2 = 1
|
|
120
|
+
j3 = 2
|
|
121
|
+
|
|
122
|
+
i1_enc = cs.encrypt(i1)
|
|
123
|
+
i2_enc = cs.encrypt(i2)
|
|
124
|
+
i3_enc = cs.encrypt(i3)
|
|
125
|
+
|
|
126
|
+
j1_enc = cs.encrypt(j1)
|
|
127
|
+
j2_enc = cs.encrypt(j2)
|
|
128
|
+
j3_enc = cs.encrypt(j3)
|
|
129
|
+
|
|
130
|
+
# homomorphic operation
|
|
131
|
+
cosine_sim_enc = i1_enc * j1_enc + i2_enc * j2_enc + i3_enc * j3_enc
|
|
132
|
+
|
|
133
|
+
# proof of work
|
|
134
|
+
assert cs.decrypt(cosine_sim_enc) == i1 * j1 + i2 * j2 + i3 * j3
|
|
135
|
+
|
|
136
|
+
logger.info(
|
|
137
|
+
f"✅ Boneh-God-Nissim cosine similarity test succeeded "
|
|
138
|
+
f"({security_level} bit ECC security level)"
|
|
139
|
+
f" in {time.time() - tic:.2f} seconds"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_euclidean_distance():
|
|
144
|
+
tic = time.time()
|
|
145
|
+
|
|
146
|
+
# v1 = [5, 2, 3]
|
|
147
|
+
i1 = 5
|
|
148
|
+
i2 = 2
|
|
149
|
+
i3 = 8
|
|
150
|
+
|
|
151
|
+
# v2 = [1, 1, 2]
|
|
152
|
+
j1 = 1
|
|
153
|
+
j2 = 1
|
|
154
|
+
j3 = 2
|
|
155
|
+
|
|
156
|
+
i1_enc = cs.encrypt(i1)
|
|
157
|
+
i2_enc = cs.encrypt(i2)
|
|
158
|
+
i3_enc = cs.encrypt(i3)
|
|
159
|
+
|
|
160
|
+
j1_enc = cs.encrypt(-j1)
|
|
161
|
+
j2_enc = cs.encrypt(-j2)
|
|
162
|
+
j3_enc = cs.encrypt(-j3)
|
|
163
|
+
|
|
164
|
+
euclidean_sqrt_enc = (
|
|
165
|
+
(i1_enc + j1_enc) * (i1_enc + j1_enc)
|
|
166
|
+
+ (i2_enc + j2_enc) * (i2_enc + j2_enc)
|
|
167
|
+
+ (i3_enc + j3_enc) * (i3_enc + j3_enc)
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
assert (
|
|
171
|
+
cs.decrypt(euclidean_sqrt_enc)
|
|
172
|
+
== (i1 - j1) ** 2 + (i2 - j2) ** 2 + (i3 - j3) ** 2
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
logger.info(
|
|
176
|
+
f"✅ Boneh-God-Nissim euclidean distance test succeeded "
|
|
177
|
+
f"({security_level} bit ECC security level)"
|
|
178
|
+
f" in {time.time() - tic:.2f} seconds"
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
111
182
|
def test_api_with_predefined_keys():
|
|
112
183
|
keys = {
|
|
113
184
|
"private_key": {"q1": 1260048562698661, "q2": 1495813357973021},
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|