Rabin_Miller

来源:互联网 发布:田众和时代网络 编辑:程序博客网 时间:2024/05/21 18:45
首先我们证明这样一个结论:如果p是一个素数的话,那么对任意一个小于p的正整数a,a, 2a, 3a, …, (p-1)a
除以p的余数正好是一个1到p-1的
排列。例如,5是素数,3, 6, 9, 12除以5的余数分别为3, 1, 4, 2,正好就是1到4这四个数。
反证法,假如结论不成立的话,那么就是说有两个小于p的正整数m和n使得na和ma除以p的余数相同。不妨假设n>m,
则p可以整除a(n-m)。但p是素
数,那么a和n-m中至少有一个含有因子p。这显然是不可能的,因为a和n-m都比p小。
用同余式表述,我们证明了:
(p-1)! ≡ a * 2a * 3a * … * (p-1)a (mod p)
也即:
(p-1)! ≡ (p-1)! * a^(p-1) (mod p)
两边同时除以(p-1)!,就得到了我们的最终结论:
1 ≡ a^(p-1) (mod p)

费马小定里的欧拉推广:a^φ(m) ≡ 1 (mod m)(其中φ(m)为与m互质的数的个数)

证明与费马小定理类似

但是费马小定理的逆命题并不正确,即,当满足a^(p-1) mod p = 1的数p不一定是素数,例如p=341,a=2,
而此时p=11*13

后来,人们又发现了561, 645, 1105等数都表明a=2时Fermat小定理的逆命题不成立。虽然这样的数不多,
但不能忽视它们的存在。于是,人们把所
有能整除2^(n-1)-1的合数n叫做伪素数(pseudoprime),意思就是告诉人们这个素数是假的。

不满足2^(n-1) mod n = 1的n一定不是素数;如果满足的话则多半是素数。这样,一个比试除法效率更高的
素性判断方法出现了:制作一张伪素数
表,记录某个范围内的所有伪素数,那么所有满足2^(n-1) mod n = 1且不在伪素数表中的n就是素数。之所以
这种方法更快,是因为我们可以使用
二分法快速计算2^(n-1) mod n 的值,这在计算机的帮助下变得非常容易;在计算机中也可以用二分查找有序
数列、Hash表开散列、构建Trie树等
方法使得查找伪素数表效率更高。

(1)计算奇数M,使得N=(2**r)*M+1

(2)选择随机数A<N

(3)对于任意i<r,若A**((2**i)*M) MOD N = N-1,则N通过随机数A的测试

(4)或者,若A**M MOD N = 1(即i=0时),则N通过随机数A的测试

(5)让A取不同的值对N进行5次测试,若全部通过则判定N为素数

另一种表述供参考,有点难理清:
首先选择一个代测n,计算b,b是2整除p-1的次数。然后计算m,使得n=1+(2^b)m。
(1) 选择一个小于n的随机数a。
(2) 设j=0(j<b)且z=a^m mod n

(3) 如果z=1或z=n-1,那麽p通过测试,可能使素数
(4) 如果j>0且z=1, 那麽n不是素数
(5) 设j=j+1。如果b且z<>n-1,设z=z^2 mod n,然后回到(4)。如果z=n-1,那麽n通过测试,可能为素数。
(6) 如果j=b 且z<>p-1,不是素数


  若N 通过一次测试,则N 不是素数的概率为 25%,若N 通过t 次测试,则N 不是

素数的概率为1/4**t。事实上取t 为5 时,N 不是素数的概率为 1/128,N 为素数的

概率已经大于99.99%。

  在实际应用中,可首先用300—500个小素数对N 进行测试,以提高拉宾米勒测试

通过的概率,从而提高测试速度。而在生成随机素数时,选取的随机数最好让 r=0,

则可省去步骤(3) 的测试,进一步提高测试速度
   */
  static boolean Witness(int a,int n)

  {

    int i,d=1,x;

    for (i=(int)Math.ceil(Math.log((double)n-1)/Math.log(2.0))-1;i>=0;--i) {

      x=d;

      d=(d*d)%n;

      if ((1==d) && (x!=1) && (x!=n-1))
        return true;

      if (((n-1)&(1<<i))>0)
        d=(d*a)%n;

     }

     return (d!=1);

  }

  static boolean Rabin_Miller(int n,int s)

  {

    int j,a;

    for (j=0;j<s;++j) {

    a=(int) (Math.random()*(n-2)+1);

    if (Witness(a,n))
      return false;

     }

     return true;

  }
  public static void main(String[] args) {
      // TODO Auto-generated method stub
     int range=100;
     int count=0; 
      for (int i=3;i<range;i+=2)
        if (Rabin_Miller(i,50)) {
            count++;
        System.out.print(i+"");
        if(count%15==0){
            System.out.println();
        }
        }
  }

}

