MadelineProto/prime.php

291 lines
7.5 KiB
PHP
Raw Normal View History

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-20 20:12:32 +02:00
2016-07-19 11:56:05 +02:00
class PrimeModule
{
public function __construct()
{
2016-07-18 18:43:50 +02:00
$this->smallprimeset = array_unique($this->primesbelow(100000));
$this->_smallprimeset = 100000;
$this->smallprimes = $this->primesbelow(10000);
}
2016-07-29 17:19:34 +02:00
2016-07-19 11:56:05 +02:00
public function primesbelow($N)
{
2016-07-18 18:43:50 +02:00
$res = [];
2016-07-19 11:56:05 +02:00
for ($i = 2; $i <= $N; $i++) {
if ($i % 2 != 1 && $i != 2) {
continue;
}
2016-07-18 18:43:50 +02:00
$d = 3;
$x = sqrt($i);
2016-07-19 11:56:05 +02:00
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-19 11:56:05 +02:00
2016-07-18 18:43:50 +02:00
return $res;
2016-07-14 15:15:50 +02:00
}
2016-07-19 11:56:05 +02:00
public function isprime($n, $precision = 7)
2016-07-18 18:43:50 +02:00
{
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);
2016-07-20 20:12:32 +02:00
$s++;
2016-07-18 18:43:50 +02:00
}
2016-07-20 20:12:32 +02:00
$break = false;
2016-07-18 18:43:50 +02:00
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-20 20:12:32 +02:00
foreach (pyjslib_range($s - 1) as $r) {
2016-07-18 18:43:50 +02:00
$x = posmod(pow($x, 2), $n);
if (($x == 1)) {
return false;
}
if (($x == ($n - 1))) {
2016-07-20 20:12:32 +02:00
$break = true;
2016-07-18 18:43:50 +02:00
}
2016-06-23 23:51:08 +02:00
}
2016-07-29 17:19:34 +02:00
if (!$break) {
return false;
}
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-19 11:56:05 +02:00
public function pollard_brent($n)
2016-07-18 18:43:50 +02:00
{
$zero = new \phpseclib\Math\BigInteger(0);
$one = new \phpseclib\Math\BigInteger(1);
$two = new \phpseclib\Math\BigInteger(2);
$three = new \phpseclib\Math\BigInteger(3);
2016-07-30 17:17:15 +02:00
if ($n->powMod($one, $two)->toString() == '0') {
2016-07-18 18:43:50 +02:00
return 2;
}
2016-07-30 17:17:15 +02:00
if ($n->powMod($one, $three)->toString() == '0') {
2016-07-18 18:43:50 +02:00
return 3;
}
2016-07-20 20:23:26 +02:00
$big = new \phpseclib\Math\BigInteger();
$max = $n->subtract($one);
list($y, $c, $m) = [new \phpseclib\Math\BigInteger(87552211475113995), new \phpseclib\Math\BigInteger(330422027228888537), new \phpseclib\Math\BigInteger(226866727920975483)];
//[$big->random($one, $max), $big->random($one, $max), $big->random($one, $max)];
list($g, $r, $q) = [$one, $one, $one];
while ($g->equals($one)) {
2016-07-18 18:43:50 +02:00
$x = $y;
$range = $r;
while (!$range->equals($zero)) {
$y = $y->powMod($two, $n)->add($c)->powMod($one, $n);
$range = $range->subtract($one);
2016-06-23 23:51:08 +02:00
}
$k = $zero;
while ($k->compare($r) == -1 && $g->equals($one)) {
2016-07-18 18:43:50 +02:00
$ys = $y;
$range = $big->min($m, $r->subtract($k));
while (!$range->equals($zero)) {
$y = $y->powMod($two, $n)->add($c)->powMod($one, $n);
$q = $q->multiply($x->subtract($y)->abs())->powMod($one, $n);
$range = $range->subtract($one);
2016-07-18 18:43:50 +02:00
}
$g = $q->gcd($n);
$k = $k->add($m);
2016-07-18 18:43:50 +02:00
}
$r = $r->multiply($two);
2016-06-23 23:51:08 +02:00
}
if ($g->equals($n)) {
2016-07-18 18:43:50 +02:00
while (true) {
$ys = $ys->powMod($two, $n)->add($c)->powMod($one, $n);
$g = $x->subtract($ys)->abs()->gcd($n);
if ($g->compare($one) == 1) {
2016-07-18 18:43:50 +02:00
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;
}
2016-07-19 11:56:05 +02:00
public function primefactors($n, $sort = false)
2016-07-18 18:43:50 +02:00
{
$factors = [];
$n = new \phpseclib\Math\BigInteger(1724114033281923457);
$one = new \phpseclib\Math\BigInteger(1);
$two = new \phpseclib\Math\BigInteger(2);
$limit = $n->root()->add($one);
2016-07-18 18:43:50 +02:00
foreach ($this->smallprimes as $checker) {
$checker = new \phpseclib\Math\BigInteger($checker);
if ($limit->compare($checker) == -1) {
2016-06-23 23:51:08 +02:00
break;
}
2016-07-30 17:17:15 +02:00
while ($n->modPow($one, $checker)->toString() == '0') {
2016-07-18 18:43:50 +02:00
$factors[] = $checker;
$n = $n->divide($checker)[0];
$limit = $n->root()->add($one);
if ($limit->compare($checker) == -1) {
2016-07-18 18:43:50 +02:00
break;
}
}
2016-06-23 23:51:08 +02:00
}
if ($n->compare($two) == -1) {
2016-07-18 18:43:50 +02:00
return $factors;
}
while ($n->compare($two) == 1) {
if ($n->isprime()) {
2016-07-18 18:43:50 +02:00
$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-19 11:56:05 +02:00
public function factorization($n)
2016-07-18 18:43:50 +02:00
{
$factors = [];
foreach (primefactors($n) as $p1) {
2016-07-19 11:56:05 +02:00
if (isset($factors[$p1])) {
2016-07-18 18:43:50 +02:00
$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-19 11:56:05 +02:00
public function totient($n)
2016-07-18 18:43:50 +02:00
{
$totients = [];
if (($n == 0)) {
return 1;
}
2016-07-19 11:56:05 +02:00
if (isset($totients[$n])) {
2016-07-18 18:43:50 +02:00
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-19 11:56:05 +02:00
public function gcd($a, $b)
2016-07-18 18:43:50 +02:00
{
if (($a == $b)) {
return $a;
}
while (($b > 0)) {
2016-07-20 20:12:32 +02:00
list($a, $b) = [$b, posmod($a, $b)];
2016-07-18 18:43:50 +02:00
}
2016-07-14 15:15:50 +02:00
2016-06-23 23:51:08 +02:00
return $a;
}
2016-07-19 11:56:05 +02:00
public function lcm($a, $b)
2016-07-18 18:43:50 +02:00
{
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-19 11:56:05 +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-19 11:56:05 +02:00
}