SEAL全同态加密开源库(四) NTT源码解析

SEAL全同态加密开源库(四) NTT源码解析

2021SC@SDUSC

2021-10-27

前言

这是SEAL开源库代码分析报告第四篇,本篇将首先照例补充一些理论知识,然后本篇将继续上一篇的介绍,重点分析SEAL对于NTT算法的实现代码。由于老师讲过,NTT是同态加密的核心基础算法,因此有仔细分析的必要。

ntt.h源码分析

首先是Arithmetic类,其包含两个参数two_times_modulus和two_times_modulus,二次系数。其中包含了一些构造函数,以及一些完成多项式算术操作的函数:

inline std::uint64_t add(const std::uint64_t &a, const std::uint64_t &b) const
            {
                return a + b;
            }

            inline std::uint64_t sub(const std::uint64_t &a, const std::uint64_t &b) const
            {
                return a + two_times_modulus_ - b;
            }

            inline std::uint64_t mul_root(const std::uint64_t &a, const MultiplyUIntModOperand &r) const
            {
                return multiply_uint_mod_lazy(a, r, modulus_);
            }

            inline std::uint64_t mul_scalar(const std::uint64_t &a, const MultiplyUIntModOperand &s) const
            {
                return multiply_uint_mod_lazy(a, s, modulus_);
            }

            inline MultiplyUIntModOperand mul_root_scalar(
                const MultiplyUIntModOperand &r, const MultiplyUIntModOperand &s) const
            {
                MultiplyUIntModOperand result;
                result.set(multiply_uint_mod(r.operand, s, modulus_), modulus_);
                return result;
            }

            inline std::uint64_t guard(const std::uint64_t &a) const
            {
                return SEAL_COND_SELECT(a >= two_times_modulus_, a - two_times_modulus_, a);
            }

然后是NTTTables类,也即NTT表。构造函数自不必多说,剩下的多是get函数,这里我们有必要对其所包含的属性逐一分析:

inv_degree_modulo_:coeff_count _ 模模数 _ 的倒数

root_powers_:按位反转顺序保存根的 1~(n-1) 次幂,0 次幂未设置

inv_root_powers_:以加扰顺序保存 inv_root_ 的 1~(n-1)-th 次幂,0 次幂未设置

CreateNTTTables函数,分配并构造一个 NTTTable 数组,每个数组具有不同的模数。如果模数为空,模数不支持 NTT,coeff_count_power 无效,或池未初始化。

void CreateNTTTables(
            int coeff_count_power, const std::vector<Modulus> &modulus, Pointer<NTTTables> &tables,
            MemoryPoolHandle pool);

然后我们这里跳转到NTT.CPP文件里的NTTTablesCreateIter类,迭代器。

LegacyInputIterator 允许引用等于 value_type,因此我们可以动态构造返回对象并按值返回。摘抄部分源码如下:

class NTTTablesCreateIter
        {
        public:
            using value_type = NTTTables;
            using pointer = void;
            using reference = value_type;
            using difference_type = ptrdiff_t;
            using iterator_category = input_iterator_tag;
        // 需要复制和移动构造函数和赋值
            NTTTablesCreateIter(const NTTTablesCreateIter &copy) = default;

            NTTTablesCreateIter(NTTTablesCreateIter &&source) = default;

            NTTTablesCreateIter &operator=(const NTTTablesCreateIter &assign) = default;

            NTTTablesCreateIter &operator=(NTTTablesCreateIter &&assign) = default;

            // 取消引用创建 NTTTables 并按值返回
            inline value_type operator*() const
            {
                return { coeff_count_power_, modulus_[index_], pool_ };
            }

            // 预增
            inline NTTTablesCreateIter &operator++() noexcept
            {
                index_++;
                return *this;
            }

            // 后增
            inline NTTTablesCreateIter operator++(int) noexcept
            {
                NTTTablesCreateIter result(*this);
                index_++;
                return result;
            }

            // 必须是 EqualityComparable
            inline bool operator==(const NTTTablesCreateIter &compare) const noexcept
            {
                return (compare.index_ == index_) && (coeff_count_power_ == compare.coeff_count_power_);
            }

            inline bool operator!=(const NTTTablesCreateIter &compare) const noexcept
            {
                return !operator==(compare);
            }

            // 必须定义箭头运算符
            value_type operator->() const
            {
                return **this;
            }

综上,我们在ntt.cpp类中,对头文件的创建NTT表函数进行了实现,代码如下:

void CreateNTTTables(
            int coeff_count_power, const vector<Modulus> &modulus, Pointer<NTTTables> &tables, MemoryPoolHandle pool)
        {
            if (!pool)
            {
                throw invalid_argument("pool is uninitialized");
            }
            if (!modulus.size())
            {
                throw invalid_argument("invalid modulus");
            }
            // coeff_count_power 和模数将通过“allocate”进行验证

            NTTTablesCreateIter iter(coeff_count_power, modulus, pool);
            tables = allocate(iter, modulus.size(), pool);
        }

SEAL中使用NTT

原文如下:

With parameter sets that support the Number Theoretic Transform (NTT) (see Section 8.5 and Section 8.6), Evaluator::multiply_plain works by first applying the Number Theoretic Transform (NTT) to both the input ciphertext, and the input plaintext, then performing a dyadic product of the transformed polynomials, and finally transforming the resulting ciphertext back. In cases where the same input plaintext or ciphertext needs to be used repeatedly for several different plain multiplications, it does not make sense to repeat the transform every single time. Instead, SEAL allows plaintexts and the ciphertexts to be NTT transformed at any time using the functions Evaluator::transform_to_ntt. Ciphertexts also can be transformed back from NTT using Evaluator::transform_from_ntt. Given a ciphertext and plaintext, both in NTT transformed form, the user can call Evaluator::multiply_plain_ntt to perform a very fast plain multiplication operation. The result will still be in NTT transformed form, and can be transformed back with Evaluator::transform_from_ntt.

尝试翻译后如下:

使用支持数论变换 (NTT) 的参数集(参见第 8.5 节和第 8.6 节),Evaluator::multiply_plain 首先将数论变换 (NTT) 应用于输入密文和输入明文,然后执行变换多项式的二元乘积,最后将得到的密文变换回来。在相同的输入明文或密文需要重复用于几个不同的明文乘法的情况下,每次都重复变换是没有意义的。相反,SEAL 允许使用函数 Evaluator::transform_to_ntt 随时对明文和密文进行 NTT 转换。密文也可以使用 Evaluator::transform_from_ntt 从 NTT 转换回来。给定密文和明文,都是 NTT 转换形式,用户可以调用 Evaluator::multiply_plain_ntt 来执行非常快速的普通乘法运算。结果仍然是 NTT 转换形式,并且可以用 Evaluator::transform_from_ntt 转换回来。

后记

以上是ntt.cpp/h的代码分析。至于上面提到的ntt.cpp/h和其他模块的配合,详见后续推出的源码分析报告。

猜你喜欢

转载自blog.csdn.net/ldxcsdn/article/details/120944126