pailliers module

Minimal pure-Python implementation of Paillier’s additively homomorphic cryptosystem.

class secret(bit_length: int)[source]

Bases: Tuple[int, int, int, int]

Wrapper class for a tuple of four integers that represents a secret key.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> isinstance(secret_key, secret)
True

Any attempt to supply an argument that is of the wrong type or outside the supported range raises an exception.

>>> secret('abc')
Traceback (most recent call last):
  ...
TypeError: bit length must be an integer
>>> secret(0)
Traceback (most recent call last):
  ...
ValueError: bit length must be a positive integer
class public(secret_key: secret)[source]

Bases: Tuple[int, int]

Wrapper class for a pair of integers that represents a public key.

>>> public_key = public(secret(2048))
>>> isinstance(public_key, public)
True

Any attempt to supply an argument that is of the wrong type or outside the supported range raises an exception.

>>> public('abc')
Traceback (most recent call last):
  ...
TypeError: secret key required to create public key
class plain[source]

Bases: int

Wrapper class for an integer that represents a plaintext.

>>> isinstance(plain(123), plain)
True
class cipher(integer: int, public_key: Optional[public] = None)[source]

Bases: int

Wrapper class for an integer that represents a ciphertext.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, plain(123))
>>> isinstance(c, cipher)
True

This class defines a number of special methods corresponding to arithmetic operations so that Python’s built-in operators can be used when working with instances of this class. These operators will only work on instances of this class that have been constructed with a public key (which is the default behavior of the encrypt function).

>>> decrypt(secret_key, c + c)
246
>>> decrypt(secret_key, 2 * c)
246

For instances that were not constructed with a public key, the add and mul functions should be used.

>>> c = cipher(int(c), public_key=public_key)
>>> decrypt(secret_key, c + c)
246
>>> n = int(c)
>>> c = cipher(n)
>>> decrypt(secret_key, add(public_key, c, c))
246
>>> decrypt(secret_key, mul(public_key, c, 2))
246
__add__(other: cipher) cipher[source]

Perform addition of encrypted values to produce the encrypted result.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 22)
>>> d = encrypt(public_key, 33)
>>> r = c + d
>>> int(decrypt(secret_key, r))
55

At least one of the two arguments must have a public key.

>>> decrypt(secret_key, cipher(int(c)) + c)
44
>>> decrypt(secret_key, c + cipher(int(c)))
44
>>> cipher(int(c)) + cipher(int(c))
Traceback (most recent call last):
  ...
ValueError: public key is required for addition
__radd__(other: Union[int, cipher]) cipher[source]

This method makes it possible to use the built-in sum function.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 22)
>>> decrypt(secret_key, sum([c, c, c, c]))
88

This method should not be invoked for any other reason.

>>> 123 + c
Traceback (most recent call last):
  ...
TypeError: can only add ciphertexts
__iadd__(other: cipher) cipher[source]

Add an encrypted value to an existing encrypted value.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 22)
>>> d = encrypt(public_key, 33)
>>> c += d
>>> int(decrypt(secret_key, c))
55

At least one of the two arguments must have a public key.

>>> c += cipher(int(c))
>>> decrypt(secret_key, c)
110
>>> d = cipher(int(d))
>>> d += c
>>> decrypt(secret_key, d)
143
>>> d = cipher(int(d))
>>> d += cipher(int(c))
Traceback (most recent call last):
  ...
ValueError: public key is required for addition

An integer base value can be used when accumulating iteratively.

>>> b = 0
>>> b += encrypt(public_key, 22)
>>> b += encrypt(public_key, 33)
>>> decrypt(secret_key, b)
55
__mul__(scalar: int) cipher[source]

Perform multiplication of an encrypted value by a scalar to produce the encrypted result.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 22)
>>> r = c * 3
>>> int(decrypt(secret_key, r))
66

This instance must have a public key.

>>> c = cipher(int(c))
>>> c * 3
Traceback (most recent call last):
  ...
