当前位置: 首页 > 工具软件 > SEAL > 使用案例 >

SEAL开源库源码08

龙正初
2023-12-01

SEAL开源库源码08

seal/publickey.h

PublicKey 类,用 Ciphertext 存储公钥

#include "seal/ciphertext.h"
#include "seal/context.h"
#include "seal/valcheck.h"
#include <iostream>

namespace seal
{
    /**
    Class to store a public key.

    @par Thread Safety
    In general, reading from PublicKey is thread-safe as long as no other thread
    is concurrently mutating it. This is due to the underlying data structure
    storing the public key not being thread-safe.

    @see KeyGenerator for the class that generates the public key.
    @see SecretKey for the class that stores the secret key.
    @see RelinKeys for the class that stores the relinearization keys.
    @see GaloisKeys for the class that stores the Galois keys.
    */
    class PublicKey
    {
        friend class KeyGenerator;
        friend class KSwitchKeys;

    public:
        /**
        Creates an empty public key.
        */
        PublicKey() = default;

        /**
        Creates a new PublicKey by copying an old one.

        @param[in] copy The PublicKey to copy from
        */
        PublicKey(const PublicKey &copy) = default;

        /**
        Creates a new PublicKey by moving an old one.

        @param[in] source The PublicKey to move from
        */
        PublicKey(PublicKey &&source) = default;

        /**
        Copies an old PublicKey to the current one.

        @param[in] assign The PublicKey to copy from
        */
        PublicKey &operator=(const PublicKey &assign) = default;

        /**
        Moves an old PublicKey to the current one.

        @param[in] assign The PublicKey to move from
        */
        PublicKey &operator=(PublicKey &&assign) = default;

        /**
        Returns a reference to the underlying data.
        */
        SEAL_NODISCARD inline auto &data() noexcept
        {
            return pk_;
        }

        /**
        Returns a const reference to the underlying data.
        */
        SEAL_NODISCARD inline auto &data() const noexcept
        {
            return pk_;
        }

        /**
        Returns an upper bound on the size of the PublicKey, as if it was written
        to an output stream.

        @param[in] compr_mode The compression mode
        @throws std::invalid_argument if the compression mode is not supported
        @throws std::logic_error if the size does not fit in the return type
        */
        SEAL_NODISCARD inline std::streamoff save_size(
            compr_mode_type compr_mode = Serialization::compr_mode_default) const
        {
            return pk_.save_size(compr_mode);
        }

        /**
        Saves the PublicKey to an output stream. The output is in binary format
        and not human-readable. The output stream must have the "binary" flag set.

        @param[out] stream The stream to save the PublicKey to
        @param[in] compr_mode The desired compression mode
        @throws std::invalid_argument if the compression mode is not supported
        @throws std::logic_error if the data to be saved is invalid, or if
        compression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff save(
            std::ostream &stream, compr_mode_type compr_mode = Serialization::compr_mode_default) const
        {
            return pk_.save(stream, compr_mode);
        }

        /**
        Loads a PublicKey from an input stream overwriting the current PublicKey.
        No checking of the validity of the PublicKey data against encryption
        parameters is performed. This function should not be used unless the
        PublicKey comes from a fully trusted source.

        @param[in] context The SEALContext
        @param[in] stream The stream to load the PublicKey from
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff unsafe_load(const SEALContext &context, std::istream &stream)
        {
            Ciphertext new_pk(pk_.pool());
            auto in_size = new_pk.unsafe_load(context, stream);
            std::swap(pk_, new_pk);
            return in_size;
        }

        /**
        Loads a PublicKey from an input stream overwriting the current PublicKey.
        The loaded PublicKey is verified to be valid for the given SEALContext.

        @param[in] context The SEALContext
        @param[in] stream The stream to load the PublicKey from
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff load(const SEALContext &context, std::istream &stream)
        {
            PublicKey new_pk(pool());
            auto in_size = new_pk.unsafe_load(context, stream);
            if (!is_valid_for(new_pk, context))
            {
                throw std::logic_error("PublicKey data is invalid");
            }
            std::swap(*this, new_pk);
            return in_size;
        }

        /**
        Saves the PublicKey to a given memory location. The output is in binary
        format and is not human-readable.

        @param[out] out The memory location to write the PublicKey to
        @param[in] size The number of bytes available in the given memory location
        @param[in] compr_mode The desired compression mode
        @throws std::invalid_argument if out is null or if size is too small to
        contain a SEALHeader, or if the compression mode is not supported
        @throws std::logic_error if the data to be saved is invalid, or if
        compression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff save(
            seal_byte *out, std::size_t size, compr_mode_type compr_mode = Serialization::compr_mode_default) const
        {
            return pk_.save(out, size, compr_mode);
        }

        /**
        Loads a PublicKey from a given memory location overwriting the current
        PublicKey. No checking of the validity of the PublicKey data against
        encryption parameters is performed. This function should not be used
        unless the PublicKey comes from a fully trusted source.

        @param[in] context The SEALContext
        @param[in] in The memory location to load the PublicKey from
        @param[in] size The number of bytes available in the given memory location
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::invalid_argument if in is null or if size is too small to
        contain a SEALHeader
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff unsafe_load(const SEALContext &context, const seal_byte *in, std::size_t size)
        {
            Ciphertext new_pk(pk_.pool());
            auto in_size = new_pk.unsafe_load(context, in, size);
            std::swap(pk_, new_pk);
            return in_size;
        }

        /**
        Loads a PublicKey from a given memory location overwriting the current
        PublicKey. The loaded PublicKey is verified to be valid for the given
        SEALContext.

        @param[in] context The SEALContext
        @param[in] in The memory location to load the PublicKey from
        @param[in] size The number of bytes available in the given memory location
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::invalid_argument if in is null or if size is too small to
        contain a SEALHeader
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff load(const SEALContext &context, const seal_byte *in, std::size_t size)
        {
            PublicKey new_pk(pool());
            auto in_size = new_pk.unsafe_load(context, in, size);
            if (!is_valid_for(new_pk, context))
            {
                throw std::logic_error("PublicKey data is invalid");
            }
            std::swap(*this, new_pk);
            return in_size;
        }

        /**
        Returns a reference to parms_id.
        */
        SEAL_NODISCARD inline auto &parms_id() noexcept
        {
            return pk_.parms_id();
        }

