Miller Rabin算法详解
何为Miller Rabin算法
首先看一下度娘的解释(如果你懒得读直接跳过就可以反正也没啥乱用:joy:)
Miller-Rabin算法是目前主流的基于概率的素数测试算法,在构建密码安全体系中占有重要的地位。通过比较各种素数测试算法和对Miller-Rabin算法进行的仔细研究,证明在计算机中构建密码安全体系时, Miller-Rabin算法是完成素数测试的最佳选择。通过对Miller-Rabin 算 法底层运算的优化,可以取得较以往实现更好的性能。[1] 随着信息技术的发展、网络的普及和电子商务的开展, 信息安全逐步显示出了其重要性。信息的泄密、伪造、篡改 等问题会给信息的合法拥有者带来重大的损失。在计算机中构建密码安全体系可以提供4种最基本的保护信息安全的服 务:保密性、数据完整性、鉴别、抗抵赖性,从而可以很大 程度上保护用户的数据安全。在密码安全体系中,公开密钥 算法在密钥交换、密钥管理、身份认证等问题的处理上极其有效,因此在整个体系中占有重要的地位。目前的公开密钥 算法大部分基于大整数分解、有限域上的离散对数问题和椭 圆曲线上的离散对数问题,这些数学难题的构建大部分都需 要生成一种超大的素数,尤其在经典的RSA算法中,生成的素数的质量对系统的安全性有很大的影响。目前大素数的生 成,尤其是随机大素数的生成主要是使用素数测试算法,本 文主要针对目前主流的Miller-Rabin 算法进行全面系统的分析 和研究,并对其实现进行了优化
说白了Miller Rabin算法在信息学奥赛中的应用就一句话:
判断一个数是否是素数
定理
Miller Rabin算法的依据是费马小定理:
证明:
性质1:个整数中没有一个是的倍数
性质2:中没有任何两个同余与模的
所以对模的同余既不为零,也没有两个同余相同
因此,这个数模的同余一定是的某一种排列
即
化简为
根据威尔逊定理可知与互质,所以同时约去
即得到
那么是不是当一个数满足任意使得成立的时候它就是素数呢?
在费马小定理被证明后的很长一段时间里,人们都觉得这是很显然的,
但是终于有一天,人们给出了反例 ,推翻了这个结论
这是否意味着利用费马小定理的思想去判断素数的思想就是错误的呢?
答案是肯定的。
但是如果我们可以人为的把出错率降到非常小呢?
比如,对于一个数,我们有%的几率做出正确判断,那这种算法不也很优越么?
于是Miller Rabin算法诞生了!
首先介绍一下二次探测定理
若为素数,,那么
证明
那么
或者
(此处可根据唯一分解定理证明)
即
这个定理和素数判定有什么用呢?
首先,根据Miller Rabin算法的过程
假设需要判断的数是
我们把分解为的形式
当是素数,有
然后随机选择一个数,计算出
让其不断的自乘,同时结合二次探测定理进行判断
如果我们自乘后的数,但是之前的数
那么这个数就是合数(违背了二次探测定理)
这样乘次,最后得到的数就是
那么如果最后计算出的数不为,这个数也是合数(费马小定理)
正确性
老祖宗告诉我们,若通过一次测试,则不是素数的概率为%
那么经过轮测试,不是素数的概率为
我习惯用这几个数进行判断
在信息学范围内出错率为%(不带高精)
code
注意在进行素数判断的时候需要用到快速幂。。
这个应该比较简单,就不细讲了
#include<cstdio> #define LL long long inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N, M, Test[10] = {2, 3, 5, 7, 11, 13, 17}; int pow(int a, int p, int mod) { int base = 1; for(; p; p >>= 1, a = (1ll * a * a) % mod) if(p & 1) base = (1ll * base * a) % mod; return base % mod; } bool Query(int P) { if(P == 1) return 0; int t = P - 1, k = 0; while(!(t & 1)) k++, t >>= 1; for(int i = 0; i < 4; i++) { if(P == Test[i]) return 1; LL a = pow(Test[i], t, P), nxt = a; for(int j = 1; j <= k; j++) { nxt = (a * a) % P; if(nxt == 1 && a != 1 && a != P - 1) return 0; a = nxt; } if(a != 1) return 0; } return 1; } main() { N = read(); M = read(); while(M--) puts(Query(read()) ? "Yes" : "No"); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库