00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00017
00018
00019
00020 class Clucas_capsule_mpz
00021 {
00022 private:
00023 static const int lucas_cache_mpz_size = 500;
00024
00025
00026 mpz_t lucas_cache_mpz [lucas_cache_mpz_size][2];
00027
00028 int lucas_cache_mpz_index;
00029
00030
00031 int lucas_cache_mpz_init_index;
00032
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
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
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
00068 mpz_set(res,lucas_cache_mpz[i][1]);
00069 --lucas_cache_mpz_index;
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))
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
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
00102
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
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);
00133 mpz_mul_ui(h2,lucas_q_mpz,4); mpz_mod(h2,h2,Primenumber);
00134
00135
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
00143 mpz_invert(lucas_p_inv_mpz,lucas_p_mpz,Primenumber); mpz_mod(lucas_p_inv_mpz,lucas_p_inv_mpz,Primenumber);
00144
00145
00146 lucas_cache_mpz_index=0;
00147
00148
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
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
00163
00164
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
00171
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
00176 }
00177 else
00178 if (mpz_remainder_ui(Primenumber,8)==5)
00179 {
00180
00181
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)
00201 {
00202
00203
00204 Clucas_capsule_mpz capsulated;
00205
00206
00207 capsulated.lucas(res,Radikant,Primenumber);
00208 }
00209 }
00210
00211 #if 0
00212
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 }