Beginnings of SEAL BFV implementation

This commit is contained in:
York Jasper Niebuhr 2025-11-27 22:05:15 +01:00
parent d39ce2d557
commit dff1d7460b
2 changed files with 229 additions and 9 deletions

View File

@ -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;

View File

@ -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");
}