软件工程与应用第四篇报告

2021SC@SDUSC

2021-10-24

第四周完成事项

工作分工

由于上周的代码难度比较大,所以这周的工作承接上周,不在布置新的工作。

代码分析

上周的重点主要是了解RLWE(带有错误的环运算)对于SEAL全同态加密算法的作用,对于代码的整体结构只是进行了初步分析,本周将详细的解读代码的细节内容。

首先便是对于生成多项式并保存在余数空间的代码的分析,这里举的是生成统一的三元多项式的例子。

void sample_poly_ternary(
    shared_ptr<UniformRandomGenerator> prng, const EncryptionParameters &parms, uint64_t *destination)
{
    auto coeff_modulus = parms.coeff_modulus();
    size_t coeff_modulus_size = coeff_modulus.size();
    size_t coeff_count = parms.poly_modulus_degree();

    RandomToStandardAdapter engine(prng);
    uniform_int_distribution<uint64_t> dist(0, 2);

    SEAL_ITERATE(iter(destination), coeff_count, [&](auto &I) {
        uint64_t rand = dist(engine);
        uint64_t flag = static_cast<uint64_t>(-static_cast<int64_t>(rand == 0));
        SEAL_ITERATE(
            iter(StrideIter<uint64_t *>(&I, coeff_count), coeff_modulus), coeff_modulus_size,
            [&](auto J) { *get<0>(J) = rand + (flag & get<1>(J).value()) - 1;         });
    });
}

之前的代码分析仅仅是对每个过程都干了什么进行了基础介绍,这里将具体展开每个部分的作用。parms.coeff_modulus()获取的coeff_modulus为当前设置的系数模数参量;parms.poly_modulus_degree()获取的是多项式模参数的次数。这些参数的作用都是为了多项式的产生。

RandomToStandardAdapter engine(prng);目的是获取C++当中随机数生成的随机源,为了后续遍历的时候生成有效随机数uint64_t rand = dist(engine);

uniform_int_distribution<uint64_t> dist(0, 2);生成指定范围随机数的变量。

