#include #include #include #include #include #include #include #include "helper.c" uint64_t *dec_to_bin(uint64_t d, uint64_t *length) { uint64_t *binary_form = calloc(100, sizeof(uint64_t)); int index = 0; while (d != 0) { binary_form[index] = d % 2; d /= 2; index++; } *length = index; return binary_form; } uint64_t quick_pow(uint64_t *d_binary, uint64_t a, uint64_t n, uint64_t length) { uint64_t *powed = calloc(100, sizeof(uint64_t)); powed[0] = a; for (int i = 1; i <= length; i++) { powed[i] = (uint64_t)(((unsigned __int128)powed[i - 1] * powed[i - 1]) % n); printf("powed: %ju, index: %d; ", powed[i], (i)); } // check where in the binary are ones uint64_t multiplied = 1; for (int i = 0; i < length; i++) { if (d_binary[i] == 1) { multiplied = (uint64_t)(((unsigned __int128)multiplied * powed[i]) % n); } } printf("\nbm quick math: %ju; %ju ", multiplied, n); free(powed); return multiplied; } bool prime_test(uint64_t n, int a) { printf("\n\nprime test: %ju\n", n); // Miller Rabin prime test // choose a base: a, which should be a prime so that (n, a) = 1 // then do 2 rounds of tests provided the first one did not fail // 1: a^d =k 1 mod n // 2: a^(d * 2^r) =k n-1 mod n // d = n-1 / 2^S (where S means how many time did we divide the number till we reached the first odd number) // S: see above // r = {0,... S-1} uint64_t d = n - 1; uint64_t S = 0; while (d % 2 == 0) { d = d / 2; S++; } uint64_t r = S - 1; // this stores the number of elements from 0 to S-1 // round 1 // 1: a^d =k 1 mod n uint64_t length = 0; uint64_t *d_binary = dec_to_bin(d, &length); uint64_t first_qp_res = quick_pow(d_binary, a, n, length); if (first_qp_res == 1) { free(d_binary); return true; } // round 2 // 2: a^(d * 2^r) =k n-1 mod n for (int i = 0; i <= r; i++) { if (first_qp_res == n - 1) { free(d_binary); printf("true\n"); return true; } else if (first_qp_res < n - 2) { printf("first_qp_res became smaller then n!!\n"); break; } else { first_qp_res = (uint64_t)(((unsigned __int128)first_qp_res * first_qp_res) % n); } } free(d_binary); return false; } void *prime_thread_worker(void *arg) { uint64_t *result_ptr = (uint64_t *)arg; do { *result_ptr = rand64(); printf("\nGenerating a new prime number (%p). Candidate: ", result_ptr); printf("%ju", *result_ptr); printf("\n"); } while (!prime_test(*result_ptr, 2)); return NULL; } int main() { // prime_test(111, 5); // prime_test(29, 2); // prime_test(27, 2); // prime_test(17, 2); // prime_test(661, 2); // prime_test(18446744073709551557UL, 2); // prime_test(18446744073709551533UL, 3); uint64_t p = 0; uint64_t q = 0; srand(time(NULL)); uint64_t base = 2; pthread_t thread_p, thread_q; // for (int i = 0; i < 10; i++) { // p = rand64(); // printf("%ju", p); // prime_test(p, base); // } pthread_create(&thread_p, NULL, prime_thread_worker, &p); pthread_create(&thread_q, NULL, prime_thread_worker, &q); pthread_join(thread_p, NULL); pthread_join(thread_q, NULL); printf("\n"); unsigned __int128 n = p * q; print_uint128(n); printf("\n"); unsigned __int128 fi_n = (p - 1) * (q - 1); print_uint128(fi_n); printf("\n"); // 2. kulcsgeneralas return 0; }