nucypher / nufhe

NuCypher fully homomorphic encryption (NuFHE) library implemented in Python
https://nufhe.readthedocs.io/en/latest/
GNU General Public License v3.0
441 stars 53 forks source link

gate_constant doesn't work as expected #8

Closed hargathor closed 5 years ago

hargathor commented 5 years ago

I'm trying to compute a operation with a constant. I tried to use the constant gate but it seems that it process my numpy array backwards. I'm passing a 32 bits constant with 31 False and the last bit at True and the results after going through the gate and deciphering it i get the first bit at True and 31 last bits at False

Here is the code i used to test it

import numpy
import nufhe
import time
from reikna.cluda import any_api

thr = any_api().Thread.create(interactive=True)

rng = numpy.random.RandomState()
secret_key, cloud_key = nufhe.make_key_pair(thr, rng)

size = 32

bits1 = numpy.zeros((size,), dtype=numpy.bool)
bits1[-1] = 1

ciphertext1 = nufhe.encrypt(thr, rng, secret_key, bits1)
reference = bits1

result = nufhe.empty_ciphertext(thr, cloud_key.params, ciphertext1.shape)
time_start = time.clock()
nufhe.gate_constant(thr, cloud_key, result, ciphertext1)
time_elapsed = (time.clock() - time_start)
print("Computation time took {}".format(time_elapsed))

result_bits = nufhe.decrypt(thr, secret_key, result)
print(reference)
print(result_bits)
assert (result_bits == reference).all()

Expected [False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False True] Actual [ True False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False]

fjarri commented 5 years ago

gate_constant() takes an array of plaintext bits (see the doc entry) and creates "encrypted" bits out of it (note that the created LWEs are trivial, so it works as a parameter in other gates, but is not secure).

The problem here is that clearly not enough input checking is performed, so the ciphertext you pass gets treated as a single boolean True (because it is an object and not None), and then result gets filled with an encrypted True as the first value and whatever garbage is located beyond the first element of the source array on GPU.

Do you need "re-encryption" functionality (that is, creating a different ciphertext encrypting the same plaintext), or were you just trying out the interface?

hargathor commented 5 years ago

Ok thanks for the explanation. Actually I need to do a operation between a encrypted value (resulting of a previous operation) against a numerical constant : enc(b)+ 1

fjarri commented 5 years ago

That is exactly the intended usage of the constant gate, you pass the representation of 1 to it as a plaintext array, and then use it in other gates just like any other encrypted value.

hargathor commented 5 years ago

Ok thanks it does work properly when doing as you said. Creating the object with numpy.int_([1], dtype=numpy.uint32) for example

fjarri commented 5 years ago

Commit e4fcaaa5b5f013ad9fcccdbb9ecfbc1237765492 and commit 229d291f3d9bcd522a0b0348c0b2bcbac071932f should help avoid further confusion like this. Closing now.