miller_rabin与pollard_rho与快速乘法

板子

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 LL n; vector <LL> z;
 5 const LL mo=1e9+7;
 6 LL gcd(LL x,LL y){
 7     return y?gcd(y,x%y):abs(x);
 8 }
 9 LL po(LL x,LL y){
10     LL z=1; x%=mo;
11     for (;y;y>>=1,x=x*x%mo)
12     if (y&1) z=z*x%mo;
13     return z;
14 }
15 LL XX(LL x,LL y,LL z){
16 /*
17     (long double)x/z*y求商可以有微小的误差,之后反正会+z%z模回来
18     但如果 没有x%=z,y%=z,商的误差可能会很大,这样作差时会±k*maxLL 而GG
19 */
20     x%=z,y%=z; return ((x*y-(LL)((long double)x/z*y)*z)%z+z)%z;
21     // return (__int128)x*y%z;
22 }
23 int St(LL a,LL b){        //a^(b-1)!=1?&&二次探测
24     //二次探测定理:如果p是奇素数,则x^2≡1(mod p)的解为x=1||x=p-1(mod p);  
25     if (a==b) return 0;
26     LL ans1=1,ans=1;
27     for (int i=64;i>=0;i--){
28         ans=XX(ans1,ans1,b);
29         if (ans==1&&ans1!=1&&ans1!=b-1) return 1;
30         if ((b-1)&(1LL<<i)) ans=XX(ans,a,b);
31         ans1=ans;
32     }
33     return ans!=1;
34 }
35 int isP(LL x){        // x=1时为0;
36     return !(St(2,x)||St(3,x)||St(5,x)||St(7,x)||St(11,x)||St(13,x)||St(17,x)||St(19,x)||St(23,x));
37 }
38 LL ra(LL x){
39     return (rand()*2147483647LL+rand()*32767LL+rand())%x;
40 }
41 LL pro(LL x){
42     LL x1=ra(x),x2=(XX(x1,x1,x)+1)%x,p=gcd(x1-x2,x);
43     while (p==1){        //不用判x=y,大不了返回x 
44         x1=(XX(x1,x1,x)+1)%x;
45         x2=(XX(x2,x2,x)+1)%x;
46         x2=(XX(x2,x2,x)+1)%x;
47         p=gcd(x1-x2,x);
48     }
49     return p;
50 }
51 void divide(LL x){
52     while (!(x&1)) z.push_back(2),x/=2;
53     if (x==1) return;
54     if (isP(x)) z.push_back(x);else{
55         LL y=pro(x);
56         divide(x/y); divide(y);
57     }
58 }
59 int main(){
60     scanf("%lld",&n);
61     divide(n);
62     printf("%lld=",n);
63     if (n==1){
64         puts("1"); return 0;
65     }
66     sort(z.begin(),z.end());
67     for (int q=0,h=0;q<z.size();q=h){
68         while (h<z.size()&&z[h]==z[q]) ++h;
69         if (q!=h-1) printf("%lld^%d",z[q],h-q); else printf("%lld",z[q]);
70         if (h!=z.size()) printf("*");
71     }
72     puts("");
73 }
冰菓

 

(没想到会在大学概统课写小论文时,回来补充高中的博客。。)

面对密码学中的大数问题,如大素数检验,大合数分解,精确的算法在现实的机器下难以实现,所以有了概率算法。

 

首先讲大素数检验

现有的概率检验算法,基本逻辑框架是,对于一个正奇数n,令集合S={1,…,n-1},存在一个S的子集W,W满足两个性质:

  1. 当给出一个a∈S ,能在较快的时间(多项式时间复杂度)内,判断是否有 a∈W;
  2. 若n为素数,则W=S ;若n为合数,则|W| <= k|S| = k(n-1),  k是确定的常数且k∈(0,1)

简单理解:若a∈S而a∉W,则能够判定n不是素数。一个合数n,有k的概率不能被检验出来。

检验的流程:每次独立随机生成 a∈S,对n作上述判定。经过t轮判断后,结束检验。

此时,合数n依然被误认为是素数的概率<=kt,t足够大时,就几乎不会出错了。

 

目标就是构造这样“良好的W”:

①很弱的办法——公约数检验(我起的名字)

  $W=\{a  | gcd(a,n)=1,a \in S\}$  ,也就是说,随机生成的a必须和n有“非1公约数”,才能判定n不是素数。

  这时候,$|W|=φ(n)$,(φ-欧拉函数),$|W| \leq n-\sqrt{n}$ ,(考虑$n=p^{2}$,p为质数,这种情况下左式取等号),显然不满足良好W的第二条性质。

