SEAL中用CRT完成多項式編碼相關(SEAL/Polycrt.h 2.3.0)


終於還是要讀源碼了,終究擺脫不了數學的噩夢,先從讀懂他們的代碼開始。
文件原位置SEAL/Polycrt.h

介紹

提供CRT批處理功能。 如果多項式模數是 xN+1x^N+1,並且明文模數是素數 TT 使得 T1mod  2NT \equiv 1 \mod 2N ,則PolyCRTBuilder允許SEAL明文元素被視爲2×(N/2)2 \times (N/2) 的矩陣,在這種加密矩陣上執行的同態操作是應用係數(槽),爲可矢量化的計算啓用強大的SIMD功能。 此功能通常在同態加密文獻中稱爲“批處理”。

  • par數學背景
    從數學上講,如果poly_modulus是 xN+1x^N+1NN2​​2 的冪,plain_modulus是素數 TT,使得 2N2N 整除 T1T-1,則模TT的整數包含 一個 2N2N 的原始根,多項式XN+1X ^ N + 1分裂成nn個不同的線性因子,如XN+1=Xa1XaNmod  TX ^ N + 1 =(X-a_1)*\dots *(X-a_N)\mod T,其中常數a1ana_1,\dots ,a_n 都是不同的原始的第2N2N個整數的根在整數模TT中。中國剩餘定理(CRT)表明在這種情況下明文空間ZT[X]/(XN+1)Z_T [X] /(X ^ N + 1)NN同構(作爲代數)摺疊領域的直接產品ZTZ_T。同構很容易在兩個方向上明確計算,這就是這個類的作用。此外,擴張的伽羅瓦羣是(Z/2NZ)=Z/2Z×Z/(N/2)(Z / 2NZ)*〜= Z / 2Z×Z /(N / 2),其對原始根的作用很容易描述。由於批處理時隙與統一的原始根對應1對1,因此通過置換時隙在明文上應用Galois自同構。通過應用伽羅瓦羣的兩個循環子羣的生成器,我們可以有效地將明文視爲2乘N/2N / 2 矩陣,並且能夠實現循環行旋轉和列旋轉(行交換)。

  • par有效參數
    是否可以使用批處理取決於是否適當選擇了明文模數。 因此,要構造PolyCRTBuilder,用戶必須提供SEALContext的實例,以使其關聯的EncryptionParameterQualifiers對象將flags_set和enable_batching設置爲true。

  • par重載
    對於分解函數,我們提供了兩個有關操作期間所需分配中使用的內存池的重載。 在一次重載中,PolyCRTBuilder的本地內存池(用於存儲預計算結果和其他成員變量)用於此目的,而在另一個重載中,用戶可以提供要使用的MemoryPoolHandle。 這是爲了允許多個線程同時使用一個PolyCRTBuilder,而不會在操作期間發生的分配中遇到線程爭用。 例如,可以跨任意數量的線程共享一個PolyCRTBuilder,但是在每個線程中通過爲其提供一個線程本地MemoryPoolHandle來調用加密函數。 對於開發人員而言,瞭解其工作原理以避免不必要的性能瓶頸非常重要。

    @有關加密參數的詳細信息,請參閱EncryptionParameters。
    @see EncryptionParameterQualifiers瞭解有關參數限定符的更多信息。
    @see Evaluator用於旋轉加密矩陣的行和列。

overview

polycrtbuilder

構造函數

基本構造

PolyCRTBuilder(const SEALContext &context, const MemoryPoolHandle &pool = MemoryPoolHandle::Global());

