Giter VIP home page Giter VIP logo

serengil / lightphe Goto Github PK

View Code? Open in Web Editor NEW
48.0 48.0 3.0 180 KB

A Lightweight Partially Homomorphic Encryption Library for Python

Home Page: https://bit.ly/46vWz9w

License: MIT License

Python 99.75% Makefile 0.06% Shell 0.19%
benaloh cryptography cyber-security cybersecurity damgard-jurik elgamal elliptic-curve encryption goldwasser-micali homomorphic homomorphic-encryption homomorphism naccache-stern okamoto-uchiyama paillier partially-homomorphic phe public-key-cryptography python rsa

lightphe's Introduction

Hey ๐Ÿ‘‹ This is Sefik

lightphe's People

Contributors

serengil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

lightphe's Issues

Goldwasser-Micali decryption fails for larger keys

Currently, we set the default key length of Goldwasser-Micali to 100 bits here. This is working fine. However, if we increase the key length (e.g. 200 bits), then decryption fails. We need to find out the root cause of this problem.

Support multi-dimensional vectors (tensors)

Currently, tensor operations support just 1D vectors. We need to change the following methods.

Instead of a one depth for loop, element wise operations can be calculated as:

def element_wise_multiply(tensor1, tensor2):
    # Make sure both tensors have the same dimensions
    if len(tensor1) == len(tensor2) and all(len(row1) == len(row2) for row1, row2 in zip(tensor1, tensor2)):
        rows = len(tensor1)
        cols = len(tensor1[0])

        result = [[0 for _ in range(cols)] for _ in range(rows)]

        # Perform element-wise multiplication using nested for loop
        for i in range(rows):
            for j in range(cols):
                result[i][j] = tensor1[i][j] * tensor2[i][j]

        return result
    else:
        raise ValueError("Tensors must have the same dimensions for element-wise multiplication.")

# Example usage
tensor1 = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

tensor2 = [
    [9, 8, 7],
    [6, 5, 4],
    [3, 2, 1]
]

result = element_wise_multiply(tensor1, tensor2)

solving dlp and ecdlp not with brute borce

In the decryption steps of algorithms Benaloh, Naccache-Stern, and Exponential ElGamal, we are solving discrete logarithm problem with brute force. Instead, we can use some faster algorithms such as baby step giant step. Luckily, sympy has out-of-the-box modulo for this.

Similarly, the decryption step of Elliptic Curve ElGamal requires to solve elliptic curve discrete logarithm problem. We should adopt something similar to ones mentioned above.

PS: I gave the links with dedicated DLP and ECDLP lines above.

encrypt float numbers if possible

As an user, I want to encrypt float numbers. In that way, I will be able perform homomorphic operations for percentage calculations. This is already supported in multiplying a ciphertext with a known constant.

Logic for converting float to int: https://github.com/serengil/LightPHE/blob/master/lightphe/models/Ciphertext.py#L116

Where this logic should be used, too: https://github.com/serengil/LightPHE/blob/master/lightphe/__init__.py#L113

You may consider to move __convert_to_int to somewhere common

I should create ciphertext object with number

LightPHE class should have create ciphertext method accepting number or tuple. One can perform homomorphic operations without holding private key in that way.

Also make public method will be good to drop private key in LightPHE class.

Effective key generation for Naccache-Stern

Currently, we set the key length of Naccace-Stern to 37 bits here and here

This is working fine but if we increase the key length, then it cannot find any keys for a long time. TBH, I never see a key is found.

We need to find a way to generate larger keys. This is answered in a stackoverflow post but when I do it, still it is not working.

Creating classes for each cryptosystem

In the interface of lightphe, create different classes for each cryptosystem that extending LightPHE class. In that way, an user does not need to set algorithm name as string, and can use auto-complete feature easily.

We will need to retire build_cryptosystem method here, and put recommend_key_size method to outside of that class.

printing ciphertexts not dumping its value

repr method should be added for Ciphertext class as well.

