LightPHE is a lightweight partially homomorphic encryption library for python. It is a hybrid homomoprhic encryption library wrapping many schemes such as RSA
, ElGamal
, Exponential ElGamal
, Elliptic Curve ElGamal
, Paillier
, Damgard-Jurik
, Okamoto–Uchiyama
, Benaloh
, Naccache–Stern
, Goldwasser–Micali
.
Even though fully homomorphic encryption (FHE) has become available in recent times, but when considering the trade-offs, LightPHE emerges as a more efficient and practical choice. If your specific task doesn't demand the full homomorphic capabilities, opting for partial homomorphism with LightPHE is the logical decision.
- 🏎️ Notably faster
- 💻 Demands fewer computational resources
- 📏 Generating much smaller ciphertexts
- 🔑 Distributing much smaller keys
- 🧠 Well-suited for memory-constrained environments
- ⚖️ Strikes a favorable balance for practical use cases
The easiest way to install the LightPHE package is to install it from python package index (PyPI).
pip install lightphe
Then you will be able to import the library and use its functionalities.
from lightphe import LightPHE
In summary, LightPHE is covering following algorithms and these are partially homomorphic with respect to the operations mentioned in the following table.
Algorithm | Multiplicatively Homomorphic |
Additively Homomorphic |
Multiplication with a Plain Constant | Exclusively Homomorphic |
Regeneration of Ciphertext |
---|---|---|---|---|---|
RSA | ✅ | ❌ | ❌ | ❌ | ❌ |
ElGamal | ✅ | ❌ | ❌ | ❌ | ✅ |
Exponential ElGamal | ❌ | ✅ | ✅ | ❌ | ✅ |
Elliptic Curve ElGamal | ❌ | ✅ | ✅ | ❌ | ❌ |
Paillier | ❌ | ✅ | ✅ | ❌ | ✅ |
Damgard-Jurik | ❌ | ✅ | ✅ | ❌ | ✅ |
Benaloh | ❌ | ✅ | ✅ | ❌ | ✅ |
Naccache-Stern | ❌ | ✅ | ✅ | ❌ | ✅ |
Okamoto-Uchiyama | ❌ | ✅ | ✅ | ❌ | ✅ |
Goldwasser-Micali | ❌ | ❌ | ❌ | ✅ | ❌ |
Once you imported the library, then you can build a cryptosystem for several algorithms. This basically generates private and public key pair.
algorithms = [
"RSA",
"ElGamal",
"Exponential-ElGamal",
"Paillier",
"Damgard-Jurik",
"Okamoto-Uchiyama",
"Benaloh",
"Naccache-Stern",
"Goldwasser-Micali",
"EllipticCurve-ElGamal"
]
phe = LightPHE(algorithm_name = algorithms[0])
Once you built your cryptosystem, you will be able to encrypt and decrypt messages with the built cryptosystem.
# define plaintext
m = 17
# calculate ciphertext
c = phe.encrypt(m)
# proof of work
assert phe.decrypt(c) == m
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.
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.
def on_premise() -> Tuple[int, int, dict]:
"""
Executes on-premise operations: initializes a cryptosystem by generating
a random public-private key pair, then encrypts two plaintext values.
Returns:
result (tuple): A tuple containing:
- c1 (int): The first ciphertext
- c2 (int): The second ciphertext
- public_key (dict): The public key for the cryptosystem
"""
# generate a random private-public key pair
phe = LightPHE(algorithm_name = "Paillier")
# define plaintexts
m1 = 10000 # base salary in usd
m2 = 500 # wage increase in usd
# calculate ciphertexts
c1 = phe.encrypt(m1).value
c2 = phe.encrypt(m2).value
return (c1, c2, phe.cs.public_key)
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.
def cloud(c1: int, c2: int, public_key: dict) -> int:
"""
Performs cloud-side operations: reconstructs a cryptosystem using the
provided public key and executes a homomorphic addition on two ciphertexts.
Args:
c1 (int): The first ciphertext
c2 (int): The second ciphertext
public_key (dict): The public key of an existing cryptosystem
Retunrs:
c3 (int): The resulting ciphertext after homomorphic addition
"""
# restore cryptosystem with just the public key
phe = LightPHE(algorithm_name = "Paillier", keys = public_key)
# cast c1 and c2 to ciphertext objects
c1 = phe.create_ciphertext_obj(c1)
c2 = phe.create_ciphertext_obj(c2)
# confirm that cloud cannot decrypt c1
with pytest.raises(ValueError, match="You must have private key"):
phe.decrypt(c1)
# confirm that cloud cannot decrypt c2
with pytest.raises(ValueError, match="You must have private key"):
phe.decrypt(c2)
# perform homomorphic addition
c3 = c1 + c2
# confirm that cloud cannot decrypt c3
with pytest.raises(ValueError, match="You must have private key"):
phe.decrypt(c3)
return c3.value
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.
# proof of work - private key required
assert phe.decrypt(c3) == m1 + m2
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.
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.
# increasing something 5%
k = 1.05
# scalar multiplication - cloud (private key is not required)
c4 = k * c1
# proof of work on-prem - private key is required
assert phe.decrypt(c4) == k * m1
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.
c1_prime = phe.regenerate_ciphertext(c1)
assert c1_prime.value != c1.value
assert phe.decrypt(c1_prime) == m1
assert phe.decrypt(c1) == m1
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.
# pailier is not multiplicatively homomorphic
with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the multiplication"):
c1 * c2
# pailier is not exclusively homomorphic
with pytest.raises(ValueError, match="Paillier is not homomorphic with respect to the exclusive or"):
c1 ^ c2
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.
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.
You should be able run make test
and make lint
commands successfully before committing. Once a PR is created, GitHub test workflow will be run automatically and unit test results will be available in GitHub actions before approval. Besides, workflow will evaluate the code with pylint as well.
There are many ways to support a project - starring⭐️ the GitHub repo is just one 🙏
You can also support this work on Patreon, GitHub Sponsors or Buy Me a Coffee.
Also, your company's logo will be shown on README on GitHub if you become sponsor in gold, silver or bronze tiers.
Please cite LightPHE in your publications if it helps your research. Here is its BibTex entry:
@misc{serengil2024lightphe,
title = {LightPHE: Integrating Partially Homomorphic Encryption into Python with Extensive Cloud Environment Evaluations},
author = {Serengil, Sefik Ilkin and Ozpinar, Alper},
year = {2024},
publisher = {arXiv},
url = {https://arxiv.org/abs/2408.05219},
doi = {10.48550/arXiv.2408.05219}
}
Also, if you use LightPHE in your projects, please add lightphe
in the requirements.txt
.
LightPHE is licensed under the MIT License - see LICENSE
for more details.