lightphe 0.0.15__tar.gz → 0.0.17__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.
Files changed (49) hide show
  1. {lightphe-0.0.15 → lightphe-0.0.17}/PKG-INFO +45 -212
  2. {lightphe-0.0.15 → lightphe-0.0.17}/README.md +44 -211
  3. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/__init__.py +1 -1
  4. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/Benaloh.py +31 -19
  5. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/DamgardJurik.py +1 -1
  6. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/ElGamal.py +1 -1
  7. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/EllipticCurveElGamal.py +1 -1
  8. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/GoldwasserMicali.py +36 -30
  9. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/NaccacheStern.py +103 -94
  10. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/OkamotoUchiyama.py +1 -1
  11. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/Paillier.py +1 -1
  12. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/models/Ciphertext.py +2 -2
  13. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/models/Homomorphic.py +21 -7
  14. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/models/Tensor.py +2 -2
  15. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe.egg-info/PKG-INFO +45 -212
  16. lightphe-0.0.17/lightphe.egg-info/requires.txt +4 -0
  17. lightphe-0.0.17/requirements.txt +4 -0
  18. {lightphe-0.0.15 → lightphe-0.0.17}/setup.py +1 -1
  19. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_benaloh.py +10 -3
  20. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_damgard.py +1 -1
  21. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_elgamal.py +2 -2
  22. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_ellipticcurveelgamal.py +1 -1
  23. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_goldwasser.py +10 -3
  24. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_keys.py +7 -2
  25. lightphe-0.0.17/tests/test_naccache.py +203 -0
  26. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_okamoto.py +1 -1
  27. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_paillier.py +1 -1
  28. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_rsa.py +1 -1
  29. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_salary.py +1 -1
  30. lightphe-0.0.15/lightphe.egg-info/requires.txt +0 -4
  31. lightphe-0.0.15/requirements.txt +0 -4
  32. lightphe-0.0.15/tests/test_naccache.py +0 -94
  33. {lightphe-0.0.15 → lightphe-0.0.17}/LICENSE +0 -0
  34. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/commons/__init__.py +0 -0
  35. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/commons/logger.py +0 -0
  36. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/commons/phe_utils.py +0 -0
  37. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/RSA.py +0 -0
  38. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/cryptosystems/__init__.py +0 -0
  39. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/models/Algorithm.py +0 -0
  40. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe/models/__init__.py +0 -0
  41. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe.egg-info/SOURCES.txt +0 -0
  42. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe.egg-info/dependency_links.txt +0 -0
  43. {lightphe-0.0.15 → lightphe-0.0.17}/lightphe.egg-info/top_level.txt +0 -0
  44. {lightphe-0.0.15 → lightphe-0.0.17}/setup.cfg +0 -0
  45. {lightphe-0.0.15 → lightphe-0.0.17}/tests/__init__.py +0 -0
  46. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_ciphertexts.py +0 -0
  47. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_cloud.py +0 -0
  48. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_exporting_keys.py +0 -0
  49. {lightphe-0.0.15 → lightphe-0.0.17}/tests/test_tensors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightphe
