mpz_sqrtmod.cc

Go to the documentation of this file.
00001 // The following functions compute square roots modulo prime numbers.
00002 // please note:
00003 //  - primality is not checked! 
00004 //    (if necessary, you have to do this beforehand, eg. using is_probab_prime)
00005 //  - no check is done, whether the square root exists!
00006 //    (if necessary, check it using legendre(Radikant,Primenumber)==1) 
00007 
00008 // written by Thorsten Reinecke 1998,1999
00009 // last change: 2005-02-28
00010 
00017 // remark: Lucasfunctions can be used without dynamic programming by evaluating
00018 // binary digits (less memory consumption). This isn't implemented yet.
00019 
00020 class Clucas_capsule_mpz
00021 {
00022  private:
00023   static const int lucas_cache_mpz_size = 500;
00024    // maximum size of cache
00025    
00026   mpz_t lucas_cache_mpz [lucas_cache_mpz_size][2];
00027   
00028   int lucas_cache_mpz_index;
00029    // position for the next value to place in cache
00030 
00031   int lucas_cache_mpz_init_index;
00032    // needed for allocating memory
00033 
00034   mpz_t lucas_p_mpz, lucas_q_mpz, lucas_p_inv_mpz;
00035 
00036   void lucasv(mpz_t res, const mpz_t Primenumber, mpz_t m);
00037   
00038  public:
00039   Clucas_capsule_mpz() : lucas_cache_mpz_index(0), lucas_cache_mpz_init_index(0)
00040   {
00041     mpz_init(lucas_p_mpz); mpz_init(lucas_q_mpz); mpz_init(lucas_p_inv_mpz);
00042   }
00043   ~Clucas_capsule_mpz()
00044   {
00045     mpz_clear(lucas_p_mpz); mpz_clear(lucas_q_mpz); mpz_clear(lucas_p_inv_mpz);
00046     for (int i=0; i<lucas_cache_mpz_init_index; ++i)
00047      {
00048        //cerr << i << ": " << lucas_cache_mpz[i][0] << ": " << lucas_cache_mpz[i][1] << endl;
00049        mpz_clear(lucas_cache_mpz[i][0]);
00050        mpz_clear(lucas_cache_mpz[i][1]);
00051      }
00052   }
00053   void lucas(mpz_t v, const mpz_t Radikant, const mpz_t Primenumber);
00054 };
00055  
00056 
00057 void Clucas_capsule_mpz::lucasv(mpz_t res, const mpz_t Primenumber, mpz_t m)
00058 {
00059   if (mpz_cmp_ui(m,0)==0) { mpz_set_ui(res,2); return; }
00060   if (mpz_cmp_ui(m,1)==0) { mpz_set(res,lucas_p_mpz); return; }
00061   
00062   // value already known?
00063   for (int i=lucas_cache_mpz_index-1; i>=0; --i)
00064     {
00065       if (mpz_cmp(lucas_cache_mpz[i][0],m)==0)
00066        { 
00067          //cout << "Cache Hit!" << i << "/" << lucas_cache_mpz_index << ": " << m << endl;
00068          mpz_set(res,lucas_cache_mpz[i][1]);
00069          --lucas_cache_mpz_index; // this one does not hit anymore
00070          mpz_swap(lucas_cache_mpz[i][0],lucas_cache_mpz[lucas_cache_mpz_index][0]);
00071          mpz_swap(lucas_cache_mpz[i][1],lucas_cache_mpz[lucas_cache_mpz_index][1]);
00072          return;
00073        }
00074     }
00075   
00076   if (mpz_odd_p(m)) // m odd
00077     {
00078       mpz_t h1;
00079       mpz_init(h1); mpz_sub_ui(m,m,1); lucasv(h1,Primenumber,m);
00080       mpz_mul(res,h1,lucas_q_mpz);
00081       mpz_add_ui(m,m,2); lucasv(h1,Primenumber,m); mpz_sub_ui(m,m,1);
00082       mpz_add(res,res,h1); mpz_mod(res,res,Primenumber);
00083       mpz_mul(res,res,lucas_p_inv_mpz); mpz_mod(res,res,Primenumber);
00084       mpz_clear(h1);
00085     }
00086   else // m even
00087     {
00088       mpz_t h1;
00089       mpz_init(h1); mpz_div_ui(m,m,2);
00090       lucasv(h1,Primenumber,m);
00091 
00092       mpz_powm(res,lucas_q_mpz,m,Primenumber); mpz_mul_ui(res,res,2);
00093       mpz_mod(res,res,Primenumber);
00094       mpz_mul_ui(m,m,2);
00095       
00096       mpz_mul(h1,h1,h1); mpz_mod(h1,h1,Primenumber);
00097       mpz_add(h1,h1,Primenumber); mpz_sub(res,h1,res);
00098       mpz_mod(res,res,Primenumber);
00099       mpz_clear(h1);
00100   
00101       // place value into cache...
00102       // (only necessary for oven indices, because recursive call is done for even ones.)
00103       if (lucas_cache_mpz_index<lucas_cache_mpz_size)
00104         {
00105           if (lucas_cache_mpz_init_index==lucas_cache_mpz_index)
00106            {
00107              mpz_init(lucas_cache_mpz[lucas_cache_mpz_init_index][0]);
00108              mpz_init(lucas_cache_mpz[lucas_cache_mpz_init_index++][1]);
00109            }
00110           mpz_set(lucas_cache_mpz[lucas_cache_mpz_index][0],m);
00111           mpz_set(lucas_cache_mpz[lucas_cache_mpz_index++][1],res);
00112         } else cerr << "Lucas-Cache needs to be increased!" << endl;
00113     }
00114 }
00115 
00116 
00117 void Clucas_capsule_mpz::lucas(mpz_t v, const mpz_t Radikant, const mpz_t Primenumber)
00118 {
00119   if (mpz_remainder_ui(Primenumber,4)!=1)
00120     { cerr << "Fehler in Lucassequenz Primenumber%4<>1!: " << Primenumber << endl; exit(1); }
00121   
00122   /* lucas_p_mpz ermitteln */
00123   mpz_set(lucas_q_mpz,Radikant);
00124   mpz_set_ui(lucas_p_mpz,1);
00125  
00126   {
00127     mpz_t h1,h2;
00128     mpz_init(h1); mpz_init(h2);
00129     do
00130      {
00131        mpz_add_ui(lucas_p_mpz,lucas_p_mpz,1);
00132        mpz_powm_ui(h1,lucas_p_mpz,2,Primenumber); //h1=squaremod(lucas_p,Primenumber);
00133        mpz_mul_ui(h2,lucas_q_mpz,4); mpz_mod(h2,h2,Primenumber); //h2=mulmod(4,lucas_q_mpz,Primenumber);
00134        
00135        //if (h1>=h2) h1-=h2; else h1=Primenumber-(h2-h1);
00136        if (mpz_cmp(h1,h2)>=0) mpz_sub(h1,h1,h2);
00137        else { mpz_sub(h1,h2,h1); mpz_sub(h1,Primenumber,h1); }
00138      } while (mpz_legendre(h1,Primenumber)!=-1);
00139     mpz_clear(h1); mpz_clear(h2);
00140   }
00141 
00142   // compute inverse of lucas_p_mpz modulo Primenumber
00143   mpz_invert(lucas_p_inv_mpz,lucas_p_mpz,Primenumber); mpz_mod(lucas_p_inv_mpz,lucas_p_inv_mpz,Primenumber);
00144   
00145   //cout << "Lucas-Cache was " << lucas_cache_mpz_index << endl;
00146   lucas_cache_mpz_index=0; // clear cache!
00147   
00148   // now compute the square root
00149   mpz_t m;
00150   mpz_init(m); mpz_add_ui(m,Primenumber,1); mpz_div_ui(m,m,2);
00151   lucasv(v,Primenumber,m);
00152   mpz_clear(m);
00153 
00154   // and divide by 2 (but modulo Primenumber!!)
00155   if (mpz_odd_p(v)) mpz_add(v,v,Primenumber);
00156   mpz_div_ui(v,v,2);
00157 }
00158 
00159 
00160 void mpz_sqrtmod(mpz_t res, const mpz_t Radikant_bel, const mpz_t Primenumber)
00161 {
00162   // we could perform a primality check here, but we omit it for the sake of efficiency.
00163 
00164   // normalize Radikant
00165   mpz_t Radikant;
00166   mpz_init(Radikant); mpz_mod(Radikant,Radikant_bel,Primenumber);
00167   
00168   if (mpz_remainder_ui(Primenumber,4)==3)
00169     {
00170       // result can be computed easily
00171       //cout << "sqrtmod: p=3 (mod 4)" << endl;
00172       mpz_t h; mpz_init(h); mpz_add_ui(h,Primenumber,1); mpz_div_ui(h,h,4);
00173       mpz_powm(res,Radikant,h,Primenumber);
00174       mpz_clear(h);
00175       //return powmod(Radikant,(Primenumber+1)>>2,Primenumber);
00176     }
00177   else
00178     if (mpz_remainder_ui(Primenumber,8)==5)
00179       {
00180         // result can be computed easily, too
00181         //cout << "sqrtmod: p=5 (mod 8)" << endl;
00182         mpz_t y;
00183         mpz_init(y); mpz_add_ui(y,Primenumber,3); mpz_div_ui(y,y,8);
00184         mpz_powm(y,Radikant,y,Primenumber);
00185         mpz_powm_ui(res,y,2,Primenumber);
00186         if (mpz_cmp(res,Radikant)==0) mpz_set(res,y);
00187         else
00188           {
00189             mpz_t Pviertel;
00190             mpz_init(Pviertel); mpz_div_ui(Pviertel,Primenumber,4);
00191             mpz_set_ui(res,2); mpz_powm(res,res,Pviertel,Primenumber);
00192             mpz_mul(res,res,y); mpz_mod(res,res,Primenumber);
00193             mpz_clear(Pviertel);
00194           }
00195         mpz_clear(y);
00196       }
00197     else
00198      { 
00199        mpz_mod(res,Radikant,Primenumber);
00200        if (mpz_cmp_ui(res,1)>0) // omit special cases: 0^2=0, 1^2=1
00201         {
00202           // compute result via Lucas sequences for Primenumber=1 (mod 4)
00203           //cout << "sqrtmod: p=1 (mod 4) -> Lucassequenzen" << endl;
00204           Clucas_capsule_mpz capsulated;
00205            // if thread-safety is no issue, then you can speed-up things a bit
00206            // in making capsulated a static variable...
00207           capsulated.lucas(res,Radikant,Primenumber);
00208         }
00209      }
00210   
00211 #if 0
00212   // final check:
00213   cout << "mpz_sqrtmod: checking squares" << endl;
00214   mpz_t x;
00215   mpz_init(x); mpz_powm_ui(x,res,2,Primenumber);
00216   if (mpz_cmp(x,Radikant)!=0)
00217    {
00218      cerr << "computing square root failed!" << endl;
00219      cerr << Radikant << "," << x << endl;
00220      exit(1);
00221    }
00222   mpz_clear(x);
00223 #endif
00224 
00225   mpz_clear(Radikant);
00226 }

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