        /**
        Returns a const reference to parms_id.
        */
        SEAL_NODISCARD inline auto &parms_id() const noexcept
        {
            return pk_.parms_id();
        }

        /**
        Returns the currently used MemoryPoolHandle.
        */
        SEAL_NODISCARD inline MemoryPoolHandle pool() const noexcept
        {
            return pk_.pool();
        }

        /**
        Enables access to private members of seal::PublicKey for SEAL_C.
        */
        struct PublicKeyPrivateHelper;

    private:
        /**
        Creates an empty public key. This is needed for loading KSwitchKeys with
        the keys residing in a single memory pool.

        @param[in] pool The MemoryPoolHandle pointing to a valid memory pool
        @throws std::invalid_argument if pool is uninitialized
        */
        PublicKey(MemoryPoolHandle pool) : pk_(std::move(pool))
        {}

        Ciphertext pk_;
    };

seal/secretkey.h

SecretKey 类,用 Plaintext 存储私钥

    /**
    Class to store a secret key.

    @par Thread Safety
    In general, reading from SecretKey is thread-safe as long as no other thread
    is concurrently mutating it. This is due to the underlying data structure
    storing the secret key not being thread-safe.

    @see KeyGenerator for the class that generates the secret key.
    @see PublicKey for the class that stores the public key.
    @see RelinKeys for the class that stores the relinearization keys.
    @see GaloisKeys for the class that stores the Galois keys.
    */
    class SecretKey
    {
        friend class KeyGenerator;

    public:
        /**
        Creates an empty secret key.
        */
        SecretKey() = default;

        /**
        Creates a new SecretKey by copying an old one.

        @param[in] copy The SecretKey to copy from
        */
        SecretKey(const SecretKey &copy)
        {
            // Note: sk_ is at this point initialized to use a custom (new)
            // memory pool with the `clear_on_destruction' property. Now use
            // Plaintext::operator =(const Plaintext &) to copy over the data.
            // This is very important to do right, otherwise newly created
            // SecretKey may use a normal memory pool obtained from
            // MemoryManager::GetPool() with currently active profile (MMProf).
            sk_ = copy.sk_;
        }

        /**
        Destroys the SecretKey object.
        */
        ~SecretKey() = default;

        /**
        Creates a new SecretKey by moving an old one.

        @param[in] source The SecretKey to move from
        */
        SecretKey(SecretKey &&source) = default;

        /**
        Copies an old SecretKey to the current one.

        @param[in] assign The SecretKey to copy from
        */
        SecretKey &operator=(const SecretKey &assign)
        {
            Plaintext new_sk(MemoryManager::GetPool(mm_prof_opt::mm_force_new, true));
            new_sk = assign.sk_;
            std::swap(sk_, new_sk);
            return *this;
        }

        /**
        Moves an old SecretKey to the current one.

        @param[in] assign The SecretKey to move from
        */
        SecretKey &operator=(SecretKey &&assign) = default;

        /**
        Returns a reference to the underlying polynomial.
        */
        SEAL_NODISCARD inline auto &data() noexcept
        {
            return sk_;
        }

        /**
        Returns a const reference to the underlying polynomial.
        */
        SEAL_NODISCARD inline auto &data() const noexcept
        {
            return sk_;
        }

        /**
        Returns an upper bound on the size of the SecretKey, as if it was written
        to an output stream.

        @param[in] compr_mode The compression mode
        @throws std::invalid_argument if the compression mode is not supported
        @throws std::logic_error if the size does not fit in the return type
        */
        SEAL_NODISCARD inline std::streamoff save_size(
            compr_mode_type compr_mode = Serialization::compr_mode_default) const
        {
            return sk_.save_size(compr_mode);
        }

