encryptorion-lab / phantom-fhe

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

The noise budget for loaded BFV symmetric ciphertexts #15

Open gogo9th opened 1 month ago

gogo9th commented 1 month ago

Hi,

At examples/serialization.cu:255, I inserted the following line:

cout << "Noise: " << secret_key.invariant_noise_budget(context, x_symmetric_cipher_load) << endl;

And if I run the example code, I get this output:

cipher noise budget is: 0

Actually, it seems that even for the unmodified serialization.cu file, the noise budgets are all 0:

Testing BFV sym Enc & Dec
testing poly_modulus_degree = 4096
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 4096
|   coeff_modulus size: 109 (36 + 36 + 37) bits

68719403009 ,  68719230977 ,  137438822401 ,

|   plain_modulus: 1032193
\
cipher noise budget is: 0
Save symmetric ciphertext to file.
Load symmetric ciphertext from file.
Decode the decrypted plaintext.
testing poly_modulus_degree = 8192
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 8192
|   coeff_modulus size: 218 (43 + 43 + 44 + 44 + 44) bits

8796092858369 ,  8796092792833 ,  17592186028033 ,  17592185438209 ,  17592184717313 ,

|   plain_modulus: 1032193
\
cipher noise budget is: 0
Save symmetric ciphertext to file.
Load symmetric ciphertext from file.
Decode the decrypted plaintext.
testing poly_modulus_degree = 16384
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 16384
|   coeff_modulus size: 438 (48 + 48 + 48 + 49 + 49 + 49 + 49 + 49 + 49) bits

281474976546817 ,  281474976317441 ,  281474975662081 ,  562949952798721 ,  562949952700417 ,  562949952274433 ,  562949951979521 ,  562949951881217 ,  562949951619073 ,

|   plain_modulus: 786433
\
cipher noise budget is: 0
Save symmetric ciphertext to file.
Load symmetric ciphertext from file.
Decode the decrypted plaintext.
testing poly_modulus_degree = 32768
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 32768
|   coeff_modulus size: 881 (55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 56) bits

36028797017456641 ,  36028797014704129 ,  36028797014573057 ,  36028797014376449 ,  36028797013327873 ,  36028797013000193 ,  36028797012606977 ,  36028797010444289 ,  36028797009985537 ,  36028797005856769 ,  36028797005529089 ,  36028797005135873 ,  36028797003694081 ,  36028797003563009 ,  36028797001138177 ,  72057594037338113 ,

|   plain_modulus: 786433
\
cipher noise budget is: 0
Save symmetric ciphertext to file.
Load symmetric ciphertext from file.
Decode the decrypted plaintext.

Testing BFV asym Enc & Dec
testing poly_modulus_degree = 4096
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 4096
|   coeff_modulus size: 109 (36 + 36 + 37) bits

68719403009 ,  68719230977 ,  137438822401 ,

|   plain_modulus: 1032193
\
Save public key to file.
Load public key from file.
cipher noise budget is: 0
Save asymmetric ciphertext to file.
Load asymmetric ciphertext from file.
Decode the decrypted plaintext.
testing poly_modulus_degree = 8192
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 8192
|   coeff_modulus size: 218 (43 + 43 + 44 + 44 + 44) bits

8796092858369 ,  8796092792833 ,  17592186028033 ,  17592185438209 ,  17592184717313 ,

|   plain_modulus: 1032193
\
Save public key to file.
Load public key from file.
cipher noise budget is: 0
Save asymmetric ciphertext to file.
Load asymmetric ciphertext from file.
Decode the decrypted plaintext.
testing poly_modulus_degree = 16384
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 16384
|   coeff_modulus size: 438 (48 + 48 + 48 + 49 + 49 + 49 + 49 + 49 + 49) bits

281474976546817 ,  281474976317441 ,  281474975662081 ,  562949952798721 ,  562949952700417 ,  562949952274433 ,  562949951979521 ,  562949951881217 ,  562949951619073 ,

|   plain_modulus: 786433
\
Save public key to file.
Load public key from file.
cipher noise budget is: 0
Save asymmetric ciphertext to file.
Load asymmetric ciphertext from file.
Decode the decrypted plaintext.
testing poly_modulus_degree = 32768
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 32768
|   coeff_modulus size: 881 (55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 56) bits

36028797017456641 ,  36028797014704129 ,  36028797014573057 ,  36028797014376449 ,  36028797013327873 ,  36028797013000193 ,  36028797012606977 ,  36028797010444289 ,  36028797009985537 ,  36028797005856769 ,  36028797005529089 ,  36028797005135873 ,  36028797003694081 ,  36028797003563009 ,  36028797001138177 ,  72057594037338113 ,

