注:本节可参考国内《信息安全数学基础》《初等数论》《抽象代数》等相关内容(即如果学习过以上课程,下面内容可以跳过)。
# 模运算(Modular Arithmetic)
在计算机的一些领域(如密码学),我们通常希望处理一串范围较小的数字。这时,模运算就起到了巨大的作用,它能将数压缩到一个较小的范围{0,1,⋯,N−1},从而简化大量运算。
在生活中,最常见的模运算例子就是时钟。时钟以12小时为一循环(如果以24小时制计算则为24小时一循环),因而我们能够轻松计算当前时刻若干小时后的时刻。
用数学语言描述的话,我们可以定义x(modm):=r,其中r为x除以m得到的余数。即:
x(modm)≡r⟺x=mq+r(0≤r≤m−1,q∈Z)
# 计算法则(加法,减法与乘法)
- 在计算x+y(modm)时,我们可以先计算x(modm)和y(modm),再将二者相加取模(这很容易证明)。同理,x−y(modm)也等于(x(modm)−y(modm))(modm)。
- 在乘法运算上,这一法则的效果更明显:xy(modm)=(x(modm))×(y(modm))(modm),借助这一公式,计算的规模可以大大减小。
# 集合表示(Set representation)
- 下面我们换个视角分析模运算。对于任意整数m与x,y,如果m整除x−y,则称x与y对m同余(congruent modulo m),即:
x≡y(modm)⟺m∣(x−y)
- 显然,在这个式子中,x与y除以m得到的余数相同,故上述式子也可记为:
x≡y(modm)⟺x(modm)=y(modm)
- 于是我们可以将所有对m同余的数组成一个集合(如{⋯,−m,0,m,2m,⋯},{⋯,−m+1,1,m+1,2m+1,⋯}等),一共可以组成m个集合。这些集合可以覆盖所有整数,也被称为模m的剩余类(residue classes mod m)。
- 通过建立这些集合,我们就可以理解上述模运算法则的原理。由于每个集合里的所有元素均相互同余,所以我们可以将运算的数转化到{0,1,⋯,m−1}这个范围内。
- 下面再用数学语言将这一命题进行阐述(可以直接用定义证明,故证明过程省略):
如果a≡c(modm)且b≡d(modm),那么a±b≡c±d(modm),同时a⋅b≡c⋅d(modm)。
- 注意到我们这里没有涉及到除法运算,这将在后面被讨论。
# 指数运算
- 在密码学中,指数运算也是一种重要的运算。那么,对于xy(x,y均为自然数),如何求它对m(m>1)的模呢?一种朴素的方法是依次计算x(modm),x2(modm),⋯一直到xy(modm),但这样效率太低(如果用程序实现时间复杂度可达O(2y))。
- 为了优化这一运算,我们可以使用下述“重复平方(repeated squaring)”技巧:
- 设计递归函数
mod_exp(x,y,m),返回值为xy(modm);
- 如果y=0,则返回
1(x0≡1(modm));
- 如果y=0,设
z=mod_exp(x,y//2,m)(z=x⌊2y⌋(modm));
- 如果y为偶数,则返回z2(modm);
- 如果y为奇数,则返回xz2(modm)。
- 这样算法的时间复杂度就降到了O(logy)(具体关于算法时间复杂度的知识可参见CS61B)。
# 双射(Bijecions)
- 在介绍除法运算前,先做一个铺垫。这里我们回顾一下高等数学中映射的概念:
- 映射(mapping):设X,Y是两个给定的集合,若按照某种规则f,使得X中的每一个元素,都可以在Y中找到唯一的元素与之对应,则称f是集合X到集合Y的一个映射。
- 单射(one-to-one):设f是集合X到集合Y的一个映射,若f的逆像也具有唯一性,即对X中的任意两个不同元素x1=x2,也满足f(x1)=f(x2)(也可表述为f(x1)=f(x2)⟹x1=x2),则f为单射。
- 满射(onto):如果∀y∈Y,∃x∈X满足f(x)=y,则称f为满射。
- 双射:如果f既是单射又是满射,那么f就是双射。
- 利用这些概念,我们考虑以下函数(均将集合{0,1,⋯,m−1}映射到自身):
f(x)≡x+1(modm)
g(x)≡2m(modm)
- 可以发现,映射f是双射(集合中的每一个y,都存在唯一原像y−1);而映射g只有当m是奇数时才是双射({0,1,⋯,m−1}映射到{0,2,⋯,m,1,3,⋯,m−1}),当m为偶数时既不是单射也不是满射。
- 另外关于双射,有以下定理:
- 对于一个有限集合A,如果映射f:A→A存在对应的逆映射g:A→A满足g(f(x))=x,则f为双射。
# 逆(Inverses)
- 之前我们进行减法模运算时,注意到−b≡m−b(modm),所以加法模运算很容易拓展到减法模运算。
- 然而想通过乘法模运算推导出除法模运算就困难一些。在实数域上,我们知道除以x等价于乘以x1。相应的,计算xa(modm),就需要找到y,使得x⋅y≡1(modm),那么就可以将问题转化为a⋅y(modm)。这里y也被称为x模m的乘法逆(multiplicative inverse)。
- 那么,能否保证y一定存在?y又是否唯一呢?我们先举一些例子:令x=9,m=17,则当y=2时,xy=18≡1(mod17),即2是9模17的乘法逆;而当x=8,m=12时,取y={1,2,3,⋯},xy(modm)={8,4,0,8,4,⋯}循环,无法取到1,即8模12的乘法逆不存在。
- 关于x模m的乘法逆的存在性与唯一性,有下述定理:
- 当m和x满足gcd(m,x)=1(即m与x互质),则x模m的乘法逆存在且唯一。
- 证明如下:
- 考虑以下数列:{0(modm),x(modm),2x(modm),⋯,(m−1)x(modm)}。可以证明这一数列没有重复值(使用反证法:如果存在a,b∈[0,m−1]∩Z,使得ax≡bx(modm),则m∣(a−b)x,而m与x互质,故只能m∣a−b,但∣a−b∣<m,产生矛盾)。因此数列包含{0,1,⋯,m−1}中的每一个值,故一定存在y∈[0,m−1]∩Z,使得y为x模m的乘法逆。
- 下面证明y唯一性:如果存在y′满足y′x≡1(modm),那么y≡yy′x≡y′(modm)。又因为y,y′∈{0,1,⋯,m−1},所以y=y′。
- 当然,这一定理的逆命题同样成立(当x模m的乘法逆存在⟹m与x互质)简单证明如下:设a为x模m的乘法逆,则ax≡1(modm),即存在k∈Z+,使得ax=km+1。而如果gcd(m,x)=d>1,则gcd(ax,km)>1,产生矛盾。
- 我们一般将x模m的乘法逆记为x−1,就像一般的算术一样。下面我们将介绍如何利用最大公约数计算x−1。
# 乘法逆的计算
- 事实上,对于最大公约数,我们可以得到以下结论(也被称为裴蜀定理):
- 如果gcd(a,b)=d,那么一定存在整数x,y,使得d=ax+by
- 基于这一结论,我们可以得出:1=gcd(m,x)=am+bx,a,b∈Z。从而bx≡1(modm),那么b对m取模即为我们所求的乘法逆。
# 欧几里得算法(辗转相除法)
- 首先,我们定义gcd(a,0)=a,gcd(0,b)=b。对于非零的两数x,y,存在以下定理:
- 设x≥y>0,则gcd(x,y)=gcd(y,x(mody))。
- 证明很容易(直接使用模运算定义即可),故省略。
- 通过这一定理,可以对x和y反复互相取模,直到其中一项变为0,则另一项即为x和y的最大公因数。
- 我们可以将这一算法用python代码实现:
def gcd(x,y):
if y==0:
return x
else:
return gcd(y,x%y)
- 这里我们再分析一下这个程序运行的时间复杂度(递归调用的次数)。可以证明,
gcd(x,y)在经过两次递归后最大项不会超过2x:
- 若y≤2x,则在一次递归后,最大项已经不超过2x,故第二次递归也一定不超过;
- 若2x<y≤x,则在两次递归后,最大项会变为x(mody)<2x。
- 所以最多经过2⌈log2n⌉次递归后,x变为0。故时间复杂度为O(logx)。
- 下面我们就使用欧几里得算法求解乘法逆。
# 欧几里得算法的扩展
我们将上面求解最大公约数的代码进行扩展:
def extended_gcd(x,y):
if y==0:
return x,1,0
else:
d,a,b=extended_gcd(y,x%y)
return d,b,a-(x//y)*b
- 这个函数输入x,y后返回d,a,b三个值,满足d=gcd(a,b)=ax+by。可以验证,当d=1时,b即为x模y的乘法逆。
- 那么这个算法是如何设计出来的呢?我们可以尝试逆向递推:
- 当y=0时,返回值d=x,a=1,b=0,显然满足d=ax+by;
- 当y>0时,首先通过递归调用
extended_gcd(y,x%y)得到d=gcd(y,x(mody)),且d=a⋅y+b⋅x(mody),然后再返回d,a′=b,b′=a−⌊yx⌋b。
- 很明显d即为最大公约数(和先前的方法相同),而对于a′和b′,有以下推导:
d=a⋅y+b⋅x(mody)=a⋅y+b(x−⌊yx⌋y)=bx+(a−⌊yx⌋b)y
这便是a′和b′表达式的由来。
- 与先前的算法相比,仅仅是增加了常数倍的计算量,时间复杂度仍为O(logx)。
- 当然,除了递归,我们还可以直接采用递推法求解。注意到d∣x且d∣y,所以d一定整除由x和y组成的线性组合。那么基于下面两个等式:
(1)x+(0)y=x(0)x+(1)y=y
对两个式子的右边做辗转相除(类似x−⌊yx⌋y的操作),左边也作出相应的运算,最后一定能得到ax+by=d。
# 除法模运算
- 在得到乘法逆后,我们就可以做除法模运算了。一种典型的使用场景如下:
- 已知8x≡11(mod15),求x。
- 为解这一方程,注意到8模15的乘法逆为2,故x=22(mod15)=7。而且这是取模后的唯一解。
# 算术基本定理(Fundamental Theorem of Arithmetic)
- 在初等数论中,有一个非常重要的定理:任何一个大于1的整数可分解为若干个质数的乘积。事实上,我们可以用拓展后的欧几里得算法进行证明。
- 首先证明一个引理:
- 设x,y,z∈Z+且gcd(x,y)=1,那么如果x∣yz,则x∣z。
- 简单证明:因为gcd(x,y)=1,所以存在整数a,b,满足ax+by=1。两边乘以z得axz+byz=z,因为x∣axz,x∣byz(因为x∣yz),所以x∣axz+byz=z。
- 有了这个引理,既可以对算术基本定理进行证明:
- 在归纳法例4中,我们已经证明了任意大于1的整数n都可以表示为一个或多个质数的乘积p1p2⋯pk。那么,就只需要证明这一序列在对质因子进行排序后唯一即可。(用数学语言描述即为:如果n=p1p2⋯pk=q1q2⋯ql,pi,qj(1≤i≤k,1≤j≤l)均为质数,那么k=l,且{pi}与{qj}仅顺序不同)
- 下面给出具体证明:
- 对于p1,因为p1∣n,所以p1∣q1q2⋯ql,又因为p1,q1,⋯,ql均为质数,所以p1一定等于q1,q2,⋯,ql的其中之一(设为qj1)。于是将等式p1p2⋯pk=q1q2⋯ql两边各除去p1和对应的qj1。
- 以此类推,可以得到p2,p3,⋯,pk对应的qji项。最终左式除到1,此时右式还剩下l−k项。又因为质数均大于1,所以只有当l−k=0,即l=k时等式成立。再由先前已经建立的pi与qj一一对应,命题得证。
- 这一证明体现了欧几里得算法的核心思想:除法与余数的唯一性(对于任意x与m>0,存在唯一的q与r(0≤r≤m−1),使得x=qy+r)
# 中国剩余定理(Chinese Remainder Theorem)
最后我们介绍另一个与模运算有关的定理。我们首先给出这个定理的简化形式: