00001
00002
00003
00004
00010 #include "elliptic_curve.H"
00011 #include "modulo.H"
00012 #include <cmath>
00013 #include "mpz_multi_invert.cc"
00014
00015 #include "PersistentData.H"
00016
00017 #if (CONTINUATION_METHOD > 0)
00018 #include "Semaphore.H"
00019 extern void get_fft_parameter(unsigned int &pg_returnvalue, unsigned int &pms_returnvalue,
00020 const double phase2, const mpz_t N);
00021 #endif
00022
00023 #ifdef REACT_ON_SIGUSR
00024 #include "usr_signals.H"
00025 extern Cusr_signal_proxy USRSignalHandler;
00026 #endif
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 void elliptic_curves::check_curve(const mpz_t x, const mpz_t y) const
00059 {
00060
00061
00062
00063 mpz_t x1,y1;
00064 mpz_init(x1); mpz_init(y1);
00065 mpz_add(x1,x,a); mpz_mul(x1,x1,x); mpz_add_ui(x1,x1,1);
00066 mpz_mul(x1,x1,x); mpz_mod(x1,x1,n);
00067 mpz_mul(y1,y,y); mpz_mul(y1,y1,b); mpz_mod(y1,y1,n);
00068 const int fl = mpz_cmp(x1,y1);
00069 mpz_clear(x1); mpz_clear(y1);
00070 if (fl!=0)
00071 {
00072 cerr << "tested point is invalid!" << endl;
00073 cerr << "(x:y:1)=(" << x << ":" << y << ":1)" << endl;
00074 exit(1);
00075 }
00076 }
00077
00078
00079 void elliptic_curves::XZ_mul2(mpz_t xr, mpz_t zr,
00080 const mpz_t x1, const mpz_t z1)
00081 {
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 mpz_add(h,x1,z1); mpz_mulmod(h,h,h,n);
00095 mpz_sub(k,x1,z1); mpz_mulmod(k,k,k,n);
00096 mpz_mulmod(xr,h,k,n);
00097
00098 mpz_sub(m,h,k);
00099 mpz_mulmod(h,b,m,n);
00100 mpz_add(k,k,h);
00101 mpz_mulmod(zr,k,m,n);
00102 }
00103 const int COST_XZ_mul2 = 5;
00104
00105 void elliptic_curves::XZ_mul2plus1(mpz_t xr, mpz_t zr,
00106 const mpz_t Xp0, const mpz_t Zp0,
00107 const mpz_t Xp1, const mpz_t Zp1,
00108 const mpz_t x1, const mpz_t z1)
00109 {
00110
00111 mpz_sub(h,Xp1,Zp1); mpz_add(m,Xp0,Zp0);
00112 mpz_mulmod(h,h,m,n);
00113 mpz_add(k,Xp1,Zp1); mpz_sub(m,Xp0,Zp0);
00114 mpz_mulmod(k,k,m,n);
00115
00116
00117
00118 mpz_add(m,h,k); mpz_sub(h,h,k);
00119 mpz_mulmod(m,m,m,n); mpz_mul(m,m,z1);
00120 mpz_mulmod(h,h,h,n); mpz_mul(h,h,x1);
00121 modulo(xr,m,n);
00122 modulo(zr,h,n);
00123 }
00124 const int COST_XZ_mul2plus1 = 6;
00125
00126
00127 #if 0
00128
00129 void elliptic_curves::XZ_multiply(mpz_t xr, mpz_t zr,
00130 const mpz_t x1, const mpz_t z1,
00131 NATNUM K)
00132 {
00133 #ifdef DEBUG_ECM
00134 cout << "XZ_multiply " << K << " -> " << endl;
00135 #endif
00136
00137 bool s[100];
00138 signed int i=0;
00139
00140 K>>=1;
00141 while (K>1)
00142 {
00143 s[i++]=(K&1);
00144 K>>=1;
00145 }
00146 #ifdef DEBUG_ECM
00147 int value=1, valuep1=2;
00148 #endif
00149 mpz_t Xp0,Zp0,Xp1,Zp1;
00150 mpz_init_set(Xp0,x1); mpz_init_set(Zp0,z1);
00151 mpz_init(Xp1); mpz_init(Zp1);
00152 XZ_mul2(Xp1,Zp1,x1,z1);
00153
00154 while (--i>=0)
00155 {
00156 if (s[i])
00157 {
00158 #ifdef DEBUG_ECM
00159 value=value+valuep1; valuep1=valuep1+valuep1;
00160 #endif
00161 XZ_mul2plus1(Xp0,Zp0,Xp0,Zp0,Xp1,Zp1,x1,z1);
00162 XZ_mul2(Xp1,Zp1,Xp1,Zp1);
00163 }
00164 else
00165 {
00166 #ifdef DEBUG_ECM
00167 valuep1=value+valuep1; value=value+value;
00168 #endif
00169 XZ_mul2plus1(Xp1,Zp1,Xp0,Zp0,Xp1,Zp1,x1,z1);
00170 XZ_mul2(Xp0,Zp0,Xp0,Zp0);
00171 }
00172
00173 }
00174
00175
00176
00177 #ifdef DEBUG_ECM
00178 cout << "value=" << value+valuep1 << endl;
00179 #endif
00180 XZ_mul2plus1(xr,zr,Xp0,Zp0,Xp1,Zp1,x1,z1);
00181
00182 mpz_clear(Xp0); mpz_clear(Zp0);
00183 mpz_clear(Xp1); mpz_clear(Zp1);
00184 }
00185
00186 #else
00187
00188
00189 inline void swap(PmpzPoint &A, PmpzPoint &B)
00190 {
00191 PmpzPoint H;
00192 H=A; A=B; B=H;
00193 }
00194
00195 inline void swap(PmpzPoint &A, PmpzPoint &B, PmpzPoint &C)
00196 {
00197 PmpzPoint H;
00198 H=A; A=B; B=C; C=H;
00199 }
00200
00201
00202 unsigned int elliptic_curves::cost_of_evaluating_lucas_chain(const NATNUM K, const double alpha)
00203 {
00204
00205
00206
00207 const NATNUM r=static_cast<NATNUM>(rint(K/alpha));
00208 register unsigned int COST=0;
00209
00210
00211
00212 COST+=COST_XZ_mul2;
00213 NATNUM d=K-r;
00214 NATNUM e=2*r-K;
00215
00216 while (d!=e)
00217 {
00218
00219 if (d<e)
00220 {
00221 std::swap(e,d);
00222 }
00223
00224
00225 if ( ((d+e)%3==0) && (d*4<=e*5) )
00226 {
00227
00228 const NATNUM d_new=(2*d-e)/3;
00229 e=(2*e-d)/3; d=d_new;
00230 COST+=3*COST_XZ_mul2plus1;
00231 continue;
00232 }
00233 if ( ((d-e)%6==0) && (d*4<=e*5) )
00234 {
00235
00236 d=(d-e)>>1;
00237 COST+=COST_XZ_mul2plus1 + COST_XZ_mul2;
00238 continue;
00239 }
00240 if (d<=4*e)
00241 {
00242
00243 d=d-e;
00244 COST+=COST_XZ_mul2plus1;
00245 continue;
00246 }
00247 if ( ((d-e)&1)==0 )
00248 {
00249
00250 d=(d-e)>>1;
00251 COST+=COST_XZ_mul2plus1 + COST_XZ_mul2;
00252 continue;
00253 }
00254 if ((d&1)==0)
00255 {
00256
00257 d>>=1;
00258 COST+=COST_XZ_mul2plus1 + COST_XZ_mul2;
00259 continue;
00260 }
00261 if (d%3==0)
00262 {
00263
00264 d=(d/3)-e;
00265 COST+=COST_XZ_mul2 + 3*COST_XZ_mul2plus1;
00266 continue;
00267 }
00268 if ((d+e)%3==0)
00269 {
00270
00271 d=(d-2*e)/3;
00272 COST+=COST_XZ_mul2 + 3*COST_XZ_mul2plus1;
00273 continue;
00274 }
00275 if ((d-e)%3==0)
00276 {
00277
00278 d=(d-e)/3;
00279 COST+=COST_XZ_mul2 + 3*COST_XZ_mul2plus1;
00280 continue;
00281 }
00282 if ((e&1)==0)
00283 {
00284
00285 e>>=1;
00286 COST+=COST_XZ_mul2plus1 + COST_XZ_mul2;
00287 continue;
00288 }
00289 cerr << "Error in PRAC-Algorithm" << endl;
00290 exit(1);
00291 }
00292 COST+=COST_XZ_mul2plus1;
00293
00294
00295 return COST;
00296 }
00297
00298
00299 void elliptic_curves::XZ_multiply(mpz_t xr, mpz_t zr,
00300 const mpz_t x1, const mpz_t z1,
00301 NATNUM K)
00302 {
00303 #ifdef DEBUG_ECM
00304 cout << "XZ_multiply (PRAC)" << K << " -> " << endl;
00305 #endif
00306
00307 static const double alpha_continued_fraction [25] =
00308 {
00309
00310 1.618033988749894848204587,
00311 1.723606797749978969640917,
00312 1.381966011250105151795413,
00313 1.580178728295464104708674,
00314 1.632839806088706285425954,
00315 1.612429949509495001921461,
00316 1.617214616534403862663845,
00317 1.620181980807415764823945,
00318 1.618347119656228057976350,
00319 1.617914406528817893862475,
00320 1.618079668469895811954673,
00321 1.618016541142025285987741,
00322 1.618040653214942998209496,
00323 1.618031443161248228921464,
00324 1.618034961079766208915596,
00325 1.618033617353155449748868,
00326 1.618034130610858549698459,
00327 1.618033934563833141806412,
00328 1.618034009447129396675689,
00329 1.618033980844254824942950,
00330 1.618033991769580649023070,
00331 1.618033987596477509789958,
00332 1.618033989190461068579593,
00333 1.618033988581613526362231,
00334 1.618033988814172593483292,
00335 };
00336
00337 static unsigned int first_best [25] =
00338 { 1, 11, 23, 103, 173,
00339 367, 491, 673, 1433, 4871,
00340 11311, 25873, 67057, 173669, 401393,
00341 1039387, 2774557, 7121347, 18732257, 48650851,
00342 126814879, 333390199, 867971879, 0, 0 };
00343
00344 unsigned int best_i = 0;
00345
00346
00347 #if 0
00348 {
00349 cout << "PRAC-implementation: searching for optimal lucas chains..." << endl;
00350 for (unsigned K=3; K<4000000000; K+=2) if (probab_prime(K))
00351 {
00352
00353 unsigned int best_i = 0;
00354 unsigned int best_cost=cost_of_evaluating_lucas_chain(K,alpha_continued_fraction[0]);
00355 for (unsigned int i=1; i<25; ++i)
00356 {
00357 const unsigned int cost=cost_of_evaluating_lucas_chain(K,alpha_continued_fraction[i]);
00358 if (cost<best_cost) { best_cost=cost; best_i=i; }
00359 }
00360
00361 static unsigned int index = 0;
00362 if (best_i>index)
00363 {
00364 index=best_i;
00365 cout << endl << "K[" << best_i << "]=" << K << endl;
00366 }
00367 }
00368 exit(0);
00369
00370
00371
00372
00373
00374 }
00375 #endif
00376
00377
00378
00379 #if 1
00380 {
00381
00382 unsigned int best_cost=cost_of_evaluating_lucas_chain(K,alpha_continued_fraction[0]);
00383 for (unsigned int i=1; K>=first_best[i] && i<23; ++i)
00384 {
00385 const unsigned int cost=cost_of_evaluating_lucas_chain(K,alpha_continued_fraction[i]);
00386 if (cost<best_cost) { best_cost=cost; best_i=i; }
00387 }
00388 }
00389 #endif
00390
00391
00392 mpz_set(A->x,x1); mpz_set(A->z,z1);
00393
00394
00395 const NATNUM r=static_cast<NATNUM>(rint(K/alpha_continued_fraction[best_i]));
00396
00397
00398 mpz_set(B->x,A->x); mpz_set(B->z,A->z);
00399 mpz_set(C->x,A->x); mpz_set(C->z,A->z);
00400 XZ_mul2(A,A);
00401 NATNUM d=K-r;
00402 NATNUM e=2*r-K;
00403
00404 while (d!=e)
00405 {
00406
00407 if (d<e)
00408 {
00409 std::swap(e,d);
00410 swap(A,B);
00411 }
00412
00413
00414 if ( ((d+e)%3==0) && (d*4<=e*5) )
00415 {
00416
00417 const NATNUM d_new=(2*d-e)/3;
00418 e=(2*e-d)/3; d=d_new;
00419 XZ_mul2plus1(T1,A,B,C);
00420 XZ_mul2plus1(T2,T1,A,B);
00421 XZ_mul2plus1(B,B,T1,A);
00422 swap(A,T2);
00423 continue;
00424 }
00425 if ( ((d-e)%6==0) && (d*4<=e*5) )
00426 {
00427
00428 d=(d-e)>>1;
00429 XZ_mul2plus1(B,A,B,C);
00430 XZ_mul2(A,A);
00431 continue;
00432 }
00433 if (d<=4*e)
00434 {
00435
00436 d=d-e;
00437 XZ_mul2plus1(T1,B,A,C);
00438 swap(B,T1,C);
00439 continue;
00440 }
00441 if ( ((d-e)&1)==0 )
00442 {
00443
00444 d=(d-e)>>1;
00445 XZ_mul2plus1(B,B,A,C);
00446 XZ_mul2(A,A);
00447 continue;
00448 }
00449 if ((d&1)==0)
00450 {
00451
00452 d>>=1;
00453 XZ_mul2plus1(C,C,A,B);
00454 XZ_mul2(A,A);
00455 continue;
00456 }
00457 if (d%3==0)
00458 {
00459
00460 d=(d/3)-e;
00461 XZ_mul2(T1,A);
00462 XZ_mul2plus1(T2,A,B,C);
00463 XZ_mul2plus1(A,T1,A,A);
00464 XZ_mul2plus1(T1,T1,T2,C);
00465 swap(C,B,T1);
00466 continue;
00467 }
00468 if ((d+e)%3==0)
00469 {
00470
00471 d=(d-2*e)/3;
00472 XZ_mul2plus1(T1,A,B,C);
00473 XZ_mul2plus1(B,T1,A,B);
00474 XZ_mul2(T1,A); XZ_mul2plus1(A,A,T1,A);
00475 continue;
00476 }
00477 if ((d-e)%3==0)
00478 {
00479
00480 d=(d-e)/3;
00481 XZ_mul2plus1(T1,A,B,C);
00482 XZ_mul2plus1(C,C,A,B);
00483 swap(B,T1);
00484 XZ_mul2(T1,A); XZ_mul2plus1(A,A,T1,A);
00485 continue;
00486 }
00487 if ((e&1)==0)
00488 {
00489
00490 e>>=1;
00491 XZ_mul2plus1(C,C,B,A);
00492 XZ_mul2(B,B);
00493 continue;
00494 }
00495 cerr << "Error in PRAC-Algorithm" << endl;
00496 exit(1);
00497 }
00498 XZ_mul2plus1(A,A,B,C);
00499
00500
00501 mpz_set(xr,A->x); mpz_set(zr,A->z);
00502 }
00503 #endif
00504
00505
00506 bool elliptic_curves::mul2(mpz_t xr, mpz_t yr, const mpz_t x1, const mpz_t y1)
00507 {
00508
00509 mpz_mul_ui(k,y1,2); mpz_mul(k,k,b); mpz_mod(k,k,n);
00510 if (!mpz_invert(k,k,n))
00511 {
00512 mpz_mul_ui(k,y1,2); mpz_mul(k,k,b); mpz_mod(k,k,n); mpz_gcd(k,k,n);
00513 factor_found(k);
00514 return true;
00515 }
00516 mpz_mul(m,x1,x1); mpz_mod(m,m,n); mpz_mul_ui(m,m,3);
00517 mpz_mul(h,a,x1); mpz_mul_ui(h,h,2); mpz_add(m,m,h); mpz_add_ui(m,m,1);
00518 mpz_mul(m,m,k); mpz_mod(m,m,n);
00519 mpz_mul(x3,m,m); mpz_mul(x3,x3,b); mpz_sub(x3,x3,a); mpz_sub(x3,x3,x1); mpz_sub(x3,x3,x1); mpz_mod(x3,x3,n);
00520 mpz_sub(y3,x1,x3); mpz_mul(y3,y3,m); mpz_sub(y3,y3,y1); mpz_mod(yr,y3,n);
00521 mpz_set(xr,x3);
00522 #ifdef DEBUG_ECM
00523 cout << "mul2 " << xr << "," << yr << endl;
00524 check_curve(xr,yr);
00525 #endif
00526 return false;
00527 }
00528
00529 bool elliptic_curves::sub(mpz_t xr, mpz_t yr,
00530 const mpz_t x1, const mpz_t y1,
00531 const mpz_t x2, const mpz_t y2)
00532 {
00533 bool flag;
00534 mpz_t y2_inv;
00535
00536 mpz_init(y2_inv);
00537 mpz_neg(y2_inv, y2);
00538 mpz_mod(y2_inv, y2_inv, n);
00539 flag = add(xr,yr,x1,y1,x2,y2_inv);
00540 mpz_clear(y2_inv);
00541 return flag;
00542 }
00543
00544
00545 bool elliptic_curves::add(mpz_t xr, mpz_t yr,
00546 const mpz_t x1, const mpz_t y1,
00547 const mpz_t x2, const mpz_t y2)
00548 {
00549
00550 if (mpz_cmp(x1,x2))
00551 {
00552 mpz_sub(k,x2,x1); mpz_mod(k,k,n);
00553 if (!mpz_invert(k,k,n))
00554 {
00555 mpz_sub(k,x2,x1); mpz_mod(k,k,n); mpz_gcd(k,k,n);
00556 factor_found(k);
00557 return true;
00558 }
00559 mpz_sub(m,y2,y1); mpz_mul(m,m,k); mpz_mod(m,m,n);
00560 mpz_mul(x3,m,m); mpz_mul(x3,x3,b); mpz_sub(x3,x3,a); mpz_sub(x3,x3,x1); mpz_sub(x3,x3,x2); mpz_mod(x3,x3,n);
00561 mpz_sub(y3,x1,x3); mpz_mul(y3,y3,m); mpz_sub(y3,y3,y1); mpz_mod(y3,y3,n);
00562 }
00563 else
00564 {
00565 if (mpz_cmp(y1,y2)==0)
00566 {
00567 mpz_mul_ui(k,y1,2); mpz_mul(k,k,b); mpz_mod(k,k,n);
00568 if (!mpz_invert(k,k,n))
00569 {
00570 mpz_mul_ui(k,y1,2); mpz_mul(k,k,b); mpz_mod(k,k,n); mpz_gcd(k,k,n);
00571 factor_found(k);
00572 return true;
00573 }
00574 mpz_mul(m,x1,x1); mpz_mod(m,m,n); mpz_mul_ui(m,m,3);
00575 mpz_mul(h,a,x1); mpz_mul_ui(h,h,2); mpz_add(m,m,h);
00576 mpz_add_ui(m,m,1);
00577 mpz_mul(m,m,k); mpz_mod(m,m,n);
00578 mpz_mul(x3,m,m); mpz_mul(x3,x3,b); mpz_sub(x3,x3,a); mpz_sub(x3,x3,x1); mpz_sub(x3,x3,x2); mpz_mod(x3,x3,n);
00579 mpz_sub(y3,x1,x3); mpz_mul(y3,y3,m); mpz_sub(y3,y3,y1); mpz_mod(y3,y3,n);
00580 }
00581 else
00582 {
00583 cout << "Elliptic curves: feature not implemented." << endl;
00584 return true;
00585 }
00586 }
00587
00588 mpz_set(xr,x3); mpz_set(yr,y3);
00589 #ifdef DEBUG_ECM
00590 cout << "add" << endl;
00591 check_curve(xr,yr);
00592 #endif
00593 return false;
00594 }
00595
00596 bool elliptic_curves::add(mpz_t xr, mpz_t yr,
00597 const mpz_t x1, const mpz_t y1,
00598 const mpz_t x2, const mpz_t y2,
00599 mpz_t k)
00600 {
00601
00602
00603
00604
00605
00606 if (mpz_cmp(x1,x2))
00607 {
00608 mpz_sub(m,y2,y1); mpz_mul(m,m,k); mpz_mod(m,m,n);
00609 mpz_mul(x3,m,m); mpz_mul(x3,x3,b); mpz_sub(x3,x3,a); mpz_sub(x3,x3,x1); mpz_sub(x3,x3,x2); mpz_mod(x3,x3,n);
00610 mpz_sub(y3,x1,x3); mpz_mul(y3,y3,m); mpz_sub(y3,y3,y1); mpz_mod(y3,y3,n);
00611 }
00612 else
00613 {
00614 if (mpz_cmp(y1,y2)==0)
00615 {
00616 mpz_mul_ui(k,y1,2); mpz_mul(k,k,b); mpz_mod(k,k,n);
00617 if (!mpz_invert(k,k,n))
00618 {
00619 mpz_mul_ui(k,y1,2); mpz_mul(k,k,b); mpz_mod(k,k,n); mpz_gcd(k,k,n);
00620 factor_found(k);
00621 return true;
00622 }
00623 mpz_mul(m,x1,x1); mpz_mod(m,m,n); mpz_mul_ui(m,m,3);
00624 mpz_mul(h,a,x1); mpz_mul_ui(h,h,2); mpz_add(m,m,h);
00625 mpz_add_ui(m,m,1);
00626 mpz_mul(m,m,k); mpz_mod(m,m,n);
00627 mpz_mul(x3,m,m); mpz_mul(x3,x3,b); mpz_sub(x3,x3,a); mpz_sub(x3,x3,x1); mpz_sub(x3,x3,x2); mpz_mod(x3,x3,n);
00628 mpz_sub(y3,x1,x3); mpz_mul(y3,y3,m); mpz_sub(y3,y3,y1); mpz_mod(y3,y3,n);
00629 }
00630 else
00631 {
00632 cout << "Elliptic curves: feature not implemented." << endl;
00633 return true;
00634 }
00635 }
00636
00637 mpz_set(xr,x3); mpz_set(yr,y3);
00638 #ifdef DEBUG_ECM
00639 cout << "add" << endl;
00640 check_curve(xr,yr);
00641 #endif
00642 return false;
00643 }
00644
00645 bool elliptic_curves::init_arithmetic_progression(
00646 mpz_t* const x, mpz_t* const y, const mpz_t startx, const mpz_t starty,
00647 const NATNUM startpos, const unsigned int delta, const unsigned int grad)
00648 {
00649 for (unsigned int i=0; i<=grad; i++)
00650 {
00651 NATNUM e = startpos + (i*delta);
00652 mpz_set(x[i], startx); mpz_set(y[i], starty);
00653 for (unsigned int j=0; j<grad; j++)
00654 if (mul(x[i],y[i],x[i],y[i],e)) return true;
00655 }
00656 for (unsigned int i=1; i<=grad; i++)
00657 {
00658 for (unsigned int j=grad; j>=i; j--)
00659 if (sub(x[j],y[j],x[j],y[j],x[j-1],y[j-1])) return true;
00660 }
00661 return false;
00662 }
00663
00664 bool elliptic_curves::arithmetic_progression(mpz_t* const x, mpz_t* const y, const int anz)
00665 {
00666
00667
00668
00669
00670 #if 0
00671
00672 bool flag=false;
00673 for (int i=0; i<anz && !flag; ++i)
00674 flag=add(x[i],y[i],x[i],y[i],x[i+1],y[i+1]);
00675 return flag;
00676 #else
00677
00678
00679 mpz_t* const h = new mpz_t[anz];
00680 mpz_t* const r = new mpz_t[anz];
00681 bool flag=false;
00682 for (int i=0; i<anz; ++i)
00683 {
00684 mpz_init(h[i]); mpz_init(r[i]);
00685 mpz_sub(h[i],x[i+1],x[i]);
00686 if (mpz_cmp_ui(h[i],0)==0)
00687 {
00688 mpz_mul_ui(h[i],y[i],2); mpz_mul(h[i],h[i],b); mpz_mod(h[i],h[i],n);
00689 }
00690 }
00691
00692 if (mpz_multi_invert(r,h,anz,n))
00693 {
00694
00695 for (int i=0; i<anz && !flag; ++i)
00696 flag=add(x[i],y[i],x[i],y[i],x[i+1],y[i+1],r[i]);
00697 }
00698 else
00699 {
00700
00701 for (int i=0; i<anz && !flag; ++i)
00702 flag=add(x[i],y[i],x[i],y[i],x[i+1],y[i+1]);
00703 }
00704 for (int i=0; i<anz; ++i)
00705 {
00706 mpz_clear(h[i]); mpz_clear(r[i]);
00707 }
00708 delete [] h; delete [] r;
00709 return flag;
00710 #endif
00711 }
00712
00713 bool elliptic_curves::mul(mpz_t xr, mpz_t yr,
00714 const mpz_t x1, const mpz_t y1,
00715 NATNUM K)
00716 {
00717
00718
00719 mpz_set(xh_mul,x1); mpz_set(yh_mul,y1);
00720 #ifdef DEBUG_ECM
00721 if (K==0) { cerr << "multiplication by 0 is forbidden!"; exit(1); }
00722 #endif
00723 while ((K&1)==0)
00724 {
00725 K>>=1;
00726 if (mul2(xh_mul,yh_mul,xh_mul,yh_mul)) return true;
00727 }
00728
00729 mpz_set(xr,xh_mul); mpz_set(yr,yh_mul);
00730 while (K>>=1)
00731 {
00732 if (mul2(xh_mul,yh_mul,xh_mul,yh_mul)) return true;
00733 if (K&1) if (add(xr,yr,xr,yr,xh_mul,yh_mul)) return true;
00734 }
00735 #ifdef DEBUG_ECM
00736 cout << "mul" << endl;
00737 check_curve(xr,yr);
00738 #endif
00739 return false;
00740 }
00741
00742
00743 void elliptic_curves::go(const int ecm_sigma, NATNUM phase1, const NATNUM phase2)
00744 {
00745 using numtheory::is_prime;
00746 using numtheory::gcd;
00747
00748 CPersistentDataCollection RecoveryData("ecm-recover.dat");
00749
00750 #if (CONTINUATION_METHOD > 0)
00751
00752
00753
00754 CNamedSemaphore MemoryAvailable("/qsieve_gigs_of_mem",1);
00755 CConditionalNamedSemaphorePostAtDestruction LockPhase2(MemoryAvailable,false);
00756 #endif
00757
00758 mpz_t x,y,z, saved_x,saved_y, xh,yh;
00759 mpz_init(x); mpz_init(y); mpz_init(z);
00760 mpz_init(saved_x); mpz_init(saved_y);
00761 mpz_init(xh); mpz_init(yh);
00762 sigma=ecm_sigma;
00763
00764 RecoveryData.RegisterVar("x",x);
00765 RecoveryData.RegisterVar("y",y);
00766 RecoveryData.RegisterVar("z",z);
00767 RecoveryData.RegisterVar("saved_x",saved_x);
00768 RecoveryData.RegisterVar("saved_y",saved_y);
00769 RecoveryData.RegisterVar("xh",xh);
00770 RecoveryData.RegisterVar("yh",yh);
00771 RecoveryData.RegisterVar("sigma",sigma);
00772
00773 RecoveryData.RegisterVar("phase",phase);
00774 RecoveryData.RegisterVar("a",a);
00775 RecoveryData.RegisterVar("b",b);
00776
00777 NATNUM i,d;
00778 RecoveryData.RegisterVar("i",i);
00779 RecoveryData.RegisterVar("d",d);
00780
00781 if (sigma==-1)
00782 {
00783
00784 RecoveryData.Load();
00785 if (phase==1)
00786 {
00787 cout << "continue recovered elliptic curve..." << endl;
00788 goto StartPhase1;
00789 }
00790 MARK;
00791 cerr << "recovery of elliptic curve failed!" << endl;
00792 goto done;
00793 }
00794
00795 cout << "--------------------------------------------------" << endl;
00796
00797 #if 1
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808 mpz_set_ui(x,sigma); mpz_mul(x,x,x); mpz_sub_ui(x,x,5); mpz_mod(x,x,n);
00809 mpz_set_ui(y,sigma); mpz_mul_ui(y,y,4); mpz_mod(y,y,n);
00810 mpz_powm_ui(b,x,3,n); mpz_mul(b,b,y); mpz_mul_ui(b,b,4); mpz_mod(b,b,n);
00811 mpz_invert(a,b,n);
00812 mpz_sub(xh,y,x); mpz_powm_ui(xh,xh,3,n);
00813 mpz_mul_ui(yh,x,3); mpz_add(yh,yh,y); mpz_mul(xh,xh,yh);
00814 mpz_mul(a,a,xh); mpz_sub_ui(a,a,2); mpz_mod(a,a,n);
00815
00816 mpz_powm_ui(x,x,3,n); mpz_powm_ui(z,y,3,n);
00817
00818
00819
00820
00821 mpz_invert(z,z,n); mpz_mul(x,x,z); mpz_mod(x,x,n);
00822 mpz_set_ui(y,1);
00823 mpz_powm_ui(xh,x,3,n); mpz_powm_ui(yh,x,2,n); mpz_mul(yh,yh,a);
00824 mpz_add(xh,xh,yh); mpz_add(b,xh,x); mpz_mod(b,b,n);
00825 mpz_set_ui(z,1);
00826
00827
00828 #else
00829 cout << "Alternative Sigma-Methode" << endl;
00830
00831 if (sigma==2) { cerr << "wrong sigma (must be <>2)!" << endl; return; }
00832 mpz_set_ui(a,sigma); mpz_set_ui(y,1);
00833 mpz_set_ui(x,2);
00834 mpz_mul_ui(b,a,4); mpz_add_ui(b,b,10);
00835 #endif
00836
00837 cout << "Trying Elliptic Curve Method with sigma=" << sigma << endl;
00838 #ifdef VERBOSE
00839 cout << "x=" << x << endl;
00840 cout << "y=" << y << endl;
00841 cout << "a=" << a << endl;
00842 cout << "b=" << b << endl;
00843 #endif
00844
00845 #ifdef DEBUG_ECM
00846 check_curve(x,y);
00847 #endif
00848
00849 #ifndef SLOW_WEIERSTRASS
00850
00851 mpz_set_ui(h,4); mpz_invert(h,h,n);
00852 mpz_add_ui(b,a,2); mpz_mul(b,b,h); mpz_mod(b,b,n);
00853 #endif
00854
00855 #if defined(NRESIDUE) && !defined(SLOW_WEIERSTRASS)
00856
00857 NResidue.convert(a); NResidue.convert(b);
00858 NResidue.convert(x); NResidue.convert(y); NResidue.convert(z);
00859 #endif
00860
00861
00862
00863 phase=0;
00864 #ifdef VERBOSE_NOTICE
00865 cout << "Elliptic Curve Phase 0" << endl;
00866 #endif
00867 #ifdef SLOW_WEIERSTRASS
00868 for (int j=1; j<=50; j++) if (mul2(x,y,x,y)) goto done;
00869 for (int j=1; j<=25; j++) if (mul(x,y,x,y,3)) goto done;
00870 #else
00871 for (int j=1; j<=50; j++) XZ_mul2(x,z,x,z);
00872 for (int j=1; j<=25; j++)
00873 {
00874 XZ_mul2(xh,yh,x,z);
00875 XZ_mul2plus1(x,z,xh,yh,x,z,x,z);
00876 }
00877 #endif
00878 d=4; i=1;
00879 while (i<500)
00880 {
00881 do { i+=d; d=6-d; } while (!is_prime(i));
00882 NATNUM j=phase2;
00883 NATNUM k=1;
00884 do { k*=i; j/=i; } while (j>=i);
00885 #ifdef SLOW_WEIERSTRASS
00886 if (mul(x,y,x,y,k)) goto done;
00887 if (mul(x,y,x,y,k)) goto done;
00888 #else
00889 XZ_multiply(x,z,x,z,k);
00890 XZ_multiply(x,z,x,z,k);
00891 #endif
00892 }
00893
00894 #ifndef SLOW_WEIERSTRASS
00895 mpz_gcd(h,z,n); if (mpz_cmp_ui(h,1)) { factor_found(h); goto done; }
00896 #endif
00897
00898 StartPhase1:
00899
00900 #ifdef DEBUG_ECM
00901 check_curve(x,y);
00902 #endif
00903
00904 {
00905
00906 phase=1;
00907 const unsigned int D=2*3*5*7*11*13*2;
00908 i=i-(i%D);
00909 #ifdef VERBOSE_NOTICE
00910 cout << "Elliptic Curve Phase 1" << endl;
00911 #endif
00912
00913 resume_phase1:
00914 while (i<=phase1)
00915 {
00916 RecoveryData.Save();
00917 #ifdef REACT_ON_SIGUSR
00918 if (USRSignalHandler.got_SIGUSR1()) goto done;
00919 if (USRSignalHandler.got_SIGUSR2()) break;
00920 #endif
00921
00922 bool sieve[D];
00923 sieve[1]=(i!=0);
00924 for (unsigned int j=3; j<=D; j+=2) sieve[j]=true;
00925 for (unsigned int p=5, dp=2; p*p<i+D; p+=dp, dp=6-dp)
00926 for (unsigned int j=p-(i%p); j<D; j+=p) sieve[j]=false;
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936 for (unsigned int j=1, dj=4; j<D; j+=dj, dj=6-dj)
00937 {
00938
00939
00940 if (sieve[j])
00941 {
00942 NATNUM i2 = i+j;
00943 NATNUM j2=phase2, k=1;
00944 do { k*=i2; j2/=i2; } while (j2>=i2);
00945 #ifdef SLOW_WEIERSTRASS
00946 if (mul(x,y,x,y,k)) goto done;
00947 #else
00948 XZ_multiply(x,z,x,z,k);
00949 #endif
00950 if (i2>=phase1) { i=i2; d=dj; break; }
00951 }
00952 }
00953
00954
00955
00956
00957 #ifndef SLOW_WEIERSTRASS
00958 mpz_gcd(h,z,n); if (mpz_cmp_ui(h,1)) { factor_found(h); goto done; }
00959 #endif
00960
00961 if (i<=phase1) i+=D;
00962 #ifdef VERBOSE_NOTICE
00963 cout << "Phase1: " << i << "/" << phase1 << "\r" << flush;
00964 #endif
00965 }
00966
00967 if (i>=phase2) goto done;
00968
00969 #if (CONTINUATION_METHOD > 0)
00970
00971
00972 if (MemoryAvailable.trywait())
00973 {
00974 LockPhase2.set_condition();
00975 }
00976 else
00977 {
00978 phase1+=2*D;
00979 cout << "phase 2 is locked by another process; extending phase 1 to " << phase1 << "." << endl;
00980 goto resume_phase1;
00981 }
00982 #endif
00983
00984 if (i%D==0)
00985 {
00986 i--; d=4; while (!is_prime(i)) { i-=d; d=6-d; }
00987 }
00988 #ifdef VERBOSE_NOTICE
00989 cout << "Elliptic Curve Phase 1, up to " << i << endl;
00990 #endif
00991
00992 }
00993
00994
00995 #ifndef SLOW_WEIERSTRASS
00996
00997 mpz_gcd(h,z,n); if (mpz_cmp_ui(h,1)) { factor_found(h); goto done; }
00998 mpz_gcd(h,x,n); if (mpz_cmp_ui(h,1)) { factor_found(h); goto done; }
00999
01000 #if defined(NRESIDUE) && !defined(SLOW_WEIERSTRASS)
01001
01002 NResidue.convert_back(a); NResidue.convert_back(b);
01003 NResidue.convert_back(x); NResidue.convert_back(y); NResidue.convert_back(z);
01004 #endif
01005
01006
01007 mpz_set_ui(y,1);
01008 mpz_invert(h,z,n); mpz_mul(x,x,h); mpz_mod(x,x,n);
01009
01010 mpz_powm_ui(xh,x,3,n); mpz_powm_ui(yh,x,2,n); mpz_mul(yh,yh,a);
01011 mpz_add(xh,xh,yh); mpz_add(b,xh,x); mpz_mod(b,b,n);
01012 mpz_set_ui(z,1);
01013
01014 check_curve(x,y);
01015 #endif
01016
01017 phase=2;
01018
01019 #if (CONTINUATION_METHOD==0)
01020
01021
01022
01023
01024
01025
01026
01027
01028 {
01029
01030
01031
01032
01033 cout << "Elliptic Curve Phase 2 (improved)" << endl;
01034 mpz_set(saved_x,x); mpz_set(saved_y,y);
01035
01036
01037
01038 unsigned int pre_mul_size = 2*3*5;
01039 {
01040
01041
01042
01043
01044
01045 unsigned int p=5;
01046 do
01047 {
01048 do p+=2; while (!is_prime(p));
01049 pre_mul_size*=p;
01050 } while (pre_mul_size<=phase2/pre_mul_size);
01051
01052 if (pre_mul_size>3*sqrt(phase2))
01053 {
01054 pre_mul_size/=p;
01055
01056 pre_mul_size*=static_cast<unsigned int>(ceil(sqrt(phase2)/pre_mul_size));
01057 }
01058 #ifdef VERBOSE_INFO
01059 cout << "pre_mul_size=" << pre_mul_size << endl;
01060 #endif
01061 }
01062
01063 mpz_t* const bfact = new mpz_t[pre_mul_size];
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101 const int table_dxy_size = 23;
01102 mpz_t table_dxy[table_dxy_size][2];
01103
01104 if (mul2(x,y,saved_x,saved_y)) goto done;
01105 mpz_set(xh,x); mpz_set(yh,y);
01106
01107 mpz_init_set(table_dxy[2][0],x);
01108 mpz_init_set(table_dxy[2][1],y);
01109 for (int j=4; j<table_dxy_size; j+=2)
01110 {
01111 if (add(x,y,x,y,xh,yh)) goto done;
01112 mpz_init_set(table_dxy[j][0],x);
01113 mpz_init_set(table_dxy[j][1],y);
01114 }
01115
01116 mpz_set(x,xh); mpz_set(y,yh);
01117 for (int j=pre_mul_size-1, jlast=pre_mul_size-1; j>=0; j-=2)
01118 {
01119 if (gcd(j,pre_mul_size)==1)
01120 {
01121
01122
01123
01124
01125 int dj=jlast-j;
01126 if (dj>=table_dxy_size)
01127 {
01128 cerr << "increase table_dxy_size to " << dj+1 << "!" << endl;
01129 exit(1);
01130 }
01131 if (dj>0)
01132 if (add(x,y,x,y,table_dxy[dj][0],table_dxy[dj][1])) goto done;
01133 jlast=j;
01134 mpz_init_set(bfact[j],x);
01135 #ifdef NRESIDUE
01136 NResidue.convert(bfact[j]);
01137 #endif
01138 }
01139 }
01140
01141 for (int j=2; j<table_dxy_size; j+=2)
01142 {
01143 mpz_clear(table_dxy[j][0]);
01144 mpz_clear(table_dxy[j][1]);
01145 }
01146
01147
01148 NATNUM next_i;
01149 mpz_t collector;
01150 mpz_init(collector); mpz_set_ui(collector,1);
01151
01152
01153 if (mul(xh,yh,saved_x,saved_y,pre_mul_size)) goto done;
01154
01155
01156 if (i<pre_mul_size)
01157 {
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169 #ifdef VERBOSE_INFO
01170 cout << "need to increase start value for phase 2..." << endl;
01171 #endif
01172 i+=pre_mul_size;
01173 }
01174 i=((i/pre_mul_size)*pre_mul_size)-1; d=2;
01175 if (mul(x,y,saved_x,saved_y,i)) goto done;
01176
01177 next_i = i+1+pre_mul_size;
01178
01179 bool* const sieve = new bool[pre_mul_size];
01180 for (int i1=pre_mul_size-1; i1>=0; i1-=2) sieve[i1]=false;
01181
01182 for (unsigned int p=5, dp=2; p<pre_mul_size && p*p<next_i; p+=dp, dp=6-dp )
01183 for (unsigned int i1=p-((next_i-pre_mul_size)%p); i1<pre_mul_size; i1+=p) sieve[i1]=true;
01184
01185 while (i<=phase2)
01186 {
01187 int runden=25000;
01188 while (runden>0)
01189 {
01190
01191 do { i+=d; d=6-d; } while (i<next_i && sieve[i%pre_mul_size]);
01192
01193
01194
01195 while (i>next_i)
01196 {
01197 next_i += pre_mul_size;
01198 if (add(x,y,x,y,xh,yh)) goto done_phase2;
01199 #ifdef NRESIDUE
01200 mpz_set(saved_x,x);
01201 NResidue.convert(saved_x);
01202 #endif
01203 for (int i1=pre_mul_size-1; i1>=0; i1-=2) sieve[i1]=false;
01204 for (unsigned int p=5, dp=2; p<pre_mul_size && p*p<next_i; p+=dp, dp=6-dp)
01205 for (unsigned int i1=p-((next_i-pre_mul_size)%p); i1<pre_mul_size; i1+=p) sieve[i1]=true;
01206 }
01207
01208
01209 #ifdef NRESIDUE
01210 mpz_sub(h,saved_x,bfact[next_i-i]);
01211 #else
01212 mpz_sub(h,x,bfact[next_i-i]);
01213 #endif
01214 mpz_mul(collector,collector,h); modulo(collector,collector,n);
01215 --runden;
01216 }
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229 mpz_gcd(collector,collector,n);
01230 if (mpz_cmp_ui(collector,1)) { factor_found(collector); goto done_phase2; }
01231 mpz_set_ui(collector,1);
01232 #ifdef VERBOSE_NOTICE
01233 cout << "Phase2: " << i << "/" << phase2 << "\r" << flush;
01234 #endif
01235 }
01236
01237 done_phase2:
01238 mpz_clear(collector);
01239 #ifdef VERBOSE_NOTICE
01240 cout << "Elliptic Curve Phase 2, up to " << i << endl;
01241 #endif
01242 for (int j=pre_mul_size-1; j>=0; j-=2)
01243 {
01244
01245
01246 if (gcd(j,pre_mul_size)==1) mpz_clear(bfact[j]);
01247 }
01248 delete [] sieve;
01249 delete [] bfact;
01250 }
01251
01252
01253
01254 #else
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271 {
01272
01273
01274
01275 #ifdef VERBOSE_NOTICE
01276 cout << "Elliptic Curve Phase 2 (improved with pairing & fft)" << endl;
01277 #endif
01278 mpz_set(saved_x,x); mpz_set(saved_y,y);
01279
01280
01281
01282
01283 unsigned int pg=256, pms=2*1050;
01284 get_fft_parameter(pg,pms,phase2,n);
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300 const unsigned int pre_mul_size = pms;
01301 const unsigned int Polynom_Index = pg;
01302
01303
01304
01305
01306 mpz_t* const collector = new mpz_t[Polynom_Index];
01307 for (unsigned int j=0; j<Polynom_Index; ++j) mpz_init(collector[j]);
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331 const int d_exp = 12;
01332 mpz_t xd[d_exp+1], yd[d_exp+1];
01333 for (int j=0; j<=d_exp; ++j) { mpz_init(xd[j]); mpz_init(yd[j]); }
01334 if (init_arithmetic_progression(xd, yd, saved_x, saved_y, 1, 2, d_exp)) goto done;
01335
01336 unsigned int Polynom_Index_i = 0;
01337 for (unsigned int j=1; j<pre_mul_size/2; j+=2)
01338 {
01339 if (gcd(j,pre_mul_size)==1)
01340 {
01341
01342
01343
01344
01345
01346 mpz_set(collector[Polynom_Index_i++],xd[0]);
01347 }
01348 if (arithmetic_progression(xd,yd,d_exp)) goto done;
01349 }
01350
01351 #ifdef VERBOSE_INFO
01352 cout << "original size of polynomial: " << Polynom_Index_i << endl;
01353 #endif
01354
01355 polynomial::TPolynom Polynom = NULL;
01356
01357
01358
01359
01360
01361
01362 {
01363 unsigned int anz_Punkte=Polynom_Index_i;
01364 while (anz_Punkte<Polynom_Index) mpz_set_ui(collector[anz_Punkte++],0);
01365 Polynom_Index_i=polynomial::construct_polynomial_from_roots(Polynom,collector,anz_Punkte,n);
01366 #ifdef VERBOSE_INFO
01367 cout << "polynomial created. size of polynomial = " << Polynom_Index_i << endl;
01368 #endif
01369 }
01370
01371
01372 i=i-(i%pre_mul_size);
01373
01374
01375
01376
01377
01378
01379 if (init_arithmetic_progression(xd, yd, saved_x, saved_y, i+pre_mul_size/2, pre_mul_size, d_exp)) goto done_phase2;
01380
01381 while (i<=phase2)
01382 {
01383
01384 #ifdef VERBOSE_NOTICE
01385 cout << "Phase2: " << i << "/" << phase2 << ", preparing new interval" << endl;
01386 #endif
01387 #ifdef VERBOSE_INFO
01388 cout << "Computing and collecting values..." << endl;
01389 #endif
01390
01391 i+=pre_mul_size/2;
01392
01393 unsigned int collector_index=0;
01394 while (collector_index<(Polynom_Index_i-1)/2)
01395 {
01396
01397 mpz_set(collector[collector_index++],xd[0]);
01398
01399 if (arithmetic_progression(xd,yd,d_exp)) goto done_phase2;
01400 i += pre_mul_size;
01401 }
01402 i-=pre_mul_size/2;
01403
01404 #ifdef REACT_ON_SIGUSR
01405 if (USRSignalHandler.got_SIGUSR1()) goto done_phase2;
01406 if (USRSignalHandler.got_SIGUSR2()) continue;
01407 #endif
01408
01409
01410 #ifdef VERBOSE_NOTICE
01411 cout << "Phase2: " << i << "/" << phase2 << ", evaluating" << endl;
01412 #endif
01413 #ifdef VERBOSE_INFO
01414 cout << "starting multipoint polynomial evaluation" << endl;
01415 cout << "Parameter: polynomial size: " << Polynom_Index_i
01416 << ", points to evaluate: " << collector_index << endl;
01417 #endif
01418 polynomial::multipoint_eval(collector,Polynom,Polynom_Index_i,collector,collector_index,n);
01419 #ifdef VERBOSE_INFO
01420 cout << "polynomial evaluation finished, computing gcd." << endl;
01421 #endif
01422 mpz_set(h,collector[0]);
01423 for (unsigned int j=1; j<collector_index; ++j) { mpz_mul(h,h,collector[j]); mpz_mod(h,h,n); }
01424 mpz_gcd(h,h,n);
01425
01426
01427
01428
01429
01430
01431 if (mpz_cmp_ui(h,1))
01432 {
01433 if (mpz_probab_prime_p(h,probab_prime_checks))
01434 { factor_found(h); goto done_phase2; }
01435 else
01436 {
01437 for (unsigned int j=0; j<collector_index; ++j)
01438 {
01439 mpz_gcd(h,collector[j],n);
01440 if (mpz_cmp_ui(h,1)) factor_found(h);
01441 }
01442 goto done_phase2;
01443 }
01444 }
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475 }
01476
01477 done_phase2:
01478 for (int j=0; j<=d_exp; ++j) { mpz_clear(xd[j]); mpz_clear(yd[j]); }
01479 for (unsigned int j=0; j<Polynom_Index; ++j) mpz_clear(collector[j]);
01480 delete [] collector;
01481 for (unsigned int j=0; j<Polynom_Index_i; ++j) mpz_clear(Polynom[j]);
01482 delete [] Polynom;
01483 #ifdef VERBOSE_NOTICE
01484 cout << "Elliptic Curve Phase 2, up to " << i << endl;
01485 #endif
01486 }
01487
01488
01489
01490
01491 #endif
01492
01493 done:
01494 RecoveryData.ClearStream();
01495 mpz_clear(x); mpz_clear(y); mpz_clear(z);
01496 mpz_clear(saved_x); mpz_clear(saved_y);
01497 mpz_clear(xh); mpz_clear(yh);
01498 }