encryptorion-lab / phantom-fhe

PhantomFHE: A CUDA-Accelerated Homomorphic Encryption Library
https://encryptorion-lab.gitbook.io/phantom-fhe/
GNU General Public License v3.0
60 stars 8 forks source link

Support for save() or its equivalency #10

Closed gogo9th closed 1 week ago

gogo9th commented 3 weeks ago

Hi,

I am porting PhantomFHE into my SEAL application and I am encountering one problem. In my original program, I transfer the encryption parameters, keys, and ciphertexts (i.e., EncryptionParameter, SecretKey, PublicKey, RelinKey, GaloisKey, Ciphertext) based on their save() API. However, PhantomFHE does not seem to support the save() API. I wonder how I can transfer these data pieces over the network and reload them. Could you give me an example code by any chance for saving & loading each of these 6 class object data over the network?

Thanks a lot.

D4rkCrypto commented 3 weeks ago

PhantomFHE currently does not support networking, but we plan to implement it as you requested. This feature should be ready in a few days. I’ll update you in this thread as soon as it’s available. Thanks for your patience!

gogo9th commented 3 weeks ago

Hi, I really appreciate your kind support. Currently, our application uses BFV, so the network support for BFV would suffice for now. (But looking at the PhantomFHE code, it seems that all schemes use the common classes, so I think the network feature is a matter of all or none).

For the future stable version, I think adding the following could be cool:

D4rkCrypto commented 3 weeks ago

The functions mod_switch_to_inplace and negate are available in evaluate.cuh, so you can refer to them directly.

As for CPU-only support, since Phantom is not intended to function as a CPU/GPU library, we won't be implementing CPU-side APIs. However, we may explore the possibility of connecting with OpenFHE/SEAL through customized adapters.

Regarding the is_zero function, it is a little bit time-consuming to execute on the GPU. While its implementation is feasible, I recommend avoiding its use unless necessary.

gogo9th commented 1 week ago

Thanks for the update, I tested it and it works fine.

Regarding PhantomRelinKey and PhantomGaloisKey, since the keys can be distributed only once in the beginning, it is fine for us to use an unoptimized version for now. Theoretically, would it work if I implement their save() and load() functions if I simply save and restore these data structures as you did?

class PhantomRelinKey {
    bool gen_flag_ = false;
    std::vector<phantom::util::cuda_auto_ptr<uint64_t>> public_keys_;
    phantom::util::cuda_auto_ptr<uint64_t *> public_keys_ptr_;
}

class PhantomGaloisKey {
    bool gen_flag_ = false;
    std::vector<PhantomRelinKey> relin_keys_;
}

Or do I also need to do the same for a subset of the friend class PhantomSecretKey's member variables below:

class PhantomSecretKey {

private:

    bool gen_flag_ = false;
    uint64_t chain_index_ = 0;
    uint64_t sk_max_power_ = 0; // the max power of secret key
    uint64_t poly_modulus_degree_ = 0;
    uint64_t coeff_modulus_size_ = 0;

    phantom::util::cuda_auto_ptr<uint64_t> data_rns_;
    phantom::util::cuda_auto_ptr<uint64_t> secret_key_array_; // the powers of secret key
}

If you are running out of time for further implementation, then I can try this out this weekend and make a pull request for your review.

D4rkCrypto commented 1 week ago

These keys involve more complex data structures. Theoretically, handling them is similar to dealing with ciphertext or plaintext. However, you should pay extra attention to std::vector because its size must be initialized before loading values.