class MyClass:
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return f"MyClass instance with value: {self.value}"

    def __repr__(self):
        return f"MyClass({self.value})"

# Create an instance of MyClass
obj = MyClass(42)

# When you print the object
print(obj)  # Calls __str__

# When you directly run the object
obj  # Calls __repr__

add homomorphic operation support for encrypted tensors

  • Encrypt & decrypt tensors with float items
  • Homomorphic operations such add addition, element-wise multiplication, scalar multiplication and xor
  • Homomorphic multiplication (dot product) will not work because it requires addition and multiplication meanwhile and this cannot be done with PHE.
  • Tensor should be 1D vectors and all items must be int or float. We will handle multi-dimensional vectors (tensors) in a separate PR.

To encrypt & decrypt floats, we may adopt one of these approaches:

Option 1: Store Dividend and Divisor Separately

Pros:

Exact Representation: This method allows you to exactly represent the original value without loss of precision. You store the dividend and divisor separately, allowing for precise arithmetic operations during decryption.

Cons:

Increased Storage: Storing both the dividend and divisor separately may require more storage compared to the second option, where you only need to store a single integer.

Complexity: Managing two separate values might add complexity to your implementation. You need to make sure that the operations are performed correctly during encryption and decryption.

Option 2: Multiply and Divide by a Fixed Factor

Pros:

Simplicity: This method is simpler to implement, as you only need to multiply and divide by a fixed factor. This reduces the complexity of your code.

Reduced Storage: You only need to store a single integer value, which can save storage space compared to storing both the dividend and divisor separately.

Cons:

Loss of Precision: Multiplying and dividing by a fixed factor can lead to a loss of precision. If your fixed factor is not large enough, you may encounter rounding errors during encryption and decryption.

Limited Range: Depending on the fixed factor, you might have a limited range for the values you can represent in your encrypted tensor.

Public key export deletes private key

When performing export_keys() in lightphe.init in case of exporting (publishing) the public key, it deletes private key in the process. This leaves the LightPHE object (who should have private key, because it generated it) unable to decrypt.

246: if public is True and keys.get("private_key") is not None:
247:     del keys["private_key"]

Current workaround:

gm = LightPHE('Paillier')
gm.export_keys('private.key', public=False)
gm.export_keys('public.key', public=True)
gm = LightPHE('Paillier', key_file='private.key')

Proposed fix:
Don't delete the private_key from keys when performing export_keys(), just export the public_key

pubkey = {'public_key': keys['public_key']}
with open(target_file, "w", encoding="UTF-8") as file:
    file.write(pubkey)

Private key for encryption?

IMO those two lines In LightPHE.init().encrypt() should check for public key, since you can encrypt with only public key, but you need private key for decryption.

119: if self.cs.keys.get("private_key") is None:
120:    raise ValueError("You must have private key to perform encryption")

Proposed fix:

119: if self.cs.keys.get("public_key") is None:
120:    raise ValueError("You must have public key to perform encryption")

Multiplication with a Plain Constant doesn't work

plain constant multiplication doesn't work for the algorithms that are supported for this operation, i.e. Paillier, Damgard-Jurik, etc.

Run the sample code in the README,

from lightphe import LightPHE
cs = LightPHE(algorithm_name = "Paillier")
m1 = 17
c1 = cs.encrypt(m1)
k = 1.05

assert cs.decrypt(k * c1) == k * m1

I get

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

I think this is due to the type of k. If k is integer, e.g. 5, the above code works. I tested in 3 environment, the result is the same:

  1. py3.10 64bit mac
  2. py3.12 64bit mac
  3. py3.10 32bit windows

Possibility to not decrypt original data

Hi,

My need is to take two values A and B, encrypt them with a public key, sum the encrypted data C.
Then I need to decrypt C with the private key but to not be able to decrypt also the original values A and B.
Is this possible using LightPHE?

supporting tensors

Current lightphe api allows users to encrypt & decrypt and homomorphic operations on numbers. As a feauture, lightphe should support tensors for these operation set. This can be used in machine learning applications!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.