        /**
        Saves the SecretKey to an output stream. The output is in binary format
        and not human-readable. The output stream must have the "binary" flag set.

        @param[out] stream The stream to save the SecretKey to
        @param[in] compr_mode The desired compression mode
        @throws std::invalid_argument if the compression mode is not supported
        @throws std::logic_error if the data to be saved is invalid, or if
        compression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff save(
            std::ostream &stream, compr_mode_type compr_mode = Serialization::compr_mode_default) const
        {
            using namespace std::placeholders;
            return Serialization::Save(
                std::bind(&Plaintext::save_members, &sk_, _1), sk_.save_size(compr_mode_type::none), stream, compr_mode,
                true);
        }

        /**
        Loads a SecretKey from an input stream overwriting the current SecretKey.
        No checking of the validity of the SecretKey data against encryption
        parameters is performed. This function should not be used unless the
        SecretKey comes from a fully trusted source.

        @param[in] context The SEALContext
        @param[in] stream The stream to load the SecretKey from
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff unsafe_load(const SEALContext &context, std::istream &stream)
        {
            using namespace std::placeholders;

            // We use a fresh memory pool with `clear_on_destruction' enabled.
            Plaintext new_sk(MemoryManager::GetPool(mm_prof_opt::mm_force_new, true));
            auto in_size = Serialization::Load(
                std::bind(&Plaintext::load_members, &new_sk, std::move(context), _1, _2), stream, true);
            std::swap(sk_, new_sk);
            return in_size;
        }

        /**
        Loads a SecretKey from an input stream overwriting the current SecretKey.
        The loaded SecretKey is verified to be valid for the given SEALContext.

        @param[in] context The SEALContext
        @param[in] stream The stream to load the SecretKey from
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff load(const SEALContext &context, std::istream &stream)
        {
            SecretKey new_sk;
            auto in_size = new_sk.unsafe_load(context, stream);
            if (!is_valid_for(new_sk, context))
            {
                throw std::logic_error("SecretKey data is invalid");
            }
            std::swap(*this, new_sk);
            return in_size;
        }

        /**
        Saves the SecretKey to a given memory location. The output is in binary
        format and is not human-readable.

        @param[out] out The memory location to write the SecretKey to
        @param[in] size The number of bytes available in the given memory location
        @param[in] compr_mode The desired compression mode
        @throws std::invalid_argument if out is null or if size is too small to
        contain a SEALHeader, or if the compression mode is not supported
        @throws std::logic_error if the data to be saved is invalid, or if
        compression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff save(
            seal_byte *out, std::size_t size, compr_mode_type compr_mode = Serialization::compr_mode_default) const
        {
            using namespace std::placeholders;
            return Serialization::Save(
                std::bind(&Plaintext::save_members, &sk_, _1), sk_.save_size(compr_mode_type::none), out, size,
                compr_mode, true);
        }

        /**
        Loads a SecretKey from a given memory location overwriting the current
        SecretKey. No checking of the validity of the SecretKey data against
        encryption parameters is performed. This function should not be used
        unless the SecretKey comes from a fully trusted source.

        @param[in] context The SEALContext
        @param[in] in The memory location to load the SecretKey from
        @param[in] size The number of bytes available in the given memory location
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::invalid_argument if in is null or if size is too small to
        contain a SEALHeader
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff unsafe_load(const SEALContext &context, const seal_byte *in, std::size_t size)
        {
            using namespace std::placeholders;

            // We use a fresh memory pool with `clear_on_destruction' enabled.
            Plaintext new_sk(MemoryManager::GetPool(mm_prof_opt::mm_force_new, true));
            auto in_size = Serialization::Load(
                std::bind(&Plaintext::load_members, &new_sk, std::move(context), _1, _2), in, size, true);
            std::swap(sk_, new_sk);
            return in_size;
        }

        /**
        Loads a SecretKey from a given memory location overwriting the current
        SecretKey. The loaded SecretKey is verified to be valid for the given
        SEALContext.

        @param[in] context The SEALContext
        @param[in] in The memory location to load the SecretKey from
        @param[in] size The number of bytes available in the given memory location
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::invalid_argument if in is null or if size is too small to
        contain a SEALHeader
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff load(const SEALContext &context, const seal_byte *in, std::size_t size)
        {
            SecretKey new_sk;
            auto in_size = new_sk.unsafe_load(context, in, size);
            if (!is_valid_for(new_sk, context))
            {
                throw std::logic_error("SecretKey data is invalid");
            }
            std::swap(*this, new_sk);
            return in_size;
        }

        /**
        Returns a reference to parms_id.

        @see EncryptionParameters for more information about parms_id.
        */
        SEAL_NODISCARD inline auto &parms_id() noexcept
        {
            return sk_.parms_id();
        }

        /**
        Returns a const reference to parms_id.

        @see EncryptionParameters for more information about parms_id.
        */
        SEAL_NODISCARD inline auto &parms_id() const noexcept
        {
            return sk_.parms_id();
        }

        /**
        Returns the currently used MemoryPoolHandle.
        */
        SEAL_NODISCARD inline MemoryPoolHandle pool() const noexcept
        {
            return sk_.pool();
        }

    private:
        // We use a fresh memory pool with `clear_on_destruction' enabled.
        Plaintext sk_{ MemoryManager::GetPool(mm_prof_opt::mm_force_new, true) };
    };

seal/kswichkeys.h,用一个 PublicKey 的二维数组保存密钥

    /**
    Class to store keyswitching keys. It should never be necessary for normal
    users to create an instance of KSwitchKeys. This class is used strictly as
    a base class for RelinKeys and GaloisKeys classes.

    @par Keyswitching
    Concretely, keyswitching is used to change a ciphertext encrypted with one
    key to be encrypted with another key. It is a general technique and is used
    in relinearization and Galois rotations. A keyswitching key contains a sequence
    (vector) of keys. In RelinKeys, each key is an encryption of a power of the
    secret key. In GaloisKeys, each key corresponds to a type of rotation.

    @par Thread Safety
    In general, reading from KSwitchKeys is thread-safe as long as no
    other thread is concurrently mutating it. This is due to the underlying
    data structure storing the keyswitching keys not being thread-safe.

    @see RelinKeys for the class that stores the relinearization keys.
    @see GaloisKeys for the class that stores the Galois keys.
    */
    class KSwitchKeys
    {
        friend class KeyGenerator;
        friend class RelinKeys;
        friend class GaloisKeys;

    public:
        /**
        Creates an empty KSwitchKeys.
        */
        KSwitchKeys() = default;

        /**
        Creates a new KSwitchKeys instance by copying a given instance.

        @param[in] copy The KSwitchKeys to copy from
        */
        KSwitchKeys(const KSwitchKeys &copy) = default;

        /**
        Creates a new KSwitchKeys instance by moving a given instance.

        @param[in] source The RelinKeys to move from
        */
        KSwitchKeys(KSwitchKeys &&source) = default;

        /**
        Copies a given KSwitchKeys instance to the current one.

        @param[in] assign The KSwitchKeys to copy from
        */
        KSwitchKeys &operator=(const KSwitchKeys &assign);

        /**
        Moves a given KSwitchKeys instance to the current one.

        @param[in] assign The KSwitchKeys to move from
        */
        KSwitchKeys &operator=(KSwitchKeys &&assign) = default;

        /**
        Returns the current number of keyswitching keys. Only keys that are
        non-empty are counted.
        */
        SEAL_NODISCARD inline std::size_t size() const noexcept
        {
            return std::accumulate(keys_.cbegin(), keys_.cend(), std::size_t(0), [](std::size_t res, auto &next_key) {
                return res + (next_key.empty() ? 0 : 1);
            });
        }

        /**
        Returns a reference to the KSwitchKeys data.
        */
        SEAL_NODISCARD inline auto &data() noexcept
        {
            return keys_;
        }

        /**
        Returns a const reference to the KSwitchKeys data.
        */
        SEAL_NODISCARD inline auto &data() const noexcept
        {
            return keys_;
        }

        /**
        Returns a reference to a keyswitching key at a given index.

        @param[in] index The index of the keyswitching key
        @throws std::invalid_argument if the key at the given index does not exist
        */
        SEAL_NODISCARD inline auto &data(std::size_t index)
        {
            if (index >= keys_.size() || keys_[index].empty())
            {
                throw std::invalid_argument("keyswitching key does not exist");
            }
            return keys_[index];
        }

        /**
        Returns a const reference to a keyswitching key at a given index.

        @param[in] index The index of the keyswitching key
        @throws std::invalid_argument if the key at the given index does not exist
        */
        SEAL_NODISCARD inline const auto &data(std::size_t index) const
        {
            if (index >= keys_.size() || keys_[index].empty())
            {
                throw std::invalid_argument("keyswitching key does not exist");
            }
            return keys_[index];
        }

        /**
        Returns a reference to parms_id.

        @see EncryptionParameters for more information about parms_id.
        */
        SEAL_NODISCARD inline auto &parms_id() noexcept
        {
            return parms_id_;
        }

        /**
        Returns a const reference to parms_id.

        @see EncryptionParameters for more information about parms_id.
        */
        SEAL_NODISCARD inline auto &parms_id() const noexcept
        {
            return parms_id_;
        }

        /**
        Returns an upper bound on the size of the KSwitchKeys, as if it was written
        to an output stream.

        @param[in] compr_mode The compression mode
        @throws std::invalid_argument if the compression mode is not supported
        @throws std::logic_error if the size does not fit in the return type
        */
        SEAL_NODISCARD inline std::streamoff save_size(
            compr_mode_type compr_mode = Serialization::compr_mode_default) const
        {
            std::size_t total_key_size = util::mul_safe(keys_.size(), sizeof(std::uint64_t)); // keys_dim2
            for (auto &key_dim1 : keys_)
            {
                for (auto &key_dim2 : key_dim1)
                {
                    total_key_size = util::add_safe(
                        total_key_size, util::safe_cast<std::size_t>(key_dim2.save_size(compr_mode_type::none)));
                }
            }

            std::size_t members_size = Serialization::ComprSizeEstimate(
                util::add_safe(
                    sizeof(parms_id_),
                    sizeof(std::uint64_t), // keys_dim1
                    total_key_size),
                compr_mode);

            return util::safe_cast<std::streamoff>(util::add_safe(sizeof(Serialization::SEALHeader), members_size));
        }

