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

2021SC@SDUSC

2021-10-31

第五周完成事项

工作内容

这周的主要工作是与李东晓弄清楚整体代码中的整数运算,我主要负责的是numth.h部分

整数运算

通过阅读陈智罡教授写过的博客http://blog.sciencenet.cn/blog-411071-617182.html,我对于整数运算在全同态加密的作用有了一定的认识。在公钥和密钥的生成、明文加密以及密文解密过程中都需要整数的运算。举个陈智罡教授博客中的一个例子,假设已知明文为m,通过加密算法得到m+2r+pq,想要对其解密就需要先通过模p运算把pq消去,模2运算把2r消去,最后剩下明文m。

代码分析

这次主要分析两个功能,一个naf,全称是non-adjacent form,中文翻译是非相邻形式;另外则是获取两个数的最大公约数。

        SEAL_NODISCARD inline std::vector<int> naf(int value)
        {
            std::vector<int> res;

            // Record the sign of the original value and compute abs
            bool sign = value < 0;
            value = std::abs(value);

            // Transform to non-adjacent form (NAF)
            for (int i = 0; value; i++)
            {
                int zi = (value & int(0x1)) ? 2 - (value & int(0x3)) : 0;
                value = (value - zi) >> 1;
                if (zi)
                {
                    res.push_back((sign ? -zi : zi) * (1 << i));
                }
            }

            return res;
        }

naf的作用是获取数字的非相邻形式,其中非零值不能相邻,举个例子,7的二进制表示可以有很多种,比如(0 1 1 1)= 4 + 2 + 1 = 7,(1 0 -1 1)= 8 - 2 + 1 = 7, (1 -1 1 1)= 8 - 4 + 2 + 1 = 7, (1 0 0 -1)= 8 - 1 = 7,但是只有最终表示(1 0 0 -1)是非相邻形式,非相邻形式也成为“规范有符号数字”表示。NAF的主要好处是该值的汉明权重将是最小的,可以加速乘法运算。

因为数的naf的结果是一段二进制串,所以使用向量进行存储。

            bool sign = value < 0;
            value = std::abs(value);

首先是判断输入数的正负性,符号不同最后会有相应的改变。如果是负数,会将结果二进制串的符号反转。

            for (int i = 0; value; i++)
            {
                int zi = (value & int(0x1)) ? 2 - (value & int(0x3)) : 0;
                value = (value - zi) >> 1;
                if (zi)
                {
                    res.push_back((sign ? -zi : zi) * (1 << i));
                }
            }

这个便是依次循环直至求出数的naf表示,sign ? -zi : zi便是判断正负,改变整体二进制串的符号。

        SEAL_NODISCARD inline std::uint64_t gcd(std::uint64_t x, std::uint64_t y)
        {
#ifdef SEAL_DEBUG
            if (x == 0)
            {
                throw std::invalid_argument("x cannot be zero");
            }
            if (y == 0)
            {
                throw std::invalid_argument("y cannot be zero");
            }
#endif
            if (x < y)
            {
                return gcd(y, x);
            }
            else if (y == 0)
            {
                return x;
            }
            else
            {
                std::uint64_t f = x % y;
                if (f == 0)
                {
                    return y;
                }
                else
                {
                    return gcd(y, f);
                }
            }
        }
        SEAL_NODISCARD inline auto xgcd(std::uint64_t x, std::uint64_t y)
            -> std::tuple<std::uint64_t, std::int64_t, std::int64_t>
        {
#ifdef SEAL_DEBUG
            if (x == 0)
            {
                throw std::invalid_argument("x cannot be zero");
            }
            if (y == 0)
            {
                throw std::invalid_argument("y cannot be zero");
            }
#endif
            std::int64_t prev_a = 1;
            std::int64_t a = 0;
            std::int64_t prev_b = 0;
            std::int64_t b = 1;

            while (y != 0)
            {
                std::int64_t q = util::safe_cast<std::int64_t>(x / y);
                std::int64_t temp = util::safe_cast<std::int64_t>(x % y);
                x = y;
                y = util::safe_cast<std::uint64_t>(temp);

                temp = a;
                a = util::sub_safe(prev_a, util::mul_safe(q, a));
                prev_a = temp;

                temp = b;
                b = util::sub_safe(prev_b, util::mul_safe(q, b));
                prev_b = temp;
            }
            return std::make_tuple(x, prev_a, prev_b);
        }

gcd是获取x与y的最大公约数。xgcd是相较于gcd的一个扩展,作用是返回(gcd,x,y),其中gcd是a和b的最大公约数。数字x,y使得gcd = ax + by

#ifdef SEAL_DEBUG
            if (x == 0)
            {
                throw std::invalid_argument("x cannot be zero");
            }
            if (y == 0)
            {
                throw std::invalid_argument("y cannot be zero");
            }

其中上述代码是gcd和xgcd里面通用的代码,主要内容是判断输入的x和y是否为0,x和y非零是通过数学求法——辗转相除法得知的,这个算法也是上述gcd算法的核心思想,这里我简单介绍一下辗转相除法。辗转相除法, 又名欧几里德算法,是求最大公约数的一种方法。它的具体做法是:用较小数除较大数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。

            if (x < y)
            {
                return gcd(y, x);
            }
            else if (y == 0)
            {
                return x;
            }
            else
            {
                std::uint64_t f = x % y;
                if (f == 0)
                {
                    return y;
                }
                else
                {
                    return gcd(y, f);
                }
            }

从gcd算法的核心内容可以得知,使用的是辗转相除法,如果x < y,则gcd(y ,x),因为算法要求x > y,如果y == 0,则算法递归结束返回x,剩下的情况便是x模y得余数,判断是结束递归还是继续递归。

总结

这周完成内容比较少,主要时间去写两篇3000字的认识实习报告了,下周会加快进度的。

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值