Implemented root and pow functions in the BigInteger lib, made some changes to support update PHPStruct lib

This commit is contained in:
danogentili 2016-07-30 16:14:25 +02:00
parent 652327fecd
commit 9e08e6fe8f
5 changed files with 182 additions and 68 deletions

2
TL.php
View File

@ -68,7 +68,7 @@ class TL
$this->method_id[$z->id] = $z;
$this->method_name[$z->method] = $z;
}
$this->struct = new \danog\PHP\Struct();
$this->struct = new \danog\PHP\StructClass();
}
public function serialize_obj($type_, $kwargs)

View File

@ -7,7 +7,7 @@ require_once 'crypt.php';
require_once 'prime.php';
require_once 'TL.php';
require_once 'vendor/autoload.php';
$struct = new \danog\PHP\Struct();
$struct = new \danog\PHP\StructClass();
/**
* Function to get hex crc32
* :param data: Data to encode.
@ -101,59 +101,6 @@ function fopen_and_write($filename, $mode, $data)
return $handle;
}
/**
* long_to_bytes(n:long, blocksize:int) : string
* Convert a long integer to a byte string.
* If optional blocksize is given and greater than zero, pad the front of the
* byte string with binary zeros so that the length is a multiple of
* blocksize.
*/
function long_to_bytes($n, $blocksize = 0)
{
$s = null;
$n = (float) $n;
while ($n > 0) {
$s = $GLOBALS['struct']->pack('I', $n & 4294967295).$s;
$n = $n >> 32;
}
$break = false;
foreach (pyjslib_range(strlen($s)) as $i) {
if ($s[$i] != string2bin('\000')[0]) {
$break = true;
break;
}
}
if (!$break) {
$s = string2bin('\000');
$i = 0;
}
$s = substr($s, $i);
if ($blocksize > 0 && strlen($s) % $blocksize) {
$s = pack('@'.$blocksize - (strlen($s) % $blocksize)).$s;
}
return $s;
}
/**
* bytes_to_long(string) : long
* Convert a byte string to a long integer.
* This is (essentially) the inverse of long_to_bytes().
*/
function bytes_to_long($s)
{
$acc = 0;
$length = strlen($s);
if ($length % 4) {
$extra = (4 - ($length % 4));
$s = pack('@'.$extra).$s;
$length += $extra;
}
foreach (pyjslib_range(0, $length, 4) as $i) {
$acc = ($acc << 32) + $GLOBALS['struct']->unpack('>I', substr($s, $i, 4))[0];
}
return $acc;
}
function string2bin($string)
{
$res = null;
@ -204,8 +151,7 @@ class Session
*/
public function send_message($message_data)
{
$message_id = long_to_bytes((int) ((time() + $this->timedelta) * pow(2, 30)) * 4);
//$message_id = $this->struct->pack('<Q', (int) ((time() + $this->timedelta) * pow(2, 30)) * 4);
$message_id = $this->struct->pack('<Q', (int) ((time() + $this->timedelta) * pow(2, 30)) * 4);
if (($this->auth_key == null) || ($this->server_salt == null)) {
$message = string2bin('\x00\x00\x00\x00\x00\x00\x00\x00').$message_id.$this->struct->pack('<I', strlen($message_data)).$message_data;
@ -219,7 +165,6 @@ class Session
$message = $this->auth_key_id.$message_key.crypt::ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv);
}
$step1 = $this->struct->pack('<II', (strlen($message) + 12), $this->number).$message;
var_dump(newcrc32($step1));
$step2 = $step1.$this->struct->pack('<I', newcrc32($step1));
fwrite($this->sock, $step2);
$this->number += 1;
@ -266,7 +211,6 @@ class Session
{
foreach (range(1, $this->MAX_RETRY) as $i) {
try {
//var_dump(py2php_kwargs_function_call('serialize_method', [$method], $kwargs));
$this->send_message($this->tl->serialize_method($method, $kwargs));
$server_answer = $this->recv_message();
} catch (Exception $e) {
@ -287,7 +231,6 @@ class Session
$public_key_fingerprint = $ResPQ['server_public_key_fingerprints'][0];
$pq_bytes = $ResPQ['pq'];
$pq = new \phpseclib\Math\BigInteger($pq_bytes, 256);
var_dump($this->PrimeModule->primefactors($pq));
die;
var_dump($this->PrimeModule->pollard_brent(15));
@ -300,9 +243,9 @@ class Session
}
assert((($p * $q) == $pq) && ($p < $q));
pyjslib_printnl(sprintf('Factorization %d = %d * %d', [$pq, $p, $q]));
$p_bytes = long_to_bytes($p);
$q_bytes = long_to_bytes($q);
$f = pyjslib_open(__DIR__.'/rsa.pub');
$p_bytes = $this->struct->pack('>Q', $p);
$q_bytes = $this->struct->pack('>Q', $q);
$f = file_get_contents(__DIR__.'/rsa.pub');
$key = RSA::importKey($f->read());
$new_nonce = random_bytes(32);
$data = py2php_kwargs_function_call('serialize_obj', ['p_q_inner_data'], ['pq' => $pq_bytes, 'p' => $p_bytes, 'q' => $q_bytes, 'nonce' => $nonce, 'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce]);

View File

@ -120,12 +120,9 @@ class PrimeModule
public function primefactors($n, $sort = false)
{
$factors = [];
if ($n->compare(PHP_INT_MAX) === -1) {
var_dump((int) $n->toString());
}
$limit = ((int) (pow($n, 0.5)) + 1);
$limit = $n->root()->add(1);
foreach ($this->smallprimes as $checker) {
if (($checker > $limit)) {
if (($limit < $checker)) {
break;
}
while (($n % $checker) == 0) {

13
sqr.php Normal file
View File

@ -0,0 +1,13 @@
<?php
function mysqr($n) {
$guess = $n / 2;
while (true) {
$last = $guess;
$guess = (($n / $guess) + $guess) / 2;
if($last == $guess) {
break;
}
}
return $guess;
}
var_dump(mysqr(234892482328),sqrt(234892482328));

View File

@ -1573,7 +1573,166 @@ class BigInteger
return array($this->_normalize($quotient), $this->_normalize($x));
}
/**
* Calculates the nth root of a biginteger.
*
* Returns the nth root of a positive biginteger, where n defaults to 2
*
* Here's an example:
* <code>
* <?php
* $a = new \phpseclib\Math\BigInteger('625');
*
* $root = $a->root();
*
* echo $root->toString(); // outputs 25
* ?>
* </code>
*
* @param \phpseclib\Math\BigInteger $n
* @return \phpseclib\Math\BigInteger
* @access public
* @internal This function is based off of {@link http://mathforum.org/library/drmath/view/52605.html this page} and {@link http://stackoverflow.com/questions/11242920/calculating-nth-root-with-bcmath-in-php this stackoverflow question}.
*/
function root($n = null)
{
$one = new static(1);
$two = new static(2);
if($n === null) $n = $two;
if ($n->compare($one) == -1) return new static(0); // we want positive exponents
if ($this->compare($one) == -1) return new static(0); // we want positive numbers
if ($this->compare($two) == -1) return $one; // n-th root of 1 or 2 is 1
$root = new static();
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$root->value = gmp_root($this->value, $n->value);
break;
case self::MODE_BCMATH:
// g is our guess number
$g = 2;
// while (g^n < num) g=g*2
while (bccomp(bcpow($g, $n->value), $this->value) == -1) {
$g = bcmul($g, "2");
}
// if (g^n==num) num is a power of 2, we're lucky, end of job
if (bccomp(bcpow($g, $n->value), $this->value) == 0) {
$root->value = $g;
break;
}
// if we're here num wasn't a power of 2 :(
$og = $g; // og means original guess and here is our upper bound
$g = bcdiv($g, "2"); // g is set to be our lower bound
$step = bcdiv(bcsub($og, $g), "2"); // step is the half of upper bound - lower bound
$g = bcadd($g, $step); // we start at lower bound + step , basically in the middle of our interval
// while step!=1
while (bccomp($step, "1")==1) {
$guess = bcpow($g, $n);
$step=bcdiv($step,"2");
$comp=bccomp($guess,$this->value); // compare our guess with real number
if ($comp==-1) { // if guess is lower we add the new step
$g=bcadd($g,$step);
} else if ($comp==1) { // if guess is higher we sub the new step
$g=bcsub($g,$step);
} else { // if guess is exactly the num we're done, we return the value
$root->value = $g;
break;
}
}
// whatever happened, g is the closest guess we can make so return it
$root->value = $g;
break;
default:
// g is our guess number
$g = $two;
// while (g^n < num) g=g*2
while ($g->pow($n)->compare($this) == -1) {
$g = $g->multiply($two);
}
// if (g^n==num) num is a power of 2, we're lucky, end of job
// == 0 bccomp(bcpow($g,$n), $n->value)==0
if ($g->pow($n)->equals($this)) {
$root = $g;
break;
}
// if we're here num wasn't a power of 2 :(
$og = $g; // og means original guess and here is our upper bound
$g = $g->divide($two)[0]; // g is set to be our lower bound
$step = $og->subtract($g)->divide($two)[0]; // step is the half of upper bound - lower bound
$g = $g->add($step); // we start at lower bound + step , basically in the middle of our interval
// while step!=1
while ($step->compare($one) == 1) {
$guess = $g->pow($n);
$step = $step->divide($two)[0];
$comp = $guess->compare($this); // compare our guess with real number
if ($comp == -1) { // if guess is lower we add the new step
$g = $g->add($step);
} else if ($comp == 1) { // if guess is higher we sub the new step
$g = $g->subtract($step);
} else { // if guess is exactly the num we're done, we return the value
$root = $g;
break;
}
}
// whatever happened, g is the closest guess we can make so return it
$root = $g;
break;
}
return $this->_normalize($root);
}
/**
* Performs exponentiation.
*
*
* @param \phpseclib\Math\BigInteger $n
* @return \phpseclib\Math\BigInteger
* @access public
*/
function pow($n)
{
$zero = new static(0);
if ($n->compare($zero) == 0) return new static(1); // n^0 = 1
$isnegative = $n->is_negative; // n^-e = 1 / n^e
if ($isnegative == true) {
$n->is_negative = false;
}
$res = new static();
switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP:
$res->value = gmp_pow($this->value, $n->value);
if($isnegative) {
$res->value = gmp_div_q('1', $res->value);
}
return $res;
case self::MODE_BCMATH:
$res->value = bcpow($this->value, $n->value);
if($isnegative) {
$res->value = bcdiv('1', $res->value);
}
return $res;
default:
$one = new static(1);
$res = $this;
while (!$n->equals($one)) {
$res = $res->multiply($this);
$n = $n->subtract($one);
}
if($isnegative) {
$res->value = $one->divide($res);
}
return $res;
break;
}
}
/**
* Divides a BigInteger by a regular integer
*
@ -1794,6 +1953,8 @@ class BigInteger
return $this->modPow($e, $n);
}
/**
* Sliding Window k-ary Modular Exponentiation
*