        /**
        Saves the KSwitchKeys instance to an output stream. The output is
        in binary format and not human-readable. The output stream must have
        the "binary" flag set.

        @param[out] stream The stream to save the KSwitchKeys to
        @param[in] compr_mode The desired compression mode
        @throws std::invalid_argument if the compression mode is not supported
        @throws std::logic_error if the data to be saved is invalid, or if
        compression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff save(
            std::ostream &stream, compr_mode_type compr_mode = Serialization::compr_mode_default) const
        {
            using namespace std::placeholders;
            return Serialization::Save(
                std::bind(&KSwitchKeys::save_members, this, _1), save_size(compr_mode_type::none), stream, compr_mode,
                false);
        }

        /**
        Loads a KSwitchKeys from an input stream overwriting the current KSwitchKeys.
        No checking of the validity of the KSwitchKeys data against encryption
        parameters is performed. This function should not be used unless the
        KSwitchKeys comes from a fully trusted source.

        @param[in] context The SEALContext
        @param[in] stream The stream to load the KSwitchKeys from
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff unsafe_load(const SEALContext &context, std::istream &stream)
        {
            using namespace std::placeholders;
            return Serialization::Load(std::bind(&KSwitchKeys::load_members, this, context, _1, _2), stream, false);
        }

        /**
        Loads a KSwitchKeys from an input stream overwriting the current KSwitchKeys.
        The loaded KSwitchKeys is verified to be valid for the given SEALContext.

        @param[in] context The SEALContext
        @param[in] stream The stream to load the KSwitchKeys from
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff load(const SEALContext &context, std::istream &stream)
        {
            KSwitchKeys new_keys;
            new_keys.pool_ = pool_;
            auto in_size = new_keys.unsafe_load(context, stream);
            if (!is_valid_for(new_keys, context))
            {
                throw std::logic_error("KSwitchKeys data is invalid");
            }
            std::swap(*this, new_keys);
            return in_size;
        }

        /**
        Saves the KSwitchKeys instance to a given memory location. The output is
        in binary format and not human-readable.

        @param[out] out The memory location to write the KSwitchKeys to
        @param[in] size The number of bytes available in the given memory location
        @param[in] compr_mode The desired compression mode
        @throws std::invalid_argument if out is null or if size is too small to
        contain a SEALHeader, or if the compression mode is not supported
        @throws std::logic_error if the data to be saved is invalid, or if
        compression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff save(
            seal_byte *out, std::size_t size, compr_mode_type compr_mode = Serialization::compr_mode_default) const
        {
            using namespace std::placeholders;
            return Serialization::Save(
                std::bind(&KSwitchKeys::save_members, this, _1), save_size(compr_mode_type::none), out, size,
                compr_mode, false);
        }

        /**
        Loads a KSwitchKeys from a given memory location overwriting the current
        KSwitchKeys. No checking of the validity of the KSwitchKeys data against
        encryption parameters is performed. This function should not be used
        unless the KSwitchKeys comes from a fully trusted source.

        @param[in] context The SEALContext
        @param[in] in The memory location to load the KSwitchKeys from
        @param[in] size The number of bytes available in the given memory location
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::invalid_argument if in is null or if size is too small to
        contain a SEALHeader
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff unsafe_load(const SEALContext &context, const seal_byte *in, std::size_t size)
        {
            using namespace std::placeholders;
            return Serialization::Load(std::bind(&KSwitchKeys::load_members, this, context, _1, _2), in, size, false);
        }

        /**
        Loads a KSwitchKeys from a given memory location overwriting the current
        KSwitchKeys. The loaded KSwitchKeys is verified to be valid for the given
        SEALContext.

        @param[in] context The SEALContext
        @param[in] in The memory location to load the KSwitchKeys from
        @param[in] size The number of bytes available in the given memory location
        @throws std::invalid_argument if the encryption parameters are not valid
        @throws std::invalid_argument if in is null or if size is too small to
        contain a SEALHeader
        @throws std::logic_error if the data cannot be loaded by this version of
        Microsoft SEAL, if the loaded data is invalid, or if decompression failed
        @throws std::runtime_error if I/O operations failed
        */
        inline std::streamoff load(const SEALContext &context, const seal_byte *in, std::size_t size)
        {
            KSwitchKeys new_keys;
            new_keys.pool_ = pool_;
            auto in_size = new_keys.unsafe_load(context, in, size);
            if (!is_valid_for(new_keys, context))
            {
                throw std::logic_error("KSwitchKeys data is invalid");
            }
            std::swap(*this, new_keys);
            return in_size;
        }

        /**
        Returns the currently used MemoryPoolHandle.
        */
        SEAL_NODISCARD inline MemoryPoolHandle pool() const noexcept
        {
            return pool_;
        }

    private:
        void save_members(std::ostream &stream) const;

        void load_members(const SEALContext &context, std::istream &stream, SEALVersion version);

        MemoryPoolHandle pool_ = MemoryManager::GetPool();

        parms_id_type parms_id_ = parms_id_zero;

        /**
        The vector of keyswitching keys.
        */
        std::vector<std::vector<PublicKey>> keys_{};
    };

seal/galoiskeys.h

GaloisKeys 类,继承自 KSwitchKeys

    /**
    Class to store Galois keys.

    @par Slot Rotations
    Galois keys are certain types of public keys that are needed to perform encrypted
    vector rotation operations on batched ciphertexts. Batched ciphertexts encrypt
    a 2-by-(N/2) matrix of modular integers in the BFV scheme, or an N/2-dimensional
    vector of complex numbers in the CKKS scheme, where N denotes the degree of the
    polynomial modulus. In the BFV scheme Galois keys can enable both cyclic rotations
    of the encrypted matrix rows, as well as row swaps (column rotations). In the CKKS
    scheme Galois keys can enable cyclic vector rotations, as well as a complex
    conjugation operation.


    @par Thread Safety
    In general, reading from GaloisKeys is thread-safe as long as no other thread is
    concurrently mutating it. This is due to the underlying data structure storing the
    Galois keys not being thread-safe.

    @see RelinKeys for the class that stores the relinearization keys.
    @see KeyGenerator for the class that generates the Galois keys.
    */
    class GaloisKeys : public KSwitchKeys
    {
    public:
        /**
        Returns the index of a Galois key in the backing KSwitchKeys instance that
        corresponds to the given Galois element, assuming that it exists in the
        backing KSwitchKeys.

        @param[in] galois_elt The Galois element
        @throws std::invalid_argument if galois_elt is not valid
        */
        SEAL_NODISCARD inline static std::size_t get_index(std::uint32_t galois_elt)
        {
            return util::GaloisTool::GetIndexFromElt(galois_elt);
        }

        /**
        Returns whether a Galois key corresponding to a given Galois element exists.

        @param[in] galois_elt The Galois element
        @throws std::invalid_argument if galois_elt is not valid
        */
        SEAL_NODISCARD inline bool has_key(std::uint32_t galois_elt) const
        {
            std::size_t index = get_index(galois_elt);
            return data().size() > index && !data()[index].empty();
        }

        /**
        Returns a const reference to a Galois key. The returned Galois key corresponds
        to the given Galois element.

        @param[in] galois_elt The Galois element
        @throws std::invalid_argument if the key corresponding to galois_elt does not exist
        */
        SEAL_NODISCARD inline const auto &key(std::uint32_t galois_elt) const
        {
            return KSwitchKeys::data(get_index(galois_elt));
        }
    };

seal/elinkeys.h

RelinKeys 类,继承自 KSwitchKeys

