#pragma once #include #include #include #include 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; // Arithmetic... }; using ciphertext = int; // Inheriting from context class allows pluggability of implementations (e.g. SEAL vs. GPU) class context { public: context(const context& other) = delete; context(context&& other) noexcept; context& operator=(const context& other) = delete; context& operator=(context&& other) noexcept; context(); virtual ~context(); virtual bool allocate(ciphertext& ct) = 0; virtual bool free(ciphertext ct) = 0; virtual bool serialize(ciphertext ct, void* buf, std::size_t& n) = 0; virtual bool deserialize(ciphertext ct, const void* buf, std::size_t n) = 0; virtual bool encrypt(const plaintext& pt, ciphertext ct) = 0; virtual bool decrypt(ciphertext ct, plaintext& pt) = 0; virtual bool add_cipher_plain(ciphertext a, const plaintext& b, ciphertext res) = 0; virtual bool add_cipher_cipher(ciphertext a, ciphertext b, ciphertext res) = 0; virtual bool sub_cipher_plain(ciphertext a, const plaintext& b, ciphertext res) = 0; virtual bool sub_cipher_cipher(ciphertext a, ciphertext b, ciphertext res) = 0; virtual bool mul_cipher_plain(ciphertext a, const plaintext& b, ciphertext res) = 0; virtual bool mul_cipher_cipher(ciphertext a, ciphertext b, ciphertext res) = 0; virtual bool rot_cipher_rows(ciphertext ct, int r, ciphertext res) = 0; virtual bool swap_cipher_rows(ciphertext ct, ciphertext res) = 0; virtual bool noise_budget(ciphertext ct, std::size_t& budget) = 0; }; /* NOTE -> Implementations may defer operations or not wait for them to finish For example, GPU implementations may dispatch multiplications when they arive Additionally, a graph of running operations is maintained to handle data dependencies Only when data is required to actually be present (e.g. decrypt), does the implementation wait */ /* activate_context(std::shared_ptr ctx) -> thread local pointer is set Raw ciphertext and plaintext classes always have the full 8192 coefficients (defined in context as static constexpr) bfv::vector<...> -> can be plaintext or ciphertext -> can be base (owns plain-/ciphertext) or component (view to part of base) -> can be local or remote -> can be a single vector or multiple vectors/components (variadic) -> arithmetic with component masks it out -> arithmetic with base does operation on all components -> tracks multiplicative depth -> warning/error if multiplicative depth exceeds limit -> use bootstrap member function to handle the warnings/errors -> callbacks to reach peer in context -> bootstrap_client (unchecked, just raw bootstrap, checks happen at an upper layer using other callbacks) -> bootstrap_server_await (waits for client to make request) -> bootstrap_server_serve (called immediately after request received with value to be returned) -> automatically does secure reveal when cipher is transformed to plain -> queues operations until used (cast to plaintext, communication with peer) Programs are defined TWICE -> local stuff is executed -> remote stuff is hosted (e.g. bootstrapping server) -> defined once from each side (differ e.g. in the plaintext inputs etc.) -> program base class may be used to handle context setting */ }