Progress on SEAL BFV implementation
This commit is contained in:
parent
dff1d7460b
commit
0893f6044c
@ -58,7 +58,8 @@ public:
|
|||||||
CTX_ARITHMETIC,
|
CTX_ARITHMETIC,
|
||||||
CTX_MEMORY,
|
CTX_MEMORY,
|
||||||
CTX_INVALID_ARGUMENT,
|
CTX_INVALID_ARGUMENT,
|
||||||
CTX_COMPONENT
|
CTX_COMPONENT,
|
||||||
|
CTX_INTERNAL
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
REASON m_reason;
|
REASON m_reason;
|
||||||
|
|||||||
126
src/seal_bfv.cpp
126
src/seal_bfv.cpp
@ -5,6 +5,9 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
#include <seal/seal.h>
|
#include <seal/seal.h>
|
||||||
|
|
||||||
namespace homcert::bfv {
|
namespace homcert::bfv {
|
||||||
@ -38,12 +41,23 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const seal::EncryptionParameters seal_bfv_params = []() {
|
||||||
|
seal::EncryptionParameters p { seal::scheme_type::bfv };
|
||||||
|
p.set_poly_modulus_degree(VECSIZE);
|
||||||
|
p.set_coeff_modulus(seal::CoeffModulus::BFVDefault(VECSIZE));
|
||||||
|
p.set_plain_modulus(PLAINMOD);
|
||||||
|
return p;
|
||||||
|
}();
|
||||||
|
static std::unique_ptr<seal::SEALContext> seal_bfv_ctx = std::make_unique<seal::SEALContext>(seal_bfv_params);
|
||||||
|
|
||||||
|
struct ct_buffer {
|
||||||
|
bool initialized = false;
|
||||||
|
seal::Ciphertext value;
|
||||||
|
};
|
||||||
|
|
||||||
struct seal_context_data {
|
struct seal_context_data {
|
||||||
int components;
|
int components;
|
||||||
|
|
||||||
seal::EncryptionParameters params;
|
|
||||||
std::unique_ptr<seal::SEALContext> ctx;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
std::unique_ptr<seal::Decryptor> decryptor;
|
std::unique_ptr<seal::Decryptor> decryptor;
|
||||||
seal::SecretKey private_key;
|
seal::SecretKey private_key;
|
||||||
@ -58,13 +72,20 @@ struct seal_context_data {
|
|||||||
seal::RelinKeys relin_keys;
|
seal::RelinKeys relin_keys;
|
||||||
} pub;
|
} pub;
|
||||||
|
|
||||||
seal_context_data() : components{ 0 } {}
|
minfree ct_id_factory;
|
||||||
|
std::unordered_map<int, ct_buffer> ciphertexts;
|
||||||
|
|
||||||
|
seal_context_data() : components{ 0 }, ct_id_factory{ 0 } {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static minfree ctx_id_factory { 0 };
|
static minfree ctx_id_factory { 0 };
|
||||||
static std::unordered_map<int, seal_context_data> ctxs;
|
static std::unordered_map<int, seal_context_data> ctxs;
|
||||||
|
|
||||||
seal_context::seal_context() : context{}, m_id{ -1 } {
|
seal_context::seal_context() : context{}, m_id{ -1 } {
|
||||||
|
if (!seal_bfv_ctx || !seal_bfv_ctx->parameters_set())
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||||
|
"Missing Microsoft SEAL parameter context!");
|
||||||
|
|
||||||
int tmp_id;
|
int tmp_id;
|
||||||
if (!ctx_id_factory.min(tmp_id))
|
if (!ctx_id_factory.min(tmp_id))
|
||||||
return;
|
return;
|
||||||
@ -99,21 +120,11 @@ void seal_context::new_components() {
|
|||||||
|
|
||||||
// Generate new private component
|
// Generate new private component
|
||||||
|
|
||||||
data.params = seal::EncryptionParameters{ seal::scheme_type::bfv };
|
seal::KeyGenerator keygen { *seal_bfv_ctx };
|
||||||
data.params.set_poly_modulus_degree(VECSIZE);
|
|
||||||
data.params.set_coeff_modulus(seal::CoeffModulus::BFVDefault(VECSIZE));
|
|
||||||
data.params.set_plain_modulus(PLAINMOD);
|
|
||||||
|
|
||||||
data.ctx = std::make_unique<seal::SEALContext>(data.params);
|
|
||||||
if (!data.ctx || !data.ctx->parameters_set())
|
|
||||||
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
|
||||||
"Failed to allocate Microsoft SEAL context for new PRIVATE_COMPONENT!");
|
|
||||||
|
|
||||||
seal::KeyGenerator keygen { *data.ctx };
|
|
||||||
|
|
||||||
data.priv.private_key = keygen.secret_key();
|
data.priv.private_key = keygen.secret_key();
|
||||||
|
|
||||||
data.priv.decryptor = std::make_unique<seal::Decryptor>(*data.ctx, data.priv.private_key);
|
data.priv.decryptor = std::make_unique<seal::Decryptor>(*seal_bfv_ctx, data.priv.private_key);
|
||||||
if (!data.priv.decryptor)
|
if (!data.priv.decryptor)
|
||||||
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
||||||
"Failed to create Microsoft SEAL decryptor for new PRIVATE_COMPONENT!");
|
"Failed to create Microsoft SEAL decryptor for new PRIVATE_COMPONENT!");
|
||||||
@ -126,17 +137,17 @@ void seal_context::new_components() {
|
|||||||
keygen.create_galois_keys(data.pub.galois_keys);
|
keygen.create_galois_keys(data.pub.galois_keys);
|
||||||
keygen.create_relin_keys(data.pub.relin_keys);
|
keygen.create_relin_keys(data.pub.relin_keys);
|
||||||
|
|
||||||
data.pub.encoder = std::make_unique<seal::BatchEncoder>(*data.ctx);
|
data.pub.encoder = std::make_unique<seal::BatchEncoder>(*seal_bfv_ctx);
|
||||||
if (!data.pub.encoder || data.pub.encoder->slot_count() != VECSIZE)
|
if (!data.pub.encoder || data.pub.encoder->slot_count() != VECSIZE)
|
||||||
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
||||||
"Failed to create Microsoft SEAL encoder for new PUBLIC_COMPONENT!");
|
"Failed to create Microsoft SEAL encoder for new PUBLIC_COMPONENT!");
|
||||||
|
|
||||||
data.pub.encryptor = std::make_unique<seal::Encryptor>(*data.ctx, data.pub.public_key);
|
data.pub.encryptor = std::make_unique<seal::Encryptor>(*seal_bfv_ctx, data.pub.public_key);
|
||||||
if (!data.pub.encryptor)
|
if (!data.pub.encryptor)
|
||||||
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
||||||
"Failed to create Microsoft SEAL encryptor for new PUBLIC_COMPONENT!");
|
"Failed to create Microsoft SEAL encryptor for new PUBLIC_COMPONENT!");
|
||||||
|
|
||||||
data.pub.evaluator = std::make_unique<seal::Evaluator>(*data.ctx);
|
data.pub.evaluator = std::make_unique<seal::Evaluator>(*seal_bfv_ctx);
|
||||||
if (!data.pub.evaluator)
|
if (!data.pub.evaluator)
|
||||||
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
||||||
"Failed to create Microsoft SEAL evaluator for new PUBLIC_COMPONENT");
|
"Failed to create Microsoft SEAL evaluator for new PUBLIC_COMPONENT");
|
||||||
@ -163,12 +174,26 @@ void seal_context::clone_components(int components, std::shared_ptr<context>& pt
|
|||||||
}
|
}
|
||||||
|
|
||||||
void seal_context::allocate(ciphertext& ct) {
|
void seal_context::allocate(ciphertext& ct) {
|
||||||
|
ct = -1;
|
||||||
|
|
||||||
if (!ctxs.contains(m_id))
|
if (!ctxs.contains(m_id))
|
||||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||||
"Object does not hold a valid Microsoft SEAL context!");
|
"Object does not hold a valid Microsoft SEAL context!");
|
||||||
|
|
||||||
seal_context_data& data = ctxs.at(m_id);
|
seal_context_data& data = ctxs.at(m_id);
|
||||||
// TODO
|
|
||||||
|
int tmp_id;
|
||||||
|
if (!data.ct_id_factory.min(tmp_id))
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_MEMORY,
|
||||||
|
"Unable to allocate new ciphertext buffer!");
|
||||||
|
|
||||||
|
if (!data.ciphertexts.emplace(tmp_id, ct_buffer{}).second) {
|
||||||
|
data.ct_id_factory.free(tmp_id);
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_MEMORY,
|
||||||
|
"Unable to allocate new ciphertext buffer!");
|
||||||
|
}
|
||||||
|
|
||||||
|
ct = tmp_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void seal_context::free(ciphertext ct) {
|
void seal_context::free(ciphertext ct) {
|
||||||
@ -177,7 +202,13 @@ void seal_context::free(ciphertext ct) {
|
|||||||
"Object does not hold a valid Microsoft SEAL context!");
|
"Object does not hold a valid Microsoft SEAL context!");
|
||||||
|
|
||||||
seal_context_data& data = ctxs.at(m_id);
|
seal_context_data& data = ctxs.at(m_id);
|
||||||
// TODO
|
|
||||||
|
if (!data.ciphertexts.contains(ct))
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_INVALID_ARGUMENT,
|
||||||
|
"The specified ciphertext does not exist in this context!");
|
||||||
|
|
||||||
|
data.ciphertexts.erase(ct);
|
||||||
|
data.ct_id_factory.free(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
void seal_context::serialize(ciphertext ct, void* buf, std::size_t& n) const {
|
void seal_context::serialize(ciphertext ct, void* buf, std::size_t& n) const {
|
||||||
@ -186,7 +217,37 @@ void seal_context::serialize(ciphertext ct, void* buf, std::size_t& n) const {
|
|||||||
"Object does not hold a valid Microsoft SEAL context!");
|
"Object does not hold a valid Microsoft SEAL context!");
|
||||||
|
|
||||||
seal_context_data& data = ctxs.at(m_id);
|
seal_context_data& data = ctxs.at(m_id);
|
||||||
// TODO
|
|
||||||
|
if (!data.ciphertexts.contains(ct))
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_INVALID_ARGUMENT,
|
||||||
|
"The specified ciphertext does not exist in this context!");
|
||||||
|
|
||||||
|
const ct_buffer& ctbuf = data.ciphertexts.at(ct);
|
||||||
|
|
||||||
|
if (!ctbuf.initialized)
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_INVALID_ARGUMENT,
|
||||||
|
"The specified ciphertext is uninitialized!");
|
||||||
|
|
||||||
|
std::stringstream ss(std::ios::binary | std::ios::in | std::ios::out);
|
||||||
|
ctbuf.value.save(ss);
|
||||||
|
|
||||||
|
if (!ss)
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_INTERNAL,
|
||||||
|
"Microsoft SEAL failed to serialize the specified ciphertext!");
|
||||||
|
|
||||||
|
std::string serialized = ss.str();
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
n = serialized.size();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serialized.size() > n)
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_INVALID_ARGUMENT,
|
||||||
|
"The given buffer is not sufficient to hold the serialized ciphertext!");
|
||||||
|
|
||||||
|
std::memcpy(buf, serialized.data(), serialized.size());
|
||||||
|
n = serialized.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void seal_context::deserialize(ciphertext ct, const void* buf, std::size_t n) const {
|
void seal_context::deserialize(ciphertext ct, const void* buf, std::size_t n) const {
|
||||||
@ -195,7 +256,26 @@ void seal_context::deserialize(ciphertext ct, const void* buf, std::size_t n) co
|
|||||||
"Object does not hold a valid Microsoft SEAL context!");
|
"Object does not hold a valid Microsoft SEAL context!");
|
||||||
|
|
||||||
seal_context_data& data = ctxs.at(m_id);
|
seal_context_data& data = ctxs.at(m_id);
|
||||||
// TODO
|
|
||||||
|
if (!buf || n == 0)
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_INVALID_ARGUMENT,
|
||||||
|
"No serialized data was given!");
|
||||||
|
|
||||||
|
if (!data.ciphertexts.contains(ct))
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_INVALID_ARGUMENT,
|
||||||
|
"The specified ciphertext does not exist in this context!");
|
||||||
|
|
||||||
|
ct_buffer& ctbuf = data.ciphertexts.at(ct);
|
||||||
|
|
||||||
|
std::string sdata(reinterpret_cast<const char*>(buf), n);
|
||||||
|
std::istringstream iss(std::move(sdata), std::ios::binary);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ctbuf.value.load(*seal_bfv_ctx, iss);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throw bfv_exception(bfv_exception::REASON::CTX_INTERNAL,
|
||||||
|
"Microsoft SEAL failed to deserialize the specified data!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void seal_context::encrypt(const plaintext& pt, ciphertext ct) const {
|
void seal_context::encrypt(const plaintext& pt, ciphertext ct) const {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user