fermat.cc

Go to the documentation of this file.
00001 
00007 void fermat_like_method()
00008 {
00009   /* Fermat-ähnliche Methode:
00010      Sei N=p*q (hier ausnahmsweise p,q nichtnotwendigerweise prim)
00011      und sei M=m1*m2 ein Multiplikator, so dass m1*q ungefähr m2*p entspricht.
00012      Dann ist (m1*q)*(m2*p)=(m1*m2)*(q*p)=M*N.
00013 
00014      Wir definieren R=floor(sqrt(M*N)).
00015      Der Ansatz ist nun, ein delta zu finden, so dass Q := (R+delta)^2 - M*N
00016      eine Quadratzahl ergibt, denn dann folgt (R+delta)^2 - Q = 0 (mod N),
00017      was gleichbedeutend ist zu (R+delta+sqrt(Q))*(R+delta-sqrt(Q)) = 0 (mod N).
00018      Mit gcd(R+delta+sqrt(Q),N) wäre dann ein Teiler von N gefunden...
00019        
00020      Diese Methode ist zwar nicht besonders effizient, da sie eher einer
00021      Probedivision entspricht; sie hilft aber, solche Zahlen besonders
00022      schnell zu faktorisieren, die auf "allzu naive" Weise als
00023      "besonders schwer" zu faktorisierende Zahlen konstruiert sind.
00024      So können zum Beispiel Produkte der Form
00025        N:= p*nextprime(10*p+"kleiner Offset")
00026      effizient zerlegt werden.
00027   */
00028 #ifdef VERBOSE_NOTICE
00029   cout << "starting Fermat factorization method" << endl;
00030 #endif
00031   if (mpz_sizeinbase(n,10)<50)
00032    {
00033      cout << "number too small, it's not worthwhile do proceed; skipping fermat..." << endl;
00034      return;
00035    }
00036   
00037   const unsigned int Witnesses = 4;
00038   const unsigned int Witness[Witnesses] = { 23*41*59, 35*29*37, 31*43*47, 61*67 };
00039   const unsigned int Maxbits = 65536;
00040   unsigned char squareflags[Maxbits]; 
00041 
00042   // initialize bitfield for witnessing non-squares via quadratic residues
00043   for (unsigned int j=0; j<Maxbits; ++j) squareflags[j]=0;
00044   for (unsigned int i=0; i<Witnesses; ++i)
00045    for (unsigned int j=0; j<Witness[i]; ++j) squareflags[(j*j)%Witness[i]] |= 1<<i;
00046 
00047   mpz_t c,r,h;
00048   mpz_init(c); mpz_init(r); mpz_init(h);
00049 
00050   const unsigned int k_max = 0x100; // or 0x040 (to be less exhaustive)
00051   for (unsigned int k=0; k<k_max; ++k)
00052     {
00053 #ifdef REACT_ON_SIGUSR
00054       if (USRSignalHandler.got_SIGUSR1()) break;
00055       if (USRSignalHandler.got_SIGUSR2()) break;
00056 #endif
00057       mpz_set_ui(c,2*2*3*5*7*11*13*17*19); mpz_pow_ui(c,c,4);
00058       unsigned int m = 1;
00059       if (k&0x001) m*=2;
00060       if (k&0x002) m*=3;
00061       if (k&0x004) m*=5;
00062       if (k&0x008) m*=7;
00063       if (k&0x010) m*=11;
00064       if (k&0x020) m*=13;
00065       if (k&0x040) m*=17;
00066       if (k&0x080) m*=19;
00067       mpz_mul_ui(c,c,m);
00068 
00069       // Idea behind these multipliers given by example:
00070       // Let t be a (small) number, then
00071       //
00072       //              t^0   t^1   t^2   t^3   t^4
00073       //  t^4 covers  --- , --- , --- , --- , --- 
00074       //              t^4   t^3   t^2   t^1   t^0
00075       //
00076       //  which is identical to the sequence
00077       //
00078       //    1     1     
00079       //   --- , --- , 1 , t^2 , t^4
00080       //   t^4   t^2
00081       //
00082       // because p*q*t^4 = p*(q*t^4) = (p*t)*(q*t^3) = (p*t^2)*(q*t^2) = ...
00083       //
00084       //                        1     1    1
00085       // Similarly t^5 covers  --- , --- , - , t , t^3, t^5
00086       //                       t^5   t^3   t
00087 
00088 #if defined(VERBOSE_INFO)
00089       cout << "using Fermat multiplier " << c << "             \r" << flush;
00090 #endif
00091       mpz_mul(c,c,n); mpz_sqrt(r,c); mpz_mul(h,r,r); mpz_sub(h,h,c);
00092       mpz_mul_ui(r,r,2);
00093 
00094       struct { unsigned int h,r; } ring[Witnesses];
00095       for (unsigned int i=0; i<Witnesses; ++i)
00096        {
00097          ring[i].h=mpz_remainder_ui(h,Witness[i]);
00098          ring[i].r=mpz_remainder_ui(r,Witness[i]);
00099          //cout << "Witness " << i << ": " << ring[i].h << ", " << ring[i].r << endl;
00100        }
00101 
00102       for (unsigned int delta=1; delta<50000; ++delta)
00103         {
00104           //if (delta%10000==0) cout << "delta=" << delta << "\r" << flush;
00105           mpz_add(h,h,r); mpz_add_ui(h,h,1); mpz_add_ui(r,r,2); // compute next square: h=(x+1)^2=x^2+2x+1=h+r+1 (using r=2x)
00106           for (unsigned int i=0; i<Witnesses; ++i)
00107            {
00108              ring[i].h+=ring[i].r+1; if (ring[i].h>=Witness[i]) ring[i].h-=Witness[i];
00109              ring[i].r+=2; if (ring[i].r>=Witness[i]) ring[i].r-=Witness[i];
00110            }
00111 
00112           if (!(squareflags[ring[0].h] & 0x01)) continue;
00113           if (!(squareflags[ring[1].h] & 0x02)) continue;
00114           if (!(squareflags[ring[2].h] & 0x04)) continue;
00115           if (!(squareflags[ring[3].h] & 0x08)) continue;
00116           //cout << "delta=" << delta << endl;          
00117           if (mpz_perfect_square_p(h))
00118             {
00119 #if 1 || defined(VERBOSE_INFO)
00120               cout << endl << "delta=" << delta << ": Square detected..." << endl;
00121 #endif
00122               mpz_div_ui(r,r,2); mpz_sqrt(h,h); mpz_add(h,h,r);
00123               mpz_gcd(h,h,n);
00124               if (mpz_cmp_ui(h,1)!=0) 
00125                 {
00126                   mpz_divexact(n,n,h);
00127                   //cout << "t1=" << h << endl;
00128                   //cout << "t2=" << n << endl;
00129                   if (mpz_probab_prime_p(h,probab_prime_checks))
00130                     {
00131 #if 0
00132  // only for debugging...
00133 {
00134   mpz_t sum,N,x;
00135   mpz_init(sum); mpz_init(N); mpz_init(x);
00136   mpz_add(sum,n,h); mpz_div_ui(sum,sum,2); mpz_mul(N,n,h);
00137   mpz_sqrt(x,N); mpz_sub(sum,sum,x);
00138   cout << "phimat-value --> " << sum << endl;
00139   mpz_clear(x); mpz_clear(N); mpz_clear(sum); 
00140 }
00141 #endif
00142 
00143                       cout << h << " is factor." << endl;
00144                       std::ostringstream comment;
00145                       comment << " [fer]";
00146                       Factorization_to_file << MAL(h,comment) << flush;
00147                     }
00148                   else
00149                     {
00150                       fermat_like_method(); // try again...
00151                       mpz_swap(n,h);
00152                       if (mpz_probab_prime_p(h,probab_prime_checks))
00153                        {
00154                          cout << h << " is factor." << endl;
00155                          std::ostringstream comment;
00156                          comment << " [fer]";
00157                          Factorization_to_file << MAL(h,comment) << flush;
00158                        }
00159                       else
00160                        {
00161                          cout << h << " is a composite factor." << endl;
00162                          if (Potenztest(h)) Factorization_to_file << " [fer]" << flush;
00163                          else
00164                           {
00165                             std::ostringstream comment;
00166                             comment << " [fer] [composite]";
00167                             Factorization_to_file << MAL(h,comment) << flush;
00168                           }
00169                        }
00170                     }
00171                   if (!mpz_probab_prime_p(h,probab_prime_checks)) fermat_like_method(); // and try again once more...
00172                   k=k_max; break;
00173                 }
00174             }
00175         }
00176     }
00177 #ifdef VERBOSE_INFO
00178   cout << endl;
00179 #endif
00180   mpz_clear(h); mpz_clear(r); mpz_clear(c);
00181 }
00182 
00183 
00184 #include "utils.H"
00185 #include <vector>
00186 #include <algorithm>
00187 
00188   class entry
00189   {
00190    private:
00191     mp_limb_t hashval;
00192     friend class phimahashvecs;
00193     static unsigned int iL;
00194     static mpz_t L;
00195    public:
00196     static mpz_t Base;
00197     entry(const unsigned int index)
00198      {
00199        if (index==iL+1)
00200         {
00201           // shortcut, inc case that items are inserted "in order"
00202           ++iL; mpz_mul(L,L,Base); mpz_mod(L,L,n);
00203         }
00204        else
00205         {
00206           mpz_powm_ui(L,Base,index,n);
00207         }
00208        hashval=mpz_getlimbn(L,0);
00209      }
00210 
00211     ~entry() { }
00212     const mpz_t& get_mpz(const unsigned int index) const
00213      {
00214        if (index==iL) return L;
00215        else
00216         {
00217           mpz_powm_ui(L,Base,index,n);
00218           return L;
00219         }
00220      }
00221     mp_limb_t get_hash() const { return hashval; }
00222     bool operator< (const entry &rhs) const
00223      {
00224        // important: we do only compare the hash values, not the multiple
00225        // precision numbers!
00226        return (hashval<rhs.hashval);
00227      }
00228     bool operator== (const entry &rhs) const
00229      {
00230        return (hashval==rhs.hashval);
00231      }
00232     signed int compare(const mp_limb_t rhs) const
00233      {
00234        // compare based on hash value
00235        return (hashval<rhs) ? -1 : (hashval>rhs) ? 1 : 0;
00236      }
00237 
00238   };
00239 
00240  class phimavec : private std::vector<entry>
00241  {
00242   private:
00243    friend class phimahashvecs;
00244    double d_linear_approx_multiplicator; 
00245   public:
00246    phimavec() : d_linear_approx_multiplicator(0.0) { }
00247    ~phimavec() { }
00248    void sort()
00249     {
00250       //cout << "sorting " << size() << " items." << endl;
00251       std::sort(begin(),end());
00252       //size_t s=size();
00253       erase(std::unique(begin(),end()),end()); // remove duplicate hash values
00254       //if (size()!=s) cout << s-size() << " duplicates removed." << endl;
00255       d_linear_approx_multiplicator = static_cast<double>(size())/(at(size()-1).get_hash()-at(0).get_hash());
00256     }
00257    bool found(const mpz_t &val) const
00258     {
00259 #ifdef VERBOSE_INFO
00260       static unsigned int cs = 0;
00261 #endif
00262 
00263       // binary search
00264       signed int L=0, R=size()-1;
00265       const mp_limb_t hash = mpz_getlimbn(val,0);
00266 
00267 #if 1
00268       // linear approximation of the index
00269       // (uniform distribution -> much better than binary search!)
00270       const signed int d = static_cast<signed int>(static_cast<double>(hash) * d_linear_approx_multiplicator);
00271       //if ( d<L || d>R ) return false; // should be outside the interval (but there are rounding errors...)
00272       const signed int dd = 127;
00273       __builtin_prefetch(&operator[](d),0,1);
00274       if (d-dd>L && at(d-dd).get_hash()<hash) L=d-dd;
00275       if (d+dd<R && at(d+dd).get_hash()>hash) R=d+dd;
00276       //cout << "-->L: " << L << " R: " << R << " d: " << d << endl;
00277 #endif
00278 
00279       while (R>=L)
00280        {
00281          //cout << "searching " << L << " - " << R << endl;
00282          const signed int pos = (L+R)>>1;
00283          __builtin_prefetch(&operator[]((L+pos-1)>>1),0,0);
00284          __builtin_prefetch(&operator[]((R+pos+1)>>1),0,0);
00285          const signed int vgl = operator[](pos).compare(hash);
00286 #ifdef VERBOSE_INFO
00287          ++cs;
00288 #endif
00289          if (vgl==0)
00290           {
00291 #ifdef VERBOSE_INFO
00292             cout << cs << " comparisons performed so far" << endl; 
00293 #endif
00294             return true;
00295           }
00296          if (vgl<0) L=pos+1; else R=pos-1;
00297        }
00298       //cout << "L: " << L << " R: " << R << " d: " << d << " size:" << size() << endl;
00299 
00300       return false; 
00301     }
00302  };
00303 
00304 
00305  class phimahashvecs
00306  {
00307   private:
00308    static const mp_size_t hashlimb = 1; // for mpz_getlimbn(<number>,hashlimb)
00309    static const unsigned int lookup_bins = 0x1000;
00310    static const mp_limb_t limbmask = lookup_bins-1;
00311    phimavec lookup[lookup_bins];
00312    size_t myIntervalsize;
00313    const static unsigned int redundancy = 8;
00314   public:
00315    phimahashvecs() : myIntervalsize(0)
00316     {
00317       entry::iL=0; mpz_init_set_ui(entry::L,1);
00318     }
00319    ~phimahashvecs() { }
00320 
00321    size_t size() const
00322     {
00323       size_t s = 0;
00324       for (unsigned int i=0; i<lookup_bins; ++i) s+=lookup[i].size();
00325       return s;
00326     }
00327    size_t max_size() const { return lookup[0].max_size(); }
00328  
00329    void insert(const unsigned int i)
00330     {
00331       const entry e(i);
00332       const mp_limb_t h=mpz_getlimbn(e.get_mpz(i),hashlimb) & limbmask;
00333       lookup[h].push_back(e);
00334     }
00335    void prepare(const size_t tablesize)
00336     {
00337       // for optimal RAM requirements we precalculate the number of items
00338       // in each lookup bin.
00339 
00340       cout << "optimizing memory layout" << endl;
00341       entry::iL=0; mpz_set_ui(entry::L,1);
00342       size_t bin_size[lookup_bins] = { 0 };
00343       for (unsigned int i=0; i<tablesize; ++i)
00344        {
00345          const mp_limb_t h=mpz_getlimbn(entry::L,hashlimb) & limbmask;
00346          ++bin_size[h];
00347          mpz_mul(entry::L,entry::L,entry::Base); mpz_mod(entry::L,entry::L,n);
00348        }
00349       entry::iL=0; mpz_set_ui(entry::L,1);
00350       for (unsigned int i=0; i<lookup_bins; ++i)
00351        {
00352          //cout << "binsize[" << i << "]=" << bin_size[i] << endl;
00353          lookup[i].reserve(bin_size[i]);
00354        }
00355  
00356       // and now actually insert the items
00357       cout << "inserting items" << endl;
00358       for (size_t i=0; i<tablesize; ++i) insert(i); // implicit constructor call
00359 
00360       myIntervalsize = size()-redundancy; // important! call it before duplicate hash values are erased!
00361 
00362 #ifdef VERBOSE_INFO
00363       size_t s = 0;
00364       for (unsigned int i=0; i<lookup_bins; ++i)
00365        {
00366          lookup[i].sort();
00367          s+=lookup[i].size();
00368          cout << s << " items prepared.\r" << flush;
00369        }
00370       cout << endl;
00371 #else
00372       for (unsigned int i=0; i<lookup_bins; ++i) lookup[i].sort();
00373 #endif
00374 
00375     }
00376 
00377    size_t Intervalsize() const { return myIntervalsize; }
00378 
00379    bool found(const mpz_t &val) const
00380     {
00381       // first hash into lookup, then do binary search inside this bin
00382       const mp_limb_t hash = mpz_getlimbn(val,hashlimb) & limbmask;
00383       if (!lookup[hash].found(val)) return false;
00384 
00385       // now it gets more complicated:
00386       // a possible candidate has been found based on equal hash values;
00387       // perform up to <redundancy> additional checks to reduce the
00388       // risk of false positives
00389       //cout << "candidate found; checking..." << endl;
00390       bool retval=true;
00391       mpz_t x;
00392       mpz_init_set(x,val);
00393       for (unsigned int i=0; i<redundancy; ++i)
00394        {
00395          mpz_mul(x,x,entry::Base); mpz_mod(x,x,n);
00396          const mp_limb_t hash = mpz_getlimbn(x,hashlimb) & limbmask;
00397          retval=lookup[hash].found(x);
00398          //cout << "candidate " << ((retval) ? "passed" : "failed") << " test " << i << endl;
00399          if (!retval) break;
00400        }
00401      mpz_clear(x);
00402      return retval;
00403     }
00404 
00405    bool found(const mpz_t &val, unsigned int &the_index) const
00406     {
00407       // first hash into lookup, then do binary search inside this bin
00408       if (!found(val)) return false;
00409 
00410       // a candidate has been found with high probability
00411       // to determine "the_index", we perform a binary search!
00412 
00413       mpz_t x;
00414       mpz_init(x);
00415       size_t d = Intervalsize()-1;
00416       { 
00417         register unsigned int i = 0;
00418         while (d>>=1) ++i;
00419         d=1<<i;
00420       }
00421       cout << "candidate found; performing binary search for the_index" << endl;
00422       size_t hhh=0;
00423       while (d)
00424        {
00425          mpz_powm_ui(x,entry::Base,hhh+d,n);
00426          mpz_invert(x,x,n); mpz_mul(x,x,val); mpz_mod(x,x,n);
00427          if (found(x)) hhh+=d;
00428          d>>=1;
00429        }
00430       mpz_powm_ui(x,entry::Base,hhh,n);
00431       if (mpz_cmp(x,val)!=0)
00432        {
00433          cout << "binary search failed? try slowsearch..." << endl;
00434          mpz_t y; mpz_init(y); mpz_invert(y,entry::Base,n);
00435          while (hhh>0)
00436           {
00437             mpz_mul(x,x,y); mpz_mod(x,x,n); --hhh;
00438             if (mpz_cmp(x,val)==0) break;
00439           }
00440          mpz_clear(y);
00441        }
00442       the_index=hhh;
00443       cout << "the_index = " << the_index << endl;
00444       mpz_clear(x);
00445       return true;
00446     }
00447  };
00448 
00449 
00450 unsigned int entry::iL = 0;
00451 mpz_t entry::L, entry::Base;
00452 
00453 extern unsigned long int allowed_memory_usage_KB(void);
00454 
00455 
00456 class lambda_delta
00457 {
00458  private:
00459    mpf_t SQRTN, DELTA;
00460    mpf_t fres, f1res;
00461    static const unsigned int bits = 2048;
00462  public:
00463 
00464   static void Delta_by_ratio(mpz_t &Delta, const mpz_t n, const double ratio_p=1.0, const double ratio_q=1.0)
00465    {
00466      mpf_set_default_prec(bits);
00467      mpf_t x,y;
00468      mpf_init(x); mpf_init(y);
00469      mpf_set_d(x,ratio_p); mpf_set_d(y,ratio_q);
00470      mpf_div(x,x,y); // full precision division (important!)
00471      mpf_sqrt(x,x);
00472      mpf_ui_div(y,1,x); mpf_add(x,x,y); mpf_sub_ui(x,x,2);
00473      mpf_set_z(y,n); mpf_sqrt(y,y); mpf_mul(x,x,y);
00474      mpz_set_f(Delta,x);
00475    }
00476 
00477 
00478   lambda_delta(const mpz_t n, const mpz_t delta)
00479    {
00480      mpf_set_default_prec(bits);
00481      mpf_init(SQRTN); mpf_set_z(SQRTN,n); mpf_sqrt(SQRTN,SQRTN); // mpf_floor(SQRTN,SQRTN);
00482      mpf_init(DELTA); mpf_set_z(DELTA,delta);
00483      mpf_init(fres); mpf_init(f1res);
00484    }
00485   ~lambda_delta()
00486    {
00487      mpf_clear(f1res); mpf_clear(fres);
00488      mpf_clear(DELTA); mpf_clear(SQRTN);
00489    }
00490 
00491   const mpf_t& f(const mpf_t &x)
00492    {
00493      mpf_t h;
00494      mpf_init(h);
00495      mpf_sqrt(fres,x); mpf_ui_div(h,1,fres); mpf_add(fres,fres,h);
00496      mpf_sub_ui(fres,fres,2);
00497      mpf_mul(fres,fres,SQRTN);
00498      mpf_sub(fres,fres,DELTA);
00499      mpf_clear(h);
00500      return fres;
00501    }
00502   const mpf_t& f1(const mpf_t &x)
00503    { 
00504      mpf_t h;
00505      mpf_init(h);
00506      mpf_sqrt(f1res,x); mpf_ui_div(f1res,1,f1res);
00507      mpf_pow_ui(h,f1res,3); mpf_sub(f1res,f1res,h);
00508      mpf_div_ui(f1res,f1res,2);
00509      mpf_mul(f1res,f1res,SQRTN);
00510      mpf_clear(h);
00511      return f1res;
00512    }
00513 #if 0   
00514   void newton()
00515    {
00516      mpf_t x0,x1;
00517      mpf_init(x0);
00518      mpf_init_set_d(x1,1.1);
00519      do
00520       {
00521         mpf_set(x0,x1);
00522         mpf_div(x1,f(x0),f1(x0)); mpf_sub(x1,x0,x1);
00523         
00524       } while (mpf_eq(x1,x0,bits-64)==0);
00525      cout << "newton: "; mpf_out_str(NULL,10,50,x1); cout << endl;
00526      //mpf_sqrt(x0,x1); mpf_div(x0,SQRTN,x0);
00527      //mpz_t p_bound; mpz_init(p_bound); mpz_set_f(p_bound,x0);
00528      //cout << "N=p*q, p<" << p_bound << endl;
00529      //int i; std::cin >> i;
00530      mpf_clear(x1); mpf_clear(x0);
00531    }
00532 #endif     
00533 };
00534 
00535 
00536 void phimat2()
00537 {
00538   cout << "Starting experimental Phimat factoring method." << endl;
00539   cout << "Warning: This method runs very long except for special constructed numbers" << endl;
00540   cout << "of the form N=p*q; p,q prime and q=p+x, x small compared to p." << endl;
00541 
00542   mpz_init_set_ui(entry::Base,2);
00543 
00544   mpz_t V,x;
00545   mpz_init(x); mpz_sqrt(x,n); mpz_mul_ui(x,x,2);
00546 
00547   unsigned int step=2;
00548   mpz_t Delta,initial_Delta,stop_Delta;
00549   mpz_init_set_ui(Delta,0);
00550   mpz_init(stop_Delta);
00551 
00552   // if this small block is omitted, then default ratio 1:1 is used.
00553   // Otherwise calculate Delta based on the assumption, that
00554   // n=p*q and p_ratio*p = q_ratio*q  (approximately)
00555   lambda_delta::Delta_by_ratio(Delta,n,1.0,1.0);
00556   lambda_delta::Delta_by_ratio(stop_Delta,n,2.0,1.0);
00557   
00558   mpz_sub_ui(Delta,Delta,mpz_remainder_ui(Delta,3*32));
00559   mpz_init_set(initial_Delta,Delta);
00560 
00561   {
00562     unsigned int r = mpz_remainder_ui(n,32);
00563     unsigned int disp=0; // displacement
00564     if (r%4==1) { disp=2; step=4; }
00565     else if (r%8==3) { disp=4; step=8; }
00566     else if (r%8==7) { disp=0; step=8; }
00567     else { cerr << "unknown state " << r << endl; exit(1); }
00568     if (mpz_remainder_ui(n,6)==5) { step*=3; disp*=3; }
00569     cout << "phimat multiplier is " << step << endl;
00570     step/=2;
00571 
00572     r=mpz_remainder_ui(x,step);
00573     mpz_sub_ui(Delta,Delta,r); mpz_add_ui(Delta,Delta,disp);
00574     mpz_sub_ui(x,x,r); mpz_add_ui(x,x,disp);
00575   }
00576 
00577   mpz_init_set(V,n); mpz_add_ui(V,V,1); mpz_sub(V,V,x);
00578   mpz_powm(V,entry::Base,V,n);
00579   mpz_powm_ui(entry::Base,entry::Base,step,n);
00580 
00581   // remark:
00582   // the "Delta" value for phimat should be exactly twice the value
00583   // of the "Fermat"-Delta value for the same number.
00584   // This is because "phimat" tries to determine p+q, whereas
00585   // the "Fermat" procedure calculates implicitly (p+q)/2.
00586   // Both procedures terminate, when "Delta" has reached this value.
00587   // (Well, maybe phimat terminates earlier with a very low probability,
00588   // because the "congruency" 2^(N+1) == 2^(p+q) (mod N) is not necessarily
00589   // a (perfect) "identity" (and we do not know for certain, that p,q are the
00590   // only prime factors of N).
00591 
00592 
00593   phimahashvecs entries; // structure of indices (sorted by powers)
00594 
00595   {
00596     //const unsigned int tablesize = 0x400000;
00597     const unsigned int t1 = entries.max_size();
00598     unsigned int t2 = static_cast<size_t>((allowed_memory_usage_KB()/sizeof(entry)));
00599     if (t2>65536) t2-=32768;
00600     t2*=1024;
00601     const unsigned int tablesize = MIN(t1,t2);
00602     cout << "Creating table of " << tablesize << " items." << endl;
00603     cout << "This may take a while..." << endl;
00604     entries.prepare(tablesize);
00605     cout << "Okay, items are prepared. Now searching for factors..." << endl;
00606   }
00607 
00608 
00609   {
00610     // correction for initial Delta (in case it's not zero)
00611     mpz_t x;
00612     mpz_init(x);
00613     mpz_div_ui(x,initial_Delta,step);
00614     mpz_powm(x,entry::Base,x,n);
00615     mpz_invert(x,x,n); // we walk downwards...
00616     mpz_mod(x,x,n);
00617     mpz_mul(V,V,x); mpz_mod(V,V,n);
00618     mpz_clear(x);
00619   }
00620 
00621   mpz_t PowIntervalStep;
00622   mpz_init_set(PowIntervalStep,entry::Base);
00623   mpz_powm_ui(PowIntervalStep,PowIntervalStep,entries.Intervalsize(),n);
00624   mpz_invert(PowIntervalStep,PowIntervalStep,n); // we walk downwards...
00625   mpz_mod(PowIntervalStep,PowIntervalStep,n);
00626 
00627   mpz_t TableStep;
00628   mpz_init_set_ui(TableStep,entries.Intervalsize()); mpz_mul_ui(TableStep,TableStep,step);
00629 
00630   for (unsigned int i=0; /* endlessly */ ; ++i)
00631    {
00632      unsigned int index;
00633      if (entries.found(V,index))
00634       {
00635         mpz_t x,y,z,myDelta;
00636         mpz_init(x); mpz_init(y); mpz_init(z); mpz_init_set(myDelta,Delta);
00637         mpz_set_ui(x,index); mpz_mul_ui(x,x,step); mpz_add(myDelta,myDelta,x);
00638         cout << "Found a candidate at Delta=" << myDelta << endl;
00639         mpz_sqrt(x,n); mpz_mul_ui(x,x,2); mpz_add(x,x,myDelta);
00640         mpz_mul(y,x,x); mpz_mul_ui(z,n,4); mpz_sub(y,y,z);
00641         mpz_sqrt(y,y); mpz_add(y,y,x);
00642         mpz_gcd(z,y,n); mpz_mod(z,z,n);
00643         if (mpz_cmp_ui(z,1)>0)
00644          {
00645            cout << "looks good :-)" << endl;
00646            mpz_set(Delta,myDelta); // accepted... :-)
00647 
00648            while (mpz_cmp_ui(n,1)!=0)
00649             {
00650              if (mpz_probab_prime_p(z,probab_prime_checks))
00651               {
00652                 cout << z << " is factor." << endl;
00653                 std::ostringstream comment;
00654                 comment << " [phimat]";
00655                 Factorization_to_file << MAL(z,comment) << flush;
00656               }
00657              else
00658               {
00659                 cout << z << " is a composite factor." << endl;
00660                 if (Potenztest(z)) Factorization_to_file << " [phimat]" << flush;
00661                 else
00662                  {
00663                    std::ostringstream comment;
00664                    comment << " [phimat] [composite]";
00665                    Factorization_to_file << MAL(z,comment) << flush;
00666                  }
00667               }
00668              mpz_divexact(n,n,z);
00669              mpz_set(z,n);
00670             }
00671          }
00672         mpz_clear(myDelta); mpz_clear(z); mpz_clear(y); mpz_clear(x);
00673         if (mpz_cmp_ui(n,1)==0) break;
00674       }
00675      mpz_add(Delta,Delta,TableStep);
00676      mpz_mul(V,V,PowIntervalStep); mpz_mod(V,V,n);
00677      if ((i&0x3ffff)==0)
00678       {
00679         if ((i&0x1ffffff)==0) // status report
00680          {
00681            mpz_t x,y,z;
00682            mpz_init(x); mpz_init(y); mpz_init(z);
00683            mpz_sqrt(x,n); mpz_mul_ui(x,x,2); mpz_add(x,x,Delta);
00684            mpz_mul(y,x,x); mpz_mul_ui(z,n,4); mpz_sub(y,y,z);
00685            mpz_sqrt(y,y); mpz_add(y,y,x);
00686            mpz_div_ui(y,y,2);
00687            mpz_div(x,n,y);
00688            cout << "new bound p<" << x << endl;
00689            mpz_clear(z); mpz_clear(y); mpz_clear(x);
00690            //cout << "stop_Delta: " << stop_Delta << endl;
00691            if (mpz_cmp(Delta,stop_Delta)>0) break;
00692          }
00693         cout << "Delta=" << Delta << '\r' << flush;
00694       }
00695    }
00696 
00697   // for validation reasons give the Delta for Fermat,
00698   // where the square could be found...
00699   mpz_div_ui(Delta,Delta,2);
00700   cout << "Fermat Delta would be " << Delta << endl;
00701 
00702   mpz_clear(TableStep); mpz_clear(PowIntervalStep);
00703   mpz_clear(initial_Delta); mpz_clear(stop_Delta); mpz_clear(Delta);
00704   mpz_clear(x); mpz_clear(V);
00705 
00706   mpz_clear(entry::Base);
00707 }
00708 
00709 
00710 
00711 void phimat(mpz_t n)
00712 {
00713   mpz_t x,y;
00714   mpz_init(x); mpz_init(y);
00715   
00716   mpz_mul_ui(x,n,4); mpz_sqrt(x,x); // x=trunc(2*sqrt(n));
00717   mpz_add_ui(y,n,1); mpz_sub(y,y,x); // y=n+1-x
00718   mpz_set_ui(x,2); mpz_powm(x,x,y,n); // x=2^y mod n;
00719 
00720   cout << "trying phimat..." << x << endl;
00721 
00722   //mpz_add_ui(y,n,1); mpz_div_ui(y,y,2);
00723   unsigned long int z=0;
00724   while (z<1000000000)
00725     {
00726       int p=mpz_scan1(x,0); z+=p; 
00727       mpz_tdiv_q_2exp(x,x,p);
00728       //cout << z << ": " << x << endl;
00729       if (mpz_cmp_ui(x,1)==0) break;
00730       mpz_add(x,x,n);
00731     }
00732 
00733   cout << z << ":" << x << endl;
00734   
00735   if (mpz_cmp_ui(x,1)==0)
00736     {
00737       cout << "x=1 ... " << endl;
00738       mpz_mul_ui(x,n,4); mpz_sqrt(x,x); mpz_add_ui(x,x,z); // x=p+q
00739       mpz_mul(y,x,x);
00740       mpz_sub(y,y,n); mpz_sub(y,y,n); mpz_sub(y,y,n); mpz_sub(y,y,n);
00741       mpz_sqrt(y,y); // y=p+q
00742       mpz_add(y,x,y); mpz_div_ui(y,y,2); // y=p
00743       mpz_div(x,n,y); // x=q
00744       mpz_mul(x,x,y);
00745       cout << x << endl; 
00746       if (mpz_cmp(x,n)==0) // wirklich echte Teiler ermittelt?
00747         {
00748           mpz_div(x,n,y); // x=q
00749           if (mpz_probab_prime_p(x,probab_prime_checks))
00750             {
00751               cout << x << " is factor." << endl;
00752               Factorization_to_file << MAL(x) << flush;
00753             }
00754           else
00755             {
00756               cout << x << " is a composite factor." << endl;
00757               Factorization_to_file << MAL(x) << " [composite]" << flush;
00758             }
00759           if (mpz_probab_prime_p(y,probab_prime_checks))
00760             {
00761               cout << y << " is factor." << endl;
00762               Factorization_to_file << MAL(y) << flush;
00763             }
00764           else
00765             {
00766               cout << y << " is a composite factor." << endl;
00767               Factorization_to_file << MAL(y) << " [composite]" << flush;
00768             }      
00769           mpz_set_ui(n,1);
00770         }
00771     }
00772   
00773   mpz_clear(x); mpz_clear(y);
00774 }

Generated on Wed Nov 7 23:29:25 2007 for Qsieve by  doxygen 1.5.4