2016-06-23 23:51:08 +02:00
|
|
|
<?php
|
2016-07-14 15:15:50 +02:00
|
|
|
|
|
|
|
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).DIRECTORY_SEPARATOR.'libpy2php');
|
|
|
|
require_once 'libpy2php.php';
|
2016-07-18 18:43:50 +02:00
|
|
|
class PrimeModule {
|
|
|
|
function __construct() {
|
|
|
|
$this->smallprimeset = array_unique($this->primesbelow(100000));
|
|
|
|
$this->_smallprimeset = 100000;
|
|
|
|
$this->smallprimes = $this->primesbelow(10000);
|
|
|
|
}
|
|
|
|
function primesbelow($N) {
|
|
|
|
$res = [];
|
|
|
|
for ($i = 2; $i <= $N; $i++)
|
|
|
|
{
|
2016-07-18 18:56:33 +02:00
|
|
|
if($i % 2 != 1 && $i != 2) continue;
|
2016-07-18 18:43:50 +02:00
|
|
|
$d = 3;
|
|
|
|
$x = sqrt($i);
|
|
|
|
while ($i % $d != 0 && $d < $x) $d += 2;
|
|
|
|
if((($i % $d == 0 && $i != $d) * 1) == 0) $res[] = $i;
|
2016-07-14 15:15:50 +02:00
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
return $res;
|
2016-07-14 15:15:50 +02:00
|
|
|
}
|
|
|
|
|
2016-07-18 18:43:50 +02:00
|
|
|
function isprime($n, $precision = 7)
|
|
|
|
{
|
|
|
|
if (($n == 1) || (($n % 2) == 0)) {
|
|
|
|
return false;
|
|
|
|
} elseif (($n < 1)) {
|
|
|
|
throw new Exception('Out of bounds, first argument must be > 0');
|
|
|
|
} elseif (($n < $this->_smallprimeset)) {
|
|
|
|
return in_array($n, $this->smallprimeset);
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
$d = ($n - 1);
|
|
|
|
$s = 0;
|
|
|
|
while (($d % 2) == 0) {
|
|
|
|
$d = floor($d / 2);
|
|
|
|
$s += 1;
|
|
|
|
}
|
|
|
|
foreach (pyjslib_range($precision) as $repeat) {
|
|
|
|
$a = rand(2, ($n - 2));
|
|
|
|
$x = posmod(pow($a, $d), $n);
|
|
|
|
if (($x == 1) || ($x == ($n - 1))) {
|
|
|
|
continue;
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
foreach (pyjslib_range(($s - 1)) as $r) {
|
|
|
|
$x = posmod(pow($x, 2), $n);
|
|
|
|
if (($x == 1)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (($x == ($n - 1))) {
|
|
|
|
break;
|
|
|
|
}
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
|
2016-07-18 18:43:50 +02:00
|
|
|
return true;
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
function pollard_brent($n)
|
|
|
|
{
|
|
|
|
if ((($n % 2) == 0)) {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
if ((($n % 3) == 0)) {
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
list($y, $c, $m) = [rand(1, ($n - 1)), rand(1, ($n - 1)), rand(1, ($n - 1))];
|
|
|
|
list($g, $r, $q) = [1, 1, 1];
|
|
|
|
while (($g == 1)) {
|
|
|
|
$x = $y;
|
|
|
|
foreach (pyjslib_range($r) as $i) {
|
2016-07-18 18:56:33 +02:00
|
|
|
$y = ((posmod(pow($y, 2), $n) + $c) % $n);
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
$k = 0;
|
|
|
|
while (($k < $r) && ($g == 1)) {
|
|
|
|
$ys = $y;
|
|
|
|
foreach (pyjslib_range(min($m, ($r - $k))) as $i) {
|
2016-07-18 18:56:33 +02:00
|
|
|
$y = ((posmod(pow($y, 2), $n) + $c) % $n);
|
2016-07-18 18:43:50 +02:00
|
|
|
$q = (($q * abs(($x - $y))) % $n);
|
|
|
|
}
|
2016-07-18 18:56:33 +02:00
|
|
|
$g = $this->gcd($q, $n);
|
2016-07-18 18:43:50 +02:00
|
|
|
$k += $m;
|
|
|
|
}
|
|
|
|
$r *= 2;
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
if (($g == $n)) {
|
|
|
|
while (true) {
|
2016-07-18 18:56:33 +02:00
|
|
|
$ys = ((posmod(pow($ys, 2), $n) + $c) % $n);
|
|
|
|
$g = $this->gcd(abs(($x - $ys)), $n);
|
2016-07-18 18:43:50 +02:00
|
|
|
if (($g > 1)) {
|
|
|
|
break;
|
|
|
|
}
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
|
2016-07-18 18:43:50 +02:00
|
|
|
return $g;
|
|
|
|
}
|
|
|
|
function primefactors($n, $sort = false)
|
|
|
|
{
|
|
|
|
$factors = [];
|
|
|
|
$limit = ((int)(pow($n, 0.5)) + 1);
|
|
|
|
foreach ($this->smallprimes as $checker) {
|
2016-06-23 23:51:08 +02:00
|
|
|
if (($checker > $limit)) {
|
|
|
|
break;
|
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
while (($n % $checker) == 0) {
|
|
|
|
$factors[] = $checker;
|
|
|
|
$n = floor($n / $checker);
|
|
|
|
$limit = ((int)(pow($n, 0.5)) + 1);
|
|
|
|
if (($checker > $limit)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
if (($n < 2)) {
|
|
|
|
return $factors;
|
|
|
|
}
|
|
|
|
while (($n > 1)) {
|
|
|
|
if ($this->isprime($n)) {
|
|
|
|
$factors[] = $n;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
$factor = $this->pollard_brent($n);
|
|
|
|
$factors[] = $this->primefactors($factor);
|
|
|
|
$n = floor($n / $factor);
|
|
|
|
}
|
|
|
|
if ($sort) {
|
|
|
|
$factors = sort($factors);
|
|
|
|
}
|
|
|
|
|
2016-06-23 23:51:08 +02:00
|
|
|
return $factors;
|
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
function factorization($n)
|
|
|
|
{
|
|
|
|
$factors = [];
|
|
|
|
foreach (primefactors($n) as $p1) {
|
|
|
|
if(isset($factors[$p1])) {
|
|
|
|
$factors[$p1] += 1;
|
|
|
|
} else {
|
|
|
|
$factors[$p1] = 1;
|
|
|
|
}
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
|
2016-07-18 18:43:50 +02:00
|
|
|
return $factors;
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
function totient($n)
|
|
|
|
{
|
|
|
|
$totients = [];
|
|
|
|
if (($n == 0)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if(isset($totients[$n])) {
|
|
|
|
return $totients[$n];
|
|
|
|
}
|
|
|
|
$tot = 1;
|
|
|
|
foreach (factorization($n) as $p => $exp) {
|
|
|
|
$tot *= (($p - 1) * pow($p, ($exp - 1)));
|
|
|
|
}
|
|
|
|
$totients[$n] = $tot;
|
|
|
|
|
|
|
|
return $tot;
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
function gcd($a, $b)
|
|
|
|
{
|
|
|
|
if (($a == $b)) {
|
|
|
|
return $a;
|
|
|
|
}
|
|
|
|
while (($b > 0)) {
|
|
|
|
list($a, $b) = [$b, ($a % $b)];
|
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
|
2016-06-23 23:51:08 +02:00
|
|
|
return $a;
|
|
|
|
}
|
2016-07-18 18:43:50 +02:00
|
|
|
function lcm($a, $b)
|
|
|
|
{
|
2016-07-18 18:56:33 +02:00
|
|
|
return floor(abs(($a * $b)) / $this->gcd($a, $b));
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-18 22:18:26 +02:00
|
|
|
/*
|
|
|
|
function pqPrimeLeemon ($what) {
|
|
|
|
$minBits = 64;
|
|
|
|
$minLen = ceil($minBits / $bpe) + 1;
|
|
|
|
$it = 0
|
|
|
|
$a = new Array(minLen)
|
|
|
|
$b = new Array(minLen)
|
|
|
|
$c = new Array(minLen)
|
|
|
|
$g = new Array(minLen)
|
|
|
|
$z = new Array(minLen)
|
|
|
|
$x = new Array(minLen)
|
|
|
|
$y = new Array(minLen)
|
|
|
|
|
|
|
|
for ($i = 0; $i < 3; $i++) {
|
|
|
|
$q = (nextRandomInt(128) & 15) + 17
|
|
|
|
copyInt_(x, nextRandomInt(1000000000) + 1)
|
|
|
|
copy_(y, x)
|
|
|
|
lim = 1 << (i + 18)
|
|
|
|
|
|
|
|
for (j = 1; j < lim; j++) {
|
|
|
|
++it
|
|
|
|
copy_(a, x)
|
|
|
|
copy_(b, x)
|
|
|
|
copyInt_(c, q)
|
|
|
|
|
|
|
|
while (!isZero(b)) {
|
|
|
|
if (b[0] & 1) {
|
|
|
|
add_(c, a)
|
|
|
|
if (greater(c, what)) {
|
|
|
|
sub_(c, what)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
add_(a, a)
|
|
|
|
if (greater(a, what)) {
|
|
|
|
sub_(a, what)
|
|
|
|
}
|
|
|
|
rightShift_(b, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
copy_(x, c)
|
|
|
|
if (greater(x, y)) {
|
|
|
|
copy_(z, x)
|
|
|
|
sub_(z, y)
|
|
|
|
} else {
|
|
|
|
copy_(z, y)
|
|
|
|
sub_(z, x)
|
|
|
|
}
|
|
|
|
eGCD_(z, what, g, a, b)
|
|
|
|
if (!equalsInt(g, 1)) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if ((j & (j - 1)) == 0) {
|
|
|
|
copy_(y, x)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (greater(g, one)) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
divide_(what, g, x, y)
|
|
|
|
|
|
|
|
if (greater(g, x)) {
|
|
|
|
P = x
|
|
|
|
Q = g
|
|
|
|
} else {
|
|
|
|
P = g
|
|
|
|
Q = x
|
|
|
|
}
|
|
|
|
|
|
|
|
// console.log(dT(), 'done', bigInt2str(what, 10), bigInt2str(P, 10), bigInt2str(Q, 10))
|
|
|
|
|
|
|
|
return [bytesFromLeemonBigInt(P), bytesFromLeemonBigInt(Q), it]
|
|
|
|
}*/
|
2016-07-14 15:15:50 +02:00
|
|
|
|
2016-07-18 18:43:50 +02:00
|
|
|
}
|