sqrt_modulo.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 
00011 // now it should be threadsafe
00012 
00013 
00020 #include "modulo.H"
00021 
00022 namespace numtheory
00023 {
00024 
00025 class Clucas_capsule
00026 {
00027  private:
00028   static const int lucas_cache_size = 128;
00029   unsigned int lucas_p, lucas_q, lucas_p_inv;
00030   int lucas_cache_index;
00031   unsigned int lucas_cache [lucas_cache_size][2];
00032   unsigned int lucasv(const unsigned int Primenumber, const unsigned int m);
00033  public:
00034   inline Clucas_capsule(void) : lucas_cache_index(0) { }
00035   unsigned int lucas(const unsigned int Radikant, const unsigned int Primenumber);  
00036 };
00037 
00038 
00039 unsigned int Clucas_capsule::lucasv(const unsigned int Primenumber, const unsigned int m)
00040 {
00041   using std::cerr;
00042   using std::endl;
00043   if (m==0) return 2;
00044   if (m==1) return lucas_p;
00045   
00046   // value already known?
00047   for (int i=lucas_cache_index-1; i>=0; --i)
00048     {
00049       if (lucas_cache[i][0]==m) return lucas_cache[i][1];
00050     }
00051   
00052   unsigned int wert; // return value for lucas_v
00053   // printf("lucasv(%i)\n",m);
00054   
00055   if (m&1) // odd?
00056     {
00057       const unsigned int h1=lucasv(Primenumber,m+1);
00058       const unsigned int h2=lucasv(Primenumber,m-1);
00059       register unsigned int xx;
00060       xx=mulmod(h2,lucas_q,Primenumber)+h1;
00061       wert=mulmod(xx%Primenumber,lucas_p_inv,Primenumber);
00062     }
00063   else // even
00064     {
00065       const unsigned int h1=lucasv(Primenumber,m>>1);
00066       unsigned int xx;
00067       xx=(powmod(lucas_q,m>>1,Primenumber)<<1)%Primenumber;
00068       wert=(squaremod(h1,Primenumber)+Primenumber-xx)%Primenumber;
00069   
00070       // write value to cache...
00071       if (lucas_cache_index<lucas_cache_size)
00072         {
00073           lucas_cache[lucas_cache_index][0]=m;
00074           lucas_cache[lucas_cache_index++][1]=wert;
00075         } else cerr << "Lucas-Cache should be increased!" << endl;
00076     }
00077   return wert;
00078 }
00079 
00080 
00081 unsigned int Clucas_capsule::lucas(const unsigned int Radikant, const unsigned int Primenumber)
00082 {
00083   using std::cerr;
00084   using std::endl;
00085   if ((Primenumber&3)!=1)
00086     {
00087       cerr << "Error in Lucassequence Primenumber%4<>1!: " << Primenumber%4 << endl;
00088       exit(1);
00089     }
00090   
00091   // compute lucas_p
00092   lucas_q=Radikant;
00093   lucas_p=1;
00094  
00095   {
00096     int h1,h2;
00097     do
00098      {
00099        lucas_p++;
00100        h1=squaremod(lucas_p,Primenumber);
00101        h2=mulmod(4,lucas_q,Primenumber);
00102        if (h1>=h2) h1-=h2; else h1=Primenumber-(h2-h1);
00103      } while (legendre(h1,Primenumber)!=-1);
00104   }
00105 
00106   // compute inverse of lucas_p mod Primenumber
00107   lucas_p_inv=fastinvmod(lucas_p,Primenumber);
00108   
00109   //cout << "Lucas-Cache was " << lucas_cache_index << endl;
00110   lucas_cache_index=0; // clear cache!
00111   
00112   // now compute the squareroot of n
00113   unsigned int v=lucasv(Primenumber,(Primenumber+1)>>1);
00114   // divide v by 2 (but do it modulo Primenumber!!)
00115   if (v&1) v+=Primenumber;
00116   return v>>1;
00117 }
00118 
00119 
00133 unsigned int sqrtmod(const unsigned int Radikant, const unsigned int Primenumber)
00134 {
00135   // we could perform a primality check here, but we omit it for the sake of efficiency.  
00136 
00137   if ((Primenumber&3)==3)
00138     {
00139       /* we can can compute our result easily... */
00140       //cout << "sqrtmod: p=3 (mod 4)" << endl;
00141       return powmod(Radikant,(Primenumber+1)>>2,Primenumber);
00142     }
00143   else
00144     if ((Primenumber&7)==5)
00145       {
00146         /* result can be computed rather easily, too... */
00147         //cout << "sqrtmod: p=5 (mod 8)" << endl;
00148         unsigned int y = powmod(Radikant,(Primenumber+3)>>3,Primenumber);
00149         if (squaremod(y,Primenumber)==Radikant) return y;
00150         else 
00151           {
00152             unsigned int w=powmod(2,Primenumber>>2,Primenumber);
00153             return mulmod(y,w,Primenumber);
00154           }
00155       }
00156     else
00157      { 
00158        if (Radikant<=1) return Radikant; // special cases: 0^2=0, 1^2=1
00159        /* efficient solution by using Lucas-Sequences for Primenumber=1 (mod 4) */
00160        //cout << "sqrtmod: p=1 (mod 4) -> Lucassequences" << endl;
00161        Clucas_capsule lucas_capsule;
00162        return lucas_capsule.lucas(Radikant,Primenumber);
00163      }
00164 }
00165 
00166 } // namespace numtheory

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