prime.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002 
00003 prime.cpp -- see prime.hpp.
00004 
00005 This file is a part of Arageli library.
00006 
00007 Copyright (C) Nikolai Yu. Zolotykh, 2005
00008 Copyright (C) Aleksey Bader, Russia, 2006
00009 
00010 *****************************************************************************/
00011 
00012 #include "config.hpp"
00013 
00014 #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || \
00015     defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_PRIME)
00016 
00017 #include <list>
00018 #include <iterator>
00019 
00020 #include "prime.hpp"
00021 #include "exception.hpp"
00022 #include "powerest.hpp"
00023 #include "rand.hpp"
00024 
00025 
00026 namespace Arageli
00027 {
00028 
00029 template <typename Out, typename T>
00030 Out small_primes (Out primes, const T& N)
00031 {
00032     // WARNING! Why do we need to generate the same primes every time?
00033 
00034     typedef typename std::iterator_traits<Out>::value_type Val;
00035     typedef typename std::iterator_traits<Out>::reference Ref;
00036 
00037     primes[0] = 2;
00038     Val n = 3;
00039 
00040     for (T j = 1; j < N; j++)
00041     {
00042         primes[j] = n;
00043         for(;;)
00044         {
00045             n += 2;
00046             for(T k = 1; ; k++)
00047             {
00048                 Val q, r;
00049                 Ref pk = primes[k];
00050                 divide(n, pk, q, r);
00051                 if(is_null(r))break;
00052                 if(q <= pk)goto next_prime;
00053             }
00054         }
00055 next_prime: ;
00056     }
00057 
00058     return primes + N;
00059 }
00060 
00061 template <typename T, typename T_factory>
00062 bool is_prime_division (const T& x, const T_factory& tfctr)
00063 {
00064     T d = tfctr.unit(x);    // d = 1
00065     if(x <= d)return false;
00066     ++d;    // d = 2
00067     if(x == d)return true;
00068     if(is_null(x % d))return false;
00069     ++d;    // d = 3
00070     if(x == d)return true;
00071     if(is_null(x % d))return false;
00072 
00073     d += 2;
00074 
00075     T q, r;
00076 
00077     for(;;)
00078         for(unsigned s = 2; s <= 4; s += 2)
00079         {
00080             divide(x, d, q, r);
00081             if(q < d)return true;
00082             if(is_null(r))return false;
00083             d += s;
00084         }
00085 }
00086 
00087 template <typename T, typename N, typename T_factory>
00088 bool is_pseudoprime_solovay_strassen (const T& x, const N& n, const T_factory& tfctr)
00089 {
00090     if (x<=unit(x)) return false;
00091     if (x == T(2)) return true;
00092     T jac; 
00093     T a;
00094     for (N i = null(n); i < n; ++i)
00095     {
00096         a = rand(x-3);
00097         a += 2;
00098         if (!is_unit(gcd(a,x))) return false;
00099         jac = jacobi(a, x);
00100         if (is_opposite_unit(jac)) jac += x;
00101         if (power_mod(a, (x-1)/2, x) != jac ) return false;
00102     }
00103     return true;
00104 }
00105 
00106 template <typename T, typename N, typename T_factory>
00107 bool is_pseudoprime_miller_rabin (const T& x, const N& n, const T_factory& tfctr)
00108 {
00109     ARAGELI_ASSERT_0(is_positive(x));
00110     if(is_unit(x))return false;
00111     if(x == 2) return true;
00112     if(is_even(x)) return false;
00113     T a, q, c;
00114     N k;
00115     const T unt = unit(x);
00116     const T start_q = (x - 1) >> 1;
00117     for (N i = null(n); i < n; ++i)
00118     {
00119         a = rand(x-3);
00120         a += 2;
00121         if(!is_unit(gcd(a,x))) return false;
00122         q = start_q;
00123         k = unit(n);
00124         while (is_even(q))
00125         {
00126             q = q >> 1;
00127             ++k;
00128         }
00129         c = power_mod(a, q, x);
00130         if (is_unit(c) || c == x - unt) continue;
00131 
00132         N j = unit(k);
00133         for (; j < k; ++j)
00134         {
00135             (c *= c) %= x;
00136             if (c == x - unt) break;
00137             if (is_unit(c)) return false;
00138         }
00139         if (j == k)
00140             return false;
00141     }
00142     return true;
00143 }
00144 
00145 template <typename T>
00146 T LPF(T p)
00147 {
00148     T s = p;
00149     T i = 2;
00150     T j = intsqrt(s);
00151     while (i <= j)
00152     {
00153         if (s%i == 0)
00154         {
00155             s=s/i;
00156             j = intsqrt(s);
00157         }
00158         else ++i;
00159     }
00160     return s;
00161 }
00162 
00163 template <typename T>
00164 bool is_power_of_prime(T n, long b)
00165 {
00166     T p = square(nbits(n)/b + 1);
00167     T q;
00168     while (true)
00169     {
00170         q = (p*(b-1) + n/(power(p,b-1)))/b;
00171         if (q>=p)
00172             break;
00173         p=q;
00174     }
00175     if ( n == power(p,b))
00176         return true;
00177     return false;
00178 }
00179 
00180 template <typename T>
00181 bool is_prime_AKS_classic (const T& n)
00182 {
00183     T N = intsqrt(n);
00184     if (square(N) == n) return false;
00185     int i;
00186     int len = n.length();
00187     for (i = 3; i < len; i+=2)
00188         if (is_power_of_prime(n,i)) return false;
00189 
00190     T r = 3;
00191     T q, s;
00192     int len4 = 4*len;
00193     while (r<N)
00194     {
00195         if (is_prime(r))
00196         {
00197             if (gcd(r,n) != 1) return false;
00198             q = LPF(r-1);
00199             if ((q >= 4*intsqrt(r)+len4) && 
00200                 (power_mod((n%r),((r-1)/q),r) <= 1))
00201                 break;  
00202         }
00203         r+=2;
00204     }
00205     if (r >= N) return true;
00206     sparse_polynom<T> mod_part;
00207     sparse_polynom<T> right_part;
00208     mod_part = power(sparse_polynom<T>("x"), r)-1;
00209     right_part = power_mod(sparse_polynom<T>("x"), n, mod_part);
00210     s = 2*N*len;
00211     for(i = 1; i <= s; ++i)
00212     {
00213         sparse_polynom<T> left_part("x");
00214         left_part -= i;
00215         left_part = power_mod(left_part, n, mod_part);
00216         left_part += i;
00217         sparse_polynom_reduction_mod(left_part, n);
00218         if (left_part != right_part) return false;
00219     }
00220     return true;
00221 }
00222 template<typename T>
00223 long primitive_root(T n, T r)
00224 {
00225     long i;
00226     long r_len = r.length();
00227     for (i = 1; i <= r_len; ++i)
00228     {
00229         if( is_unit(power_mod(n%r,i,r)) )
00230             return i;
00231     }
00232     return 0;
00233 }
00234 
00235 template <typename T>
00236 bool is_prime_AKS (const T& n)
00237 {
00238     T N = intsqrt(n);
00239     if (square(N) == n) return false;
00240     long i;
00241     long len = n.length();
00242     for (i = 3; i < len; i+=2)
00243         if (is_power_of_prime(n,i)) return false;
00244     T r = next_prime(power(len,2));
00245     T q, s;
00246 
00247     for (;primitive_root(n,r+2);r=next_prime(r+2));
00248     for (q = 3; (is_unit(gcd(q,n)) || (gcd(q,n) == n)) && (q < r); ++q);
00249     if (q<r) { return false; }
00250     else
00251         if (n<=r) { return false;}
00252 
00253         sparse_polynom<T> mod_part;
00254         sparse_polynom<T> right_part;
00255         mod_part = power(sparse_polynom<T>("x"), r)-1;
00256         right_part = power_mod(sparse_polynom<T>("x"), n, mod_part);
00257         s = intsqrt(r)*len; 
00258         for(i = 1; i <= s; ++i)
00259         {
00260             sparse_polynom<T> left_part("x");
00261             left_part -= i;
00262             left_part = power_mod(left_part, n, mod_part);
00263             left_part += i;
00264             sparse_polynom_reduction_mod(left_part, n);
00265             if (left_part != right_part) return false;
00266         }
00267         return true;
00268 }
00269 
00270 template <typename T, typename N>
00271 int is_prime_small_primes_division (const T& n, const N& np)
00272 {
00273     ARAGELI_ASSERT_0(n > unit(n));
00274 
00275     vector<int, false> small_primes;
00276     small_primes(small_primes, np); // WARNING! Why is this every time generated?
00277 
00278     for(int j = 0; j < np; j++)
00279     {
00280         if(n == small_primes[j])return 1;
00281         if(is_divisible(n, small_primes[j]))return 0;
00282     }
00283 
00284     // n doesn't have prime divisors less or equal than np-th prime number
00285     return -1; 
00286 }
00287 
00288 template <typename T1, typename T2, bool REFCNT2, typename T_factory>
00289 vector<T2, REFCNT2>& factorize_division
00290     (T1 x, vector<T2, REFCNT2>& res, const T_factory& tfctr)
00291 {
00292     ARAGELI_DEBUG_EXEC_2(T1 xx = x);    // save original value
00293     ARAGELI_ASSERT_0(is_positive(x));
00294 
00295     if(is_unit(x))
00296     {
00297         res.resize(0);
00298         return res;
00299     }
00300 
00301     T1 d = tfctr.unit(x);   // d = 1
00302     ARAGELI_ASSERT_0(x >= d);
00303     ++d;    // d = 2
00304 
00305     std::list<T2> resbuf;
00306 
00307     while(is_null(x % 2))
00308     {
00309         x >>= 1;
00310         resbuf.push_back(d);
00311     }
00312 
00313     T1 q, r;
00314 
00315     ++d;    // d = 3
00316 
00317     for(;;)
00318     {
00319         divide(x, d, q, r);
00320         if(is_null(r))
00321         {
00322             x = q;
00323             resbuf.push_back(d);
00324         }
00325         else break;
00326     }
00327 
00328     d += 2; // d = 5
00329 
00330     unsigned s = 2;
00331 
00332     while(!is_unit(x))
00333     {
00334         ARAGELI_ASSERT_1(x >= d);
00335 
00336         divide(x, d, q, r);
00337         if(is_null(r))
00338         {
00339             x = q;
00340             resbuf.push_back(d);
00341         }
00342         else if(q < d)
00343         {
00344             ARAGELI_ASSERT_1(is_prime(x, tfctr));
00345             //std::cout << "\nARAGELI DEBUG OUTPUT: d = " << d << std::endl;
00346             resbuf.push_back(x);
00347             break;
00348         }
00349         else
00350         {
00351             //d = next_prime(d);
00352             d += s;
00353             if(s == 2)s = 4;
00354             else s = 2;
00355         }
00356     }
00357 
00358     res.assign(resbuf.size(), resbuf.begin());
00359 
00360     ARAGELI_DEBUG_EXEC_2(T1 tt);
00361     ARAGELI_ASSERT_2(product(res, tt) == xx);
00362 
00363     return res;
00364 }
00365 
00366 namespace _Internal
00367 {
00368     template<typename T> 
00369     T random_function(T x, T n)
00370     {
00371         return (x*x+5)%n;
00372     }
00373 }
00374 
00375 template<typename T, typename T_factory> 
00376 T rho_pollard(const T& n, const T_factory& tfctr)
00377 {
00379     //T x = 2, y = 2, d = unit(n);
00380     //while(is_unit(d))
00381     //{
00382     //    x = _Internal::random_function(x, n);
00383     //    y = _Internal::random_function(_Internal::random_function(y, n), n);
00384     //    d = gcd(std::abs(x-y), n);
00385     //    if ((1 < d) && (d < n))
00386     //    {
00387     //        return d;
00388     //    }
00389     //    if (d == n)
00390     //        return 1; // failure
00391     //}
00392     //return d;
00393 
00394     // Zolotykh - Computer Algebra
00395     ARAGELI_ASSERT_1(n >= 4);
00396     T x0 = rand(n-1);
00397     T x = x0;
00398     T d;
00399     unsigned int i, j = 1;
00400     while (true)
00401     {
00402         x0 = x;
00403         for (i = 1; i <= j; ++i)
00404         {
00405             x = _Internal::random_function(x, n);
00406             d = gcd(std::abs(x-x0), n);
00407             if ((d > 1) && (d <= n)) return d;
00408         }
00409         j*=2;
00410     }
00411 }
00412 
00413 template<typename T, typename N, typename T_factory> 
00414 T brent(const T& n, N no_of_iter, const T_factory& tfctr)
00415 {
00416     N r = 1;
00417     N m = 10;
00418     N iter = 0;
00419 
00420     T y = 0;
00421     T q = 1;
00422     T x, ys, g;
00423 
00424     do
00425     {
00426         x = y;
00427         for (N j = 1; j <= r; j++)
00428             y = _Internal::random_function(y, n);
00429 
00430         N k = 0;
00431 
00432         do
00433         {
00434             iter++;
00435             if (iter > no_of_iter)
00436                 return 0; // failure
00437             ys = y;
00438             T mn = r - k;
00439             if (m < mn) mn = m;
00440             for (N j = 1; j <= mn; j++)
00441             {
00442                 y = _Internal::random_function(y, n);
00443                 q = (q * std::abs(x - y)) % n;
00444             }
00445             g = gcd(q, n);
00446             k = k + m;
00447 
00448         }
00449         while(k < r && g <= 1);
00450 
00451         r = 2 * r;
00452     }
00453     while (g <= 1);
00454 
00455     if (g == n)
00456     {
00457         do
00458         {
00459             ys = _Internal::random_function(ys, n);
00460             g = gcd(x - ys, n);
00461         }
00462         while (g <= 1);
00463     }
00464 
00465     if (g == n)
00466         return 0;
00467     else
00468         return g;
00469 }
00470 
00471 template<typename T, typename N, typename T_factory> 
00472 T pollard_pm1(const T& n, const N& no_of_iter, const T_factory& tfctr)
00473 {
00474     T b = 2, t = 2, p = unit(n);
00475     for(N i = 2; i <= no_of_iter; i++)
00476     {
00477         //  if (i % 10 == 0) std::cout << " i = " << i << std::endl;
00478         t = power_mod(t, i, n); // now t = b^(i!) 
00479         p = gcd(n, t - 1);
00480         if (p > unit(n) && p < n)
00481             return p;
00482         if (p == n)
00483         {
00484             i = 2;
00485             t = ++b;
00486             if (b == 5) 
00487                 return null(n);
00488         }
00489     }
00490     return null(n);
00491 }
00492 
00493 template
00494     <
00495     typename T1,
00496     typename T2, bool REFCNT2,
00497     typename T3, typename T4
00498     >
00499     vector<T2, REFCNT2>& partial_factorize_division
00500     (T1 x, vector<T2, REFCNT2>& res, const T3& max, T4& rest)
00501 {
00502     ARAGELI_DEBUG_EXEC_2(T1 xx = x);    // save original value
00503 
00504     if(is_unit(x) || max < 2)
00505     {
00506         res.resize(0);
00507         rest = x;
00508 
00509         ARAGELI_DEBUG_EXEC_2(T1 tt);
00510         ARAGELI_ASSERT_2(product(res, tt)*rest == xx);
00511 
00512         return res;
00513     }
00514 
00515     T1 d = unit(x); // d = 1
00516     ARAGELI_ASSERT_0(x >= d);
00517     ++d;    // d = 2
00518 
00519     std::list<T2> resbuf;
00520 
00521     while(is_null(x % 2))
00522     {
00523         x >>= 1;
00524         resbuf.push_back(d);
00525     }
00526 
00527     if(max < 3)
00528     {
00529         res.assign(resbuf.size(), resbuf.begin());
00530         rest = x;
00531 
00532         ARAGELI_DEBUG_EXEC_2(T1 tt);
00533         ARAGELI_ASSERT_2(product(res, tt)*rest == xx);
00534 
00535         return res;
00536     }
00537 
00538     T1 q, r;
00539 
00540     ++d;    // d = 3
00541 
00542     for(;;)
00543     {
00544         divide(x, d, q, r);
00545         if(is_null(r))
00546         {
00547             x = q;
00548             resbuf.push_back(d);
00549         }
00550         else break;
00551     }
00552 
00553     d += 2; // d = 5
00554 
00555     unsigned s = 2;
00556     rest = x;
00557     while(!is_unit(x))
00558     {
00559         ARAGELI_ASSERT_1(x >= d);
00560 
00561         if(max < d)
00562         {
00563             if (is_prime(x)) 
00564             {
00565                 resbuf.push_back(x);
00566                 rest = unit(rest);
00567             }
00568             else
00569             {
00570                 rest = x;
00571             }
00572             res.assign(resbuf.size(), resbuf.begin());
00573             
00574             ARAGELI_DEBUG_EXEC_2(T1 tt);
00575             ARAGELI_ASSERT_2(product(res, tt)*rest == xx);
00576 
00577             return res;
00578         }
00579 
00580         divide(x, d, q, r);
00581         if(is_null(r))
00582         {
00583             x = q;
00584             resbuf.push_back(d);
00585         }
00586         else if(q < d)
00587         {
00588             ARAGELI_ASSERT_1(is_prime(x));
00589             rest = 1;
00590             resbuf.push_back(x);
00591             break;
00592         }
00593         else
00594         {
00595             //d = next_prime(d);
00596             d += s;
00597             if(s == 2)s = 4;
00598             else s = 2;
00599         }
00600     }
00601 
00602     res.assign(resbuf.size(), resbuf.begin());
00603 
00604     ARAGELI_DEBUG_EXEC_2(T1 tt);
00605     ARAGELI_ASSERT_2(product(res, tt)*rest == xx);
00606 
00607     return res;
00608 }
00609 
00610 
00611 template <typename T1, typename T2, typename T3, typename T4>
00612 const T4& factorize_multiplier (T1 x, const T2& m, T3& remx, T4& nm)
00613 {
00614     ARAGELI_ASSERT_0(!is_null(m));
00615     ARAGELI_ASSERT_0(!is_unit(m));
00616     ARAGELI_ASSERT_0(!is_opposite_unit(m));
00617 
00618     T1 q = x; T2 r;
00619     nm = null(nm);
00620 
00621     for(;;)
00622     {
00623         remx = x;
00624         divide(remx, m, x, r);
00625         if(!is_null(r))break;
00626         ++nm;
00627     }
00628 
00629     return nm;
00630 }
00631 
00632 
00633 template <typename T>
00634 T next_prime_successive_checking (T x)
00635 {
00636     for(++x; !is_prime(x); ++x);
00637     return x;
00638 }
00639 
00640 
00641 template <typename T>
00642 T prev_prime_successive_checking (T x)
00643 {
00644     ARAGELI_ASSERT_0(x > 2);
00645     for(--x; !is_prime(x); --x);
00646     return x;
00647 }
00648 
00649 template <typename T>
00650 T next_probably_prime (T x)
00651 {
00652     for(++x; !is_probably_prime(x); ++x);
00653     return x;
00654 }
00655 
00656 
00657 template <typename T>
00658 T prev_probably_prime (T x)
00659 {
00660     ARAGELI_ASSERT_0(x > 2);
00661     for(--x; !is_probably_prime(x); --x);
00662     return x;
00663 }
00664 
00665 
00666 template<typename T, typename N>
00667 void rsa_generate_keys(N l, T& c, T& public_key, T& d)
00668 {
00669     T p = rand(l/2);
00670     //    init_random(time(NULL));
00671     T q = rand(l/2);
00672     public_key = p * q;
00673 
00674     T phi = (p-1)*(q-1);
00675 
00676     for (c = 3; !is_unit(gcd(c, phi)); c = c + 2)
00677         ;
00678 
00679     d = inverse_mod(c, phi);
00680 }
00681 
00682 template<typename T>
00683 T rsa_encyph(const T& x, const T& c, const T& key)
00684 {
00685     return power_mod(x, c, key);
00686 }
00687 
00688 template<typename T>
00689 T rsa_decyph(const T& y, const T& d, const T& key)
00690 {
00691     return power_mod(y, d, key);
00692 }
00693 
00694 
00695 template <typename T>
00696 T next_mersen_prime_degree (const T& n)
00697 {
00698     static const unsigned mersen_degrees[] =
00699     {
00700         2,3,5,7,13,17,19,31,61,89,107,127,521,607,1279,
00701         2203,2281,3217,4253,4423,9689,9941,11213,19937,
00702         21701,23209,44497,86243,110503,132049,216091,
00703         756839,859433,1257787,1398269,2976221,3021377,
00704         6972593,13466917
00705     };
00706 
00707     const unsigned* res = std::upper_bound
00708         (
00709         &mersen_degrees[0],
00710         &mersen_degrees[sizeof(mersen_degrees)/sizeof(unsigned)],
00711         n
00712         );
00713 
00714     if(res == &mersen_degrees[sizeof(mersen_degrees)/sizeof(unsigned)])
00715         throw invalid_argument();
00716 
00717     return *res;
00718 }
00719 
00720 
00721 
00722 } // namespace Arageli
00723 
00724 #endif
00725 

Generated on Thu Aug 31 17:38:08 2006 for Arageli by  doxygen 1.4.7