|   plain_modulus: 786433
\
Save public key to file.
Load public key from file.
cipher noise budget is: 0
Save asymmetric ciphertext to file.
Load asymmetric ciphertext from file.
Decode the decrypted plaintext.

Testing BFV mul
testing poly_modulus_degree = 4096
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 4096
|   coeff_modulus size: 109 (36 + 36 + 37) bits

68719403009 ,  68719230977 ,  137438822401 ,

|   plain_modulus: 1032193
\
Save relin key to file.
Load relin key from file.
testing poly_modulus_degree = 8192
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 8192
|   coeff_modulus size: 218 (43 + 43 + 44 + 44 + 44) bits

8796092858369 ,  8796092792833 ,  17592186028033 ,  17592185438209 ,  17592184717313 ,

|   plain_modulus: 1032193
\
Save relin key to file.
Load relin key from file.
testing poly_modulus_degree = 16384
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 16384
|   coeff_modulus size: 438 (48 + 48 + 48 + 49 + 49 + 49 + 49 + 49 + 49) bits

281474976546817 ,  281474976317441 ,  281474975662081 ,  562949952798721 ,  562949952700417 ,  562949952274433 ,  562949951979521 ,  562949951881217 ,  562949951619073 ,

|   plain_modulus: 786433
\
Save relin key to file.
Load relin key from file.
testing poly_modulus_degree = 32768
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 32768
|   coeff_modulus size: 881 (55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 56) bits

36028797017456641 ,  36028797014704129 ,  36028797014573057 ,  36028797014376449 ,  36028797013327873 ,  36028797013000193 ,  36028797012606977 ,  36028797010444289 ,  36028797009985537 ,  36028797005856769 ,  36028797005529089 ,  36028797005135873 ,  36028797003694081 ,  36028797003563009 ,  36028797001138177 ,  72057594037338113 ,

|   plain_modulus: 786433
\
Save relin key to file.
Load relin key from file.

Testing BFV rotate
testing poly_modulus_degree = 4096
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 4096
|   coeff_modulus size: 109 (36 + 36 + 37) bits

68719403009 ,  68719230977 ,  137438822401 ,

|   plain_modulus: 1032193
\
Save galois key to file.
Load galois key from file.
testing poly_modulus_degree = 8192
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 8192
|   coeff_modulus size: 218 (43 + 43 + 44 + 44 + 44) bits

8796092858369 ,  8796092792833 ,  17592186028033 ,  17592185438209 ,  17592184717313 ,

|   plain_modulus: 1032193
\
Save galois key to file.
Load galois key from file.
testing poly_modulus_degree = 16384
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 16384
|   coeff_modulus size: 438 (48 + 48 + 48 + 49 + 49 + 49 + 49 + 49 + 49) bits

281474976546817 ,  281474976317441 ,  281474975662081 ,  562949952798721 ,  562949952700417 ,  562949952274433 ,  562949951979521 ,  562949951881217 ,  562949951619073 ,

|   plain_modulus: 786433
\
Save galois key to file.
Load galois key from file.
testing poly_modulus_degree = 32768
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 32768
|   coeff_modulus size: 881 (55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 55 + 56) bits

36028797017456641 ,  36028797014704129 ,  36028797014573057 ,  36028797014376449 ,  36028797013327873 ,  36028797013000193 ,  36028797012606977 ,  36028797010444289 ,  36028797009985537 ,  36028797005856769 ,  36028797005529089 ,  36028797005135873 ,  36028797003694081 ,  36028797003563009 ,  36028797001138177 ,  72057594037338113 ,

|   plain_modulus: 786433
\
Save galois key to file.
Load galois key from file.

Shouldn't we expect the noise budgets to be some positive numbers?

gogo9th commented 1 month ago

Hi,

I figured out another more concrete issue: the noise budgets of PhantomFHE ciphertexts seem to be actually lower than those of SEAL ciphertexts, even under the same crypto parameter setup. I found this issue because my software using PhantomFHE does not generate correct results, while everything works correctly when using the original SEAL library.

Below I create the minimal reproducible example code for this issue:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <stdlib.h>

using namespace std;

#ifdef SEAL
    #include "seal/seal.h"
    using namespace seal;
#elif defined(PHANTOM)
    #include "phantom.h"

    using namespace phantom;
    using namespace phantom::arith;
    using namespace phantom::util;
#endif