    /**
    Class to store relinearization keys.

    @par Relinearization
    Freshly encrypted ciphertexts have a size of 2, and multiplying ciphertexts
    of sizes K and L results in a ciphertext of size K+L-1. Unfortunately, this
    growth in size slows down further multiplications and increases noise growth.
    Relinearization is an operation that has no semantic meaning, but it reduces
    the size of ciphertexts back to 2. Microsoft SEAL can only relinearize size 3
    ciphertexts back to size 2, so if the ciphertexts grow larger than size 3,
    there is no way to reduce their size. Relinearization requires an instance of
    RelinKeys to be created by the secret key owner and to be shared with the
    evaluator. Note that plain multiplication is fundamentally different from
    normal multiplication and does not result in ciphertext size growth.

    @par When to Relinearize
    Typically, one should always relinearize after each multiplications. However,
    in some cases relinearization should be postponed as late as possible due to
    its computational cost. For example, suppose the computation involves several
    homomorphic multiplications followed by a sum of the results. In this case it
    makes sense to not relinearize each product, but instead add them first and
    only then relinearize the sum. This is particularly important when using the
    CKKS scheme, where relinearization is much more computationally costly than
    multiplications and additions.

    @par Thread Safety
    In general, reading from RelinKeys is thread-safe as long as no other thread
    is concurrently mutating it. This is due to the underlying data structure
    storing the relinearization keys not being thread-safe.

    @see GaloisKeys for the class that stores the Galois keys.
    @see KeyGenerator for the class that generates the relinearization keys.
    */
    class RelinKeys : public KSwitchKeys
    {
    public:
        /**
        Returns the index of a relinearization key in the backing KSwitchKeys
        instance that corresponds to the given secret key power, assuming that
        it exists in the backing KSwitchKeys.

        @param[in] key_power The power of the secret key
        @throws std::invalid_argument if key_power is less than 2
        */
        SEAL_NODISCARD inline static std::size_t get_index(std::size_t key_power)
        {
            if (key_power < 2)
            {
                throw std::invalid_argument("key_power cannot be less than 2");
            }
            return key_power - 2;
        }

        /**
        Returns whether a relinearization key corresponding to a given power of
        the secret key exists.

        @param[in] key_power The power of the secret key
        @throws std::invalid_argument if key_power is less than 2
        */
        SEAL_NODISCARD inline bool has_key(std::size_t key_power) const
        {
            std::size_t index = get_index(key_power);
            return data().size() > index && !data()[index].empty();
        }

        /**
        Returns a const reference to a relinearization key. The returned
        relinearization key corresponds to the given power of the secret key.

        @param[in] key_power The power of the secret key
        @throws std::invalid_argument if the key corresponding to key_power does not exist
        */
        SEAL_NODISCARD inline auto &key(std::size_t key_power) const
        {
            return KSwitchKeys::data(get_index(key_power));
        }
    };

seal/keygenerator.h

Generates matching secret key and public key. An existing KeyGenerator can
also at any time be used to generate relinearization keys and Galois keys.
Constructing a KeyGenerator requires only a SEALContext.

生成匹配的密钥和公钥。现有的KeyGenerator还可以在任何时候用于生成线性化密钥和伽罗瓦密钥。构造KeyGenerator只需要一个SEALContext。

KeyGenerator 类

保存了一个context 和一个 secretkey,私钥在构造函数中被初始化

    /**
    Generates matching secret key and public key. An existing KeyGenerator can
    also at any time be used to generate relinearization keys and Galois keys.
    Constructing a KeyGenerator requires only a SEALContext.

    @see EncryptionParameters for more details on encryption parameters.
    @see SecretKey for more details on secret key.
    @see PublicKey for more details on public key.
    @see RelinKeys for more details on relinearization keys.
    @see GaloisKeys for more details on Galois keys.
    */
    class KeyGenerator
    {
    public:
        /**
        Creates a KeyGenerator initialized with the specified SEALContext.

        @param[in] context The SEALContext
        @throws std::invalid_argument if the encryption parameters are not valid
        */
        KeyGenerator(const SEALContext &context);

        /**
        Creates an KeyGenerator instance initialized with the specified SEALContext
        and specified previously secret key. This can e.g. be used to increase
        the number of relinearization keys from what had earlier been generated,
        or to generate Galois keys in case they had not been generated earlier.


        @param[in] context The SEALContext
        @param[in] secret_key A previously generated secret key
        @throws std::invalid_argument if encryption parameters are not valid
        @throws std::invalid_argument if secret_key is not valid for encryption
        parameters
        */
        KeyGenerator(const SEALContext &context, const SecretKey &secret_key);

        /**
        Returns a const reference to the secret key.
        */
        SEAL_NODISCARD const SecretKey &secret_key() const;

        /**
        Generates a public key and stores the result in destination. Every time
        this function is called, a new public key will be generated.

        @param[out] destination The public key to overwrite with the generated
        public key
        */
        inline void create_public_key(PublicKey &destination) const
        {
            destination = generate_pk(false);
        }

        /**
        Generates and returns a public key as a serializable object. Every time
        this function is called, a new public key will be generated.

        Half of the key data is pseudo-randomly generated from a seed to reduce
        the object size. The resulting serializable object cannot be used
        directly and is meant to be serialized for the size reduction to have an
        impact.
        */
        SEAL_NODISCARD inline Serializable<PublicKey> create_public_key() const
        {
            return generate_pk(true);
        }

