tf-encrypted / tf-encrypted

A Framework for Encrypted Machine Learning in TensorFlow

Home Page:https://tf-encrypted.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Is the 'x' sent by the client to servers in plaintext or ciphertest?

giraffeCjl opened this issue · comments

In /tf-encrypted/tf_encrypted/serving.py, tfe defines a 'run(self, sess, x)' function which gets image from 'x_test' and sends x to servers. But the print result seems that 'x' is in plaintext.
I have a question: In the homomorphic encryption computing mode, shouldn't the data be encrypted on the client and then sent to the server? Why is the input of the client in plaintext here?

TL;DR the inputs/outputs to this function are encrypted/decrypted for you. The QueueClient & QueueServer are working at a high-level of abstraction, and the details of how the input & output to the serving queue are kept secure is determined by the current protocol (& config) being used.


I think you're referring to this function:

def run(self, sess, x):
"""
Send `x` to servers and return result.
"""
self.send_input(sess, x)
return self.receive_output(sess)

This calls QueueClient.send_input, which is probably the source of confusion:

def send_input(self, sess, x, tag="input"):
"""
Send `x` to servers for processing.
"""
assert isinstance(x, np.ndarray)
assert list(x.shape) == list(self.input_shape)
# simply run the input op with
sess.run(
self.input_op,
tag=tag,
output_partition_graphs=True,
feed_dict=self.input_placeholder.feed(x),
)

The name send_input is a bit misleading here, especially given that it's checking the input to be a raw numpy array. However, there is work being done behind the scenes to make this numpy array secret before it's sent away from the QueueClient. This extra work is defined here, when we call tfe.define_private_placeholder:

input_queue = tfe.queue.FIFOQueue(
capacity=input_queue_capacity,
shape=input_shape,
shared_name=input_queue_name,
)
self.input_placeholder = tfe.define_private_placeholder(shape=input_shape)
self.input_op = input_queue.enqueue(self.input_placeholder)

Under the hood, this is creating a tf.Placeholder that is then secret shared according to the currently active protocol, producing a reference to some future private value. This secret sharing happens wherever the QueueClient is being used, so the result of send_input is actually a set of multiple shares making up the private value. The QueueServer is then a wrapper around a protocol-specific Queue, and for Pond this is essentially managing one FIFOQueue for each compute server's physical device. The shares in this queue can then be used in further protocol computation before being dequeued and returned to the client, where the shares will be reconstructed into the plaintext computation result (which is what the client sees at the end of it all).

@jvmncs Thank you for such a detailed answer, the send_input function is indeed a bit misleading, and I studied it until late LOL.
In general, can I understand this way, the QueueClient can see the calculated ciphertext result and the decrypted output, but the QueueServer cannot output the ciphertext in the whole process? I once tried to only output a ‘PondPrivateTensor’ on the QueueServer side.

Closing this. Please open a new issue if there is further question.