Skip to main content

A Lightweight Partially Homomorphic Encryption Library for Python

Project description

LightPHE

PyPI Downloads Stars Tests License DOI

Blog YouTube Twitter

Support me on Patreon GitHub Sponsors Buy Me a Coffee

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.

Partially vs Fully Homomorphic Encryption

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

Installation PyPI

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

Summary of Homomorphic Features of Different Cryptosystems in 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

Building cryptosystem

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"
]

cs = LightPHE(algorithm_name = algorithms[0])

Encryption & Decryption

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 = cs.encrypt(m)

# proof of work
assert cs.decrypt(c) == m

Homomorphic Operations

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.

On-Prem Encryption

This Python code snippet demonstrates how to generate a private-public key pair using the Paillier cryptosystem via the LightPHE library. First, an instance of the LightPHE class is created with the Paillier algorithm. Then, the public key is exported and saved to a file named "public.txt" to build the same cryptosystem with only public key in the cloud side later. The code defines two plaintext values, m1 and m2, respectively. These plaintext values are encrypted to generate ciphertexts c1 and c2 using the public key. Finally, the ciphertexts c1 and c2 are prepared to be sent to a cloud system for secure processing or storage.

# generate private-public key pair
cs = LightPHE(algorithm_name = "Paillier")

# export public key to build same cryptosystem with only public key in the cloud
cs.export_keys(target_file = "public.txt", public = True)

# export private key to build same cryptosystem on-prem later
cs.export_keys(target_file = "private.txt", public = False)

# define plaintexts
m1 = 17
m2 = 23

# calculate ciphertexts
c1 = cs.encrypt(m1).value
c2 = cs.encrypt(m2).value

# send c1 and c2 pair to a cloud system

Homomorphic Operations on Cloud

This Python code snippet illustrates how to handle encrypted data on the cloud side using the Paillier cryptosystem with the LightPHE library. Upon receiving the encrypted values c1 and c2, the cloud system initializes the cryptosystem using the exported public key stored in public.txt. To ensure the security of the data, a test is performed to confirm that the cloud system cannot decrypt c1 and c2 without the private key. This is done using the pytest library, which raises a ValueError if decryption is attempted, verifying that decryption is not possible without the private key. Finally, the code demonstrates homomorphic addition by adding the two ciphertexts, resulting in a new ciphertext c3 that represents the encrypted sum of the original plaintext values.

# cloud side receives encrypted c1 and c2

# restore cryptosystem with the exported public key
cs = LightPHE(algorithm_name = "Paillier", key_file = "public.txt")

# convert c1 and c2 to ciphertext objects
c1 = cs.create_ciphertext_obj(c1)
c2 = cs.create_ciphertext_obj(c2)

# confirm that cloud cannot decrypt c1
with pytest.raises(ValueError, match="You must have private key to perform decryption"):
  cs.decrypt(c1)

# confirm that cloud cannot decrypt c2
with pytest.raises(ValueError, match="You must have private key to perform decryption"):
  cs.decrypt(c2)

# homomorphic addition - private key not required
c3 = c1 + c2

# confirm that cloud cannot decrypt c3
with pytest.raises(ValueError, match="You must have private key to perform decryption"):
  cs.decrypt(c3)

On-Prem Decryption

This Python code snippet demonstrates the final step in a secure computation process using homomorphic encryption with the LightPHE library. After receiving the ciphertext c3 from the cloud, which is the result of homomorphic addition of two ciphertexts c1 and c2, the on-premises system (which has the private key) decrypts c3 to verify the result. The decrypted value is then asserted to be equal to the sum of the original plaintext values m1 and m2. This step ensures the correctness of the homomorphic computation performed by the cloud.

# on-prem side receives c3 from cloud

# restore cryptosystem with the exported private key
cs = LightPHE(algorithm_name = "Paillier", key_file = "private.txt")

# proof of work - private key required
assert cs.decrypt(c3) == m1 + m2

Scalar Multiplication