創建PolyCRTBuilder。 通過SEALContext對象提供的加密參數必須支持批處理。 動態分配的成員變量是從給定的MemoryPoolHandle指向的內存池中分配的。 默認情況下,使用全局內存池。

     @param [in] context SEALContext
     @param [in] pool MemoryPoolHandle 指向有效的內存池
     如果加密參數對批處理無效,則@throws std :: invalid_argument
     如果池未初始化,則@throws std :: invalid_argument
    PolyCRTBuilder::PolyCRTBuilder(const SEALContext &context, const MemoryPoolHandle &pool) :
        pool_(pool), parms_(context.parms()),
        ntt_tables_(pool_),
        slots_(parms_.poly_modulus().coeff_count() - 1),
        qualifiers_(context.qualifiers())
    {
        int coeff_count = parms_.poly_modulus().coeff_count();

        // Verify parameters
        if (!qualifiers_.parameters_set)
        {
            throw invalid_argument("encryption parameters are not set correctly");
        }
        if (!qualifiers_.enable_batching)
        {
            throw invalid_argument("encryption parameters are not valid for batching");
        }
        if (!pool)
        {
            throw invalid_argument("pool is uninitialized");
        }

        // Set mod_ and polymod_
        mod_ = parms_.plain_modulus();
        polymod_ = PolyModulus(parms_.poly_modulus().pointer(), coeff_count, 
            parms_.poly_modulus().coeff_uint64_count());

        // Reserve space for all of the primitive roots
        roots_of_unity_ = allocate_uint(slots_, pool_);

        // Copy over NTT tables (switching to local pool)
        ntt_tables_ = context.plain_ntt_tables_;

        // Fill the vector of roots of unity with all distinct odd powers of generator.
        // These are all the primitive (2*slots_)-th roots of unity in integers modulo parms_.plain_modulus().
        populate_roots_of_unity_vector();

        // Populate matrix representation index map
        populate_matrix_reps_index_map();
    }

深拷貝

PolyCRTBuilder(const PolyCRTBuilder &copy);

創建給定PolyCRTBuilder的深拷貝。

     @param [in] copy 要複製的PolyCRTBuilder
PolyCRTBuilder::PolyCRTBuilder(const PolyCRTBuilder &copy) :
        pool_(copy.pool_), parms_(copy.parms_),
        ntt_tables_(copy.ntt_tables_),
        slots_(copy.slots_),
        qualifiers_(copy.qualifiers_)
    {
        int coeff_uint64_count = parms_.plain_modulus().uint64_count();

        // Allocate and copy over roots of unity
        roots_of_unity_ = allocate_poly(slots_, coeff_uint64_count, pool_);
        set_poly_poly(copy.roots_of_unity_.get(), slots_, coeff_uint64_count, roots_of_unity_.get());

        // Set mod_ and polymod_
        mod_ = parms_.plain_modulus();
        polymod_ = PolyModulus(parms_.poly_modulus().pointer(), parms_.poly_modulus().coeff_count(), 
            parms_.poly_modulus().coeff_uint64_count());
    }

移動

PolyCRTBuilder(PolyCRTBuilder &&source) = default;

通過移動給定的一個來創建一個新的PolyCRTBuilder。

     @param [in] source 要移動的PolyCRTBuilder

編碼(compose)

uint64_t

void compose(const std::vectorstd::uint64_t &values, Plaintext &destination);

從給定矩陣創建SEAL明文。 該函數將以明文模數爲模的給定整數矩陣“批處理”爲SEAL明文元素,並將結果存儲在目標參數中。 輸入向量的大小必須至多等於多項式模數的大小。 元素的前半部分代表矩陣的第一行,後半部分代表第二行。 矩陣中的大小最大等於明文模數,以表示有效的SEAL明文。

     @param [in] values 整數矩陣模數爲明文模數
     @param [out] destination 用結果覆蓋的明文多項式
     @throws std :: invalid_argument 如果值太大,拋出異常
void PolyCRTBuilder::compose(const vector<int64_t> &values_matrix, Plaintext &destination)
    {
        // Validate input parameters,驗證輸入的參數,如果矩陣的大小大於crtbuilder 的slot_counts,則報錯。
        if (values_matrix.size() > slots_)
        {
            throw logic_error("values_matrix size is too large");
        }
#ifdef SEAL_DEBUG
        for (auto v : values_matrix)
        {
            // Validate the i-th input
            if (v >= mod_.value())
            {
                throw invalid_argument("input value is larger than plain_modulus");
            }
        }
#endif
        // 當前輸入矩陣的大小
        int input_matrix_size = values_matrix.size();

        // Set destination to full size,將明文多項式的目標位置預先設置爲slot_counts        
        destination.resize(slots_);

        // First write the values to destination coefficients. Read in top row, then bottom row. 不全的數組數據用0補充。
        for (int i = 0; i < input_matrix_size; i++)
        {
            *(destination.pointer() + matrix_reps_index_map_[i]) = values_matrix[i];
        }        
        for (int i = input_matrix_size; i < slots_; i++)
        {
            *(destination.pointer() + matrix_reps_index_map_[i]) = 0;
        }

        // Transform destination using inverse of negacyclic NTT
        // Note: We already performed bit-reversal when reading in the matrix
        inverse_ntt_negacyclic_harvey(destination.pointer(), ntt_tables_);

int64_t

void compose(const std::vectorstd::int64_t &values, Plaintext &destination);

同上,只類型不同。
從給定矩陣創建SEAL明文。 該函數將以明文模數爲模的給定整數矩陣“批處理”爲SEAL明文元素,並將結果存儲在目標參數中。 輸入向量的大小必須至多等於多項式模數的大小。 元素的前半部分代表矩陣的第一行,後半部分代表第二行。 矩陣中的數字最多等於明文模數,以表示有效的SEAL明文。

     @param [in] values 整數矩陣模數爲明文模數
     @param [out] destination 用結果覆蓋的明文多項式
     @throws std :: invalid_argument 如果值太大
void PolyCRTBuilder::compose(const vector<int64_t> &values_matrix, Plaintext &destination)
    {
        // Validate input parameters
        if (values_matrix.size() > slots_)
        {
            throw logic_error("values_matrix size is too large");
        }

        uint64_t plain_modulus_div_two = mod_.value() >> 1;
#ifdef SEAL_DEBUG
        for (auto v : values_matrix)
        {
            // Validate the i-th input
            if (abs(v) > plain_modulus_div_two)
            {
                throw invalid_argument("input value is larger than plain_modulus");
            }
        }
#endif
        int input_matrix_size = values_matrix.size();

        // Set destination to full size
        destination.resize(slots_);

        // First write the values to destination coefficients. Read 
        // in top row, then bottom row.
        for (int i = 0; i < input_matrix_size; i++)
        {
            *(destination.pointer() + matrix_reps_index_map_[i]) = (values_matrix[i] < 0) ? 
                (mod_.value() + values_matrix[i]) : values_matrix[i];
        }
        for (int i = input_matrix_size; i < slots_; i++)
        {
            *(destination.pointer() + matrix_reps_index_map_[i]) = 0;
        }

        // Transform destination using inverse of negacyclic NTT
        // Note: We already performed bit-reversal when reading in the matrix
        inverse_ntt_negacyclic_harvey(destination.pointer(), ntt_tables_);
    }

plaintext

void PolyCRTBuilder::compose(Plaintext &plain, const MemoryPoolHandle &pool)

從給定矩陣創建SEAL明文。該函數將給定的整數模量的整數給定矩陣“批處理”爲準備加密的SEAL明文。矩陣作爲明文元素給出,其前 N/2N / 2 係數表示矩陣的第一行,後N/2N / 2係數表示第二行,其中 NN 表示多項式模數的程度。輸入明文必須具有小於多項式模數的遞減,並且係數小於明文模數,即它必須是加密參數的有效明文。進程中的動態內存分配是從給定MemoryPoolHandle指向的內存池中分配的。

    @param [in] plain整數矩陣模數爲明文模數
    @param [in] pool MemoryPoolHandle指向有效的內存池
    如果plain對加密參數無效,則@throws std :: invalid_argument
    如果池未初始化,則@throws std :: invalid_argument
    * /
 void PolyCRTBuilder::compose(Plaintext &plain, const MemoryPoolHandle &pool)
    {
        int coeff_count = parms_.poly_modulus().coeff_count();

        // Validate input parameters
        if (plain.coeff_count() > coeff_count || 
            (plain.coeff_count() == coeff_count && plain[coeff_count - 1] != 0))
        {
            throw invalid_argument("plain is not valid for encryption parameters");
        }
#ifdef SEAL_DEBUG
        if (plain.significant_coeff_count() >= coeff_count || !are_poly_coefficients_less_than(plain.pointer(),
            plain.coeff_count(), 1, parms_.plain_modulus().pointer(), parms_.plain_modulus().uint64_count()))
        {
            throw invalid_argument("plain is not valid for encryption parameters");
        }
#endif
        if (!pool)
        {
            throw invalid_argument("pool is uninitialized");
        }

        // We need to permute the coefficients of plain. To do this, we allocate 
        // temporary space.
        int input_plain_coeff_count = min(plain.coeff_count(), slots_);
        Pointer temp(allocate_uint(input_plain_coeff_count, pool));
        set_uint_uint(plain.pointer(), input_plain_coeff_count, temp.get());

        // Set plain to full slot count size.
        plain.resize(slots_);

        // First write the values to destination coefficients. Read 
        // in top row, then bottom row.
        for (int i = 0; i < input_plain_coeff_count; i++)
        {
            *(plain.pointer() + matrix_reps_index_map_[i]) = temp[i];
        }
        for (int i = input_plain_coeff_count; i < slots_; i++)
        {
            *(plain.pointer() + matrix_reps_index_map_[i]) = 0;
        }

        // Transform destination using inverse of negacyclic NTT
        // Note: We already performed bit-reversal when reading in the matrix
        inverse_ntt_negacyclic_harvey(plain.pointer(), ntt_tables_);
    }

解碼(decompose)

uint64_t

void PolyCRTBuilder::decompose(const Plaintext &plain, vector<uint64_t> &destination, const MemoryPoolHandle &pool)

iverse of compose。 該函數將給定SEAL明文“解”爲以明文模數爲模的整數矩陣,並將結果存儲在目標參數中。 輸入明文必須具有小於多項式模數的遞減,並且係數小於明文模數,即它必須是加密參數的有效明文。 進程中的動態內存分配是從給定MemoryPoolHandle指向的內存池中分配的。

     @param [in] plain要解開的明文多項式
     @param [out] destination要用槽的值覆蓋的向量
     @param [in] pool MemoryPoolHandle指向有效的內存池
     如果plain對加密參數無效,則@throws std :: invalid_argument
     如果池未初始化,則@throws std :: invalid_argument
void PolyCRTBuilder::decompose(const Plaintext &plain, vector<uint64_t> &destination, const MemoryPoolHandle &pool) 
    {
        int coeff_count = parms_.poly_modulus().coeff_count();

        // Validate input parameters
        if (plain.coeff_count() > coeff_count || 
            (plain.coeff_count() == coeff_count && plain[coeff_count - 1] != 0))
        {
            throw invalid_argument("plain is not valid for encryption parameters");
        }
#ifdef SEAL_DEBUG
        if (plain.significant_coeff_count() >= coeff_count || !are_poly_coefficients_less_than(plain.pointer(),
            plain.coeff_count(), 1, parms_.plain_modulus().pointer(), parms_.plain_modulus().uint64_count()))
        {
            throw invalid_argument("plain is not valid for encryption parameters");
        }
#endif
        if (!pool)
        {
            throw invalid_argument("pool is uninitialized");
        }

        // Set destination size
        destination.resize(slots_);

        // Never include the leading zero coefficient (if present)
        int plain_coeff_count = min(plain.coeff_count(), slots_);

        Pointer temp_dest(allocate_uint(slots_, pool));

        // Make a copy of poly
        set_uint_uint(plain.pointer(), plain_coeff_count, temp_dest.get());
        set_zero_uint(slots_ - plain_coeff_count, temp_dest.get() + plain_coeff_count);

        // Transform destination using negacyclic NTT.
        ntt_negacyclic_harvey(temp_dest.get(), ntt_tables_);

        // Read top row
        for (int i = 0; i < slots_; i++)
        {
            destination[i] = temp_dest[matrix_reps_index_map_[i]];
        }
    }

int64_t

void PolyCRTBuilder::decompose(const Plaintext &plain, vector<int64_t> &destination, const MemoryPoolHandle &pool)

同上

void PolyCRTBuilder::decompose(const Plaintext &plain, vector<int64_t> &destination,
        const MemoryPoolHandle &pool)
    {
        int coeff_count = parms_.poly_modulus().coeff_count();

        // Validate input parameters
        if (plain.coeff_count() > coeff_count || 
            (plain.coeff_count() == coeff_count && plain[coeff_count - 1] != 0))
        {
            throw invalid_argument("plain is not valid for encryption parameters");
        }
#ifdef SEAL_DEBUG
        if (plain.significant_coeff_count() >= coeff_count || !are_poly_coefficients_less_than(plain.pointer(),
            plain.coeff_count(), 1, parms_.plain_modulus().pointer(), parms_.plain_modulus().uint64_count()))
        {
            throw invalid_argument("plain is not valid for encryption parameters");
        }
#endif
        if (!pool)
        {
            throw invalid_argument("pool is uninitialized");
        }

        // Set destination size
        destination.resize(slots_);

        // Never include the leading zero coefficient (if present)
        int plain_coeff_count = min(plain.coeff_count(), slots_);

        Pointer temp_dest(allocate_uint(slots_, pool));

        // Make a copy of poly
        set_uint_uint(plain.pointer(), plain_coeff_count, temp_dest.get());
        set_zero_uint(slots_ - plain_coeff_count, temp_dest.get() + plain_coeff_count);

        // Transform destination using negacyclic NTT.
        ntt_negacyclic_harvey(temp_dest.get(), ntt_tables_);

        // Read top row, then bottom row
        uint64_t plain_modulus_div_two = mod_.value() >> 1;
        for (int i = 0; i < slots_; i++)
        {
            int64_t curr_value = temp_dest[matrix_reps_index_map_[i]];
            destination[i] = (curr_value > plain_modulus_div_two) ?
                (curr_value - mod_.value()) : curr_value;
        }
    }

plaintext

void PolyCRTBuilder::decompose(Plaintext &plain, const MemoryPoolHandle &pool)

void PolyCRTBuilder::decompose(Plaintext &plain, const MemoryPoolHandle &pool)
    {
        int coeff_count = parms_.poly_modulus().coeff_count();

        // Validate input parameters
        if (plain.coeff_count() > coeff_count || 
            (plain.coeff_count() == coeff_count && plain[coeff_count - 1] != 0))
        {
            throw invalid_argument("plain is not valid for encryption parameters");
        }
#ifdef SEAL_DEBUG
        if (plain.significant_coeff_count() >= coeff_count || !are_poly_coefficients_less_than(plain.pointer(),
            plain.coeff_count(), 1, parms_.plain_modulus().pointer(), parms_.plain_modulus().uint64_count()))
        {
            throw invalid_argument("plain is not valid for encryption parameters");
        }
#endif
        if (!pool)
        {
            throw invalid_argument("pool is uninitialized");
        }

        // Never include the leading zero coefficient (if present)
        int plain_coeff_count = min(plain.coeff_count(), slots_);

        // Allocate temporary space to store a wide copy of plain
        Pointer temp(allocate_uint(slots_, pool));

        // Make a copy of poly
        set_uint_uint(plain.pointer(), plain_coeff_count, temp.get());
        set_zero_uint(slots_ - plain_coeff_count, temp.get() + plain_coeff_count);

        // Transform destination using negacyclic NTT.
        ntt_negacyclic_harvey(temp.get(), ntt_tables_);

        // Set plain to full slot count size (note that all new coefficients are 
        // set to zero).
        plain.resize(slots_);

        // Read top row, then bottom row
        for (int i = 0; i < slots_; i++)
        {
            *(plain.pointer() + i) = temp[matrix_reps_index_map_[i]];
        }
    }

其他

void PolyCRTBuilder::populate_roots_of_unity_vector()

    void PolyCRTBuilder::populate_roots_of_unity_vector()
    {
        uint64_t generator_sq = multiply_uint_uint_mod(ntt_tables_.get_root(), ntt_tables_.get_root(), mod_);
        roots_of_unity_[0] = ntt_tables_.get_root();

        for (int i = 0; i < slots_ - 1; i++)
        {
            roots_of_unity_[i + 1] = multiply_uint_uint_mod(roots_of_unity_[i], generator_sq, mod_);
        }
    }

void PolyCRTBuilder::populate_matrix_reps_index_map()

    void PolyCRTBuilder::populate_matrix_reps_index_map()
    {
        int logn = get_power_of_two(slots_);
        uint32_t row_size = slots_ >> 1;
        matrix_reps_index_map_.resize(slots_);

        // Copy from the matrix to the value vectors 
        uint32_t gen = 3;
        uint32_t pos = 1;
        uint32_t m = slots_ << 1;
        for (uint32_t i = 0; i < row_size; i++)
        {
            // Position in normal bit order
            uint32_t index1 = (pos - 1) >> 1;
            uint32_t index2 = (m - pos - 1) >> 1;

            // Set the bit-reversed locations
            matrix_reps_index_map_[i] = util::reverse_bits(index1, logn);
            matrix_reps_index_map_[row_size | i] = util::reverse_bits(index2, logn);

            // Next primitive root
            pos *= gen;
            pos &= (m - 1);
        }
    }

inline int slot_count()

inline int slot_count() const
        {
            return slots_;
        }

inline void reverse_bits(std::uint64_t *input)

inline void reverse_bits(std::uint64_t *input)
        {
#ifdef SEAL_DEBUG
            if (input == nullptr)
            {
                throw std::invalid_argument("input cannot be null");
            }
#endif
            std::uint32_t n = parms_.poly_modulus().coeff_count() - 1;
            int logn = util::get_power_of_two(n);
            for (std::uint32_t i = 0; i < n; i++)
            {
                std::uint32_t reversed_i = util::reverse_bits(i, logn);
                if (i < reversed_i)
                {
                    std::swap(input[i], input[reversed_i]);
                }
            }
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章