LCOV - code coverage report
Current view: top level - modules/nt - prime_test.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 82 143 57.3 %
Date: 2024-05-13 05:06:06 Functions: 8 12 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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>
      38             : #include <openGPMP/nt/prime_test.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
      55             : gpmp::Basics ba;
      56             : gpmp::PrimalityTest prim;
      57             : 
      58             : // Calculates (a * b) mod m
      59        4533 : uint64_t gpmp::PrimalityTest::mod_mul(uint64_t a, uint64_t b, uint64_t m) {
      60        4533 :     uint64_t res = 0;
      61       37265 :     while (b > 0) {
      62       32732 :         if (b & 1) {
      63       18625 :             res = (res + a) % m;
      64             :         }
      65       32732 :         a = (2 * a) % m;
      66       32732 :         b >>= 1;
      67             :     }
      68        4533 :     return res;
      69             : }
      70             : 
      71             : // Calculates (a ^ b) mod m
      72         394 : uint64_t gpmp::PrimalityTest::mod_pow(uint64_t a, uint64_t b, uint64_t m) {
      73         394 :     uint64_t res = 1;
      74         394 :     a %= m;
      75        3808 :     while (b > 0) {
      76        3414 :         if (b & 1) {
      77        1112 :             res = mod_mul(res, a, m);
      78             :         }
      79        3414 :         a = mod_mul(a, a, m);
      80        3414 :         b >>= 1;
      81             :     }
      82         394 :     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             : 
     102           8 : bool gpmp::PrimalityTest::is_prime(uint64_t n) {
     103           8 :     if (n <= 1) {
     104           1 :         return false;
     105             :     }
     106             : 
     107             :     // Check from 2 to n-1
     108      532483 :     for (uint64_t iter = 2; iter < n; iter++) {
     109      532479 :         if (n % iter == 0) {
     110           3 :             return false;
     111             :         }
     112             :     }
     113           4 :     return true;
     114             : }
     115             : 
     116             : /*
     117             :  * determining if a given number is likely to be prime
     118             :  */
     119           0 : 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           0 :     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           0 :     uint64_t x = mod_pow(a, d, n);
     140             : 
     141           0 :     if (x == 1 || x == n - 1) {
     142           0 :         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           0 :     while (d != n - 1) {
     151           0 :         x = (x * x) % n;
     152           0 :         d *= 2;
     153             : 
     154           0 :         if (x == 1) {
     155           0 :             return false;
     156             :         }
     157           0 :         if (x == n - 1) {
     158           0 :             return true;
     159             :         }
     160             :     }
     161             : 
     162             :     // Return composite
     163           0 :     return false;
     164             : }
     165             : 
     166          12 : bool gpmp::PrimalityTest::witness(uint64_t n,
     167             :                                   uint64_t d,
     168             :                                   uint64_t a,
     169             :                                   uint64_t s) {
     170          12 :     uint64_t x = mod_pow(a, d, n);
     171          12 :     if (x == 1 || x == n - 1) {
     172           6 :         return false;
     173             :     }
     174           7 :     for (uint64_t r = 1; r < s; r++) {
     175           7 :         x = mod_mul(x, x, n);
     176           7 :         if (x == n - 1) {
     177           6 :             return false;
     178             :         }
     179             :     }
     180           0 :     return true;
     181             : }
     182             : 
     183           7 : bool gpmp::PrimalityTest::miller_rabin_prime(uint64_t n, uint64_t iters = 10) {
     184           7 :     if (n < 2) {
     185           0 :         return false;
     186             :     }
     187           7 :     if (n == 2 || n == 3) {
     188           1 :         return true;
     189             :     }
     190           6 :     if (n % 2 == 0) {
     191           3 :         return false;
     192             :     }
     193           3 :     uint64_t d = n - 1, s = 0;
     194           9 :     while (d % 2 == 0) {
     195           6 :         d /= 2;
     196           6 :         s++;
     197             :     }
     198          15 :     for (uint64_t i = 0; i < iters; i++) {
     199          12 :         uint64_t a = rand() % (n - 3) + 2;
     200          12 :         if (witness(n, d, a, s)) {
     201           0 :             return false;
     202             :         }
     203             :     }
     204           3 :     return true;
     205             : }
     206             : 
     207           0 : void gpmp::PrimalityTest::miller_rabin(uint64_t iters,
     208             :                                        uint64_t min_val,
     209             :                                        uint64_t max_val) {
     210           0 :     std::cout << "Primes between " << min_val << " and " << max_val
     211           0 :               << 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           0 :     for (; min_val < max_val; min_val++) {
     218             :         // while (min_val < max_val) {
     219           0 :         if (miller_rabin_prime(min_val, iters)) {
     220           0 :             std::cout << min_val << " ";
     221             :         }
     222             :     }
     223           0 :     std::cout << "\n";
     224           0 : }
     225             : 
     226           0 : bool gpmp::PrimalityTest::AKS(uint64_t n) {
     227             :     // Check if n is a perfect power
     228           0 :     for (uint64_t b = 2; b <= std::sqrt(n); b++) {
     229           0 :         uint64_t a = std::round(std::pow(n, 1.0 / b));
     230             :         // if (std::pow(a, b) == n) {
     231           0 :         if (std::pow(a, b) < std::numeric_limits<double>::epsilon()) {
     232           0 :             return false;
     233             :         }
     234             :     }
     235             : 
     236             :     // Find the smallest r such that ord_r(n) > log2(n)^2
     237           0 :     uint64_t r = 2;
     238           0 :     while (r < n) {
     239           0 :         bool is_coprime = true;
     240           0 :         for (uint64_t i = 2; i <= std::sqrt(r); i++) {
     241           0 :             if (r % i == 0 && n % i == 0) {
     242           0 :                 is_coprime = false;
     243           0 :                 break;
     244             :             }
     245             :         }
     246           0 :         if (is_coprime) {
     247           0 :             uint64_t t = 1;
     248           0 :             for (uint64_t i = 0; i < std::floor(2 * std::log2(n)); i++) {
     249           0 :                 t = (t * r) % n;
     250             :             }
     251           0 :             if (t == 1) {
     252           0 :                 r++;
     253           0 :                 continue;
     254             :             }
     255           0 :             bool is_prime = true;
     256           0 :             for (uint64_t i = 0; i < std::floor(std::log2(n)); i++) {
     257           0 :                 t = (t * t) % n;
     258           0 :                 if (t == 1) {
     259           0 :                     is_prime = false;
     260           0 :                     break;
     261             :                 }
     262             :             }
     263           0 :             if (is_prime) {
     264           0 :                 return true;
     265             :             }
     266             :         }
     267           0 :         r++;
     268             :     }
     269           0 :     return false;
     270             : }
     271             : 
     272             : /*
     273             :  * another algorithm capable of finding primes
     274             :  */
     275          58 : uint64_t gpmp::PrimalityTest::jacobian_number(uint64_t a, uint64_t n) {
     276          58 :     if (!a)
     277           0 :         return 0; // (0/n) = 0
     278             : 
     279          58 :     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          58 :     if (a == 1)
     288          25 :         return ans; // (1/n) = 1
     289             : 
     290         102 :     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         116 :         while (a % 2 == 0) {
     298          47 :             a = a / 2;
     299          47 :             if (n % 8 == 3 || n % 8 == 5)
     300          33 :                 ans = -ans;
     301             :         }
     302          69 :         std::swap(a, n);
     303             : 
     304          69 :         if (a % 4 == 3 && n % 4 == 3)
     305          12 :             ans = -ans;
     306             : 
     307          69 :         a = a % n;
     308             : 
     309          69 :         if (a > n / 2)
     310          10 :             a = a - n;
     311             :     }
     312             : 
     313          33 :     if (n == 1)
     314          30 :         return ans;
     315             : 
     316           3 :     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           6 : bool gpmp::PrimalityTest::solovoy_strassen(uint64_t p, uint64_t iters) {
     326           6 :     if (p < 2)
     327           0 :         return false;
     328             : 
     329           6 :     if (p != 2 && p % 2 == 0)
     330           1 :         return false;
     331             : 
     332          59 :     for (uint64_t i = 0; i < iters; i++) {
     333             :         // Generate a random number a
     334          58 :         uint64_t a = rand() % (p - 1) + 1;
     335          58 :         uint64_t jacobian = (p + jacobian_number(a, p)) % p;
     336          58 :         uint64_t mod = mod_pow(a, (p - 1) / 2, p);
     337             : 
     338          58 :         if (!jacobian || mod != jacobian)
     339           4 :             return false;
     340             :     }
     341           1 :     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             :  */
     349           2 : bool gpmp::PrimalityTest::carmichael_num(uint64_t n) {
     350         562 :     for (uint64_t b = 2; b < n; b++) {
     351             :         // If "b" is relatively prime to n
     352         561 :         if (ba.op_gcd(b, n) == 1)
     353             :             // And pow(b, n-1)%n is not 1, return false.
     354         320 :             if (mod_pow(b, n - 1, n) != 1)
     355           1 :                 return false;
     356             :     }
     357           1 :     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           0 : uint64_t gpmp::PrimalityTest::ETF(uint64_t n) {
     409           0 :     uint64_t result = 1;
     410             : 
     411           0 :     for (uint64_t index = 2; uint64_t(index) < n; index++) {
     412           0 :         if (ba.op_gcd(index, n) == 1) {
     413           0 :             result++;
     414             :         }
     415             :     }
     416             : 
     417           0 :     return result;
     418             : }

Generated by: LCOV version 1.14