蒙哥马利算法(Montgomery algorithm)是一种用于快速执行模重复平方(\(a^n\;mod\;N\))和模乘法(\(a*b\;mod\;N\))的算法。它主要用于解决大数取模运算的效率问题。
优化重点是避免除法,只使用乘法和位操作。
取模运算
例如:\(10\;mod\;3 = 1\),取模即求余数。
对于取模运算常见的性质有:
\((a + b) \;mod \;N = (a \;mod \;N + b\; mod \;N) \;mod \;N\)
\((a - b) \;mod \;N = (a \;mod \;N - b \;mod \;N) \;mod \;N\)
\((a * b) \;mod \;N = (a \;mod \;N * b \;mod \;N) \;mod \;N\)
\(a^b \;mod \;N = ((a \;mod \;N)^b) \;mod \;N\)
普通算法
求 \(a\;mod\;N\)时,最容易想到的方法就是:如果\(a<N\)获得取模结果即为\(a\),如果\(a*b>N\),那么就需要用到除法\(a \div N = c\;余 \;n\),获得结果为余数\(n\)。因为除法在计算机当中效率非常低,所以采用普通算法计算大数取模(\(a\)远远大于 \(N\))时,会因为使用到除法导致耗时非常长。
那如何避免使用除法,以提高大数取模的效率,蒙哥马利算法提出了对应的方法。
蒙哥马利算法
模逆元
如果 \(ab\;mod\;N=1\),则称\(b\)为\(a\)的模\(N\)逆元(inverse),记为\(a^{-1}\)。
蒙哥马利形式
设\(N>1\),找一个数\(R\),需要满足:
1. \(R>N\)
2. \(R\)与\(N\)的最大公约数为 1,即:\(gcd(R,N)=1\)
3. 为了计算方便,\(R\)应为\(2\)的幂,假设\(2^k=R\)
令\(a'= aR\;mod\;N\),这种形式称为蒙哥马利形式。
有了这个形式之后,就可以“绕路”来求\(ab\;mod\;N\)的值,通过“绕路”可以避免除法。
蒙哥马利约简
已有蒙哥马利形式是:\(aR\;mod\;N\),蒙哥马利约简就是想办法将: \(aR\;mod\;N\)转化为\(a\;mod\;N\)。
我们令\(x=aR\),则\(\frac{x}{R}\;mod\;N=\frac{aR}{R}\;mod\;N=a\;mod\;N\)。这里乍看起来好像有点多此一举,但其实不然,因为\(R\)是\(2\)的幂,所以除以\(R\)在计算机中处理时可以使用移位操作来处理,这样就可以先计算\(aR\)然后对获得的结果进行移位操作即可(避免了除法)。
但有个新问题,移位操作时可能会丢失一些二进制位,例如:\(\frac{7}{2^2}\)是将\(7=0000\;0111\)右移2位变为\(0000\;0001\),这里丢失了一些二级制的低位值,本来\(\frac{7}{2^2}=1.75\),而我们移位得到的结果却是\(1\)。
那如何避免这个问题?只要除数是被除数的倍数即可,例如:\(\frac{8}{2^2}=\frac{2^3}{2^2} =0000\;1000 \;右移2位\)\(=0000\;0010=2\)
那么新的问题就变成了,如何将\(\frac{x}{R}\)里面的\(x\)转化为\(R\)的倍数,同时还不影响最终的计算结果?
让\(x+mN\)即可(\(m\)是一个我们后面要计算的值),因为\((x+mN)\;mod\;N=(x\;mod\;N+mN\;mod\;N)\;mod\;N=(x\;mod\;N+0)\;mod\;N=x\;mod\;N\),所以给\(x\)加上\(mN\)不会影响最终的计算结果。
为什么要给\(x+mN\)呢?
骚操作来了!!!
因为\(gcd(R,N)=1\),根据扩展的欧几里得算法有:
1. \(0 < R⁻¹ < N\) //\(R^{-1}\)是\(R\)关于\(N\)的模逆元
2. \(0 < (-N)⁻¹ < R\) //\((-N)⁻¹\)是\(-N\)关于\(R\)的模逆元
3. \(R * R⁻¹ - N * (-N)⁻¹ = 1\)
有了这些等式,我们就可以来求\(m\)的值:
因为:\((x+mN)\;mod\;R = 0\;mod\;R\)
所以:\((x(-N)^{-1}+mN(-N)^{-1})\;mod\;R=0\;mod\;R\)
所以:\((x(-N)^{-1}+m(RR^{-1}−1))\;modN=0modR\)
所以:\(x(-N)^{-1}\;mod\;R=m\;mod\;R\)
最终得到\(m=x(-N)^{-1}\;mod\;R\),
因为\(R\)是\(2\)的幂,所以对\(R\)取模可以通过位运算来实现,同样避免了除法。
最终的式子就变为了:\(\frac{x+(x(-N)^{-1}\;mod\;R)*N}{R}\;mod\;N\),
其中\(x(-N)^{-1}\;mod\;R\)可以通过位操作实现,同时除以\(R\)通过移位操作实现。
又因为:
\(x<N^2,\;m<R,\;N<R\)
所以令\(y=\frac{x+mN}{R}\)有:
\(y=\frac{x+mN}{R}<\frac{N^2+RN}{R}<\frac{RN+RN}{R}=2N\)
则对于 \(y\;mod\;N\):如果\(y<N\)则\(y\;mod\;N=y\),如果\(y>N\),则\(y\;mod\;N=y-N\)。
以上就是蒙哥马利的约减过程,通过“绕路”的方式,避免除法的使用。
最终算法
回到我们最开始需要计算的问题,大数相乘取模:\(ab\;mod\;N\),可以写为:\(\frac{aR*bR}{R^2}\;mod\;N\),相当于对\(aR*bR\)做两次蒙哥马利约简即可获得最终的结果\(ab\;mod\;N\)。
总结
蒙哥马利算法通过结合蒙哥马利形式与约简,将大数相乘取模中的除法去掉,虽然多了数次的乘法,但是算法效率依然大大超过需要除法运算的效率。
重点在于:
1. 因为\(R\)是\(2\)的幂,所以对\(R\)取模可以使用位操作来进行。
2. 因为约简之后的结果\(0<y<2N\),所以对\(N\)取模时,最多需要减法即可。
3. 因为\(R\)、\((-N)^{-1}\)是常数,所以可以提前计算。
而对于类似\(a^n\;mod\;N\),可以采用重复平方-乘法法去处理。
参考
● [1] https://accu.cc/content/cryptography/montgomery/
● [2] https://blog.csdn.net/weixin_46395886/article/details/112988136
文章评论
所以:(x(−N)−1+mN(−N)−1)modR=0modR
#所以:(x(−N)−1+m(RR−1−1))modN=0modR
所以:x(−N)−1modR=mmodR
最终得到m=x(−N)−1modR,
Typo => (x(−N)−1+m(RR−1−1))modR=0modR