Beginnings of SEAL BFV implementation
This commit is contained in:
parent
d39ce2d557
commit
dff1d7460b
@ -51,6 +51,7 @@ using ciphertext = int;
|
||||
class bfv_exception : public std::exception {
|
||||
public:
|
||||
enum class REASON {
|
||||
CTX_INVALID,
|
||||
CTX_NOT_IMPLEMENTED,
|
||||
CTX_NO_PRIVATE,
|
||||
CTX_NO_PUBLIC,
|
||||
@ -74,10 +75,16 @@ struct context {
|
||||
static constexpr int PUBLIC_COMPONENT = 1;
|
||||
static constexpr int PRIVATE_COMPONENT = 2;
|
||||
|
||||
context(const context& other) = delete;
|
||||
context(context&& other) = delete;
|
||||
context& operator=(const context& other) = delete;
|
||||
context& operator=(context&& other) = delete;
|
||||
|
||||
context() = default;
|
||||
virtual ~context() = default;
|
||||
|
||||
virtual void new_components(int components) = 0; // context default constructs empty
|
||||
virtual void has_components(int components) const = 0;
|
||||
virtual void new_components() = 0; // context default constructs empty
|
||||
virtual void has_components(int& components) const = 0;
|
||||
virtual void clone_components(int components, std::shared_ptr<context>& ptr) const = 0;
|
||||
// virtual void dump_components(int components, void* buf, std::size_t& n) const = 0;
|
||||
// virtual void load_components(int components, const void* buf, std::size_t n) = 0;
|
||||
@ -112,8 +119,8 @@ struct seal_context : public context {
|
||||
seal_context();
|
||||
~seal_context();
|
||||
|
||||
void new_components(int components) override;
|
||||
void has_components(int components) const override;
|
||||
void new_components() override;
|
||||
void has_components(int& components) const override;
|
||||
void clone_components(int components, std::shared_ptr<context>& ptr) const override;
|
||||
void allocate(ciphertext& ct) override;
|
||||
void free(ciphertext ct) override;
|
||||
|
||||
223
src/seal_bfv.cpp
223
src/seal_bfv.cpp
@ -2,86 +2,299 @@
|
||||
|
||||
#ifdef HOMCERT_BFV_SEAL
|
||||
|
||||
#include <set>
|
||||
#include <limits>
|
||||
#include <unordered_map>
|
||||
#include <seal/seal.h>
|
||||
|
||||
namespace homcert::bfv {
|
||||
|
||||
seal_context::seal_context() {
|
||||
class minfree {
|
||||
int next;
|
||||
std::set<int> freed;
|
||||
public:
|
||||
minfree(int start) : next{ start } {}
|
||||
|
||||
bool min(int& v) {
|
||||
auto it = freed.begin();
|
||||
if (it == freed.end()) {
|
||||
if (next >= std::numeric_limits<int>::max())
|
||||
return false;
|
||||
|
||||
v = next++;
|
||||
return true;
|
||||
}
|
||||
|
||||
v = *it;
|
||||
freed.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
void free(int v) {
|
||||
if (v >= next || freed.contains(v))
|
||||
return; // Just to be safe
|
||||
|
||||
freed.insert(v);
|
||||
}
|
||||
};
|
||||
|
||||
struct seal_context_data {
|
||||
int components;
|
||||
|
||||
seal::EncryptionParameters params;
|
||||
std::unique_ptr<seal::SEALContext> ctx;
|
||||
|
||||
struct {
|
||||
std::unique_ptr<seal::Decryptor> decryptor;
|
||||
seal::SecretKey private_key;
|
||||
} priv;
|
||||
|
||||
struct {
|
||||
std::unique_ptr<seal::BatchEncoder> encoder;
|
||||
std::unique_ptr<seal::Encryptor> encryptor;
|
||||
std::unique_ptr<seal::Evaluator> evaluator;
|
||||
seal::PublicKey public_key;
|
||||
seal::GaloisKeys galois_keys;
|
||||
seal::RelinKeys relin_keys;
|
||||
} pub;
|
||||
|
||||
seal_context_data() : components{ 0 } {}
|
||||
};
|
||||
|
||||
static minfree ctx_id_factory { 0 };
|
||||
static std::unordered_map<int, seal_context_data> ctxs;
|
||||
|
||||
seal_context::seal_context() : context{}, m_id{ -1 } {
|
||||
int tmp_id;
|
||||
if (!ctx_id_factory.min(tmp_id))
|
||||
return;
|
||||
|
||||
if (!ctxs.emplace(tmp_id, seal_context_data{}).second) {
|
||||
ctx_id_factory.free(tmp_id);
|
||||
return;
|
||||
}
|
||||
|
||||
m_id = tmp_id;
|
||||
}
|
||||
|
||||
seal_context::~seal_context() {
|
||||
if (m_id == -1)
|
||||
return;
|
||||
|
||||
ctxs.erase(m_id);
|
||||
ctx_id_factory.free(m_id);
|
||||
m_id = -1;
|
||||
}
|
||||
|
||||
void seal_context::new_components(int components) {
|
||||
void seal_context::new_components() {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
|
||||
if (data.components & (PUBLIC_COMPONENT | PRIVATE_COMPONENT))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
||||
"Object already holds valid components!");
|
||||
|
||||
// Generate new private component
|
||||
|
||||
data.params = seal::EncryptionParameters{ seal::scheme_type::bfv };
|
||||
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.decryptor = std::make_unique<seal::Decryptor>(*data.ctx, data.priv.private_key);
|
||||
if (!data.priv.decryptor)
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
||||
"Failed to create Microsoft SEAL decryptor for new PRIVATE_COMPONENT!");
|
||||
|
||||
data.components |= PRIVATE_COMPONENT;
|
||||
|
||||
// Generate new private component
|
||||
|
||||
keygen.create_public_key(data.pub.public_key);
|
||||
keygen.create_galois_keys(data.pub.galois_keys);
|
||||
keygen.create_relin_keys(data.pub.relin_keys);
|
||||
|
||||
data.pub.encoder = std::make_unique<seal::BatchEncoder>(*data.ctx);
|
||||
if (!data.pub.encoder || data.pub.encoder->slot_count() != VECSIZE)
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_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);
|
||||
if (!data.pub.encryptor)
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
||||
"Failed to create Microsoft SEAL encryptor for new PUBLIC_COMPONENT!");
|
||||
|
||||
data.pub.evaluator = std::make_unique<seal::Evaluator>(*data.ctx);
|
||||
if (!data.pub.evaluator)
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT,
|
||||
"Failed to create Microsoft SEAL evaluator for new PUBLIC_COMPONENT");
|
||||
|
||||
data.components |= PUBLIC_COMPONENT;
|
||||
}
|
||||
|
||||
void seal_context::has_components(int components) const {
|
||||
void seal_context::has_components(int& components) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
components = data.components;
|
||||
}
|
||||
|
||||
void seal_context::clone_components(int components, std::shared_ptr<context>& ptr) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::allocate(ciphertext& ct) {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::free(ciphertext ct) {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::serialize(ciphertext ct, void* buf, std::size_t& n) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::deserialize(ciphertext ct, const void* buf, std::size_t n) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::encrypt(const plaintext& pt, ciphertext ct) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::decrypt(ciphertext ct, plaintext& pt) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::add_cipher_plain(ciphertext a, const plaintext& b, ciphertext res) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::add_cipher_cipher(ciphertext a, ciphertext b, ciphertext res) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::sub_cipher_plain(ciphertext a, const plaintext& b, ciphertext res) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::sub_cipher_cipher(ciphertext a, ciphertext b, ciphertext res) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::mul_cipher_plain(ciphertext a, const plaintext& b, ciphertext res) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::mul_cipher_cipher(ciphertext a, ciphertext b, ciphertext res) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::rot_cipher_rows(ciphertext ct, int r, ciphertext res) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::swap_cipher_rows(ciphertext ct, ciphertext res) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
void seal_context::noise_budget(ciphertext ct, std::size_t& budget) const {
|
||||
if (!ctxs.contains(m_id))
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_INVALID,
|
||||
"Object does not hold a valid Microsoft SEAL context!");
|
||||
|
||||
seal_context_data& data = ctxs.at(m_id);
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
||||
@ -94,11 +307,11 @@ seal_context::seal_context() {}
|
||||
|
||||
seal_context::~seal_context() {}
|
||||
|
||||
void seal_context::new_components(int components) {
|
||||
void seal_context::new_components() {
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_NOT_IMPLEMENTED, "BFV context for Microsoft SEAL is not implemented");
|
||||
}
|
||||
|
||||
void seal_context::has_components(int components) const {
|
||||
void seal_context::has_components(int& components) const {
|
||||
throw bfv_exception(bfv_exception::REASON::CTX_NOT_IMPLEMENTED, "BFV context for Microsoft SEAL is not implemented");
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user