Rabin -Miller算法是典型的验证一个数字是否为素数的方法。判断素数的方法是Rabin-Miller概率测试,那么他具体的流程是什么呢。假设我们要判断n是不是素数,首先我们必须保证n 是个奇数,那么我们就可以把n 表示为 n = (2^r)*s+1,注意s 也必须是一个奇数。然后我们就要选择一个随机的整数a (1<=a<=n-1),接下来我们就是要判断 a^s=1 (mod n) 或a^((2^j)*s)= -1(mod n)(0<=j如果任意一式成立,我们就说n通过了测试,但是有可能不是素数也能通过测试。所以我们通常要做多次这样的测试,以确保我们得到的是一个素数。(DDS的标准是要经过50次测试)
采用Rabin-Miller算法进行验算
首先选择一个代测n,计算b,b是2整除p-1的次数。然后计算m,使得n=1+(2^b)m。
(1) 选择一个小于n的随机数a。
(2) 设j=0(j<b)且z=a^m mod n

(3) 如果z=1或z=n-1,那麽p通过测试,可能使素数
(4) 如果j>0且z=1, 那麽n不是素数
(5) 设j=j+1。如果b且z<>n-1,设z=z^2 mod n,然后回到(4)。如果z=n-1,那麽n通过测试,可能为素数。
(6) 如果j=b 且z<>p-1,不是素数

[cpp] view plaincopyprint?

  1. #include<iostream.h>   
  2. #include<time.h>   
  3. #include<stdlib.h>   
  4.   
  5. //随机数产生器   
  6. //产生m~n之间的一个随机数   
  7. unsigned long random(unsigned long m,unsigned long n)  
  8. {  
  9.     srand((unsigned long)time(NULL));  
  10.     return(unsigned long)(m+rand()%n);  
  11. }  
  12. //模幂函数   
  13. //返回X^YmodN   
  14. long PowMod(long x,long y,long n)  
  15. {  
  16.     long s,t,u;  
  17.       
  18.     s=1;t=x;u=y;  
  19.     while(u){  
  20.         if(u&1)s=(s*t)%n;  
  21.         u>>=1;  
  22.         t=(t*t)%n;  
  23.     }  
  24.     return s;  
  25. }  
  26.   
  27.   
  28. //Rabin-Miller素数测试,通过测试返回1,否则返回0。   
  29. //n是待测素数。   
  30. //注意:通过测试并不一定就是素数,非素数通过测试的概率是1/4   
  31.   
  32. int RabinMillerKnl(unsigned long n)  
  33. {  
  34.     unsigned long b,m,j,v,i;  
  35.     //先计算出m、j,使得n-1=m*2^j,其中m是正奇数,j是非负整数   
  36.     m=n-1;  
  37.     j=0;  
  38.     while(!(m&1))  
  39.     {  
  40.         ++j;  
  41.         m>>=1;  
  42.     }  
  43.     //随机取一个b,2<=b<n-1   
  44.     b=random(2,m);  
  45.     //计算v=b^mmodn   
  46.     v=PowMod(b,m,n);  
  47.     //如果v==1,通过测试   
  48.     if(v==1)  
  49.     {  
  50.         return 1;  
  51.     }  
  52.       
  53.     i=1;  
  54.     //如果v=n-1,通过测试   
  55.     while(v!=n-1)  
  56.     {  
  57.         //如果i==l,非素数,结束   
  58.         if(i==j)  
  59.         {  
  60.             return 0;  
  61.         }  
  62.         //v=v^2modn,i=i+1   
  63.         v=PowMod(v,2,n);  
  64.         i++;  
  65.     }  
  66.     return 1;  
  67. }  
  68. intmain()  
  69. {  
  70.     unsigned long p;  
  71.     int count=0;  
  72.     cout<<"请输入一个数字"<<endl;  
  73.     cin>>p;  
  74.     for(int temp=0;temp<5;temp++)  
  75.     {  
  76.         if(RabinMillerKnl(p))  
  77.         {  
  78.             count++;  
  79.         }  
  80.         else  
  81.             break;  
  82.           
  83.     }  
  84.       
  85.     if(count==5)  
  86.         cout<<"一共通过5次测试,是素数!"<<endl;  
  87.     else  
  88.         cout<<"不是素数"<<endl;  
  89.     return 0;  

原创粉丝点击