From fab47a227a03a00c64ac6b56a0cd9ab226c29bb8 Mon Sep 17 00:00:00 2001 From: York Jasper Niebuhr Date: Fri, 28 Nov 2025 22:19:04 +0100 Subject: [PATCH] Progress on the SEAL BFV implementation --- include/bfv.hpp | 33 ++++------------------ src/seal_bfv.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 31 deletions(-) diff --git a/include/bfv.hpp b/include/bfv.hpp index 997445d..2cc38d6 100644 --- a/include/bfv.hpp +++ b/include/bfv.hpp @@ -13,33 +13,8 @@ namespace homcert::bfv { constexpr std::size_t VECSIZE = 8192; constexpr std::size_t PLAINMOD = 16760833; // 8192*2*1023+1 and prime -template -struct smallest_uint; - -template -struct smallest_uint> { - using type = std::uint8_t; -}; - -template -struct smallest_uint> { - using type = std::uint16_t; -}; - -template -struct smallest_uint> { - using type = std::uint32_t; -}; - -template -struct smallest_uint> { - using type = std::uint64_t; -}; - struct plaintext { - using coefficient = typename smallest_uint::type; - - std::array coefficients; + std::array slots; // Arithmetic... }; @@ -87,8 +62,8 @@ struct context { 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& 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; + virtual void dump_components(int components, void* buf, std::size_t& n) const = 0; + virtual void load_components(const void* buf, std::size_t n) = 0; virtual void allocate(ciphertext& ct) = 0; virtual void free(ciphertext ct) = 0; @@ -123,6 +98,8 @@ struct seal_context : public context { void new_components() override; void has_components(int& components) const override; void clone_components(int components, std::shared_ptr& ptr) const override; + void dump_components(int components, void* buf, std::size_t& n) const override; + void load_components(const void* buf, std::size_t n) override; void allocate(ciphertext& ct) override; void free(ciphertext ct) override; void serialize(ciphertext ct, void* buf, std::size_t& n) const override; diff --git a/src/seal_bfv.cpp b/src/seal_bfv.cpp index 1859791..5281fdf 100644 --- a/src/seal_bfv.cpp +++ b/src/seal_bfv.cpp @@ -81,10 +81,25 @@ struct seal_context_data { static minfree ctx_id_factory { 0 }; static std::unordered_map ctxs; +static seal::Plaintext encode_plaintext(const seal::BatchEncoder& encoder, const plaintext& pt) { + seal::Plaintext res; + + try { + encoder.encode(gsl::span(pt.slots), res); + } catch (const std::exception& e) { + std::string what; + what += "Microsoft SEAL failed to encode data ("; + what += e.what(); + what += ")"; + throw bfv_exception(bfv_exception::REASON::CTX_INTERNAL, what); + } + + return std::move(res); +} + 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!"); + return; int tmp_id; if (!ctx_id_factory.min(tmp_id)) @@ -173,6 +188,24 @@ void seal_context::clone_components(int components, std::shared_ptr& pt // TODO } +void seal_context::dump_components(int components, 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::load_components(const void* buf, std::size_t n) { + 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) { ct = -1; @@ -276,6 +309,8 @@ void seal_context::deserialize(ciphertext ct, const void* buf, std::size_t n) co throw bfv_exception(bfv_exception::REASON::CTX_INTERNAL, "Microsoft SEAL failed to deserialize the specified data!"); } + + ctbuf.initialized = true; } void seal_context::encrypt(const plaintext& pt, ciphertext ct) const { @@ -284,7 +319,30 @@ void seal_context::encrypt(const plaintext& pt, ciphertext ct) const { "Object does not hold a valid Microsoft SEAL context!"); seal_context_data& data = ctxs.at(m_id); - // TODO + + if (!(data.components & PUBLIC_COMPONENT)) + throw bfv_exception(bfv_exception::REASON::CTX_COMPONENT, + "Context does not hold required PUBLIC_COMPONENT!"); + + 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); + + seal::Plaintext encoded = encode_plaintext(*data.pub.encoder, pt); + + try { + data.pub.encryptor->encrypt(encoded, ctbuf.value); + } catch (const std::exception& e) { + std::string what; + what += "Microsoft SEAL failed to encrypt the given plaintext ("; + what += e.what(); + what += ")"; + throw bfv_exception(bfv_exception::REASON::CTX_INTERNAL, what); + } + + ctbuf.initialized = true; } void seal_context::decrypt(ciphertext ct, plaintext& pt) const { @@ -399,6 +457,14 @@ void seal_context::clone_components(int components, std::shared_ptr& pt throw bfv_exception(bfv_exception::REASON::CTX_NOT_IMPLEMENTED, "BFV context for Microsoft SEAL is not implemented"); } +void seal_context::dump_components(int components, void* buf, std::size_t& n) const { + throw bfv_exception(bfv_exception::REASON::CTX_NOT_IMPLEMENTED, "BFV context for Microsoft SEAL is not implemented"); +} + +void seal_context::load_components(const void* buf, std::size_t n) { + throw bfv_exception(bfv_exception::REASON::CTX_NOT_IMPLEMENTED, "BFV context for Microsoft SEAL is not implemented"); +} + void seal_context::allocate(ciphertext& ct) { throw bfv_exception(bfv_exception::REASON::CTX_NOT_IMPLEMENTED, "BFV context for Microsoft SEAL is not implemented"); }