openGPMP
Open Source Mathematics Package
prime_test.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  *
3  * Project
4  * _____ _____ __ __ _____
5  * / ____| __ \| \/ | __ \
6  * ___ _ __ ___ _ __ | | __| |__) | \ / | |__) |
7  * / _ \| '_ \ / _ \ '_ \| | |_ | ___/| |\/| | ___/
8  *| (_) | |_) | __/ | | | |__| | | | | | | |
9  * \___/| .__/ \___|_| |_|\_____|_| |_| |_|_|
10  * | |
11  * |_|
12  *
13  * Copyright (C) Akiel Aries, <akiel@akiel.org>, et al.
14  *
15  * This software is licensed as described in the file LICENSE, which
16  * you should have received as part of this distribution. The terms
17  * among other details are referenced in the official documentation
18  * seen here : https://akielaries.github.io/openGPMP/ along with
19  * important files seen in this project.
20  *
21  * You may opt to use, copy, modify, merge, publish, distribute
22  * and/or sell copies of the Software, and permit persons to whom
23  * the Software is furnished to do so, under the terms of the
24  * LICENSE file.
25  *
26  *
27  *
28  * This software is distributed on an AS IS basis, WITHOUT
29  * WARRANTY OF ANY KIND, either express or implied.
30  *
31  ************************************************************************/
32 
33 /*
34  * Some core concepts seen in Number Theory primarily prime number
35  * based equations, formulas, algorithms.
36  */
37 #include <openGPMP/arithmetic.hpp>
39 
40 #include <algorithm>
41 #include <cmath>
42 #include <cstdlib>
43 
44 #ifdef __APPLE__
45 #include <stdlib.h>
46 #endif
47 
48 #include <cstring>
49 #include <iostream>
50 #include <random>
51 #include <stdio.h>
52 #include <string>
53 
54 // declare Basics and Primality class objects
57 
58 // Calculates (a * b) mod m
59 uint64_t gpmp::PrimalityTest::mod_mul(uint64_t a, uint64_t b, uint64_t m) {
60  uint64_t res = 0;
61  while (b > 0) {
62  if (b & 1) {
63  res = (res + a) % m;
64  }
65  a = (2 * a) % m;
66  b >>= 1;
67  }
68  return res;
69 }
70 
71 // Calculates (a ^ b) mod m
72 uint64_t gpmp::PrimalityTest::mod_pow(uint64_t a, uint64_t b, uint64_t m) {
73  uint64_t res = 1;
74  a %= m;
75  while (b > 0) {
76  if (b & 1) {
77  res = mod_mul(res, a, m);
78  }
79  a = mod_mul(a, a, m);
80  b >>= 1;
81  }
82  return res;
83 }
84 
85 /*
86 uint64_t gpmp::PrimalityTest::mod_pow(uint64_t base, uint64_t exponent,
87  uint64_t mod) {
88  uint64_t x = 1;
89  uint64_t y = base;
90 
91  while (exponent > 0) {
92  if (exponent & 1) {
93  x = (x * y) % mod;
94  }
95  exponent = exponent >> 1;
96  y = (y * y) % mod;
97  }
98 
99  return x;
100 }*/
101 
103  if (n <= 1) {
104  return false;
105  }
106 
107  // Check from 2 to n-1
108  for (uint64_t iter = 2; iter < n; iter++) {
109  if (n % iter == 0) {
110  return false;
111  }
112  }
113  return true;
114 }
115 
116 /*
117  * determining if a given number is likely to be prime
118  */
119 bool gpmp::PrimalityTest::compute_miller_rabin(uint64_t d, uint64_t n) {
120  // Pick a random number in [2..n-2] Corner cases make sure that n
121  // > 4
122 
123 #ifdef __APPLE__
124  std::random_device rd;
125  std::mt19937 gen(rd());
126  std::uniform_int_distribution<uint64_t> dist(2, n - 3);
127  uint64_t a = dist(gen);
128 #else
129  uint64_t a = 2 + rand() % (n - 4);
130 #endif
131  /*
132  std::random_device rd;
133  std::mt19937_64 gen(rd());
134  std::uniform_int_distribution<uint64_t> dis(2, n - 4);
135  uint64_t a = dis(gen);
136  */
137 
138  // Compute a^d % n
139  uint64_t x = mod_pow(a, d, n);
140 
141  if (x == 1 || x == n - 1) {
142  return true;
143  }
144 
145  // Keep squaring x while one of the following doesn't
146  // happen
147  // (I) d does not reach n-1
148  // (II) (x^2) % n is not 1
149  // (III) (x^2) % n is not n-1
150  while (d != n - 1) {
151  x = (x * x) % n;
152  d *= 2;
153 
154  if (x == 1) {
155  return false;
156  }
157  if (x == n - 1) {
158  return true;
159  }
160  }
161 
162  // Return composite
163  return false;
164 }
165 
167  uint64_t d,
168  uint64_t a,
169  uint64_t s) {
170  uint64_t x = mod_pow(a, d, n);
171  if (x == 1 || x == n - 1) {
172  return false;
173  }
174  for (uint64_t r = 1; r < s; r++) {
175  x = mod_mul(x, x, n);
176  if (x == n - 1) {
177  return false;
178  }
179  }
180  return true;
181 }
182 
183 bool gpmp::PrimalityTest::miller_rabin_prime(uint64_t n, uint64_t iters = 10) {
184  if (n < 2) {
185  return false;
186  }
187  if (n == 2 || n == 3) {
188  return true;
189  }
190  if (n % 2 == 0) {
191  return false;
192  }
193  uint64_t d = n - 1, s = 0;
194  while (d % 2 == 0) {
195  d /= 2;
196  s++;
197  }
198  for (uint64_t i = 0; i < iters; i++) {
199  uint64_t a = rand() % (n - 3) + 2;
200  if (witness(n, d, a, s)) {
201  return false;
202  }
203  }
204  return true;
205 }
206 
208  uint64_t min_val,
209  uint64_t max_val) {
210  std::cout << "Primes between " << min_val << " and " << max_val
211  << std::endl;
212  // int d = iters - 1;
213  // int min_val = minimum;
214  // int max_val = maximum;
215 
216  // traverse from the min to max
217  for (; min_val < max_val; min_val++) {
218  // while (min_val < max_val) {
219  if (miller_rabin_prime(min_val, iters)) {
220  std::cout << min_val << " ";
221  }
222  }
223  std::cout << "\n";
224 }
225 
226 bool gpmp::PrimalityTest::AKS(uint64_t n) {
227  // Check if n is a perfect power
228  for (uint64_t b = 2; b <= std::sqrt(n); b++) {
229  uint64_t a = std::round(std::pow(n, 1.0 / b));
230  // if (std::pow(a, b) == n) {
231  if (std::pow(a, b) < std::numeric_limits<double>::epsilon()) {
232  return false;
233  }
234  }
235 
236  // Find the smallest r such that ord_r(n) > log2(n)^2
237  uint64_t r = 2;
238  while (r < n) {
239  bool is_coprime = true;
240  for (uint64_t i = 2; i <= std::sqrt(r); i++) {
241  if (r % i == 0 && n % i == 0) {
242  is_coprime = false;
243  break;
244  }
245  }
246  if (is_coprime) {
247  uint64_t t = 1;
248  for (uint64_t i = 0; i < std::floor(2 * std::log2(n)); i++) {
249  t = (t * r) % n;
250  }
251  if (t == 1) {
252  r++;
253  continue;
254  }
255  bool is_prime = true;
256  for (uint64_t i = 0; i < std::floor(std::log2(n)); i++) {
257  t = (t * t) % n;
258  if (t == 1) {
259  is_prime = false;
260  break;
261  }
262  }
263  if (is_prime) {
264  return true;
265  }
266  }
267  r++;
268  }
269  return false;
270 }
271 
272 /*
273  * another algorithm capable of finding primes
274  */
275 uint64_t gpmp::PrimalityTest::jacobian_number(uint64_t a, uint64_t n) {
276  if (!a)
277  return 0; // (0/n) = 0
278 
279  uint64_t ans = 1;
280 
281  /*if (a < 0) {
282  a = -a; // (a/n) = (-a/n)*(-1/n)
283  if (n % 4 == 3)
284  ans = -ans; // (-1/n) = -1 if n = 3 (mod 4)
285  }*/
286 
287  if (a == 1)
288  return ans; // (1/n) = 1
289 
290  while (a) {
291  /*if (a < 0) {
292  a = -a; // (a/n) = (-a/n)*(-1/n)
293  if (n % 4 == 3)
294  ans = -ans; // (-1/n) = -1 if n = 3 (mod 4)
295  }*/
296 
297  while (a % 2 == 0) {
298  a = a / 2;
299  if (n % 8 == 3 || n % 8 == 5)
300  ans = -ans;
301  }
302  std::swap(a, n);
303 
304  if (a % 4 == 3 && n % 4 == 3)
305  ans = -ans;
306 
307  a = a % n;
308 
309  if (a > n / 2)
310  a = a - n;
311  }
312 
313  if (n == 1)
314  return ans;
315 
316  return 0;
317 }
318 
319 /*
320  * primality test determining if a number is composite or probably
321  * prime.
322  *
323  * a^(p-1)/2 = (a/p) (mod p)
324  */
325 bool gpmp::PrimalityTest::solovoy_strassen(uint64_t p, uint64_t iters) {
326  if (p < 2)
327  return false;
328 
329  if (p != 2 && p % 2 == 0)
330  return false;
331 
332  for (uint64_t i = 0; i < iters; i++) {
333  // Generate a random number a
334  uint64_t a = rand() % (p - 1) + 1;
335  uint64_t jacobian = (p + jacobian_number(a, p)) % p;
336  uint64_t mod = mod_pow(a, (p - 1) / 2, p);
337 
338  if (!jacobian || mod != jacobian)
339  return false;
340  }
341  return true;
342 }
343 
344 /*
345  * Absolute Fermat Pseudoprimes referred to as Carmichael Numbers
346  * are composite integers satisfying the congruence forumla below
347  * b^n - 1 = b (mod n)
348  */
350  for (uint64_t b = 2; b < n; b++) {
351  // If "b" is relatively prime to n
352  if (ba.op_gcd(b, n) == 1)
353  // And pow(b, n-1)%n is not 1, return false.
354  if (mod_pow(b, n - 1, n) != 1)
355  return false;
356  }
357  return true;
358 }
359 
360 /*
361  * since this module deals with a great deal of number theory and
362  * various logical arithmetic operations, the greek algorithm sieve of
363  * Eratosthenes is able to capture all prime numbers to any given
364  * limit
365  */
366 /*
367 void gpmp::PrimalityTest::sieve_of_eratosthenes(uint64_t n) {
368  // Create a boolean array "prime[0..n]" and initialize
369  // all entries it as true. A value in prime[i] will
370  // finally be false if i is Not a prime, else true.
371  bool prime[n + 1];
372  memset(prime, true, sizeof(prime));
373 
374  for (uint64_t p = 2; p * p <= n; p++) {
375  // If prime[p] is not changed, then it is a prime
376  if (prime[p] == true) {
377  // Update all multiples of p greater than or
378  // equal to the square of it numbers which are
379  // multiple of p and are less than p^2 are
380  // already been marked.
381  for (uint64_t i = p * p; i <= n; i += p)
382  prime[i] = false;
383  }
384  }
385 
386  // Print all prime numbers
387  for (uint64_t p = 2; p <= n; p++) {
388  if (prime[p]) {
389  std::cout << p << " " << std::endl;
390  }
391  }
392 }*/
393 
394 /*
395  * Euler's Totient Function counts the positive numbers up until a
396  * given integer
397  *
398  * Definition: For any positive integer n, Φ(n) is the number of all
399  * positive integers less than or equal to n that are relatively prime
400  * to n.
401  *
402  * Example: Φ(1) = 1
403  * Φ(2) = 1
404  * Φ(3) = 2
405  * Φ(4) = 2
406  * Φ(5) = 4
407  */
408 uint64_t gpmp::PrimalityTest::ETF(uint64_t n) {
409  uint64_t result = 1;
410 
411  for (uint64_t index = 2; uint64_t(index) < n; index++) {
412  if (ba.op_gcd(index, n) == 1) {
413  result++;
414  }
415  }
416 
417  return result;
418 }
User API for openGPMP ARITHMETIC MODULE.
Arithmetic Operations
Definition: arithmetic.hpp:101
int64_t op_gcd(int64_t x, int64_t y)
Find Greatest Common Divisor of 2 integers.
Definition: arith.cpp:50
bool miller_rabin_prime(uint64_t n, uint64_t iters)
Modified primes algorithm.
Definition: prime_test.cpp:183
uint64_t jacobian_number(uint64_t a, uint64_t n)
Definition: prime_test.cpp:275
uint64_t mod_mul(uint64_t a, uint64_t b, uint64_t m)
Definition: prime_test.cpp:59
uint64_t ETF(uint64_t n)
Definition: prime_test.cpp:408
bool carmichael_num(uint64_t n)
Definition: prime_test.cpp:349
bool witness(uint64_t n, uint64_t d, uint64_t a, uint64_t s)
Definition: prime_test.cpp:166
void miller_rabin(uint64_t iters, uint64_t min_val, uint64_t max_val)
Miller-Rabin driver, prints values that satisfy conditions.
Definition: prime_test.cpp:207
uint64_t mod_pow(uint64_t a, uint64_t b, uint64_t m)
Definition: prime_test.cpp:72
bool is_prime(uint64_t n)
Determine if an integer is prime.
Definition: prime_test.cpp:102
bool compute_miller_rabin(uint64_t d, uint64_t n)
Algorithm determining liklihood a number is prime.
Definition: prime_test.cpp:119
bool solovoy_strassen(uint64_t p, uint64_t iters)
Definition: prime_test.cpp:325
bool AKS(uint64_t n)
Definition: prime_test.cpp:226
gpmp::PrimalityTest prim
Definition: prime_test.cpp:56
gpmp::Basics ba
Definition: prime_test.cpp:55