00001
00007 #include <string>
00008 #include <iostream>
00009 #include <stdexcept>
00010 #include <cmath>
00011 #include <gmp.h>
00012 #include "utils.H"
00013
00014 #include "qsieve.H"
00015
00016 using namespace std;
00017
00018 extern mpz_t n;
00019
00020
00021 ostream& operator<< (ostream& ostr, const CRelation& GL)
00022 {
00023 if (GL.Relation_dense) ostr << "dense"; else ostr << "sparse";
00024 ostr << "1=";
00025
00026 char *str;
00027 str = new char [mpz_sizeinbase(GL.Delta,10)+2]; mpz_get_str(str, 10, GL.Delta);
00028 ostr << str << "^2";
00029 delete [] str;
00030
00031 if (GL.Relation_dense)
00032 {
00033 for (int i=GL.Relation_dense->first(); i>=0; i=GL.Relation_dense->next(i))
00034 ostr << "*p" << i;
00035 }
00036 else
00037 {
00038 const CTinyFBsizetypeVector& R = *GL.Relation_sparse;
00039 for (int pos=0; pos<R.size(); ++pos)
00040 ostr << "*p" << R[pos];
00041 }
00042
00043 return ostr;
00044 }
00045
00046
00047 void CRelation::convert_Relation_to_dense()
00048 {
00049
00050 if (Relation_dense)
00051 { cerr << "Relation is already dense!" << endl; return; }
00052 Relation_dense = new myBitString;
00053 for (int pos=Relation_sparse->size()-1; pos>=0; --pos)
00054 Relation_dense->set((*Relation_sparse)[pos]);
00055
00056 delete Relation_sparse; Relation_sparse=NULL;
00057 }
00058
00059 void CRelation::convert_Relation_to_sparse()
00060 {
00061
00062 if (Relation_sparse)
00063 { cerr << "Relation is already sparse!" << endl; return; }
00064 Relation_sparse = new CTinyFBsizetypeVector(Relation_dense->count(1));
00065 for (int i=Relation_dense->first(); i>=0; i=Relation_dense->next(i))
00066 Relation_sparse->fast_append(i);
00067
00068 delete Relation_dense; Relation_dense=NULL;
00069 }
00070
00071
00072 void CRelation::combine(const CRelation& GL2)
00073
00074
00075 {
00076
00077
00078
00079
00080
00081
00082
00083
00084 mpz_set_ui(x,1);
00085
00086 if ( GL2.Relation_dense )
00087 {
00088 if (!Relation_dense)
00089 convert_Relation_to_dense();
00090
00091
00092
00093
00094 for (int i=GL2.Relation_dense->last(); i>0; i=GL2.Relation_dense->prev(i))
00095 if (Relation_dense->test(i))
00096 {
00097 mpz_mul_ui(x,x,PrimeNumbers[i]);
00098 if (mpz_cmp(x,n)>=0)
00099 {
00100 mpz_mod(x,x,n); mpz_mul(Delta,Delta,x);
00101 mpz_mod(Delta,Delta,n); mpz_set_ui(x,1);
00102 }
00103 }
00104
00105 (*Relation_dense)._xor(*GL2.Relation_dense);
00106 }
00107 else
00108 if (Relation_dense)
00109 {
00110
00111
00112 for (int pos=0; pos<GL2.Relation_sparse->size(); ++pos)
00113 {
00114 if (Relation_dense->test((*GL2.Relation_sparse)[pos]))
00115 if ((*GL2.Relation_sparse)[pos]>0)
00116 {
00117 mpz_mul_ui(x,x,PrimeNumbers[(*GL2.Relation_sparse)[pos]]);
00118 if (mpz_cmp(x,n)>=0)
00119 {
00120 mpz_mod(x,x,n); mpz_mul(Delta,Delta,x);
00121 mpz_mod(Delta,Delta,n); mpz_set_ui(x,1);
00122 }
00123 }
00124 Relation_dense->invert((*GL2.Relation_sparse)[pos]);
00125 }
00126 }
00127 else
00128 {
00129
00130 int p1 = 0;
00131 int p2 = 0;
00132 const CTinyFBsizetypeVector& R = *Relation_sparse;
00133 const CTinyFBsizetypeVector& R2 = *GL2.Relation_sparse;
00134 CTinyFBsizetypeVector neueMenge(R.size()+R2.size());
00135
00136 while (p2<R2.size() && p1<R.size())
00137 {
00138 while (R2[p2]<R[p1])
00139 {
00140 neueMenge.fast_append(R2[p2]); ++p2;
00141 if (p2==R2.size()) goto done;
00142 }
00143 while (R[p1]<R2[p2])
00144 {
00145 neueMenge.fast_append(R[p1]); ++p1;
00146 if (p1==R.size()) goto done;
00147 }
00148 while (R2[p2]==R[p1])
00149 {
00150 if (R[p1]>0)
00151 {
00152 mpz_mul_ui(x,x,PrimeNumbers[R[p1]]);
00153 if (mpz_cmp(x,n)>=0)
00154 {
00155 mpz_mod(x,x,n); mpz_mul(Delta,Delta,x);
00156 mpz_mod(Delta,Delta,n); mpz_set_ui(x,1);
00157 }
00158 }
00159 ++p1; ++p2;
00160 if (p2==R2.size()) goto done;
00161 if (p1==R.size()) goto done;
00162 }
00163 }
00164 done:
00165 while (p2!=R2.size()) { neueMenge.fast_append(R2[p2]); ++p2; }
00166 while (p1!=R.size()) { neueMenge.fast_append(R[p1]); ++p1; }
00167 Relation_sparse->copy_from(neueMenge);
00168
00169 }
00170
00171
00172 mpz_mul(Delta,Delta,x); mpz_mod(Delta,Delta,n);
00173
00174
00175
00176 mpz_mul(Delta,Delta,GL2.Delta); mpz_mod(Delta,Delta,n);
00177
00178 relevant_factor=largest_factor_in_Relation();
00179
00180 }
00181
00182
00183
00184
00185
00186
00187
00188 void CRelation::multi_combine_init()
00189 {
00190
00191
00192
00193
00194 if (pMulticombineData==NULL)
00195 {
00196 MARK; cerr << "Error: pMulticombineData invalid!" << endl;
00197 exit(1);
00198 }
00199 if (!pMulticombineData->multi_combine_Counter) return;
00200 pMulticombineData->multi_combine_Counter=0;
00201 for (int i=0; i<StaticFactorbaseSettings::Size(); i++) pMulticombineData->ExponentArray[i]=0;
00202 }
00203
00204 void CRelation::multi_combine_exit()
00205 {
00206 if (!pMulticombineData->multi_combine_Counter) return;
00207 #ifdef VERBOSE
00208 cout << "Multicombine_exit after " << pMulticombineData->multi_combine_Counter
00209 << " calls." << endl;
00210 #endif
00211
00212 if (pMulticombineData->multi_combine_Counter>std::numeric_limits<TExponentArrayElement>::max())
00213 {
00214 MARK;
00215 cerr << "Elements of CRelation::ExponentArray may have exceeded limits," << endl
00216 << "you have to increase the type of CRelation::TExponentArrayElement" << endl
00217 << "and recompile the program to assure correct computation." << endl
00218 << "(Data computed so far are still correct and can be reused afterwards.)" << endl;
00219 exit(8);
00220 }
00221
00222 optisize();
00223
00224
00225 mpz_set_ui(y,1);
00226 pMulticombineData->ExponentArray[0]=0;
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 #define MY_BASIS_WORKAROUND
00237 #if !defined(__GNUC__) || !defined(MY_BASIS_WORKAROUND)
00238
00239
00240
00241 mpz_t* const Basis = new mpz_t[StaticFactorbaseSettings::Size()];
00242 bool* const Flag = new bool[StaticFactorbaseSettings::Size()];
00243 #else
00244 #warning "enabling workaround for possible Basis assertion failure"
00245
00246
00247 __extension__ mpz_t Basis[StaticFactorbaseSettings::Size()];
00248 __extension__ bool Flag[StaticFactorbaseSettings::Size()];
00249 #endif
00250 for (int i=0; i<StaticFactorbaseSettings::Size(); ++i) Flag[i]=false;
00251
00252 for (int i=1; i<StaticFactorbaseSettings::Size(); ++i)
00253 if (pMulticombineData->ExponentArray[i])
00254 {
00255 const unsigned long int e=pMulticombineData->ExponentArray[i];
00256 pMulticombineData->ExponentArray[i]=0;
00257
00258 if (e>=StaticFactorbaseSettings::Size())
00259 {
00260 cout << "Unexpected exponent " << e << "! Use normal exponentiation..." << endl;
00261 mpz_set_ui(y,PrimeNumbers[i]); mpz_powm_ui(y,y,e,n);
00262 mpz_mul(Delta,Delta,y);
00263 continue;
00264 }
00265
00266 if (Flag[e])
00267 {
00268
00269 mpz_mul_ui(Basis[e],Basis[e],PrimeNumbers[i]);
00270 if (mpz_cmp(Basis[e],n)>=0)
00271 {
00272
00273 mpz_mod(Basis[e],Basis[e],n);
00274 }
00275 }
00276 else
00277 {
00278
00279 Flag[e]=true;
00280 mpz_init_set_ui(Basis[e],PrimeNumbers[i]);
00281 }
00282 }
00283
00284
00285
00286
00287
00288
00289
00290 unsigned int e2 = StaticFactorbaseSettings::Size()-1;
00291 Flag[0]=true;
00292 while (!Flag[e2]) --e2;
00293
00294 mpz_set_ui(y,1);
00295 if (e2>1)
00296 for (unsigned int e=e2-1; e>0; --e)
00297 if (Flag[e])
00298 {
00299 mpz_mul(Basis[e],Basis[e],Basis[e2]);
00300 if (mpz_cmp(Basis[e],n)>=0)
00301 {
00302
00303 mpz_mod(Basis[e],Basis[e],n);
00304 }
00305 if (e2-e>1) mpz_powm_ui(Basis[e2],Basis[e2],e2-e,n);
00306 mpz_mul(y,y,Basis[e2]);
00307 if (mpz_cmp(y,n)>=0)
00308 {
00309
00310 mpz_mod(y,y,n);
00311 }
00312 mpz_clear(Basis[e2]);
00313 e2=e;
00314 }
00315
00316 if (e2>1) mpz_powm_ui(Basis[e2],Basis[e2],e2,n);
00317 if (e2>0)
00318 {
00319 mpz_mul(y,y,Basis[e2]); mpz_mod(y,y,n);
00320 mpz_clear(Basis[e2]);
00321 }
00322
00323 #if !defined(__GNUC__) || !defined(MY_BASIS_WORKAROUND)
00324 delete [] Basis; delete [] Flag;
00325 #endif
00326
00327 mpz_mul(Delta,Delta,y); mpz_mod(Delta,Delta,n);
00328 pMulticombineData->multi_combine_Counter=0;
00329 #ifdef VERBOSE
00330 cout << "Multi_combine_exit finished." << endl;
00331 #endif
00332 }
00333
00334 void CRelation::multi_combine_main(const CRelation& GL2)
00335
00336
00337 {
00338
00339 adjust_multi_combine();
00340
00341
00342
00343
00344
00345
00346 if ( GL2.Relation_dense )
00347 {
00348 if (!Relation_dense)
00349 convert_Relation_to_dense();
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 Relation_dense->test_and_add_carry(*GL2.Relation_dense,pMulticombineData->ExponentArray);
00361 (*Relation_dense)._xor(*GL2.Relation_dense);
00362 }
00363 else
00364 if (Relation_dense)
00365 {
00366
00367 const CTinyFBsizetypeVector& R2 = *GL2.Relation_sparse;
00368 for (int pos=0; pos<R2.size(); ++pos)
00369 {
00370 if (Relation_dense->test_and_invert(R2[pos])) ++pMulticombineData->ExponentArray[R2[pos]];
00371 }
00372 }
00373 else
00374 {
00375 int p1 = 0;
00376 int p2 = 0;
00377 const CTinyFBsizetypeVector& R = *Relation_sparse;
00378 const CTinyFBsizetypeVector& R2 = *GL2.Relation_sparse;
00379 CTinyFBsizetypeVector neueMenge(R.size()+R2.size());
00380
00381 while (p2<R2.size() && p1<R.size())
00382 {
00383 while (R2[p2]<R[p1])
00384 {
00385 neueMenge.fast_append(R2[p2]); ++p2;
00386 if (p2==R2.size()) goto done;
00387 }
00388 while (R[p1]<R2[p2])
00389 {
00390 neueMenge.fast_append(R[p1]); ++p1;
00391 if (p1==R.size()) goto done;
00392 }
00393 while (R2[p2]==R[p1])
00394 {
00395 ++pMulticombineData->ExponentArray[R[p1]];
00396 ++p1; ++p2;
00397 if (p2==R2.size()) goto done;
00398 if (p1==R.size()) goto done;
00399 }
00400 }
00401 done:
00402 while (p2!=R2.size()) { neueMenge.fast_append(R2[p2]); ++p2; }
00403 while (p1!=R.size()) { neueMenge.fast_append(R[p1]); ++p1; }
00404 Relation_sparse->copy_from(neueMenge);
00405 }
00406
00407
00408
00409 mpz_mul(Delta,Delta,GL2.Delta); mpz_mod(Delta,Delta,n);
00410
00411
00412
00413
00414
00415
00416
00417 relevant_factor=largest_factor_in_Relation();
00418
00419 }
00420
00421
00422
00423 void CRelation::seek_emergency_default_handler(istream &, const streampos)
00424 {
00425 throw ios_base::failure("invalid seek position on istream");
00426 }
00427
00428
00429 void (*CRelation::seek_emergency_handler)(istream &, const streampos) = CRelation::seek_emergency_default_handler;
00430
00431 CmpqsFactor CRelation::combine(istream &in, const streampos pos)
00432 {
00433 const streampos merkfpos=in.tellg();
00434 in.seekg(pos); if (in.peek()==EOF) seek_emergency_handler(in,pos);
00435 CmpqsFactor f=combine(in);
00436 in.seekg(merkfpos);
00437 return f;
00438 }
00439
00440 CmpqsFactor CRelation::multi_combine_main(istream &in, const streampos pos)
00441 {
00442 const streampos merkfpos=in.tellg();
00443 in.seekg(pos); if (in.peek()==EOF) seek_emergency_handler(in,pos);
00444 CmpqsFactor f=multi_combine_main(in);
00445 in.seekg(merkfpos);
00446 return f;
00447 }
00448
00449
00450 int CStreamDecoder::GetValue()
00451 {
00452 if (ahead_value>0) { int w=ahead_value; ahead_value=0; return w; }
00453
00454 char c;
00455 in >> c;
00456 if ( c>='A' && c<='Z' ) return c-('A'-1);
00457 if ( c>='g' && c<='z' )
00458 {
00459 int h = (c-'g');
00460 ahead_value=(h%5)+1;
00461 return (h/5)+1;
00462 }
00463 if (c=='0') return 0;
00464 if (c=='$') return -1;
00465 if (c=='%') return -2;
00466
00467 if (c==' ')
00468 {
00469 MARK;
00470 cerr << "GetValue: Read a space? How to handle this?" << endl;
00471 in.setstate(std::ios::failbit);
00472 throw std::runtime_error("GetValue: read invalid character");
00473 }
00474
00475
00476 int w;
00477 in.unget();
00478 in >> w;
00479 return w;
00480 }
00481
00482 void CStreamEncoder::PutValue(const int w)
00483 {
00484 if (w<=5 && w>=1 && prev_value>0)
00485 {
00486 out << char( (prev_value-1)*5 + w-1 + 'g' );
00487 prev_value=0;
00488 return;
00489 }
00490
00491 if (prev_value>0)
00492 {
00493 out << char(prev_value+('A'-1));
00494 prev_value=0;
00495 }
00496
00497 if (w>26)
00498 {
00499 out << w << " ";
00500 return;
00501 }
00502 if (w>0)
00503 {
00504 if (w<=4) { prev_value=w; return; }
00505 out << char(w+('A'-1));
00506 return;
00507 }
00508 switch (w)
00509 {
00510 case -2: out << "%"; break;
00511 case -1: out << "$"; break;
00512 case 0: out << "0"; break;
00513 default:
00514 MARK;
00515 cerr << "PutValue: don't know how to handle this..." << endl;
00516 cerr << "w=" << w << endl;
00517 out.setstate(std::ios::failbit);
00518 throw std::invalid_argument("PutValue: invalid value");
00519 }
00520 }
00521
00522 bool CRelation::is_valid() const
00523 {
00524 mpz_t x,y;
00525 mpz_init(x);
00526 mpz_init_set_ui(y,1);
00527 if (Relation_sparse)
00528 {
00529 for (int i=0; i<Relation_sparse->size(); ++i)
00530 {
00531 mpz_mul_si(y,y,PrimeNumbers[(*Relation_sparse)[i]]);
00532 mpz_mod(y,y,n);
00533 }
00534 }
00535 else
00536 {
00537 for (int i=Relation_dense->first(); i>=0; i=Relation_dense->next(i))
00538 {
00539 mpz_mul_si(y,y,PrimeNumbers[i]);
00540 mpz_mod(y,y,n);
00541 }
00542 }
00543
00544 mpz_invert(x,Delta,n); mpz_powm_ui(x,x,2,n);
00545
00546 #ifdef VERBOSE
00547 cout << "checking for congruency: ";
00548 cout << x << " = " << y << " (mod N)" << endl;
00549 #endif
00550 if (mpz_cmp(x,y)!=0)
00551 {
00552 #ifdef VERBOSE_WARN
00553 MARK; cout << "Relation is invalid: Values are NOT congruent!" << endl;
00554 #endif
00555 mpz_clear(x); mpz_clear(y);
00556 return false;
00557 }
00558 mpz_clear(x); mpz_clear(y);
00559 return true;
00560 }
00561
00562
00563 #include <fstream>
00564 #include <set>
00565 struct myintcompare_
00566 {
00567 inline bool operator() (const int i1, const int i2) const
00568 {
00569 return i1 < i2;
00570 }
00571 };
00572 typedef std::set<int, myintcompare_> TMyIntSet;
00573
00574 bool CRelation::is_valid(istream &in)
00575 {
00576 static TMyIntSet InductiveDynamicFactorSet;
00577
00578 CStreamDecoder enc_in(in);
00579 bool retval = false;
00580
00581 string s;
00582 CmpqsFactor MainFactor;
00583
00584 mpz_t x,y,Delta;
00585 mpz_init_set_ui(x,1);
00586 mpz_init_set_ui(y,1);
00587 mpz_init_set_ui(Delta,1);
00588
00589
00590 const ios::fmtflags oldFlags = in.flags();
00591 in.unsetf(ios::hex); in.setf(ios::dec);
00592 in.unsetf(ios::showbase);
00593
00594 in >> s;
00595 if (s != "G")
00596 {
00597 #ifdef VERBOSE_WARN
00598 MARK;
00599 cerr << "error: wrong position while reading relation" << endl;
00600 #endif
00601 retval=false; goto done;
00602 }
00603 in >> MainFactor;
00604 in >> s;
00605 mpz_set_str(Delta, s.c_str(), mpzbase_f);
00606 mpz_mod(Delta, Delta, n);
00607
00608
00609 in.unsetf(ios::dec); in.setf(ios::hex);
00610 in.unsetf(ios::showbase);
00611
00612 signed int distance;
00613
00614 {
00615 const size_t sizeinbase_of_n = mpz_sizeinbase(n,2);
00616 mpz_set_ui(x,1);
00617
00618 distance=enc_in.GetValue();
00619 int index=distance;
00620 while (distance >= 0)
00621 {
00622 if (index>=StaticFactorbaseSettings::Size())
00623 {
00624 #ifdef VERBOSE_INFO
00625 MARK;
00626 #endif
00627 #ifdef VERBOSE_WARN
00628 cerr << "static factor outside the factorbase (index " << index << ")" << endl;
00629 #endif
00630 retval=false; goto done;
00631 }
00632
00633 mpz_mul_si(x,x,PrimeNumbers[index]);
00634 if (mpz_sizeinbase(x,2)>sizeinbase_of_n)
00635 {
00636 mpz_mod(x,x,n); mpz_mul(y,y,x);
00637 mpz_mod(y,y,n); mpz_set_ui(x,1);
00638 }
00639 distance=enc_in.GetValue(); index+=distance;
00640 }
00641 mpz_mul(y,y,x); mpz_mod(y,y,n);
00642 }
00643
00644 if (distance == -2)
00645 {
00646
00647
00648
00649
00650 int Korrekturfaktor;
00651 while ( (Korrekturfaktor=enc_in.GetValue())>0 )
00652 {
00653 const TMyIntSet::const_iterator p = InductiveDynamicFactorSet.find(Korrekturfaktor);
00654 if (p==InductiveDynamicFactorSet.end())
00655 {
00656 #ifdef VERBOSE_INFO
00657 MARK;
00658 #endif
00659 #ifdef VERBOSE_WARN
00660 cerr << "Unknown correction value (Korrekturfaktor): " << Korrekturfaktor << endl;
00661 #endif
00662 retval=false; goto done;
00663 }
00664 mpz_mul_ui(y,y,Korrekturfaktor); mpz_mod(y,y,n);
00665 }
00666 }
00667
00668 if (MainFactor.LP1()) mpz_mul_si(y,y,MainFactor.LP1());
00669 if (MainFactor.LP2()) mpz_mul_si(y,y,MainFactor.LP2());
00670 mpz_mod(y,y,n);
00671
00672 mpz_invert(x,Delta,n); mpz_powm_ui(x,x,2,n);
00673
00674 #ifdef VERBOSE
00675 cout << "checking for congruency: ";
00676 cout << x << " = " << y << " (mod N)" << endl;
00677 #endif
00678 if (mpz_cmp(x,y)!=0)
00679 {
00680 #ifdef VERBOSE_WARN
00681 MARK; cout << "Relation is invalid: Values are NOT congruent!" << endl;
00682 #endif
00683 retval=false; goto done;
00684 }
00685
00686 if (MainFactor.IsTypeOf(CmpqsFactor::single_large_prime))
00687 {
00688
00689
00690
00691 InductiveDynamicFactorSet.insert(MainFactor.int_value());
00692 }
00693
00694 retval=true;
00695 done:
00696 mpz_clear(Delta); mpz_clear(y); mpz_clear(x);
00697 in.flags(oldFlags);
00698 return retval;
00699 }
00700
00701 void CRelation::SanityCheckRelationsFile(const std::string FileName)
00702 {
00703 #ifdef VERBOSE_NOTICE
00704 cout << "Performing sanity check for " << FileName << endl;
00705 #endif
00706 std::ifstream MyFile(FileName.c_str());
00707 if (!MyFile)
00708 {
00709 cerr << "problems to open \"" << FileName << "\"!" << endl;
00710 exit(1);
00711 }
00712
00713 MyFile.seekg(0,ios::beg);
00714 unsigned int count = 0, line=0, invalid=0, obsolete=0;
00715 while (MyFile)
00716 {
00717 while (MyFile.peek()=='U') { ++line; ++obsolete; MyFile.ignore(1000000,'\n'); }
00718 while (MyFile.peek()=='G')
00719 {
00720 ++count; ++line;
00721 if (!is_valid(MyFile))
00722 {
00723 ++invalid;
00724 cerr << "invalid Relation in " << FileName << ", line " << line << endl;
00725 MyFile.ignore(1000000,'\n');
00726 } else MyFile.ignore(1,'\n');
00727 #ifdef VERBOSE_NOTICE
00728 if (count%500==0) cout << count << " relations validated.\r" << flush;
00729 #endif
00730 }
00731 if (MyFile.peek()!=EOF && MyFile.peek()!='U')
00732 {
00733 ++line; ++invalid;
00734 cerr << "Garbage in " << FileName << ", line " << line << endl;
00735 cerr << "Giving up!" << endl;
00736 break;
00737
00738 }
00739
00740
00741 MyFile.get();
00742 if (MyFile.eof()) break;
00743 MyFile.unget();
00744 }
00745 #ifdef VERBOSE_NOTICE
00746 cout << line << " lines scanned. " << endl;
00747 if (obsolete) cout << obsolete << " obsolete relations skipped." << endl;
00748 cout << count << " relations validated." << endl;
00749 #endif
00750 if (invalid)
00751 {
00752 cout << invalid << " INVALID relations detected in " << FileName << endl;
00753 exit(1);
00754 }
00755 }