注:本节可参考国内《信息安全数学基础》《初等数论》《抽象代数》等相关内容(即如果学习过以上课程,下面内容可以跳过)。

# 模运算(Modular Arithmetic)

在计算机的一些领域(如密码学),我们通常希望处理一串范围较小的数字。这时,模运算就起到了巨大的作用,它能将数压缩到一个较小的范围{0,1,,N1}\{0,1,\cdots,N-1\},从而简化大量运算。
在生活中,最常见的模运算例子就是时钟。时钟以12小时为一循环(如果以24小时制计算则为24小时一循环),因而我们能够轻松计算当前时刻若干小时后的时刻。
用数学语言描述的话,我们可以定义x(modm)rx\hspace{0.3em}(\operatorname*{mod}m)\coloneqq r,其中rrxx除以mm得到的余数。即:

x(modm)rx=mq+r(0rm1,qZ)x\hspace{0.3em}(\operatorname*{mod}m)\equiv r \Longleftrightarrow x=mq+r\hspace{0.5em}(0\leq r\leq m-1,q\in\mathbb{Z})

# 计算法则(加法,减法与乘法)

  • 在计算x+y(modm)x+y\hspace{0.3em}(\operatorname*{mod}m)时,我们可以先计算x(modm)x\hspace{0.3em}(\operatorname*{mod}m)y(modm)y\hspace{0.3em}(\operatorname*{mod}m),再将二者相加取模(这很容易证明)。同理,xy(modm)x-y\hspace{0.3em}(\operatorname*{mod}m)也等于(x(modm)y(modm))(modm)(x\hspace{0.3em}(\operatorname*{mod}m)-y\hspace{0.3em}(\operatorname*{mod}m))(\operatorname*{mod}m)
  • 在乘法运算上,这一法则的效果更明显:xy(modm)=(x(modm))×(y(modm))(modm)xy(\operatorname*{mod}m)=(x\hspace{0.3em}(\operatorname*{mod}m))\times(y\hspace{0.3em}(\operatorname*{mod}m))(\operatorname*{mod}m),借助这一公式,计算的规模可以大大减小。

# 集合表示(Set representation)

  • 下面我们换个视角分析模运算。对于任意整数mmx,yx,y,如果mm整除xyx-y,则称xxyymm同余(congruent modulo m),即:

xy(modm)m(xy)x\equiv y\hspace{0.3em}(\operatorname*{mod}m)\Longleftrightarrow m\mid (x-y)

  • 显然,在这个式子中,xxyy除以mm得到的余数相同,故上述式子也可记为:

xy(modm)x(modm)=y(modm)x\equiv y\hspace{0.3em}(\operatorname*{mod}m)\Longleftrightarrow x\hspace{0.3em}(\operatorname*{mod}m)=y\hspace{0.3em}(\operatorname*{mod}m)

  • 于是我们可以将所有对mm同余的数组成一个集合(如{,m,0,m,2m,}\{\cdots,-m,0,m,2m,\cdots\}{,m+1,1,m+1,2m+1,}\{\cdots,-m+1,1,m+1,2m+1,\cdots\}等),一共可以组成mm个集合。这些集合可以覆盖所有整数,也被称为模mm的剩余类(residue classes mod m)。
  • 通过建立这些集合,我们就可以理解上述模运算法则的原理。由于每个集合里的所有元素均相互同余,所以我们可以将运算的数转化到{0,1,,m1}\{0,1,\cdots,m-1\}这个范围内。
  • 下面再用数学语言将这一命题进行阐述(可以直接用定义证明,故证明过程省略):
    如果ac(modm)a\equiv c\hspace{0.3em}(\operatorname*{mod}m)bd(modm)b\equiv d\hspace{0.3em}(\operatorname*{mod}m),那么a±bc±d(modm)a\pm b\equiv c\pm d\hspace{0.3em}(\operatorname*{mod}m),同时abcd(modm)a\cdot b\equiv c\cdot d\hspace{0.3em}(\operatorname*{mod}m)
  • 注意到我们这里没有涉及到除法运算,这将在后面被讨论。