int main()
{
    vector<int> coeff_mod_list = {60, 60, 60, 60, 60, 60};

   EncryptionParameters parms(scheme_type::bfv);
    vector<Modulus> mod_list;
    //if (poly_modulus_degree == 16384)
        mod_list = CoeffModulus::Create(16384, coeff_mod_list);
    //else
    //  mod_list = CoeffModulus::BFVDefault(poly_modulus_degree);

   parms.set_poly_modulus_degree(16384);
    parms.set_coeff_modulus(mod_list);
    parms.set_plain_modulus(PlainModulus::Batching(16384, 22));
    #if defined(SEAL) || defined(SEAL_PHANTOM)
        SEALContext context(parms);
        SecretKey sk;
        PublicKey pk;
        RelinKeys relin_keys;
        GaloisKeys gal_keys;
        KeyGenerator keygen(context);
        Evaluator evaluator(context);
        BatchEncoder batch_encoder(context);

        keygen.create_public_key(pk);
        sk = keygen.secret_key();
        stringstream relin_stream, gal_stream;
        keygen.create_relin_keys().save(relin_stream);
        keygen.create_galois_keys().save(gal_stream);
        relin_keys.load(context, relin_stream);
        gal_keys.load(context, gal_stream);
        Encryptor encryptor(context, pk);
        encryptor.set_secret_key(sk); // set it up in the SEAL context
        Decryptor decryptor = Decryptor(context, sk);

    #elif defined(PHANTOM)
        PhantomContext context(parms);
        PhantomSecretKey sk(context);
        PhantomPublicKey pk = sk.gen_publickey(context);
        PhantomRelinKey relin_keys(sk.gen_relinkey(context));
        PhantomGaloisKey gal_keys = sk.create_galois_keys(context);
        PhantomBatchEncoder batch_encoder = PhantomBatchEncoder(context);
    #endif

    vector<uint64_t> vec(16384, 0);
    #if defined(PHANTOM)
        PhantomPlaintext pt;
        PhantomCiphertext ct;
        batch_encoder.encode(context, vec, pt);
        sk.encrypt_symmetric(context, pt, ct);
    #elif defined(SEAL)
        Plaintext pt;
        Ciphertext ct;
        batch_encoder.encode(vec, pt);
        encryptor.encrypt_symmetric(pt, ct);
    #endif

    for (int i = 0; i < 4; i++)
    {   cout << "Changing multiplicative chain index from " << i << " -> " << i + 1 << endl;
        #if defined(PHANTOM)
            multiply_inplace(context, ct, ct);
            relinearize_inplace(context, ct, relin_keys);
            mod_switch_to_next_inplace(context, ct);
        #elif defined(SEAL)
            evaluator.multiply_inplace(ct, ct);
            evaluator.relinearize_inplace(ct, relin_keys);
            evaluator.mod_switch_to_next_inplace(ct);
        #endif

        vector<uint64_t> ret_list;
        //assert(this->is_debug);

        #if defined(PHANTOM)
            PhantomPlaintext pt;
            sk.decrypt(context, ct, pt);
            batch_encoder.decode(context, pt, ret_list);
        #elif defined(SEAL)
            Plaintext pt;
            decryptor.decrypt(ct, pt);
            batch_encoder.decode(pt, ret_list);
        #endif    

        if (ret_list[0] != 0)
        {   cout << "- A decryption error found at multiplicative chain index : " << i << endl;
            exit(0);
        }
    }
    cout << "4 multiplications done successfuly" << endl;
    return 0;
}

I also attach the complete source code for this example: src.zip

This example assumes that you have installbed both SEAL and PhantomFHE libraries on your Ubuntu 22.04 (or higher) machine. You only need to run:

unzip src.zip
cd src/build
cmake .. --fresh -DSEAL=ON # To compile with the SEAL library
make -j
./main   # The 5 consecutive cipher multiplications should work fine

cmake .. --fresh -DPHANTOM=ON # To compile with the PhantomFHE library
make -j
./main   # Only 2 consecutive cipher multiplications will work and the results gets corrupted afterwards
D4rkCrypto commented 1 month ago

It seems the code for evaluating the noise budget might be broken. I noticed this a while ago as well. I’ll work on fixing it soon.

gogo9th commented 4 weeks ago

Hi, I just got back from CCS 2024 and HE meetup, where Dan Boneh gave a keynote speech about the future of security, where he picked FHE as the first topic. There were also many papers on FHE. So your library is really important for the future of FHE.

Today I tested your update on secret key packing and it works fine. Thanks a lot. Now the only remaining issue is the noise budget issue... Now my application is good enough to demonstrate its speed enhancement by using PhantomFHE (although the correctness does not hold due to the noise budget issue). Hope this one can be also resolved soon :)

D4rkCrypto commented 4 weeks ago

Thanks for testing the update. I’m glad to hear the secret key packing is working well.

I’m currently traveling for work and will be back early next month. I’ll fix the noise budget issue as soon as I return. In the meantime, my colleagues may be able to help.

gogo9th commented 5 days ago

Hi, I hope you had a wonderful trip. Just wonder if you had any chance to look into the bug fix...

D4rkCrypto commented 5 days ago

Yes, I am working on this, the bug will be fixed soon (maybe today).