Support for public data serialization / deserialization
- Dominant language
- MLIR
- Stars
- 906
- Forks
- 171
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 32
Description
(This issue originated from discussions with @j2kun on the Python backend document; see issue #1105 . )
As far as I am aware, FHE applications are generally split between at least two parties - in the simplest case, a ‘client’ with access to secret data and a ‘server’ without access to secret data. One important source of complexity for newcomers can be to determine what information can or can't be sent to the ‘server’ without compromising the security of encrypted data. I think it would be great for HEIR to have a way to (semi-) automatically (de)serialize the data that can / needs to be exchanged between the ‘client’ and ‘server’. (See for instance [this OpenFHE example](https://github.com/openfheorg/openfhe-development/blob/main/src/pke/examples/simple-integers-serial.cpp) or [serialization in TFHE-rs](https://docs.zama.ai/tfhe-rs/0.10/fundamentals/serialization).)
I'm not sure yet exactly which form it would take. Taking the first example of the [Python frontend document](https://docs.google.com/document/d/1pv7ri7GN4VN2-VUuIXwkfYnJOK3rEg16at1qSuNkU7o/edit?usp=sharing), maybe one way to split it between client-side and server-side operations could be:
```python
#example_client.py
# some library used for client/server communication
from some_user_lib import send_data_to_server, receive_data_from_server
@heir.compile(backend="openfhe")
def foo(a: heir.secret[heir.i32], b: heir.secret[heir.i32]):
if a < b:
return a
else:
return b - 1
key = foo.gen_keys()
enc_a = foo.encrypt_a(key.client_key, 7)
enc_b = foo.encrypt_b(key.client_key, 6)
# serialize the information the server will need (e.g. bootstrapping key, key-switching key, and LUTs for CGGI, plus the encrypted data)
serialized_server_info = key.serialize_public()
serialized_data = foo.serialize_input_ciphers([enc_a, enc_b], batch_size=1)
# send data to the server
send_data_to_server([serialized_server_info, serialized_data])
# receive data from the server and deserialize it
serialized_enc_result = receive_data_from_server()
enc_result = foo.deserialize_output_ciphers(serialized_enc_result, batch_size=1)
result = foo.decrypt_result(key.client_key, enc_result)
```
```python
#example_server.py
from some_user_lib import send_data_to_client, receive_data_from_client
# Alternatively, the function body could be replaced by `pass` if all the information required
# to evaluate it are part of the data sent by the client
@heir.compile(backend="openfhe")
def foo(a: heir.secret[heir.i32], b: heir.secret[heir.i32]) -> heir.secret[heir.i32] :
if a < b:
return a
else:
return b - 1
serialized_server_info, serialized_data = receive_data_from_client()
server_info = foo.deserialize_server_info(serialized_server_info)
enc_a, enc_b = foo.deserialize_data(serialized_data, batch_size=1)
enc_result = foo.foo(server_info.server_keys, enc_a, enc_b)
serialized_enc_result = foo.serialize_output_ciphers([enc_a, enc_b], batch_size=1)
send_data_to_client()
```
Contributor guide
Assessment
This issue has not been assessed yet.