密码学数学基础 笔记 2:欧几里得算法及其变形、Bézout 等式,以及线性丢番图方程的求解

欧几里得算法

最大公因数与辗转相除法

设整数 a,ba,b 不同时为 00。它们的最大公因数记为 gcd(a,b)\gcd(a,b),是二者最大的正公因子

欧几里得算法还会证明一个更强的性质:a,ba,b 的每一个公因子都整除 gcd(a,b)\gcd(a,b)

一步变换为什么成立

a=qb+r,a=qb+r,

a,ba,bb,rb,r 有完全相同的公因子:

  • dad\mid adbd\mid b,则 d(aqb=r)d\mid (a-qb=r)
  • dbd\mid bdrd\mid r,则 d(qb+r=a)d\mid (qb+r=a)

因此

gcd(a,b)=gcd(b,r)\boxed{\gcd(a,b)=\gcd(b,r)}

每次做带余除法,并用“除数、余数”替换原来的两个数,最大公因数就保持不变

算法与例子

252,198252,198 为例:

252=1×198+54,198=3×54+36,54=1×36+18,36=2×18+0\begin{aligned} 252&=1\times198+54,\\ 198&=3\times54+36,\\ 54&=1\times36+18,\\ 36&=2\times18+0 \end{aligned}

因此

gcd(252,198)=gcd(198,54)=gcd(54,36)=gcd(36,18)=18\gcd(252,198)=\gcd(198,54)=\gcd(54,36) =\gcd(36,18)=18

每一步的非零余数都比除数小,所以过程必然终止。到达 (d,0)(d,0) 时,最大公因数就是 dd,即最后一个非零余数。若初始就有一个数为 00,直接返回另一个数的绝对值

更进一步,因为整个过程中公因子的集合保持不变,而 (d,0)(d,0) 的公因子恰好是 dd 的因子,所以原来每个公因子都整除 dd

1
2
3
4
5
def gcd(a, b):
a, b = abs(a), abs(b)
while b:
a, b = b, a % b
return a

这段实现也采用常见的约定 gcd(0,0)=0\gcd(0,0)=0

算法需要多少次除法

先假设 a>b>0a>b>0。把余数依次记为

r1=a,r0=b,ri+1=ri1modrir_{-1}=a,\qquad r_0=b,\qquad r_{i+1}=r_{i-1}\bmod r_i

仅由“余数严格递减”,可以得到至多 bb 次除法的粗略上界。更好的观察是:每两步,余数至少缩小一半

考虑相邻的 ri,ri+1r_i,r_{i+1},在下一步仍能执行时:

  • ri+1ri/2r_{i+1}\leq r_i/2,则 ri+2<ri+1ri/2r_{i+2}<r_{i+1}\leq r_i/2
  • ri+1>ri/2r_{i+1}>r_i/2,则 rir_i 除以 ri+1r_{i+1} 的商为 11,于是 ri+2=riri+1<ri/2r_{i+2}=r_i-r_{i+1}<r_i/2

因此

ri+2<ri2r_{i+2}<\frac{r_i}{2}

bb 开始,连续减半 O(logb)O(\log b) 次后就会降到 11 以下,算法必须终止。一个宽松的除法次数上界为

2log2b+22\log_2 b+2

这里统计的是整数除法的次数。若输入有 LL 个二进制位,那么除法次数为 O(L)O(L);大整数除法本身还需要计算成本,不能把它当成一次固定时间的操作

两种变形

最小余数版本

等式 gcd(a,b)=gcd(b,r)\gcd(a,b)=\gcd(b,r) 只要求 a=qb+ra=qb+r,对余数的正负没有要求。又因为

gcd(b,r)=gcd(b,r),\gcd(b,r)=\gcd(b,-r),

所以可以选择绝对值不超过 b/2b/2 的余数,再取其绝对值继续计算

例如

123987=4×3476215061,34762=2×15061+4640,15061=3×4640+1141,4640=4×1141+76,1141=15×76+1,76=76×1+0\begin{aligned} 123987&=4\times34762-15061,\\ 34762&=2\times15061+4640,\\ 15061&=3\times4640+1141,\\ 4640&=4\times1141+76,\\ 1141&=15\times76+1,\\ 76&=76\times1+0 \end{aligned}

因此 gcd(123987,34762)=1\gcd(123987,34762)=1

实现时,先求普通余数 r=amodbr=a\bmod b。如果 2r>b2r>b,就用 brb-r 替换它。这相当于选择负余数 rbr-b 后取绝对值

1
2
3
4
5
6
7
8
def balanced_gcd(a, b):
a, b = abs(a), abs(b)
while b:
r = a % b
if 2 * r > b:
r = b - r
a, b = b, r
return a

此时每一步的新余数都不超过当前除数的一半。对 a>b>0a>b>0,除法次数至多为

bits(b)=log2b+1\operatorname{bits}(b)=\lfloor\log_2 b\rfloor+1

这个上界比普通版本更小,但实际运行时间还取决于额外判断和具体的大整数实现

二进制 GCD

二进制 GCD 根据奇偶性,用除以 22 和减法缩小输入。对非负整数 u,vu,v,基本规则为:

条件 变换
u=0u=0 gcd(0,v)=v\gcd(0,v)=v
u,vu,v 都为偶数 gcd(u,v)=2gcd(u/2,v/2)\gcd(u,v)=2\gcd(u/2,v/2)
uu 偶、vv gcd(u,v)=gcd(u/2,v)\gcd(u,v)=\gcd(u/2,v)
uu 奇、vv gcd(u,v)=gcd(u,v/2)\gcd(u,v)=\gcd(u,v/2)
u,vu,v 都为奇数,且 uvu\geq v gcd(u,v)=gcd((uv)/2,v)\gcd(u,v)=\gcd((u-v)/2,v)

例如,两个数都为奇数时,先由 gcd(u,v)=gcd(uv,v)\gcd(u,v)=\gcd(u-v,v) 做减法;由于 uvu-v 为偶数、vv 为奇数,再去掉前者的因子 22

这些版本共同依赖两点:变换保持最大公因数不变,并且不断减小待处理的整数

Bézout 等式与扩展欧几里得算法

普通算法只返回最大公因数。如果在计算过程中同时记录每个余数如何由原来的 a,ba,b 线性组合得到,就能找到整数 u,vu,v,使得

au+bv=gcd(a,b)\boxed{au+bv=\gcd(a,b)}

这就是 Bézout 等式

从余数反向代入

继续使用 252,198252,198 的例子。从最后一个非零余数出发:

18=5436=54(1983×54)=4×54198=4(252198)198=4×2525×198\begin{aligned} 18&=54-36\\ &=54-(198-3\times54)\\ &=4\times54-198\\ &=4(252-198)-198\\ &=4\times252-5\times198 \end{aligned}

因此一组 Bézout 系数为 (u,v)=(4,5)(u,v)=(4,-5)

一般地,若 a=qb+ra=qb+r,递归求得

d=ub+vr,d=u'b+v'r,

r=aqbr=a-qb 代回,就有

d=va+(uqv)bd=v'a+(u'-qv')b

因此,扩展算法的系数递推为

