![应用密码学:原理、分析与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=1738834581-O9egioC8xLWM8nEDhpWweHeioStHjvvo-0-c76a5b046843718d6e4091ce07e0cb83)
仅需4次计算就能得到结果。相比进行15次重复运算,大大节约了时间。
如果幂不是2的倍数呢?比如,应该如何计算?其实也很简单,拆分计算即可:
![pg41b](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/pg41b.jpg?sign=1738834581-PImUdvZhlANgJKCf8zbXSxUTHfji7JLY-0-1169f79f27e416a36fab2022a26489e7)
这样也仅需6次就可以得到答案。
例2.7.3 上面例子的计算较简单,不使用相关公式也可以计算。如果是)这种大数模的幂运算呢?在通常的运算过程中人们都不想处理大数,因为这时候计算太繁琐。此时可应用幂取模运算的办法。
解:第1步,将中的指数
转化为二进制数。
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02778.jpg?sign=1738834581-QugjJ8EYsSg4S1Y8gFaINkx5Xmsg09Mg-0-a08fa8480994af58eedc54cd54d57977)
用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=1738834581-of9axgucSeklw8liXOCpmRVr6Rya8A6e-0-b2a40db721cf4eb3fcce9eec6b6898a4)
第3步,将第1步得到的幂次相乘。
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02820.jpg?sign=1738834581-77iU4QUd46jVN0FAREKT9Slk36fpUCH3-0-ce894ba3b002127c81e261861ca0db9b)
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=1738834581-o4MeT66NVsRYcZb9FfbshrsskRFijaOE-0-9dc7a7f4474ddfa84508af4faa6c8e6c)
如果为素数,那么就很容易得到:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02887.jpg?sign=1738834581-1SROBJbWlSbkgOML7bLC4DghvsHQI4yG-0-61929bf18d419d3c2c660b83587ba6a6)
例2.7.4 计算、
。
解:计算。因为
,且997是素数,所以:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02913.jpg?sign=1738834581-ScsZNGGAfx5sDPLKJXD6ZFIgeEfoLpuE-0-f9cebb881fba1d54874cd9b4ab3b40d0)
计算。因为
,所以可以用欧拉定理。但151255不是素数,所以需要计算
。首先
,因此可以很容易算出:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02940.jpg?sign=1738834581-o1CdWXmizAwwvWosRY9Sk1sVfyR3FnX7-0-0edfacf6e2f41765630b15ba1ed04e78)
那么:
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02948.jpg?sign=1738834581-hEg2m4XROyQ0NWUySaPja3DYvWEQarG5-0-cf7062ed3de979844a01e99c7620ad0a)
![](https://epubservercos.yuewen.com/3B24BD/31309821707952606/epubprivate/OEBPS/Images/tx02951.jpg?sign=1738834581-Sw98KNbUmsc86fMWhQvoe4KQXkntXgHd-0-70467d3f295bea0d8ebc7428411284b1)