欧几里得算法即辗转相除法,是求两个数的最大公因数的有效算法。而扩展欧几里得算法则可以求出等式sa+tb=gcd(a,b)中的s和t,该算法可以被用于求解模p运算的逆元,也是一个很有效的算法。
有两个整数 a a a和 b b b, 并且 a > b a > b a>b, 则 a a a和 b b b有如下关系(欧几里得除法)( a a a为被除数, b b b为除数,求出余数 r r r):
a = q b + r ( 0 ≤ r < b ) a=qb+r \quad (0 \leq r < b) a=qb+r(0≤r<b)
我们令 a 2 = b , b 2 = r a_2=b, \ b_2=r a2=b, b2=r则类似的有(把除数 b b b和余数 r r r作为被除数和除数再次执行上述运算)
a 2 = q 2 b 2 + r 2 ( 0 ≤ r 2 < b 2 < b ) a_2=q_2 b_2 + r_2 \quad (0 \leq r_2 < b_2 < b) a2=q2b2+r2(0≤r2<b2<b)
依次类推, 必然存在 a n , b n , r n a_n, \ b_n, \ r_n an, bn, rn满足
a n = q n b n + r n ( r n = 0 ) a_n = q_n b_n + r_n \quad (r_n = 0) an=qnbn+rn(rn=0)
即
a n = q n b n a_n = q_n b_n an=qnbn
理由是 r > r 1 > r 2 . . . > r n r > r_1 > r_2...>r_n r>r1>r2...>rn且 r i ( i = 1 , 2 , 3... , n ) r_i (i = 1,2,3...,n) ri(i=1,2,3...,n)为大于等于0的整数, r i r_i ri依次减小最终必然会到0
此时的 b n b_n bn就是 a a a和 b b b的最大公因数
欧几里得算法之所以有效,基于这样一个事实
若 a = q b + r ( 0 ≤ r < b ) , 则 a 和 b 的 最 大 公 因 数 与 b 和 r 的 最 大 公 因 素 相 同 若a=qb+r \quad (0 \leq r < b),则a和b的最大公因数与b和r的最大公因素相同 若a=qb+r(0≤r<b),则a和b的最大公因数与b和r的最大公因素相同
证明如下:
设 d = ( a , b ) , d 1 = ( b , r ) 则 有 d ∣ ( a − q b ) , d 1 ∣ ( q b + r ) 即 d ∣ r , 即 d 1 ∣ a 所 以 有 d ∣ d ‘ 且 d 1 ∣ d 所 以 d = d 1 设d = (a, \ b),\quad d_1=(b, \ r) \\ 则有d \ | \ (a-qb), \quad d_1 \ | \ (qb + r) \\ 即d \ | \ r , 即 d_1 \ | \ a \\ 所以有 d \ | \ d^` 且 d_1 \ | \ d \\ 所以 d = d_1 设d=(a, b),d1=(b, r)则有d ∣ (a−qb),d1 ∣ (qb+r)即d ∣ r,即d1 ∣ a所以有d ∣ d‘且d1 ∣ d所以d=d1
我们利用这个性质,把求较大的两个数 a a a和 b b b的公因数的问题不断转换成求两个较小的数(除数和余数)最大公因数的问题,直到这两个较小的数中有一个为0了,由于0和任何一个数x$ 的 最 大 公 因 数 就 是 的最大公因数就是 的最大公因数就是x$,因为就求出了最大公因数。
def gcd(big_num, small_num):
remainder = big_num % small_num
if remainder == 0:
return small_num
return gcd(small_num, remainder)
根据定理,对于任意整数 a a a和 b b b,必然存在整数 s s s和 t t t使得如下等式成立
s a + t b = ( a , b ) sa+tb=(a,b) sa+tb=(a,b)
要求出其中的 s s s和 t t t可以利用欧几里得算法求最大公因数的过程
在这里,为了更好的说明算法,我们使用 a 1 和 a 2 a_1和a_2 a1和a2 ( a 1 > a 2 ) (a_1 > a_2) (a1>a2)来表示欧几里得算法中的 a 和 b a和b a和b,按照欧几里得算法,有如下求 a 1 和 a 2 a_1和a_2 a1和a2最大公因数 ( a 1 , a 2 ) (a_1,a_2) (a1,a2)的过程
a 1 = q 1 a 2 + a 3 a 2 = q 2 a 3 + a 4 a 3 = q 3 a 4 + a 5 . . . a n − 3 = q n − 3 a n − 2 + a n − 1 a n − 2 = q n − 2 a n − 1 + a n a n − 1 = q n − 1 a n a_1=q_1a_2+a_3 \\ a_2=q_2a_3+a_4 \\ a_3=q_3a_4+a_5 \\ ... \\ a_{n-3}=q_{n-3}a_{n-2}+a_{n-1} \\ a_{n-2}=q_{n-2}a_{n-1}+a_n \\ a_{n-1} = q_{n-1}a_n a1=q1a2+a3a2=q2a3+a4a3=q3a4+a5...an−3=qn−3an−2+an−1an−2=qn−2an−1+anan−1=qn−1an
a n a_n an就是 a 1 和 a 2 a_1和a_2 a1和a2的最大公因数
首先根据欧几里得算法的求解过程,我们容易得到
( a 1 , a 2 ) = a n = a n − 2 − q n − 2 a n − 1 (a_1,a_2) = a_n = a_{n-2} - q_{n-2}a_{n-1} (a1,a2)=an=an−2−qn−2an−1
根据上式子,可以得到对于 a n − 2 和 a n − 1 a_{n-2}和a_{n-1} an−2和an−1来说使等式
( a 1 , a 2 ) = s n − 2 ⋅ a n − 2 + t n − 2 ⋅ a n − 1 式 1 (a_1, a_2) = s_{n-2} \ \cdot \ a_{n-2} + t_{n-2} \ \cdot \ a_{n-1} \qquad 式1 (a1,a2)=sn−2 ⋅ an−2+tn−2 ⋅ an−1式1
成立的 s n − 2 和 t n − 2 s_{n-2}和t_{n-2} sn−2和tn−2的值,即
s n − 2 = 1 t n − 2 = − q n − 2 s_{n-2} = 1 \\t_{n-2} = -q_{n-2} sn−2=1tn−2=−qn−2
现在我们想要计算对于 a n − 3 和 a n − 2 a_{n-3}和a_{n-2} an−3和an−2来说等式
( a 1 , a 2 ) = s n − 3 ⋅ a n − 3 + t n − 3 ⋅ a n − 2 式 2 (a_1, a_2) = s_{n-3} \ \cdot \ a_{n-3} + t_{n-3} \ \cdot \ a_{n-2} \qquad 式2 (a1,a2)=sn−3 ⋅ an−3+tn−3 ⋅ an−2式2
成立的 s n − 3 和 t n − 3 s_{n-3}和t_{n-3} sn−3和tn−3的值
根据欧几里得算法的求解过程,有如下等式对n>3都成立
a n − 1 = a n − 3 − q n − 3 a n − 2 式 3 a_{n-1} = a_{n-3} - q_{n-3}a_{n-2} \qquad 式3 an−1=an−3−qn−3an−2式3
将式3中 a n − 1 a_{n-1} an−1的表达式带入式1得到
( a 1 , a 2 ) = t n − 2 ⋅ a n − 3 + ( s n − 2 − q n − 3 ⋅ t n − 2 ) ⋅ a n − 2 式 4 (a1, a2) = t_{n-2} \ \cdot \ a_{n-3} + (s_{n-2}-q_{n-3} \cdot t_{n-2}) \ \cdot \ a_{n-2} \qquad 式4 (a1,a2)=tn−2 ⋅ an−3+(sn−2−qn−3⋅tn−2) ⋅ an−2式4
可以看到,我们在式2中需要求的 s n − 3 和 t n − 3 s_{n-3}和t_{n-3} sn−3和tn−3求出来了,且这个关系也对n>3都成立
s n − 3 = t n − 2 t n − 3 = s n − 2 − q n − 3 ⋅ t n − 2 s_{n-3} = t_{n-2} \\ t_{n-3} = s_{n-2} - q_{n-3} \ \cdot \ t_{n-2} sn−3=tn−2tn−3=sn−2−qn−3 ⋅ tn−2
按照这个关系,我们可以一直向前推,直到 s 1 和 t 1 s_1和t_1 s1和t1满足
( a 1 , a 2 ) = s 1 ⋅ a 1 + t 1 ⋅ a 2 (a_1,a_2)=s_1 \ \cdot a_1 + t_1 \ \cdot \ a_2 (a1,a2)=s1 ⋅a1+t1 ⋅ a2
从而解出了想要求出的 s s s和 t t t。
注: s s s和 t t t不唯一的(只考虑绝对值不同),例如:
6720 × 46480 + ( − 19713 ) × 39423 = 1 ( − 22703 ) × 46480 + 26767 × 39423 = 1 6720 \times 46480 + (-19713) \times 39423 = 1 \\ (-22703) \times 46480 + 26767 \times 39423 = 1 6720×46480+(−19713)×39423=1(−22703)×46480+26767×39423=1
这似乎说明39423模46480的逆元有两个,但实际上有 ( − 19713 ) + 46480 = 26767 (-19713) + 46480 = 26767 (−19713)+46480=26767
即 − 19713 ≡ 26767 ( m o d 46480 ) -19713 \equiv 26767 \ (mod \ 46480) −19713≡26767 (mod 46480), 对于 a a a和 b b b不互质的情况,暂不清楚。
该算法可以在 a a a和 p p p互质时被用来快速求 a a a模 p p p的逆元 a ‘ a^` a‘
因为若
s ⋅ a + t ⋅ p = 1 s \ \cdot \ a + t \ \cdot \ p = 1 \\ s ⋅ a+t ⋅ p=1
则有
s ⋅ a ≡ 1 ( m o d p ) s \ \cdot \ a \equiv 1 \ (mod \ p) s ⋅ a≡1 (mod p)
其中 s s s就是 a a a的逆元 a ‘ a^` a‘
# 参数为两个数,大数在前小数在后
# 返回值为s,t和两个数的最大公因数
def gcd_ext(big_num, small_num):
remainder = big_num % small_num
iq = int(big_num / small_num)
if small_num % remainder == 0:
s = remainder
t = -iq
return (s, t, remainder)
s_last, t_last, gcd = gcd_ext(small_num, remainder)
s = t_last
t = s_last - t_last * iq
return (s, t, gcd)
信息安全数学基础(第2版)陈恭亮【清华大学出版社】