Advertisement
Guest User

Quadratic Sieve

a guest
Nov 19th, 2012
865
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.72 KB | None | 0 0
  1. #include <iostream>
  2. #include <mpir.h>
  3. #include <vector>
  4. #include <stdint.h>
  5.  
  6. using namespace std;
  7.  
  8. vector<unsigned long long> factor_base;
  9. vector<unsigned long long> start;
  10. vector<unsigned long long> factor_base_index;
  11.  
  12. //ms == 'matrix size'
  13. const int ms = 21000;
  14. uint8_t vec[ms][ms];
  15. uint8_t ident[ms][ms];
  16.  
  17. //dcs == 'data collection size'
  18. unsigned long long dcs;
  19. unsigned long long pointer = 0;
  20. unsigned long long closenuf;
  21.  
  22. //solution found boolean
  23. bool sol_found = false;
  24.  
  25. //T is used to calculate the threshold when sieving
  26. double T;
  27.  
  28. void sieve(unsigned long long b1);
  29. void refine(const mpz_t n);
  30. void data_collection(const mpz_t n, mpz_t *tX, mpz_t *tY, mpz_t *zero, mpz_t xprog);
  31. void solve_congruences(const mpz_t n);
  32. void quadratic_sieve(mpz_t *zero, mpz_t *X, mpz_t *tX, mpz_t *Y, mpz_t *tY);
  33. void build_matrix(mpz_t *B);
  34. void forward_elimination();
  35. void backwards_elimination();
  36. void find_solution(const mpz_t n, mpz_t *Y, mpz_t *X);
  37. void update_congruences();
  38. void calculate_threshold(const mpz_t n);
  39.  
  40.  
  41. int main(){
  42.     //get n, the number to be factored
  43.     mpz_t n;
  44.     mpz_init(n);
  45.     char input[1024];
  46.     cout << "n = ";
  47.     cin >> input;
  48.     mpz_set_str(n, input, 10);
  49.  
  50.     //set xprog, used to save the progress of X, used for data collection
  51.     mpz_t xprog;
  52.     mpz_init(xprog);
  53.     mpz_sqrt(xprog, n);
  54.     mpz_add_ui(xprog, xprog, 1);
  55.  
  56.     //get b1, the upper boundary for the factor base
  57.     unsigned long long b1;
  58.     cout << "b1 = ";
  59.     cin >> b1;
  60.  
  61.     //get T, used for calculating the threshold for sieving
  62.     cout << "T = ";
  63.     cin >> T;
  64.  
  65.     //sieve out all the composite numbers using the sieve of Eratosthenes
  66.     cout << "Sieving for prime factors...\n";
  67.     sieve(b1);
  68.     cout << "Complete!\n";
  69.  
  70.     //refine the factor base, leaving only quadratic residues
  71.     cout << "Searching for quadratic residues...\n";
  72.     refine(n);
  73.     cout << "Complete!\n";
  74.  
  75.     //set the data collection size to 1 greater than the size of the factor base
  76.     dcs = factor_base.size() + 1;
  77.  
  78.     //use the values of T and n to calculate the sieving threshold
  79.     calculate_threshold(n);
  80.  
  81.     //initialise arrays to be used for data collection
  82.     unsigned long long i;
  83.  
  84.     mpz_t *X = new mpz_t[250000];
  85.     mpz_t *Y = new mpz_t[250000];
  86.     mpz_t *tX = new mpz_t[250000];
  87.     mpz_t *tY = new mpz_t[250000];
  88.     mpz_t *zero = new mpz_t[250000];
  89.     mpz_t *B = new mpz_t[250000];
  90.  
  91.     for(i = 0; i < 250000; i++){
  92.         mpz_init_set_str(X[i], "0", 10);
  93.         mpz_init_set_str(Y[i], "0", 10);
  94.         mpz_init_set_str(B[i], "0", 10);
  95.         mpz_init_set_str(tX[i], "0", 10);
  96.         mpz_init_set_str(tY[i], "0", 10);
  97.         mpz_init_set_str(zero[i], "0", 10);
  98.     }
  99.  
  100.     //the congruences are stored in the arrays 'start' and 'factor_base_index'
  101.     //'start' contains the index value in the tY array to start the loop on
  102.     //'factor_base_index' contains the value of p, the prime which the indexed value in tY is divisible by
  103.     solve_congruences(n);
  104.  
  105.     cout << "Collecting data...\n";
  106.     while(pointer <= dcs){
  107.         data_collection(n, tX, tY, zero, xprog);
  108.         quadratic_sieve(zero, X, tX, Y, tY);
  109.         update_congruences();
  110.     }
  111.  
  112.     for(i = 0; i <= dcs; i++){
  113.         mpz_set(B[i], Y[i]);
  114.     }
  115.  
  116.     //use the values from the B array for trial division to build the matrix
  117.     cout << "Building matrix...\n";
  118.     build_matrix(B);
  119.     cout << "Complete!\n";
  120.  
  121.     mpz_clear(*tX);
  122.     mpz_clear(*tY);
  123.     mpz_clear(*B);
  124.  
  125.     while(sol_found == false){
  126.         //call the gaussian elimination functions
  127.         cout << "Reducing matrix...\n";
  128.         forward_elimination();
  129.         backwards_elimination();
  130.    
  131.         cout << "Looking for a solution...\n";
  132.         find_solution(n, Y, X);
  133.         cout << "fb: " << factor_base.size() << "\ndcs:" << dcs << "\n";
  134.     }
  135.     system("pause");
  136.     return 0;
  137. }
  138.  
  139. void sieve(unsigned long long b1){
  140.     //sieve of Eratosthenes
  141.     vector<int> consecutive;
  142.     unsigned long long p = 0;
  143.     unsigned long long i;
  144.     cout << "Building Prime Base...\n";
  145.     consecutive.push_back(0);
  146.     consecutive.push_back(0);
  147.     consecutive.push_back(2);
  148.     for(i = 3; i <= b1; i+=2) {
  149.         consecutive.push_back(i);
  150.         consecutive.push_back(0);
  151.     }
  152.     while(p <= b1) {
  153.         if(consecutive[p] != 0) {
  154.             p = consecutive[p];
  155.             for(i = p; i <= b1; i+=p) {
  156.                 if(i > p && consecutive[i] != 0) {
  157.                     consecutive[i] = 0;
  158.                 }
  159.             }
  160.         }
  161.         p++;
  162.     }
  163.     for(i = 0; i <= b1; i++) {
  164.         if(consecutive[i] != 0) {
  165.             factor_base.push_back(consecutive[i]);
  166.         }
  167.     }
  168.     consecutive.erase(consecutive.begin(), consecutive.end());
  169. }
  170.  
  171. void refine(const mpz_t n){
  172.     mpz_t temp;
  173.     mpz_init(temp);
  174.     unsigned long long i;
  175.  
  176.     //loop through the factor base, if the legendre symbol isn't +1, discard that factor
  177.     for(i = 1; i < factor_base.size(); i++){
  178.         mpz_set_ui(temp, factor_base[i]);
  179.         if(mpz_legendre(n, temp) != 1){
  180.             factor_base.erase(factor_base.begin()+i);
  181.             i--;
  182.         }
  183.     }
  184.     mpz_clear(temp);
  185. }
  186.  
  187. void data_collection(const mpz_t n, mpz_t *tX, mpz_t *tY, mpz_t *zero, mpz_t xprog){
  188.     mpz_t temp;
  189.     mpz_init(temp);
  190.     unsigned long long cntr = 0;
  191.  
  192.     //xprog saves the last value that X was set to, so we can start from where we left off
  193.     //calculate x^2 - n and save value in the tX array if it is greater than 1
  194.     //reset the zero array to... zero
  195.     while(cntr < 250000){
  196.         mpz_set(tX[cntr], xprog);
  197.         mpz_mul(temp, xprog, xprog);
  198.         mpz_sub(temp, temp, n);
  199.         mpz_set_ui(zero[cntr], 0);
  200.         if(mpz_cmp_ui(temp, 1) > 0){
  201.             mpz_set(tY[cntr], temp);
  202.             cntr++;
  203.         }
  204.         mpz_add_ui(xprog, xprog, 1);
  205.     }
  206.  
  207.     mpz_clear(temp);
  208. }
  209.  
  210. void solve_congruences(const mpz_t n){
  211.     //calculate ceiling of square root of n
  212.     mpz_t sqrt;
  213.     mpz_init(sqrt);
  214.     mpz_sqrt(sqrt, n);
  215.     mpz_add_ui(sqrt, sqrt, 1);
  216.  
  217.     //solve the case of (X+sqrt)^2 - n = 0 (mod 2)
  218.     unsigned long long X = 0;
  219.     mpz_t temp;
  220.     mpz_init(temp);
  221.  
  222.     //increment X until a solution is found
  223.     while(1){
  224.         mpz_add_ui(temp, sqrt, X);
  225.         mpz_mul(temp, temp, temp);
  226.         mpz_sub(temp, temp, n);
  227.         mpz_mod_ui(temp, temp, 2);
  228.         if(mpz_cmp_ui(temp, 0) == 0){
  229.             start.push_back(X);
  230.             factor_base_index.push_back(2);
  231.             break;
  232.         }
  233.         X++;
  234.     }
  235.  
  236.     //now iterate through the factor base, and solve (X+sqrt)^2 - n = 0 (mod p)
  237.     //once solved, push X onto start array, and p onto factor_base_index. Repeat twice for both solutions.
  238.     unsigned long long i;
  239.     unsigned long long solved;
  240.  
  241.     for(i = 1; i < factor_base.size(); i++){
  242.         X = 0;
  243.         solved = 0;
  244.         while(solved < 2){
  245.             mpz_add_ui(temp, sqrt, X);
  246.             mpz_mul(temp, temp, temp);
  247.             mpz_sub(temp, temp, n);
  248.             mpz_mod_ui(temp, temp, factor_base[i]);
  249.             if(mpz_cmp_ui(temp, 0) == 0){
  250.                 start.push_back(X);
  251.                 factor_base_index.push_back(factor_base[i]);
  252.                 solved++;
  253.             }
  254.             X++;
  255.         }
  256.         cout << "Solved " << i << " of " << factor_base.size() << " congruences\r";
  257.     }
  258.  
  259.     mpz_clear(sqrt);
  260.     mpz_clear(temp);
  261. }
  262.  
  263.  
  264. void quadratic_sieve(mpz_t *zero, mpz_t *X, mpz_t *tX, mpz_t *Y, mpz_t *tY){
  265.     mpz_t temp;
  266.     mpz_init(temp);
  267.     unsigned long long s;
  268.     unsigned long long st;
  269.     unsigned long long inc;
  270.     unsigned long long cntr;
  271.     mpz_t base2;
  272.     mpz_init(base2);
  273.     size_t sz;
  274.  
  275.     for(s = 0; s < start.size(); s++){
  276.         //starting at st, and incrementing by inc, divide each value by inc
  277.         inc = factor_base_index[s];
  278.         mpz_set_ui(base2, inc);
  279.         sz = mpz_sizeinbase(base2, 2);
  280.         for(st = start[s]; st < 250000; st += inc){
  281.             //increment the zero array by ~log2(inc)
  282.             mpz_add_ui(zero[st], zero[st], sz);
  283.         }
  284.     }
  285.    
  286.     for(s = 0; s < 250000; s++){
  287.         //values which are at or above the threshold (closenuf) enter the trial division stage
  288.         if(mpz_cmp_ui(zero[s], closenuf) >= 0){
  289.             //the potential smooth number is backed up in the X and Y arrays
  290.             mpz_set(X[pointer], tX[s]);
  291.             mpz_set(Y[pointer], tY[s]);
  292.  
  293.             //the potential smooth number is divided by each factor in the factor base
  294.             for(cntr = 0; cntr < factor_base.size(); cntr++){
  295.                 mpz_mod_ui(temp, tY[s], factor_base[cntr]);
  296.                 while(mpz_cmp_ui(temp, 0) == 0){
  297.                     mpz_div_ui(tY[s], tY[s], factor_base[cntr]);
  298.                     mpz_mod_ui(temp, tY[s], factor_base[cntr]);
  299.                 }
  300.  
  301.                 //if the number is smooth increment the pointer, otherwise the value in the X/Y arrays will be
  302.                 //overwritten on the next iteration of the loop
  303.                 if(mpz_cmp_ui(tY[s], 1) == 0){
  304.                     pointer++;
  305.                     cout << pointer << "/" << dcs << "                    \r";
  306.                     break;
  307.                 }
  308.             }
  309.         }
  310.     }
  311.  
  312.     mpz_clear(temp);
  313.     mpz_clear(base2);
  314. }
  315.  
  316. void update_congruences(){
  317.     unsigned long long difference;
  318.     unsigned long long overlap;
  319.     unsigned long long offset;
  320.     unsigned long long i;
  321.  
  322.     for(i = 0; i < start.size(); i++){
  323.         difference = 250000 - start[i];
  324.         overlap = difference % factor_base_index[i];
  325.         offset = factor_base_index[i] - overlap;
  326.         start[i] = offset;
  327.     }
  328. }
  329.  
  330.  
  331. void build_matrix(mpz_t *B){
  332.     //initialise arrays
  333.     unsigned long long outer;
  334.     unsigned long long inner;
  335.  
  336.     for(outer = 0; outer < ms; outer++){
  337.         for(inner = 0; inner < ms; inner++){
  338.             vec[outer][inner] = 0;
  339.             ident[outer][inner] = 0;
  340.         }
  341.     }
  342.  
  343.     for(outer = 0; outer < ms; outer++){
  344.         ident[outer][outer] = 1;
  345.     }
  346.  
  347.     //build matrix
  348.     mpz_t temp;
  349.     mpz_init(temp);
  350.     uint8_t flipper = 0;
  351.     unsigned long long row = 0;
  352.     unsigned long long col = 0;
  353.    
  354.     for(outer = 0; outer < dcs; outer++){
  355.             while(col < factor_base.size()){
  356.                 mpz_mod_ui(temp, B[outer], factor_base[col]);
  357.                 if(mpz_cmp_ui(temp, 0) == 0){
  358.                     flipper++;
  359.                     flipper = flipper % 2;
  360.                     vec[row][col] = flipper;
  361.                     mpz_div_ui(B[outer], B[outer], factor_base[col]);
  362.                 }
  363.                 else
  364.                 {
  365.                     col++;
  366.                     flipper = 0;
  367.                 }
  368.             }
  369.             if(mpz_cmp_ui(B[outer], 1) == 0){
  370.                 row++;
  371.             }
  372.             col = 0;
  373.             flipper = 0;
  374.             if(row > dcs){
  375.                 break;
  376.             }
  377.     }
  378.     dcs = row;
  379.     mpz_clear(temp);
  380. }
  381.  
  382. void forward_elimination(){
  383.     long int pivot;
  384.     long int row;
  385.     long int i;
  386.     long int row_iterator;
  387.     long int size;
  388.     size = factor_base.size();
  389.  
  390.     for(pivot = 0; pivot < size; pivot++){
  391.         cout << pivot << "/" << size << "\r";
  392.         for(row = pivot; row < dcs-1; row++){
  393.             if(vec[row][pivot] == 1){
  394.                 for(row_iterator = row+1; row_iterator < dcs; row_iterator++){
  395.                     if(vec[row_iterator][pivot] == 1){
  396.                         for(i = 0; i < size; i++){
  397.                             if(vec[row][i] == 1){
  398.                                 vec[row_iterator][i] += vec[row][i];
  399.                                 vec[row_iterator][i] = vec[row_iterator][i] % 2;
  400.                             }
  401.                         }
  402.                         for(i = 0; i < dcs; i++){
  403.                             if(ident[row][i] == 1){
  404.                                 ident[row_iterator][i] += ident[row][i];
  405.                                 ident[row_iterator][i] = ident[row_iterator][i] % 2;
  406.                             }
  407.                         }
  408.                     }
  409.                 }
  410.             }
  411.         }
  412.     }
  413. }
  414.  
  415. void backwards_elimination(){
  416.     long int pivot;
  417.     long int row;
  418.     long int i;
  419.     long int row_iterator;
  420.     long int size;
  421.     size = factor_base.size();
  422.  
  423.     for(pivot = size - 1; pivot >= 0; pivot--){
  424.         cout << pivot << "/" << size << "\r";
  425.         for(row = pivot; row > 0; row--){
  426.             if(vec[row][pivot] == 1){
  427.                 for(row_iterator = row-1; row_iterator >= 0; row_iterator--){
  428.                     if(vec[row_iterator][pivot] == 1){
  429.                         for(i = 0; i < size; i++){
  430.                             if(vec[row][i] == 1){
  431.                                 vec[row_iterator][i] += vec[row][i];
  432.                                 vec[row_iterator][i] = vec[row_iterator][i] % 2;
  433.                             }
  434.                         }
  435.                         for(i = 0; i < dcs; i++){
  436.                             if(ident[row][i] == 1){
  437.                                 ident[row_iterator][i] += ident[row][i];
  438.                                 ident[row_iterator][i] = ident[row_iterator][i] % 2;
  439.                             }
  440.                         }
  441.                     }
  442.                 }
  443.             }
  444.         }
  445.     }
  446. }
  447.  
  448. void find_solution(const mpz_t n, mpz_t *Y, mpz_t *X){
  449.     unsigned long long i;
  450.     unsigned long long c;
  451.     unsigned long long indexer;
  452.     bool flag;
  453.  
  454.     vector<unsigned long long> luckydip;
  455.  
  456.     mpz_t Xt;
  457.     mpz_t Yt;
  458.     mpz_t temp;
  459.     mpz_init(Xt);
  460.     mpz_init(Yt);
  461.     mpz_init(temp);
  462.  
  463.     for(i = 0; i < dcs; i++){
  464.         mpz_set_ui(Xt, 1);
  465.         mpz_set_ui(Yt, 1);
  466.         flag = true;
  467.         for(c = 0; c < factor_base.size(); c++){
  468.             if(vec[i][c] != 0){
  469.                 flag = false;
  470.                 break;
  471.             }
  472.         }
  473.         if(flag == true){
  474.             for(c = 0; c < dcs; c++){
  475.                 if(ident[i][c] == 1){
  476.                     luckydip.push_back(c);
  477.                 }
  478.             }
  479.             for(indexer = 0; indexer < luckydip.size(); indexer++){
  480.                 mpz_mul(Xt, Xt, X[luckydip[indexer]]);
  481.                 mpz_mul(Yt, Yt, Y[luckydip[indexer]]);
  482.             }
  483.             mpz_sqrt(Yt, Yt);
  484.             mpz_sub(temp, Xt, Yt);
  485.             mpz_gcd(temp, temp, n);
  486.             if(mpz_cmp_ui(temp, 1) != 0 && mpz_cmp(temp, n) != 0){
  487.                 mpz_out_str(stdout, 10, temp);
  488.                 cout << "\n\a";
  489.                 mpz_div(temp, n, temp);
  490.                 mpz_out_str(stdout, 10, temp);
  491.                 cout << "\n";
  492.                 sol_found = true;
  493.                 return;
  494.             }
  495.         }
  496.         luckydip.erase(luckydip.begin(), luckydip.end());
  497.     }
  498. }
  499.  
  500. void calculate_threshold(const mpz_t n){
  501.     unsigned long long target;
  502.     size_t sz;
  503.     mpz_t base2;
  504.     mpz_init(base2);
  505.  
  506.     sz = mpz_sizeinbase(n, 2);
  507.     target = sz / 2;
  508.     mpz_set_ui(base2, 125000);
  509.     sz = mpz_sizeinbase(base2, 2);
  510.     target += sz;
  511.  
  512.     mpz_set_ui(base2, factor_base[factor_base.size() - 1]);
  513.     sz = mpz_sizeinbase(base2, 2);
  514.     closenuf = T * sz;
  515.     closenuf = target - closenuf;
  516.  
  517.     cout << "TARGET = " << target << " bits\n";
  518.     cout << "THRESHOLD = " << closenuf << " bits\n";
  519.     cout << "T = " << T << endl;
  520.     system("pause");
  521. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement