From 9e08e6fe8fd6d5b9ffd7db613480a915c46880bd Mon Sep 17 00:00:00 2001 From: danogentili Date: Sat, 30 Jul 2016 16:14:25 +0200 Subject: [PATCH] Implemented root and pow functions in the BigInteger lib, made some changes to support update PHPStruct lib --- TL.php | 2 +- mtproto.php | 67 +------- prime.php | 7 +- sqr.php | 13 ++ .../phpseclib/phpseclib/Math/BigInteger.php | 161 ++++++++++++++++++ 5 files changed, 182 insertions(+), 68 deletions(-) create mode 100644 sqr.php diff --git a/TL.php b/TL.php index ae7e73df..a44c23cb 100644 --- a/TL.php +++ b/TL.php @@ -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) diff --git a/mtproto.php b/mtproto.php index 8e196d87..d78e1a4c 100755 --- a/mtproto.php +++ b/mtproto.php @@ -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('timedelta) * pow(2, 30)) * 4); + $message_id = $this->struct->pack('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('auth_key_id.$message_key.crypt::ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv); } $step1 = $this->struct->pack('number).$message; - var_dump(newcrc32($step1)); $step2 = $step1.$this->struct->pack('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]); diff --git a/prime.php b/prime.php index 7146a108..fc6af5d5 100644 --- a/prime.php +++ b/prime.php @@ -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) { diff --git a/sqr.php b/sqr.php new file mode 100644 index 00000000..76144b1c --- /dev/null +++ b/sqr.php @@ -0,0 +1,13 @@ +_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: + * + * root(); + * + * echo $root->toString(); // outputs 25 + * ?> + * + * + * @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 *