BFV Encrypting immediately to a lower level modulus
Would it be feasible to encrypt a plaintext directly into a lower context data? This would be beneficial in combination with the seeded symmetric encryption, which to my understanding is not possible right now.
- How about call the
encrypt(encrypt_symmetric) then drop the modulus. - For seeded ciphertext, it might be also work because the
seedis used to generate each RNS component in modulus-first order.
I don't think this works... Here is a sample program. The output is:
Degree: 8192 Plain Modulus: 1032193 Parameter validation: valid Key Switching enabled: true Batching enabled: true Encrypting 6 as 0x6 0x6 ...... Correct. Size of original seeded ciphertext: 216367 Size of mod switched seeded ciphertext: 323749 Size of original public key ciphertext: 432519 Size of mod switched public key ciphertext: 323809
Note that the size of the mod switched seeded ciphertext is larger than that of the original seeded.
#include "seal/seal.h"
#include <iostream>
#include <sstream>
using namespace std;
using namespace seal;
std::string uint64_to_hex_string(std::uint64_t value)
{
return seal::util::uint_to_hex_string(&value, std::size_t(1));
}
int main(int argc, char *argv[]){
srand (time(NULL));
uint32_t N = 8192;
uint32_t logt = 20;
//Initialize parameters
EncryptionParameters params(scheme_type::bfv);
params.set_poly_modulus_degree(N);
params.set_coeff_modulus(CoeffModulus::BFVDefault(N));
params.set_plain_modulus(PlainModulus::Batching(N, logt));
uint64_t plain_modulus = params.plain_modulus().value();
cout << "Degree: " << N << endl;
cout << "Plain Modulus: " << plain_modulus << endl;
//Initialize context
SEALContext context(params, true);
cout << "Parameter validation: " << context.parameter_error_message() << endl;
cout << "Key Switching enabled: " << boolalpha << context.using_keyswitching() << endl;
cout << "Batching enabled: " << boolalpha << context.first_context_data()->qualifiers().using_batching << endl;
//Initialize keys
KeyGenerator keygen(context);
PublicKey public_key;
keygen.create_public_key(public_key);
SecretKey secret_key = keygen.secret_key();
//Initialize enc/eval/dec
Encryptor encryptor(context, public_key);
encryptor.set_secret_key(secret_key);
Evaluator evaluator(context);
Decryptor decryptor(context, secret_key);
stringstream data_stream;
uint64_t x = 6;
Plaintext pt(uint64_to_hex_string(x));
cout << "Encrypting " << x << " as 0x" << pt.to_string() << endl;
Ciphertext ct;
Ciphertext ct2;
encryptor.encrypt_symmetric(pt, ct);
encryptor.encrypt(pt, ct2);
uint64_t size1 = encryptor.encrypt_symmetric(pt).save(data_stream);
uint64_t size3 = encryptor.encrypt(pt).save(data_stream);
evaluator.mod_switch_to_next_inplace(ct);
evaluator.mod_switch_to_next_inplace(ct2);
uint64_t size2 = ct.save(data_stream);
uint64_t size4 = ct2.save(data_stream);
Plaintext decrypted;
decryptor.decrypt(ct, decrypted);
cout << "0x" << decrypted.to_string() << " ...... Correct." << endl;
cout << "Size of original seeded ciphertext: " << size1 << endl;
cout << "Size of mod switched seeded ciphertext: " << size2 << endl;
cout << "Size of original public key ciphertext: " << size3 << endl;
cout << "Size of mod switched public key ciphertext: " << size4 << endl;
return 0;
}
Good suggestion! I will add these new APIs to Encryptor in a future release. Let's keep the issue open until then.
At the moment, it has to be done in a hacky way. If you have an urgent need of this, please let me know, I might be able to (with 80% confidence) write a temporary workaround for you.
@abeams A quick solution is to re-use the underlying api
https://github.com/microsoft/SEAL/blob/main/native/src/seal/util/rlwe.cpp#L262