https://github.com/cslarsen/miller-rabin/blob/master/miller-rabin.cpp
/*
* The Miller-Rabin primality test
*
* Written by Christian Stigen Larsen, 2012-01-10
* http://csl.sublevel3.org
*
* Distributed under the modified BSD license
*
* NOTE: I implemented this probabilistic algorithm purely as a recreational
* challenge. The code has big room for improvements, but it does work
* as advertised.
*/
#include <stdlib.h>
// rand
#include <stdint.h>
// uint64_t
#include "miller-rabin.h"
/*
* Which PRNG function to use; libc rand() by default
*/
static
int
(
*
rand_func
)(
void
)
=
rand
;
/*
* Maximum number that rand_func can return.
*/
static
int
rand_max
=
RAND_MAX
;
/*
* Fast calculation of `a^x mod n´ by using right-to-left
* binary modular exponentiation.
*
* This algorithm is taken from Bruce Schneier's book
* APPLIED CRYPTOGRAPHY.
*
* See http://en.wikipedia.org/wiki/Modular_exponentiation
*/
static
uint64_t
pow_mod
(
uint64_t
a
,
uint64_t
x
,
uint64_t
n
)
{
/*
* Note that this code is sensitive to overflowing for testing
* of large prime numbers. The `a*r´ and `a*a´ operations can
* overflow. One easy way of solving this is to use 128-bit
* precision for calculating a*b % n, since the mod operator
* should always get us back to 64bits again.
*
* You can either use GCC's built-in __int128_t or use
*
* typedef unsigned int uint128_t __attribute__((mode(TI)));
*
* to create a 128-bit datatype.
*/
uint64_t
r
=
1
;
while
(
x
)
{
if
(
(
x
&
1
)
==
1
)
//r = (__int128_t)a*r % n; // Slow
r
=
a
*
r
%
n
;
x
>>=
1
;
//a = (__int128_t)a*a % n; // SLow
a
=
a
*
a
%
n
;
}
return
r
;
}
/*
* Return an integer between a and b.
*
* Note that we use rand() here, meaning that all its pathological cases
* will apply here as well --- i.e., it's slow and not very random --- but
* should suffice.
*
*/
static
uint64_t
rand_between
(
uint64_t
a
,
uint64_t
b
)
{
// Assume rand_func() is 32 bits
uint64_t
r
=
(
static_cast
<
uint64_t
>
(
rand_func
())
<<
32
)
|
rand_func
();
return
a
+
(
uint64_t
)((
double
)(
b
-
a
+
1
)
*
r
/
(
UINT64_MAX
+
1.0
));
}
/*
* The Miller-Rabin probabilistic primality test.
*
* Returns true if ``n´´ is PROBABLY prime, false if it's composite.
* The parameter ``k´´ is the accuracy.
*
* The running time should be somewhere around O(k log_3 n).
*
*/
bool
isprime
(
uint64_t
n
,
int
k
)
{
// Must have ODD n greater than THREE
if
(
n
==
2
||
n
==
3
)
return
true
;
if
(
n
<=
1
||
!
(
n
&
1
)
)
return
false
;
// Write n-1 as d*2^s by factoring powers of 2 from n-1
int
s
=
0
;
for
(
uint64_t
m
=
n
-
1
;
!
(
m
&
1
);
++
s
,
m
>>=
1
)
;
// loop
uint64_t
d
=
(
n
-
1
)
/
(
1
<<
s
);
for
(
int
i
=
0
;
i
<
k
;
++
i
)
{
uint64_t
a
=
rand_between
(
2
,
n
-
2
);
uint64_t
x
=
pow_mod
(
a
,
d
,
n
);
if
(
x
==
1
||
x
==
n
-
1
)
continue
;
for
(
int
r
=
1
;
r
<=
s
-
1
;
++
r
)
{
x
=
pow_mod
(
x
,
2
,
n
);
if
(
x
==
1
)
return
false
;
if
(
x
==
n
-
1
)
goto
LOOP
;
}
return
false
;
LOOP:
continue
;
}
// n is *probably* prime
return
true
;
}
/*
* Set which rand function to use.
*
* If passed a NULL parameter, it will revert back to the default libc
* rand().
*/
void
setrand
(
int
(
*
pf
)(
void
),
const
int
rmax
)
{
if
(
pf
!=
NULL
)
{
rand_func
=
pf
;
rand_max
=
rmax
;
}
else
{
rand_func
=
rand
;
rand_max
=
RAND_MAX
;
}
}