(u,v)=(v,uqv)(u,v)=(v',u'-qv')

正向维护系数

也可以在求余数时同步更新系数,避免最后反向代入。始终维护

ri=uia+vibr_i=u_i a+v_i b

因为

ri+1=ri1qi+1ri,r_{i+1}=r_{i-1}-q_{i+1}r_i,

对应的系数满足同样的递推:

ui+1=ui1qi+1ui,vi+1=vi1qi+1vi\begin{aligned} u_{i+1}&=u_{i-1}-q_{i+1}u_i,\\ v_{i+1}&=v_{i-1}-q_{i+1}v_i \end{aligned}

初始时,a=1a+0ba=1a+0bb=0a+1bb=0a+1b。前面的例子可以整理为:

当前整数 rr aa 的系数 uu bb 的系数 vv
252252 11 00
198198 00 11
5454 11 1-1
3636 3-3 44
1818 44 5-5
00 11-11 1414

对应的迭代实现如下,返回 (d,u,v)(d,u,v),满足 d0d\geq0au+bv=dau+bv=d

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def extended_gcd(a, b):
old_r, r = abs(a), abs(b)
old_u, u = 1, 0
old_v, v = 0, 1

while r:
q = old_r // r
old_r, r = r, old_r - q * r
old_u, u = u, old_u - q * u
old_v, v = v, old_v - q * v

if a < 0:
old_u = -old_u
if b < 0:
old_v = -old_v

return old_r, old_u, old_v

Python 的多重赋值先计算右侧所有表达式,再更新左侧变量,因此每次递推使用的都是更新前的系数

矩阵形式

一次欧几里得变换也可以写成

(b,r)=(a,b)(011q)(b,r)=(a,b) \begin{pmatrix} 0&1\\ 1&-q \end{pmatrix}

设每一步的变换矩阵为 MiM_i,算法结束时有

(d,0)=(a,b)M1M2Mt(d,0)=(a,b)M_1M_2\cdots M_t

如果把矩阵乘积写成

M1M2Mt=(uevf),M_1M_2\cdots M_t= \begin{pmatrix} u&e\\ v&f \end{pmatrix},

就得到 d=au+bvd=au+bv,所以第一列正是 Bézout 系数

例如,对 15,615,6,两次除法的商都是 22,因此

(0112)2=(1225),3=152×6\begin{pmatrix}0&1\\1&-2\end{pmatrix}^2 =\begin{pmatrix}1&-2\\-2&5\end{pmatrix}, \qquad 3=15-2\times6

矩阵形式与前面的系数递推描述的是同一个计算过程

线性丢番图方程

丢番图方程要求未知数取整数值。考虑最基本的情形

ax+by=c,ax+by=c,

下面设 a,ba,b 均非零,并记 d=gcd(a,b)d=\gcd(a,b)

有解的条件

方程有整数解,当且仅当

dc\boxed{d\mid c}

必要性来自整除的性质:dd 整除 a,ba,b,因此整除任何 ax+byax+by

充分性来自 Bézout 等式。若 au+bv=dau+bv=d,且 c=kdc=kd,则

a(ku)+b(kv)=ca(ku)+b(kv)=c

所以一组特解为

x0=cdu,y0=cdvx_0=\frac cd u,\qquad y_0=\frac cd v

例如,gcd(713,851)=23\gcd(713,851)=23,但 231023\nmid10,所以 713x+851y=10713x+851y=10 无整数解

全部整数解

(x0,y0)(x_0,y_0) 是一组特解,则全部整数解为

x=x0+bdt,y=y0adt,tZ\boxed{ x=x_0+\frac bd t,\qquad y=y_0-\frac ad t,\qquad t\in\mathbb{Z} }

代回原式,新增的两项相互抵消,因此这些确实都是解

再说明没有遗漏。记 A=a/dA=a/dB=b/dB=b/d,由 Bézout 等式可得某些整数 u,vu,v 满足 Au+Bv=1Au+Bv=1,因此 A,BA,B 互素

任意另一组解与特解相减,得到

A(xx0)+B(yy0)=0A(x-x_0)+B(y-y_0)=0

于是 BA(xx0)B\mid A(x-x_0)。将 Au+Bv=1Au+Bv=1 乘以 xx0x-x_0,可知 Bxx0B\mid x-x_0,所以 xx0=Btx-x_0=Bt。代回上式就得到 yy0=Aty-y_0=-At

例如,求解

252x+198y=36252x+198y=36

18=4×2525×19818=4\times252-5\times198 乘以 22,得到特解 (8,10)(8,-10)。全部解为

x=8+11t,y=1014t,tZx=8+11t,\qquad y=-10-14t,\qquad t\in\mathbb{Z}

应用:模逆元

n>1n>1。若

ax1(modn),ax\equiv1\pmod n,

也就是 nax1n\mid ax-1,则称 xxaann乘法逆元

这等价于存在整数 yy,使得

ax+ny=1ax+ny=1

因此逆元存在的充要条件是 gcd(a,n)=1\gcd(a,n)=1,扩展欧几里得算法可以直接给出逆元

例如

1=2×263×17,1=2\times26-3\times17,

所以 17172626 的逆元为 323(mod26)-3\equiv23\pmod{26}。检查可得 17×23=391=15×26+117\times23=391=15\times26+1

在 RSA 的一种常见构造中,给定不同素数 p,qp,q,记 φ(n)=(p1)(q1)\varphi(n)=(p-1)(q-1)。选取与 φ(n)\varphi(n) 互素的公钥指数 ee 后,私钥指数 dd 满足

ed1(modφ(n))ed\equiv1\pmod{\varphi(n)}

这一步就是用扩展欧几里得算法求模逆元


© 2024 本网站由 Ywang22 使用 Stellar主题 创建
总访问 次 | 本页访问
共发表 87 篇 Blog(s) · 总计 211.3k 字