Quadratic Sieve


SUBMITTED BY: Guest

DATE: Nov. 12, 2013, 2:48 a.m.

FORMAT: Text only

SIZE: 14.2 kB

HITS: 897

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

comments powered by Disqus