ValueError: public key is required for scalar multiplication
__rmul__(scalar: int) cipher[source]

Perform multiplication of an encrypted value by a scalar (that appears on the left side of the operator) to produce the encrypted result.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 22)
>>> r = 3 * c
>>> int(decrypt(secret_key, r))
66

This instance must have a public key.

>>> c = cipher(int(c))
>>> c * 3
Traceback (most recent call last):
  ...
ValueError: public key is required for scalar multiplication
__imul__(scalar: int) cipher[source]

Perform multiplication of an encrypted value by a scalar.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 22)
>>> c *= 3
>>> int(decrypt(secret_key, c))
66

This instance must have a public key.

>>> c = cipher(int(c))
>>> c * 3
Traceback (most recent call last):
  ...
ValueError: public key is required for scalar multiplication
encrypt(public_key: public, plaintext: Union[plain, int]) cipher[source]

Encrypt the supplied plaintext using the supplied public key.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 123)
>>> isinstance(c, cipher)
True

Any attempt to invoke this function using arguments that do not have the expected types raises an exception.

>>> encrypt(secret_key, 123)
Traceback (most recent call last):
  ...
TypeError: can only encrypt using a public key
decrypt(secret_key: secret, ciphertext: cipher) plain[source]

Decrypt the supplied plaintext using the supplied secret key.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 123)
>>> decrypt(secret_key, c)
123

Any attempt to invoke this function using arguments that do not have the expected types raises an exception.

>>> decrypt(public_key, c)
Traceback (most recent call last):
  ...
TypeError: can only decrypt using a secret key
>>> decrypt(secret_key, 123)
Traceback (most recent call last):
  ...
TypeError: can only decrypt a ciphertext
add(public_key: public, *ciphertexts: cipher) cipher[source]

Perform addition of encrypted values to produce the encrypted result.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 22)
>>> d = encrypt(public_key, 33)
>>> r = add(public_key, c, d)
>>> int(decrypt(secret_key, r))
55

This function supports one or more ciphertexts. If only one ciphertext is supplied, that same ciphertext is returned.

>>> x = encrypt(public_key, 4)
>>> y = encrypt(public_key, 5)
>>> z = encrypt(public_key, 6)
>>> r = add(public_key, x, y, z)
>>> int(decrypt(secret_key, r))
15
>>> r = add(public_key, x)
>>> int(decrypt(secret_key, r))
4

Iterables of ciphertexts can be provided with the help of unpacking via * (thus allowing this function to be used in a manner that resembles the way that the built-in sum function can be used).

>>> r = add(public_key, *(c for c in [x, y, z]))
>>> int(decrypt(secret_key, r))
15

Any attempt to invoke this function using arguments that do not have the expected types raises an exception.

>>> add(secret_key, c, d)
Traceback (most recent call last):
  ...
TypeError: can only perform operation using a public key
>>> add(public_key, c, 123)
Traceback (most recent call last):
  ...
TypeError: can only add ciphertexts
>>> add(public_key)
Traceback (most recent call last):
  ...
ValueError: at least one ciphertext is required
mul(public_key: public, ciphertext: cipher, scalar: int) cipher[source]

Perform multiplication of an encrypted value by a scalar to produce the encrypted result.

>>> secret_key = secret(2048)
>>> public_key = public(secret_key)
>>> c = encrypt(public_key, 22)
>>> r = mul(public_key, c, 3)
>>> int(decrypt(secret_key, r))
66

Any attempt to invoke this function using arguments that do not have the expected types raises an exception.

>>> mul(secret_key, c, 3)
Traceback (most recent call last):
  ...
TypeError: can only perform operation using a public key
>>> mul(public_key, 123, 3)
Traceback (most recent call last):
  ...
TypeError: can only multiply a ciphertext
>>> mul(public_key, c, 'abc')
Traceback (most recent call last):
  ...
TypeError: can only multiply by an integer scalar