②尝试改进 ——“费马素性检验”算法

  费马小定理:对于质数$n$,若正整数$a \in S$,且$gcd(a,n)=1$,则$a^{n-1}≡1$

  但是,费马小定理只是素数的必要不充分条件,逆命题不成立。

  有一些合数,对于部分a 满足费马小定理,这样的合数被称为“伪素数”(确切的说,是“a的伪素数”),最小的伪素数是341。

  

  假设$W=\{ a|a \in S 且gcd(a,n)=1 且 a^{n-1} ≡ 1 \}$

  下面证明一个定理:

  若$W=\{a_{1},a_{2},...,a_{k}\}$,如果$\exists a \in S 且 gcd(a,n)=1 , a^{n-1} \neq 1 ,则 (a \cdot a_{i})^{n-1} \neq 1$

  则,$\{a \cdot a_{1},a \cdot a_{2},...,a \cdot a_{k}\}$ 也是S的子集, 且与W无交集。

  因此,$|W| \leq \frac{1}{2} |S|$。

 

  由上定理知,对于一个n,只要存在$a \in S$可以检验出n不是素数,则该检验方法就能满足“良好W”的性质。

  实际上,这种算法确实已经很棒了,优先取2,3,5,7等小质数,可以很快淘汰掉绝大部分合数。

  但是,在伪素数中,还有一类数——卡迈尔数。它对任何$a \in S$都满足费马小定理,最小的卡迈尔数是561。

  虽然,1亿以内只有255个卡迈尔数,可一旦遇到了,费马素性检验就退化成了①。

 

 ③再次改进——Miller_rabin算法

  二次探测定理:  对于质数$n$,若正整数$a \in S$,且$a^{2} \equiv 1 (mod n)$,则 a=1或-1

 算法原理:

  对于正奇数n,$n-1=r2^{s}$,r为奇数。

  若n为素数,则$a^{r2^{s}} \equiv 1$,  则,$a^{r2^{s-1}} = 1或-1$ ;若为1,则,$a^{r2^{s-2}} = 1或-1$ ……

   由此得到,素数n,应满足:$\forall a \in S,\{ a^{r},a^{r2^{1}},a^{r2^{2}},...,a^{r2^{s-1}} \}$,要么全为1,要么有一个-1(其后每一项都为1)。

  令W={满足上述条件的a}

 

  可以证明$|W| \leq \frac{1}{4} |S|$ ,且不像②那样依赖于n或者a。

   这样,我们就得到了一个“良好的W”,能出色的完成大素数检验的任务了。

 

下面补充Miller_rabin一次误判概率$\leq \frac{1}{4}$的证明,不感兴趣的可以跳过。

 定理1:

   对正整数n,在mod n意义下的m阶有限群$\{x,x^{2},x^{3},\cdots,x^{m}=1\}$中,(x为生成元),有$gcd(m,k)$个元素,满足$(x^{i})^{k}=1$。

  证明很简单。若$d=gcd(m,k)$,则满足条件的i的集合$=\{\frac{m}{d},\frac{2m}{d},\cdots,m\}$。

 定理2:

  对于奇素数n,$n-1=h2^{s}$,h为奇数,则对于正奇数t,满足$x^{t2^{r}}=-1$的x的个数$= \begin{cases} 0,\qquad \qquad r \geq s \\ 2^{r}*gcd(h,t),\quad r < s \end{cases} $

   证明:

  Case1:$(x^{t2^{r}})^{h}=(x^{h2^{r}})^{t}=\big((x^{h2^{s}})^{2^{r-s}}\big)^{t}=1$,    又$\because h$为奇数,$\therefore x^{t2^{r}} \neq -1$

  Case2:设奇素数n 原根是g, $S=\{1,g^{1},\cdots,g^{n-2}\} ,g^{\frac{n-1}{2}}=-1$。

  即求,满足$(g^{i})^{t2^{r}}=-1$的i的个数,$i \in [0,n-2]$,

  则,$(n-1) \mid (it2^{r}-\frac{n-1}{2}) \qquad \Rightarrow \qquad (2^{s}h) \mid (it2^{r}-h2^{s-1}) $

  设$d=gcd(h,t)$  $\Rightarrow (2^{s-r} \cdot \frac{h}{d}) \mid (i \cdot \frac{t}{d}-2^{s-1-r} \cdot \frac{h}{d})$

   应取$i=2^{s-1-r} \cdot \frac{h}{d} \cdot (2k+1)$,k为整数,显然,在$i \in [0,n-2]$中,分别对应$k \in [0,2^{r}d-1]$,一共$2^{r}d$个。

 

 

另外,补充一个有一点点相关的知识:

  素数定理(关于素数个数的定理): π(x)表示不大于x的素数个数, π(x) ~ $\frac{x}{\ln{x}}$。

  这也说明,从$[1,n]$中随机选一个数,它是素数的概率大约是 $\frac {1}{ \ln{n}}$

  所以,即使是近50位的十进制大整数,也有约1%的概率是素数。

 

================================================================

1、a^(b-1)!=1 加上 二次探测  误判率据说是 1/4

(而这个板子只判了9次  误判概率好像有点高啊)

2、生日悖论

  期望 sqrt(n)个 [1,n]中随机的数  当中 有两个数是相同的

3、

 选取xi= (xi-1* xi-1 +1)%n  可以认为是会有循环节的 [1,n]中的随机函数

  根据生日悖论  ,循环节长度期望是 sqrt(n)

 假设 ,p是n的最小质因子, 则p<=sqrt(n)

  同理可得,xi%p的 循环节长度期望是sqrt(p)

 然后,我们用两个指针 i1,i2 分别以一倍速和二倍速扫这些数

  期望sqrt(p)步,i1与i2 在%p意义下是相同的(即在两个循环节的同一个位置,位置的差为一个循环节), 而它们在%n意义下是不同的。

  此时,gcd(i1-i2,n) 是p的倍数,n的约数,于是我们成功分解了一次n,期望用 n^(1/4)次。

  当然 这都是基于期望,也有可能循环节太短找不到,所以要做多次。

posted @ 2017-02-06 11:30  cyz666  阅读(133)  评论(0)    收藏  举报