![应用密码学:原理、分析与Python实现](https://wfqqreader-1252317822.image.myqcloud.com/cover/378/52717378/b_52717378.jpg)
2.7.2 快速模幕运算
幂运算非常简单,很容易计算。比如计算,可以列出
,只需要计算15次乘法就能得到答案。但是如果指数是一个大数,比如1000000000 ,那么求这种高次幂的最小正整数模应该怎么办呢?对于这种大数,挨个计算就太复杂了,会降低加解密的效率。为了提高效率,就必须想办法在计算的过程中用最少的步骤来快速达到指定的指数。
想快速得到幂运算的结果就需要用到二进制。当指数使用二进制表示时,只有0和1可以作为系数出现,这意味着每个正整数都可以表示为2的不同幂的和。还是以为例,十进制转二进制的方法如例1.3.1所示。利用平方,可以快速得到结果:
![pg41a](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/pg41a.jpg?sign=1738914586-lrRL2M1OCG8ZeBSRm8otclsEBp55PnPO-0-1cb27bd61a1981d66c04838ed6d1c181)
仅需4次计算就能得到结果。相比进行15次重复运算,大大节约了时间。
如果幂不是2的倍数呢?比如,应该如何计算?其实也很简单,拆分计算即可:
![pg41b](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/pg41b.jpg?sign=1738914586-rqeK1S1ghYMksXVbdp5S6u1Iez6bdiqb-0-88feefa7be384541dfecce2f6b4fcd17)
这样也仅需6次就可以得到答案。
例2.7.3 上面例子的计算较简单,不使用相关公式也可以计算。如果是)这种大数模的幂运算呢?在通常的运算过程中人们都不想处理大数,因为这时候计算太繁琐。此时可应用幂取模运算的办法。
解:第1步,将中的指数
转化为二进制数。
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02778.jpg?sign=1738914586-zpNy2QmGfxfqvKpCrLhhrHgilbqlnAgb-0-b04a73e5418517b9e73fec70c5e92dbd)
用Python代码可写成:
1 #二进制数 2 number = 2641 3 number_bin = bin(number)[2:] 4 cov_number_bin = bin(number)[2:][::-1] 5 6 sum_number = '' 7 for i in range(len(cov_number_bin)): 8 if cov_number_bin[i] == '1': 9 if sum_number == '': 10 sum_number += str(2**(i)) 11 else: 12 sum_number += ' + ' + str(2**(i)) 13 print(sum_number)
第2步,用重复平方(Repeated Squaring)得到幂的余。
因为,因此
,得到3278564后继续使用
作为
的基本单位。不用直接计算
,只需要计算
。得到1631541后又可以继续应用在
上,使得
。以此类推,以减少运算量,得到所有
的2次幂项的余:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02809.jpg?sign=1738914586-BFvYyf3MnU2pA0u7nlH3ivZHT6iaZoZi-0-9a0d559a710ccc61fc74313eec2085cf)
第3步,将第1步得到的幂次相乘。
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02820.jpg?sign=1738914586-ZbUzJLWla7D42Oq4Bn0VKVeQXgAON8Eh-0-b15dacfc740976414db52bb3b2810846)
Python计算过程如下,速度比Python的运算符快,因为无须重复计算。下面的函数等同于Python内置函数
pow(a,n,p)
。
1 def fastExpMod(a, n, p): 2 result = 1 3 while n != 0: 4 if (n&1) == 1: 5 # ei = 1, then mul 6 result = (result * a) % p 7 n >>= 1 8 # a, a^2, a^4, a^8, ... , a^(2^n) 9 a = (a*a) % p 10 return result
因此,如果是正整数,计算
的时间复杂度大约为
。
欧拉定理除了可以用于快速求大数幂运算的模,还可以用于求逆元。当时,因为根据欧拉定理
,同乘
可以得到
,等式两边调换一下位置得到:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02878.jpg?sign=1738914586-j4fJaDLu8vKLBvqrxaclczkm7QzpG2cy-0-8766752f10ca0623a06e51c401d7c2d6)
如果为素数,那么就很容易得到:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02887.jpg?sign=1738914586-sPDJZUtHAP4qzJOaKoCtAz1pQ2VBsTwr-0-705c5d128b01675768cd2ed47b6de719)
例2.7.4 计算、
。
解:计算。因为
,且997是素数,所以:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02913.jpg?sign=1738914586-2Ntp2SlIDNEcNlgdP7R4BMAPmiYASIxI-0-d1ef5392dd51d705fcae18d58c6e0b1c)
计算。因为
,所以可以用欧拉定理。但151255不是素数,所以需要计算
。首先
,因此可以很容易算出:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02940.jpg?sign=1738914586-8MpUflKpL3NQ9VJJAcwWS5mR3iE7c6zb-0-2f8e5cc1b7dd9799bcfe6d912d4e30a3)
那么:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02948.jpg?sign=1738914586-QyN0EjcbpR0B7SvDdeAjVvJEXKcLJu9e-0-af8cb1084c31bdf7cae0458ec6cb95c0)
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02951.jpg?sign=1738914586-gAxc2zs2n3i1jnHLCpWTD0aeXM4v8Qcs-0-90a654c390444f497bb129e4a7ad0ec7)