Skip to main content

Dead-simple full homomorphic encryption (FHE) for Python

Project description

A Simple Drop-In Solution for Full Homomorphic Encryption

Full Homomorphic Encryption (FHE) allows untrusted (e.g. cloud) applications to operate directly on encrypted data, eliminating the need for server-side decryption or trust.

simplefhe is a Python library for FHE that intends to be as easy-to-use as possible. In the simplest case, just a few lines of code are all you need to have working FHE!

The Problem

Suppose we have some sensitive data we wish to process on a remote server. The usual approach is to send the data over a secure connection to be processed server-side.

# The server
def process(x):
    return x*x - 3*x + 1


# The client
sensitive_data = [-30, -5, 17, 28]
for entry in sensitive_data:
    print(entry, process(entry)) # Bad! We are leaking sensitive information.

The result:

-30 991
-5 41
17 239
28 701

However, this requires trusting the server to keep your data confidential. One rogue admin or database hack is all it takes to expose your sensitive data to the public.

The Solution

A few lines of extra code is all it takes to implement Full Homomorphic Encryption (FHE):

from simplefhe import (
    encrypt, decrypt,
    generate_keypair,
    set_public_key, set_private_key,
    display_config
)

# In a real application, the keypair would be generated once,
# and only the public key would be provided to the server.
# A more realistic example is given later.
public_key, private_key = generate_keypair()
set_private_key(private_key)
set_public_key(public_key)

display_config()


# The server
def process(x):
    return x*x - 3*x + 1


# The client
sensitive_data = [-30, -5, 17, 28]
for entry in sensitive_data:
    encrypted = encrypt(entry) # Encrypt the data...
    result = process(encrypted) # Process the data encrypted on the server...
    print(entry, decrypt(result)) # Decrypt the result on the client.

We obtain the same results, as expected:

===== simplefhe config =====
mode: integer (exact)
min_int: -1048575
max_int: 1048576
public_key: initialized
private_key: initialized

-30 991
-5 41
17 239
28 701

In this example, we encrypt the data on the client, send only the encrypted data to the server, process the encrypted data server-side, and return the encrypted result to be client-side decrypted. This requires zero trust of the remote server.

A More Realistic Example

Of course, the client and server will generally be separate applications. Here we demonstrate a more realistic pipeline.

Step 1: Keypair Generation

We first generate a fixed pair of keys:

from simplefhe import generate_keypair

public_key, private_key  = generate_keypair()
public_key.save('keys/public.key')
private_key.save('keys/private.key')
print('Keypair saved to keys/ directory')

Step 2: Client-Side Encryption

Next, we encrypt our sensitive data on the client. Here we save the encrypted results to disk, but in the real-world these files would be sent over a network to the server.

from simplefhe import encrypt, load_public_key, display_config

load_public_key('keys/public.key')
display_config()


# Encrypt our data (client-side)
sensitive_data = [-30, -5, 17, 28]

for i, entry in enumerate(sensitive_data):
    encrypted = encrypt(entry)
    encrypted.save(f'inputs/{i}.dat')
    print(f'[CLIENT] Input {entry} encrypted to inputs/{i}.dat')


# We may then safely send these files to the server
# over a (possibly insecure) network connection

Output:

===== simplefhe config =====
mode: integer (exact)
min_int: -1048575
max_int: 1048576
public_key: initialized
private_key: missing

[CLIENT] Input -30 encrypted to inputs/0.dat
[CLIENT] Input -5 encrypted to inputs/1.dat
[CLIENT] Input 17 encrypted to inputs/2.dat
[CLIENT] Input 28 encrypted to inputs/3.dat

Step 3: Server-Side Processing

We process the encrypted data from the client. The server never has access to the private key, and can never decrypt the client's sensitive data.

from simplefhe import load_public_key, display_config, load_encrypted_value

load_public_key('keys/public.key')
display_config()

# Process values on server.
def f(x): return x*x - 3*x + 1

for i in range(4):
    # Load encrypted value sent from client
    value = load_encrypted_value(f'inputs/{i}.dat')

    # simplefhe seamlessly translates all arithmetic to
    # FHE encrypted operations.
    # We never gain access to the unencrypted information.
    result = f(value) 

    # Send encrypted result back to client
    result.save(f'outputs/{i}.dat')
    print(f'[SERVER] Processed entry {i}: inputs/{i}.dat -> outputs/{i}.dat')

Output:

===== simplefhe config =====
mode: integer (exact)
min_int: -1048575
max_int: 1048576
public_key: initialized
private_key: missing

[SERVER] Processed entry 0: inputs/0.dat -> outputs/0.dat
[SERVER] Processed entry 1: inputs/1.dat -> outputs/1.dat
[SERVER] Processed entry 2: inputs/2.dat -> outputs/2.dat
[SERVER] Processed entry 3: inputs/3.dat -> outputs/3.dat

Step 4: Client-Side Decryption

Finally, the encrypted results are sent back to the client, where they are decrypted. The private key never needs to leave the client.

from simplefhe import (
    load_private_key, display_config,
    decrypt, load_encrypted_value
)

# Note: this is the only step at which the private key is used!
load_private_key('keys/private.key')
display_config()


# Decrypt results from the server (client-side)
sensitive_data = [-30, -5, 17, 28]

for i, entry in enumerate(sensitive_data):
    encrypted = load_encrypted_value(f'outputs/{i}.dat')
    result = decrypt(encrypted)
    print(f'[CLIENT] Result for {entry}: {result}')

As expected, we obtain the correct results:

===== simplefhe config =====
mode: integer (exact)
min_int: -1048575
max_int: 1048576
public_key: missing
private_key: initialized

[CLIENT] Result for -30: 991
[CLIENT] Result for -5: 41
[CLIENT] Result for 17: 239
[CLIENT] Result for 28: 701

Installation

simplefhe depends on SEAL-Python and all its prerequisites. After installing SEAL-Python, the simplefhe library is just a pip install away: pip3 install simplefhe

Notes

  • Comparison operations (<, =, >) are not supported on encrypted data. If they were, it would be pretty easy to figure out what the plaintext is! As a side effect, it's not really possible to branch based on encrypted data.
  • There is some randomness in the encryption process: the same value, encrypted with the same key, will yield different ciphertexts. This prevents a simple plaintext enumeration attack.
  • Float support is currently experimental.

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

simplefhe-1.0.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

simplefhe-1.0.0-py3-none-any.whl (6.7 kB view details)

Uploaded Python 3

File details

Details for the file simplefhe-1.0.0.tar.gz.

File metadata

  • Download URL: simplefhe-1.0.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.23.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.30.0 CPython/3.8.2

File hashes

Hashes for simplefhe-1.0.0.tar.gz
Algorithm Hash digest
SHA256 d5655587a09db7e8363ec831497def43b4d129a3536cc45d4d35cb2bd3853341
MD5 d1df45d864233550ff242ca2e2e6d778
BLAKE2b-256 ab72da24e8bdeca6400128487dd14da98894425e00f9c763bdb9941bb60a37ec

See more details on using hashes here.

File details

Details for the file simplefhe-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: simplefhe-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 6.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.23.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.30.0 CPython/3.8.2

File hashes

Hashes for simplefhe-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6c28357eeb5a35db586c2534e536c3e7c5c6d7c871e935ac9492aeeb08bd6353
MD5 1bdec3e60dcb3dd4cf71b956f176317c
BLAKE2b-256 a0d002e277bd7f64584f8f648e3a1b8ff67d7c6b5fc8d973039190fe30ec1aa6

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