3
- Version: 0.0.15
3
+ Version: 0.0.17
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
@@ -28,7 +28,7 @@ License-File: LICENSE
28
28
  [![YouTube](https://img.shields.io/:youtube-@sefiks-red.svg?style=flat&logo=youtube)](https://www.youtube.com/@sefiks?sub_confirmation=1)
29
29
  [![Twitter](https://img.shields.io/:follow-@serengil-blue.svg?style=flat&logo=x)](https://twitter.com/intent/user?screen_name=serengil)
30
30
 
31
- [![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dserengil%26type%3Dpatrons&style=flat)](https://www.patreon.com/serengil?repo=lightphe)
31
+ [![Patreon](https://img.shields.io/:become-patron-f96854.svg?style=flat&logo=patreon)](https://www.patreon.com/serengil?repo=lightphe)
32
32
  [![GitHub Sponsors](https://img.shields.io/github/sponsors/serengil?logo=GitHub&color=lightgray)](https://github.com/sponsors/serengil)
33
33
  [![Buy Me a Coffee](https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee)](https://buymeacoffee.com/serengil)
34
34
 
@@ -67,7 +67,7 @@ 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 | Multiplication with a Plain Constant | Exclusively<br>Homomorphic | Regeneration<br>of Ciphertext |
70
+ | Algorithm | Multiplicatively<br>Homomorphic | Additively<br>Homomorphic | Scalar Multiplication | Exclusively<br>Homomorphic | Regeneration<br>of Ciphertext |
71
71
  | --- | --- | --- | --- | --- | --- |
72
72
  | RSA | ✅ | ❌ | ❌ | ❌ | ❌ |
73
73
  | ElGamal | ✅ | ❌ | ❌ | ❌ | ✅ |
@@ -98,124 +98,56 @@ algorithms = [
98
98
  "EllipticCurve-ElGamal"
99
99
  ]
100
100
 
101
- phe = LightPHE(algorithm_name = algorithms[0])
101
+ cs = LightPHE(algorithm_name = algorithms[0])
102
102
  ```
103
103
 
104
- # Encryption & Decryption
104
+ # Homomorphic Operations
105
105
 
106
- Once you built your cryptosystem, you will be able to encrypt and decrypt messages with the built cryptosystem.
106
+ The following example demonstrates a simple workflow using LightPHE with an additively homomorphic cryptosystem (e.g. Paillier). First, we build the cryptosystem on-premises and define two plaintext values. Next, we encrypt the plaintexts, which can be done either on-premises or in the cloud, and does not require the private key. Homomorphic operations, such as addition and scalar multiplication, can then be performed on the ciphertexts—these operations can be offloaded to the cloud, leveraging its computational power without revealing the private key or the plaintext. Finally, the results are decrypted on-premises using the private key, verifying that the homomorphic operations on encrypted data produce the expected plaintext results.
107
107
 
108
108
  ```python
109
- # define plaintext
110
- m = 17
109
+ # build an additively homomorphic cryptosystem
110
+ cs = LightPHE(algorithm_name = "Paillier")
111
111
 
112
- # calculate ciphertext
113
- c = phe.encrypt(m)
112
+ # define plaintexts
113
+ m1 = 10000 # base salary in usd
114
+ m2 = 500 # wage increase in usd
114
115
 
115
- # proof of work
116
- assert phe.decrypt(c) == m
117
- ```
118
-
119
- # Homomorphic Operations
116
+ # encrypt plaintexts - private key is not required.
117
+ c1 = cs.encrypt(m1)
118
+ c2 = cs.encrypt(m2)
120
119
 
121
- Once you have the ciphertext, you will be able to perform homomorphic operations on encrypted data without holding private key. For instance, Paillier is homomorphic with respect to the addition. In other words, decryption of the addition of two ciphertexts is equivalent to addition of plaintexts.
120
+ # homomorphic addition - private key is not required
121
+ c3 = c1 + c2
122
122
 
123
- ### On-Prem Encryption
124
-
125
- This code snippet illustrates how to generate a random public-private key pair using the Paillier and encrypt a plaintext pair. The resulting ciphertext pair, c1 and c2, along with the public key, is then sent from the on-premises environment to the cloud.
126
-
127
- ```python
128
- def on_premise() -> Tuple[int, int, dict]:
129
- """
130
- Executes on-premise operations: initializes a cryptosystem by generating
131
- a random public-private key pair, then encrypts two plaintext values.
132
-
133
- Returns:
134
- result (tuple): A tuple containing:
135
- - c1 (int): The first ciphertext
136
- - c2 (int): The second ciphertext
137
- - public_key (dict): The public key for the cryptosystem
138
- """
139
- # generate a random private-public key pair
140
- phe = LightPHE(algorithm_name = "Paillier")
141
-
142
- # define plaintexts
143
- m1 = 10000 # base salary in usd
144
- m2 = 500 # wage increase in usd
145
-
146
- # calculate ciphertexts
147
- c1 = phe.encrypt(m1).value
148
- c2 = phe.encrypt(m2).value
149
-
150
- return (c1, c2, phe.cs.public_key)
151
- ```
152
-
153
- ### Homomorphic Operations on Cloud
154
-
155
- This code snippet demonstrates how to perform homomorphic addition on the cloud side without using the private key. However, the cloud is unable to decrypt c3 itself, even though it is the one that calculated it.
123
+ # homomorphic scalar multiplication - private key is not required
124
+ k = 1.05 # increase something 5%
125
+ c4 = k * c1
156
126
 
157
- ```python
158
- def cloud(c1: int, c2: int, public_key: dict) -> int:
159
- """
160
- Performs cloud-side operations: reconstructs a cryptosystem using the
161
- provided public key and executes a homomorphic addition on two ciphertexts.
162
-
163
- Args:
164
- c1 (int): The first ciphertext
165
- c2 (int): The second ciphertext
166
- public_key (dict): The public key of an existing cryptosystem
167
- Retunrs:
168
- c3 (int): The resulting ciphertext after homomorphic addition
169
- """
170
- # restore cryptosystem with just the public key
171
- phe = LightPHE(algorithm_name = "Paillier", keys = public_key)
172
-
173
- # cast c1 and c2 to ciphertext objects
174
- c1 = phe.create_ciphertext_obj(c1)
175
- c2 = phe.create_ciphertext_obj(c2)
176
-
177
- # confirm that cloud cannot decrypt c1
178
- with pytest.raises(ValueError, match="You must have private key"):
179
- phe.decrypt(c1)
180
-
181
- # confirm that cloud cannot decrypt c2
182
- with pytest.raises(ValueError, match="You must have private key"):
183
- phe.decrypt(c2)
184
-
185
- # perform homomorphic addition
186
- c3 = c1 + c2
187
-
188
- # confirm that cloud cannot decrypt c3
189
- with pytest.raises(ValueError, match="You must have private key"):
190
- phe.decrypt(c3)
191
-
192
- return c3.value
127
+ # decryption - private key is required
128
+ assert cs.decrypt(c3) == m1 + m2
129
+ assert cs.decrypt(c4) == k * m1
193
130
  ```
194
131
 
195
- ### On-Prem Decryption And Proof of Work
196
-
197
- This code snippet demonstrates the proof of work. Even though c3 was calculated in the cloud by adding c1 and c2, on-premises can validate that its decryption must be equal to the addition of plaintexts m1 and m2.
132
+ On the other hand, if you adopt a multiplicatively homomorphic cryptosyste (e.g. RSA or ElGamal), you can multiply ciphertexts without revealing the private key or the plaintext.
198
133
 
199
134
  ```python
200
- # proof of work - private key required
201
- assert phe.decrypt(c3) == m1 + m2
202
- ```
135
+ # build a multiplicatively homomorphic cryptosystem
136
+ cs = LightPHE(algorithm_name = "RSA")
203
137
 
204
- In this homomorphic pipeline, the cloud's computational power was utilized to calculate c3, but it can only be decrypted by the on-premises side. Additionally, while we performed the encryption on the on-premises side, this is not strictly necessary; only the public key is required for encryption. Therefore, encryption can also be performed on the non-premises side. This approach is particularly convenient when collecting data from multiple edge devices and storing all of it in the cloud simultaneously.
138
+ # define plaintexts
139
+ m1 = 17
140
+ m2 = 21
205
141
 
206
- ### Scalar Multiplication
142
+ # encrypt plaintexts - private key is not required.
143
+ c1 = cs.encrypt(m1)
144
+ c2 = cs.encrypt(m2)
207
145
 
208
- Besides, Paillier is supporting multiplying ciphertexts by a known plain constant. This code snippet demonstrates how to perform scalar multiplication on encrypted data using Paillier homomorphic encryption with the LightPHE library.
209
-
210
- ```python
211
- # increasing something 5%
212
- k = 1.05
213
-
214
- # scalar multiplication - cloud (private key is not required)
215
- c4 = k * c1
146
+ # homomorphic multiplication
147
+ c3 = c1 * c2
216
148
 
217
- # proof of work on-prem - private key is required
218
- assert phe.decrypt(c4) == k * m1
149
+ # decryption - private key is required
150
+ assert cs.decrypt(c3) == m1 * m2
219
151
  ```
220
152
 
221
153
  ### Ciphertext Regeneration
@@ -223,28 +155,12 @@ assert phe.decrypt(c4) == k * m1
223
155
  Similar to the most of additively homomorphic algorithms, Paillier lets you to regenerate ciphertext while you are not breaking its plaintext restoration. You may consider to do this re-generation many times to have stronger ciphertexts.
224
156
 
225
157
  ```python
226
- c1_prime = phe.regenerate_ciphertext(c1)
158
+ c1_prime = cs.regenerate_ciphertext(c1)
227
159
  assert c1_prime.value != c1.value
228
- assert phe.decrypt(c1_prime) == m1
229
- assert phe.decrypt(c1) == m1
230
- ```
231
-
232
- ### Unsupported Operations
233
-
234
- Finally, if you try to perform an operation that algorithm does not support, then an exception will be thrown. For instance, Paillier is not homomorphic with respect to the multiplication or xor. To put it simply, you cannot multiply two ciphertexts. If you enforce this calculation, you will have an exception.
235
-
236
- ```python
237
- # pailier is not multiplicatively homomorphic
238
- with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the multiplication"):
239
- c1 * c2
240
-
241
- # pailier is not exclusively homomorphic
242
- with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the exclusive or"):
243
- c1 ^ c2
160
+ assert cs.decrypt(c1_prime) == m1
161
+ assert cs.decrypt(c1) == m1
244
162
  ```
245
163
 
246
- 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
164
  ### Elliptic Curve Cryptography
249
165
 
250
166
  ECC is a powerful public-key cryptosystem based on the algebraic structure of elliptic curves over finite fields. The library supports 3 elliptic curve forms (weierstrass, edwards and koblitz) and 100+ standard elliptic curve configurations.
@@ -252,9 +168,10 @@ ECC is a powerful public-key cryptosystem based on the algebraic structure of el
252
168
  In LightPHE, the [Elliptic Curve ElGamal](https://sefiks.com/2018/08/21/elliptic-curve-elgamal-encryption/) scheme is implemented, offering a secure and efficient homomorphic encryption option.
253
169
 
254
170
  ```python
171
+ forms = ["weierstrass", "edwards", "koblitz"]
255
172
  phe = LightPHE(
256
173
  algorithm_name="EllipticCurve-ElGamal",
257
- form="edwards", # or weierstrass, koblitz
174
+ form=forms[1],
258
175
  )
259
176
  ```
260
177
 
@@ -262,50 +179,11 @@ One of the crucial factors that define the security level of an elliptic curve c
262
179
 
263
180
  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.
264
181
 
265
- See [`curves`](https://github.com/serengil/LightECC) page for a list of all supported forms, curves and their details.
266
-
267
- ### Vector Embeddings and Tensors
268
-
269
- LightPHE supports homomorphic encryption on vector embeddings and tensors. This is useful in privacy-preserving machine learning, secure aggregation, and confidential data processing.
270
-
271
- ```python
272
- # build a cryptosystem
273
- cs = LightPHE(algorithm_name="Paillier")
274
-
275
- # define plain embedding
276
- tensor = [1.005, 2.05, 3.005, 4.005, -5.05, 6, 7.003, 7.002]
277
-
278
- # encrypt vector embedding
279
- encrypted_tensors = cs.encrypt(tensor)
182
+ See [`curves`](https://github.com/serengil/LightECC#supported-curves) page for a list of all supported forms, curves and their details.
280
183
 
281
- # restore embedding
282
- decrypted_tensors = cs.decrypt(encrypted_tensors)
184
+ ### Vector Embeddings
283
185
 
284
- # proof of work
285
- assert all(abs(original - decrypted) < 1e-2 for original, decrypted in zip(tensor, decrypted_tensors))
286
- ```
287
-
288
- Encrypted embeddings retain their homomorphic properties, enabling secure computations on encrypted data without decryption. For example, two embeddings encrypted using a multiplicatively homomorphic algorithm can be multiplied element-wise.
289
-
290
- ```python
291
- # build a multiplicatively homomorphic cryptosystem (e.g. RSA)
292
- cs = LightPHE("RSA")
293
-
294
- # define plain embeddings
295
- t1 = [1.005, 2.05, -3.5, 3.1, -4]
296
- t2 = [5, 6.2, -7.002, -7.1, 8.02]
297
-
298
- # encrypt embeddings
299
- c1, c2 = cs.encrypt(t1), cs.encrypt(t2)
300
-
301
- # perform element-wise homomorphic multiplication
302
- c3 = c1 * c2
303
-
304
- # proof of work
305
- assert np.allclose(cs.decrypt(c3), [a * b for a, b in zip(t1, t2)], rtol=1e-2)
306
- ```
307
-
308
- Similarly, two embeddings encrypted with an additively homomorphic algorithm can be added. Additionally, an encrypted embedding can be multiplied by a constant or a plain embedding.
186
+ LightPHE supports homomorphic encryption on vector embeddings. This is useful in privacy-preserving machine learning, secure aggregation, and confidential data processing.
309
187
 
310
188
  ```python
311
189
  # build an additively homomorphic cryptosystem (e.g. Paillier)
@@ -334,51 +212,6 @@ assert np.allclose(cs.decrypt(c5), [a * 3 for a in t1], rtol=1e-2)
334
212
  assert np.allclose(cs.decrypt(c6), [a * b for a, b in zip(t1, t3)], rtol=1e-2)
335
213
  ```
336
214
 
337
- ### Vector Similarity Search with PHE
338
-
339
- Many machine learning models rely on a two-tower architecture, including facial recognition, reverse image search, recommendation engines, large language models, and more. In this setup, user and item inputs are separately mapped to vector embeddings.
340
-
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.
342
-
343
- ```python
344
- # define a plain vectors for source and target
345
- alpha = [7.1, 5.2, 5.3, 2.4, 3.5, 4.6] # On-prem vector (user tower)
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))
348
-
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
357
- encrypted_alpha = cs.encrypt(alpha)
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
366
- encrypted_cosine_similarity = encrypted_alpha @ beta
367
-
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]
377
-
378
- # proof of work
379
- assert abs(calculated_similarity - expected_similarity) < 1e-2
380
- ```
381
-
382
215
  # Contributing
383
216
 
384
217
  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.
@@ -392,11 +225,11 @@ There are many ways to support a project - starring⭐️ the GitHub repo is jus
392
225
  You can also support this work on [Patreon](https://www.patreon.com/serengil?repo=lightphe), [GitHub Sponsors](https://github.com/sponsors/serengil) or [Buy Me a Coffee](https://buymeacoffee.com/serengil).
393
226
 
394
227
  <a href="https://www.patreon.com/serengil?repo=lightphe">
395
- <img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/patreon.png" width="30%" height="30%">
228
+ <img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/patreon.png" width="30%">
396
229
  </a>
397
230
 
398
231
  <a href="https://buymeacoffee.com/serengil">
399
- <img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/bmc-button.png" width="25%" height="25%">
232
+ <img src="https://raw.githubusercontent.com/serengil/LightPHE/master/icons/bmc-button.png" width="25%">
400
233
  </a>
401
234
 
402
235
  Also, your company's logo will be shown on README on GitHub if you become sponsor in gold, silver or bronze tiers.