Besides, Paillier is supporting multiplying ciphertexts by a known plain constant. This Python code snippet demonstrates how to perform scalar multiplication on encrypted data using homomorphic encryption with the LightPHE library. The factor k is set to 1.05, representing a 5% increase. On the cloud side, this factor is used to multiply the ciphertext c1, resulting in a new ciphertext c4. When the on-premises system, which holds the private key, receives c4, it decrypts it and verifies that the decrypted value matches the original plaintext m1 scaled by k (i.e., 1.05 * m1). This ensures that the homomorphic scalar multiplication was performed correctly on the encrypted data.

# 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 cs.decrypt(c4) == k * m1

Ciphertext Regeneration

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 = cs.regenerate_ciphertext(c1)
assert c1_prime.value != c1.value
assert cs.decrypt(c1_prime) == m1
assert cs.decrypt(c1) == m1

Unsupported Operations

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.

Working with vectors

You can encrypt the output vectors of machine learning models with LightPHE. These encrypted tensors come with homomorphic operation support including homomorphic addition, element-wise multiplication and scalar multiplication.

# build an additively homomorphic cryptosystem
cs = LightPHE(algorithm_name="Paillier")

# define plain tensors
t1 = [1.005, 2.05, 3.5, 4]
t2 = [5, 6.2, 7.002, 8.02]

# encrypt tensors
c1 = cs.encrypt(t1)
c2 = cs.encrypt(t2)

# perform homomorphic addition
c3 = c1 + c2

# perform homomorphic element-wise multiplication
c4 = c1 * c2

# perform homomorphic scalar multiplication
k = 5
c5 = k * c1

# decrypt the addition tensor
t3 = cs.decrypt(c3)

# decrypt the element-wise multiplied tensor
t4 = cs.decrypt(c4)

# decrypt the scalar multiplied tensor
t5 = cs.decrypt(c5)

# data validations
threshold = 0.5
for i in range(0, len(t1)):
   assert abs((t1[i] + t2[i]) - t3[i]) < threshold
   assert abs((t1[i] * t2[i]) - t4[i]) < threshold
   assert abs((t1[i] * k) - t5[i]) < threshold

Unfortunately, vector multiplication (dot product) requires both homomorphic addition and homomorphic multiplication and this cannot be done with partially homomorphic encryption algorithms.

Contributing

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.

Support

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.

Citation

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.

License

LightPHE is licensed under the MIT License - see LICENSE for more details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lightphe-0.0.8.tar.gz (34.0 kB view details)

Uploaded Source

Built Distribution

lightphe-0.0.8-py3-none-any.whl (53.5 kB view details)

Uploaded Python 3

File details

Details for the file lightphe-0.0.8.tar.gz.

File metadata

  • Download URL: lightphe-0.0.8.tar.gz
  • Upload date:
  • Size: 34.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.31.0 requests-toolbelt/0.10.1 urllib3/1.26.15 tqdm/4.50.2 importlib-metadata/6.8.0 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.8.5

File hashes

Hashes for lightphe-0.0.8.tar.gz
Algorithm Hash digest
SHA256 8a8d1c521f1f4ea302c9e41166743f3643bfc15ad72dcbd568d649c4938af495
MD5 ddf097ae9770df46a3071f3dd3f22b56
BLAKE2b-256 ab7979e0f06e95049e77d4915c71fec5168b9ecf8b09be7619fed9324869f532

See more details on using hashes here.

File details

Details for the file lightphe-0.0.8-py3-none-any.whl.

File metadata

  • Download URL: lightphe-0.0.8-py3-none-any.whl
  • Upload date:
  • Size: 53.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.31.0 requests-toolbelt/0.10.1 urllib3/1.26.15 tqdm/4.50.2 importlib-metadata/6.8.0 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.8.5

File hashes

Hashes for lightphe-0.0.8-py3-none-any.whl
Algorithm Hash digest
SHA256 ae878d8b1f18b99f2edf09e0c9f595307cdd22dc56b13c3c76b100e7997ed1e7
MD5 f9c9617bc5695dd81210fa01dcdd19d3
BLAKE2b-256 ce8f605c2ca40d454188a8685e0b351d045ba54451c6619ff4b6cde52ba86fc4

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page