Updated On : Nov-20,2019 Time Investment : ~30 mins

Overview

Paillier is a public key homomorphic encryption scheme. Python library paillier provides an implementation of a paillier cryptosystem.

Below are a list of homomorphic properties :

  • Encrypted numbers can be multiplied by a non-encrypted scalar numbers.
  • Two encrypted numbers can be added.
  • Non-encrypted scalar can be added to Encrypted numbers.

Installation:

Paillier does not come with default python package or conda package that's why we'll need to install it.

  • pip install phe
!pip install --upgrade pip
!pip install phe
Collecting pip
  Downloading https://files.pythonhosted.org/packages/d7/41/34dd96bd33958e52cb4da2f1bf0818e396514fd4f4725a79199564cd0c20/pip-19.0.2-py2.py3-none-any.whl (1.4MB)
    100% |████████████████████████████████| 1.4MB 13.6MB/s
Installing collected packages: pip
  Found existing installation: pip 18.1
    Uninstalling pip-18.1:
      Successfully uninstalled pip-18.1
Successfully installed pip-19.0.2
Collecting phe
  Downloading https://files.pythonhosted.org/packages/32/0e/568e97b014eb14e794a1258a341361e9da351dc6240c63b89e1541e3341c/phe-1.4.0.tar.gz
Building wheels for collected packages: phe
  Building wheel for phe (setup.py) ... - done
  Stored in directory: /tmp/.cache/pip/wheels/f8/dc/36/dcb6bf0f1b9907e7b710ace63e64d08e7022340909315fdea4
Successfully built phe
Installing collected packages: phe
Successfully installed phe-1.4.0
import phe
from phe import paillier
import json
  • paillier.generate_paillier_keypair(n_length=2048) - It generates a public/private key pair of default length 2048 bits. A developer can change this length according to their need. It takes a bit of time to generate initial pairs.
%%time
pub_key,priv_key = paillier.generate_paillier_keypair() ## Generating public/private key pair
## %%time is magic command to find out time taken to execute this cell
CPU times: user 100 ms, sys: 0 ns, total: 100 ms
Wall time: 99.2 ms
  • public_key.encrypt(value, precision=None, r_value=None) - It's used to encrypt value with precision provided as precision for float numbers. User can supply random value to be used during encryption as r_value. Returns object of class EncryptedNumber.
  • private_key.decrypt() - It's used to decrypt encrypted value.
enc1 = pub_key.encrypt(5)
enc2 = pub_key.encrypt(5.649)
enc3 = pub_key.encrypt(5.5397,precision=1e-2)
priv_key.decrypt(enc1), priv_key.decrypt(enc2), priv_key.decrypt(enc3)
(5, 5.649, 5.5390625)

If developers are planning to use more that one public/private key sets then they can main list of private keys through keyring.

  • paillier.PaillierPrivateKeyring(private_keys=None) - Lets developer generates keyring which will main list of private keys give as input to it. Developers can supply all private keys as list initially or can add later as well using add() method.

The benefit of using the ring is that the developer does not need to loop through all private keys to decrypt any encrypted number.

keyring = paillier.PaillierPrivateKeyring()
pub_keys = []
for i in range(5):
    pub,priv = paillier.generate_paillier_keypair()
    pub_keys.append(pub)
    keyring.add(priv)
enc1= pub_keys[0].encrypt(5.5)
enc2= pub_keys[2].encrypt(13.6)
enc3= pub_keys[3].encrypt(3.14)
## Notice below keyring will findout right private key for decrypting number without developer manually keeping track of it..
keyring.decrypt(enc1), keyring.decrypt(enc2), keyring.decrypt(enc3)
(5.5, 13.6, 3.14)

Homomorphic Properties:

Below we'll verify homomorphic properties using various examples.

enc1 = pub_key.encrypt(5.5)
enc2 = pub_key.encrypt(8.3)
enc3 = pub_key.encrypt(12.6)
print(priv_key.decrypt(enc1))
enc1 = enc1 + 3.3
print(priv_key.decrypt(enc1))
enc1 = enc1 - 3.3
print(priv_key.decrypt(enc1))
enc4 = enc2 + enc3
print(priv_key.decrypt(enc4))
enc5 = enc3 - enc2
print(priv_key.decrypt(enc5))
enc6 = -5 + enc5
print(priv_key.decrypt(enc6))
5.5
8.8
5.5
20.9
4.299999999999999
-0.7000000000000011
enc1 = enc1 * 2.2
print(priv_key.decrypt(enc1))
enc1 = enc1 / 10
print(priv_key.decrypt(enc1))
enc7 = enc1 * -2
print(priv_key.decrypt(enc7))
enc8 = enc1 / -2
print(priv_key.decrypt(enc8))
12.100000000000001
1.2100000000000002
-2.4200000000000004
-0.6050000000000001

Serialisation of encrypted numbers to pass it over network/store on disk:

Below steps explain the serialisation of an encrypted number along with public key and then deserializing & reconstructing encrypted number and public key.

print(priv_key.decrypt(enc1))
enc_with_pub_key = {}
enc_with_pub_key['public_key'] = { 'g':pub_key.g, 'n':pub_key.n}
enc_with_pub_key['enc_value'] = (str(enc1.ciphertext()),enc1.exponent)
serialised = json.dumps(enc_with_pub_key)
1.2100000000000002
received_dict = json.loads(serialised)
pk = received_dict['public_key']
public_key_rec = paillier.PaillierPublicKey(n=int(pk['n']))
enc_nums_rec = paillier.EncryptedNumber(public_key_rec, int(received_dict['enc_value'][0]), int(received_dict['enc_value'][1]))
priv_key.decrypt(enc_nums_rec)
1.2100000000000002

Security Caveats:

TBD

Other API functions:

TBD

Other Python libraries providing implementations:

TBD

Sunny Solanki  Sunny Solanki

Share Views Stuck Somewhere? Need Help with Coding? Have Doubts About the Topic/Code?

When going through coding examples, it's quite common to have doubts and errors.

If you have doubts about some code examples or are stuck somewhere when trying our code, send us an email at coderzcolumn07@gmail.com. We'll help you or point you in the direction where you can find a solution to your problem.

You can even send us a mail if you are trying something new and need guidance regarding coding. We'll try to respond as soon as possible.

Share Views Want to Share Your Views? Have Any Suggestions?

If you want to

  • provide some suggestions on topic
  • share your views
  • include some details in tutorial
  • suggest some new topics on which we should create tutorials/blogs
Please feel free to contact us at coderzcolumn07@gmail.com. We appreciate and value your feedbacks. You can also support us with a small contribution by clicking DONATE.