About serialization for ckks and bfv
When I run the ckks serialization example, I want to compute three numbers, so I modify the coode like this:
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license.
#include "examples.h"
using namespace std; using namespace seal;
void example_serialization() { print_example_banner("Example: Serialization");
#if (!defined(SEAL_USE_ZSTD) && !defined(SEAL_USE_ZLIB)) cout << "Neither ZLIB nor Zstandard support is enabled; this example is not available." << endl; cout << endl; return; #else stringstream parms_stream; stringstream data_stream; stringstream sk_stream;
{
EncryptionParameters parms(scheme_type::ckks);
size_t poly_modulus_degree = 8192;
parms.set_poly_modulus_degree(poly_modulus_degree);
parms.set_coeff_modulus(CoeffModulus::Create(poly_modulus_degree, { 50, 30, 50 }));
auto size = parms.save(parms_stream);
print_line(__LINE__);
cout << "EncryptionParameters: wrote " << size << " bytes" << endl;
print_line(__LINE__);
cout << "EncryptionParameters: data size upper bound (compr_mode_type::none): "
<< parms.save_size(compr_mode_type::none) << endl;
cout << " "
<< "EncryptionParameters: data size upper bound (compression): "
<< parms.save_size(/* Serialization::compr_mode_default */) << endl;
vector<seal_byte> byte_buffer(static_cast<size_t>(parms.save_size()));
parms.save(reinterpret_cast<seal_byte*>(byte_buffer.data()), byte_buffer.size());
EncryptionParameters parms2;
parms2.load(reinterpret_cast<const seal_byte*>(byte_buffer.data()), byte_buffer.size());
print_line(__LINE__);
cout << "EncryptionParameters: parms == parms2: " << boolalpha << (parms == parms2) << endl;
}
{
EncryptionParameters parms;
parms.load(parms_stream);
parms_stream.seekg(0, parms_stream.beg);
SEALContext context(parms);
KeyGenerator keygen(context);
auto sk = keygen.secret_key();
PublicKey pk;
keygen.create_public_key(pk);
sk.save(sk_stream);
Serializable<RelinKeys> rlk = keygen.create_relin_keys();
RelinKeys rlk_big;
keygen.create_relin_keys(rlk_big);
auto size_rlk = rlk.save(data_stream);
auto size_rlk_big = rlk_big.save(data_stream);
print_line(__LINE__);
cout << "Serializable<RelinKeys>: wrote " << size_rlk << " bytes" << endl;
cout << " "
<< "RelinKeys wrote " << size_rlk_big << " bytes" << endl;
data_stream.seekp(-size_rlk_big, data_stream.cur);
double scale = pow(2.0, 30);
CKKSEncoder encoder(context);
Plaintext plain1, plain2;
Plaintext plain3;
encoder.encode(2.3, scale, plain1);
encoder.encode(4.5, scale, plain2);
encoder.encode(2.2, scale, plain3);
Encryptor encryptor(context, pk);
encryptor.set_secret_key(sk);
auto size_sym_encrypted1 = encryptor.encrypt_symmetric(plain1).save(data_stream);
auto size_sym_encrypted2 = encryptor.encrypt_symmetric(plain2).save(data_stream);
auto size_sym_encrypted3 = encryptor.encrypt_symmetric(plain3).save(data_stream);
print_line(__LINE__);
cout << " "
<< "Serializable<Ciphertext> (seeded secret-key): wrote " << size_sym_encrypted2 << " bytes" << endl;
}
{
EncryptionParameters parms;
parms.load(parms_stream);
parms_stream.seekg(0, parms_stream.beg);
SEALContext context(parms);
Evaluator evaluator(context);
RelinKeys rlk;
Ciphertext encrypted1, encrypted2;
// Ciphertext encrypted3; rlk.load(context, data_stream); encrypted1.load(context, data_stream); encrypted2.load(context, data_stream); // encrypted3.load(context, data_stream); Ciphertext encrypted_prod, encrypted_prod2;
evaluator.multiply(encrypted1, encrypted2, encrypted_prod);
evaluator.relinearize_inplace(encrypted_prod, rlk);
evaluator.rescale_to_next_inplace(encrypted_prod);
evaluator.multiply_inplace(encrypted_prod, encrypted3);
evaluator.relinearize_inplace(encrypted_prod, rlk);
evaluator.rescale_to_next_inplace(encrypted_prod);
data_stream.seekp(0, parms_stream.beg);
data_stream.seekg(0, parms_stream.beg);
auto size_encrypted_prod = encrypted_prod.save(data_stream);
print_line(__LINE__);
cout << "Ciphertext (secret-key): wrote " << size_encrypted_prod << " bytes" << endl;
}
{
EncryptionParameters parms;
parms.load(parms_stream);
parms_stream.seekg(0, parms_stream.beg);
SEALContext context(parms);
SecretKey sk;
sk.load(context, sk_stream);
Decryptor decryptor(context, sk);
CKKSEncoder encoder(context);
Ciphertext encrypted_result;
encrypted_result.load(context, data_stream);
Plaintext plain_result;
decryptor.decrypt(encrypted_result, plain_result);
vector<double> result;
encoder.decode(plain_result, result);
print_line(__LINE__);
cout << "Decrypt the loaded ciphertext" << endl;
cout << " + Expected result:" << endl;
vector<double> true_result(encoder.slot_count(), 2.3 * 4.5 * 2.2);
print_vector(true_result, 3, 7);
cout << " + Computed result ...... Correct." << endl;
print_vector(result, 3, 7);
}
Plaintext pt("1x^2 + 3");
stringstream stream;
auto data_size = pt.save(stream);
Serialization::SEALHeader header;
Serialization::LoadHeader(stream, header);
print_line(__LINE__);
cout << "Size written to stream: " << data_size << " bytes" << endl;
cout << " "
<< "Size indicated in SEALHeader: " << header.size << " bytes" << endl;
cout << endl;
#endif }
why can't compute the multipication for three numbers?
To make bfv acchieve serialization, I write code for it accoeding to the ckks serialization example like this:
#include "examples.h"
using namespace std; using namespace seal;
void bfv_serialization() { print_example_banner("Example: Serialization for BFV");
#if (!defined(SEAL_USE_ZSTD) && !defined(SEAL_USE_ZLIB)) cout << "Neither ZLIB nor Zstandard support is enabled; this example is not available." << endl; cout << endl; return; #else stringstream parms_stream; stringstream data_stream; stringstream sk_stream; //server determines the computation and sets encryption parameters { cout << "Server:set encryption parameters" << endl; EncryptionParameters parms(scheme_type::bfv); size_t poly_modulus_degree = 8192; parms.set_poly_modulus_degree(poly_modulus_degree); parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));
parms.set_plain_modulus(PlainModulus::Batching(poly_modulus_degree, 20));
auto size = parms.save(parms_stream);
print_line(__LINE__);
cout << "EncryptionParameters: wrote " << size << " bytes" << endl;
}
//Client starts by loading the encryption parameters, sets up the SEALContext,and creates the required keys.
{
cout << "Client:load encryption parameters、set SEALContext、create keys" << endl;
EncryptionParameters parms;
parms.load(parms_stream);
parms_stream.seekg(0, parms_stream.beg);
SEALContext context(parms);
KeyGenerator keygen(context);
auto secret_key = keygen.secret_key();
PublicKey public_key;
keygen.create_public_key(public_key);
Serializable<RelinKeys> rlk = keygen.create_relin_keys();//create as seeded objects to minimize communication cost
GaloisKeys gal_keys;
keygen.create_galois_keys(gal_keys);
secret_key.save(sk_stream);
Encryptor encryptor(context, public_key);
print_line(__LINE__);
string x;
cout << "Please set plaintext :" << endl;
cin >> x;
Plaintext x_plain(x);
cout << "Express x = " + x + " as a plaintext polynomial 0x" + x_plain.to_string() + "." << endl;
Plaintext plain_one("1"), plain_three("3"), plain_four("4");
auto one = encryptor.encrypt(plain_one);
one.save(data_stream);
auto four = encryptor.encrypt(plain_four);
one.save(data_stream);
auto three = encryptor.encrypt(plain_three);
one.save(data_stream);
auto x_value = encryptor.encrypt(x_plain);
one.save(data_stream);
/*
auto size_encrypted0 = encryptor.encrypt_symmetric(plain_one).save(data_stream);
auto size_encrypted1 = encryptor.encrypt_symmetric(plain_four).save(data_stream);
auto size_encrypted3 = encryptor.encrypt_symmetric(plain_three).save(data_stream);
auto size_encrypted = encryptor.encrypt_symmetric(x_plain).save(data_stream);
*/
cout << "Having encrypted three coefficiens" << endl;
}
//The server compute on the encrypted data.
{
cout << "Server:compute the encrypted data" << endl;
EncryptionParameters parms;
parms.load(parms_stream);
parms_stream.seekg(0, parms_stream.beg);
SEALContext context(parms);
Evaluator evaluator(context);
RelinKeys rlk;
Ciphertext encrypted3, encrypted1, encrypted0, encrypted;
cout << "Server:define finished!" << endl;
rlk.load(context, data_stream);
encrypted0.load(context, data_stream);
encrypted1.load(context, data_stream);
encrypted3.load(context, data_stream);
encrypted.load(context, data_stream);
cout << "Server:compute" << endl;
Ciphertext x_encrypted_sq;
evaluator.square(encrypted, x_encrypted_sq);//x^2
evaluator.relinearize_inplace(x_encrypted_sq, rlk);
evaluator.multiply(encrypted, encrypted3, encrypted3);//3x
evaluator.multiply_inplace(encrypted3, x_encrypted_sq);//x^2*3x
evaluator.relinearize_inplace(x_encrypted_sq, rlk);
evaluator.multiply(encrypted, encrypted1, encrypted1);//4x
Ciphertext encrypted_prod;
evaluator.add_inplace(encrypted3, encrypted1);
evaluator.add(encrypted3, encrypted0, encrypted_prod);//3x^3+4x+1
evaluator.relinearize_inplace(encrypted_prod, rlk);
data_stream.seekp(0, parms_stream.beg);
data_stream.seekg(0, parms_stream.beg);
auto size_encrypted_prod = encrypted_prod.save(data_stream);
}
//Client decrpts the result
{
cout << "Client:decrpts the result" << endl;
EncryptionParameters parms;
parms.load(parms_stream);
parms_stream.seekg(0, parms_stream.beg);
SEALContext context(parms);
//Load back the secret key from sk_stream.
SecretKey secret_key;
secret_key.load(context, sk_stream);
Decryptor decryptor(context, secret_key);
Ciphertext encrypted_result;
encrypted_result.load(context, data_stream);
Plaintext plain_result;
decryptor.decrypt(encrypted_result, plain_result);
cout << "0x" << plain_result.to_string() << " ...... Correct." << endl;
}
#endif }
But it show error at the line with red point
I don't know where wronged. Can you give me some advices?
Could you push your changes to some repository where it's easy to see them clearly?
Well, I'll show you the changes.
For ckks serialization example, I add another number, so I add codes in line 287、290 and 313 like the following picture
Add codes in line 371-373 like the following picture
And true results change like this:
vector
As for bfv serialization codes, I just according to ckks serialization example. I make save data to two lines like this, but it seems can not load the data in server.
To see the changes in bfv and ckks, I just do not encode the plaintexts, is it affects? But SEAL do not support encode one data.