Orbiter 2022
Combinatorial Objects
cryptography_domain.cpp
Go to the documentation of this file.
1/*
2 * cryptography_domain.cpp
3 *
4 * Created on: Nov 4, 2020
5 * Author: betten
6 */
7
8
9
10
11#include "foundations.h"
12
13using namespace std;
14
15
16namespace orbiter {
17namespace layer1_foundations {
18namespace cryptography {
19
20
21static double letter_probability[] = {
22 0.082, // a
23 0.015, // b
24 0.028, // c
25 0.043, // d
26 0.127, // e
27 0.022, // f
28 0.020, // g
29 0.061, // h
30 0.070, // i
31 0.002, // j
32 0.008, // k
33 0.040, // l
34 0.024, // m
35 0.067, // n
36 0.075, // o
37 0.019, // p
38 0.001, // q
39 0.060, // r
40 0.063, // s
41 0.091, // t
42 0.028, // u
43 0.010, // v
44 0.001, // x
45 0.020, // y
46 0.001 // z
47};
48
49
50
51
52
54{
55
56}
57
59{
60
61}
62
63void cryptography_domain::affine_cipher(std::string &ptext, std::string &ctext, int a, int b)
64{
65 int i, l, x, y;
66 char *str;
67
68 cout << "applying key (" << a << "," << b << ")" << endl;
69 l = ptext.length();
70 str = NEW_char(l + 1);
71 for (i = 0; i < l; i++) {
72 x = (int)(upper_case(ptext[i]) - 'A');
73 y = a * x + b;
74 y = y % 26;
75 str[i] = 'A' + y;
76 }
77 str[l] = 0;
78 ctext.assign(str);
79 FREE_char(str);
80}
81
82void cryptography_domain::affine_decipher(std::string &ctext, std::string &ptext, std::string &guess)
83// we have ax_1 + b = y_1
84// and ax_2 + b = y_2
85// or equivalently
86// matrix(x_1,1,x_2,1) vector(a,b) = vector(y_1,y_2)
87// and hence
88// vector(a,b) = matrix(1,-1,-x_2,x_1) vector(y_1,y_2) * 1/(x_1 - x_2)
89{
90 int x1, x2, y1, y2, dy, dx, i;
91 int a, b, a0, av, c, g, dxv, n, gg;
93
94 if (guess.length() != 4) {
95 cout << "guess must be 4 characters long!" << endl;
96 exit(1);
97 }
98 cout << "guess=" << guess << endl;
99 y1 = lower_case(guess[0]) - 'a';
100 x1 = lower_case(guess[1]) - 'a';
101 y2 = lower_case(guess[2]) - 'a';
102 x2 = lower_case(guess[3]) - 'a';
103
104 cout << "y1=" << y1 << endl;
105 cout << "x1=" << x1 << endl;
106 cout << "y2=" << y2 << endl;
107 cout << "x2=" << x2 << endl;
108 dy = remainder(y2 - y1, 26);
109 dx = remainder(x2 - x1, 26);
110 //cout << "dx = x2 - x1 = " << dx << endl;
111 //cout << "dy = y2 - y1 = " << dy << endl;
112 cout << "solving: a * (x2-x1) = y2 - y1 mod 26" << endl;
113 cout << "here: a * " << dx << " = " << dy << " mod 26" << endl;
114 n = 26;
115 //g = gcd_int(dx, n);
116 g = NT.gcd_lint(dx, n);
117 if (remainder(dy, g) != 0) {
118 cout << "gcd(x2-x1,26) does not divide y2-y1, hence no solution! try again" << endl;
119 exit(1);
120 }
121 if (g != 1) {
122 dy /= g;
123 dx /= g;
124 n /= g;
125 cout << "reducing to: a * " << dx << " = " << dy << " mod " << n << endl;
126 }
127 dxv = NT.inverse_mod(dx, n);
128 cout << dx << "^-1 mod " << n << " = " << dxv << endl;
129 a0 = remainder(dy * dxv, n);
130 cout << "solution a = " << a0 << " mod " << n << endl;
131 cout << "(ie " << g << " solutions for a mod 26)" << endl;
132 for (i = 0; i < g; i++) {
133 cout << "trying solution " << i + 1 << ":" << endl;
134 a = a0 + i * n;
135 b = remainder(y1 - a * x1, 26);
136 cout << "yields key (" << a << "," << b << ")" << endl;
137 //gg = gcd_int(a, 26);
138 gg = NT.gcd_lint(a, 26);
139 if (gg != 1) {
140 cout << a << " not prime to 26, no solution" << endl;
141 continue;
142 }
143 av = NT.inverse_mod(a, 26);
144 cout << "a^-1 mod 26 = " << av << endl;
145 c = av * (-b);
146 c = remainder(c, 26);
147 cout << "a^-1 (-b) = " << c << " mod 26" << endl;
148 affine_cipher(ctext, ptext, av, c);
149 cout << " " << endl;
150 print_on_top(ptext, ctext);
151 }
152}
153
154void cryptography_domain::vigenere_cipher(std::string &ptext, std::string &ctext, std::string &key)
155{
156 int i, j, l, key_len, a, b, c;
157 char *str;
158
159 key_len = key.length();
160 l = ptext.length();
161 str = NEW_char(l + 1);
162 for (i = 0, j = 0; i < l; i++, j++) {
163 if (j == key_len) {
164 j = 0;
165 }
166 if (is_alnum(ptext[i]) && is_alnum(key[j])) {
167 a = (int)(lower_case(ptext[i]) - 'a');
168 b = (int)(lower_case(key[j]) - 'a');
169 c = a + b;
170 c = c % 26;
171 str[i] = 'a' + c;
172 }
173 else {
174 str[i] = ptext[i];
175 }
176 }
177 str[l] = 0;
178 ctext.assign(str);
179 FREE_char(str);
180}
181
182void cryptography_domain::vigenere_decipher(std::string &ctext, std::string &ptext, std::string &key)
183{
184 int i, j, l, key_len, a, b, c;
185 char *str;
186
187 key_len = key.length();
188 l = ctext.length();
189 str = NEW_char(l + 1);
190 for (i = 0, j = 0; i < l; i++, j++) {
191 if (j == key_len)
192 j = 0;
193 if (is_alnum(ctext[i]) && is_alnum(key[j])) {
194 a = (int)(lower_case(ctext[i]) - 'a');
195 b = (int)(lower_case(key[j]) - 'a');
196 c = a - b;
197 if (c < 0)
198 c += 26;
199 str[i] = 'a' + c;
200 }
201 else {
202 str[i] = ctext[i];
203 }
204 }
205 str[l] = 0;
206 ptext.assign(str);
207 FREE_char(str);
208}
209
211{
212 int stride, l, n, m, j;
213 int mult[100];
214 double I, II;
215
216 cout.precision(3);
217 l = ctext.length();
218 cout << "key length : Friedman indices in 1/1000-th : average" << endl;
219 for (stride = 1; stride <= MINIMUM(l, 20); stride++) {
220 m = l / stride;
221 if (m < 2)
222 continue;
223 II = 0;
224 cout << stride << " : ";
225 for (j = 0; j < stride; j++) {
226 if (j == stride - 1) {
227 n = l - (stride - 1) * m;
228 }
229 else {
230 n = m;
231 }
232
233 std::string str2;
234
235 str2 = ctext.substr(j, n);
236 single_frequencies2(str2, stride, n, mult);
237
238 //print_frequencies(mult);
239 I = friedman_index(mult, n);
240 if (stride < 20) {
241 if (j) {
242 cout << ", ";
243 }
244 cout << (int)(1000. * I);
245 }
246 II += I;
247 }
248 II *= 1. / (double) stride;
249 cout << " : " << (int)(1000. * II) << endl;
250 }
251}
252
253void cryptography_domain::vigenere_analysis2(std::string &ctext, int key_length)
254{
255 int i, j, shift, n, m, l, a, h;
256 int mult[100];
257 int index[100];
258 int shift0[100];
259 double I;
260 char c;
261
262 l = ctext.length();
263 m = l / key_length;
264 cout << " :";
265 for (shift = 0; shift < 26; shift++) {
266 cout << " ";
267 c = 'a' + shift;
268 cout << c;
269 }
270 cout << endl;
271 for (j = 0; j < key_length; j++) {
272 cout.width(3);
273 cout << j << " :";
274 if (j == key_length - 1) {
275 n = l - (key_length - 1) * m;
276 }
277 else {
278 n = m;
279 }
280
281 std::string str = ctext.substr(j, n);
282 single_frequencies2(str, key_length, n, mult);
283
284 //print_frequencies(mult);
285 for (shift = 0; shift < 26; shift++) {
286 I = friedman_index_shifted(mult, n, shift);
287 cout.width(3);
288 a = (int)(1000. * I);
289 cout << a;
290 if (shift) {
291 for (i = 0; i < shift; i++) {
292 if (index[i] < a) {
293 for (h = shift; h > i; h--) {
294 index[h] = index[h - 1];
295 shift0[h] = shift0[h - 1];
296 }
297 index[i] = a;
298 shift0[i] = shift;
299 break;
300 }
301 }
302 }
303 else {
304 index[0] = a;
305 shift0[0] = shift;
306 }
307 }
308 cout << " : ";
309 for (i = 0; i < 5; i++) {
310 c = 'a' + shift0[i];
311 if (i) {
312 cout << ", ";
313 }
314 cout << c << " " << index[i];
315 }
316 cout << endl;
317 }
318}
319
320int cryptography_domain::kasiski_test(std::string &ctext, int threshold)
321{
322 int l, i, j, k, u, h, offset;
323 int *candidates, nb_candidates, *Nb_candidates;
324 int *f_taken;
325 int g = 0, g1;
327
328 l = ctext.length();
329 candidates = new int[l];
330 f_taken = new int[l];
331 Nb_candidates = new int[l];
332 for (i = 0; i < l; i++) {
333 f_taken[i] = FALSE;
334 }
335
336 for (i = 0; i < l; i++) {
337 //cout << "position " << i << endl;
338 nb_candidates = 0;
339 for (j = i + 1; j < l; j++) {
340 if (ctext[j] == ctext[i]) {
341 candidates[nb_candidates++] = j;
342 }
343 }
344 h = 1;
345 //print_candidates(ctext, i, h, nb_candidates, candidates);
346
347 //cout << "at position " << i << ", found " << nb_candidates << " matches of length 1" << endl;
348 Nb_candidates[h - 1] += nb_candidates;
349 while (nb_candidates) {
350 for (k = 0; k < nb_candidates; k++) {
351 j = candidates[k];
352 if (ctext[i + h] != ctext[j + h]) {
353 for (u = k + 1; u < nb_candidates; u++) {
354 candidates[u - 1] = candidates[u];
355 }
356 nb_candidates--;
357 k--;
358 }
359 }
360 h++;
361 Nb_candidates[h - 1] += nb_candidates;
362 if (h >= threshold && nb_candidates) {
363 print_candidates(ctext, i, h, nb_candidates, candidates);
364 g1 = 0;
365 for (k = 0; k < nb_candidates; k++) {
366 offset = candidates[k] - i;
367 if (g1 == 0) {
368 g1 = offset;
369 }
370 else {
371 //g1 = gcd_int(g1, offset);
372 g1 = NT.gcd_lint(g1, offset);
373 }
374 }
375 //cout << "g1 = " << g1 << endl;
376 if (g == 0) {
377 g = g1;
378 }
379 else {
380 //g = gcd_int(g, g1);
381 g = NT.gcd_lint(g, g1);
382 }
383 //cout << "g = " << g << endl;
384 //break;
385 }
386 }
387 }
388 for (i = 0; Nb_candidates[i]; i++) {
389 cout << "matches of length " << i + 1 << " : " << Nb_candidates[i] << endl;
390 }
391 delete [] candidates;
392 delete [] f_taken;
393 delete [] Nb_candidates;
394 return g;
395}
396
398 int i, int h, int nb_candidates, int *candidates)
399{
400 int k, j, u;
401
402 if (nb_candidates == 0) {
403 return;
404 }
405 cout << "there are " << nb_candidates << " level " << h << " coincidences with position " << i << endl;
406 for (k = 0; k < nb_candidates; k++) {
407 j = candidates[k];
408 cout << "at " << j << " : ";
409 for (u = 0; u < h; u++) {
410 cout << ctext[i + u];
411 }
412 cout << " : ";
413 for (u = 0; u < h; u++) {
414 cout << ctext[j + u];
415 }
416 cout << " offset " << j - i;
417 cout << endl;
418 }
419}
420
422{
423 int i;
424
425 for (i = 0; i < l; i++) {
426 cout << s[i] << " ";
427 }
428 cout << endl;
429}
430
431void cryptography_domain::print_on_top(std::string &text1, std::string &text2)
432{
433 int i, j, l, l2, lines, line_length;
434
435 l = text1.length();
436 l2 = text2.length();
437 if (l2 != l) {
438 cout << "text lengths do not match" << endl;
439 exit(1);
440 }
441 lines = l / 80;
442 for (i = 0; i <= lines; i++) {
443 if (i == lines) {
444 line_length = l % 80;
445 }
446 else {
447 line_length = 80;
448 }
449 for (j = 0; j < line_length; j++) {
450 cout << text1[i * 80 + j];
451 }
452 cout << endl;
453 for (j = 0; j < line_length; j++) {
454 cout << text2[i * 80 + j];
455 }
456 cout << endl;
457 cout << " " << endl;
458 }
459}
460
461void cryptography_domain::decipher(std::string &ctext, std::string &ptext, std::string &guess)
462{
463 int i, j, l;
464 char str_key[1000], c1, c2;
465
466 l = guess.length() / 2;
467 for (i = 0; i < 26; i++) {
468 str_key[i] = '-';
469 }
470 str_key[26] = 0;
471 for (i = 0; i < l; i++) {
472 c1 = guess[2 * i + 0];
473 c2 = guess[2 * i + 1];
474 c1 = lower_case(c1);
475 c2 = lower_case(c2);
476 cout << c1 << " -> " << c2 << endl;
477 j = c1 - 'a';
478 //cout << "j=" << j << endl;
479 str_key[j] = c2;
480 }
481 string key;
482
483 key.assign(str_key);
484 substition_cipher(ctext, ptext, key);
485}
486
487void cryptography_domain::analyze(std::string &text)
488{
489 int mult[100];
490 int mult2[100];
491
492 single_frequencies(text, mult);
493 cout << "single frequencies:" << endl;
494 print_frequencies(mult);
495 cout << endl;
496
497 double_frequencies(text, mult2);
498 cout << "double frequencies:" << endl;
499 print_frequencies(mult2);
500 cout << endl;
501}
502
504{
505 int i, a = 0, b = n * (n - 1);
506 double d;
507
508 for (i = 0; i < 26; i++) {
509 if (mult[i] > 1) {
510 a += mult[i] * (mult[i] - 1);
511 }
512 }
513 d = (double) a / (double) b;
514 return d;
515}
516
517double cryptography_domain::friedman_index_shifted(int *mult, int n, int shift)
518{
519 int i, ii;
520 double a = 0., d;
521
522 for (i = 0; i < 26; i++) {
523 ii = i + shift;
524 ii = ii % 26;
525 if (mult[ii]) {
526 a += letter_probability[i] * (double) mult[ii];
527 }
528 }
529 d = (double) a / (double) n;
530 return d;
531}
532
534{
535 int i, j = 0, k = 0, h, l = 0, f_first = TRUE;
536 char c;
537
538 for (i = 0; i < 26; i++) {
539 if (mult[i]) {
540 l++;
541 }
542 }
543 int *mult_val = new int[2 * l];
544 for (i = 0; i < 26; i++) {
545 if (mult[i]) {
546 for (j = 0; j < k; j++) {
547 if (mult_val[2 * j + 1] < mult[i]) {
548 // insert here:
549 for (h = k; h > j; h--) {
550 mult_val[2 * h + 1] = mult_val[2 * (h - 1) + 1];
551 mult_val[2 * h + 0] = mult_val[2 * (h - 1) + 0];
552 }
553 mult_val[2 * j + 0] = i;
554 mult_val[2 * j + 1] = mult[i];
555 break;
556 }
557 }
558 if (j == k) {
559 mult_val[2 * k + 0] = i;
560 mult_val[2 * k + 1] = mult[i];
561 }
562 k++;
563 }
564 }
565
566 for (i = 0; i < l; i++) {
567 c = 'a' + mult_val[2 * i + 0];
568 j = mult_val[2 * i + 1];
569 if (!f_first) {
570 cout << ", ";
571 }
572 cout << c;
573 if (j > 1) {
574 cout << "^" << j;
575 }
576 f_first = FALSE;
577 }
578}
579
580void cryptography_domain::single_frequencies(std::string &text, int *mult)
581{
582 int i, l;
583
584 l = text.length();
585 for (i = 0; i < 26; i++) {
586 mult[i] = 0;
587 }
588 for (i = 0; i < l; i++) {
589 mult[text[i] - 'a']++;
590 }
591}
592
593void cryptography_domain::single_frequencies2(std::string &text, int stride, int n, int *mult)
594{
595 int i;
596
597 for (i = 0; i < 26; i++) {
598 mult[i] = 0;
599 }
600 for (i = 0; i < n; i++) {
601 mult[text[i * stride] - 'a']++;
602 }
603}
604
605void cryptography_domain::double_frequencies(std::string &text, int *mult)
606{
607 int i, l;
608
609 l = text.length();
610 for (i = 0; i < 26; i++) {
611 mult[i] = 0;
612 }
613 for (i = 0; i < l - 1; i++) {
614 if (text[i] == text[i + 1]) {
615 mult[text[i] - 'a']++;
616 }
617 }
618}
619
620void cryptography_domain::substition_cipher(std::string &ptext, std::string &ctext, std::string &key)
621{
622 int i, l;
623 char c;
624 char *str;
625
626 cout << "applying key:" << endl;
627 for (i = 0; i < 26; i++) {
628 c = 'a' + i;
629 cout << c;
630 }
631 cout << endl;
632 cout << key << endl;
633 l = ptext.length();
634 str = NEW_char(l + 1);
635 for (i = 0; i < l; i++) {
636 if (is_alnum(ptext[i])) {
637 str[i] = key[lower_case(ptext[i]) - 'a'];
638 }
639 else {
640 str[i] = ptext[i];
641 }
642 }
643 str[l] = 0;
644 ctext.assign(str);
645 FREE_char(str);
646}
647
649{
650 if (c >= 'A' && c <= 'Z') {
651 c = c - ('A' - 'a');
652 return c;
653 }
654 else if (c >= 'a' && c <= 'z') {
655 return c;
656 }
657 else {
658 //cout << "illegal character " << c << endl;
659 //exit(1);
660 return c;
661 }
662}
663
665{
666 if (c >= 'a' && c <= 'z') {
667 c = c + ('A' - 'a');
668 return c;
669 }
670 else if (c >= 'A' && c <= 'Z') {
671 return c;
672 }
673 else {
674 //cout << "illegal character " << c << endl;
675 //exit(1);
676 return c;
677 }
678}
679
681{
682 if (c >= 'A' && c <= 'Z') {
683 return TRUE;
684 }
685 if (c >= 'a' && c <= 'z') {
686 return TRUE;
687 }
688 return FALSE;
689}
690
692{
693 char digits[100];
694 int i, j, k, l;
696
697 for (i = 0; i < 26; i++) {
698 digits[i] = 'a' + i;
699 }
700 digits[26] = 0;
701 for (i = 0; i < 26; i++) {
702 l = strlen(digits);
703 j = OS.random_integer(l);
704 p[i] = digits[j];
705 for (k = j + 1; k <= l; k++) {
706 digits[k - 1] = digits[k];
707 }
708 l--;
709 }
710 p.assign(digits);
711}
712
713
714
715
716void cryptography_domain::make_affine_sequence(int a, int c, int m, int verbose_level)
717{
718 int f_v = (verbose_level >= 1);
719 int *f_reached;
720 int *orbit;
721 int x0, x, y, len, cnt;
723
724 if (f_v) {
725 cout << "make_affine_sequence a=" << a << " c=" << c << " m=" << m << endl;
726 }
727 f_reached = NEW_int(m);
728 orbit = NEW_int(m);
729 Int_vec_zero(f_reached, m);
730 cnt = 0;
731 for (x0 = 0; x0 < m; x0++) {
732 if (f_reached[x0]) {
733 continue;
734 }
735
736 x = x0;
737 orbit[0] = x0;
738 len = 1;
739 while (TRUE) {
740 f_reached[x] = TRUE;
741 y = NT.mult_mod(a, x, m);
742 y = NT.add_mod(y, c, m);
743
744 if (f_reached[y]) {
745 break;
746 }
747 orbit[len++] = y;
748 x = y;
749 }
750 cout << "orbit " << cnt << " of " << x0 << " has length " << len << " : ";
751 Int_vec_print(cout, orbit, len);
752 cout << endl;
753
754 make_2D_plot(orbit, len, cnt, m, a, c, verbose_level);
755 //make_graph(orbit, len, m, verbose_level);
756 //list_sequence_in_binary(orbit, len, m, verbose_level);
757 cnt++;
758 }
759 FREE_int(orbit);
760 FREE_int(f_reached);
761
762
763}
764
766 int *orbit, int orbit_len, int cnt, int m, int a, int c,
767 int verbose_level)
768{
769 int f_v = (verbose_level >= 1);
770
771 if (f_v) {
772 cout << "m=" << m << " orbit_len=" << orbit_len << endl;
773 }
774 int *M;
775 int h, x, y;
776
777 M = NEW_int(m * m);
778 Int_vec_zero(M, m * m);
779
780
781
782 for (h = 0; h < orbit_len - 1; h++) {
783 x = orbit[h];
784 y = orbit[h + 1];
785 M[x * m + y] = 1;
786 }
787 char str[1000];
788 string fname;
790
791 snprintf(str, 1000, "orbit_cnt%d_m%d_a%d_c%d.csv", cnt, m, a, c);
792 fname.assign(str);
793 Fio.int_matrix_write_csv(fname, M, m, m);
794
795 cout << "Written file " << fname << " of size " << Fio.file_size(fname) << endl;
796
797 FREE_int(M);
798}
799
800
801
802void cryptography_domain::do_random_last(int random_nb, int verbose_level)
803{
804 int i, r = 0;
805
806
807 cout << "RAND_MAX=" << RAND_MAX << endl;
808
809 for (i = 0; i < random_nb; i++) {
810 r = rand();
811 }
812 cout << r << endl;
813
814
815}
816
817void cryptography_domain::do_random(int random_nb, std::string &fname_csv, int verbose_level)
818{
819 int i;
820 int *R;
821
822
823 cout << "RAND_MAX=" << RAND_MAX << endl;
824
825 R = NEW_int(random_nb);
826 for (i = 0; i < random_nb; i++) {
827 R[i] = rand();
828 }
829
831
832 Fio.int_vec_write_csv(R, random_nb, fname_csv, "R");
833
834 cout << "written file " << fname_csv << " of size " << Fio.file_size(fname_csv) << endl;
835
836
837}
838
840 int EC_b, int EC_c, int EC_s,
841 std::string &pt_text, std::string &EC_message,
842 int verbose_level)
843{
844 int f_v = (verbose_level >= 1);
845 int x0, x, y;
846
847 if (f_v) {
848 cout << "do_EC_Koblitz_encoding" << endl;
849 }
850 if (f_v) {
851 cout << "do_EC_Koblitz_encoding b = " << EC_b << endl;
852 cout << "do_EC_Koblitz_encoding c = " << EC_c << endl;
853 cout << "do_EC_Koblitz_encoding s = " << EC_s << endl;
854 }
855
856 vector<vector<int>> Encoding;
857 vector<int> J;
858
859 int u, i, j, r;
860
861 u = F->q / 27;
862 if (f_v) {
863 cout << "do_EC_Koblitz_encoding u = " << u << endl;
864 }
865
866
867 for (i = 1; i <= 26; i++) {
868 x0 = i * u;
869 for (j = 0; j < u; j++) {
870 x = x0 + j;
871 r = EC_evaluate_RHS(F, EC_b, EC_c, x);
872 if (F->is_square(r)) {
873 y = F->square_root(r);
874 break;
875 }
876 }
877 if (j < u) {
878 {
879 vector<int> pt;
880
881 J.push_back(j);
882 pt.push_back(x);
883 pt.push_back(y);
884 pt.push_back(1);
885 Encoding.push_back(pt);
886 }
887 }
888 else {
889 cout << "failure to encode letter " << i << endl;
890 exit(1);
891 }
892 }
893 for (i = 0; i < 26; i++) {
894
895
896 x = (i + 1) * u + J[i];
897
898 r = EC_evaluate_RHS(F, EC_b, EC_c, x);
899
900 y = F->square_root(r);
901
902 cout << (char)('A' + i) << " & " << i + 1 << " & " << J[i] << " & " << x
903 << " & " << r
904 << " & " << y
905 << " & $(" << Encoding[i][0] << "," << Encoding[i][1] << ")$ "
906 << "\\\\" << endl;
907
908 }
909
910 cout << "without j:" << endl;
911 for (i = 0; i < 26; i++) {
912 cout << (char)('A' + i) << " & $(" << Encoding[i][0] << "," << Encoding[i][1] << ")$ \\\\" << endl;
913
914 }
915
916
917
918 vector<vector<int>> Pts;
919 int order;
920 int *v;
921 int len;
922 int Gx, Gy, Gz;
923 int Mx, My, Mz;
924 int Rx, Ry, Rz;
925 int Ax, Ay, Az;
926 int Cx, Cy, Cz;
927 int Tx, Ty, Tz;
928 int Dx, Dy, Dz;
929 int msRx, msRy, msRz;
930 int m, k, plain;
933
934 Int_vec_scan(pt_text, v, len);
935 if (len != 2) {
936 cout << "point should have just two coordinates" << endl;
937 exit(1);
938 }
939 Gx = v[0];
940 Gy = v[1];
941 Gz = 1;
942 FREE_int(v);
943 cout << "G = (" << Gx << "," << Gy << "," << Gz << ")" << endl;
944
945
947 EC_b, EC_c, order,
948 Gx, Gy, Gz,
949 Pts,
950 verbose_level);
951
952
953 int minus_s;
954
955 minus_s = order - EC_s;
956
957 cout << "order = " << order << endl;
958 cout << "minus_s = " << minus_s << endl;
959
960 Ax = Pts[EC_s - 1][0];
961 Ay = Pts[EC_s - 1][1];
962 Az = 1;
963 cout << "A = (" << Ax << "," << Ay << "," << Az << ")" << endl;
964
965 len = EC_message.length();
966
967 //F->nb_calls_to_elliptic_curve_addition() = 0;
968
969 vector<vector<int>> Ciphertext;
970
971 for (i = 0; i < len; i++) {
972 if (EC_message[i] < 'A' || EC_message[i] > 'Z') {
973 continue;
974 }
975 m = EC_message[i] - 'A' + 1;
976 k = 1 + Os.random_integer(order - 1);
977
978 Mx = Encoding[m - 1][0];
979 My = Encoding[m - 1][1];
980 Mz = 1;
981
982 // R := k * G
983 //cout << "$R=" << k << "*G$\\\\" << endl;
984
985 NT.elliptic_curve_point_multiple /*_with_log*/(F,
986 EC_b, EC_c, k,
987 Gx, Gy, Gz,
988 Rx, Ry, Rz,
989 0 /*verbose_level*/);
990 //cout << "$R=" << k << "*G=(" << Rx << "," << Ry << "," << Rz << ")$\\\\" << endl;
991
992 // C := k * A
993 //cout << "$C=" << k << "*A$\\\\" << endl;
994 NT.elliptic_curve_point_multiple /*_with_log*/(F,
995 EC_b, EC_c, k,
996 Ax, Ay, Az,
997 Cx, Cy, Cz,
998 0 /*verbose_level*/);
999 //cout << "$C=" << k << "*A=(" << Cx << "," << Cy << "," << Cz << ")$\\\\" << endl;
1000
1001 // T := C + M
1003 EC_b, EC_c,
1004 Cx, Cy, Cz,
1005 Mx, My, Mz,
1006 Tx, Ty, Tz,
1007 0 /*verbose_level*/);
1008 //cout << "$T=C+M=(" << Tx << "," << Ty << "," << Tz << ")$\\\\" << endl;
1009 {
1010 vector<int> cipher;
1011
1012 cipher.push_back(Rx);
1013 cipher.push_back(Ry);
1014 cipher.push_back(Tx);
1015 cipher.push_back(Ty);
1016 Ciphertext.push_back(cipher);
1017 }
1018
1019 cout << setw(4) << i << " & " << EC_message[i] << " & " << setw(4) << m << " & " << setw(4) << k
1020 << "& (" << setw(4) << Mx << "," << setw(4) << My << "," << setw(4) << Mz << ") "
1021 << "& (" << setw(4) << Rx << "," << setw(4) << Ry << "," << setw(4) << Rz << ") "
1022 << "& (" << setw(4) << Cx << "," << setw(4) << Cy << "," << setw(4) << Cz << ") "
1023 << "& (" << setw(4) << Tx << "," << setw(4) << Ty << "," << setw(4) << Tz << ") "
1024 << "\\\\"
1025 << endl;
1026
1027 }
1028
1029 cout << "Ciphertext:\\\\" << endl;
1030 for (i = 0; i < (int) Ciphertext.size(); i++) {
1031 cout << Ciphertext[i][0] << ",";
1032 cout << Ciphertext[i][1] << ",";
1033 cout << Ciphertext[i][2] << ",";
1034 cout << Ciphertext[i][3] << "\\\\" << endl;
1035 }
1036
1037 for (i = 0; i < (int) Ciphertext.size(); i++) {
1038 Rx = Ciphertext[i][0];
1039 Ry = Ciphertext[i][1];
1040 Tx = Ciphertext[i][2];
1041 Ty = Ciphertext[i][3];
1042
1043 // msR := -s * R
1045 EC_b, EC_c, minus_s,
1046 Rx, Ry, Rz,
1047 msRx, msRy, msRz,
1048 0 /*verbose_level*/);
1049
1050 // D := msR + T
1052 EC_b, EC_c,
1053 msRx, msRy, msRz,
1054 Tx, Ty, Tz,
1055 Dx, Dy, Dz,
1056 0 /*verbose_level*/);
1057
1058 plain = Dx / u;
1059
1060 cout << setw(4) << i << " & (" << Rx << "," << Ry << "," << Tx << "," << Ty << ") "
1061 << "& (" << setw(4) << msRx << "," << setw(4) << msRy << "," << setw(4) << msRz << ") "
1062 << "& (" << setw(4) << Dx << "," << setw(4) << Dy << "," << setw(4) << Dz << ") "
1063 << " & " << plain << " & " << (char)('A' - 1 + plain)
1064 << "\\\\"
1065 << endl;
1066
1067 }
1068
1069 //cout << "nb_calls_to_elliptic_curve_addition="
1070 // << F->nb_calls_to_elliptic_curve_addition() << endl;
1071
1072
1073 if (f_v) {
1074 cout << "cryptography_domain::do_EC_Koblitz_encoding done" << endl;
1075 }
1076}
1077
1079 int EC_b, int EC_c, int verbose_level)
1080{
1081 int f_v = (verbose_level >= 1);
1082 int x, y, r, y1, y2;
1083
1084 if (f_v) {
1085 cout << "cryptography_domain::do_EC_points" << endl;
1086 }
1087 vector<vector<int>> Pts;
1088
1089 for (x = 0; x < F->q; x++) {
1090 r = EC_evaluate_RHS(F, EC_b, EC_c, x);
1091 if (r == 0) {
1092
1093 {
1094 vector<int> pt;
1095
1096 pt.push_back(x);
1097 pt.push_back(0);
1098 pt.push_back(1);
1099 Pts.push_back(pt);
1100 }
1101 }
1102 else {
1103 if (F->is_square(r)) {
1104 y = F->square_root(r);
1105 y1 = y;
1106 y2 = F->negate(y);
1107 if (y2 == y1) {
1108 {
1109 vector<int> pt;
1110
1111 pt.push_back(x);
1112 pt.push_back(y1);
1113 pt.push_back(1);
1114 Pts.push_back(pt);
1115 }
1116 }
1117 else {
1118 if (y2 < y1) {
1119 y1 = y2;
1120 y2 = y;
1121 }
1122 {
1123 vector<int> pt;
1124
1125 pt.push_back(x);
1126 pt.push_back(y1);
1127 pt.push_back(1);
1128 Pts.push_back(pt);
1129 }
1130 {
1131 vector<int> pt;
1132
1133 pt.push_back(x);
1134 pt.push_back(y2);
1135 pt.push_back(1);
1136 Pts.push_back(pt);
1137 }
1138 }
1139 }
1140 else {
1141 // no point for this x coordinate
1142 }
1143
1144#if 0
1145 if (p != 2) {
1146 l = Legendre(r, q, 0);
1147
1148 if (l == 1) {
1149 y = sqrt_mod_involved(r, q);
1150 // DISCRETA/global.cpp
1151
1152 if (F->mult(y, y) != r) {
1153 cout << "There is a problem "
1154 "with the square root" << endl;
1155 exit(1);
1156 }
1157 y1 = y;
1158 y2 = F->negate(y);
1159 if (y2 < y1) {
1160 y1 = y2;
1161 y2 = y;
1162 }
1163 add_point_to_table(x, y1, 1);
1164 if (nb == bound) {
1165 cout << "The number of points "
1166 "exceeds the bound" << endl;
1167 exit(1);
1168 }
1169 add_point_to_table(x, y2, 1);
1170 if (nb == bound) {
1171 cout << "The number of points "
1172 "exceeds the bound" << endl;
1173 exit(1);
1174 }
1175 //cout << nb++ << " : (" << x << ","
1176 // << y << ",1)" << endl;
1177 //cout << nb++ << " : (" << x << ","
1178 // << F.negate(y) << ",1)" << endl;
1179 }
1180 }
1181 else {
1182 y = F->frobenius_power(r, e - 1);
1183 add_point_to_table(x, y, 1);
1184 if (nb == bound) {
1185 cout << "The number of points exceeds "
1186 "the bound" << endl;
1187 exit(1);
1188 }
1189 //cout << nb++ << " : (" << x << ","
1190 // << y << ",1)" << endl;
1191 }
1192#endif
1193
1194 }
1195 }
1196 {
1197 vector<int> pt;
1198
1199 pt.push_back(0);
1200 pt.push_back(1);
1201 pt.push_back(0);
1202 Pts.push_back(pt);
1203 }
1204 int i;
1205 cout << "We found " << Pts.size() << " points:" << endl;
1206
1207
1208 for (i = 0; i < (int) Pts.size(); i++) {
1209 if (i == (int) Pts.size()) {
1210
1211 cout << i << " : {\\cal O} : 1\\\\" << endl;
1212
1213 }
1214 else {
1215 {
1216 vector<vector<int>> Multiples;
1217 int order;
1219
1221 EC_b, EC_c, order,
1222 Pts[i][0], Pts[i][1], 1,
1223 Multiples,
1224 0 /*verbose_level*/);
1225
1226 //cout << "we found that the point has order " << order << endl;
1227
1228 cout << i << " : $(" << Pts[i][0] << "," << Pts[i][1] << ")$ : " << order << "\\\\" << endl;
1229 }
1230 }
1231 }
1232
1233 {
1234 int *M;
1235
1236 M = NEW_int(F->q * F->q);
1237 Int_vec_zero(M, F->q * F->q);
1238
1239
1240 for (i = 0; i < (int) Pts.size(); i++) {
1241 vector<int> pt;
1242 int x, y, z;
1243
1244 pt = Pts[i];
1245 x = pt[0];
1246 y = pt[1];
1247 z = pt[2];
1248 if (z == 1) {
1249 M[(F->q - 1 - y) * F->q + x] = 1;
1250 }
1251 }
1252 string fname;
1254
1255 fname.assign(label);
1256 fname.append("_points_xy.csv");
1257 Fio.int_matrix_write_csv(fname, M, F->q, F->q);
1258 cout << "Written file " << fname << " of size " << Fio.file_size(fname) << endl;
1259
1260 FREE_int(M);
1261 }
1262
1263 {
1264 int *M;
1265 int cnt = 0;
1266
1267 M = NEW_int((int) Pts.size() * 2);
1268 Int_vec_zero(M, (int) Pts.size() * 2);
1269
1270
1271 for (i = 0; i < (int) Pts.size(); i++) {
1272 vector<int> pt;
1273 int x, y, z;
1274
1275 pt = Pts[i];
1276 x = pt[0];
1277 y = pt[1];
1278 z = pt[2];
1279 if (z == 1) {
1280 M[cnt * 2 + 0] = x;
1281 M[cnt * 2 + 1] = y;
1282 cnt++;
1283 }
1284 }
1285 string fname;
1287
1288 fname.assign(label);
1289 fname.append("_points_xy_affine_pts.csv");
1290 Fio.int_matrix_write_csv(fname, M, cnt, 2);
1291 cout << "Written file " << fname << " of size " << Fio.file_size(fname) << endl;
1292
1293 FREE_int(M);
1294 }
1295
1296
1297 if (f_v) {
1298 cout << "cryptography_domain::do_EC_points done" << endl;
1299 }
1300}
1301
1303 int EC_b, int EC_c, int x)
1304// evaluates x^3 + bx + c
1305{
1306 int x2, x3, t;
1307
1308 x2 = F->mult(x, x);
1309 x3 = F->mult(x2, x);
1310 t = F->add(x3, F->mult(EC_b, x));
1311 t = F->add(t, EC_c);
1312 return t;
1313}
1314
1315
1317 int EC_b, int EC_c,
1318 std::string &pt1_text, std::string &pt2_text,
1319 int verbose_level)
1320{
1321 int f_v = (verbose_level >= 1);
1322 int x1, y1, z1;
1323 int x2, y2, z2;
1324 int x3, y3, z3;
1325 int *v;
1326 int len;
1328 //sscanf(p1, "(%d,%d,%d)", &x1, &y1, &z1);
1329
1330 if (f_v) {
1331 cout << "do_EC_add" << endl;
1332 }
1333 vector<vector<int>> Pts;
1334
1335 Int_vec_scan(pt1_text, v, len);
1336 if (len != 2) {
1337 cout << "point should have just two coordinates" << endl;
1338 exit(1);
1339 }
1340 x1 = v[0];
1341 y1 = v[1];
1342 z1 = 1;
1343 FREE_int(v);
1344
1345 Int_vec_scan(pt2_text, v, len);
1346 if (len != 2) {
1347 cout << "point should have just two coordinates" << endl;
1348 exit(1);
1349 }
1350 x2 = v[0];
1351 y2 = v[1];
1352 z2 = 1;
1353 FREE_int(v);
1354
1355
1357 EC_b, EC_c,
1358 x1, y1, z1,
1359 x2, y2, z2,
1360 x3, y3, z3,
1361 verbose_level);
1362 cout << "(" << x1 << "," << y1 << "," << z1 << ")";
1363 cout << " + ";
1364 cout << "(" << x2 << "," << y2 << "," << z2 << ")";
1365 cout << " = ";
1366 cout << "(" << x3 << "," << y3 << "," << z3 << ")";
1367 cout << endl;
1368
1369
1370 //FREE_OBJECT(F);
1371
1372 if (f_v) {
1373 cout << "do_EC_add done" << endl;
1374 }
1375}
1376
1378 int EC_b, int EC_c, std::string &pt_text, int verbose_level)
1379{
1380 int f_v = (verbose_level >= 1);
1381 int x1, y1, z1;
1382 int *v;
1383 int len, i;
1385 //sscanf(p1, "(%d,%d,%d)", &x1, &y1, &z1);
1386
1387 if (f_v) {
1388 cout << "cryptography_domain::do_EC_cyclic_subgroup" << endl;
1389 }
1390 vector<vector<int>> Pts;
1391 int order;
1392
1393 Int_vec_scan(pt_text, v, len);
1394 if (len != 2) {
1395 cout << "cryptography_domain::do_EC_cyclic_subgroup "
1396 "point should have just two coordinates" << endl;
1397 exit(1);
1398 }
1399 x1 = v[0];
1400 y1 = v[1];
1401 z1 = 1;
1402 FREE_int(v);
1403
1404
1406 EC_b, EC_c, order,
1407 x1, y1, z1,
1408 Pts,
1409 verbose_level);
1410
1411 cout << "cryptography_domain::do_EC_cyclic_subgroup "
1412 "we found that the point has order " << order << endl;
1413 cout << "The multiples are:" << endl;
1414 cout << "i : (" << x1 << "," << y1 << ")" << endl;
1415 for (i = 0; i < (int) Pts.size(); i++) {
1416
1417 vector<int> pts = Pts[i];
1418
1419 if (i < (int) Pts.size() - 1) {
1420 cout << setw(3) << i + 1 << " : ";
1421 cout << "$(" << pts[0] << "," << pts[1] << ")$";
1422 cout << "\\\\" << endl;
1423 }
1424 else {
1425 cout << setw(3) << i + 1 << " : ";
1426 cout << "${\\cal O}$";
1427 cout << "\\\\" << endl;
1428
1429 }
1430 }
1431
1432 if (f_v) {
1433 cout << "cryptography_domain::do_EC_cyclic_subgroup done" << endl;
1434 }
1435}
1436
1438 int EC_b, int EC_c, std::string &pt_text, int n, int verbose_level)
1439{
1440 int f_v = (verbose_level >= 1);
1441 int x1, y1, z1;
1442 int x3, y3, z3;
1443 int *v;
1444 int len;
1446
1447 if (f_v) {
1448 cout << "cryptography_domain::do_EC_multiple_of" << endl;
1449 }
1450
1451 Int_vec_scan(pt_text, v, len);
1452 if (len != 2) {
1453 cout << "cryptography_domain::do_EC_multiple_of "
1454 "point should have just two coordinates" << endl;
1455 exit(1);
1456 }
1457 x1 = v[0];
1458 y1 = v[1];
1459 z1 = 1;
1460 FREE_int(v);
1461
1462
1464 EC_b, EC_c, n,
1465 x1, y1, z1,
1466 x3, y3, z3,
1467 verbose_level);
1468
1469 cout << "The " << n << "-fold multiple of (" << x1 << "," << y1 << ") is ";
1470 if (z3 == 0) {
1471
1472 }
1473 else {
1474 if (z3 != 1) {
1475 cout << "z1 != 1" << endl;
1476 exit(1);
1477 }
1478 cout << "(" << x3 << "," << y3 << ")" << endl;
1479 }
1480
1481 if (f_v) {
1482 cout << "cryptography_domain::do_EC_multiple_of done" << endl;
1483 }
1484}
1485
1487 int EC_b, int EC_c,
1488 std::string &base_pt_text, std::string &pt_text, int verbose_level)
1489{
1490 int f_v = (verbose_level >= 1);
1491 int x1, y1, z1;
1492 int x3, y3, z3;
1493 int *v;
1494 int len;
1495 int n;
1497
1498 if (f_v) {
1499 cout << "cryptography_domain::do_EC_discrete_log" << endl;
1500 }
1501
1502 Int_vec_scan(base_pt_text, v, len);
1503 if (len != 2) {
1504 cout << "point should have just two coordinates" << endl;
1505 exit(1);
1506 }
1507 x1 = v[0];
1508 y1 = v[1];
1509 z1 = 1;
1510 FREE_int(v);
1511
1512
1513 Int_vec_scan(pt_text, v, len);
1514 if (len == 2) {
1515 x3 = v[0];
1516 y3 = v[1];
1517 z3 = 1;
1518 }
1519 else if (len == 3) {
1520 x3 = v[0];
1521 y3 = v[1];
1522 z3 = v[2];
1523 }
1524 else {
1525 cout << "the point should have either two or three coordinates" << endl;
1526 exit(1);
1527 }
1528 FREE_int(v);
1529
1530
1532 EC_b, EC_c,
1533 x1, y1, z1,
1534 x3, y3, z3,
1535 verbose_level);
1536
1537
1538 cout << "The discrete log of (" << x3 << "," << y3 << "," << z3 << ") "
1539 "w.r.t. (" << x1 << "," << y1 << "," << z1 << ") "
1540 "is " << n << endl;
1541
1542 if (f_v) {
1543 cout << "cryptography_domain::do_EC_discrete_log done" << endl;
1544 }
1545}
1546
1548 std::string &EC_bsgs_G, int EC_bsgs_N,
1549 std::string &EC_bsgs_cipher_text,
1550 int verbose_level)
1551{
1552 int f_v = (verbose_level >= 1);
1553 int Gx, Gy, Gz;
1554 int nGx, nGy, nGz;
1555 int Cx, Cy, Cz;
1556 int Mx, My, Mz;
1557 int Ax, Ay, Az;
1558 int *v;
1559 int len;
1560 int n;
1562
1563 if (f_v) {
1564 cout << "cryptography_domain::do_EC_baby_step_giant_step" << endl;
1565 }
1566
1567
1568 Int_vec_scan(EC_bsgs_G, v, len);
1569 if (len != 2) {
1570 cout << "point should have just two coordinates" << endl;
1571 exit(1);
1572 }
1573 Gx = v[0];
1574 Gy = v[1];
1575 Gz = 1;
1576 FREE_int(v);
1577
1578 n = (int) sqrt((double) EC_bsgs_N) + 1;
1579 if (f_v) {
1580 cout << "cryptography_domain::do_EC_baby_step_giant_step N = " << EC_bsgs_N << endl;
1581 cout << "cryptography_domain::do_EC_baby_step_giant_step n = " << n << endl;
1582 }
1583
1584 Int_vec_scan(EC_bsgs_cipher_text, v, len);
1585
1586 int cipher_text_length = len >> 1;
1587 int h, i;
1588
1589 if (f_v) {
1590 cout << "cryptography_domain::do_EC_baby_step_giant_step "
1591 "cipher_text_length = " << cipher_text_length << endl;
1592 }
1593
1595 EC_b, EC_c, n,
1596 Gx, Gy, Gz,
1597 nGx, nGy, nGz,
1598 0 /*verbose_level*/);
1599
1600 cout << "$" << n << " * G = (" << nGx << "," << nGy << ")$\\\\" << endl;
1601
1602 cout << " & ";
1603 for (h = 0; h < cipher_text_length; h++) {
1604 Cx = v[2 * h + 0];
1605 Cy = v[2 * h + 1];
1606 Cz = 1;
1607 cout << " & (" << Cx << "," << Cy << ")";
1608 }
1609 cout << endl;
1610
1611 for (i = 1; i <= n + 1; i++) {
1612
1614 EC_b, EC_c, i,
1615 Gx, Gy, Gz,
1616 Mx, My, Mz,
1617 0 /*verbose_level*/);
1618
1619 cout << i << " & (" << Mx << "," << My << ")";
1620
1621 for (h = 0; h < cipher_text_length; h++) {
1622 Cx = v[2 * h + 0];
1623 Cy = v[2 * h + 1];
1624 Cz = 1;
1625
1627 EC_b, EC_c, i,
1628 nGx, nGy, nGz,
1629 Mx, My, Mz,
1630 0 /*verbose_level*/);
1631
1632 My = F->negate(My);
1633
1634
1635
1637 EC_b, EC_c,
1638 Cx, Cy, Cz,
1639 Mx, My, Mz,
1640 Ax, Ay, Az,
1641 0 /*verbose_level*/);
1642
1643 cout << " & (" << Ax << "," << Ay << ")";
1644
1645 }
1646 cout << "\\\\" << endl;
1647 }
1648
1649
1650
1651 FREE_int(v);
1652
1653 if (f_v) {
1654 cout << "cryptography_domain::do_EC_baby_step_giant_step done" << endl;
1655 }
1656}
1657
1659 field_theory::finite_field *F, int EC_b, int EC_c,
1660 std::string &EC_bsgs_A, int EC_bsgs_N,
1661 std::string &EC_bsgs_cipher_text, std::string &EC_bsgs_keys,
1662 int verbose_level)
1663{
1664 int f_v = (verbose_level >= 1);
1665 int Ax, Ay, Az;
1666 int Tx, Ty, Tz;
1667 int Cx, Cy, Cz;
1668 int Mx, My, Mz;
1669 int *v;
1670 int len;
1671 int n;
1672 int *keys;
1673 int nb_keys;
1674 int u, plain;
1676
1677 if (f_v) {
1678 cout << "cryptography_domain::do_EC_baby_step_giant_step_decode" << endl;
1679 }
1680
1681 u = F->q / 27;
1682 if (f_v) {
1683 cout << "cryptography_domain::do_EC_baby_step_giant_step_decode u = " << u << endl;
1684 }
1685
1686
1687 Int_vec_scan(EC_bsgs_A, v, len);
1688 if (len != 2) {
1689 cout << "cryptography_domain::do_EC_baby_step_giant_step_decode "
1690 "point should have just two coordinates" << endl;
1691 exit(1);
1692 }
1693 Ax = v[0];
1694 Ay = v[1];
1695 Az = 1;
1696 FREE_int(v);
1697
1698 Int_vec_scan(EC_bsgs_keys, keys, nb_keys);
1699
1700
1701 n = (int) sqrt((double) EC_bsgs_N) + 1;
1702 if (f_v) {
1703 cout << "cryptography_domain::do_EC_baby_step_giant_step_decode N = " << EC_bsgs_N << endl;
1704 cout << "cryptography_domain::do_EC_baby_step_giant_step_decode n = " << n << endl;
1705 }
1706
1707 Int_vec_scan(EC_bsgs_cipher_text, v, len);
1708
1709 int cipher_text_length = len >> 1;
1710 int h;
1711
1712 if (f_v) {
1713 cout << "cryptography_domain::do_EC_baby_step_giant_step_decode "
1714 "cipher_text_length = " << cipher_text_length << endl;
1715 cout << "cryptography_domain::do_EC_baby_step_giant_step_decode "
1716 "nb_keys = " << nb_keys << endl;
1717 }
1718 if (nb_keys != cipher_text_length) {
1719 cout << "nb_keys != cipher_text_length" << endl;
1720 exit(1);
1721 }
1722
1723
1724 for (h = 0; h < cipher_text_length; h++) {
1725 Tx = v[2 * h + 0];
1726 Ty = v[2 * h + 1];
1727 Tz = 1;
1728 cout << h << " & (" << Tx << "," << Ty << ")\\\\" << endl;;
1729 }
1730 cout << endl;
1731
1732
1733 for (h = 0; h < cipher_text_length; h++) {
1734
1735
1736
1737 Tx = v[2 * h + 0];
1738 Ty = v[2 * h + 1];
1739 Tz = 1;
1740
1741
1743 EC_b, EC_c, keys[h],
1744 Ax, Ay, Az,
1745 Cx, Cy, Cz,
1746 0 /*verbose_level*/);
1747
1748 Cy = F->negate(Cy);
1749
1750
1751 cout << h << " & " << keys[h]
1752 << " & (" << Tx << "," << Ty << ")"
1753 << " & (" << Cx << "," << Cy << ")";
1754
1755
1757 EC_b, EC_c,
1758 Tx, Ty, Tz,
1759 Cx, Cy, Cz,
1760 Mx, My, Mz,
1761 0 /*verbose_level*/);
1762
1763 cout << " & (" << Mx << "," << My << ")";
1764
1765 plain = Mx / u;
1766 cout << " & " << plain << " & " << (char)('A' - 1 + plain) << "\\\\" << endl;
1767
1768 }
1769
1770
1771 FREE_int(v);
1772 FREE_int(keys);
1773
1774 if (f_v) {
1775 cout << "cryptography_domain::do_EC_baby_step_giant_step_decode done" << endl;
1776 }
1777}
1778
1779void cryptography_domain::do_RSA_encrypt_text(long int RSA_d, long int RSA_m,
1780 int RSA_block_size, std::string &RSA_encrypt_text, int verbose_level)
1781{
1782 int f_v = (verbose_level >= 1);
1783
1784 if (f_v) {
1785 cout << "cryptography_domain::do_RSA_encrypt_text" << endl;
1786 }
1787
1788 int i, j, l, nb_blocks;
1789 long int a;
1790 char c;
1791 long int *Data;
1792
1793 l = RSA_encrypt_text.length();
1794 nb_blocks = (l + RSA_block_size - 1) / RSA_block_size;
1795 Data = NEW_lint(nb_blocks);
1796 for (i = 0; i < nb_blocks; i++) {
1797 a = 0;
1798 for (j = 0; j < RSA_block_size; j++) {
1799 c = RSA_encrypt_text[i * RSA_block_size + j];
1800 if (c >= 'a' && c <= 'z') {
1801 a *= 100;
1802 a += (int) (c - 'a') + 1;
1803 }
1804 Data[i] = a;
1805 }
1806 }
1807
1810
1811 M.create(RSA_m, __FILE__, __LINE__);
1812
1813 for (i = 0; i < nb_blocks; i++) {
1814 A.create(Data[i], __FILE__, __LINE__);
1815 D.power_int_mod(
1816 A, RSA_d, M);
1817 cout << A;
1818 if (i < nb_blocks - 1) {
1819 cout << ",";
1820 }
1821 }
1822 cout << endl;
1823 if (f_v) {
1824 cout << "cryptography_domain::do_RSA_encrypt_text done" << endl;
1825 }
1826}
1827
1828void cryptography_domain::do_RSA(long int RSA_d, long int RSA_m, int RSA_block_size,
1829 std::string &RSA_text, int verbose_level)
1830{
1831 int f_v = (verbose_level >= 1);
1832 long int *data;
1833 int data_sz;
1834 int i;
1835
1836 if (f_v) {
1837 cout << "cryptography_domain::do_RSA RSA_d=" << RSA_d << " RSA_m=" << RSA_m << endl;
1838 }
1839 Lint_vec_scan(RSA_text, data, data_sz);
1840 if (f_v) {
1841 cout << "text: ";
1842 Lint_vec_print(cout, data, data_sz);
1843 cout << endl;
1844 }
1845
1848
1849 M.create(RSA_m, __FILE__, __LINE__);
1850 for (i = 0; i < data_sz; i++) {
1851 A.create(data[i], __FILE__, __LINE__);
1852 D.power_int_mod(
1853 A, RSA_d, M);
1854 cout << i << " : " << data[i] << " : " << A << endl;
1855 }
1856 for (i = 0; i < data_sz; i++) {
1857 A.create(data[i], __FILE__, __LINE__);
1858 D.power_int_mod(
1859 A, RSA_d, M);
1860 cout << A;
1861 if (i < data_sz - 1) {
1862 cout << ",";
1863 }
1864 }
1865 cout << endl;
1866
1867 long int a;
1868 int b, j;
1869 char str[1000];
1870
1871 for (i = 0; i < data_sz; i++) {
1872 A.create(data[i], __FILE__, __LINE__);
1873 D.power_int_mod(A, RSA_d, M);
1874 //cout << A;
1875 a = A.as_lint();
1876 for (j = 0; j < RSA_block_size; j++) {
1877 b = a % 100;
1878 if (b > 26 || b == 0) {
1879 str[RSA_block_size - 1 - j] = ' ';
1880 }
1881 else {
1882 str[RSA_block_size - 1 - j] = 'a' + b - 1;
1883 }
1884 a -= b;
1885 a /= 100;
1886 }
1887 str[RSA_block_size] = 0;
1888 for (j = 0; j < RSA_block_size; j++) {
1889 if (str[j] != ' ') {
1890 break;
1891 }
1892 }
1893 cout << str + j;
1894 if (i < data_sz - 1) {
1895 cout << ",";
1896 }
1897 }
1898 cout << endl;
1899}
1900
1901
1903 std::string &H_coeffs, std::string &R_coeffs, std::string &Msg_coeffs,
1904 int verbose_level)
1905{
1906 int f_v = (verbose_level >= 1);
1907
1908 if (f_v) {
1909 cout << "cryptography_domain::NTRU_encrypt" << endl;
1910 }
1911
1912
1913 int *data_H;
1914 int *data_R;
1915 int *data_Msg;
1916 int sz_H, sz_R, sz_Msg;
1917
1918 Int_vec_scan(H_coeffs, data_H, sz_H);
1919 Int_vec_scan(R_coeffs, data_R, sz_R);
1920 Int_vec_scan(Msg_coeffs, data_Msg, sz_Msg);
1921
1923
1924
1925
1927 ring_theory::unipoly_object H, R, Msg, M, C, D;
1928
1929
1930 int dh = sz_H - 1;
1931 int dr = sz_R - 1;
1932 int dm = sz_Msg - 1;
1933 int i;
1934
1935 FX.create_object_of_degree(H, dh);
1936
1937 for (i = 0; i <= dh; i++) {
1938 if (data_H[i] < 0 || data_H[i] >= Fq->q) {
1939 data_H[i] = NT.mod(data_H[i], Fq->q);
1940 }
1941 FX.s_i(H, i) = data_H[i];
1942 }
1943
1944 FX.create_object_of_degree(R, dr);
1945
1946 for (i = 0; i <= dr; i++) {
1947 if (data_R[i] < 0 || data_R[i] >= Fq->q) {
1948 data_R[i] = NT.mod(data_R[i], Fq->q);
1949 }
1950 FX.s_i(R, i) = data_R[i];
1951 }
1952
1953 FX.create_object_of_degree(Msg, dm);
1954
1955 for (i = 0; i <= dm; i++) {
1956 if (data_Msg[i] < 0 || data_Msg[i] >= Fq->q) {
1957 data_Msg[i] = NT.mod(data_Msg[i], Fq->q);
1958 }
1959 FX.s_i(Msg, i) = data_Msg[i];
1960 }
1961
1962 FX.create_object_of_degree(M, N);
1963 for (i = 0; i <= N; i++) {
1964 FX.s_i(M, i) = 0;
1965 }
1966 FX.s_i(M, 0) = Fq->negate(1);
1967 FX.s_i(M, N) = 1;
1968
1969 cout << "H(X)=";
1970 FX.print_object(H, cout);
1971 cout << endl;
1972
1973
1974 cout << "R(X)=";
1975 FX.print_object(R, cout);
1976 cout << endl;
1977
1978 cout << "Msg(X)=";
1979 FX.print_object(Msg, cout);
1980 cout << endl;
1981
1982 FX.create_object_of_degree(C, dh);
1983
1984 FX.create_object_of_degree(D, dh);
1985
1986
1987
1988 if (f_v) {
1989 cout << "cryptography_domain::NTRU_encrypt before FX.mult_mod" << endl;
1990 }
1991
1992 {
1993 FX.mult_mod(R, H, C, M, verbose_level);
1994 int d;
1995
1996 d = FX.degree(C);
1997
1998 for (i = 0; i <= d; i++) {
1999 FX.s_i(C, i) = Fq->mult(p, FX.s_i(C, i));
2000 }
2001
2002 FX.add(C, Msg, D);
2003
2004 }
2005
2006 if (f_v) {
2007 cout << "cryptography_domain::NTRU_encrypt after FX.mult_mod" << endl;
2008 }
2009
2010 cout << "D(X)=";
2011 FX.print_object(D, cout);
2012 cout << endl;
2013
2014 cout << "deg D(X) = " << FX.degree(D) << endl;
2015
2016
2017
2018
2019
2020
2021 if (f_v) {
2022 cout << "cryptography_domain::NTRU_encrypt done" << endl;
2023 }
2024}
2025
2026
2029 int verbose_level)
2030{
2031 int f_v = (verbose_level >= 1);
2032
2033 if (f_v) {
2034 cout << "cryptography_domain::polynomial_center_lift" << endl;
2035 }
2036
2037
2038 int *data_A;
2039 int sz_A;
2040
2041 Int_vec_scan(A_coeffs, data_A, sz_A);
2042
2044
2045
2046
2049
2050
2051 int da = sz_A - 1;
2052 int i;
2053
2054 FX.create_object_of_degree(A, da);
2055
2056 for (i = 0; i <= da; i++) {
2057 if (data_A[i] < 0 || data_A[i] >= F->q) {
2058 data_A[i] = NT.mod(data_A[i], F->q);
2059 }
2060 FX.s_i(A, i) = data_A[i];
2061 }
2062
2063
2064 cout << "A(X)=";
2065 FX.print_object(A, cout);
2066 cout << endl;
2067
2068
2069
2070
2071 if (f_v) {
2072 cout << "cryptography_domain::polynomial_center_lift before FX.mult_mod" << endl;
2073 }
2074
2075 {
2076 FX.center_lift_coordinates(A, F->q);
2077
2078 }
2079
2080 if (f_v) {
2081 cout << "cryptography_domain::polynomial_center_lift after FX.mult_mod" << endl;
2082 }
2083
2084 cout << "A(X)=";
2085 FX.print_object(A, cout);
2086 cout << endl;
2087
2088
2089
2090
2091 if (f_v) {
2092 cout << "cryptography_domain::polynomial_center_lift done" << endl;
2093 }
2094}
2095
2096
2099 int verbose_level)
2100{
2101 int f_v = (verbose_level >= 1);
2102
2103 if (f_v) {
2104 cout << "cryptography_domain::polynomial_reduce_mod_p" << endl;
2105 }
2106
2107
2108 int *data_A;
2109 int sz_A;
2110
2111 Int_vec_scan(A_coeffs, data_A, sz_A);
2112
2114
2115
2116
2119
2120
2121 int da = sz_A - 1;
2122 int i;
2123
2124 FX.create_object_of_degree(A, da);
2125
2126 for (i = 0; i <= da; i++) {
2127 data_A[i] = NT.mod(data_A[i], F->q);
2128 FX.s_i(A, i) = data_A[i];
2129 }
2130
2131
2132 cout << "A(X)=";
2133 FX.print_object(A, cout);
2134 cout << endl;
2135
2136
2137
2138
2139 if (f_v) {
2140 cout << "cryptography_domain::polynomial_reduce_mod_p done" << endl;
2141 }
2142}
2143
2144
2145
2146void cryptography_domain::do_jacobi(int jacobi_top, int jacobi_bottom, int verbose_level)
2147{
2148 char fname[1000];
2149 char title[1000];
2150 char author[1000];
2151
2152 snprintf(fname, 1000, "jacobi_%d_%d.tex", jacobi_top, jacobi_bottom);
2153 snprintf(title, 1000, "Jacobi %d over %d", jacobi_top, jacobi_bottom);
2154 //sprintf(author, "");
2155 author[0] = 0;
2156
2157
2158 {
2159 ofstream f(fname);
2160
2161
2163
2164
2165 L.head(f, FALSE /* f_book*/, TRUE /* f_title */,
2166 title, author, FALSE /* f_toc */, FALSE /* f_landscape */,
2167 TRUE /* f_12pt */,
2168 TRUE /* f_enlarged_page */,
2169 TRUE /* f_pagenumbers */,
2170 NULL /* extra_praeamble */);
2171
2172
2175
2177
2178 A.create(jacobi_top, __FILE__, __LINE__);
2179
2180 B.create(jacobi_bottom, __FILE__, __LINE__);
2181
2182 D.jacobi(A, B, verbose_level);
2183
2185 jacobi_top, jacobi_bottom, verbose_level);
2186 //Computes the Jacobi symbol $\left( \frac{a}{m} \right)$.
2187
2188 L.foot(f);
2189 }
2190
2192
2193 cout << "written file " << fname << " of size " << Fio.file_size(fname) << endl;
2194
2195
2196}
2197
2198void cryptography_domain::do_solovay_strassen(int p, int a, int verbose_level)
2199{
2200 char fname[1000];
2201 char title[1000];
2202 char author[1000];
2203
2204 snprintf(fname, 1000, "solovay_strassen_%d_%d.tex", p, a);
2205 snprintf(title, 1000, "Solovay Strassen %d with base %d", p, a);
2206 //sprintf(author, "");
2207 author[0] = 0;
2208
2209
2210 {
2211 ofstream f(fname);
2212
2213
2215
2216
2217 L.head(f, FALSE /* f_book*/, TRUE /* f_title */,
2218 title, author, FALSE /* f_toc */, FALSE /* f_landscape */,
2219 TRUE /* f_12pt */,
2220 TRUE /* f_enlarged_page */,
2221 TRUE /* f_pagenumbers */,
2222 NULL /* extra_praeamble */);
2223
2224
2226 //longinteger_domain D;
2227
2229
2230 P.create(p, __FILE__, __LINE__);
2231
2232 A.create(a, __FILE__, __LINE__);
2233
2234 //D.jacobi(A, B, verbose_level);
2235
2237 P, A,
2238 verbose_level);
2239
2240
2241 L.foot(f);
2242 }
2243
2245
2246 cout << "written file " << fname << " of size " << Fio.file_size(fname) << endl;
2247
2248
2249}
2250
2251void cryptography_domain::do_miller_rabin(int p, int nb_times, int verbose_level)
2252{
2253 char fname[1000];
2254 char title[1000];
2255 char author[1000];
2256
2257 snprintf(fname, 1000, "miller_rabin_%d.tex", p);
2258 snprintf(title, 1000, "Miller Rabin %d", p);
2259 //sprintf(author, "");
2260 author[0] = 0;
2261
2262
2263 {
2264 ofstream f(fname);
2265
2266
2268
2269
2270 L.head(f, FALSE /* f_book*/, TRUE /* f_title */,
2271 title, author, FALSE /* f_toc */, FALSE /* f_landscape */,
2272 TRUE /* f_12pt */,
2273 TRUE /* f_enlarged_page */,
2274 TRUE /* f_pagenumbers */,
2275 NULL /* extra_praeamble */);
2276
2277
2278 //longinteger_domain D;
2279
2281
2282 P.create(p, __FILE__, __LINE__);
2283
2284 int i;
2285
2286 for (i = 0; i < nb_times; i++) {
2287
2288 f << "Miller Rabin test no " << i << ":\\\\" << endl;
2290 P, i,
2291 verbose_level)) {
2292 break;
2293 }
2294
2295 }
2296 if (i == nb_times) {
2297 f << "Miller Rabin: The number is probably prime. Miller Rabin is inconclusive.\\\\" << endl;
2298 }
2299 else {
2300 f << "Miller Rabin: The number is not prime.\\\\" << endl;
2301 }
2302
2303 L.foot(f);
2304 }
2305
2307
2308 cout << "written file " << fname << " of size " << Fio.file_size(fname) << endl;
2309
2310
2311}
2312
2313void cryptography_domain::do_fermat_test(int p, int nb_times, int verbose_level)
2314{
2315 char fname[1000];
2316 char title[1000];
2317 char author[1000];
2318
2319 snprintf(fname, 1000, "fermat_%d.tex", p);
2320 snprintf(title, 1000, "Fermat test %d", p);
2321 //sprintf(author, "");
2322 author[0] = 0;
2323
2324
2325 {
2326 ofstream f(fname);
2327
2328
2330
2331
2332 L.head(f, FALSE /* f_book*/, TRUE /* f_title */,
2333 title, author, FALSE /* f_toc */, FALSE /* f_landscape */,
2334 TRUE /* f_12pt */,
2335 TRUE /* f_enlarged_page */,
2336 TRUE /* f_pagenumbers */,
2337 NULL /* extra_praeamble */);
2338
2339
2340 //longinteger_domain D;
2342
2343
2344 P.create(p, __FILE__, __LINE__);
2345
2347 P, nb_times,
2348 verbose_level)) {
2349 f << "Fermat: The number $" << P << "$ is not prime.\\\\" << endl;
2350 }
2351 else {
2352 f << "Fermat: The number $" << P << "$ is probably prime. Fermat test is inconclusive.\\\\" << endl;
2353 }
2354
2355 L.foot(f);
2356 }
2357
2359
2360 cout << "written file " << fname << " of size " << Fio.file_size(fname) << endl;
2361
2362
2363}
2364
2366 int nb_fermat, int nb_miller_rabin, int nb_solovay_strassen,
2367 int verbose_level)
2368{
2369 char fname[1000];
2370 char title[1000];
2371 char author[1000];
2372
2373 snprintf(fname, 1000, "pseudoprime_%d.tex", nb_digits);
2374 snprintf(title, 1000, "Pseudoprime %d", nb_digits);
2375 //sprintf(author, "");
2376 author[0] = 0;
2377
2378
2379 {
2380 ofstream ost(fname);
2381
2382
2384
2385
2386 L.head(ost, FALSE /* f_book*/, TRUE /* f_title */,
2387 title, author, FALSE /* f_toc */, FALSE /* f_landscape */,
2388 TRUE /* f_12pt */,
2389 TRUE /* f_enlarged_page */,
2390 TRUE /* f_pagenumbers */,
2391 NULL /* extra_praeamble */);
2392
2393
2396
2397
2398 int cnt = -1;
2399
2400 //f << "\\begin{multicols}{2}" << endl;
2401 ost << "\\begin{enumerate}[(1)]" << endl;
2402 while (TRUE) {
2403
2404 cnt++;
2405
2406 D.random_number_with_n_decimals(P, nb_digits, verbose_level);
2407
2408 ost << "\\item" << endl;
2409 ost << "Trial " << cnt << ", testing random number " << P << endl;
2410
2411 if (P.ith(0) != 1 && P.ith(0) != 3 && P.ith(0) != 7 && P.ith(0) != 9) {
2412 ost << "the number is not prime by looking at the lowest digit." << endl;
2413 continue;
2414 }
2415
2416 ost << "\\begin{enumerate}[(a)]" << endl;
2417 ost << "\\item" << endl;
2419 P, nb_fermat,
2420 verbose_level)) {
2421 //f << "Fermat: The number $" << P << "$ is not prime.\\\\" << endl;
2422 ost << "\\end{enumerate}" << endl;
2423 continue;
2424 }
2425 else {
2426 //f << "Fermat: The number $" << P << "$ is probably prime. Fermat test is inconclusive.\\\\" << endl;
2427 }
2428
2429
2430 if (nb_miller_rabin) {
2431 ost << "\\item" << endl;
2433 P, nb_miller_rabin,
2434 verbose_level)) {
2435 ost << "Miller Rabin: The number $" << P << "$ is not prime.\\\\" << endl;
2436 ost << "\\end{enumerate}" << endl;
2437 continue;
2438 }
2439 else {
2440 //ost << "Miller Rabin: The number $" << P << "$ is probably prime. Miller Rabin test is inconclusive.\\\\" << endl;
2441 }
2442 }
2443 else {
2444 ost << "\\end{enumerate}" << endl;
2445 break;
2446 }
2447
2448 if (nb_solovay_strassen) {
2449 ost << "\\item" << endl;
2451 P, nb_solovay_strassen,
2452 verbose_level)) {
2453 //ost << "Solovay-Strassen: The number $" << P << "$ is not prime.\\\\" << endl;
2454 ost << "\\end{enumerate}" << endl;
2455 continue;
2456 }
2457 else {
2458 //ost << "Solovay-Strassen: The number $" << P << "$ is probably prime. Solovay-Strassen test is inconclusive.\\\\" << endl;
2459 ost << "\\end{enumerate}" << endl;
2460 break;
2461 }
2462 }
2463 else {
2464 ost << "\\end{enumerate}" << endl;
2465 break;
2466 }
2467 ost << "\\end{enumerate}" << endl;
2468
2469 }
2470 ost << "\\end{enumerate}" << endl;
2471 //ost << "\\end{multicols}" << endl;
2472
2473 ost << "\\noindent" << endl;
2474 ost << "The number $" << P << "$ is probably prime. \\\\" << endl;
2475 ost << "Number of Fermat tests = " << nb_fermat << " \\\\" << endl;
2476 ost << "Number of Miller Rabin tests = " << nb_miller_rabin << " \\\\" << endl;
2477 ost << "Number of Solovay-Strassen tests = " << nb_solovay_strassen << " \\\\" << endl;
2478
2479 L.foot(ost);
2480 }
2481
2483
2484 cout << "written file " << fname << " of size " << Fio.file_size(fname) << endl;
2485
2486
2487}
2488
2489void cryptography_domain::do_find_strong_pseudoprime(int nb_digits, int nb_fermat, int nb_miller_rabin, int verbose_level)
2490{
2491 char fname[1000];
2492 char title[1000];
2493 char author[1000];
2494
2495 snprintf(fname, 1000, "strong_pseudoprime_%d.tex", nb_digits);
2496 snprintf(title, 1000, "Strong Pseudoprime %d", nb_digits);
2497 //sprintf(author, "");
2498 author[0] = 0;
2499
2500
2501 {
2502 ofstream f(fname);
2503
2504
2506
2507
2508 L.head(f, FALSE /* f_book*/, TRUE /* f_title */,
2509 title, author, FALSE /* f_toc */, FALSE /* f_landscape */,
2510 TRUE /* f_12pt */,
2511 TRUE /* f_enlarged_page */,
2512 TRUE /* f_pagenumbers */,
2513 NULL /* extra_praeamble */);
2514
2515
2518
2519
2520 int cnt = -1;
2521
2522 f << "\\begin{multicols}{2}" << endl;
2523 f << "\\begin{enumerate}[(1)]" << endl;
2524 while (TRUE) {
2525
2526 cnt++;
2527
2528 D.random_number_with_n_decimals(P, nb_digits, verbose_level);
2529
2530 f << "\\item" << endl;
2531 f << "Trial " << cnt << ", testing random number " << P << endl;
2532
2533 if (P.ith(0) != 1 && P.ith(0) != 3 && P.ith(0) != 7 && P.ith(0) != 9) {
2534 f << "the number is not prime by looking at the lowest digit" << endl;
2535 continue;
2536 }
2537
2538 f << "\\begin{enumerate}[(a)]" << endl;
2539 f << "\\item" << endl;
2541 P, nb_fermat,
2542 verbose_level)) {
2543 //f << "Fermat: The number $" << P << "$ is not prime.\\\\" << endl;
2544 f << "\\end{enumerate}" << endl;
2545 continue;
2546 }
2547 else {
2548 //f << "Fermat: The number $" << P << "$ is probably prime. Fermat test is inconclusive.\\\\" << endl;
2549 }
2550
2551 f << "\\item" << endl;
2553 P, nb_miller_rabin,
2554 verbose_level)) {
2555 //f << "Miller Rabin: The number $" << P << "$ is not prime.\\\\" << endl;
2556 f << "\\end{enumerate}" << endl;
2557 continue;
2558 }
2559 else {
2560 //f << "Miller Rabin: The number $" << P << "$ is probably prime. Miller Rabin test is inconclusive.\\\\" << endl;
2561 f << "\\end{enumerate}" << endl;
2562 break;
2563 }
2564
2565
2566 f << "\\end{enumerate}" << endl;
2567
2568 }
2569 f << "\\end{enumerate}" << endl;
2570 f << "\\end{multicols}" << endl;
2571
2572 f << "\\noindent" << endl;
2573 f << "The number $" << P << "$ is probably prime. \\\\" << endl;
2574 f << "Number of Fermat tests = " << nb_fermat << " \\\\" << endl;
2575 f << "Number of Miller Rabin tests = " << nb_miller_rabin << " \\\\" << endl;
2576
2577 L.foot(f);
2578 }
2579
2581
2582 cout << "written file " << fname << " of size " << Fio.file_size(fname) << endl;
2583
2584
2585}
2586
2587
2588void cryptography_domain::do_miller_rabin_text(std::string &number_text,
2589 int nb_miller_rabin, int verbose_level)
2590{
2591 char fname[1000];
2592 char title[1000];
2593 char author[1000];
2594
2595 snprintf(fname, 1000, "miller_rabin_%s.tex", number_text.c_str());
2596 snprintf(title, 1000, "Miller Rabin %s", number_text.c_str());
2597 //sprintf(author, "");
2598 author[0] = 0;
2599
2600
2601 {
2602 ofstream f(fname);
2603
2604
2606
2607
2608 L.head(f, FALSE /* f_book*/, TRUE /* f_title */,
2609 title, author, FALSE /* f_toc */, FALSE /* f_landscape */,
2610 TRUE /* f_12pt */,
2611 TRUE /* f_enlarged_page */,
2612 TRUE /* f_pagenumbers */,
2613 NULL /* extra_praeamble */);
2614
2615
2616 //longinteger_domain D;
2618
2619
2620 f << "\\begin{multicols}{2}" << endl;
2621
2622 P.create_from_base_10_string(number_text);
2623
2624
2625 if (P.ith(0) != 1 && P.ith(0) != 3 && P.ith(0) != 7 && P.ith(0) != 9) {
2626 f << "the number is not prime by looking at the lowest digit" << endl;
2627 }
2628 else {
2629
2631 P, nb_miller_rabin,
2632 verbose_level)) {
2633 f << "Miller Rabin: The number $" << P << "$ is not prime.\\\\" << endl;
2634 }
2635 else {
2636 f << "The number $" << P << "$ is probably prime. \\\\" << endl;
2637 }
2638 }
2639
2640
2641 f << "\\end{multicols}" << endl;
2642
2643 f << "\\noindent" << endl;
2644 f << "Number of Miller Rabin tests = " << nb_miller_rabin << " \\\\" << endl;
2645
2646 L.foot(f);
2647 }
2648
2650
2651 cout << "written file " << fname << " of size " << Fio.file_size(fname) << endl;
2652
2653
2654}
2655
2657 int factorbase, int x0, int verbose_level)
2658{
2659 int f_v = (verbose_level >= 1);
2660 vector<int> small_factors, primes, primes_log2, R1, R2;
2664 int f_found_small_factor = FALSE;
2665 int small_factor;
2666 int i;
2667
2668 if (f_v) {
2669 cout << "quadratic_sieve" << endl;
2670 }
2671 if (f_v) {
2672 cout << "quadratic_sieve before sieve" << endl;
2673 }
2674 NT.sieve(primes, factorbase, verbose_level - 1);
2675 if (f_v) {
2676 cout << "quadratic_sieve after sieve" << endl;
2677 cout << "list of primes has length " << primes.size() << endl;
2678 }
2679 D.create_Mersenne(M, n);
2680 cout << "Mersenne number M_" << n << "=" << M << " log10=" << M.len() << endl;
2681 D.square_root(M, sqrtM, 0 /*verbose_level - 1*/);
2682 cout << "sqrtM=" << sqrtM << " log10=" << sqrtM.len() << endl;
2683
2684 // N1.mult(sqrtM, sqrtM);
2685 // sqrtM.inc();
2686 // N2.mult(sqrtM, sqrtM);
2687 // sqrtM.dec();
2688 // cout << "sqrtM^2=" << N1 << endl;
2689 // cout << "M=" << M << endl;
2690 // cout << "(sqrtM+1)^2=" << N2 << endl;
2691 // longinteger_compare_verbose(N1, M);
2692 // longinteger_compare_verbose(M, N2);
2693
2694 cout << "calling reduce_primes" << endl;
2695 //small_primes.m_l(0);
2696 while (TRUE) {
2697 //int p;
2698 reduce_primes(primes, M,
2699 f_found_small_factor, small_factor,
2700 verbose_level - 1);
2701 if (!f_found_small_factor) {
2702 break;
2703 }
2705
2706 cout << "dividing out small factor " << small_factor << endl;
2707 small_factors.push_back(small_factor);
2708 P.create(small_factor, __FILE__, __LINE__);
2709 D.integral_division_exact(M, P, Q);
2710 Q.assign_to(M);
2711 cout << "reduced M=" << M << " log10=" << M.len() << endl;
2712 D.square_root(M, sqrtM, 0 /*verbose_level - 1*/);
2713 cout << "sqrtM=" << sqrtM << endl << endl;
2714 }
2715 cout << "list of small factors has length " << small_factors.size() << endl;
2716 for (i = 0; i < (int) small_factors.size(); i++) {
2717 cout << i << " : " << small_factors[i] << endl;
2718 }
2719
2720 if (M.is_one()) {
2721 cout << "the number has been completely factored" << endl;
2722 exit(0);
2723 }
2724
2725
2726 calc_roots(M, sqrtM, primes, R1, R2, 0/*verbose_level - 1*/);
2727 calc_log2(primes, primes_log2, 0 /*verbose_level - 1*/);
2728
2729
2730 int f_x_file = FALSE;
2731 vector<int> X;
2732
2733 if (f_x_file) {
2734#if 0
2735 int l = primes.size();
2736 int ll = l + 10;
2737
2738 read_x_file(X, x_file, ll);
2739#endif
2740 }
2741 else {
2742 Quadratic_Sieve(factorbase, FALSE /* f_mod */, 0 /* mod_n */, 0 /* mod_r */, x0,
2743 n, M, sqrtM,
2744 primes, primes_log2, R1, R2, X, verbose_level - 1);
2745 if (FALSE /*f_mod*/) {
2746 exit(1);
2747 }
2748 }
2749
2750
2751 if (f_v) {
2752 cout << "quadratic_sieve done" << endl;
2753 }
2754
2755}
2756
2757void cryptography_domain::calc_log2(vector<int> &primes, vector<int> &primes_log2, int verbose_level)
2758{
2759 int i, l, k;
2760
2761 l = primes.size();
2762 for (i = 0; i < l; i++) {
2763 k = log2(primes[i]);
2764 primes_log2.push_back(k);
2765 }
2766}
2767
2769 std::string &square_root_mod_n,
2770 std::vector<long int> &S, int verbose_level)
2771{
2772 int f_v = (verbose_level >= 1);
2773 long int i, a, n;
2775
2776 if (f_v) {
2777 cout << "cryptography_domain::all_square_roots_mod_n_by_exhaustive_search_lint" << endl;
2778 }
2779
2780 a = ST.strtoi(square_root_a);
2781 n = ST.strtoi(square_root_mod_n);
2782 for (i = 0; i < a; i++) {
2783 if (((i * i) % n) == a) {
2784 S.push_back(i);
2785 }
2786 }
2787
2788 if (f_v) {
2789 cout << "cryptography_domain::all_square_roots_mod_n_by_exhaustive_search_lint done" << endl;
2790 }
2791}
2792
2793void cryptography_domain::square_root(std::string &square_root_number, int verbose_level)
2794{
2795 int f_v = (verbose_level >= 1);
2798
2799 if (f_v) {
2800 cout << "square_root" << endl;
2801 }
2802 a.create_from_base_10_string(square_root_number);
2803 cout << "computing square root of " << a << endl;
2804 D.square_root(a, b, verbose_level - 4);
2805 cout << "square root of " << a << " is " << b << endl;
2806
2807 if (f_v) {
2808 cout << "square_root done" << endl;
2809 }
2810}
2811
2812void cryptography_domain::square_root_mod(std::string &square_root_number,
2813 std::string &mod_number, int verbose_level)
2814{
2815 int f_v = (verbose_level >= 1);
2818 int b;
2819
2820 if (f_v) {
2821 cout << "square_root" << endl;
2822 }
2823 a.create_from_base_10_string(square_root_number);
2824 cout << "computing square root of " << a << endl;
2825 m.create_from_base_10_string(mod_number);
2826 cout << "modulo " << m << endl;
2827 b = D.square_root_mod(a.as_int(), m.as_int(), verbose_level -1);
2828 cout << "square root of " << a << " mod " << m << " is " << b << endl;
2829
2830 if (f_v) {
2831 cout << "square_root done" << endl;
2832 }
2833}
2834
2835void cryptography_domain::reduce_primes(vector<int> &primes,
2837 int &f_found_small_factor, int &small_factor,
2838 int verbose_level)
2839{
2840 int f_v = (verbose_level >= 1);
2841 int i, l, r, s, p;
2844
2845 if (f_v) {
2846 cout << "reduce_primes" << endl;
2847 }
2848 f_found_small_factor = FALSE;
2849 small_factor = 0;
2850 l = primes.size();
2851 for (i = 0; i < l; i++) {
2852 p = primes[i];
2853 // cout << "i=" << i << " prime=" << p << endl;
2855 p, Q, r);
2856
2857 R.create(r, __FILE__, __LINE__);
2858 P.create(p, __FILE__, __LINE__);
2859
2860 s = D.jacobi(R, P, 0 /* verbose_level */);
2861 //s = Legendre(r, p, 0);
2862 // cout << "i=" << i << " p=" << p << " Mmodp=" << r
2863 //<< " Legendre(r,p)=" << s << endl;
2864 if (s == 0) {
2865 cout << "M is divisible by " << p << endl;
2866 //exit(1);
2867 f_found_small_factor = TRUE;
2868 small_factor = p;
2869 return;
2870 }
2871 if (s == -1) {
2872 primes.erase(primes.begin()+i);
2873 l--;
2874 i--;
2875 }
2876 }
2877 cout << "number of primes remaining = " << primes.size() << endl;
2878}
2879
2880
2881void cryptography_domain::do_sift_smooth(int sift_smooth_from,
2882 int sift_smooth_len,
2883 std::string &sift_smooth_factor_base, int verbose_level)
2884{
2885 int f_v = (verbose_level >= 1);
2886 int *B;
2887 int sz;
2888 int a, i, j, nb, p, idx, cnt;
2891
2892 if (f_v) {
2893 cout << "do_sift_smooth" << endl;
2894 }
2895
2896 Int_vec_scan(sift_smooth_factor_base, B, sz);
2897 Sorting.int_vec_heapsort(B, sz);
2898
2899 cnt = 0;
2900 for (i = 0; i < sift_smooth_len; i++) {
2901 a = sift_smooth_from + i;
2902
2903 int *primes;
2904 int *exponents;
2905
2906 nb = NT.factor_int(a, primes, exponents);
2907 for (j = 0; j < nb; j++) {
2908 p = primes[j];
2909 if (!Sorting.int_vec_search(B, sz, p, idx)) {
2910 break;
2911 }
2912 }
2913 if (j == nb) {
2914 // the number is smooth:
2915
2916 cout << cnt << " : " << a << " : ";
2917 NT.print_factorization(nb, primes, exponents);
2918 cout << endl;
2919
2920 cnt++;
2921 }
2922
2923 FREE_int(primes);
2924 FREE_int(exponents);
2925
2926 }
2927}
2928
2929void cryptography_domain::do_discrete_log(long int y, long int a, long int p, int verbose_level)
2930{
2931 int f_v = (verbose_level >= 1);
2933 int t0, t1, dt;
2935
2936 if (f_v) {
2937 cout << "do_discrete_log" << endl;
2938 cout << "y=" << y << endl;
2939 cout << "a=" << a << endl;
2940 cout << "p=" << p << endl;
2941 }
2942
2943 t0 = Os.os_ticks();
2944 //finite_field F;
2945 long int n, b;
2946
2947 //F.init(p, 0);
2948 for (n = 0; n < p - 1; n++) {
2949 //b = F.power(a, n);
2950 b = NT.power_mod(a, n, p);
2951 if (b == y) {
2952 break;
2953 }
2954 }
2955
2956 if (n == p - 1) {
2957 cout << "could not solve the discrete log problem." << endl;
2958 }
2959 else {
2960 cout << "The discrete log is " << n << " since ";
2961 cout << y << " = " << a << "^" << n << " mod " << p << endl;
2962 }
2963
2964 t1 = Os.os_ticks();
2965 dt = t1 - t0;
2966 cout << "time: ";
2967 Os.time_check_delta(cout, dt);
2968 cout << endl;
2969}
2970
2971void cryptography_domain::do_primitive_root(long int p, int verbose_level)
2972{
2974 long int a;
2975 int t0, t1, dt;
2977
2978 t0 = Os.os_ticks();
2979
2980 a = NT.primitive_root_randomized(p, verbose_level);
2981 cout << "a primitive root modulo " << p << " is " << a << endl;
2982
2983 t1 = Os.os_ticks();
2984 dt = t1 - t0;
2985 cout << "time: ";
2986 Os.time_check_delta(cout, dt);
2987 cout << endl;
2988}
2989
2990
2992{
2994 long int a;
2995 int t0, t1, dt;
2997
2998 t0 = Os.os_ticks();
2999
3000 a = NT.primitive_root_randomized(p.as_lint(), verbose_level);
3001 cout << "a primitive root modulo " << p << " is " << a << endl;
3002
3003 t1 = Os.os_ticks();
3004 dt = t1 - t0;
3005 cout << "time: ";
3006 Os.time_check_delta(cout, dt);
3007 cout << endl;
3008}
3009
3010
3011
3012void cryptography_domain::do_smallest_primitive_root(long int p, int verbose_level)
3013{
3014 int f_v = (verbose_level >= 1);
3016 long int a;
3017 int t0, t1, dt;
3019
3020 t0 = Os.os_ticks();
3021 if (f_v) {
3022 cout << "cryptography_domain::do_smallest_primitive_root p=" << p << endl;
3023 }
3024
3025
3026 a = NT.primitive_root(p, verbose_level);
3027 cout << "a primitive root modulo " << p << " is " << a << endl;
3028
3029 t1 = Os.os_ticks();
3030 dt = t1 - t0;
3031 cout << "time: ";
3032 Os.time_check_delta(cout, dt);
3033 cout << endl;
3034 if (f_v) {
3035 cout << "cryptography_domain::do_smallest_primitive_root done" << endl;
3036 }
3037}
3038
3039void cryptography_domain::do_smallest_primitive_root_interval(long int p_min, long int p_max, int verbose_level)
3040{
3041 int f_v = (verbose_level >= 1);
3043 long int a, p, i;
3044 long int *T;
3045 int t0, t1, dt;
3048 char str[1000];
3049
3050 t0 = Os.os_ticks();
3051 if (f_v) {
3052 cout << "cryptography_domain::do_smallest_primitive_root_interval p_min=" << p_min << " p_max=" << p_max << endl;
3053 }
3054
3055 std::vector<std::pair<long int, long int>> Table;
3056
3057 for (p = p_min; p < p_max; p++) {
3058
3059 if (!NT.is_prime(p)) {
3060 continue;
3061 }
3062
3063 std::pair<long int, long int> P;
3064
3065 a = NT.primitive_root(p, verbose_level);
3066 cout << "a primitive root modulo " << p << " is " << a << endl;
3067
3068 P.first = p;
3069 P.second = a;
3070
3071 Table.push_back(P);
3072
3073 }
3074 T = NEW_lint(2 * Table.size());
3075 for (i = 0; i < Table.size(); i++) {
3076 T[2 * i + 0] = Table[i].first;
3077 T[2 * i + 1] = Table[i].second;
3078 }
3079 sprintf(str, "primitive_element_table_%ld_%ld.csv", p_min, p_max);
3080 string fname;
3081
3082 fname.assign(str);
3083 Fio.lint_matrix_write_csv(fname, T, Table.size(), 2);
3084
3085 cout << "Written file " << fname << " of size " << Fio.file_size(fname) << endl;
3086
3087
3088
3089 t1 = Os.os_ticks();
3090 dt = t1 - t0;
3091 cout << "time: ";
3092 Os.time_check_delta(cout, dt);
3093 cout << endl;
3094 if (f_v) {
3095 cout << "cryptography_domain::do_smallest_primitive_root_interval done" << endl;
3096 }
3097}
3098
3099void cryptography_domain::do_number_of_primitive_roots_interval(long int p_min, long int p_max, int verbose_level)
3100{
3101 int f_v = (verbose_level >= 1);
3103 long int a, p, i;
3104 long int *T;
3105 int t0, t1, dt;
3108 char str[1000];
3109
3110 t0 = Os.os_ticks();
3111 if (f_v) {
3112 cout << "cryptography_domain::do_number_of_primitive_roots_interval p_min=" << p_min << " p_max=" << p_max << endl;
3113 }
3114
3115 std::vector<std::pair<long int, long int>> Table;
3116
3117 for (p = p_min; p < p_max; p++) {
3118
3119 if (!NT.is_prime(p)) {
3120 continue;
3121 }
3122
3123 std::pair<long int, long int> P;
3124
3125 a = NT.euler_function(p - 1);
3126 cout << "the number of primitive elements modulo " << p << " is " << a << endl;
3127
3128 P.first = p;
3129 P.second = a;
3130
3131 Table.push_back(P);
3132
3133 }
3134 T = NEW_lint(2 * Table.size());
3135 for (i = 0; i < Table.size(); i++) {
3136 T[2 * i + 0] = Table[i].first;
3137 T[2 * i + 1] = Table[i].second;
3138 }
3139 sprintf(str, "table_number_of_pe_%ld_%ld.csv", p_min, p_max);
3140 string fname;
3141
3142 fname.assign(str);
3143 Fio.lint_matrix_write_csv(fname, T, Table.size(), 2);
3144
3145 cout << "Written file " << fname << " of size " << Fio.file_size(fname) << endl;
3146
3147
3148
3149 t1 = Os.os_ticks();
3150 dt = t1 - t0;
3151 cout << "time: ";
3152 Os.time_check_delta(cout, dt);
3153 cout << endl;
3154 if (f_v) {
3155 cout << "cryptography_domain::do_number_of_primitive_roots_interval done" << endl;
3156 }
3157}
3158
3159
3160void cryptography_domain::do_inverse_mod(long int a, long int n, int verbose_level)
3161{
3163 long int b;
3164 int t0, t1, dt;
3166
3167 t0 = Os.os_ticks();
3168
3169 b = NT.inverse_mod(a, n);
3170 cout << "the inverse of " << a << " mod " << n << " is " << b << endl;
3171
3172 t1 = Os.os_ticks();
3173 dt = t1 - t0;
3174 cout << "time: ";
3175 Os.time_check_delta(cout, dt);
3176 cout << endl;
3177}
3178
3179void cryptography_domain::do_extended_gcd(int a, int b, int verbose_level)
3180{
3181 {
3183
3184 ring_theory::longinteger_object A, B, G, U, V;
3185
3186 A.create(a, __FILE__, __LINE__);
3187 B.create(b, __FILE__, __LINE__);
3188
3189 cout << "before D.extended_gcd" << endl;
3190 D.extended_gcd(A, B,
3191 G, U, V, verbose_level);
3192 cout << "after D.extended_gcd" << endl;
3193
3194 }
3195
3196}
3197
3198
3201 int verbose_level)
3202{
3204 //number_theory_domain NT;
3206 int t0, t1, dt;
3208
3209 t0 = Os.os_ticks();
3210
3211 a.assign_to(b);
3212 D.power_longint_mod(b, k, n, 0 /* verbose_level */);
3213 //b = NT.power_mod(a, k, n);
3214 cout << "the power of " << a << " to the " << k << " mod " << n << " is " << b << endl;
3215
3216 t1 = Os.os_ticks();
3217 dt = t1 - t0;
3218 cout << "time: ";
3219 Os.time_check_delta(cout, dt);
3220 cout << endl;
3221
3222}
3223
3226 vector<int> &primes, vector<int> &R1, vector<int> &R2,
3227 int verbose_level)
3228// computes the root of the polynomial
3229// $X^2 + a X + b$ over $GF(p)$
3230// here, $a = 2 \cdot \lfloor \sqrt{M} \rfloor$
3231// and $b= {\lfloor \sqrt{M} \rfloor }^2 - M$
3232// which is equal to
3233// (X + \lfloor \sqrt{M} \rfloor)^2 - M.
3234// If $x$ is a root of this polynomial mod p then
3235// (x + \lfloor \sqrt{M} \rfloor)^2 = M mod p
3236// and M is a square mod p.
3237// Due to reduce prime, only such p are considered.
3238// The polynomial factors as
3239// $(X - r_1)(X - r_1)= X^2 - (r_1 + r_2) X + r_1 r_2$
3240// Due to reduce primes, the polynomial factors mod p.
3241{
3242 int f_v = (verbose_level >= 1);
3243 int i, l, p, Mmodp, sqrtMmodp, b;
3244 int r1, r2, c, c2, s;
3246 ring_theory::longinteger_object P, l1, l2, l3;
3247
3248 if (f_v) {
3249 cout << "cryptography_domain::calc_roots, verbose_level=" << verbose_level << endl;
3250 cout << "cryptography_domain::calc_roots, M=" << M << endl;
3251 cout << "cryptography_domain::calc_roots, sqrtM=" << sqrtM << endl;
3252 }
3253 l = primes.size();
3254 for (i = 0; i < l; i++) {
3255 p = primes[i];
3256 if (f_v) {
3257 cout << "cryptography_domain::calc_roots i=" << i << " / " << l << " p=" << p << endl;
3258 }
3259 P.create(p, __FILE__, __LINE__);
3260
3261 if (f_v) {
3262 cout << "cryptography_domain::calc_roots before remainder_mod_int" << endl;
3263 }
3264 Mmodp = D.remainder_mod_int(M, p);
3265 if (f_v) {
3266 cout << "cryptography_domain::calc_roots after remainder_mod_int "
3267 "Mmodp=" << Mmodp << endl;
3268 }
3269 if (f_v) {
3270 cout << "cryptography_domain::calc_roots before remainder_mod_int" << endl;
3271 }
3272 sqrtMmodp = D.remainder_mod_int(sqrtM, p);
3273 if (f_v) {
3274 cout << "cryptography_domain::calc_roots after remainder_mod_int, "
3275 "sqrtMmodp=" << sqrtMmodp << endl;
3276 }
3277
3278 // a = 2 * sqrtMmodp mod p
3279 //a = (sqrtMmodp << 1) % p;
3280
3281 // b = (sqrtMmodp * sqrtMmodp) % p;
3282 l1.create(sqrtMmodp, __FILE__, __LINE__);
3283 D.mult_mod(l1, l1, l2, P, 0 /* verbose_level */);
3284 b = l2.as_int();
3285
3286 b = b - Mmodp;
3287 if (b < 0) {
3288 b += p;
3289 }
3290 else {
3291 b = b % p;
3292 }
3293
3294 // use the quadratic formula to compute the roots:
3295 // sqrtMmodp = a / 2.
3296
3297 l1.create(sqrtMmodp, __FILE__, __LINE__);
3298 D.mult_mod(l1, l1, l2, P, 0 /* verbose_level */);
3299 c2 = l2.as_int();
3300 c2 -= b;
3301 while (c2 < 0) {
3302 c2 += p;
3303 }
3304 // c2 = discriminant
3305
3306
3307 if (f_v) {
3308 cout << "cryptography_domain::calc_roots computing square root "
3309 "of discriminant c2=" << c2 << endl;
3310 }
3311 s = D.square_root_mod(c2, p, 0 /* verbose_level*/);
3312 if (f_v) {
3313 cout << "cryptography_domain::calc_roots c2=" << c2 << " s=" << s << endl;
3314 }
3315
3316
3317 c = - sqrtMmodp;
3318 if (c < 0) {
3319 c += p;
3320 }
3321
3322 r1 = (c + s) % p;
3323
3324 r2 = c - s;
3325 if (r2 < 0) {
3326 r2 += p;
3327 }
3328 r2 = r2 % p;
3329
3330
3331 if (f_v) {
3332 cout << "cryptography_domain::calc_roots r1=" << r1 << " r2=" << r2 << endl;
3333 }
3334
3335
3336 R1.push_back(r1);
3337 R2.push_back(r2);
3338 // cout << "i=" << i << " p=" << p
3339 //<< " r1=" << r1 << " r2=" << r2 << endl;
3340
3341 } // next i
3342
3343 if (f_v) {
3344 cout << "cryptography_domain::calc_roots done" << endl;
3345 }
3346}
3347
3349 int factorbase,
3350 int f_mod, int mod_n, int mod_r, int x0,
3352 std::vector<int> &primes, std::vector<int> &primes_log2,
3353 std::vector<int> &R1, std::vector<int> &R2,
3354 std::vector<int> &X,
3355 int verbose_level)
3356{
3357 int f_v = (verbose_level >= 1);
3358 ostringstream ff;
3359 string s;
3360
3361 if (f_v) {
3362 cout << "cryptography_domain::Quadratic_Sieve" << endl;
3363 }
3364 ff << "X_M_" << n << "_FB_" << factorbase;
3365 if (f_mod) {
3366 ff << "_mod_" << mod_n << "_" << mod_r;
3367 }
3368 ff << ".txt";
3369 ff << ends;
3370 s = ff.str();
3371
3372 int l = primes.size();
3373 int ll = l + 10;
3374 int from = x0, to = x0, count = -1, step_size = 50000;
3375
3376 if (f_mod) {
3377 ll = ll / mod_n + 1;
3378 }
3379 //X.m_l(0);
3380
3381
3382
3383
3384 while (TRUE) {
3385 from = to;
3386 to = from + step_size;
3387 count++;
3388
3389 if (f_mod) {
3390 if (count % mod_n != mod_r) {
3391 continue;
3392 }
3393 }
3394 if (quadratic_sieve(M, sqrtM,
3395 primes, primes_log2, R1, R2, from, to, ll, X, verbose_level)) {
3396 break;
3397 }
3398 }
3399
3400 if (f_v) {
3401 cout << "found " << ll << " x_i" << endl;
3402 }
3403
3404 {
3405 ofstream f(s.c_str());
3406
3407#if 1
3408 int i;
3409
3410 for (i = 0; i < ll; i++) {
3411 f << X[i] << " ";
3412 if ((i + 1) % 10 == 0)
3413 f << endl;
3414 }
3415#endif
3416 f << endl << "-1" << endl;
3417 }
3418}
3419
3422 std::vector<int> &primes, std::vector<int> &primes_log2,
3423 std::vector<int> &R1, std::vector<int> &R2,
3424 int from, int to,
3425 int ll, std::vector<int> &X,
3426 int verbose_level)
3427{
3428 int f_v = (verbose_level >= 1);
3429 int x, j;
3431 ring_theory::longinteger_object Z, zero, a, b, c, d;
3432 int i, l;
3433 vector<int> factor_idx, factor_exp;
3434
3435 if (f_v) {
3436 cout << "cryptography_domain::quadratic_sieve" << endl;
3437 }
3438 zero.create(0, __FILE__, __LINE__);
3439 l = primes.size();
3440 j = X.size();
3441 if (f_v) {
3442 cout << "quadratic sieve from=" << from
3443 << " to=" << to << " j=" << j << endl;
3444 cout << "searching for " << ll << " numbers" << endl;
3445 }
3446 for (x = from; x < to; x++) {
3447 if (x == 0)
3448 continue;
3449 a.create(x, __FILE__, __LINE__);
3450 D.add(a, sqrtM, c);
3451 D.mult(c, a, d);
3452 d.assign_to(a);
3453 M.assign_to(b);
3454 b.negate();
3455 D.add(a, b, c);
3456 c.assign_to(a);
3457 if (D.compare_unsigned(a, zero) <= 0) {
3458 continue;
3459 }
3460 a.normalize();
3461
3462#if 1
3463 int xmodp, log2a, sumlog2;
3464 log2a = 3 * (a.len() - 1);
3465 sumlog2 = 0;
3466 for (i = 0; i < l; i++) {
3467 xmodp = x % primes[i];
3468 if (xmodp == R1[i]) {
3469 sumlog2 += primes_log2[i] + 0;
3470 }
3471 if (xmodp == R2[i]) {
3472 sumlog2 += primes_log2[i] + 0;
3473 }
3474 }
3475 // cout << "sieve x=" << x << " log2=" << log2a
3476 //<< " sumlog2=" << sumlog2 << endl;
3477 if (sumlog2 < log2a)
3478 continue;
3479#endif
3481 primes, factor_idx, factor_exp,
3482 verbose_level - 1)) {
3483 continue;
3484 }
3485 //f << x << endl;
3486 if (f_v) {
3487 cout << "found solution " << j << " which is " << x
3488 << ", need " << ll - j << " more" << endl;
3489 }
3490 X.push_back(x);
3491 j++;
3492 if (j >= ll) {
3493 if (f_v) {
3494 cout << "sieve: found enough numbers "
3495 "(enough = " << ll << ")" << endl;
3496 }
3497 if (f_v) {
3498 cout << "cryptography_domain::quadratic_sieve done" << endl;
3499 }
3500 return TRUE;
3501 }
3502 } // next x
3503 if (f_v) {
3504 cout << "cryptography_domain::quadratic_sieve done" << endl;
3505 }
3506 return FALSE;
3507}
3508
3510 std::vector<int> &primes,
3511 std::vector<int> &factor_idx, std::vector<int> &factor_exp,
3512 int verbose_level)
3513{
3515 ring_theory::longinteger_object y, z1, residue;
3516 int i, l, n, p;
3517
3518 x.assign_to(y);
3519 z1.create(1, __FILE__, __LINE__);
3520 l = primes.size();
3521 //factor_idx.m_l(0);
3522 //factor_exp.m_l(0);
3523 for (i = 0; i < l; i++) {
3524 if (D.compare(y, z1) <= 0) {
3525 break;
3526 }
3527 p = primes[i];
3528 n = D.multiplicity_of_p(y, residue, p);
3529 residue.assign_to(y);
3530 if (n) {
3531 factor_idx.push_back(i);
3532 factor_exp.push_back(n);
3533 }
3534 }
3535 if (D.compare_unsigned(y, z1) == 0) {
3536 return TRUE;
3537 }
3538 else {
3539 return FALSE;
3540 }
3541}
3542
3545 vector<int> &primes, vector<int> &exponents,
3546 int verbose_level)
3547{
3549 ring_theory::longinteger_object y, z1, residue;
3550 int i, l, n, nn, p;
3551
3552 x.assign_to(y);
3553 z1.create(1, __FILE__, __LINE__);
3554 l = primes.size();
3555 for (i = 0; i < l; i++) {
3556 if (D.compare(x, z1) <= 0) {
3557 break;
3558 }
3559 p = primes[i];
3560 n = D.multiplicity_of_p(x, residue, p);
3561 residue.assign_to(x);
3562 //n = x.ny_p(p);
3563 // cout << "p=" << p << " ny_p=" << n << endl;
3564 if (n) {
3565 nn = exponents[i] + n;
3566 exponents[i] = nn;
3567 }
3568 }
3569 if (D.compare_unsigned(x, z1) == 0) {
3570 return TRUE;
3571 }
3572 else {
3573 return FALSE;
3574 }
3575}
3576
3577
3580 int nb_solovay_strassen_tests, int f_miller_rabin_test,
3581 int verbose_level)
3582{
3583 int f_v = (verbose_level >= 1);
3584 int f_vv = (verbose_level >= 2);
3587 int i = 0;
3588
3589 if (f_v) {
3590 cout << "cryptography_domain::find_probable_prime_above" << endl;
3591 }
3592 one.create(1, __FILE__, __LINE__);
3593 while (TRUE) {
3594 if (f_vv) {
3595 cout << "considering " << a << endl;
3596 }
3597 if (!miller_rabin_test(a, verbose_level - 2)) {
3598 if (f_vv) {
3599 cout << "is not prime because of Miller Rabin" << endl;
3600 }
3601 goto loop;
3602 }
3604 nb_solovay_strassen_tests, verbose_level - 2)) {
3605 if (f_vv) {
3606 cout << "may be prime" << endl;
3607 }
3608 break;
3609 }
3610 else {
3611 if (f_vv) {
3612 cout << "is not prime because of "
3613 "Solovay Strassen" << endl;
3614 }
3615 }
3616loop:
3617 D.add(a, one, b);
3618 b.assign_to(a);
3619 i++;
3620 }
3621 if (f_v) {
3622 cout << "cryptography_domain::find_probable_prime_above: probable prime: "
3623 << a << " (found after " << i << " tests)" << endl;
3624 }
3625}
3626
3628 ring_theory::longinteger_object &n, int nb_tests, int verbose_level)
3629{
3630 int f_v = (verbose_level >= 1);
3631 int i;
3632
3633 if (f_v) {
3634 cout << "cryptography_domain::solovay_strassen_is_prime for "
3635 << n << " with " << nb_tests << " tests:" << endl;
3636 }
3637 for (i = 0; i < nb_tests; i++) {
3639 n, verbose_level - 2)) {
3640 if (f_v) {
3641 cout << "is not prime after "
3642 << i + 1 << " tests" << endl;
3643 }
3644 return FALSE;
3645 }
3646 }
3647 return TRUE;
3648}
3649
3651 ring_theory::longinteger_object &n, int verbose_level)
3652{
3653 int f_v = (verbose_level >= 1);
3654 int f_vv = (verbose_level >= 2);
3656 ring_theory::longinteger_object a, one, b, m_one, n_minus_one;
3657 int r;
3658
3659 if (f_v) {
3660 cout << "cryptography_domain::solovay_strassen_is_prime_single_test" << endl;
3661 }
3662 one.create(1, __FILE__, __LINE__);
3663 m_one.create(-1, __FILE__, __LINE__);
3664 D.add(n, m_one, n_minus_one);
3665 D.random_number_less_than_n(n_minus_one, a);
3666 D.add(a, one, b);
3667 b.assign_to(a);
3668 if (f_vv) {
3669 cout << "cryptography_domain::solovay_strassen_is_prime "
3670 "choosing integer " << a
3671 << " less than " << n << endl;
3672 }
3673
3674 r = solovay_strassen_test(n, a, verbose_level);
3675 return r;
3676
3677}
3678
3680 ring_theory::longinteger_object &P, int nb_times,
3681 int verbose_level)
3682// returns TRUE is the test is conclusive, i.e. if the number is not prime.
3683{
3684 int f_v = (verbose_level >= 1);
3686 ring_theory::longinteger_object A, B, one, minus_two, n_minus_two;
3687 int i, ret;
3688
3689 if (f_v) {
3690 cout << "cryptography_domain::fermat_test_iterated_with_latex_key" << endl;
3691 }
3692 one.create(1, __FILE__, __LINE__);
3693 minus_two.create(-2, __FILE__, __LINE__);
3694
3695 D.add(P, minus_two, n_minus_two);
3696
3697 ost << "We will do " << nb_times << " Fermat tests for $" << P << "$:\\\\" << endl;
3698
3699 ost << "\\begin{enumerate}[(1)]" << endl;
3700 for (i = 0; i < nb_times; i++) {
3701
3702
3703 ost << "\\item" << endl;
3704 ost << "Fermat test no " << i + 1 << ":\\\\" << endl;
3705
3706 // choose a random integer a with 1 <= a < n - 1
3707 D.random_number_less_than_n(n_minus_two, A);
3708 D.add(A, one, B);
3709 B.assign_to(A);
3710
3711
3712 ost << "Choosing base $" << A << ".$\\\\" << endl;
3713
3715 P, A,
3716 verbose_level)) {
3717 // test applies, the number is not prime
3718 break;
3719 }
3720
3721 }
3722 ost << "\\end{enumerate}" << endl;
3723 if (i == nb_times) {
3724 //ost << "Fermat: The number $" << P << "$ is probably prime. Fermat test is inconclusive.\\\\" << endl;
3725 ret = FALSE;
3726 }
3727 else {
3728 //ost << "Fermat: The number $" << P << "$ is not prime.\\\\" << endl;
3729 ret = TRUE;
3730 }
3731 if (f_v) {
3732 cout << "cryptography_domain::fermat_test_iterated_with_latex_key done" << endl;
3733 }
3734 return ret;
3735}
3736
3739 int verbose_level)
3740{
3741 int f_v = (verbose_level >= 1);
3742 int f_vv = (verbose_level >= 2);
3744 ring_theory::longinteger_object b, one, m_one, n2, n_minus_one;
3745
3746 if (f_v) {
3747 cout << "cryptography_domain::fermat_test_with_latex_key" << endl;
3748 }
3749 one.create(1, __FILE__, __LINE__);
3750 m_one.create(-1, __FILE__, __LINE__);
3751 D.add(n, m_one, n_minus_one);
3752 if (f_vv) {
3753 cout << "cryptography_domain::fermat_test_with_latex_key "
3754 "a = " << a << endl;
3755 }
3756 ost << "Fermat test for $n=" << n << ",$ picking basis $a=" << a << "$\\\\" << endl;
3757 D.power_longint_mod(a, n_minus_one, n, 0 /*verbose_level - 2*/);
3758 if (f_vv) {
3759 cout << "cryptography_domain::fermat_test_with_latex_key "
3760 "a^((n-1)) = " << a << endl;
3761 }
3762 ost << "$a^{" << n_minus_one << "} \\equiv " << a << "$\\\\" << endl;
3763 if (a.is_one()) {
3764 if (f_v) {
3765 cout << "cryptography_domain::fermat_test_with_latex_key "
3766 "inconclusive" << endl;
3767 }
3768 ost << "The Fermat test is inconclusive.\\\\" << endl;
3769 return FALSE;
3770 }
3771 else {
3772 if (f_v) {
3773 cout << "cryptography_domain::fermat_test_with_latex_key "
3774 "not prime (sure)" << endl;
3775 }
3776 ost << "The number $" << n << "$ is not prime because of the Fermat test.\\\\" << endl;
3777 return TRUE;
3778 }
3779}
3780
3783 int verbose_level)
3784{
3785 int f_v = (verbose_level >= 1);
3786 int f_vv = (verbose_level >= 2);
3788 ring_theory::longinteger_object b, one, m_one, n2, n_minus_one;
3789 int x, r;
3790
3791 if (f_v) {
3792 cout << "cryptography_domain::solovay_strassen_test" << endl;
3793 }
3794 one.create(1, __FILE__, __LINE__);
3795 m_one.create(-1, __FILE__, __LINE__);
3796 D.add(n, m_one, n_minus_one);
3797 if (f_vv) {
3798 cout << "cryptography_domain::solovay_strassen_test "
3799 "a = " << a << endl;
3800 }
3801 x = D.jacobi(a, n, verbose_level - 2);
3802 if (x == 0) {
3803 if (f_v) {
3804 cout << "not prime (sure)" << endl;
3805 }
3806 return FALSE;
3807 }
3808 D.add(n, m_one, b);
3809 D.integral_division_by_int(b, 2, n2, r);
3810 if (f_vv) {
3811 cout << "cryptography_domain::solovay_strassen_test "
3812 "raising to the power " << n2 << endl;
3813 }
3814 D.power_longint_mod(a, n2, n, 0 /*verbose_level - 2*/);
3815 if (f_vv) {
3816 cout << "cryptography_domain::solovay_strassen_test "
3817 "a^((n-1)/2) = " << a << endl;
3818 }
3819 if (x == 1) {
3820 if (a.is_one()) {
3821 if (f_v) {
3822 cout << "cryptography_domain::solovay_strassen_test "
3823 "inconclusive" << endl;
3824 }
3825 return TRUE;
3826 }
3827 else {
3828 if (f_v) {
3829 cout << "cryptography_domain::solovay_strassen_test "
3830 "not prime (sure)" << endl;
3831 }
3832 return FALSE;
3833 }
3834 }
3835 if (x == -1) {
3836 if (D.compare_unsigned(a, n_minus_one) == 0) {
3837 if (f_v) {
3838 cout << "cryptography_domain::solovay_strassen_test "
3839 "inconclusive" << endl;
3840 }
3841 return TRUE;
3842 }
3843 else {
3844 if (f_v) {
3845 cout << "cryptography_domain::solovay_strassen_test "
3846 "not prime (sure)" << endl;
3847 }
3848 return FALSE;
3849 }
3850 }
3851 // we should never be here:
3852 cout << "cryptography_domain::solovay_strassen_test "
3853 "error" << endl;
3854 exit(1);
3855}
3856
3859 int verbose_level)
3860{
3861 int f_v = (verbose_level >= 1);
3862 int f_vv = (verbose_level >= 2);
3864 ring_theory::longinteger_object b, one, m_one, n2, n_minus_one;
3865 int x, r;
3866
3867 if (f_v) {
3868 cout << "cryptography_domain::solovay_strassen_test_with_latex_key" << endl;
3869 }
3870 one.create(1, __FILE__, __LINE__);
3871 m_one.create(-1, __FILE__, __LINE__);
3872 D.add(n, m_one, n_minus_one);
3873 if (f_vv) {
3874 cout << "cryptography_domain::solovay_strassen_test_with_latex_key "
3875 "a = " << a << endl;
3876 }
3877 ost << "Solovay-Strassen pseudoprime test for $n=" << n
3878 << ",$ picking basis $a=" << a << "$\\\\" << endl;
3879 x = D.jacobi(a, n, verbose_level - 2);
3880 ost << "$\\Big( \\frac{" << a
3881 << " }{ " << n << "}\\Big) = " << x << "$\\\\" << endl;
3882 if (x == 0) {
3883 if (f_v) {
3884 cout << "not prime (sure)" << endl;
3885 }
3886 return FALSE;
3887 }
3888 D.add(n, m_one, b);
3889 D.integral_division_by_int(b, 2, n2, r);
3890 if (f_vv) {
3891 cout << "cryptography_domain::solovay_strassen_test_with_latex_key "
3892 "raising to the power " << n2 << endl;
3893 }
3894 D.power_longint_mod(a, n2, n, 0 /*verbose_level - 2*/);
3895 if (f_vv) {
3896 cout << "cryptography_domain::solovay_strassen_test_with_latex_key "
3897 "a^((n-1)/2) = " << a << endl;
3898 }
3899
3900
3901 ost << "$a^{\\frac{" << n << "-1}{2}} \\equiv " << a;
3902 if (D.compare_unsigned(a, n_minus_one) == 0) {
3903 ost << " \\equiv -1";
3904 }
3905 ost << "$\\\\" << endl;
3906
3907 if (x == 1) {
3908 if (a.is_one()) {
3909 if (f_v) {
3910 cout << "cryptography_domain::solovay_strassen_test_with_latex_key "
3911 "inconclusive" << endl;
3912 }
3913 ost << "The Solovay-Strassen test is inconclusive.\\\\" << endl;
3914 return TRUE;
3915 }
3916 else {
3917 if (f_v) {
3918 cout << "cryptography_domain::solovay_strassen_test_with_latex_key "
3919 "not prime (sure)" << endl;
3920 }
3921 ost << "The number $n$ is not prime by the Solovay-Strassen test.\\\\" << endl;
3922 return FALSE;
3923 }
3924 }
3925 if (x == -1) {
3926 if (D.compare_unsigned(a, n_minus_one) == 0) {
3927 if (f_v) {
3928 cout << "cryptography_domain::solovay_strassen_test_with_latex_key "
3929 "inconclusive" << endl;
3930 }
3931 ost << "The Solovay-Strassen test is inconclusive.\\\\" << endl;
3932 return TRUE;
3933 }
3934 else {
3935 if (f_v) {
3936 cout << "cryptography_domain::solovay_strassen_test_with_latex_key "
3937 "not prime (sure)" << endl;
3938 }
3939 ost << "The number $n$ is not prime by the Solovay-Strassen test.\\\\" << endl;
3940 return FALSE;
3941 }
3942 }
3943 // we should never be here:
3944 cout << "cryptography_domain::solovay_strassen_test_with_latex_key "
3945 "error" << endl;
3946 exit(1);
3947}
3948
3950 ring_theory::longinteger_object &P, int nb_times,
3951 int verbose_level)
3952// returns TRUE is the test is conclusive, i.e. if the number is not prime.
3953{
3954 int f_v = (verbose_level >= 1);
3955 //int f_vv = (verbose_level >= 2);
3957 ring_theory::longinteger_object A, B, one, m_one, m_two, P_minus_one, P_minus_two;
3958 int i, ret;
3959
3960 if (f_v) {
3961 cout << "cryptography_domain::solovay_strassen_test_iterated_with_latex_key" << endl;
3962 }
3963
3964 ost << "We will do " << nb_times << " Solovay-Strassen "
3965 "tests for $" << P << "$:\\\\" << endl;
3966
3967 one.create(1, __FILE__, __LINE__);
3968 m_one.create(-1, __FILE__, __LINE__);
3969 m_two.create(-2, __FILE__, __LINE__);
3970 D.add(P, m_one, P_minus_one);
3971 D.add(P, m_two, P_minus_two);
3972
3973 ost << "\\begin{enumerate}[(1)]" << endl;
3974
3975
3976 for (i = 0; i < nb_times; i++) {
3977
3978
3979 ost << "\\item" << endl;
3980 ost << "Solovay-Strassen test no " << i + 1 << ":\\\\" << endl;
3981
3982 // choose a random integer a with 1 <= a < n - 1
3983 D.random_number_less_than_n(P_minus_two, A);
3984 D.add(A, one, B);
3985 B.assign_to(A);
3986
3987
3988 ost << "Choosing base $" << A << ".$\\\\" << endl;
3989
3991 P, A,
3992 verbose_level)) {
3993 // test applies, the number is not prime
3994 break;
3995 }
3996
3997 }
3998 ost << "\\end{enumerate}" << endl;
3999
4000 if (i == nb_times) {
4001 //ost << "Solovay-Strassen: The number $" << P << "$ is probably prime. Solovay-Strassen test is inconclusive.\\\\" << endl;
4002 ret = FALSE;
4003 }
4004 else {
4005 //ost << "Solovay-Strassen: The number $" << P << "$ is not prime.\\\\" << endl;
4006 ret = TRUE;
4007 }
4008 if (f_v) {
4009 cout << "cryptography_domain::solovay_strassen_test_iterated_with_latex_key done" << endl;
4010 }
4011 return ret;
4012}
4013
4014
4015
4016
4018 ring_theory::longinteger_object &n, int verbose_level)
4019{
4020 int f_v = (verbose_level >= 1);
4021 int f_vv = (verbose_level >= 2);
4023 ring_theory::longinteger_object a, b, c, one, m_one, n_minus_one, m, mm;
4024 int k, i;
4025
4026 if (f_v) {
4027 cout << "cryptography_domain::miller_rabin_test "
4028 "for " << n << endl;
4029 }
4030 one.create(1, __FILE__, __LINE__);
4031 m_one.create(-1, __FILE__, __LINE__);
4032 D.add(n, m_one, n_minus_one);
4033
4034#if 1
4035 // choose a random integer a with 1 <= a <= n - 1
4036 D.random_number_less_than_n(n_minus_one, a);
4037 D.add(a, one, b);
4038 b.assign_to(a);
4039#else
4040 a.create(2, __FILE__, __LINE__);
4041#endif
4042 if (f_vv) {
4043 cout << "cryptography_domain::miller_rabin_test "
4044 "choosing integer " << a << " less than " << n << endl;
4045 }
4046
4047 k = D.multiplicity_of_p(n_minus_one, m, 2);
4048 m.assign_to(mm);
4049 if (f_vv) {
4050 cout << n_minus_one << " = 2^" << k << " x " << m << endl;
4051 }
4052
4053 // compute b := a^m mod n
4054 a.assign_to(b);
4055 D.power_longint_mod(b, m, n, FALSE /* f_v */);
4056 if (f_vv) {
4057 cout << a << "^" << mm << " = " << b << endl;
4058 }
4059 if (b.is_one()) {
4060 if (f_v) {
4061 cout << "a^m = 1 mod n, so the test is inconclusive" << endl;
4062 }
4063 return TRUE;
4064 }
4065 if (D.compare_unsigned(b, n_minus_one) == 0) {
4066 if (f_v) {
4067 cout << "is minus one, so the test is inconclusive" << endl;
4068 }
4069 return TRUE;
4070 }
4071 for (i = 0; i < k; i++) {
4072 D.mult_mod(b, b, c, n, 0);
4073 if (f_vv) {
4074 cout << "b_" << i << "=" << b
4075 << " b_" << i + 1 << "=" << c << endl;
4076 }
4077 c.assign_to(b);
4078 if (D.compare_unsigned(b, n_minus_one) == 0) {
4079 if (f_v) {
4080 cout << "is minus one, so the test is inconclusive" << endl;
4081 }
4082 return TRUE;
4083 }
4084 if (D.compare_unsigned(b, one) == 0) {
4085 if (f_v) {
4086 cout << "is one, we reject as composite" << endl;
4087 }
4088 return FALSE;
4089 }
4090 //mult(b, b, c);
4091 }
4092 if (f_v) {
4093 cout << "inconclusive, we accept as probably prime" << endl;
4094 }
4095 return TRUE;
4096}
4097
4099 ring_theory::longinteger_object &n, int iteration, int verbose_level)
4100{
4101 int f_v = (verbose_level >= 1);
4102 int f_vv = (verbose_level >= 2);
4104 ring_theory::longinteger_object a, b, c, one, m_one, n_minus_one, m, mm;
4105 int k, i;
4106
4107 if (f_v) {
4108 cout << "cryptography_domain::miller_rabin_test_with_latex_key "
4109 "for " << n << " iteration=" << iteration << endl;
4110 }
4111 ost << "Miller-Rabin pseudoprime test for $n=" << n << "$\\\\" << endl;
4112 one.create(1, __FILE__, __LINE__);
4113 m_one.create(-1, __FILE__, __LINE__);
4114 D.add(n, m_one, n_minus_one);
4115
4116
4117
4118 if (iteration < 5) {
4119 int small_prime;
4121
4122 small_prime = NT.get_prime_from_table(iteration);
4123 a.create(small_prime, __FILE__, __LINE__);
4124 }
4125 else {
4126 // choose a random integer a with 1 <= a <= n - 1
4127 D.random_number_less_than_n(n_minus_one, a);
4128 D.add(a, one, b);
4129 b.assign_to(a);
4130 }
4131
4132
4133 if (f_vv) {
4134 cout << "cryptography_domain::miller_rabin_test_with_latex_key "
4135 "choosing test base a= " << a << endl;
4136 }
4137
4138 ost << "Picking test base $a=" << a << "$\\\\" << endl;
4139
4140
4141 // do a Fermat test:
4142 a.assign_to(b);
4143 D.power_longint_mod(b, n_minus_one, n, FALSE /* f_v */);
4144 if (f_vv) {
4145 cout << a << "^{n-1} = " << b << endl;
4146 }
4147
4148 ost << "$a^{n-1} = a^{" << n_minus_one << "}=" << b << "$\\\\" << endl;
4149
4150 if (!b.is_one()) {
4151 if (f_v) {
4152 cout << "a^{n-1} != 1 mod n, so the number is not prime by Fermat" << endl;
4153 }
4154 ost << "The number is not prime, a=" << a << " is a Fermat witness\\\\" << endl;
4155 return TRUE;
4156 }
4157 else {
4158 ost << "The number survives the Fermat test\\\\" << endl;
4159
4160 }
4161
4162
4163 k = D.multiplicity_of_p(n_minus_one, m, 2);
4164 m.assign_to(mm);
4165 if (f_vv) {
4166 cout << n_minus_one << " = 2^" << k << " x " << m << endl;
4167 }
4168 ost << "$n-1=2^s \\cdot m = 2^{" << k << "} \\cdot " << m << "$\\\\" << endl;
4169
4170
4171
4172 // compute b := a^m mod n
4173 a.assign_to(b);
4174 D.power_longint_mod(b, m, n, FALSE /* f_v */);
4175 if (f_vv) {
4176 cout << a << "^" << mm << " = " << b << endl;
4177 }
4178
4179 ost << "$b_0 = a^m = a^{" << mm << "}=" << b << "$\\\\" << endl;
4180
4181 if (b.is_one()) {
4182 if (f_v) {
4183 cout << "a^m = 1 mod n, so the test is inconclusive" << endl;
4184 }
4185 ost << "The Miller-Rabin test is inconclusive\\\\" << endl;
4186 return FALSE;
4187 }
4188 if (D.compare_unsigned(b, n_minus_one) == 0) {
4189 if (f_v) {
4190 cout << "is minus one, so the test is inconclusive" << endl;
4191 }
4192 ost << "The Miller-Rabin test is inconclusive\\\\" << endl;
4193 return FALSE;
4194 }
4195 ost << "$b_{0} = " << b << "$\\\\" << endl;
4196 for (i = 0; i < k; i++) {
4197 D.mult_mod(b, b, c, n, 0);
4198 if (f_vv) {
4199 cout << "b_" << i << "=" << b
4200 << " b_" << i + 1 << "=" << c << endl;
4201 }
4202 ost << "$b_{" << i + 1 << "} = " << c << "$\\\\" << endl;
4203 c.assign_to(b);
4204 if (D.compare_unsigned(b, n_minus_one) == 0) {
4205 if (f_v) {
4206 cout << "is minus one, so the test is inconclusive" << endl;
4207 }
4208 ost << "The Miller-Rabin test is inconclusive.\\\\" << endl;
4209 return FALSE;
4210 }
4211 if (D.compare_unsigned(b, one) == 0) {
4212 if (f_v) {
4213 cout << "is one, we reject as composite" << endl;
4214 }
4215 ost << "The number is not prime because of the Miller-Rabin test.\\\\" << endl;
4216 return TRUE;
4217 }
4218 //mult(b, b, c);
4219 }
4220 if (f_v) {
4221 cout << "inconclusive, we accept as probably prime" << endl;
4222 }
4223 ost << "The Miller-Rabin test is inconclusive.\\\\" << endl;
4224
4225 if (f_v) {
4226 cout << "cryptography_domain::miller_rabin_test_with_latex_key "
4227 "done" << endl;
4228 }
4229 return FALSE;
4230}
4231
4233 ring_theory::longinteger_object &P, int nb_times,
4234 int verbose_level)
4235// returns TRUE if the test is conclusive, i.e. if the number is not prime.
4236{
4237 int f_v = (verbose_level >= 1);
4238 int i, ret;
4239
4240 if (f_v) {
4241 cout << "cryptography_domain::miller_rabin_test_iterated_with_latex_key" << endl;
4242 }
4243
4244 ost << "Miller-Rabin test for $" << P << "$:\\\\" << endl;
4245
4246 ost << "\\begin{enumerate}[(1)]" << endl;
4247 for (i = 0; i < nb_times; i++) {
4248
4249
4250 ost << "\\item" << endl;
4251 ost << "Miller-Rabin test no " << i + 1 << ":\\\\" << endl;
4252
4254 P, i,
4255 verbose_level)) {
4256 // test applies, the number is not prime
4257 break;
4258 }
4259
4260 }
4261 ost << "\\end{enumerate}" << endl;
4262 if (i == nb_times) {
4263 //ost << "Miller Rabin: The number $" << P << "$ is probably prime. Miller Rabin test is inconclusive.\\\\" << endl;
4264 ret = FALSE;
4265 }
4266 else {
4267 //ost << "Miller Rabin: The number $" << P << "$ is not prime.\\\\" << endl;
4268 ret = TRUE;
4269 }
4270 if (f_v) {
4271 cout << "cryptography_domain::miller_rabin_test_iterated_with_latex_key done" << endl;
4272 }
4273 return ret;
4274}
4275
4278 int nb_tests_solovay_strassen,
4279 int f_miller_rabin_test, int verbose_level)
4280{
4281 int f_v = (verbose_level >= 1);
4283 int kk = (k * 3) / 10;
4285
4286 if (f_v) {
4287 cout << "cryptography_domain::get_k_bit_random_pseudoprime "
4288 "trying to get a " << k << " bit, " << kk
4289 << " decimals random pseudoprime" << endl;
4290 }
4291 a.create(10, __FILE__, __LINE__);
4292 D.power_int(a, kk);
4294 if (f_v) {
4295 cout << "choosing integer " << b << " less than " << a << endl;
4296 }
4297 D.add(a, b, n);
4298 if (f_v) {
4299 cout << "the sum is " << n << endl;
4300 }
4301
4303 nb_tests_solovay_strassen, f_miller_rabin_test,
4304 verbose_level - 1);
4305
4306}
4307
4312 int nb_bits,
4313 int nb_tests_solovay_strassen, int f_miller_rabin_test,
4314 int verbose_level)
4315{
4316 int f_v = (verbose_level >= 1);
4317 int f_vv = (verbose_level >= 2);
4319 ring_theory::longinteger_object m1, pm1, qm1, phi_n, v, g;
4320 int half_bits = nb_bits >> 1;
4321
4322 if (f_v) {
4323 cout << "cryptography_domain::RSA_setup nb_bits=" << nb_bits
4324 << " nb_tests_solovay_strassen=" << nb_tests_solovay_strassen
4325 << " f_miller_rabin_test=" << f_miller_rabin_test << endl;
4326 }
4327 m1.create(-1, __FILE__, __LINE__);
4328 get_k_bit_random_pseudoprime(p, half_bits,
4329 nb_tests_solovay_strassen,
4330 f_miller_rabin_test, verbose_level - 2);
4331 if (f_vv) {
4332 cout << "choosing p = " << p << endl;
4333 }
4334 get_k_bit_random_pseudoprime(q, half_bits,
4335 nb_tests_solovay_strassen,
4336 f_miller_rabin_test, verbose_level - 2);
4337 if (f_v) {
4338 cout << "choosing p = " << p << endl;
4339 cout << "choosing q = " << q << endl;
4340 }
4341 D.mult(p, q, n);
4342 if (f_v) {
4343 cout << "n = pq = " << n << endl;
4344 }
4345 D.add(p, m1, pm1);
4346 D.add(q, m1, qm1);
4347 D.mult(pm1, qm1, phi_n);
4348 if (f_v) {
4349 cout << "phi(n) = (p - 1)(q - 1) = "
4350 << phi_n << endl;
4351 }
4352
4353 while (TRUE) {
4355 if (f_v) {
4356 cout << "choosing integer " << a
4357 << " less than " << n << endl;
4358 }
4359 D.extended_gcd(a, phi_n, g, b, v, verbose_level - 2);
4360 if (g.is_one()) {
4361 break;
4362 }
4363 if (f_v) {
4364 cout << "non trivial gcd: " << g
4365 << " , repeating" << endl;
4366 }
4367 }
4368 if (b.sign()) {
4369 if (f_v) {
4370 cout << "making b positive" << endl;
4371 }
4372 D.add(b, phi_n, v);
4373 v.assign_to(b);
4374 }
4375 if (f_v) {
4376 cout << "the public key is (a,n) = " << a << "," << n << endl;
4377 cout << "the private key is (b,n) = " << b << "," << n << endl;
4378 }
4379}
4380
4381
4382
4383
4384}}}
4385
4386
void single_frequencies2(std::string &text, int stride, int n, int *mult)
void do_miller_rabin_text(std::string &number_text, int nb_miller_rabin, int verbose_level)
void print_on_top(std::string &text1, std::string &text2)
void do_jacobi(int jacobi_top, int jacobi_bottom, int verbose_level)
void vigenere_cipher(std::string &ptext, std::string &ctext, std::string &key)
void do_EC_discrete_log(field_theory::finite_field *F, int EC_b, int EC_c, std::string &base_pt_text, std::string &pt_text, int verbose_level)
void do_sift_smooth(int sift_smooth_from, int sift_smooth_len, std::string &sift_smooth_factor_base, int verbose_level)
void do_find_strong_pseudoprime(int nb_digits, int nb_fermat, int nb_miller_rabin, int verbose_level)
void do_EC_Koblitz_encoding(field_theory::finite_field *F, int EC_b, int EC_c, int EC_s, std::string &pt_text, std::string &EC_message, int verbose_level)
int miller_rabin_test(ring_theory::longinteger_object &n, int verbose_level)
void do_discrete_log(long int y, long int a, long int p, int verbose_level)
void do_fermat_test(int p, int nb_times, int verbose_level)
void make_affine_sequence(int a, int c, int m, int verbose_level)
void do_EC_baby_step_giant_step(field_theory::finite_field *F, int EC_b, int EC_c, std::string &EC_bsgs_G, int EC_bsgs_N, std::string &EC_bsgs_cipher_text, int verbose_level)
void all_square_roots_mod_n_by_exhaustive_search_lint(std::string &square_root_a, std::string &square_root_mod_n, std::vector< long int > &S, int verbose_level)
void NTRU_encrypt(int N, int p, field_theory::finite_field *Fq, std::string &H_coeffs, std::string &R_coeffs, std::string &Msg_coeffs, int verbose_level)
void do_RSA(long int RSA_d, long int RSA_m, int RSA_block_size, std::string &RSA_text, int verbose_level)
void decipher(std::string &ctext, std::string &ptext, std::string &guess)
void do_EC_cyclic_subgroup(field_theory::finite_field *F, int EC_b, int EC_c, std::string &pt_text, int verbose_level)
int factor_over_factor_base2(ring_theory::longinteger_object &x, std::vector< int > &primes, std::vector< int > &exponents, int verbose_level)
int solovay_strassen_is_prime_single_test(ring_theory::longinteger_object &n, int verbose_level)
void do_random(int random_nb, std::string &fname_csv, int verbose_level)
void do_power_mod(ring_theory::longinteger_object &a, ring_theory::longinteger_object &k, ring_theory::longinteger_object &n, int verbose_level)
void reduce_primes(std::vector< int > &primes, ring_theory::longinteger_object &M, int &f_found_small_factor, int &small_factor, int verbose_level)
void substition_cipher(std::string &ptext, std::string &ctext, std::string &key)
void RSA_setup(ring_theory::longinteger_object &n, ring_theory::longinteger_object &p, ring_theory::longinteger_object &q, ring_theory::longinteger_object &a, ring_theory::longinteger_object &b, int nb_bits, int nb_tests_solovay_strassen, int f_miller_rabin_test, int verbose_level)
void find_probable_prime_above(ring_theory::longinteger_object &a, int nb_solovay_strassen_tests, int f_miller_rabin_test, int verbose_level)
void Quadratic_Sieve(int factorbase, int f_mod, int mod_n, int mod_r, int x0, int n, ring_theory::longinteger_object &M, ring_theory::longinteger_object &sqrtM, std::vector< int > &primes, std::vector< int > &primes_log2, std::vector< int > &R1, std::vector< int > &R2, std::vector< int > &X, int verbose_level)
void affine_cipher(std::string &ptext, std::string &ctext, int a, int b)
int solovay_strassen_test_iterated_with_latex_key(std::ostream &ost, ring_theory::longinteger_object &P, int nb_times, int verbose_level)
int solovay_strassen_is_prime(ring_theory::longinteger_object &n, int nb_tests, int verbose_level)
void calc_roots(ring_theory::longinteger_object &M, ring_theory::longinteger_object &sqrtM, std::vector< int > &primes, std::vector< int > &R1, std::vector< int > &R2, int verbose_level)
void do_miller_rabin(int p, int nb_times, int verbose_level)
void polynomial_center_lift(std::string &A_coeffs, field_theory::finite_field *F, int verbose_level)
void print_candidates(std::string &ctext, int i, int h, int nb_candidates, int *candidates)
int solovay_strassen_test(ring_theory::longinteger_object &n, ring_theory::longinteger_object &a, int verbose_level)
void do_number_of_primitive_roots_interval(long int p_min, long int p_max, int verbose_level)
void do_inverse_mod(long int a, long int n, int verbose_level)
void calc_log2(std::vector< int > &primes, std::vector< int > &primes_log2, int verbose_level)
void do_RSA_encrypt_text(long int RSA_d, long int RSA_m, int RSA_block_size, std::string &RSA_encrypt_text, int verbose_level)
int fermat_test_with_latex_key(std::ostream &ost, ring_theory::longinteger_object &n, ring_theory::longinteger_object &a, int verbose_level)
void square_root(std::string &square_root_number, int verbose_level)
void affine_decipher(std::string &ctext, std::string &ptext, std::string &guess)
int miller_rabin_test_iterated_with_latex_key(std::ostream &ost, ring_theory::longinteger_object &P, int nb_times, int verbose_level)
void polynomial_reduce_mod_p(std::string &A_coeffs, field_theory::finite_field *F, int verbose_level)
void do_EC_baby_step_giant_step_decode(field_theory::finite_field *F, int EC_b, int EC_c, std::string &EC_bsgs_A, int EC_bsgs_N, std::string &EC_bsgs_cipher_text_T, std::string &EC_bsgs_keys, int verbose_level)
int EC_evaluate_RHS(field_theory::finite_field *F, int EC_b, int EC_c, int x)
void do_EC_points(field_theory::finite_field *F, std::string &label, int EC_b, int EC_c, int verbose_level)
void square_root_mod(std::string &square_root_number, std::string &mod_number, int verbose_level)
int fermat_test_iterated_with_latex_key(std::ostream &ost, ring_theory::longinteger_object &P, int nb_times, int verbose_level)
void vigenere_decipher(std::string &ctext, std::string &ptext, std::string &key)
int miller_rabin_test_with_latex_key(std::ostream &ost, ring_theory::longinteger_object &n, int iteration, int verbose_level)
void make_2D_plot(int *orbit, int orbit_len, int cnt, int m, int a, int c, int verbose_level)
void do_primitive_root_longinteger(ring_theory::longinteger_object &p, int verbose_level)
void do_smallest_primitive_root_interval(long int p_min, long int p_max, int verbose_level)
int factor_over_factor_base(ring_theory::longinteger_object &x, std::vector< int > &primes, std::vector< int > &factor_idx, std::vector< int > &factor_exp, int verbose_level)
void quadratic_sieve(int n, int factorbase, int x0, int verbose_level)
void do_EC_add(field_theory::finite_field *F, int EC_b, int EC_c, std::string &pt1_text, std::string &pt2_text, int verbose_level)
int solovay_strassen_test_with_latex_key(std::ostream &ost, ring_theory::longinteger_object &n, ring_theory::longinteger_object &a, int verbose_level)
void get_k_bit_random_pseudoprime(ring_theory::longinteger_object &n, int k, int nb_tests_solovay_strassen, int f_miller_rabin_test, int verbose_level)
void do_EC_multiple_of(field_theory::finite_field *F, int EC_b, int EC_c, std::string &pt_text, int n, int verbose_level)
void do_find_pseudoprime(int nb_digits, int nb_fermat, int nb_miller_rabin, int nb_solovay_strassen, int verbose_level)
a collection of functions related to sorted vectors
int int_vec_search(int *v, int len, int a, int &idx)
Definition: sorting.cpp:1094
functions related to strings and character arrays
void sieve(std::vector< int > &primes, int factorbase, int verbose_level)
void elliptic_curve_addition(field_theory::finite_field *F, int b, int c, int x1, int x2, int x3, int y1, int y2, int y3, int &z1, int &z2, int &z3, int verbose_level)
void elliptic_curve_all_point_multiples(field_theory::finite_field *F, int b, int c, int &order, int x1, int y1, int z1, std::vector< std::vector< int > > &Pts, int verbose_level)
void print_factorization(int nb_primes, int *primes, int *exponents)
int elliptic_curve_discrete_log(field_theory::finite_field *F, int b, int c, int x1, int y1, int z1, int x3, int y3, int z3, int verbose_level)
void elliptic_curve_point_multiple(field_theory::finite_field *F, int b, int c, int n, int x1, int y1, int z1, int &x3, int &y3, int &z3, int verbose_level)
int Jacobi_with_key_in_latex(std::ostream &ost, long int a, long int m, int verbose_level)
void int_matrix_write_csv(std::string &fname, int *M, int m, int n)
Definition: file_io.cpp:1300
void int_vec_write_csv(int *v, int len, std::string &fname, const char *label)
Definition: file_io.cpp:1175
void lint_matrix_write_csv(std::string &fname, long int *M, int m, int n)
Definition: file_io.cpp:1323
void head(std::ostream &ost, int f_book, int f_title, const char *title, const char *author, int f_toc, int f_landscape, int f_12pt, int f_enlarged_page, int f_pagenumbers, const char *extras_for_preamble)
domain to compute with objects of type longinteger
Definition: ring_theory.h:240
void extended_gcd(longinteger_object &a, longinteger_object &b, longinteger_object &g, longinteger_object &u, longinteger_object &v, int verbose_level)
int jacobi(longinteger_object &a, longinteger_object &m, int verbose_level)
int compare(longinteger_object &a, longinteger_object &b)
void integral_division_exact(longinteger_object &a, longinteger_object &b, longinteger_object &a_over_b)
int multiplicity_of_p(longinteger_object &a, longinteger_object &residue, int p)
void power_longint_mod(longinteger_object &a, longinteger_object &n, longinteger_object &m, int verbose_level)
void add(longinteger_object &a, longinteger_object &b, longinteger_object &c)
void integral_division_by_int(longinteger_object &a, int b, longinteger_object &q, int &r)
void mult(longinteger_object &a, longinteger_object &b, longinteger_object &c)
void random_number_with_n_decimals(longinteger_object &R, int n, int verbose_level)
void square_root(longinteger_object &a, longinteger_object &sqrt_a, int verbose_level)
void mult_mod(longinteger_object &a, longinteger_object &b, longinteger_object &c, longinteger_object &m, int verbose_level)
void random_number_less_than_n(longinteger_object &n, longinteger_object &r)
void power_int_mod(longinteger_object &a, int n, longinteger_object &m)
int compare_unsigned(longinteger_object &a, longinteger_object &b)
a class to represent arbitrary precision integers
Definition: ring_theory.h:366
void create_from_base_10_string(const char *str, int verbose_level)
void create(long int i, const char *file, int line)
domain of polynomials in one variable over a finite field
Definition: ring_theory.h:691
void add(unipoly_object a, unipoly_object b, unipoly_object &c)
void mult_mod(unipoly_object a, unipoly_object b, unipoly_object &c, unipoly_object m, int verbose_level)
void print_object(unipoly_object p, std::ostream &ost)
#define Int_vec_scan(A, B, C)
Definition: foundations.h:716
#define MINIMUM(x, y)
Definition: foundations.h:216
#define FREE_int(p)
Definition: foundations.h:640
#define Int_vec_zero(A, B)
Definition: foundations.h:713
#define Lint_vec_scan(A, B, C)
Definition: foundations.h:717
#define NEW_char(n)
Definition: foundations.h:632
#define Lint_vec_print(A, B, C)
Definition: foundations.h:686
#define NEW_int(n)
Definition: foundations.h:625
#define TRUE
Definition: foundations.h:231
#define FALSE
Definition: foundations.h:234
#define FREE_char(p)
Definition: foundations.h:646
#define NEW_lint(n)
Definition: foundations.h:628
#define Int_vec_print(A, B, C)
Definition: foundations.h:685
int sqrt_mod_involved(int a, int p, int verbose_level)
Definition: global.cpp:628
the orbiter library for the classification of combinatorial objects