        /**
        Generates relinearization keys and stores the result in destination.
        Every time this function is called, new relinearization keys will be
        generated.

        @param[out] destination The relinearization keys to overwrite with the
        generated relinearization keys
        @throws std::logic_error if the encryption parameters do not support
        keyswitching
        */
        inline void create_relin_keys(RelinKeys &destination)
        {
            destination = create_relin_keys(1, false);
        }

        /**
        Generates and returns relinearization keys as a serializable object.
        Every time this function is called, new relinearization keys will be
        generated.

        Half of the key data is pseudo-randomly generated from a seed to reduce
        the object size. The resulting serializable object cannot be used
        directly and is meant to be serialized for the size reduction to have an
        impact.

        @throws std::logic_error if the encryption parameters do not support
        keyswitching
        */
        SEAL_NODISCARD inline Serializable<RelinKeys> create_relin_keys()
        {
            return create_relin_keys(1, true);
        }

        /**
        Generates Galois keys and stores the result in destination. Every time
        this function is called, new Galois keys will be generated.

        This function creates specific Galois keys that can be used to apply
        specific Galois automorphisms on encrypted data. The user needs to give
        as input a vector of Galois elements corresponding to the keys that are
        to be created.

        The Galois elements are odd integers in the interval [1, M-1], where
        M = 2*N, and N = poly_modulus_degree. Used with batching, a Galois element
        3^i % M corresponds to a cyclic row rotation i steps to the left, and
        a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation i
        steps to the right. The Galois element M-1 corresponds to a column rotation
        (row swap) in BFV, and complex conjugation in CKKS. In the polynomial view
        (not batching), a Galois automorphism by a Galois element p changes
        Enc(plain(x)) to Enc(plain(x^p)).

        @param[in] galois_elts The Galois elements for which to generate keys
        @param[out] destination The Galois keys to overwrite with the generated
        Galois keys
        @throws std::logic_error if the encryption parameters do not support
        keyswitching
        @throws std::invalid_argument if the Galois elements are not valid
        */
        inline void create_galois_keys(const std::vector<std::uint32_t> &galois_elts, GaloisKeys &destination)
        {
            destination = create_galois_keys(galois_elts, false);
        }

        /**
        Generates and returns Galois keys as a serializable object. Every time
        this function is called, new Galois keys will be generated.

        Half of the key data is pseudo-randomly generated from a seed to reduce
        the object size. The resulting serializable object cannot be used
        directly and is meant to be serialized for the size reduction to have an
        impact.

        This function creates specific Galois keys that can be used to apply
        specific Galois automorphisms on encrypted data. The user needs to give
        as input a vector of Galois elements corresponding to the keys that are
        to be created.

        The Galois elements are odd integers in the interval [1, M-1], where
        M = 2*N, and N = poly_modulus_degree. Used with batching, a Galois element
        3^i % M corresponds to a cyclic row rotation i steps to the left, and
        a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation i
        steps to the right. The Galois element M-1 corresponds to a column rotation
        (row swap) in BFV, and complex conjugation in CKKS. In the polynomial view
        (not batching), a Galois automorphism by a Galois element p changes
        Enc(plain(x)) to Enc(plain(x^p)).

        @param[in] galois_elts The Galois elements for which to generate keys
        @throws std::logic_error if the encryption parameters do not support
        keyswitching
        @throws std::invalid_argument if the Galois elements are not valid
        */
        SEAL_NODISCARD inline Serializable<GaloisKeys> create_galois_keys(const std::vector<std::uint32_t> &galois_elts)
        {
            return create_galois_keys(galois_elts, true);
        }

        /**
        Generates Galois keys and stores the result in destination. Every time
        this function is called, new Galois keys will be generated.

        The user needs to give as input a vector of desired Galois rotation step
        counts, where negative step counts correspond to rotations to the right
        and positive step counts correspond to rotations to the left. A step
        count of zero can be used to indicate a column rotation in the BFV scheme
        and complex conjugation in the CKKS scheme.

        @param[in] steps The rotation step counts for which to generate keys
        @param[out] destination The Galois keys to overwrite with the generated
        Galois keys
        @throws std::logic_error if the encryption parameters do not support
        batching and scheme is scheme_type::BFV
        @throws std::logic_error if the encryption parameters do not support
        keyswitching
        @throws std::invalid_argument if the step counts are not valid
        */
        inline void create_galois_keys(const std::vector<int> &steps, GaloisKeys &destination)
        {
            if (!context_.key_context_data()->qualifiers().using_batching)
            {
                throw std::logic_error("encryption parameters do not support batching");
            }
            create_galois_keys(context_.key_context_data()->galois_tool()->get_elts_from_steps(steps), destination);
        }

        /**
        Generates and returns Galois keys as a serializable object. Every time
        this function is called, new Galois keys will be generated.

        Half of the key data is pseudo-randomly generated from a seed to reduce
        the object size. The resulting serializable object cannot be used
        directly and is meant to be serialized for the size reduction to have an
        impact.

        The user needs to give as input a vector of desired Galois rotation step
        counts, where negative step counts correspond to rotations to the right
        and positive step counts correspond to rotations to the left. A step
        count of zero can be used to indicate a column rotation in the BFV scheme
        and complex conjugation in the CKKS scheme.

        @param[in] steps The rotation step counts for which to generate keys
        @throws std::logic_error if the encryption parameters do not support
        batching and scheme is scheme_type::BFV
        @throws std::logic_error if the encryption parameters do not support
        keyswitching
        @throws std::invalid_argument if the step counts are not valid
        */
        SEAL_NODISCARD inline Serializable<GaloisKeys> create_galois_keys(const std::vector<int> &steps)
        {
            if (!context_.key_context_data()->qualifiers().using_batching)
            {
                throw std::logic_error("encryption parameters do not support batching");
            }
            return create_galois_keys(context_.key_context_data()->galois_tool()->get_elts_from_steps(steps));
        }

        /**
        Generates Galois keys and stores the result in destination. Every time
        this function is called, new Galois keys will be generated.

        This function creates logarithmically many (in degree of the polynomial
        modulus) Galois keys that is sufficient to apply any Galois automorphism
        (e.g., rotations) on encrypted data. Most users will want to use this
        overload of the function.

        Precisely it generates 2*log(n)-1 number of Galois keys where n is the
        degree of the polynomial modulus. When used with batching, these keys
        support direct left and right rotations of power-of-2 steps of rows in BFV
        or vectors in CKKS and rotation of columns in BFV or conjugation in CKKS.

        @param[out] destination The Galois keys to overwrite with the generated
        Galois keys
        @throws std::logic_error if the encryption parameters do not support
        keyswitching
        */
        inline void create_galois_keys(GaloisKeys &destination)
        {
            create_galois_keys(context_.key_context_data()->galois_tool()->get_elts_all(), destination);
        }

        /**
        Generates and returns Galois keys as a serializable object. Every time
        this function is called, new Galois keys will be generated.

        Half of the key data is pseudo-randomly generated from a seed to reduce
        the object size. The resulting serializable object cannot be used
        directly and is meant to be serialized for the size reduction to have an
        impact.

        This function creates logarithmically many (in degree of the polynomial
        modulus) Galois keys that is sufficient to apply any Galois automorphism
        (e.g., rotations) on encrypted data. Most users will want to use this
        overload of the function.

        Precisely it generates 2*log(n)-1 number of Galois keys where n is the
        degree of the polynomial modulus. When used with batching, these keys
        support direct left and right rotations of power-of-2 steps of rows in BFV
        or vectors in CKKS and rotation of columns in BFV or conjugation in CKKS.

        @throws std::logic_error if the encryption parameters do not support
        keyswitching
        */
        SEAL_NODISCARD inline Serializable<GaloisKeys> create_galois_keys()
        {
            return create_galois_keys(context_.key_context_data()->galois_tool()->get_elts_all());
        }

        /**
        Enables access to private members of seal::KeyGenerator for SEAL_C.
        */
        struct KeyGeneratorPrivateHelper;

    private:
        KeyGenerator(const KeyGenerator &copy) = delete;

        KeyGenerator &operator=(const KeyGenerator &assign) = delete;

        KeyGenerator(KeyGenerator &&source) = delete;

        KeyGenerator &operator=(KeyGenerator &&assign) = delete;

        void compute_secret_key_array(const SEALContext::ContextData &context_data, std::size_t max_power);

        /**
        Generates new secret key.

        @param[in] is_initialized True if the secret key has already been
        initialized so that only the secret_key_array_ should be initialized, for
        example, if the secret key was provided in the constructor
        */
        void generate_sk(bool is_initialized = false);

        /**
        Generates new public key matching to existing secret key.
        */
        PublicKey generate_pk(bool save_seed) const;

        /**
        Generates new key switching keys for an array of new keys.
        */
        void generate_kswitch_keys(
            util::ConstPolyIter new_keys, std::size_t num_keys, KSwitchKeys &destination, bool save_seed = false);

        /**
        Generates one key switching key for a new key.
        */
        void generate_one_kswitch_key(
            util::ConstRNSIter new_key, std::vector<PublicKey> &destination, bool save_seed = false);

        /**
        Generates and returns the specified number of relinearization keys.

        @param[in] count The number of relinearization keys to generate
        @param[in] save_seed If true, save seed instead of a polynomial.
        @throws std::invalid_argument if count is zero or too large
        */
        RelinKeys create_relin_keys(std::size_t count, bool save_seed);

        /**
        Generates and returns Galois keys. This function creates specific Galois
        keys that can be used to apply specific Galois automorphisms on encrypted
        data. The user needs to give as input a vector of Galois elements
        corresponding to the keys that are to be created.

        The Galois elements are odd integers in the interval [1, M-1], where
        M = 2*N, and N = poly_modulus_degree. Used with batching, a Galois element
        3^i % M corresponds to a cyclic row rotation i steps to the left, and
        a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation i
        steps to the right. The Galois element M-1 corresponds to a column rotation
        (row swap) in BFV, and complex conjugation in CKKS. In the polynomial view
        (not batching), a Galois automorphism by a Galois element p changes
        Enc(plain(x)) to Enc(plain(x^p)).

        @param[in] galois_elts The Galois elements for which to generate keys
        @param[in] save_seed If true, replace second poly in Ciphertext with seed
        @throws std::invalid_argument if the Galois elements are not valid
        */
        GaloisKeys create_galois_keys(const std::vector<std::uint32_t> &galois_elts, bool save_seed);

        // We use a fresh memory pool with `clear_on_destruction' enabled.
        MemoryPoolHandle pool_ = MemoryManager::GetPool(mm_prof_opt::mm_force_new, true);

        SEALContext context_;

        SecretKey secret_key_;

        std::size_t secret_key_array_size_ = 0;

        util::Pointer<std::uint64_t> secret_key_array_;

        mutable util::ReaderWriterLocker secret_key_array_locker_;

        bool sk_generated_ = false;
    };
 类似资料: