Sei sulla pagina 1di 23

using

using
using
using

System;
System.Collections.Generic;
System.ComponentModel;
System.Windows.Forms;

namespace AKSPrimalityTest
{
class AKSTest
{
bool prime, rTooBig;
long[] n;
MainForm mainForm;
TextBox atb, ltb;
public bool Prime
{
get
{
return prime;
}
}
public bool RTooBig
{
get
{
return rTooBig;
}
}
long Log10(long[] n)
{
long b = lngint.BASE;
long l = (long)Math.Log10(b);
long h = (long)Math.Log10(n[n.Length - 1]);
return l * (n.Length - 2) + h;
}
long Order(long[] n, ref long[] r, ref long log10)
{
log10 = Log10(n);
long l2 = log10 * log10;
long[] one = { 1, 1 };
long[] g = null, p = null;
r = new long[2];
r[0] = 1;
r[1] = 2;
while (true)
{
g = lngint.gcd(n, r);
if (lngint.compare(g, one) == 0)
{
for (long k = l2 + 1; k <= l2 + 64; k++)
{
p = lngint.powermod(n, k, r);

if (lngint.compare(p, one) == 0)
return k;
}
}
r = lngint.add(r, one);
}
}
long Phi(List<long> primes, long m)
{
int index = primes.BinarySearch(m);
if (index >= 0)
return primes[index] - 1;
long d = m;
long phi = 1;
for (int i = 0; i < primes.Count; i++)
{
long p = primes[i];
if (d % p == 0)
{
long e = 1;
d /= p;
while (d % p == 0)
{
d /= p;
e++;
}
phi *= (m - m / p);
}
}
return phi;
}
void Sieve(long B0, ref List<long> primes)
{
// Sieve of Eratosthenes
// find all prime numbers
// less than or equal B0
bool[] sieve = new bool[B0 + 1];
long c = 3, i, inc;
sieve[2] = true;
for (i = 3; i <= B0; i++)
if (i % 2 == 1)
sieve[i] = true;
do
{
i = c * c;

inc = c + c;
while (i <= B0)
{
sieve[i] = false;
i += inc;
}
c += 2;
while (!sieve[c])
c++;
} while (c * c <= B0);
primes = new List<long>();
for (i = 2; i <= B0; i++)
if (sieve[i])
primes.Add(i);
}
public struct Coeff
{
public long[] val;
}
void polydivmod(long m, long n, long[] N, Coeff[] u, Coeff[] v,
ref Coeff[] q, ref Coeff[] r, ref long p, ref long s)
{
long j, jk, k, nk;
long[] a = null, b = null;
long[] vn = v[n].val;
r = new Coeff[m + 1];
for (j = 0; j <= m; j++)
r[j].val = slngint.copy(u[j].val);
if (m < n)
{
p = 0;
s = m;
q = new Coeff[1];
q[0].val = new long[2];
q[0].val[0] = 1;
q[0].val[1] = 0;
}
else
{
p = m - n;
s = n - 1;
q = new Coeff[p + 1];
for (k = p; k >= 0; k--)
{
nk = n + k;
a = slngint.powermod(vn, k, N);

q[k].val = slngint.mulmod(r[nk].val, a, N);


for (j = nk - 1; j >= 0; j--)
{
jk = j - k;
if (jk >= 0)
{
a = slngint.mulmod(vn, r[j].val, N);
b = slngint.mulmod(r[nk].val, v[jk].val, N);
r[j].val = slngint.submod(a, b, N);
}
else
r[j].val = slngint.mulmod(r[j].val, vn, N);
}
}
long[] z = { 1, 0 };
while (p > 0 && slngint.compare(q[p].val, z) == 0) p--;
while (s > 0 && slngint.compare(r[s].val, z) == 0) s--;
}
}
Coeff[] polymulmod(Coeff[] u, Coeff[] v, long[] n)
{
long r = u.Length - 1;
long s = v.Length - 1;
Coeff[] w = new Coeff[r + s + 1];
for (int k = 0; k <= r + s; k++)
{
long[] sum = {1, 0};
for (int i = 0; i <= k; i++)
{
if (i <= r && k - i <= s)
{
long[] p = slngint.mulmod(u[i].val, v[k - i].val, n);
sum = slngint.addmod(sum, p, n);
}
}
w[k].val = slngint.copy(sum);
}
return w;
}
Coeff[] polypowmod(Coeff[] g, Coeff[] f, long[] k, long[] n)
{
Coeff[] S = new Coeff[1];
S[0].val = new long[2];
S[0].val[0] = 1;
S[0].val[1] = 0;
if (k[0] == 1 && k[1] == 0)

return S;
long p = 0,
long[] kk =
long[] c2 =
Coeff[] G =
Coeff[] Q =
Coeff[] R =

s = 0;
slngint.copy(k);
{ 1, 2 };
new Coeff[g.Length];
null;
null;

for (int i = 0; i < g.Length; i++)


G[i].val = slngint.copy(g[i].val);
long[] km2 = slngint.mod(kk, c2);
if (km2[1] == 1)
{
S = new Coeff[g.Length];
for (int i = 0; i < g.Length; i++)
S[i].val = slngint.copy(g[i].val);
}
long[] quo = null;
long[] rem = null;
slngint.divide(kk, c2, ref quo, ref rem);
kk = slngint.copy(quo);
while (!(kk[0] == 1 && kk[1] == 0))
{
G = polymulmod(G, G, n);
polydivmod(G.Length - 1, f.Length - 1, n, G, f,
ref Q, ref R, ref p, ref s);
G = new Coeff[s + 1];
for (int i = 0; i <= s; i++)
G[i].val = R[i].val;
if (rem[1] == 1)
{
S = polymulmod(G, S, n);
polydivmod(S.Length - 1, f.Length - 1, n, S, f,
ref Q, ref R, ref p, ref s);
S = new Coeff[s + 1];
for (int i = 0; i <= s; i++)
S[i].val = R[i].val;
}
slngint.divide(kk, c2, ref quo, ref rem);
kk = slngint.copy(quo);
}
return S;
}
public void Composite(BackgroundWorker worker, DoWorkEventArgs e)

{
MillerRabin mr = new MillerRabin();
if (mr.Composite(n, 8))
{
prime = false;
return;
}
long log10
long[] r =
long[] o =
long[] a =
long ord =

= 0;
null;
{ 1, 1 };
{ 1, 2 };
Order(n, ref r, ref log10);

if (lngint.compare(r, n) > 0)
{
prime = false;
return;
}
while (lngint.compare(a, r) < 0)
{
long[] g = lngint.gcd(a, n);
if (lngint.compare(g, o) > 0 && lngint.compare(g, n) < 0)
{
prime = false;
return;
}
a = lngint.add(a, o);
}
if (r.Length == 2)
{
if (worker.CancellationPending)
e.Cancel = true;
else
{
rTooBig = false;
long A = a[1];
long R = r[1];
long B0 = 10000000;
List<long> primes = null;
Sieve(B0, ref primes);
long phi = Phi(primes, R);
long upper = (long)(Math.Sqrt(phi) * log10);
long[] z = { 1, 0 };
Coeff[] X = new Coeff[R + 1];
Coeff[] Y = new Coeff[2];
for (int i = 1; i < R; i++)
X[i].val = slngint.copy(z);
X[R].val = slngint.copy(o);

X[0].val = slngint.copy(o);
X[0].val[0] = -1;
mainForm.SetText5(upper.ToString());
for (A = 1; A <= upper; A++)
{
if (worker.CancellationPending)
e.Cancel = true;
else
{
mainForm.SetText4(A.ToString());
a[0] = 1;
a[1] = A;
long[] g = lngint.gcd(a, n);
if (g[0] == 1 && g[1] == 1)
{
Y[1].val = slngint.copy(o);
Y[0].val = slngint.copy(a);
Coeff[] P = polypowmod(Y, X, n, n);
if (!(P[0].val[0] == 1 && P[0].val[1] == A))
{
prime = false;
return;
}
}
}
}
prime = true;
return;
}
}
else
{
rTooBig = true;
return;
}
}
public AKSTest(long[] n, MainForm mainForm, TextBox atb, TextBox ltb)
{
this.n = slngint.copy(n);
this.mainForm = mainForm;
this.atb = atb;
this.ltb = ltb;
prime = false;
}
}
}

================================================================================
=============================================
================================================================================
=============================================
#include <iostream>
using namespace std;
#include <math.h>
#ifdef _M_IX86
#define
__asm
__asm
__asm
__asm

umulrem(z, x, y, m)
mov
eax, x
mul
y
div
m
mov
z, edx

\
\
\
\

#define
__asm
__asm
__asm
__asm
__asm
__asm

umuladdrem(z, x, y, a, m)
mov
eax, x \
mul
y
\
add
eax, a \
adc
edx, 0 \
div
m
\
mov
z, edx

#else
#ifdef _MSC_VER
typedef unsigned __int64
#else
typedef unsigned long long
#endif

Tu64;
Tu64;

#define umulrem(z, x, y, m)
\
{
\
z = (unsigned int)(x * (Tu64)y % m);
}

#define umuladdrem(z, x, y, a, m)
\
{
\
z = (unsigned int)((x * (Tu64)y + a) % m);
}
#endif
static bool IsPrime(unsigned int n)
{
if (n < 2) return false;
if (n < 4) return true;
if (n % 2 == 0) return false;
const unsigned int iMax = (int)sqrt(n) + 1;
unsigned int i;
for (i = 3; i <= iMax; i += 2)
if (n % i == 0)
return false;

return true;
}
static unsigned int LargestPrimeFactor(unsigned int n)
{
if (n < 2) return 1;
unsigned int r = n, p;
if (r % 2 == 0)
{
p = 2;
do { r /= 2; } while (r % 2 == 0);
}
unsigned int i;
for (i = 3; i <= r; i += 2)
{
if (r % i == 0)
{
p = i;
do { r /= i; } while (r % i == 0);
}
}
return p;
}
static unsigned int Powm(unsigned int n, unsigned int e, unsigned int m)
{
unsigned int r = 1;
unsigned int t = n % m;
unsigned int i;
for (i = e; i != 0; i /= 2)
{
if (i % 2 != 0)
{
umulrem(r, r, t, m);
}
umulrem(t, t, t, m);
}
return r;
}
static unsigned int Inv(unsigned int n, unsigned int m)
{
unsigned int a = n, b = m;
int u = 1, v = 0;
do
{
const unsigned int q = a / b;
const unsigned int t1 = a - q*b;
a = b;
b = t1;
const int t2 = u - (int)q*v;
u = v;
v = t2;
} while (b != 0);
if (a != 1) u = 0;
if (u < 0) u += m;
return u;

}
class CPolyMod
{
protected:
// (mod x^r - 1, n)
const unsigned int m_r;
const unsigned int m_n;
unsigned int m_deg;
unsigned int * mp_a;
private:
CPolyMod():m_r(0), m_n(0) { mp_a = NULL; };
public:
// default value is x
CPolyMod(unsigned int r, unsigned int n)
: m_r(r), m_n(n)
{
m_deg = 1;
mp_a = new unsigned int [2];
mp_a[0] = 0; mp_a[1] = 1;
}
CPolyMod(const CPolyMod & p)
: m_r(p.m_r), m_n(p.m_n)
{
m_deg = p.m_deg;
mp_a = new unsigned int [p.m_deg + 1];
unsigned int i;
for (i = 0; i <= p.m_deg; ++i)
mp_a[i] = p.mp_a[i];
}
virtual ~CPolyMod()
{
if (mp_a != NULL)
delete [] mp_a;
}
private:
void _polySquare()
{
const unsigned int deg = m_deg;
const unsigned int n = m_n;
const unsigned int * const p_a = mp_a;
const unsigned int degr = deg + deg;
unsigned int * const p_ar = new unsigned int [degr + 1];
unsigned int k;
for (k = 0; k <= degr; ++k)
p_ar[k] = 0;
unsigned int j;
for (j = 1; j <= deg; ++j)
{
const unsigned int x = p_a[j];
if (x != 0)
{
unsigned int i;

for (i = 0; i < j; ++i)


{
const unsigned int y = 2 * p_a[i];
unsigned int t = p_ar[j + i];
umuladdrem(t, x, y, t, n);
p_ar[j + i] = t;
}
}
}
unsigned int i;
for (i = 0; i <= deg; ++i)
{
const unsigned int x = p_a[i];
unsigned int t = p_ar[2 * i];
umuladdrem(t, x, x, t, n);
p_ar[2 * i] = t;
}
m_deg = degr;
delete [] mp_a;
mp_a = p_ar;
}
void _polyMul(const CPolyMod & p)
{
const unsigned int deg = m_deg;
const unsigned int n = m_n;
const unsigned int * const p_a = mp_a;
const unsigned int degr = deg + p.m_deg;
unsigned int * const p_ar = new unsigned int [degr + 1];
unsigned int k;
for (k = 0; k <= degr; ++k)
p_ar[k] = 0;
unsigned int j;
for (j = 0; j <= p.m_deg; ++j)
{
const unsigned int x = p.mp_a[j];
if (x != 0)
{
unsigned int i;
for (i = 0; i <= deg; ++i)
{
const unsigned int y = p_a[i];
unsigned int t = p_ar[j + i];
umuladdrem(t, x, y, t, n);
p_ar[j + i] = t;
}
}
}
m_deg = degr;
delete [] mp_a;
mp_a = p_ar;
}
void _Mod()
{
unsigned int deg = m_deg;

unsigned int * const p_a = mp_a;


while (deg >= m_r)
{
p_a[deg - m_r] += p_a[deg];
if (p_a[deg - m_r] >= m_n) p_a[deg - m_r] -= m_n;
--deg;
while (p_a[deg] == 0) --deg;
}
m_deg = deg;
}
void _Norm()
{
const unsigned int deg = m_deg;
const unsigned int n = m_n;
unsigned int * const p_a = mp_a;
if (p_a[deg] != 1)
{
const unsigned int y = Inv(p_a[deg], m_n);
unsigned int i;
for (i = 0; i <= deg; ++i)
{
unsigned int t = p_a[i];
umulrem(t, t, y, n);
p_a[i] = t;
}
}
}
public:
CPolyMod & operator = (const CPolyMod & p)
{
if (&p == this) return *this;
m_deg = p.m_deg;
delete [] mp_a;
mp_a = new unsigned int [p.m_deg + 1];
unsigned int i;
for (i = 0; i <= p.m_deg; ++i)
mp_a[i] = p.mp_a[i];
return *this;
}
int operator != (const CPolyMod & p) const
{
if (m_deg != p.m_deg)
return true;
unsigned int i;
for (i = 0; i <= m_deg; ++i)
if (mp_a[i] != p.mp_a[i])
return true;
return false;
}
CPolyMod & operator += (unsigned int i)
{
const unsigned int t = i % m_n;
mp_a[0] += t;
if (mp_a[0] >= m_n) mp_a[0] -= m_n;
return *this;

}
CPolyMod & operator -= (unsigned int i)
{
const unsigned int t = m_n - i % m_n;
mp_a[0] += t;
if (mp_a[0] >= m_n) mp_a[0] -= m_n;
return *this;
}
CPolyMod Pow(unsigned int e) const
{
unsigned int er = 1;
unsigned int j;
for (j = e; j != 1; j /= 2)
{
er = 2 * er + (j % 2);
}
CPolyMod t(*this);
unsigned int i;
for (i = er; i != 1; i /= 2)
{
t._polySquare();
t._Mod();
if (i % 2 != 0)
{
t._polyMul(*this);
t._Mod();
}
}
t._Norm();
return t;
}
};
int main(int argc, char * argv[])
{
// AKS
// n=11701, r=11699, q=5849, s=2923
// n=1000000007, r=57287, q=28643, s=14311
//
// Bernstein
// n=349, r=347, q=173, s=140
// n=1000000007, r=3623, q=1811, s=1785
unsigned int n0;
cout << "n ? ";
cin >> n0;
unsigned int n;
for (n = n0; true; n += 2)
{
bool b = false;
unsigned int q, r, s;
for (r = 3; r < n; r += 2)
{
if (IsPrime(r))
{
const unsigned int m = n % r;

if (m == 0) break;
q = LargestPrimeFactor(r - 1);
if (Powm(m, (r - 1) / q, r) <= 1) continue;
/*
// AKS
if (q >= 4 * sqrt(r) * n.Log()/log(2))
{
s = (unsigned int)(2 * sqrt(r) * n.Log()
/log(2));
b = true;
break;
}
*/
// Bernstein
const double cMin = 2 * floor(sqrt(r)) * log(n);
double c = 0;
for (s = 1; s <= q; s++)
{
c += log(q + s - 1) - log(s);
if (c >= cMin)
{
b = true;
break;
}
}
if (b) break;
}
}
if (b)
{
cout << "n=" << n << ", r=" << r << ", q=" << q << ", s=
" << s << "\r" << flush;;
bool b = true;
CPolyMod rPoly(r, n);
// x
try
{
rPoly = rPoly.Pow(n);
// x^n
}
catch (...)
{
b = false;
}
if (b)
{
unsigned int a;
for (a = 1; a <= s; ++a)
{
cout << "n=" << n << ", r=" << r << ", q
=" << q << ", s=" << s << " " << a << "\r" << flush;;
CPolyMod lPoly(r, n);
lPoly -= a;

// x

// x - a
try
{
lPoly = lPoly.Pow(n);
a)^n

// (x -

}
catch (...)
{
b = false;
break;
}
lPoly += a;
// (x - a)^n + a
if (lPoly != rPoly)
{
b = false;
break;
}
}
}
if (b)
cout << "n=" << n << ", r=" << r << ", q=" << q
<< ", s=" << s << ", power of a prime." << endl;
else
cout << "n=" << n << ", r=" << r << ", q=" << q
<< ", s=" << s << ", composite." << endl;
}
}
return 0;
}
================================================================================
=================================================
================================================================================
=================================================
use strict;
# use bignum;
print <<USAGE and exit 0 unless @ARGV;
$0 [-v] n
Use the AKS primality test to check whether n is prime
-v adds verbose log spew
USAGE
sub
sub
sub
sub
sub
sub
sub
sub
sub
sub

is_power($$);
ceil_log2($);
first_r($$);
check_gcds($$);
check_polynomials($$$);
gcd($$);
totient($);
polypow($$\@);
polymult($$\@\@);
polyeq(\@\@);

my $verbose = $ARGV[0] eq
shift @ARGV if $verbose;

-v ;

die Expected only one argument


my $n = shift;

unless 1 == @ARGV;

# step 0: restrict to integers >= 2


print $n is not an integer and so is NEITHER PRIME NOR COMPOSITE\n and exit 0 unle
ss int($n) == $n;

print

$n < 2 and so is NEITHER PRIME OR COMPOSITE\n

and exit 0 unless $n >= 2;

# step 1: check if the number is a power of some lower number.


# this can be done quickly by iterating over the exponent (2, 3, )
# and doing a binary search on the base.
# we start at the top and work down for performance reasons;
# several subroutines need to know ceil(log2(n)) so we calculate it once and pas
s it around.
my $log2_n = ceil_log2($n);
is_power($n, $log2_n) and exit 0;
print Not a power.\n ;
# step 2: find the smallest r such that o_r(n) > (log2 n)^2
# where o_r(n) is the multiplicative order of n mod r
# that is, the smallest k such that n^k == 1 mod r
my $r = first_r($n, $log2_n);
print r = $r\n ;
# step 3: for all a between 2 and r inclusive, check whether gcd(a, n) > 1
check_gcds($n, $r) or exit 0;
# step 4: if r >= n, we re done
if ($r >= $n) {
print $r >= $n so $n is PRIME\n ;
exit 0;
}
# step 5: for all a between 1 and floor( sqrt(phi(r)) log2(n) )
# check whether (x + a)^n = x^n + a mod x^r
1, n
check_polynomials($n, $r, $log2_n) or exit 0;
# step 6: if we got this far, n is prime
print $n is PRIME\n ;
sub is_power($$) {
my $n = shift;
my $log2_n = shift; # actually ceil(log2(n))
print Checking for power-ness \n ;
# we consider numbers of the form b^i
# we iterate over the exponent i
# starting at i = ceil(log2(n)) and working down to i = 2
#
# for each exponent we do a binary search on the base
# the lowest the base can be is 2
# and the highest the base can be (initially) is 2
#
# we set up bounds on the base that are guaranteed to
# surround the actual base
my $b_low = 1; # 1 ^ ceil(log2(n)) = 1 < n
my $b_high = 3; # 3 ^ ceil(log2(n)) > 2 ^ log2(n) = n
for (my $i = $log2_n; $i >= 2; $i ) {
print \tb^$i\n if $verbose;
# let s check that the bounds are really correct
die $b_low ^ $i is not < $n unless $b_low ** $i < $n;
die $b_high ^ $i is not > $n unless $b_high ** $i > $n;

# do a binary search to find b such that b ^ i = n


while ($b_high
$b_low > 1) {
print \t\tb^$i: b is between $b_low and $b_high\n
my $b = int(($b_low + $b_high)/2);

if $verbose;

my $t = $b ** $i;
if ($t == $n) {
print $n = $b^$i; $n is COMPOSITE\n ;
return 1;
}
($t > $n ? $b_high : $b_low) = $b;
}
#
#
#
#
#
#
#
#

as we pass from the exponent (say, 5)


to the exponent below (say, 4)
we need to reconsider our bounds
b_low can remain the same because b ^ (i
OPEN ISSUE: can we even raise b_low?

1) is even less than b ^ i

but we need to raise b_high since b ^ i > n does NOT imply b ^ (i

1) >

n
#
# we ll square b_high; b ^ i > n => (b ^ 2) ^ (i 1) = b ^ (2 i
2) > n
# since i >= 2
#
# OPEN ISSUE: is there a better way to raise this higher bound? Does thi
s help much?
$b_high *= $b_high;
}
# nope, not a power
return 0;
}
sub ceil_log2($) {
my $n = shift;
my $i = 0;
my $t = 1;
until ($t >= $n) {
$i++;
$t *= 2;
}
return $i;
}
sub first_r($$) {
my $n = shift;
my $log2_n = shift; # actually ceil(log2(n))
my $s = $log2_n ** 2;
print Looking for the first r where o_r($n) > $s \n ;
# for each r we want to find the smallest k such that
# n^k == 1 mod r

my $r;
for ($r = 2; ; $r++) {
# print \tTrying $r \n ;
# find the multiplicative order of n mod r
my $k = 1;
my $t = $n % $r;
until (1 == $t or $k > $s) {
$t = ($t * $n) % $r;
$k++;
}
if ($k > $s) {
# print \to_$r($n) is at least $k\n ;
last;
} else {
# print \to_$r($n) = $k\n ;
}
}
return $r;
}
sub check_gcds($$) {
my ($n, $r) = @_;
print Checking GCD($n, a) for a = 2 to $r \n ;
for (my $a = 2; $a <= $r; $a++) {
my $g = gcd($n, $a);
next if ($g == $n); # this is OK
if (1 != $g) {
print gcd($n, $a) = $g; $n is COMPOSITE\n ;
return 0;
}
}
print All GCDs are 1 or $n\n ;
return 1;
}
sub gcd($$) {
my ($x, $y) = @_;
($x, $y) = ($y, $x) unless $x > $y;
while ($y) {
($x, $y) = ($y, $x % $y);
}
return $x;
}
sub check_polynomials($$$) {
my $n = shift;
my $r = shift;

my $log2_n = shift; # actually ceil(log2(n))


# iterate over a from 1 to floor( sqrt(phi(r)) log2(n) )
# for each a, check whether the polynomial equality holds:
# (x + a)^n = x^n + a mod (x^r
1, n)
# if it fails to hold, the number is composite
#
# first we need to evaluate phi(r) so we can determine the upper bound
# OPEN ISSUE: this seems to be a potential weakness in the algorithm
# because the usual way to evaluate phi(r) is to find the prime factorizatio
n of r
# and then form the product r*PI(1
1/p) where the product ranges over all pr
imes
# which divide r
my $phi = totient($r);
# a < sqrt(phi(r)) * log2(n) => a^2 < phi(r) * (log2(n))^2
my $a2_max = $phi * $log2_n * $log2_n;
print Checking polynomials up to roughly , int sqrt($a2_max),

\n ;

for (my $a = 1; $a * $a <= $a2_max; $a++) {


print \ta = $a \n if $verbose;
# polynomials are of the form (c0, c1, c2, , ci, )
# which corresponds to c0 + c1 x + c2 x^2 + + ci x^i + )
my @x = (0, 1);
my @x_plus_a = ($a % $n, 1);
my @lhs = polypow($n, $r, @x_plus_a);
# POTENTIAL OPTIMIZATION:
# x^n + a mod (x^r 1) is just x^(n % r) + a
# and we know n % r != 0
my @rhs = polypow($n, $r, @x); # x^n
$rhs[0] = ($rhs[0] + $a) % $n; # + a
next if polyeq(@lhs, @rhs);
print (x + $a)^$n is not equal to x^$n + $a mod(x^$r
print So $n is COMPOSITE\n ;
return 0;
}
return 1;
}
sub totient($) {
my $r = shift;
print

Finding the Euler totient of $r\n ;

# we ll do a trial division to find the totient


# there are faster ways that use a sieve
# but we don t know how big r is
my $t = $r;
# by construction p will always be prime when it is used
# OPEN ISSUE: this might be slow
for (my $p = 2; $r > 1; $p++) {

1, $n)\n ;

next if $r % $p;
print \t$p is a factor\n if $verbose;
# decrease the totient
$t /= $p;
$t *= $p 1;
# decrease r
$r /= $p; # we know there s at least one factor of p
$r /= $p until $r % $p; # there might be more
}
print

Totient is $t\n ;

return $t;
}
sub polypow($$\@) {
my $n = shift; # this is both the mod and the exponent
my $r = shift;
my @base = @{ +shift };
my $exp = $n;
my @result = (1); # 1
# print \t( , join(

, @base), )^$exp mod (x^$r

1, $n)\n

if $verbose;

# basic modpow routine, but with polynomials


while ($exp) {
if ($exp % 2) {
@result = polymult($n, $r, @result, @base);
}
$exp = int ($exp / 2);
@base = polymult($n, $r, @base, @base);
}
# print \t= ( , join(
return @result;

, @result), )\n

if $verbose;

}
sub polymult($$\@\@) {
my $n = shift;
my $r = shift;
my @first = @{ +shift };
my @second = @{ +shift };
# print
ose;

\t\t( , join(

, @first),

) * ( , join(

my @result = ();
# first
my $s =
for (my
for

do a straight multiplication first * second


@second 1;
$i = @first
1; $i >= 0; $i ) {
(my $j = $s; $j >= 0; $j ) {
my $k = $i + $j;
$result[$k] += $first[$i] * $second[$j];
$result[$k] %= $n;

, @second), ) mod (x^$r

1, $n)\

}
#
#
#
#
#
#
#
#

then do a straight mod x^r


1
consider a polynomial
c0 + + ck x^k
with k >= r
we can subtract ck (x^r
1)
without changing the mod value
the net effect is to eliminate the x^k term
and add ck to the x^(k r) term

for (my $i = @result 1; $i >= $r; $i ) {


my $j = $i $r;
$result[$j] += $result[$i];
$result[$j] %= $n;
pop @result;
}
# eliminate any leading zero terms
for (my $i = @result
1; 0 == $result[$i]; $i ) {
pop @result;
}
# print \t\t= ( , join(
return @result;

, @result), )\n

