首页
社区
课程
招聘
[旧帖] [原创][邀请码已发]密码学基本算法--数域筛法的改进 0.00雪花
发表于: 2010-10-14 10:50 1719

[旧帖] [原创][邀请码已发]密码学基本算法--数域筛法的改进 0.00雪花

2010-10-14 10:50
1719
密码破解中对于计算的要求比较,所以最基本的要求是算法简单快速。对于RSA大数分解中,经常用到求素数,对于大素数的生成,需要用到一些概率性算法,所以要对算法生成的P进行基本的验证。为了使算法不犯低级的错误,最基本的是用小素数表进行检验。
对于小素数的生成(以下用2^23内全部素数为例),数域筛法是快速有效的。但是传统的筛法对于个人的计算机来说,需要很长的时间,甚至一天一夜也无法算出。所以我做了些改进,原始的筛法简单的比较了一下。
采用两种方法进行,分别是传统的试除法和埃拉托斯特尼(Eratosthenes)筛法,也就是数域筛法。
1.传统的试除法基本思想很简单,在判断n是否是素数时,用作除数的所有整数都小于【根号n】(郁闷,连基本的数学符号都打不出来,建议斑竹们向领导们提议一下,增添这个功能) ,如果这些数中的某任意一个数可以整除n,那么n就不是素数(整数2除外)。这样逐个生成,直到所要求的上限。
这种算法可以通过只检验奇数来改进,但总体来说是效率非常低的算法。实验的程序比较简单,其伪码可以表示如下:
Test(n)
{
r←2
while (r< )
{
If(r∣n)return “合数”
r←r+1
}
return “素数”
}
分析算法的复杂度,如果假定每一个算术运算只用一比特的操作(不是实际的运算),那么这个算法的比特运算复杂度就是【2的nb次幂后再开平方】--表达一个指数幂真复杂……         其中nb是n的比特数,可以表示成为O(【2的nb次幂后再开平方】),如果n非常大的时候,这种算法是不可能的。这还只是判断一个素数。对于生成2^23以下所有素数,计算量是非常大的。
2.埃拉托斯特尼(Eratosthenes)筛法的具体做法是,先把n个自然数按次序排列起来。1不是素数,也不是合数,要划去。第二个数
2是素数留下来,而把2后面所有能被2整除的数都划去。2后面第一个没划去的数是3,把3留 下,再把3后面所有能被3整除的数都划去。3后面第一个没划去的数是5,把5留下,再把5后 面所有能被5整除的数都划去。这样一直做下去,就会把不超过n的全部合数都筛掉,留下的就是不超过n的全部素数。
针对这种算法,本组分别做了两种实验。
实验(1)的主要代码如下:
void PrimeNumber2()
{
     int Max[MAX_NUMBER/2];
     memset(Max,0,MAX_NUMBER);
     Max[0] = 2;     int cout = 1;
     bool bflag = true;
     for(int i = 3; i < MAX_NUMBER; ++i)
     {
         bflag = true;
         for (int j = 0; j < cout; ++j)
         {
              if(i%Max[j] == 0)
              {
                   bflag = false;
                   break;
              }
         }
         if(bflag)
         {
              Max[cout++] = i;
         }
     }
}
实验(1)在判断过程中用到的除法,我们知道在计算机中做除法的运算总是速度慢的,所以在实验生成2^23以下全部素数时,运算的时间非常长,甚至是几个小时也很难完成。
实验(2)做了以下改进,首先对于偶数除2以外都不是素数,程序可以只针对奇数运算。将除法改为乘法来判断,只检测到【根号n】 。实验主要程序如下:
void prime()
{

        clock_t start, finish;
        start = clock();
        char *primes = new char[MAX_NUMBER+1];
        for( int i=0; i<MAX_NUMBER; i=i+2)
                primes[i] = '0';
        for( int i=1; i<MAX_NUMBER; i=i+2)
                primes[i] = '1';
        primes[1] = '0';
        primes[2] = '1';
        primes[MAX_NUMBER] = '\0';
        int M = (int)sqrt((float)MAX_NUMBER);
        for( int i=3; i<=M; )
        {
                int b=0;
                for( int n=3; ; n=n+2)
                {
                        b = n*i;
                        if(b>=MAX_NUMBER)break;
                        primes = '0';
                }
                do
                {i++;}
                while( primes[i] !='1');
        }
        primes[MAX_NUMBER] = '\0';
        finish = clock();
        double duration = (double) (finish - start)/ CLOCKS_PER_SEC;
        printf( "%2.1f seconds\n", duration );
        cout<<"保存文件"<<endl;
        FILE *fp;
        fp = fopen("primes.txt","w");
        for(int i=0;i<MAX_NUMBER;i++)
        {
                if( primes[i] =='1')fprintf(fp,"%d ",i);
        }
        delete []primes;
        fclose(fp);
int _tmain(int argc, _TCHAR* argv[])
{
        prime();
        return 0;
}
运行后得到的实验结果非常理想,生成2^23以下全部素数只用了0.3秒。得到了非常大的改善和提高。

主要是改变除法的基本测试,不妥之处,请大家批评。或者是有更好的方法的,请告诉我。
邀请码已发,在此谢谢版主!!

[课程]Linux pwn 探索篇!

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 92
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
貌似2^23一下的素数生成的时间本来就是在1秒以下的、。。。

而且楼主的线性筛法的(1)的代码根本不是线性筛法。
2010-10-14 12:10
0
雪    币: 92
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
附上快速线性筛法:
   1. #include<iostream>      
   2. using namespace std;      
   3. const long N =8388609;        //N=2^23+1;
   4. long prime[N] = {0},num_prime = 0;      
   5. int isNotPrime[N] = {1, 1};      
   6. int main()      
   7. {      
   8.     for(long i = 2 ; i < N ; i ++)      
   9.     {      
  10.         if(! isNotPrime[i])      
  11.             prime[num_prime ++]=i;    
  12. //关键处1            
  13.         for(long j = 0 ; j < num_prime && i * prime[j] <  N ; j ++)      
  14.         {      
  15.             isNotPrime[i * prime[j]] = 1;      
  16.             if( !(i % prime[j]))  //关键处2    
  17.                 break;      
  18.         }      
  19.     }      
  20.     return 0;      
  21. }           
2010-10-14 12:14
0
雪    币: 1022
活跃值: (31)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
数域筛法的改进?
请问你的哪一个算法是数域筛法?改进的地方也没看到啊!
数域筛法主要是用来分解大整数的,并不是用来生成小素数。
2010-10-14 12:21
0
雪    币: 12
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
比较高深,慢慢消化。
2010-10-14 12:26
0
雪    币: 52
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
可能我没说清楚吧,主要是针对试除法的比较。而且试除法我的确测试过,N个小时也没跑出来。
不知道你说的线性筛法指什么,可能我们大家用的称呼不同。
谢谢你给的代码哈!
2010-10-14 15:05
0
雪    币: 52
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
2是数域筛法。
改进在帖子的最后说的,只是改除法为乘法做的,除法总是浪费时间的,所以只是在测试节省时间。
数域筛法是用来大数分解的,这里只是在构造小素数表为后面的分解服务。
2010-10-14 15:09
0
雪    币: 8
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
   坐下来慢慢消化
2010-10-14 15:13
0
游客
登录 | 注册 方可回帖
返回
//