# 指数运算

  • 在密码学中,指数运算也是一种重要的运算。那么,对于xyx^yx,yx,y均为自然数),如何求它对m(m>1)m(m>1)的模呢?一种朴素的方法是依次计算x(modm),x2(modm),x\hspace{0.3em}(\operatorname*{mod}m),x^2\hspace{0.3em}(\operatorname*{mod}m),\cdots一直到xy(modm)x^y\hspace{0.3em}(\operatorname*{mod}m),但这样效率太低(如果用程序实现时间复杂度可达O(2y)O(2^y))。
  • 为了优化这一运算,我们可以使用下述“重复平方(repeated squaring)”技巧:
    • 设计递归函数mod_exp(x,y,m),返回值为xy(modm)x^y\hspace{0.3em}(\operatorname*{mod}m)
    • 如果y=0y=0,则返回1x01(modm)x^0\equiv 1\hspace{0.3em}(\operatorname*{mod}m));
    • 如果y0y\neq 0,设z=mod_exp(x,y//2,m)z=xy2(modm)z=x^{\lfloor\frac{y}{2}\rfloor}\hspace{0.3em}(\operatorname*{mod}m));
      • 如果yy为偶数,则返回z2(modm)z^2\hspace{0.3em}(\operatorname*{mod}m)
      • 如果yy为奇数,则返回xz2(modm)xz^2\hspace{0.3em}(\operatorname*{mod}m)
  • 这样算法的时间复杂度就降到了O(logy)O(\log y)(具体关于算法时间复杂度的知识可参见CS61B)。

# 双射(Bijecions)

  • 在介绍除法运算前,先做一个铺垫。这里我们回顾一下高等数学中映射的概念:
    • 映射(mapping):设XX,YY是两个给定的集合,若按照某种规则ff,使得XX中的每一个元素,都可以在YY中找到唯一的元素与之对应,则称ff是集合XX到集合YY的一个映射。
    • 单射(one-to-one):设ff是集合XX到集合YY的一个映射,若ff的逆像也具有唯一性,即对XX中的任意两个不同元素x1x2x_1\neq x_2,也满足f(x1)f(x2)f(x_1)\neq f(x_2)(也可表述为f(x1)=f(x2)x1=x2f(x_1)=f(x_2)\Longrightarrow x_1=x_2),则ff为单射。
    • 满射(onto):如果yY\forall y\in YxX\exists x\in X满足f(x)=yf(x)=y,则称ff为满射。
    • 双射:如果ff既是单射又是满射,那么ff就是双射。
  • 利用这些概念,我们考虑以下函数(均将集合{0,1,,m1}\{0,1,\cdots,m-1\}映射到自身):

f(x)x+1(modm)f(x)\equiv x+1\hspace{0.3em}(\operatorname*{mod}m)

g(x)2m(modm)g(x)\equiv 2m\hspace{0.3em}(\operatorname*{mod}m)

  • 可以发现,映射ff是双射(集合中的每一个yy,都存在唯一原像y1y-1);而映射gg只有当mm是奇数时才是双射({0,1,,m1}\{0,1,\cdots,m-1\}映射到{0,2,,m,1,3,,m1}\{0,2,\cdots,m,1,3,\cdots,m-1\}),当mm为偶数时既不是单射也不是满射。
  • 另外关于双射,有以下定理:
    • 对于一个有限集合AA,如果映射f:AAf:A\rightarrow A存在对应的逆映射g:AAg:A\rightarrow A满足g(f(x))=xg(f(x))=x,则ff为双射。

# 逆(Inverses)

  • 之前我们进行减法模运算时,注意到bmb(modm)-b\equiv m-b\hspace{0.3em}(\operatorname*{mod}m),所以加法模运算很容易拓展到减法模运算。
  • 然而想通过乘法模运算推导出除法模运算就困难一些。在实数域上,我们知道除以xx等价于乘以1x\frac{1}{x}。相应的,计算ax(modm)\frac{a}{x}\hspace{0.3em}(\operatorname*{mod}m),就需要找到yy,使得xy1(modm)x\cdot y\equiv 1\hspace{0.3em}(\operatorname*{mod}m),那么就可以将问题转化为ay(modm)a\cdot y\hspace{0.3em}(\operatorname*{mod}m)。这里yy也被称为xxmm的乘法逆(multiplicative inverse)。
  • 那么,能否保证yy一定存在?yy又是否唯一呢?我们先举一些例子:令x=9,m=17x=9,m=17,则当y=2y=2时,xy=181(mod17)xy=18\equiv 1\hspace{0.3em}(\operatorname*{mod}17),即22991717的乘法逆;而当x=8,m=12x=8,m=12时,取y={1,2,3,}y=\{1,2,3,\cdots\}xy(modm)={8,4,0,8,4,}xy\hspace{0.3em}(\operatorname*{mod}m)=\{8,4,0,8,4,\cdots\}循环,无法取到11,即881212的乘法逆不存在。
  • 关于xxmm的乘法逆的存在性与唯一性,有下述定理:
    • mmxx满足gcd(m,x)=1\operatorname*{gcd}(m,x)=1(即mmxx互质),则xxmm的乘法逆存在且唯一。
  • 证明如下:
    • 考虑以下数列:{0(modm),x(modm),2x(modm),,(m1)x(modm)}\{0\hspace{0.3em}(\operatorname*{mod}m),x\hspace{0.3em}(\operatorname*{mod}m),2x\hspace{0.3em}(\operatorname*{mod}m),\cdots,(m-1)x\hspace{0.3em}(\operatorname*{mod}m)\}。可以证明这一数列没有重复值(使用反证法:如果存在a,b[0,m1]Za,b\in [0,m-1]\cap\mathbb{Z},使得axbx(modm)ax\equiv bx\hspace{0.3em}(\operatorname*{mod}m),则m(ab)xm\mid (a-b)x,而mmxx互质,故只能mabm\mid a-b,但ab<m|a-b|< m,产生矛盾)。因此数列包含{0,1,,m1}\{0,1,\cdots,m-1\}中的每一个值,故一定存在y[0,m1]Zy\in [0,m-1]\cap\mathbb{Z},使得yyxxmm的乘法逆。
    • 下面证明yy唯一性:如果存在yy'满足yx1(modm)y'x\equiv 1\hspace{0.3em}(\operatorname*{mod}m),那么yyyxy(modm)y\equiv yy'x\equiv y'\hspace{0.3em}(\operatorname*{mod}m)。又因为y,y{0,1,,m1}y,y'\in\{0,1,\cdots,m-1\},所以y=yy=y'
    • 当然,这一定理的逆命题同样成立(当xxmm的乘法逆存在m\Longrightarrow mxx互质)简单证明如下:设aaxxmm的乘法逆,则ax1(modm)ax\equiv 1\hspace{0.3em}(\operatorname*{mod}m),即存在kZ+k\in\mathbb{Z}^+,使得ax=km+1ax=km+1。而如果gcd(m,x)=d>1\operatorname*{gcd}(m,x)=d>1,则gcd(ax,km)>1\operatorname*{gcd}(ax,km)>1,产生矛盾。
  • 我们一般将xxmm的乘法逆记为x1x^{-1},就像一般的算术一样。下面我们将介绍如何利用最大公约数计算x1x^{-1}

# 乘法逆的计算

  • 事实上,对于最大公约数,我们可以得到以下结论(也被称为裴蜀定理):
    • 如果gcd(a,b)=d\operatorname*{gcd}(a,b)=d,那么一定存在整数x,yx,y,使得d=ax+byd=ax+by
  • 基于这一结论,我们可以得出:1=gcd(m,x)=am+bx,a,bZ1=\operatorname*{gcd}(m,x)=am+bx,a,b\in\mathbb{Z}。从而bx1(modm)bx\equiv 1\hspace{0.3em}(\operatorname*{mod}m),那么bbmm取模即为我们所求的乘法逆。

# 欧几里得算法(辗转相除法)

  • 首先,我们定义gcd(a,0)=a,gcd(0,b)=b\operatorname*{gcd}(a,0)=a,\operatorname*{gcd}(0,b)=b。对于非零的两数x,yx,y,存在以下定理:
    • xy>0x\geq y>0,则gcd(x,y)=gcd(y,x(mody))\operatorname*{gcd}(x,y)=\operatorname*{gcd}(y,x(\operatorname*{mod}y))
    • 证明很容易(直接使用模运算定义即可),故省略。
  • 通过这一定理,可以对xxyy反复互相取模,直到其中一项变为00,则另一项即为xxyy的最大公因数。
  • 我们可以将这一算法用python代码实现:
def gcd(x,y):
  if y==0:
    return x
  else:
    return gcd(y,x%y)
  • 这里我们再分析一下这个程序运行的时间复杂度(递归调用的次数)。可以证明,gcd(x,y)在经过两次递归后最大项不会超过x2\frac{x}{2}
    • yx2y\leq\frac{x}{2},则在一次递归后,最大项已经不超过x2\frac{x}{2},故第二次递归也一定不超过;
    • x2<yx\frac{x}{2}< y\leq x,则在两次递归后,最大项会变为x(mody)<x2x(\operatorname*{mod}y)<\frac{x}{2}
  • 所以最多经过2log2n2\lceil\log_2n\rceil次递归后,xx变为00。故时间复杂度为O(logx)O(\log x)
  • 下面我们就使用欧几里得算法求解乘法逆。

# 欧几里得算法的扩展

我们将上面求解最大公约数的代码进行扩展:

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,yx,y后返回d,a,bd,a,b三个值,满足d=gcd(a,b)=ax+byd=\operatorname{gcd}(a,b)=ax+by。可以验证,当d=1d=1时,bb即为xxyy的乘法逆。
  • 那么这个算法是如何设计出来的呢?我们可以尝试逆向递推:
    • y=0y=0时,返回值d=x,a=1,b=0d=x,a=1,b=0,显然满足d=ax+byd=ax+by
    • y>0y>0时,首先通过递归调用extended_gcd(y,x%y)得到d=gcd(y,x(mody))d=\operatorname*{gcd}(y,x(\operatorname*{mod}y)),且d=ay+bx(mody)d=a\cdot y+b\cdot x(\operatorname*{mod}y),然后再返回d,a=b,b=axybd,a'=b,b'=a-\lfloor\frac{x}{y}\rfloor b
    • 很明显dd即为最大公约数(和先前的方法相同),而对于aa'bb',有以下推导:

    d=ay+bx(mody)=ay+b(xxyy)=bx+(axyb)y\begin{gathered} d=a\cdot y+b\cdot x(\operatorname*{mod}y)\\ =a\cdot y+b(x-\lfloor\frac{x}{y}\rfloor y)\\ =bx+(a-\lfloor\frac{x}{y}\rfloor b)y \end{gathered}

    这便是aa'bb'表达式的由来。
  • 与先前的算法相比,仅仅是增加了常数倍的计算量,时间复杂度仍为O(logx)O(\log x)
  • 当然,除了递归,我们还可以直接采用递推法求解。注意到dxd\mid xdyd\mid y,所以dd一定整除由xxyy组成的线性组合。那么基于下面两个等式:

    (1)x+(0)y=x(0)x+(1)y=y\begin{gathered} (1)x+(0)y=x\\ (0)x+(1)y=y \end{gathered}

对两个式子的右边做辗转相除(类似xxyyx-\lfloor\frac{x}{y}\rfloor y的操作),左边也作出相应的运算,最后一定能得到ax+by=dax+by=d

# 除法模运算

  • 在得到乘法逆后,我们就可以做除法模运算了。一种典型的使用场景如下:
    • 已知8x11(mod15)8x\equiv 11(\operatorname*{mod} 15),求xx
    • 为解这一方程,注意到881515的乘法逆为22,故x=22(mod15)=7x=22(\operatorname*{mod} 15)=7。而且这是取模后的唯一解。

# 算术基本定理(Fundamental Theorem of Arithmetic)

  • 在初等数论中,有一个非常重要的定理:任何一个大于11的整数可分解为若干个质数的乘积。事实上,我们可以用拓展后的欧几里得算法进行证明。
  • 首先证明一个引理:
    • x,y,zZ+x,y,z\in\mathbb{Z^+}gcd(x,y)=1\operatorname*{gcd}(x,y)=1,那么如果xyzx\mid yz,则xzx\mid z
    • 简单证明:因为gcd(x,y)=1\operatorname*{gcd}(x,y)=1,所以存在整数a,ba,b,满足ax+by=1ax+by=1。两边乘以zzaxz+byz=zaxz+byz=z,因为xaxzx\mid axzxbyzx\mid byz(因为xyzx\mid yz),所以xaxz+byz=zx\mid axz+byz=z
  • 有了这个引理,既可以对算术基本定理进行证明:
    • 归纳法例4中,我们已经证明了任意大于11的整数nn都可以表示为一个或多个质数的乘积p1p2pkp_1p_2\cdots p_k。那么,就只需要证明这一序列在对质因子进行排序后唯一即可。(用数学语言描述即为:如果n=p1p2pk=q1q2qln=p_1p_2\cdots p_k=q_1q_2\cdots q_lpi,qj(1ik,1jl)p_i,q_j(1\leq i\leq k,1\leq j\leq l)均为质数,那么k=lk=l,且{pi}\{p_i\}{qj}\{q_j\}仅顺序不同)
    • 下面给出具体证明:
    • 对于p1p_1,因为p1np_1\mid n,所以p1q1q2qlp_1\mid q_1q_2\cdots q_l,又因为p1,q1,,qlp_1,q_1,\cdots,q_l均为质数,所以p1p_1一定等于q1,q2,,qlq_1,q_2,\cdots,q_l的其中之一(设为qj1q_{j1})。于是将等式p1p2pk=q1q2qlp_1p_2\cdots p_k=q_1q_2\cdots q_l两边各除去p1p_1和对应的qj1q_{j1}
    • 以此类推,可以得到p2,p3,,pkp_2,p_3,\cdots,p_k对应的qjiq_{ji}项。最终左式除到11,此时右式还剩下lkl-k项。又因为质数均大于11,所以只有当lk=0l-k=0,即l=kl=k时等式成立。再由先前已经建立的pip_iqjq_j一一对应,命题得证。
  • 这一证明体现了欧几里得算法的核心思想:除法与余数的唯一性(对于任意xxm>0m>0,存在唯一的qqr(0rm1)r(0\leq r\leq m-1),使得x=qy+rx=qy+r

# 中国剩余定理(Chinese Remainder Theorem)

最后我们介绍另一个与模运算有关的定理。我们首先给出这个定理的简化形式:

  • 对于任意m,nm,n满足gcd(m,n)=1\operatorname*{gcd}(m,n)=1,存在唯一的x(modmn)x\hspace{0.3em}(\operatorname*{mod}mn),满足:

    xa(modn)xb(modm)x\equiv a\hspace{0.3em}(\operatorname*{mod}n)\text{且}x\equiv b\hspace{0.3em}(\operatorname*{mod}m)

  • 证明如下:
    • 先证明存在性:因为gcd(m,n)=1\operatorname*{gcd}(m,n)=1,由先前乘法逆的存在性定理,分别存在mm关于nn的乘法逆(记为m1m^{-1})与nn关于mm的乘法逆(记为n1n^{-1})。令

      um(m1(modn))(modn),vn(n1(modm))(modm)u\equiv m\cdot(m^{-1}(\operatorname*{mod}n))\hspace{0.3em}(\operatorname*{mod}n),v\equiv n\cdot(n^{-1}(\operatorname*{mod}m))\hspace{0.3em}(\operatorname*{mod}m)

      注意到u1(modn)u\equiv 1\hspace{0.3em}(\operatorname*{mod}n)u0(modm)u\equiv 0\hspace{0.3em}(\operatorname*{mod}m)(类似有v1(modm)v\equiv 1\hspace{0.3em}(\operatorname*{mod}m)v0(modn)v\equiv 0\hspace{0.3em}(\operatorname*{mod}n)),因此令x=ua+vbx=ua+vb,则有x1a+0ba(modn)x\equiv 1\cdot a+0\cdot b\equiv a\hspace{0.3em}(\operatorname*{mod}n)(类似有xb(modm)x\equiv b\hspace{0.3em}(\operatorname*{mod}m)),故xx满足命题要求。
    • 再证明唯一性:设xxyy均满足命题要求,则有n(xy)n\mid(x-y)m(xy)m\mid(x-y),又因为m,nm,n互质,故mn(xy)mn\mid(x-y),即存在kZk\in\mathbb{Z},使得xy=kmnx-y=kmn。而x,y{0,1,,mn1}x,y\in\{0,1,\cdots,mn-1\},所以xyx-y只能等于00,即x=yx=y
  • 将这一定理进行推广,就得到了下述中国剩余定理
    • n1,n2,,nkn_1,n_2,\cdots,n_k为正整数且两两互质,那么对于任意数列{ai}(i=1,2,,k)\{a_i\}(i=1,2,\cdots,k),存在唯一的x[0,i=1kni]x\in[0,\prod_{i=1}^kn_i]满足以下方程组:

      {xa1(modn1)xai(modni)xak(modnk)\begin{cases} x\equiv a_1\hspace{0.3em}(\operatorname*{mod}n_1)\\ \cdot\cdot\equiv\cdots\\ x\equiv a_i\hspace{0.3em}(\operatorname*{mod}n_i)\\ \cdot\cdot\equiv\cdots\\ x\equiv a_k\hspace{0.3em}(\operatorname*{mod}n_k) \end{cases}

      x(i=1kaibi)(modN),N=i=1kni,bi=Nni(Nni)ni1x\equiv(\sum_{i=1}^ka_ib_i)(\operatorname*{mod}N),\hspace{1em}N=\prod_{i=1}^kn_i,\hspace{0.3em}b_i=\frac{N}{n_i}(\frac{N}{n_i})_{n_i}^{-1}

      其中(Nni)ni1(\frac{N}{n_i})_{n_i}^{-1}表示Nni\frac{N}{n_i}nin_i的乘法逆。
    • 这里bi(modnj)b_i(\operatorname*{mod}n_j)的取值只可能为11(当i=ji=j)与00(当iji\neq j)因此,如果将xx看成一个kk维向量(第ii个元素为x(modni)x\hspace{0.3em}(\operatorname*{mod}n_i)),那么bib_i就可以看成第ii个元素为11,其余元素均为00的基向量,而xxb1,,bkb_1,\cdots,b_k的线性组合(所以b1,,bkb_1,\cdots,b_k乘以任意倍数均满足方程)
  • 证明xx的唯一性与上面的二元情况类似,就不再赘述了。
  • 最后,我们注意到如果用(xa,xb)(x_a,x_b)表示xxxa=x(modn),xb=x(modm)x_a=x(\operatorname*{mod}n),x_b=x(\operatorname*{mod}m)),用(ya,yb)(y_a,y_b)表示yy,那么就可以用(xa+ya,ya+yb)(x_a+y_a,y_a+y_b)表示x+yx+y(即xa+ya,ya+ybx_a+y_a,y_a+y_b可以唯一确定x+yx+y)。对于乘法也是类似,(xaya,xbyb)(x_ay_a,x_by_b)可以唯一表示xyxy。因此{0,1,,mn1}\{0,1,\cdots,mn-1\}{0,1,,m1}×{0,1,,n1}\{0,1,\cdots,m-1\}\times\{0,1,\cdots,n-1\}形成了一个同构(环同构)。