SEAL_ITERATE(iter(destination), coeff_count, [&](auto &I)遍历器,根据目标多项式的大小依次进行遍历。


然后是对公钥生成的代码详细分析

    void encrypt_zero_asymmetric(
        const PublicKey &public_key, const SEALContext &context, parms_id_type parms_id, bool is_ntt_form,Ciphertext &destination)
    {
#ifdef SEAL_DEBUG
        if (!is_valid_for(public_key, context))
        {
            throw invalid_argument("public key is not valid for the encryption parameters");
        }
#endif
        // We use a fresh memory pool with `clear_on_destruction' enabled
        MemoryPoolHandle pool = MemoryManager::GetPool(mm_prof_opt::mm_force_new, true);

        auto &context_data = *context.get_context_data(parms_id);
        auto &parms = context_data.parms();
        auto &coeff_modulus = parms.coeff_modulus();
        size_t coeff_modulus_size = coeff_modulus.size();
        size_t coeff_count = parms.poly_modulus_degree();
        auto ntt_tables = context_data.small_ntt_tables();
        size_t encrypted_size = public_key.data().size();

        // Make destination have right size and parms_id
        // Ciphertext (c_0,c_1, ...)
        destination.resize(context, parms_id, encrypted_size);
        destination.is_ntt_form() = is_ntt_form;
        destination.scale() = 1.0;

        // c[j] = public_key[j] * u + e[j] where e[j] <-- chi, u <-- R_3

        // Create a PRNG; u and the noise/error share the same PRNG
        auto prng = parms.random_generator()->create();

        // Generate u <-- R_3
        auto u(allocate_poly(coeff_count, coeff_modulus_size, pool));
        sample_poly_ternary(prng, parms, u.get());

        // c[j] = u * public_key[j]
        for (size_t i = 0; i < coeff_modulus_size; i++)
        {
            ntt_negacyclic_harvey(u.get() + i * coeff_count, ntt_tables[i]);
            for (size_t j = 0; j < encrypted_size; j++)
            {
                dyadic_product_coeffmod(
                u.get() + i * coeff_count, public_key.data().data(j) + i * coeff_count, coeff_count,coeff_modulus[i], destination.data(j) + i * coeff_count);

                // Addition with e_0, e_1 is in non-NTT form
                if (!is_ntt_form)
                {
                    inverse_ntt_negacyclic_harvey(destination.data(j) + i * coeff_count, ntt_tables[i]);
                }
            }
        }

        // Generate e_j <-- chi
        // c[j] = public_key[j] * u + e[j]
        for (size_t j = 0; j < encrypted_size; j++)
        {
            SEAL_NOISE_SAMPLER(prng, parms, u.get());
            for (size_t i = 0; i < coeff_modulus_size; i++)
            {
                // Addition with e_0, e_1 is in NTT form
                if (is_ntt_form)
                {
                    ntt_negacyclic_harvey(u.get() + i * coeff_count, ntt_tables[i]);
                }
                add_poly_coeffmod(
                    u.get() + i * coeff_count, destination.data(j) + i * coeff_count, coeff_count, coeff_modulus[i],destination.data(j) + i * coeff_count);
            }
        }
    }

首先是判断是否bug就不再过多讲解了。

第一步肯定是在内存池开辟一片空间,用于结果的存储,因为在内存的运算速度会更快。

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

        auto &context_data = *context.get_context_data(parms_id);
        auto &parms = context_data.parms();
        auto &coeff_modulus = parms.coeff_modulus();
        size_t coeff_modulus_size = coeff_modulus.size();
        size_t coeff_count = parms.poly_modulus_degree();
        auto ntt_tables = context_data.small_ntt_tables();
        size_t encrypted_size = public_key.data().size();

第二步根据传进来的参数更新一下目标密文的大小与编号。

        // Make destination have right size and parms_id
        // Ciphertext (c_0,c_1, ...)
        destination.resize(context, parms_id, encrypted_size);
        destination.is_ntt_form() = is_ntt_form;
        destination.scale() = 1.0;

第三步生成一个prng,这时候我们可以回去看生成统一三元多项式的代码,里面也有shared_ptr<UniformRandomGenerator> prng以及RandomToStandardAdapter engine(prng);,便可以明白prng的作用,在理想状态下是不存在噪声与错误的,但是现实生活中常常会有各种各样的问题影响我们实验的结果,所以这里生成一个随机数的随机源,后面用来生成噪声,表示我们日常生活中的一般状况。

        // c[j] = public_key[j] * u + e[j] where e[j] <-- chi, u <-- R_3

        // Create a PRNG; u and the noise/error share the same PRNG
        auto prng = parms.random_generator()->create();

第四步是调用之前定义的生成统一的三元多项式的函数生成三元多项式,这里同时说明了多项式和噪声拥有统一的随机源,保证了结果的一致性。

        // Generate u <-- R_3
        auto u(allocate_poly(coeff_count, coeff_modulus_size, pool));
        sample_poly_ternary(prng, parms, u.get());

第五步便是根据系数模数的大小以及加密的大小进行双重循环生成目标密文。

        // c[j] = u * public_key[j]
        for (size_t i = 0; i < coeff_modulus_size; i++)
        {
            ntt_negacyclic_harvey(u.get() + i * coeff_count, ntt_tables[i]);
            for (size_t j = 0; j < encrypted_size; j++)
            {
                dyadic_product_coeffmod(
                u.get() + i * coeff_count, public_key.data().data(j) + i * coeff_count, coeff_count,coeff_modulus[i], destination.data(j) + i * coeff_count);

                // Addition with e_0, e_1 is in non-NTT form
                if (!is_ntt_form)
                {
                    inverse_ntt_negacyclic_harvey(destination.data(j) + i * coeff_count, ntt_tables[i]);
                }
            }
        }
        // Generate e_j <-- chi
        // c[j] = public_key[j] * u + e[j]
        for (size_t j = 0; j < encrypted_size; j++)
        {
            SEAL_NOISE_SAMPLER(prng, parms, u.get());
            for (size_t i = 0; i < coeff_modulus_size; i++)
            {
                // Addition with e_0, e_1 is in NTT form
                if (is_ntt_form)
                {
                    ntt_negacyclic_harvey(u.get() + i * coeff_count, ntt_tables[i]);
                }
                add_poly_coeffmod(
                    u.get() + i * coeff_count, destination.data(j) + i * coeff_count, coeff_count, coeff_modulus[i],destination.data(j) + i * coeff_count);
            }
        }

总结

第四周由于机器学习实验导致事件比较匆忙,所以没有来的及布置新的内容。正好上次的代码没有进行深度分析,可以将功补过了。

下次一定会提前做好工作分工,做好组长的职责。

最后,感谢孔老师的指导,感谢戴老师和其他审核老师的阅读!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值