2021SC@SDUSC
2021-11-07
第六周完成事项
工作内容
这周的主要工作是与李东晓继续分析整体代码中的整数运算。
知识补充
质数
质数,又称素数,指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数(也可定义为只有1与该数本身两个正因数的数)。大于1的自然数若不是素数,则称之为合数(也称为合成数)。例如,5是个素数,因为其正约数只有1与5。7是个素数,因为其正约数只有1与7。而4则是个合数,因为除了1与4外,2也是其正约数。6也是个合数,因为除了1与6外,2与3也是其正约数。算术基本定理确立了素数于数论里的核心地位:任何大于1的整数均可被表示成一串唯一素数之乘积。为了确保该定理的唯一性,1被定义为不是素数,因为在因式分解中可以有任意多个1(如3、1×3、1×1×3等都是3的有效约数分解)。
共轭类
数学上,特别是在群论中,群的元素可以分割成共轭类(Conjugacy class);同一个共轭类的元素有很多共同的属性,而且研究非交换群的共轭类可以看出很多关于它们的结构的重要特征。对于交换群,这个概念是平凡的,因为每个类就是一个单元素集合
在同一个共轭类上取常值的函数称为类函数。
代码分析
SEAL_NODISCARD inline bool are_coprime(std::uint64_t x, std::uint64_t y) noexcept
{
return !(gcd(x, y) > 1);
}
函数are_coprime
根据字面意思是判断两个数是否互为质数。
如果两个数互为质数,则返回true;如果不是质数,则返回false。内部判断是通过之前讲过的寻找最大公约数的函数gcd
实现的,如果两个数存在最大公约数,则值一定大于1,gcd(x, y) > 1
为true,取反为false,如果存在最大公约数,说明两个数不是互为质数。
SEAL_NODISCARD std::vector<std::uint64_t> multiplicative_orders(
std::vector<std::uint64_t> conjugate_classes, std::uint64_t modulus);
SEAL_NODISCARD std::vector<std::uint64_t> conjugate_classes(
std::uint64_t modulus, std::uint64_t subgroup_generator);
函数multiplicative_orders
是通过输入共轭类和模数生成并返回乘法的顺序;函数conjugate_classes
则是通过模数和子群生成器得到群的共轭类。
因为获取乘法顺序需要用到共轭类,这里先介绍一下如何通过模数和子群生成器得到共轭类。
vector<uint64_t> classes{};
for (uint64_t i = 0; i < modulus; i++)
{
if (gcd(i, modulus) > 1)
{
classes.push_back(0);
}
else
{
classes.push_back(i);
}
}
首先对于共轭类进行了初始化,将与模数互为质数的值放入共轭类。
for (uint64_t i = 0; i < modulus; i++)
{
if (classes[static_cast<size_t>(i)] == 0)
{
continue;
}
if (classes[static_cast<size_t>(i)] < i)
{
// i is not a pivot, updated its pivot
classes[static_cast<size_t>(i)] = classes[static_cast<size_t>(classes[static_cast<size_t>(i)])];
continue;
}
// If i is a pivot, update other pivots to point to it
uint64_t j = (i * subgroup_generator) % modulus;
while (classes[static_cast<size_t>(j)] != i)
{
// Merge the equivalence classes of j and i
// Note: if classes[j] != j then classes[j] will be updated later,
// when we get to i = j and use the code for "i not pivot".
classes[static_cast<size_t>(classes[static_cast<size_t>(j)])] = i;
j = (j * subgroup_generator) % modulus;
}
}
然后开始迭代更新共轭类中的数值。先判断该位置是否为零,如果为零,说明该位置和模数不互为质数,直接continue
。然后判断共轭类第i个位置的值是否为i,如果不是,说明i不是一个支点,这里对于支点的定义通过后面的代码可以简单理解为对应位置的数为本身。剩下的可能性就是i是一个支点,然后通过子群生成器和模数构建一个j,以i为支点迭代j对应位置的值。最后返回共轭类。
然后分析函数multiplicative_orders
的主要代码。
for (uint64_t i = 2; i < modulus; i++)
{
if (conjugate_classes[static_cast<size_t>(i)] <= 1)
{
orders.push_back(conjugate_classes[static_cast<size_t>(i)]);
continue;
}
if (conjugate_classes[static_cast<size_t>(i)] < i)
{
orders.push_back(orders[static_cast<size_t>(conjugate_classes[static_cast<size_t>(i)])]);
continue;
}
uint64_t j = (i * i) % modulus;
uint64_t order = 2;
while (conjugate_classes[static_cast<size_t>(j)] != 1)
{
j = (j * i) % modulus;
order++;
}
orders.push_back(order);
}
orders
就是我们最后返回的乘法顺序。
首先判断所在位置的共轭类是否小于等于1,如果是直接将i位置对应的共轭类放入顺序。然后判断对应的位置是否小于i,这里说明了之前分析过的内容,i不是一个支点,然后就将以i位置共轭类为位置共轭类放入顺序,最后就是i是一个支点的情况,这时候就通过模数生成一个j,依次遍历,直到j位置对应的共轭类不等于1的时候,将order
放入顺序。最后返回顺序。
总结
通过两周的学习,逐渐掌握了整数运算的大致内容。也通过阅读了大量的文章,知道了整数运算对于整个全同态加密算法的作用。
最后,感谢孔老师的指导,感谢戴老师和其他审核老师的阅读!