if $verbose;

}
sub polyeq(\@\@) {
my @lhs = @{ +shift };
my @rhs = @{ +shift };
# print

( , join(

, @lhs),

) = ( , join(

return 0 unless @lhs == @rhs;


for (my $i = @lhs
1; $i >= 0; $i ) {
return 0 unless $lhs[$i] == $rhs[$i];
}
return 1;
}
Here s the output when I run it on 19:
>perl -w aks.pl 19
Checking for power-ness
Not a power.
Looking for the first r where o_r(19) > 25
r = 19
Checking GCD(19, a) for a = 2 to 19
All GCDs are 1 or 19
19 >= 19 so 19 is PRIME
And here s the output with a bigger input:
>perl -w aks.pl 99
Checking for power-ness
Not a power.
Looking for the first r where o_r(997) > 100
r = 103

, @rhs),

)?\n if $verbose;

Checking GCD(997, a) for a = 2 to 103


All GCDs are 1 or 997
Finding the Euler totient of 103
Totient is 102
Checking polynomials up to roughly 100
997 is PRIME

================================================================================
========================================================
================================================================================
====================================
import math
import sys
#used literature http://teal.gmu.edu/courses/ECE746/project/F06_Project_resource
s/Salembier_Southerington_AKS.pdf
#http://dha.spb.ru/PDF/AKS.pdf
#https://en.wikipedia.org/wiki/AKS_primality_test
def Main():
if len(sys.argv) != 3:
print ('Invalid number of input arguments')
else:
try:
fil = sys.argv[1]
f = open(fil, 'r')
except:
print ('File not found')
else:
fil
f =
n =
q =

= sys.argv[1]
open(fil, 'r')
int(f.read()) #?????????? ???????? ?????
int(4 * pow(math.log2(n),2) + 1)

check_input(n)
PerfectPower(n)
Individual_r(n,q)
def check_input(n):
if n < 1 :
Output('\nFalse, input is incorrect')
elif n == 1 :
Output('\nFalse, Composite number')
def Output(text) :
fil1 = sys.argv[2]
f = open(fil1, 'w')
f.writelines(text)
f.close()
exit(0)
def PerfectPower(n):
b = 2
if b > math.log2(n):
Output('\nPrime')

while b <= math.log2(n):


m = math.ceil(n**(1/b)) #?????? b'?? ??????? ?? n
if n == m**b:
Output('\nFalse, Composite number,Perfect power')
else:
b+=1
def Individual_r(n,q):
for j in range(1,int(4 * pow(math.log2(n),2))) :
if (n ** j) % q != 1 :
r = q
GCD(n,r)
FermaTest(n,r)
continue

#??????? ????? n

else:
q += 1
return Individual_r(q)
def GCD(n,r):
if r >= n:
r = n - 1
for gcd in range(r,0,-1) :
z = n
if z % gcd == 0 :
if gcd != 1:
Output('\nFalse, Composite number')
else:
for gcd in range(r,0,-1) :
z = n
if z % gcd == 0 :
if gcd != 1:
Output('\nFalse, Composite number')
def FermaTest(n,r):
for k in range(2 , int(2 * math.sqrt(r) * math.log2(n))) : #????? ?????
if (pow(k , (n - 1)) - 1) % n != 0 :
Output('\nFalse, Composite number')
continue
else :
Output('\nPrime')
Main()
================================================================================
====================================================
================================================================================
====================================================

Potrebbero piacerti anche