蒙哥马利算法
蒙哥马利模乘运算(Montgomery Modular Multiplication)[1]与蒙哥马利幂模运算(Montgomery power module)和蒙哥马利约减运算(Montgomery model reduction)统称蒙哥马利算法(Montgomery Algorithm)。
- 蒙哥马利模乘运算:
- 蒙哥马利幂模运算:
- 蒙哥马利约减运算:
蒙哥马利模乘#
模乘是计算
- 蒙哥马利形式(Montgomery form, Montgomery domain)
为了计算
,需要找到一个 ,然后使得 。 这个
不是随便取的,需要满足两个条件:
,其中 是满足条件的最小正数,这就能保证除以 就相当于右移 位 ,这就可以求出
在计算
这个函数
所以蒙哥马利模乘可以分三步进行计算:
- 将输入
转成蒙哥马利形式,即 ; - 做一次标准乘法得
; - 最后做一次REDC得
; - 注意上面三个步骤返回的是蒙哥马利形式的
,即 。若需要转换成正常形式的 ,需要再做一次 得 ;
代码实现#
给出一个蒙哥马利模乘的Python实现计算 (23456789*12345678)%123456789,注意程序里面取
import math
class MontMul:
"""docstring for ClassName"""
def __init__(self, R, N):
self.N = N
self.R = R
self.logR = int(math.log(R, 2)) #log_2 ^ R
N_inv = MontMul.modinv(N, R)
self.N_inv_neg = R - N_inv #N_inv_neg=R-N^{-1}
self.R2 = (R*R)%N
@staticmethod
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = MontMul.egcd(b % a, a)
return (g, x - (b // a) * y, y) #g=gcd(a,b)
@staticmethod
def modinv(a, m):
g, x, y = MontMul.egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
def REDC(self, T):
N, R, logR, N_inv_neg = self.N, self.R, self.logR, self.N_inv_neg
m = ((T&int('1'*logR, 2)) * N_inv_neg)&int('1'*logR, 2) # m = (T%R * N_inv_neg)%R
t = (T+m*N) >> logR # t = int((T+m*N)/R)
if t >= N:
return t-N
else:
return t
def ModMul(self, a, b):
if a >= self.N or b >= self.N:
raise Exception('input integer must be smaller than the modulus N')
R2 = self.R2
aR = self.REDC(a*R2) # convert a to Montgomery form
bR = self.REDC(b*R2) # convert b to Montgomery form
T = aR*bR # standard multiplication
abR = self.REDC(T) # Montgomery reduction
return self.REDC(abR) # covnert abR to normal ab
if __name__ == '__main__':
N = 123456789
R = 2**64 # assume here we are working on 64-bit integer multiplication
g, x, y = MontMul.egcd(N,R)
if R<=N or g !=1:
raise Exception('N must be larger than R and gcd(N,R) == 1')
inst = MontMul(R, N)
input1, input2 = 23456789, 12345678
mul = inst.ModMul(input1, input2)
if mul == (input1*input2)%N:
print ('({input1}*{input2})%{N} is {mul}'.format(input1 = input1, input2 = input2, N = N, mul = mul))
蒙哥马利模约简#
蒙哥马利模约简(REDC)是蒙哥马利模乘最重要的部分,主要是计算
一般做模约减运算
由于
如何找?
由于
扩展欧几里得:
若
,则必存在整数 ,使得 。
这样就求出了
所以在已知
- 计算
; - 计算
,即将 右移 位; - 若
,则 ,由于 ,所以 ,故: - 返回
;
蒙哥马利幂模运算#
蒙哥马利幂模运算是快速计算
蒙哥马利幂模的优点在于减少了取模的次数(在大数的条件下)以及简化了除法的复杂度(在2的k次幂的进制下除法仅需要进行左移操作)。
计算方式是将幂模运算转化为模乘运算
例如:求D=C^15 % N
由于:ab % n = (a % n)(b % n) % n
所以令:
C = C%N
C1 =C*C % N =C^2 % N
C2 =C1*C % N =C^3 % N
C3 =C2*C2 % N =C^6 % N
C4 =C3*C % N =C^7 % N
C5 =C4*C4 % N =C^14 % N
C6 =C5*C % N =C^15 % N
即:对于E=15的幂模运算可分解为6 个乘模运算。
归纳分析以上方法可以发现:对于任意指数E,都可采用以下算法计算 D=C^E % N:
D=1
WHILE E>0
IF E%2=0
C=C*C % N
E=E/2
ELSE
D=D*C % N
E=E-1
RETURN D
继续分析会发现,要知道E何时能整除 2,并不需要反复进行减一或除二的操作,只需验证E 的二进制各位是0还是1就可以了,从左至右或从右至左验证都可以,从左至右会更简洁。
D=1
FOR i=n TO 0
D=D*D % N
IF e=1 //e是E的最后一位【判断E是否为奇数】
D=D*C % N
RETURN D
这样,模幂运算就转化成了一系列的模乘运算。
/*例如求D=C^15%N
由于:C*k % n = (C % n)*(k % n) % n
所以令:
【奇数】 C1 = C*C % N =C^2 % N 1 15
C2 = C1*C % N =C^3 % N 3 7
【奇数】C3 = C2*C2 % N =C^6 % N
C4 = C3*C % N =C^7 % N 7 3
【奇数】C5 = C4*C4 % N =C^14 % N
C6 = C5*C % N =C^15 % N 15 1
蒙哥马利幂模运算*/
#include <iostream>
using namespace std;
typedef long long __int64;
__int64 Montgomery(__int64 base,__int64 exp,__int64 mod)
{
__int64 res = 1;
while(exp)
{
if ( exp&1 ) //取exp的最后一位为1(奇数)
res = (res*base) % mod;
exp >>= 1; //exp/2
base = (base*base) % mod;
}
return res;
}
int main()
{
//base 底数,exponential 指数,mod 模
__int64 base,exp,mod; //base^exp % mod
base=12,exp=15,mod=99;
cout << base<<"^"<<exp<<"%"<<mod<<"="<<Montgomery(base,exp,mod) << endl;
return 0;
}
复杂度分析#
-
将模除运算转换为移位运算;
-
当出现大量模乘运算时,可以通过并行运算进行预计算,节省时间;
参考#
作者:Hang Shao
出处:https://www.cnblogs.com/pam-sh/p/17390377.html
版权:本作品采用「知识共享」许可协议进行许可。
声明:欢迎交流! 原文链接 ,如有问题,可邮件(mir_soh@163.com)咨询.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2020-05-11 计组:计算机概论