PageRenderTime 122ms CodeModel.GetById 4ms app.highlight 94ms RepoModel.GetById 1ms app.codeStats 1ms

/vendor/phpseclib/Math/BigInteger.php

https://github.com/KenjiOhtsuka/core
PHP | 3714 lines | 1983 code | 491 blank | 1240 comment | 401 complexity | aafc7122eb095e2112211e2b1392fc2e MD5 | raw file
   1<?php
   2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3
   4namespace PHPSecLib\Math;
   5
   6/**
   7 * Pure-PHP arbitrary precision integer arithmetic library.
   8 *
   9 * Supports base-2, base-10, base-16, and base-256 numbers.  Uses the GMP or BCMath extensions, if available,
  10 * and an internal implementation, otherwise.
  11 *
  12 * PHP versions 4 and 5
  13 *
  14 * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
  15 * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
  16 *
  17 * BigInteger uses base-2**26 to perform operations such as multiplication and division and
  18 * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction.  Because the largest possible
  19 * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
  20 * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
  21 * used.  As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
  22 * which only supports integers.  Although this fact will slow this library down, the fact that such a high
  23 * base is being used should more than compensate.
  24 *
  25 * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format.  ie.
  26 * (new \PHPSecLib\Math\BigInteger(pow(2, 26)))->value = array(0, 1)
  27 *
  28 * Useful resources are as follows:
  29 *
  30 *  - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
  31 *  - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
  32 *  - Java's BigInteger classes.  See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
  33 *
  34 * Here's an example of how to use this library:
  35 * <code>
  36 * <?php
  37 *    $a = new \PHPSecLib\Math\BigInteger(2);
  38 *    $b = new \PHPSecLib\Math\BigInteger(3);
  39 *
  40 *    $c = $a->add($b);
  41 *
  42 *    echo $c->toString(); // outputs 5
  43 * ?>
  44 * </code>
  45 *
  46 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  47 * of this software and associated documentation files (the "Software"), to deal
  48 * in the Software without restriction, including without limitation the rights
  49 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  50 * copies of the Software, and to permit persons to whom the Software is
  51 * furnished to do so, subject to the following conditions:
  52 *
  53 * The above copyright notice and this permission notice shall be included in
  54 * all copies or substantial portions of the Software.
  55 *
  56 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  57 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  58 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  59 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  60 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  61 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  62 * THE SOFTWARE.
  63 *
  64 * @category  Math
  65 * @package   Math_BigInteger
  66 * @author    Jim Wigginton <terrafrost@php.net>
  67 * @copyright MMVI Jim Wigginton
  68 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  69 * @link      http://pear.php.net/package/Math_BigInteger
  70 */
  71
  72use \phpseclib\Crypt\Random;
  73
  74/**#@+
  75 * Reduction constants
  76 *
  77 * @access private
  78 * @see BigInteger::_reduce()
  79 */
  80/**
  81 * @see BigInteger::_montgomery()
  82 * @see BigInteger::_prepMontgomery()
  83 */
  84define('MATH_BIGINTEGER_MONTGOMERY', 0);
  85/**
  86 * @see BigInteger::_barrett()
  87 */
  88define('MATH_BIGINTEGER_BARRETT', 1);
  89/**
  90 * @see BigInteger::_mod2()
  91 */
  92define('MATH_BIGINTEGER_POWEROF2', 2);
  93/**
  94 * @see BigInteger::_remainder()
  95 */
  96define('MATH_BIGINTEGER_CLASSIC', 3);
  97/**
  98 * @see BigInteger::__clone()
  99 */
 100define('MATH_BIGINTEGER_NONE', 4);
 101/**#@-*/
 102
 103/**#@+
 104 * Array constants
 105 *
 106 * Rather than create a thousands and thousands of new BigInteger objects in repeated function calls to add() and
 107 * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
 108 *
 109 * @access private
 110 */
 111/**
 112 * $result[MATH_BIGINTEGER_VALUE] contains the value.
 113 */
 114define('MATH_BIGINTEGER_VALUE', 0);
 115/**
 116 * $result[MATH_BIGINTEGER_SIGN] contains the sign.
 117 */
 118define('MATH_BIGINTEGER_SIGN', 1);
 119/**#@-*/
 120
 121/**#@+
 122 * @access private
 123 * @see BigInteger::_montgomery()
 124 * @see BigInteger::_barrett()
 125 */
 126/**
 127 * Cache constants
 128 *
 129 * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
 130 */
 131define('MATH_BIGINTEGER_VARIABLE', 0);
 132/**
 133 * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
 134 */
 135define('MATH_BIGINTEGER_DATA', 1);
 136/**#@-*/
 137
 138/**#@+
 139 * Mode constants.
 140 *
 141 * @access private
 142 * @see BigInteger::__construct()
 143 */
 144/**
 145 * To use the pure-PHP implementation
 146 */
 147define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
 148/**
 149 * To use the BCMath library
 150 *
 151 * (if enabled; otherwise, the internal implementation will be used)
 152 */
 153define('MATH_BIGINTEGER_MODE_BCMATH', 2);
 154/**
 155 * To use the GMP library
 156 *
 157 * (if present; otherwise, either the BCMath or the internal implementation will be used)
 158 */
 159define('MATH_BIGINTEGER_MODE_GMP', 3);
 160/**#@-*/
 161
 162/**
 163 * Karatsuba Cutoff
 164 *
 165 * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
 166 *
 167 * @access private
 168 */
 169define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
 170
 171/**
 172 * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
 173 * numbers.
 174 *
 175 * @package Math_BigInteger
 176 * @author  Jim Wigginton <terrafrost@php.net>
 177 * @access  public
 178 */
 179class BigInteger
 180{
 181    /**
 182     * Holds the BigInteger's value.
 183     *
 184     * @var Array
 185     * @access private
 186     */
 187    var $value;
 188
 189    /**
 190     * Holds the BigInteger's magnitude.
 191     *
 192     * @var Boolean
 193     * @access private
 194     */
 195    var $is_negative = false;
 196
 197    /**
 198     * Random number generator function
 199     *
 200     * @access private
 201     */
 202    var $generator = 'mt_rand';
 203
 204    /**
 205     * Precision
 206     *
 207     * @see setPrecision()
 208     * @access private
 209     */
 210    var $precision = -1;
 211
 212    /**
 213     * Precision Bitmask
 214     *
 215     * @see setPrecision()
 216     * @access private
 217     */
 218    var $bitmask = false;
 219
 220    /**
 221     * Mode independent value used for serialization.
 222     *
 223     * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
 224     * a variable that'll be serializable regardless of whether or not extensions are being used.  Unlike $this->value,
 225     * however, $this->hex is only calculated when $this->__sleep() is called.
 226     *
 227     * @see __sleep()
 228     * @see __wakeup()
 229     * @var String
 230     * @access private
 231     */
 232    var $hex;
 233
 234    /**
 235     * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
 236     *
 237     * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
 238     * two's compliment.  The sole exception to this is -10, which is treated the same as 10 is.
 239     *
 240     * Here's an example:
 241     * <code>
 242     * <?php
 243     *    $a = new \PHPSecLib\Math\BigInteger('0x32', 16); // 50 in base-16
 244     *
 245     *    echo $a->toString(); // outputs 50
 246     * ?>
 247     * </code>
 248     *
 249     * @param optional $x base-10 number or base-$base number if $base set.
 250     * @param optional integer $base
 251     * @return \PHPSecLib\Math\BigInteger
 252     * @access public
 253     */
 254    function __construct($x = 0, $base = 10)
 255    {
 256        if ( !defined('MATH_BIGINTEGER_MODE') ) {
 257            switch (true) {
 258                case extension_loaded('gmp'):
 259                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
 260                    break;
 261                case extension_loaded('bcmath'):
 262                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
 263                    break;
 264                default:
 265                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
 266            }
 267        }
 268
 269        if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
 270            // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
 271            ob_start();
 272            @phpinfo();
 273            $content = ob_get_contents();
 274            ob_end_clean();
 275
 276            preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
 277
 278            $versions = array();
 279            if (!empty($matches[1])) {
 280                for ($i = 0; $i < count($matches[1]); $i++) {
 281                    $versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
 282                }
 283            }
 284
 285            // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
 286            switch (true) {
 287                case !isset($versions['Header']):
 288                case !isset($versions['Library']):
 289                case $versions['Header'] == $versions['Library']:
 290                    define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
 291                    break;
 292                default:
 293                    define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
 294            }
 295        }
 296
 297        if (!defined('PHP_INT_SIZE')) {
 298            define('PHP_INT_SIZE', 4);
 299        }
 300
 301        if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {
 302            switch (PHP_INT_SIZE) {
 303                case 8: // use 64-bit integers if int size is 8 bytes
 304                    define('MATH_BIGINTEGER_BASE',       31);
 305                    define('MATH_BIGINTEGER_BASE_FULL',  0x80000000);
 306                    define('MATH_BIGINTEGER_MAX_DIGIT',  0x7FFFFFFF);
 307                    define('MATH_BIGINTEGER_MSB',        0x40000000);
 308                    // 10**9 is the closest we can get to 2**31 without passing it
 309                    define('MATH_BIGINTEGER_MAX10',      1000000000);
 310                    define('MATH_BIGINTEGER_MAX10_LEN',  9);
 311                    // the largest digit that may be used in addition / subtraction
 312                    define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62));
 313                    break;
 314                //case 4: // use 64-bit floats if int size is 4 bytes
 315                default:
 316                    define('MATH_BIGINTEGER_BASE',       26);
 317                    define('MATH_BIGINTEGER_BASE_FULL',  0x4000000);
 318                    define('MATH_BIGINTEGER_MAX_DIGIT',  0x3FFFFFF);
 319                    define('MATH_BIGINTEGER_MSB',        0x2000000);
 320                    // 10**7 is the closest to 2**26 without passing it
 321                    define('MATH_BIGINTEGER_MAX10',      10000000);
 322                    define('MATH_BIGINTEGER_MAX10_LEN',  7);
 323                    // the largest digit that may be used in addition / subtraction
 324                    // we do pow(2, 52) instead of using 4503599627370496 directly because some
 325                    // PHP installations will truncate 4503599627370496.
 326                    define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52));
 327            }
 328        }
 329
 330        switch ( MATH_BIGINTEGER_MODE ) {
 331            case MATH_BIGINTEGER_MODE_GMP:
 332                switch (true) {
 333                    case is_resource($x) && get_resource_type($x) == 'GMP integer':
 334                    // PHP 5.6 switched GMP from using resources to objects
 335                    case is_object($x) && get_class($x) == 'GMP':
 336                        $this->value = $x;
 337                        return;
 338                }
 339                $this->value = gmp_init(0);
 340                break;
 341            case MATH_BIGINTEGER_MODE_BCMATH:
 342                $this->value = '0';
 343                break;
 344            default:
 345                $this->value = array();
 346        }
 347
 348        // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
 349        // '0' is the only value like this per http://php.net/empty
 350        if (empty($x) && (abs($base) != 256 || $x !== '0')) {
 351            return;
 352        }
 353
 354        switch ($base) {
 355            case -256:
 356                if (ord($x[0]) & 0x80) {
 357                    $x = ~$x;
 358                    $this->is_negative = true;
 359                }
 360            case  256:
 361                switch ( MATH_BIGINTEGER_MODE ) {
 362                    case MATH_BIGINTEGER_MODE_GMP:
 363                        $sign = $this->is_negative ? '-' : '';
 364                        $this->value = gmp_init($sign . '0x' . bin2hex($x));
 365                        break;
 366                    case MATH_BIGINTEGER_MODE_BCMATH:
 367                        // round $len to the nearest 4 (thanks, DavidMJ!)
 368                        $len = (strlen($x) + 3) & 0xFFFFFFFC;
 369
 370                        $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
 371
 372                        for ($i = 0; $i < $len; $i+= 4) {
 373                            $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
 374                            $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
 375                        }
 376
 377                        if ($this->is_negative) {
 378                            $this->value = '-' . $this->value;
 379                        }
 380
 381                        break;
 382                    // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
 383                    default:
 384                        while (strlen($x)) {
 385                            $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
 386                        }
 387                }
 388
 389                if ($this->is_negative) {
 390                    if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
 391                        $this->is_negative = false;
 392                    }
 393                    $temp = $this->add(new static('-1'));
 394                    $this->value = $temp->value;
 395                }
 396                break;
 397            case  16:
 398            case -16:
 399                if ($base > 0 && $x[0] == '-') {
 400                    $this->is_negative = true;
 401                    $x = substr($x, 1);
 402                }
 403
 404                $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
 405
 406                $is_negative = false;
 407                if ($base < 0 && hexdec($x[0]) >= 8) {
 408                    $this->is_negative = $is_negative = true;
 409                    $x = bin2hex(~pack('H*', $x));
 410                }
 411
 412                switch ( MATH_BIGINTEGER_MODE ) {
 413                    case MATH_BIGINTEGER_MODE_GMP:
 414                        $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
 415                        $this->value = gmp_init($temp);
 416                        $this->is_negative = false;
 417                        break;
 418                    case MATH_BIGINTEGER_MODE_BCMATH:
 419                        $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
 420                        $temp = new static(pack('H*', $x), 256);
 421                        $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
 422                        $this->is_negative = false;
 423                        break;
 424                    default:
 425                        $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
 426                        $temp = new static(pack('H*', $x), 256);
 427                        $this->value = $temp->value;
 428                }
 429
 430                if ($is_negative) {
 431                    $temp = $this->add(new static('-1'));
 432                    $this->value = $temp->value;
 433                }
 434                break;
 435            case  10:
 436            case -10:
 437                // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
 438                // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
 439                // [^-0-9].*: find any non-numeric characters and then any characters that follow that
 440                $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
 441
 442                switch ( MATH_BIGINTEGER_MODE ) {
 443                    case MATH_BIGINTEGER_MODE_GMP:
 444                        $this->value = gmp_init($x);
 445                        break;
 446                    case MATH_BIGINTEGER_MODE_BCMATH:
 447                        // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
 448                        // results then doing it on '-1' does (modInverse does $x[0])
 449                        $this->value = $x === '-' ? '0' : (string) $x;
 450                        break;
 451                    default:
 452                        $temp = new static();
 453
 454                        $multiplier = new static();
 455                        $multiplier->value = array(MATH_BIGINTEGER_MAX10);
 456
 457                        if ($x[0] == '-') {
 458                            $this->is_negative = true;
 459                            $x = substr($x, 1);
 460                        }
 461
 462                        $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
 463                        while (strlen($x)) {
 464                            $temp = $temp->multiply($multiplier);
 465                            $temp = $temp->add(new static($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
 466                            $x = substr($x, MATH_BIGINTEGER_MAX10_LEN);
 467                        }
 468
 469                        $this->value = $temp->value;
 470                }
 471                break;
 472            case  2: // base-2 support originally implemented by Lluis Pamies - thanks!
 473            case -2:
 474                if ($base > 0 && $x[0] == '-') {
 475                    $this->is_negative = true;
 476                    $x = substr($x, 1);
 477                }
 478
 479                $x = preg_replace('#^([01]*).*#', '$1', $x);
 480                $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
 481
 482                $str = '0x';
 483                while (strlen($x)) {
 484                    $part = substr($x, 0, 4);
 485                    $str.= dechex(bindec($part));
 486                    $x = substr($x, 4);
 487                }
 488
 489                if ($this->is_negative) {
 490                    $str = '-' . $str;
 491                }
 492
 493                $temp = new static($str, 8 * $base); // ie. either -16 or +16
 494                $this->value = $temp->value;
 495                $this->is_negative = $temp->is_negative;
 496
 497                break;
 498            default:
 499                // base not supported, so we'll let $this == 0
 500        }
 501    }
 502
 503    /**
 504     * Converts a BigInteger to a byte string (eg. base-256).
 505     *
 506     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
 507     * saved as two's compliment.
 508     *
 509     * Here's an example:
 510     * <code>
 511     * <?php
 512     *    $a = new \PHPSecLib\Math\BigInteger('65');
 513     *
 514     *    echo $a->toBytes(); // outputs chr(65)
 515     * ?>
 516     * </code>
 517     *
 518     * @param Boolean $twos_compliment
 519     * @return String
 520     * @access public
 521     * @internal Converts a base-2**26 number to base-2**8
 522     */
 523    function toBytes($twos_compliment = false)
 524    {
 525        if ($twos_compliment) {
 526            $comparison = $this->compare(new static());
 527            if ($comparison == 0) {
 528                return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 529            }
 530
 531            $temp = $comparison < 0 ? $this->add(new static(1)) : $this->copy();
 532            $bytes = $temp->toBytes();
 533
 534            if (empty($bytes)) { // eg. if the number we're trying to convert is -1
 535                $bytes = chr(0);
 536            }
 537
 538            if (ord($bytes[0]) & 0x80) {
 539                $bytes = chr(0) . $bytes;
 540            }
 541
 542            return $comparison < 0 ? ~$bytes : $bytes;
 543        }
 544
 545        switch ( MATH_BIGINTEGER_MODE ) {
 546            case MATH_BIGINTEGER_MODE_GMP:
 547                if (gmp_cmp($this->value, gmp_init(0)) == 0) {
 548                    return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 549                }
 550
 551                $temp = gmp_strval(gmp_abs($this->value), 16);
 552                $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
 553                $temp = pack('H*', $temp);
 554
 555                return $this->precision > 0 ?
 556                    substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
 557                    ltrim($temp, chr(0));
 558            case MATH_BIGINTEGER_MODE_BCMATH:
 559                if ($this->value === '0') {
 560                    return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 561                }
 562
 563                $value = '';
 564                $current = $this->value;
 565
 566                if ($current[0] == '-') {
 567                    $current = substr($current, 1);
 568                }
 569
 570                while (bccomp($current, '0', 0) > 0) {
 571                    $temp = bcmod($current, '16777216');
 572                    $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
 573                    $current = bcdiv($current, '16777216', 0);
 574                }
 575
 576                return $this->precision > 0 ?
 577                    substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
 578                    ltrim($value, chr(0));
 579        }
 580
 581        if (!count($this->value)) {
 582            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 583        }
 584        $result = $this->_int2bytes($this->value[count($this->value) - 1]);
 585
 586        $temp = $this->copy();
 587
 588        for ($i = count($temp->value) - 2; $i >= 0; --$i) {
 589            $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
 590            $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
 591        }
 592
 593        return $this->precision > 0 ?
 594            str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
 595            $result;
 596    }
 597
 598    /**
 599     * Converts a BigInteger to a hex string (eg. base-16)).
 600     *
 601     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
 602     * saved as two's compliment.
 603     *
 604     * Here's an example:
 605     * <code>
 606     * <?php
 607     *    $a = new \PHPSecLib\Math\BigInteger('65');
 608     *
 609     *    echo $a->toHex(); // outputs '41'
 610     * ?>
 611     * </code>
 612     *
 613     * @param Boolean $twos_compliment
 614     * @return String
 615     * @access public
 616     * @internal Converts a base-2**26 number to base-2**8
 617     */
 618    function toHex($twos_compliment = false)
 619    {
 620        return bin2hex($this->toBytes($twos_compliment));
 621    }
 622
 623    /**
 624     * Converts a BigInteger to a bit string (eg. base-2).
 625     *
 626     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
 627     * saved as two's compliment.
 628     *
 629     * Here's an example:
 630     * <code>
 631     * <?php
 632     *    $a = new \PHPSecLib\Math\BigInteger('65');
 633     *
 634     *    echo $a->toBits(); // outputs '1000001'
 635     * ?>
 636     * </code>
 637     *
 638     * @param Boolean $twos_compliment
 639     * @return String
 640     * @access public
 641     * @internal Converts a base-2**26 number to base-2**2
 642     */
 643    function toBits($twos_compliment = false)
 644    {
 645        $hex = $this->toHex($twos_compliment);
 646        $bits = '';
 647        for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
 648            $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
 649        }
 650        if ($start) { // hexdec('') == 0
 651            $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
 652        }
 653        $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
 654
 655        if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) {
 656            return '0' . $result;
 657        }
 658
 659        return $result;
 660    }
 661
 662    /**
 663     * Converts a BigInteger to a base-10 number.
 664     *
 665     * Here's an example:
 666     * <code>
 667     * <?php
 668     *    $a = new \PHPSecLib\Math\BigInteger('50');
 669     *
 670     *    echo $a->toString(); // outputs 50
 671     * ?>
 672     * </code>
 673     *
 674     * @return String
 675     * @access public
 676     * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
 677     */
 678    function toString()
 679    {
 680        switch ( MATH_BIGINTEGER_MODE ) {
 681            case MATH_BIGINTEGER_MODE_GMP:
 682                return gmp_strval($this->value);
 683            case MATH_BIGINTEGER_MODE_BCMATH:
 684                if ($this->value === '0') {
 685                    return '0';
 686                }
 687
 688                return ltrim($this->value, '0');
 689        }
 690
 691        if (!count($this->value)) {
 692            return '0';
 693        }
 694
 695        $temp = $this->copy();
 696        $temp->is_negative = false;
 697
 698        $divisor = new static();
 699        $divisor->value = array(MATH_BIGINTEGER_MAX10);
 700        $result = '';
 701        while (count($temp->value)) {
 702            list($temp, $mod) = $temp->divide($divisor);
 703            $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result;
 704        }
 705        $result = ltrim($result, '0');
 706        if (empty($result)) {
 707            $result = '0';
 708        }
 709
 710        if ($this->is_negative) {
 711            $result = '-' . $result;
 712        }
 713
 714        return $result;
 715    }
 716
 717    /**
 718     * Copy an object
 719     *
 720     * PHP5 passes objects by reference while PHP4 passes by value.  As such, we need a function to guarantee
 721     * that all objects are passed by value, when appropriate.  More information can be found here:
 722     *
 723     * {@link http://php.net/language.oop5.basic#51624}
 724     *
 725     * @access public
 726     * @see __clone()
 727     * @return \PHPSecLib\Math\BigInteger
 728     */
 729    function copy()
 730    {
 731        $temp = new static();
 732        $temp->value = $this->value;
 733        $temp->is_negative = $this->is_negative;
 734        $temp->generator = $this->generator;
 735        $temp->precision = $this->precision;
 736        $temp->bitmask = $this->bitmask;
 737        return $temp;
 738    }
 739
 740    /**
 741     *  __toString() magic method
 742     *
 743     * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
 744     * toString().
 745     *
 746     * @access public
 747     * @internal Implemented per a suggestion by Techie-Michael - thanks!
 748     */
 749    function __toString()
 750    {
 751        return $this->toString();
 752    }
 753
 754    /**
 755     * __clone() magic method
 756     *
 757     * Although you can call BigInteger::__toString() directly in PHP5, you cannot call BigInteger::__clone() directly
 758     * in PHP5.  You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
 759     * only syntax of $y = clone $x.  As such, if you're trying to write an application that works on both PHP4 and
 760     * PHP5, call BigInteger::copy(), instead.
 761     *
 762     * @access public
 763     * @see copy()
 764     * @return \PHPSecLib\Math\BigInteger
 765     */
 766    function __clone()
 767    {
 768        return $this->copy();
 769    }
 770
 771    /**
 772     *  __sleep() magic method
 773     *
 774     * Will be called, automatically, when serialize() is called on a BigInteger object.
 775     *
 776     * @see __wakeup()
 777     * @access public
 778     */
 779    function __sleep()
 780    {
 781        $this->hex = $this->toHex(true);
 782        $vars = array('hex');
 783        if ($this->generator != 'mt_rand') {
 784            $vars[] = 'generator';
 785        }
 786        if ($this->precision > 0) {
 787            $vars[] = 'precision';
 788        }
 789        return $vars;
 790
 791    }
 792
 793    /**
 794     *  __wakeup() magic method
 795     *
 796     * Will be called, automatically, when unserialize() is called on a BigInteger object.
 797     *
 798     * @see __sleep()
 799     * @access public
 800     */
 801    function __wakeup()
 802    {
 803        $temp = new static($this->hex, -16);
 804        $this->value = $temp->value;
 805        $this->is_negative = $temp->is_negative;
 806        if ($this->precision > 0) {
 807            // recalculate $this->bitmask
 808            $this->setPrecision($this->precision);
 809        }
 810    }
 811
 812    /**
 813     * Adds two BigIntegers.
 814     *
 815     * Here's an example:
 816     * <code>
 817     * <?php
 818     *    $a = new \PHPSecLib\Math\BigInteger('10');
 819     *    $b = new \PHPSecLib\Math\BigInteger('20');
 820     *
 821     *    $c = $a->add($b);
 822     *
 823     *    echo $c->toString(); // outputs 30
 824     * ?>
 825     * </code>
 826     *
 827     * @param \PHPSecLib\Math\BigInteger $y
 828     * @return \PHPSecLib\Math\BigInteger
 829     * @access public
 830     * @internal Performs base-2**52 addition
 831     */
 832    function add($y)
 833    {
 834        switch ( MATH_BIGINTEGER_MODE ) {
 835            case MATH_BIGINTEGER_MODE_GMP:
 836                $temp = new static();
 837                $temp->value = gmp_add($this->value, $y->value);
 838
 839                return $this->_normalize($temp);
 840            case MATH_BIGINTEGER_MODE_BCMATH:
 841                $temp = new static();
 842                $temp->value = bcadd($this->value, $y->value, 0);
 843
 844                return $this->_normalize($temp);
 845        }
 846
 847        $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
 848
 849        $result = new static();
 850        $result->value = $temp[MATH_BIGINTEGER_VALUE];
 851        $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
 852
 853        return $this->_normalize($result);
 854    }
 855
 856    /**
 857     * Performs addition.
 858     *
 859     * @param Array $x_value
 860     * @param Boolean $x_negative
 861     * @param Array $y_value
 862     * @param Boolean $y_negative
 863     * @return Array
 864     * @access private
 865     */
 866    function _add($x_value, $x_negative, $y_value, $y_negative)
 867    {
 868        $x_size = count($x_value);
 869        $y_size = count($y_value);
 870
 871        if ($x_size == 0) {
 872            return array(
 873                MATH_BIGINTEGER_VALUE => $y_value,
 874                MATH_BIGINTEGER_SIGN => $y_negative
 875            );
 876        } else if ($y_size == 0) {
 877            return array(
 878                MATH_BIGINTEGER_VALUE => $x_value,
 879                MATH_BIGINTEGER_SIGN => $x_negative
 880            );
 881        }
 882
 883        // subtract, if appropriate
 884        if ( $x_negative != $y_negative ) {
 885            if ( $x_value == $y_value ) {
 886                return array(
 887                    MATH_BIGINTEGER_VALUE => array(),
 888                    MATH_BIGINTEGER_SIGN => false
 889                );
 890            }
 891
 892            $temp = $this->_subtract($x_value, false, $y_value, false);
 893            $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
 894                                          $x_negative : $y_negative;
 895
 896            return $temp;
 897        }
 898
 899        if ($x_size < $y_size) {
 900            $size = $x_size;
 901            $value = $y_value;
 902        } else {
 903            $size = $y_size;
 904            $value = $x_value;
 905        }
 906
 907        $value[count($value)] = 0; // just in case the carry adds an extra digit
 908
 909        $carry = 0;
 910        for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
 911            $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
 912            $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
 913            $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
 914
 915            $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
 916
 917            $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
 918            $value[$j] = $temp;
 919        }
 920
 921        if ($j == $size) { // ie. if $y_size is odd
 922            $sum = $x_value[$i] + $y_value[$i] + $carry;
 923            $carry = $sum >= MATH_BIGINTEGER_BASE_FULL;
 924            $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
 925            ++$i; // ie. let $i = $j since we've just done $value[$i]
 926        }
 927
 928        if ($carry) {
 929            for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {
 930                $value[$i] = 0;
 931            }
 932            ++$value[$i];
 933        }
 934
 935        return array(
 936            MATH_BIGINTEGER_VALUE => $this->_trim($value),
 937            MATH_BIGINTEGER_SIGN => $x_negative
 938        );
 939    }
 940
 941    /**
 942     * Subtracts two BigIntegers.
 943     *
 944     * Here's an example:
 945     * <code>
 946     * <?php
 947     *    $a = new \PHPSecLib\Math\BigInteger('10');
 948     *    $b = new \PHPSecLib\Math\BigInteger('20');
 949     *
 950     *    $c = $a->subtract($b);
 951     *
 952     *    echo $c->toString(); // outputs -10
 953     * ?>
 954     * </code>
 955     *
 956     * @param \PHPSecLib\Math\BigInteger $y
 957     * @return \PHPSecLib\Math\BigInteger
 958     * @access public
 959     * @internal Performs base-2**52 subtraction
 960     */
 961    function subtract($y)
 962    {
 963        switch ( MATH_BIGINTEGER_MODE ) {
 964            case MATH_BIGINTEGER_MODE_GMP:
 965                $temp = new static();
 966                $temp->value = gmp_sub($this->value, $y->value);
 967
 968                return $this->_normalize($temp);
 969            case MATH_BIGINTEGER_MODE_BCMATH:
 970                $temp = new static();
 971                $temp->value = bcsub($this->value, $y->value, 0);
 972
 973                return $this->_normalize($temp);
 974        }
 975
 976        $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
 977
 978        $result = new static();
 979        $result->value = $temp[MATH_BIGINTEGER_VALUE];
 980        $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
 981
 982        return $this->_normalize($result);
 983    }
 984
 985    /**
 986     * Performs subtraction.
 987     *
 988     * @param Array $x_value
 989     * @param Boolean $x_negative
 990     * @param Array $y_value
 991     * @param Boolean $y_negative
 992     * @return Array
 993     * @access private
 994     */
 995    function _subtract($x_value, $x_negative, $y_value, $y_negative)
 996    {
 997        $x_size = count($x_value);
 998        $y_size = count($y_value);
 999
1000        if ($x_size == 0) {
1001            return array(
1002                MATH_BIGINTEGER_VALUE => $y_value,
1003                MATH_BIGINTEGER_SIGN => !$y_negative
1004            );
1005        } else if ($y_size == 0) {
1006            return array(
1007                MATH_BIGINTEGER_VALUE => $x_value,
1008                MATH_BIGINTEGER_SIGN => $x_negative
1009            );
1010        }
1011
1012        // add, if appropriate (ie. -$x - +$y or +$x - -$y)
1013        if ( $x_negative != $y_negative ) {
1014            $temp = $this->_add($x_value, false, $y_value, false);
1015            $temp[MATH_BIGINTEGER_SIGN] = $x_negative;
1016
1017            return $temp;
1018        }
1019
1020        $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
1021
1022        if ( !$diff ) {
1023            return array(
1024                MATH_BIGINTEGER_VALUE => array(),
1025                MATH_BIGINTEGER_SIGN => false
1026            );
1027        }
1028
1029        // switch $x and $y around, if appropriate.
1030        if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
1031            $temp = $x_value;
1032            $x_value = $y_value;
1033            $y_value = $temp;
1034
1035            $x_negative = !$x_negative;
1036
1037            $x_size = count($x_value);
1038            $y_size = count($y_value);
1039        }
1040
1041        // at this point, $x_value should be at least as big as - if not bigger than - $y_value
1042
1043        $carry = 0;
1044        for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
1045            $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
1046            $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
1047            $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
1048
1049            $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
1050
1051            $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
1052            $x_value[$j] = $temp;
1053        }
1054
1055        if ($j == $y_size) { // ie. if $y_size is odd
1056            $sum = $x_value[$i] - $y_value[$i] - $carry;
1057            $carry = $sum < 0;
1058            $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
1059            ++$i;
1060        }
1061
1062        if ($carry) {
1063            for (; !$x_value[$i]; ++$i) {
1064                $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
1065            }
1066            --$x_value[$i];
1067        }
1068
1069        return array(
1070            MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
1071            MATH_BIGINTEGER_SIGN => $x_negative
1072        );
1073    }
1074
1075    /**
1076     * Multiplies two BigIntegers
1077     *
1078     * Here's an example:
1079     * <code>
1080     * <?php
1081     *    $a = new \PHPSecLib\Math\BigInteger('10');
1082     *    $b = new \PHPSecLib\Math\BigInteger('20');
1083     *
1084     *    $c = $a->multiply($b);
1085     *
1086     *    echo $c->toString(); // outputs 200
1087     * ?>
1088     * </code>
1089     *
1090     * @param \PHPSecLib\Math\BigInteger $x
1091     * @return \PHPSecLib\Math\BigInteger
1092     * @access public
1093     */
1094    function multiply($x)
1095    {
1096        switch ( MATH_BIGINTEGER_MODE ) {
1097            case MATH_BIGINTEGER_MODE_GMP:
1098                $temp = new static();
1099                $temp->value = gmp_mul($this->value, $x->value);
1100
1101                return $this->_normalize($temp);
1102            case MATH_BIGINTEGER_MODE_BCMATH:
1103                $temp = new static();
1104                $temp->value = bcmul($this->value, $x->value, 0);
1105
1106                return $this->_normalize($temp);
1107        }
1108
1109        $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
1110
1111        $product = new static();
1112        $product->value = $temp[MATH_BIGINTEGER_VALUE];
1113        $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
1114
1115        return $this->_normalize($product);
1116    }
1117
1118    /**
1119     * Performs multiplication.
1120     *
1121     * @param Array $x_value
1122     * @param Boolean $x_negative
1123     * @param Array $y_value
1124     * @param Boolean $y_negative
1125     * @return Array
1126     * @access private
1127     */
1128    function _multiply($x_value, $x_negative, $y_value, $y_negative)
1129    {
1130        //if ( $x_value == $y_value ) {
1131        //    return array(
1132        //        MATH_BIGINTEGER_VALUE => $this->_square($x_value),
1133        //        MATH_BIGINTEGER_SIGN => $x_sign != $y_value
1134        //    );
1135        //}
1136
1137        $x_length = count($x_value);
1138        $y_length = count($y_value);
1139
1140        if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1141            return array(
1142                MATH_BIGINTEGER_VALUE => array(),
1143                MATH_BIGINTEGER_SIGN => false
1144            );
1145        }
1146
1147        return array(
1148            MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1149                $this->_trim($this->_regularMultiply($x_value, $y_value)) :
1150                $this->_trim($this->_karatsuba($x_value, $y_value)),
1151            MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
1152        );
1153    }
1154
1155    /**
1156     * Performs long multiplication on two BigIntegers
1157     *
1158     * Modeled after 'multiply' in MutableBigInteger.java.
1159     *
1160     * @param Array $x_value
1161     * @param Array $y_value
1162     * @return Array
1163     * @access private
1164     */
1165    function _regularMultiply($x_value, $y_value)
1166    {
1167        $x_length = count($x_value);
1168        $y_length = count($y_value);
1169
1170        if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1171            return array();
1172        }
1173
1174        if ( $x_length < $y_length ) {
1175            $temp = $x_value;
1176            $x_value = $y_value;
1177            $y_value = $temp;
1178
1179            $x_length = count($x_value);
1180            $y_length = count($y_value);
1181        }
1182
1183        $product_value = $this->_array_repeat(0, $x_length + $y_length);
1184
1185        // the following for loop could be removed if the for loop following it
1186        // (the one with nested for loops) initially set $i to 0, but
1187        // doing so would also make the result in one set of unnecessary adds,
1188        // since on the outermost loops first pass, $product->value[$k] is going
1189        // to always be 0
1190
1191        $carry = 0;
1192
1193        for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
1194            $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
1195            $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1196            $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1197        }
1198
1199        $product_value[$j] = $carry;
1200
1201        // the above for loop is what the previous comment was talking about.  the
1202        // following for loop is the "one with nested for loops"
1203        for ($i = 1; $i < $y_length; ++$i) {
1204            $carry = 0;
1205
1206            for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
1207                $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
1208                $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1209                $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1210            }
1211
1212            $product_value[$k] = $carry;
1213        }
1214
1215        return $product_value;
1216    }
1217
1218    /**
1219     * Performs Karatsuba multiplication on two BigIntegers
1220     *
1221     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1222     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
1223     *
1224     * @param Array $x_value
1225     * @param Array $y_value
1226     * @return Array
1227     * @access private
1228     */
1229    function _karatsuba($x_value, $y_value)
1230    {
1231        $m = min(count($x_value) >> 1, count($y_value) >> 1);
1232
1233        if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1234            return $this->_regularMultiply($x_value, $y_value);
1235        }
1236
1237        $x1 = array_slice($x_value, $m);
1238        $x0 = array_slice($x_value, 0, $m);
1239        $y1 = array_slice($y_value, $m);
1240        $y0 = array_slice($y_value, 0, $m);
1241
1242        $z2 = $this->_karatsuba($x1, $y1);
1243        $z0 = $this->_karatsuba($x0, $y0);
1244
1245        $z1 = $this->_add($x1, false, $x0, false);
1246        $temp = $this->_add($y1, false, $y0, false);
1247        $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
1248        $temp = $this->_add($z2, false, $z0, false);
1249        $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1250
1251        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1252        $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1253
1254        $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1255        $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
1256
1257        return $xy[MATH_BIGINTEGER_VALUE];
1258    }
1259
1260    /**
1261     * Performs squaring
1262     *
1263     * @param Array $x
1264     * @return Array
1265     * @access private
1266     */
1267    function _square($x = false)
1268    {
1269        return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1270            $this->_trim($this->_baseSquare($x)) :
1271            $this->_trim($this->_karatsubaSquare($x));
1272    }
1273
1274    /**
1275     * Performs traditional squaring on two BigIntegers
1276     *
1277     * Squaring can be done faster than multiplying a number by itself can be.  See
1278     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1279     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
1280     *
1281     * @param Array $value
1282     * @return Array
1283     * @access private
1284     */
1285    function _baseSquare($value)
1286    {
1287        if ( empty($value) ) {
1288            return array();
1289        }
1290        $square_value = $this->_array_repeat(0, 2 * count($value));
1291
1292        for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
1293            $i2 = $i << 1;
1294
1295            $temp = $square_value[$i2] + $value[$i] * $value[$i];
1296            $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1297            $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1298
1299            // note how we start from $i+1 instead of 0 as we do in multiplication.
1300            for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1301                $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
1302                $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1303                $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1304            }
1305
1306            // the following line can yield values larger 2**15.  at this point, PHP should switch
1307            // over to floats.
1308            $square_value[$i + $max_index + 1] = $carry;
1309        }
1310
1311        return $square_value;
1312    }
1313
1314    /**
1315     * Performs Karatsuba "squaring" on two BigIntegers
1316     *
1317     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1318     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
1319     *
1320     * @param Array $value
1321     * @return Array
1322     * @access private
1323     */
1324    function _karatsubaSquare($value)
1325    {
1326        $m = count($value) >> 1;
1327
1328        if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1329            return $this->_baseSquare($value);
1330        }
1331
1332        $x1 = array_slice($value, $m);
1333        $x0 = array_slice($value, 0, $m);
1334
1335        $z2 = $this->_karatsubaSquare($x1);
1336        $z0 = $this->_karatsubaSquare($x0);
1337
1338        $z1 = $this->_add($x1, false, $x0, false);
1339        $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
1340        $temp = $this->_add($z2, false, $z0, false);
1341        $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1342
1343        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1344        $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1345
1346        $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1347        $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
1348
1349        return $xx[MATH_BIGINTEGER_VALUE];
1350    }
1351
1352    /**
1353     * Divides two BigIntegers.
1354     *
1355     * Returns an array whose first element contains the quotient and whose second element contains the
1356     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
1357     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
1358     * and the divisor (basically, the "common residue" is the first positive modulo).
1359     *
1360     * Here's an example:
1361     * <code>
1362     * <?php
1363     *    $a = new \PHPSecLib\Math\BigInteger('10');
1364     *    $b = new \PHPSecLib\Math\BigInteger('20');
1365     *
1366     *    list($quotient, $remainder) = $a->divide($b);
1367     *
1368     *    echo $quotient->toString(); // outputs 0
1369     *    echo "\r\n";
1370     *    echo $remainder->toString(); // outputs 10
1371     * ?>
1372     * </code>
1373     *
1374     * @param \PHPSecLib\Math\BigInteger $y
1375     * @return Array
1376     * @access public
1377     * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
1378     */
1379    function divide($y)
1380    {
1381        switch ( MATH_BIGINTEGER_MODE ) {
1382            case MATH_BIGINTEGER_MODE_GMP:
1383                $quotient = new static();
1384                $remainder = new static();
1385
1386                list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
1387
1388                if (gmp_sign($remainder->value) < 0) {
1389                    $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
1390                }
1391
1392                return array($this->_normalize($quotient), $this->_normalize($remainder));
1393            case MATH_BIGINTEGER_MODE_BCMATH:
1394                $quotient = new static();
1395                $remainder = new static();
1396
1397                $quotient->value = bcdiv($this->value, $y->value, 0);
1398                $remainder->value = bcmod($this->value, $y->value);
1399
1400                if ($remainder->value[0] == '-') {
1401                    $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
1402                }
1403
1404                return array($this->_normalize($quotient), $this->_normalize($remainder));
1405        }
1406
1407        if (count($y->value) == 1) {
1408            list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
1409            $quotient = new static();
1410            $remainder = new static();
1411            $quotient->value = $q;
1412            $remainder->value = array($r);
1413            $quotient->is_negative = $this->is_negative != $y->is_negative;
1414            return array($this->_normalize($quotient), $this->_normalize($remainder));
1415        }
1416
1417        static $zero;
1418        if ( !isset($zero) ) {
1419            $zero = new static();
1420        }
1421
1422        $x = $this->copy();
1423        $y = $y->copy();
1424
1425        $x_sign = $x->is_negative;
1426        $y_sign = $y->is_negative;
1427
1428        $x->is_negative = $y->is_negative = false;
1429
1430        $diff = $x->compare($y);
1431
1432        if ( !$diff ) {
1433            $temp = new static();
1434            $temp->value = array(1);
1435            $temp->is_negative = $x_sign != $y_sign;
1436            return array($this->_normalize($temp), $this->_normalize(new static()));
1437        }
1438
1439        if ( $diff < 0 ) {
1440            // if $x is negative, "add" $y.
1441            if ( $x_sign ) {
1442                $x = $y->subtract($x);
1443            }
1444            return array($this->_normalize(new static()), $this->_normalize($x));
1445        }
1446
1447        // normalize $x and $y as described in HAC 14.23 / 14.24
1448        $msb = $y->value[count($y->value) - 1];
1449        for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {
1450            $msb <<= 1;
1451        }
1452        $x->_lshift($shift);
1453        $y->_lshift($shift);
1454        $y_value = &$y->value;
1455
1456        $x_max = count($x->value) - 1;
1457        $y_max = count($y->value) - 1;
1458
1459        $quotient = new static();
1460        $quotient_value = &$quotient->value;
1461        $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
1462
1463        static $temp, $lhs, $rhs;
1464        if (!isset($temp)) {
1465            $temp = new static();
1466            $lhs =  new static();
1467            $rhs =  new static();
1468        }
1469        $temp_value = &$temp->value;
1470        $rhs_value =  &$rhs->value;
1471
1472        // $temp = $y << ($x_max - $y_max-1) in base 2**26
1473        $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
1474
1475        while ( $x->compare($temp) >= 0 ) {
1476            // calculate the "common residue"
1477            ++$quotient_value[$x_max - $y_max];
1478            $x = $x->subtract($temp);
1479            $x_max = count($x->value) - 1;
1480        }
1481
1482        for ($i = $x_max; $i >= $y_max + 1; --$i) {
1483            $x_value = &$x->value;
1484            $x_window = array(
1485                isset($x_value[$i]) ? $x_value[$i] : 0,
1486                isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
1487                isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
1488            );
1489            $y_window = array(
1490                $y_value[$y_max],
1491                ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
1492            );
1493
1494            $q_index = $i - $y_max - 1;
1495            if ($x_window[0] == $y_window[0]) {
1496                $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
1497            } else {
1498                $quotient_value[$q_index] = $this->_safe_divide(
1499                    $x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1],
1500                    $y_window[0]
1501                );
1502            }
1503
1504            $temp_value = array($y_window[1], $y_window[0]);
1505
1506            $lhs->value = array($quotient_value[$q_index]);
1507            $lhs = $lhs->multiply($temp);
1508
1509            $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
1510
1511            while ( $lhs->compare($rhs) > 0 ) {
1512                --$quotient_value[$q_index];
1513
1514                $lhs->value = array($quotient_value[$q_index]);
1515                $lhs = $lhs->multiply($temp);
1516            }
1517
1518            $adjust = $this->_array_repeat(0, $q_index);
1519            $temp_value = array($quotient_value[$q_index]);
1520            $temp = $temp->multiply($y);
1521            $temp_value = &$temp->value;
1522            $temp_value = array_merge($adjust, $temp_value);
1523
1524            $x = $x->subtract($temp);
1525
1526            if ($x->compare($zero) < 0) {
1527                $temp_value = array_merge($adjust, $y_value);
1528                $x = $x->add($temp);
1529
1530                --$quotient_value[$q_index];
1531            }
1532
1533            $x_max = count($x_value) - 1;
1534        }
1535
1536        // unnormalize the remainder
1537        $x->_rshift($shift);
1538
1539        $quotient->is_negative = $x_sign != $y_sign;
1540
1541        // calculate the "common residue", if appropriate
1542        if ( $x_sign ) {
1543            $y->_rshift($shift);
1544            $x = $y->subtract($x);
1545        }
1546
1547        return array($this->_normalize($quotient), $this->_normalize($x));
1548    }
1549
1550    /**
1551     * Divides a BigInteger by a regular integer
1552     *
1553     * abc / x = a00 / x + b0 / x + c / x
1554     *
1555     * @param Array $dividend
1556     * @param Array $divisor
1557     * @return Array
1558     * @access private
1559     */
1560    function _divide_digit($dividend, $divisor)
1561    {
1562        $carry = 0;
1563        $result = array();
1564
1565        for ($i = count($dividend) - 1; $i >= 0; --$i) {
1566            $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];
1567            $result[$i] = $this->_safe_divide($temp, $divisor);
1568            $carry = (int) ($temp - $divisor * $result[$i]);
1569        }
1570
1571        return array($result, $carry);
1572    }
1573
1574    /**
1575     * Performs modular exponentiation.
1576     *
1577     * Here's an example:
1578     * <code>
1579     * <?php
1580     *    $a = new \PHPSecLib\Math\BigInteger('10');
1581     *    $b = new \PHPSecLib\Math\BigInteger('20');
1582     *    $c = new \PHPSecLib\Math\BigInteger('30');
1583     *
1584     *    $c = $a->modPow($b, $c);
1585     *
1586     *    echo $c->toString(); // outputs 10
1587     * ?>
1588     * </code>
1589     *
1590     * @param \PHPSecLib\Math\BigInteger $e
1591     * @param \PHPSecLib\Math\BigInteger $n
1592     * @return \PHPSecLib\Math\BigInteger
1593     * @access public
1594     * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
1595     *    and although the approach involving repeated squaring does vastly better, it, too, is impractical
1596     *    for our purposes.  The reason being that division - by far the most complicated and time-consuming
1597     *    of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
1598     *
1599     *    Modular reductions resolve this issue.  Although an individual modular reduction takes more time
1600     *    then an individual division, when performed in succession (with the same modulo), they're a lot faster.
1601     *
1602     *    The two most commonly used modular reductions are Barrett and Montgomery reduction.  Montgomery reduction,
1603     *    although faster, only works when the gcd of the modulo and of the base being used is 1.  In RSA, when the
1604     *    base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
1605     *    the product of two odd numbers is odd), but what about when RSA isn't used?
1606     *
1607     *    In contrast, Barrett reduction has no such constraint.  As such, some bigint implementations perform a
1608     *    Barrett reduction after every operation in the modpow function.  Others perform Barrett reductions when the
1609     *    modulo is even and Montgomery reductions when the modulo is odd.  BigInteger.java's modPow method, however,
1610     *    uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
1611     *    the other, a power of two - and recombine them, later.  This is the method that this modPow function uses.
1612     *    {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
1613     */
1614    function modPow($e, $n)
1615    {
1616        $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
1617
1618        if ($e->compare(new static()) < 0) {
1619            $e = $e->abs();
1620
1621            $temp = $this->modInverse($n);
1622            if ($temp === false) {
1623                return false;
1624            }
1625
1626            return $this->_normalize($temp->modPow($e, $n));
1627        }
1628
1629        if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) {
1630            $temp = new static();
1631            $temp->value = gmp_powm($this->value, $e->value, $n->value);
1632
1633            return $this->_normalize($temp);
1634        }
1635
1636        if ($this->compare(new static()) < 0 || $this->compare($n) > 0) {
1637            list(, $temp) = $this->divide($n);
1638            return $temp->modPow($e, $n);
1639        }
1640
1641        if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
1642            $components = array(
1643                'modulus' => $n->toBytes(true),
1644                'publicExponent' => $e->toBytes(true)
1645            );
1646
1647            $components = array(
1648                'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
1649                'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
1650            );
1651
1652            $RSAPublicKey = pack('Ca*a*a*',
1653                48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
1654                $components['modulus'], $components['publicExponent']
1655            );
1656
1657            $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1658            $RSAPublicKey = chr(0) . $RSAPublicKey;
1659            $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
1660
1661            $encapsulated = pack('Ca*a*',
1662                48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
1663            );
1664
1665            $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1666                             chunk_split(base64_encode($encapsulated)) .
1667                             '-----END PUBLIC KEY-----';
1668
1669            $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
1670
1671            if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
1672                return new static($result, 256);
1673            }
1674        }
1675
1676        if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
1677                $temp = new static();
1678                $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
1679
1680                return $this->_normalize($temp);
1681        }
1682
1683        if ( empty($e->value) ) {
1684            $temp = new static();
1685            $temp->value = array(1);
1686            return $this->_normalize($temp);
1687        }
1688
1689        if ( $e->value == array(1) ) {
1690            list(, $temp) = $this->divide($n);
1691            return $this->_normalize($temp);
1692        }
1693
1694        if ( $e->value == array(2) ) {
1695            $temp = new static();
1696            $temp->value = $this->_square($this->value);
1697            list(, $temp) = $temp->divide($n);
1698            return $this->_normalize($temp);
1699        }
1700
1701        return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
1702
1703        // the following code, although not callable, can be run independently of the above code
1704        // although the above code performed better in my benchmarks the following could might
1705        // perform better under different circumstances. in lieu of deleting it it's just been
1706        // made uncallable
1707
1708        // is the modulo odd?
1709        if ( $n->value[0] & 1 ) {
1710            return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
1711        }
1712        // if it's not, it's even
1713
1714        // find the lowest set bit (eg. the max pow of 2 that divides $n)
1715        for ($i = 0; $i < count($n->value); ++$i) {
1716            if ( $n->value[$i] ) {
1717                $temp = decbin($n->value[$i]);
1718                $j = strlen($temp) - strrpos($temp, '1') - 1;
1719                $j+= 26 * $i;
1720                break;
1721            }
1722        }
1723        // at this point, 2^$j * $n/(2^$j) == $n
1724
1725        $mod1 = $n->copy();
1726        $mod1->_rshift($j);
1727        $mod2 = new static();
1728        $mod2->value = array(1);
1729        $mod2->_lshift($j);
1730
1731        $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new static();
1732        $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
1733
1734        $y1 = $mod2->modInverse($mod1);
1735        $y2 = $mod1->modInverse($mod2);
1736
1737        $result = $part1->multiply($mod2);
1738        $result = $result->multiply($y1);
1739
1740        $temp = $part2->multiply($mod1);
1741        $temp = $temp->multiply($y2);
1742
1743        $result = $result->add($temp);
1744        list(, $result) = $result->divide($n);
1745
1746        return $this->_normalize($result);
1747    }
1748
1749    /**
1750     * Performs modular exponentiation.
1751     *
1752     * Alias for modPow().
1753     *
1754     * @param \PHPSecLib\Math\BigInteger $e
1755     * @param \PHPSecLib\Math\BigInteger $n
1756     * @return \PHPSecLib\Math\BigInteger
1757     * @access public
1758     */
1759    function powMod($e, $n)
1760    {
1761        return $this->modPow($e, $n);
1762    }
1763
1764    /**
1765     * Sliding Window k-ary Modular Exponentiation
1766     *
1767     * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
1768     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}.  In a departure from those algorithims,
1769     * however, this function performs a modular reduction after every multiplication and squaring operation.
1770     * As such, this function has the same preconditions that the reductions being used do.
1771     *
1772     * @param \PHPSecLib\Math\BigInteger $e
1773     * @param \PHPSecLib\Math\BigInteger $n
1774     * @param Integer $mode
1775     * @return \PHPSecLib\Math\BigInteger
1776     * @access private
1777     */
1778    function _slidingWindow($e, $n, $mode)
1779    {
1780        static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
1781        //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
1782
1783        $e_value = $e->value;
1784        $e_length = count($e_value) - 1;
1785        $e_bits = decbin($e_value[$e_length]);
1786        for ($i = $e_length - 1; $i >= 0; --$i) {
1787            $e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT);
1788        }
1789
1790        $e_length = strlen($e_bits);
1791
1792        // calculate the appropriate window size.
1793        // $window_size == 3 if $window_ranges is between 25 and 81, for example.
1794        for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);
1795
1796        $n_value = $n->value;
1797
1798        // precompute $this^0 through $this^$window_size
1799        $powers = array();
1800        $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
1801        $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
1802
1803        // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
1804        // in a 1.  ie. it's supposed to be odd.
1805        $temp = 1 << ($window_size - 1);
1806        for ($i = 1; $i < $temp; ++$i) {
1807            $i2 = $i << 1;
1808            $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
1809        }
1810
1811        $result = array(1);
1812        $result = $this->_prepareReduce($result, $n_value, $mode);
1813
1814        for ($i = 0; $i < $e_length; ) {
1815            if ( !$e_bits[$i] ) {
1816                $result = $this->_squareReduce($result, $n_value, $mode);
1817                ++$i;
1818            } else {
1819                for ($j = $window_size - 1; $j > 0; --$j) {
1820                    if ( !empty($e_bits[$i + $j]) ) {
1821                        break;
1822                    }
1823                }
1824
1825                for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
1826                    $result = $this->_squareReduce($result, $n_value, $mode);
1827                }
1828
1829                $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
1830
1831                $i+=$j + 1;
1832            }
1833        }
1834
1835        $temp = new static();
1836        $temp->value = $this->_reduce($result, $n_value, $mode);
1837
1838        return $temp;
1839    }
1840
1841    /**
1842     * Modular reduction
1843     *
1844     * For most $modes this will return the remainder.
1845     *
1846     * @see _slidingWindow()
1847     * @access private
1848     * @param Array $x
1849     * @param Array $n
1850     * @param Integer $mode
1851     * @return Array
1852     */
1853    function _reduce($x, $n, $mode)
1854    {
1855        switch ($mode) {
1856            case MATH_BIGINTEGER_MONTGOMERY:
1857                return $this->_montgomery($x, $n);
1858            case MATH_BIGINTEGER_BARRETT:
1859                return $this->_barrett($x, $n);
1860            case MATH_BIGINTEGER_POWEROF2:
1861                $lhs = new static();
1862                $lhs->value = $x;
1863                $rhs = new static();
1864                $rhs->value = $n;
1865                return $x->_mod2($n);
1866            case MATH_BIGINTEGER_CLASSIC:
1867                $lhs = new static();
1868                $lhs->value = $x;
1869                $rhs = new static();
1870                $rhs->value = $n;
1871                list(, $temp) = $lhs->divide($rhs);
1872                return $temp->value;
1873            case MATH_BIGINTEGER_NONE:
1874                return $x;
1875            default:
1876                // an invalid $mode was provided
1877        }
1878    }
1879
1880    /**
1881     * Modular reduction preperation
1882     *
1883     * @see _slidingWindow()
1884     * @access private
1885     * @param Array $x
1886     * @param Array $n
1887     * @param Integer $mode
1888     * @return Array
1889     */
1890    function _prepareReduce($x, $n, $mode)
1891    {
1892        if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1893            return $this->_prepMontgomery($x, $n);
1894        }
1895        return $this->_reduce($x, $n, $mode);
1896    }
1897
1898    /**
1899     * Modular multiply
1900     *
1901     * @see _slidingWindow()
1902     * @access private
1903     * @param Array $x
1904     * @param Array $y
1905     * @param Array $n
1906     * @param Integer $mode
1907     * @return Array
1908     */
1909    function _multiplyReduce($x, $y, $n, $mode)
1910    {
1911        if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1912            return $this->_montgomeryMultiply($x, $y, $n);
1913        }
1914        $temp = $this->_multiply($x, false, $y, false);
1915        return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
1916    }
1917
1918    /**
1919     * Modular square
1920     *
1921     * @see _slidingWindow()
1922     * @access private
1923     * @param Array $x
1924     * @param Array $n
1925     * @param Integer $mode
1926     * @return Array
1927     */
1928    function _squareReduce($x, $n, $mode)
1929    {
1930        if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1931            return $this->_montgomeryMultiply($x, $x, $n);
1932        }
1933        return $this->_reduce($this->_square($x), $n, $mode);
1934    }
1935
1936    /**
1937     * Modulos for Powers of Two
1938     *
1939     * Calculates $x%$n, where $n = 2**$e, for some $e.  Since this is basically the same as doing $x & ($n-1),
1940     * we'll just use this function as a wrapper for doing that.
1941     *
1942     * @see _slidingWindow()
1943     * @access private
1944     * @param \PHPSecLib\Math\BigInteger
1945     * @return \PHPSecLib\Math\BigInteger
1946     */
1947    function _mod2($n)
1948    {
1949        $temp = new static();
1950        $temp->value = array(1);
1951        return $this->bitwise_and($n->subtract($temp));
1952    }
1953
1954    /**
1955     * Barrett Modular Reduction
1956     *
1957     * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
1958     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information.  Modified slightly,
1959     * so as not to require negative numbers (initially, this script didn't support negative numbers).
1960     *
1961     * Employs "folding", as described at
1962     * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}.  To quote from
1963     * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
1964     *
1965     * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
1966     * usable on account of (1) its not using reasonable radix points as discussed in
1967     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
1968     * radix points, it only works when there are an even number of digits in the denominator.  The reason for (2) is that
1969     * (x >> 1) + (x >> 1) != x / 2 + x / 2.  If x is even, they're the same, but if x is odd, they're not.  See the in-line
1970     * comments for details.
1971     *
1972     * @see _slidingWindow()
1973     * @access private
1974     * @param Array $n
1975     * @param Array $m
1976     * @return Array
1977     */
1978    function _barrett($n, $m)
1979    {
1980        static $cache = array(
1981            MATH_BIGINTEGER_VARIABLE => array(),
1982            MATH_BIGINTEGER_DATA => array()
1983        );
1984
1985        $m_length = count($m);
1986
1987        // if ($this->_compare($n, $this->_square($m)) >= 0) {
1988        if (count($n) > 2 * $m_length) {
1989            $lhs = new static();
1990            $rhs = new static();
1991            $lhs->value = $n;
1992            $rhs->value = $m;
1993            list(, $temp) = $lhs->divide($rhs);
1994            return $temp->value;
1995        }
1996
1997        // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
1998        if ($m_length < 5) {
1999            return $this->_regularBarrett($n, $m);
2000        }
2001
2002        // n = 2 * m.length
2003
2004        if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2005            $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2006            $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
2007
2008            $lhs = new static();
2009            $lhs_value = &$lhs->value;
2010            $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
2011            $lhs_value[] = 1;
2012            $rhs = new static();
2013            $rhs->value = $m;
2014
2015            list($u, $m1) = $lhs->divide($rhs);
2016            $u = $u->value;
2017            $m1 = $m1->value;
2018
2019            $cache[MATH_BIGINTEGER_DATA][] = array(
2020                'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
2021                'm1'=> $m1 // m.length
2022            );
2023        } else {
2024            extract($cache[MATH_BIGINTEGER_DATA][$key]);
2025        }
2026
2027        $cutoff = $m_length + ($m_length >> 1);
2028        $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
2029        $msd = array_slice($n, $cutoff);    // m.length >> 1
2030        $lsd = $this->_trim($lsd);
2031        $temp = $this->_multiply($msd, false, $m1, false);
2032        $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
2033
2034        if ($m_length & 1) {
2035            return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
2036        }
2037
2038        // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
2039        $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
2040        // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
2041        // if odd:  ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
2042        $temp = $this->_multiply($temp, false, $u, false);
2043        // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
2044        // if odd:  (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
2045        $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
2046        // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
2047        // if odd:  (m.length - (m.length >> 1)) + m.length     = 2 * m.length - (m.length >> 1)
2048        $temp = $this->_multiply($temp, false, $m, false);
2049
2050        // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
2051        // number from a m.length + (m.length >> 1) + 1 digit number.  ie. there'd be an extra digit and the while loop
2052        // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
2053
2054        $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2055
2056        while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
2057            $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
2058        }
2059
2060        return $result[MATH_BIGINTEGER_VALUE];
2061    }
2062
2063    /**
2064     * (Regular) Barrett Modular Reduction
2065     *
2066     * For numbers with more than four digits BigInteger::_barrett() is faster.  The difference between that and this
2067     * is that this function does not fold the denominator into a smaller form.
2068     *
2069     * @see _slidingWindow()
2070     * @access private
2071     * @param Array $x
2072     * @param Array $n
2073     * @return Array
2074     */
2075    function _regularBarrett($x, $n)
2076    {
2077        static $cache = array(
2078            MATH_BIGINTEGER_VARIABLE => array(),
2079            MATH_BIGINTEGER_DATA => array()
2080        );
2081
2082        $n_length = count($n);
2083
2084        if (count($x) > 2 * $n_length) {
2085            $lhs = new static();
2086            $rhs = new static();
2087            $lhs->value = $x;
2088            $rhs->value = $n;
2089            list(, $temp) = $lhs->divide($rhs);
2090            return $temp->value;
2091        }
2092
2093        if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2094            $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2095            $cache[MATH_BIGINTEGER_VARIABLE][] = $n;
2096            $lhs = new static();
2097            $lhs_value = &$lhs->value;
2098            $lhs_value = $this->_array_repeat(0, 2 * $n_length);
2099            $lhs_value[] = 1;
2100            $rhs = new static();
2101            $rhs->value = $n;
2102            list($temp, ) = $lhs->divide($rhs); // m.length
2103            $cache[MATH_BIGINTEGER_DATA][] = $temp->value;
2104        }
2105
2106        // 2 * m.length - (m.length - 1) = m.length + 1
2107        $temp = array_slice($x, $n_length - 1);
2108        // (m.length + 1) + m.length = 2 * m.length + 1
2109        $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
2110        // (2 * m.length + 1) - (m.length - 1) = m.length + 2
2111        $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);
2112
2113        // m.length + 1
2114        $result = array_slice($x, 0, $n_length + 1);
2115        // m.length + 1
2116        $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
2117        // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
2118
2119        if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
2120            $corrector_value = $this->_array_repeat(0, $n_length + 1);
2121            $corrector_value[count($corrector_value)] = 1;
2122            $result = $this->_add($result, false, $corrector_value, false);
2123            $result = $result[MATH_BIGINTEGER_VALUE];
2124        }
2125
2126        // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
2127        $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
2128        while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
2129            $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
2130        }
2131
2132        return $result[MATH_BIGINTEGER_VALUE];
2133    }
2134
2135    /**
2136     * Performs long multiplication up to $stop digits
2137     *
2138     * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
2139     *
2140     * @see _regularBarrett()
2141     * @param Array $x_value
2142     * @param Boolean $x_negative
2143     * @param Array $y_value
2144     * @param Boolean $y_negative
2145     * @param Integer $stop
2146     * @return Array
2147     * @access private
2148     */
2149    function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
2150    {
2151        $x_length = count($x_value);
2152        $y_length = count($y_value);
2153
2154        if ( !$x_length || !$y_length ) { // a 0 is being multiplied
2155            return array(
2156                MATH_BIGINTEGER_VALUE => array(),
2157                MATH_BIGINTEGER_SIGN => false
2158            );
2159        }
2160
2161        if ( $x_length < $y_length ) {
2162            $temp = $x_value;
2163            $x_value = $y_value;
2164            $y_value = $temp;
2165
2166            $x_length = count($x_value);
2167            $y_length = count($y_value);
2168        }
2169
2170        $product_value = $this->_array_repeat(0, $x_length + $y_length);
2171
2172        // the following for loop could be removed if the for loop following it
2173        // (the one with nested for loops) initially set $i to 0, but
2174        // doing so would also make the result in one set of unnecessary adds,
2175        // since on the outermost loops first pass, $product->value[$k] is going
2176        // to always be 0
2177
2178        $carry = 0;
2179
2180        for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
2181            $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
2182            $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2183            $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
2184        }
2185
2186        if ($j < $stop) {
2187            $product_value[$j] = $carry;
2188        }
2189
2190        // the above for loop is what the previous comment was talking about.  the
2191        // following for loop is the "one with nested for loops"
2192
2193        for ($i = 1; $i < $y_length; ++$i) {
2194            $carry = 0;
2195
2196            for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
2197                $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
2198                $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2199                $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
2200            }
2201
2202            if ($k < $stop) {
2203                $product_value[$k] = $carry;
2204            }
2205        }
2206
2207        return array(
2208            MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
2209            MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
2210        );
2211    }
2212
2213    /**
2214     * Montgomery Modular Reduction
2215     *
2216     * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
2217     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
2218     * improved upon (basically, by using the comba method).  gcd($n, 2) must be equal to one for this function
2219     * to work correctly.
2220     *
2221     * @see _prepMontgomery()
2222     * @see _slidingWindow()
2223     * @access private
2224     * @param Array $x
2225     * @param Array $n
2226     * @return Array
2227     */
2228    function _montgomery($x, $n)
2229    {
2230        static $cache = array(
2231            MATH_BIGINTEGER_VARIABLE => array(),
2232            MATH_BIGINTEGER_DATA => array()
2233        );
2234
2235        if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2236            $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2237            $cache[MATH_BIGINTEGER_VARIABLE][] = $x;
2238            $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
2239        }
2240
2241        $k = count($n);
2242
2243        $result = array(MATH_BIGINTEGER_VALUE => $x);
2244
2245        for ($i = 0; $i < $k; ++$i) {
2246            $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
2247            $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2248            $temp = $this->_regularMultiply(array($temp), $n);
2249            $temp = array_merge($this->_array_repeat(0, $i), $temp);
2250            $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
2251        }
2252
2253        $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);
2254
2255        if ($this->_compare($result, false, $n, false) >= 0) {
2256            $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
2257        }
2258
2259        return $result[MATH_BIGINTEGER_VALUE];
2260    }
2261
2262    /**
2263     * Montgomery Multiply
2264     *
2265     * Interleaves the montgomery reduction and long multiplication algorithms together as described in
2266     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
2267     *
2268     * @see _prepMontgomery()
2269     * @see _montgomery()
2270     * @access private
2271     * @param Array $x
2272     * @param Array $y
2273     * @param Array $m
2274     * @return Array
2275     */
2276    function _montgomeryMultiply($x, $y, $m)
2277    {
2278        $temp = $this->_multiply($x, false, $y, false);
2279        return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
2280
2281        // the following code, although not callable, can be run independently of the above code
2282        // although the above code performed better in my benchmarks the following could might
2283        // perform better under different circumstances. in lieu of deleting it it's just been
2284        // made uncallable
2285
2286        static $cache = array(
2287            MATH_BIGINTEGER_VARIABLE => array(),
2288            MATH_BIGINTEGER_DATA => array()
2289        );
2290
2291        if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2292            $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2293            $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
2294            $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
2295        }
2296
2297        $n = max(count($x), count($y), count($m));
2298        $x = array_pad($x, $n, 0);
2299        $y = array_pad($y, $n, 0);
2300        $m = array_pad($m, $n, 0);
2301        $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
2302        for ($i = 0; $i < $n; ++$i) {
2303            $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
2304            $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2305            $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
2306            $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2307            $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
2308            $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2309            $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
2310        }
2311        if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
2312            $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
2313        }
2314        return $a[MATH_BIGINTEGER_VALUE];
2315    }
2316
2317    /**
2318     * Prepare a number for use in Montgomery Modular Reductions
2319     *
2320     * @see _montgomery()
2321     * @see _slidingWindow()
2322     * @access private
2323     * @param Array $x
2324     * @param Array $n
2325     * @return Array
2326     */
2327    function _prepMontgomery($x, $n)
2328    {
2329        $lhs = new static();
2330        $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
2331        $rhs = new static();
2332        $rhs->value = $n;
2333
2334        list(, $temp) = $lhs->divide($rhs);
2335        return $temp->value;
2336    }
2337
2338    /**
2339     * Modular Inverse of a number mod 2**26 (eg. 67108864)
2340     *
2341     * Based off of the bnpInvDigit function implemented and justified in the following URL:
2342     *
2343     * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
2344     *
2345     * The following URL provides more info:
2346     *
2347     * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
2348     *
2349     * As for why we do all the bitmasking...  strange things can happen when converting from floats to ints. For
2350     * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
2351     * int(-2147483648).  To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
2352     * auto-converted to floats.  The outermost bitmask is present because without it, there's no guarantee that
2353     * the "residue" returned would be the so-called "common residue".  We use fmod, in the last step, because the
2354     * maximum possible $x is 26 bits and the maximum $result is 16 bits.  Thus, we have to be able to handle up to
2355     * 40 bits, which only 64-bit floating points will support.
2356     *
2357     * Thanks to Pedro Gimeno Fortea for input!
2358     *
2359     * @see _montgomery()
2360     * @access private
2361     * @param Array $x
2362     * @return Integer
2363     */
2364    function _modInverse67108864($x) // 2**26 == 67,108,864
2365    {
2366        $x = -$x[0];
2367        $result = $x & 0x3; // x**-1 mod 2**2
2368        $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
2369        $result = ($result * (2 - ($x & 0xFF) * $result))  & 0xFF; // x**-1 mod 2**8
2370        $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
2371        $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26
2372        return $result & MATH_BIGINTEGER_MAX_DIGIT;
2373    }
2374
2375    /**
2376     * Calculates modular inverses.
2377     *
2378     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
2379     *
2380     * Here's an example:
2381     * <code>
2382     * <?php
2383     *    $a = new \PHPSecLib\Math\BigInteger(30);
2384     *    $b = new \PHPSecLib\Math\BigInteger(17);
2385     *
2386     *    $c = $a->modInverse($b);
2387     *    echo $c->toString(); // outputs 4
2388     *
2389     *    echo "\r\n";
2390     *
2391     *    $d = $a->multiply($c);
2392     *    list(, $d) = $d->divide($b);
2393     *    echo $d; // outputs 1 (as per the definition of modular inverse)
2394     * ?>
2395     * </code>
2396     *
2397     * @param \PHPSecLib\Math\BigInteger $n
2398     * @return mixed false, if no modular inverse exists, \PHPSecLib\Math\BigInteger, otherwise.
2399     * @access public
2400     * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
2401     */
2402    function modInverse($n)
2403    {
2404        switch ( MATH_BIGINTEGER_MODE ) {
2405            case MATH_BIGINTEGER_MODE_GMP:
2406                $temp = new static();
2407                $temp->value = gmp_invert($this->value, $n->value);
2408
2409                return ( $temp->value === false ) ? false : $this->_normalize($temp);
2410        }
2411
2412        static $zero, $one;
2413        if (!isset($zero)) {
2414            $zero = new static();
2415            $one = new static(1);
2416        }
2417
2418        // $x mod -$n == $x mod $n.
2419        $n = $n->abs();
2420
2421        if ($this->compare($zero) < 0) {
2422            $temp = $this->abs();
2423            $temp = $temp->modInverse($n);
2424            return $this->_normalize($n->subtract($temp));
2425        }
2426
2427        extract($this->extendedGCD($n));
2428
2429        if (!$gcd->equals($one)) {
2430            return false;
2431        }
2432
2433        $x = $x->compare($zero) < 0 ? $x->add($n) : $x;
2434
2435        return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
2436    }
2437
2438    /**
2439     * Calculates the greatest common divisor and Bezout's identity.
2440     *
2441     * Say you have 693 and 609.  The GCD is 21.  Bezout's identity states that there exist integers x and y such that
2442     * 693*x + 609*y == 21.  In point of fact, there are actually an infinite number of x and y combinations and which
2443     * combination is returned is dependant upon which mode is in use.  See
2444     * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
2445     *
2446     * Here's an example:
2447     * <code>
2448     * <?php
2449     *    $a = new \PHPSecLib\Math\BigInteger(693);
2450     *    $b = new \PHPSecLib\Math\BigInteger(609);
2451     *
2452     *    extract($a->extendedGCD($b));
2453     *
2454     *    echo $gcd->toString() . "\r\n"; // outputs 21
2455     *    echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
2456     * ?>
2457     * </code>
2458     *
2459     * @param \PHPSecLib\Math\BigInteger $n
2460     * @return \PHPSecLib\Math\BigInteger
2461     * @access public
2462     * @internal Calculates the GCD using the binary xGCD algorithim described in
2463     *    {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}.  As the text above 14.61 notes,
2464     *    the more traditional algorithim requires "relatively costly multiple-precision divisions".
2465     */
2466    function extendedGCD($n)
2467    {
2468        switch ( MATH_BIGINTEGER_MODE ) {
2469            case MATH_BIGINTEGER_MODE_GMP:
2470                extract(gmp_gcdext($this->value, $n->value));
2471
2472                return array(
2473                    'gcd' => $this->_normalize(new static($g)),
2474                    'x'   => $this->_normalize(new static($s)),
2475                    'y'   => $this->_normalize(new static($t))
2476                );
2477            case MATH_BIGINTEGER_MODE_BCMATH:
2478                // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
2479                // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway.  as is,
2480                // the basic extended euclidean algorithim is what we're using.
2481
2482                $u = $this->value;
2483                $v = $n->value;
2484
2485                $a = '1';
2486                $b = '0';
2487                $c = '0';
2488                $d = '1';
2489
2490                while (bccomp($v, '0', 0) != 0) {
2491                    $q = bcdiv($u, $v, 0);
2492
2493                    $temp = $u;
2494                    $u = $v;
2495                    $v = bcsub($temp, bcmul($v, $q, 0), 0);
2496
2497                    $temp = $a;
2498                    $a = $c;
2499                    $c = bcsub($temp, bcmul($a, $q, 0), 0);
2500
2501                    $temp = $b;
2502                    $b = $d;
2503                    $d = bcsub($temp, bcmul($b, $q, 0), 0);
2504                }
2505
2506                return array(
2507                    'gcd' => $this->_normalize(new static($u)),
2508                    'x'   => $this->_normalize(new static($a)),
2509                    'y'   => $this->_normalize(new static($b))
2510                );
2511        }
2512
2513        $y = $n->copy();
2514        $x = $this->copy();
2515        $g = new static();
2516        $g->value = array(1);
2517
2518        while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {
2519            $x->_rshift(1);
2520            $y->_rshift(1);
2521            $g->_lshift(1);
2522        }
2523
2524        $u = $x->copy();
2525        $v = $y->copy();
2526
2527        $a = new static();
2528        $b = new static();
2529        $c = new static();
2530        $d = new static();
2531
2532        $a->value = $d->value = $g->value = array(1);
2533        $b->value = $c->value = array();
2534
2535        while ( !empty($u->value) ) {
2536            while ( !($u->value[0] & 1) ) {
2537                $u->_rshift(1);
2538                if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) {
2539                    $a = $a->add($y);
2540                    $b = $b->subtract($x);
2541                }
2542                $a->_rshift(1);
2543                $b->_rshift(1);
2544            }
2545
2546            while ( !($v->value[0] & 1) ) {
2547                $v->_rshift(1);
2548                if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) {
2549                    $c = $c->add($y);
2550                    $d = $d->subtract($x);
2551                }
2552                $c->_rshift(1);
2553                $d->_rshift(1);
2554            }
2555
2556            if ($u->compare($v) >= 0) {
2557                $u = $u->subtract($v);
2558                $a = $a->subtract($c);
2559                $b = $b->subtract($d);
2560            } else {
2561                $v = $v->subtract($u);
2562                $c = $c->subtract($a);
2563                $d = $d->subtract($b);
2564            }
2565        }
2566
2567        return array(
2568            'gcd' => $this->_normalize($g->multiply($v)),
2569            'x'   => $this->_normalize($c),
2570            'y'   => $this->_normalize($d)
2571        );
2572    }
2573
2574    /**
2575     * Calculates the greatest common divisor
2576     *
2577     * Say you have 693 and 609.  The GCD is 21.
2578     *
2579     * Here's an example:
2580     * <code>
2581     * <?php
2582     *    $a = new \PHPSecLib\Math\BigInteger(693);
2583     *    $b = new \PHPSecLib\Math\BigInteger(609);
2584     *
2585     *    $gcd = a->extendedGCD($b);
2586     *
2587     *    echo $gcd->toString() . "\r\n"; // outputs 21
2588     * ?>
2589     * </code>
2590     *
2591     * @param \PHPSecLib\Math\BigInteger $n
2592     * @return \PHPSecLib\Math\BigInteger
2593     * @access public
2594     */
2595    function gcd($n)
2596    {
2597        extract($this->extendedGCD($n));
2598        return $gcd;
2599    }
2600
2601    /**
2602     * Absolute value.
2603     *
2604     * @return \PHPSecLib\Math\BigInteger
2605     * @access public
2606     */
2607    function abs()
2608    {
2609        $temp = new static();
2610
2611        switch ( MATH_BIGINTEGER_MODE ) {
2612            case MATH_BIGINTEGER_MODE_GMP:
2613                $temp->value = gmp_abs($this->value);
2614                break;
2615            case MATH_BIGINTEGER_MODE_BCMATH:
2616                $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
2617                break;
2618            default:
2619                $temp->value = $this->value;
2620        }
2621
2622        return $temp;
2623    }
2624
2625    /**
2626     * Compares two numbers.
2627     *
2628     * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this is
2629     * demonstrated thusly:
2630     *
2631     * $x  > $y: $x->compare($y)  > 0
2632     * $x  < $y: $x->compare($y)  < 0
2633     * $x == $y: $x->compare($y) == 0
2634     *
2635     * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
2636     *
2637     * @param \PHPSecLib\Math\BigInteger $y
2638     * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
2639     * @access public
2640     * @see equals()
2641     * @internal Could return $this->subtract($x), but that's not as fast as what we do do.
2642     */
2643    function compare($y)
2644    {
2645        switch ( MATH_BIGINTEGER_MODE ) {
2646            case MATH_BIGINTEGER_MODE_GMP:
2647                return gmp_cmp($this->value, $y->value);
2648            case MATH_BIGINTEGER_MODE_BCMATH:
2649                return bccomp($this->value, $y->value, 0);
2650        }
2651
2652        return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
2653    }
2654
2655    /**
2656     * Compares two numbers.
2657     *
2658     * @param Array $x_value
2659     * @param Boolean $x_negative
2660     * @param Array $y_value
2661     * @param Boolean $y_negative
2662     * @return Integer
2663     * @see compare()
2664     * @access private
2665     */
2666    function _compare($x_value, $x_negative, $y_value, $y_negative)
2667    {
2668        if ( $x_negative != $y_negative ) {
2669            return ( !$x_negative && $y_negative ) ? 1 : -1;
2670        }
2671
2672        $result = $x_negative ? -1 : 1;
2673
2674        if ( count($x_value) != count($y_value) ) {
2675            return ( count($x_value) > count($y_value) ) ? $result : -$result;
2676        }
2677        $size = max(count($x_value), count($y_value));
2678
2679        $x_value = array_pad($x_value, $size, 0);
2680        $y_value = array_pad($y_value, $size, 0);
2681
2682        for ($i = count($x_value) - 1; $i >= 0; --$i) {
2683            if ($x_value[$i] != $y_value[$i]) {
2684                return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;
2685            }
2686        }
2687
2688        return 0;
2689    }
2690
2691    /**
2692     * Tests the equality of two numbers.
2693     *
2694     * If you need to see if one number is greater than or less than another number, use BigInteger::compare()
2695     *
2696     * @param \PHPSecLib\Math\BigInteger $x
2697     * @return Boolean
2698     * @access public
2699     * @see compare()
2700     */
2701    function equals($x)
2702    {
2703        switch ( MATH_BIGINTEGER_MODE ) {
2704            case MATH_BIGINTEGER_MODE_GMP:
2705                return gmp_cmp($this->value, $x->value) == 0;
2706            default:
2707                return $this->value === $x->value && $this->is_negative == $x->is_negative;
2708        }
2709    }
2710
2711    /**
2712     * Set Precision
2713     *
2714     * Some bitwise operations give different results depending on the precision being used.  Examples include left
2715     * shift, not, and rotates.
2716     *
2717     * @param Integer $bits
2718     * @access public
2719     */
2720    function setPrecision($bits)
2721    {
2722        $this->precision = $bits;
2723        if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {
2724            $this->bitmask = new static(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
2725        } else {
2726            $this->bitmask = new static(bcpow('2', $bits, 0));
2727        }
2728
2729        $temp = $this->_normalize($this);
2730        $this->value = $temp->value;
2731    }
2732
2733    /**
2734     * Logical And
2735     *
2736     * @param \PHPSecLib\Math\BigInteger $x
2737     * @access public
2738     * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2739     * @return \PHPSecLib\Math\BigInteger
2740     */
2741    function bitwise_and($x)
2742    {
2743        switch ( MATH_BIGINTEGER_MODE ) {
2744            case MATH_BIGINTEGER_MODE_GMP:
2745                $temp = new static();
2746                $temp->value = gmp_and($this->value, $x->value);
2747
2748                return $this->_normalize($temp);
2749            case MATH_BIGINTEGER_MODE_BCMATH:
2750                $left = $this->toBytes();
2751                $right = $x->toBytes();
2752
2753                $length = max(strlen($left), strlen($right));
2754
2755                $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2756                $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2757
2758                return $this->_normalize(new static($left & $right, 256));
2759        }
2760
2761        $result = $this->copy();
2762
2763        $length = min(count($x->value), count($this->value));
2764
2765        $result->value = array_slice($result->value, 0, $length);
2766
2767        for ($i = 0; $i < $length; ++$i) {
2768            $result->value[$i]&= $x->value[$i];
2769        }
2770
2771        return $this->_normalize($result);
2772    }
2773
2774    /**
2775     * Logical Or
2776     *
2777     * @param \PHPSecLib\Math\BigInteger $x
2778     * @access public
2779     * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2780     * @return \PHPSecLib\Math\BigInteger
2781     */
2782    function bitwise_or($x)
2783    {
2784        switch ( MATH_BIGINTEGER_MODE ) {
2785            case MATH_BIGINTEGER_MODE_GMP:
2786                $temp = new static();
2787                $temp->value = gmp_or($this->value, $x->value);
2788
2789                return $this->_normalize($temp);
2790            case MATH_BIGINTEGER_MODE_BCMATH:
2791                $left = $this->toBytes();
2792                $right = $x->toBytes();
2793
2794                $length = max(strlen($left), strlen($right));
2795
2796                $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2797                $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2798
2799                return $this->_normalize(new static($left | $right, 256));
2800        }
2801
2802        $length = max(count($this->value), count($x->value));
2803        $result = $this->copy();
2804        $result->value = array_pad($result->value, $length, 0);
2805        $x->value = array_pad($x->value, $length, 0);
2806
2807        for ($i = 0; $i < $length; ++$i) {
2808            $result->value[$i]|= $x->value[$i];
2809        }
2810
2811        return $this->_normalize($result);
2812    }
2813
2814    /**
2815     * Logical Exclusive-Or
2816     *
2817     * @param \PHPSecLib\Math\BigInteger $x
2818     * @access public
2819     * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2820     * @return \PHPSecLib\Math\BigInteger
2821     */
2822    function bitwise_xor($x)
2823    {
2824        switch ( MATH_BIGINTEGER_MODE ) {
2825            case MATH_BIGINTEGER_MODE_GMP:
2826                $temp = new static();
2827                $temp->value = gmp_xor($this->value, $x->value);
2828
2829                return $this->_normalize($temp);
2830            case MATH_BIGINTEGER_MODE_BCMATH:
2831                $left = $this->toBytes();
2832                $right = $x->toBytes();
2833
2834                $length = max(strlen($left), strlen($right));
2835
2836                $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2837                $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2838
2839                return $this->_normalize(new static($left ^ $right, 256));
2840        }
2841
2842        $length = max(count($this->value), count($x->value));
2843        $result = $this->copy();
2844        $result->value = array_pad($result->value, $length, 0);
2845        $x->value = array_pad($x->value, $length, 0);
2846
2847        for ($i = 0; $i < $length; ++$i) {
2848            $result->value[$i]^= $x->value[$i];
2849        }
2850
2851        return $this->_normalize($result);
2852    }
2853
2854    /**
2855     * Logical Not
2856     *
2857     * @access public
2858     * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2859     * @return \PHPSecLib\Math\BigInteger
2860     */
2861    function bitwise_not()
2862    {
2863        // calculuate "not" without regard to $this->precision
2864        // (will always result in a smaller number.  ie. ~1 isn't 1111 1110 - it's 0)
2865        $temp = $this->toBytes();
2866        $pre_msb = decbin(ord($temp[0]));
2867        $temp = ~$temp;
2868        $msb = decbin(ord($temp[0]));
2869        if (strlen($msb) == 8) {
2870            $msb = substr($msb, strpos($msb, '0'));
2871        }
2872        $temp[0] = chr(bindec($msb));
2873
2874        // see if we need to add extra leading 1's
2875        $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
2876        $new_bits = $this->precision - $current_bits;
2877        if ($new_bits <= 0) {
2878            return $this->_normalize(new static($temp, 256));
2879        }
2880
2881        // generate as many leading 1's as we need to.
2882        $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
2883        $this->_base256_lshift($leading_ones, $current_bits);
2884
2885        $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);
2886
2887        return $this->_normalize(new static($leading_ones | $temp, 256));
2888    }
2889
2890    /**
2891     * Logical Right Shift
2892     *
2893     * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
2894     *
2895     * @param Integer $shift
2896     * @return \PHPSecLib\Math\BigInteger
2897     * @access public
2898     * @internal The only version that yields any speed increases is the internal version.
2899     */
2900    function bitwise_rightShift($shift)
2901    {
2902        $temp = new static();
2903
2904        switch ( MATH_BIGINTEGER_MODE ) {
2905            case MATH_BIGINTEGER_MODE_GMP:
2906                static $two;
2907
2908                if (!isset($two)) {
2909                    $two = gmp_init('2');
2910                }
2911
2912                $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
2913
2914                break;
2915            case MATH_BIGINTEGER_MODE_BCMATH:
2916                $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
2917
2918                break;
2919            default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
2920                     // and I don't want to do that...
2921                $temp->value = $this->value;
2922                $temp->_rshift($shift);
2923        }
2924
2925        return $this->_normalize($temp);
2926    }
2927
2928    /**
2929     * Logical Left Shift
2930     *
2931     * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
2932     *
2933     * @param Integer $shift
2934     * @return \PHPSecLib\Math\BigInteger
2935     * @access public
2936     * @internal The only version that yields any speed increases is the internal version.
2937     */
2938    function bitwise_leftShift($shift)
2939    {
2940        $temp = new static();
2941
2942        switch ( MATH_BIGINTEGER_MODE ) {
2943            case MATH_BIGINTEGER_MODE_GMP:
2944                static $two;
2945
2946                if (!isset($two)) {
2947                    $two = gmp_init('2');
2948                }
2949
2950                $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
2951
2952                break;
2953            case MATH_BIGINTEGER_MODE_BCMATH:
2954                $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
2955
2956                break;
2957            default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
2958                     // and I don't want to do that...
2959                $temp->value = $this->value;
2960                $temp->_lshift($shift);
2961        }
2962
2963        return $this->_normalize($temp);
2964    }
2965
2966    /**
2967     * Logical Left Rotate
2968     *
2969     * Instead of the top x bits being dropped they're appended to the shifted bit string.
2970     *
2971     * @param Integer $shift
2972     * @return \PHPSecLib\Math\BigInteger
2973     * @access public
2974     */
2975    function bitwise_leftRotate($shift)
2976    {
2977        $bits = $this->toBytes();
2978
2979        if ($this->precision > 0) {
2980            $precision = $this->precision;
2981            if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
2982                $mask = $this->bitmask->subtract(new static(1));
2983                $mask = $mask->toBytes();
2984            } else {
2985                $mask = $this->bitmask->toBytes();
2986            }
2987        } else {
2988            $temp = ord($bits[0]);
2989            for ($i = 0; $temp >> $i; ++$i);
2990            $precision = 8 * strlen($bits) - 8 + $i;
2991            $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
2992        }
2993
2994        if ($shift < 0) {
2995            $shift+= $precision;
2996        }
2997        $shift%= $precision;
2998
2999        if (!$shift) {
3000            return $this->copy();
3001        }
3002
3003        $left = $this->bitwise_leftShift($shift);
3004        $left = $left->bitwise_and(new static($mask, 256));
3005        $right = $this->bitwise_rightShift($precision - $shift);
3006        $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
3007        return $this->_normalize($result);
3008    }
3009
3010    /**
3011     * Logical Right Rotate
3012     *
3013     * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
3014     *
3015     * @param Integer $shift
3016     * @return \PHPSecLib\Math\BigInteger
3017     * @access public
3018     */
3019    function bitwise_rightRotate($shift)
3020    {
3021        return $this->bitwise_leftRotate(-$shift);
3022    }
3023
3024    /**
3025     * Generates a random BigInteger
3026     *
3027     * Byte length is equal to $length. Uses Crypt\Random if it's loaded and mt_rand if it's not.
3028     *
3029     * @param Integer $length
3030     * @return \PHPSecLib\Math\BigInteger
3031     * @access private
3032     */
3033    function _random_number_helper($size)
3034    {
3035        if (class_exists('phpseclib\Crypt\Random')) {
3036            $random = Random::string($size);
3037        } else {
3038            $random = '';
3039
3040            if ($size & 1) {
3041                $random.= chr(mt_rand(0, 255));
3042            }
3043
3044            $blocks = $size >> 1;
3045            for ($i = 0; $i < $blocks; ++$i) {
3046                // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
3047                $random.= pack('n', mt_rand(0, 0xFFFF));
3048            }
3049        }
3050
3051        return new static($random, 256);
3052    }
3053
3054    /**
3055     * Generate a random number
3056     *
3057     * Returns a random number between $min and $max where $min and $max
3058     * can be defined using one of the two methods:
3059     *
3060     * $min->random($max)
3061     * $max->random($min)
3062     *
3063     * @param \PHPSecLib\Math\BigInteger $arg1
3064     * @param optional \PHPSecLib\Math\BigInteger $arg2
3065     * @return \PHPSecLib\Math\BigInteger
3066     * @access public
3067     * @internal The API for creating random numbers used to be $a->random($min, $max), where $a was a BigInteger object.
3068     *           That method is still supported for BC purposes.
3069     */
3070    function random($arg1, $arg2 = false)
3071    {
3072        if ($arg1 === false) {
3073            return false;
3074        }
3075
3076        if ($arg2 === false) {
3077            $max = $arg1;
3078            $min = $this;
3079        } else {
3080            $min = $arg1;
3081            $max = $arg2;
3082        }
3083
3084        $compare = $max->compare($min);
3085
3086        if (!$compare) {
3087            return $this->_normalize($min);
3088        } else if ($compare < 0) {
3089            // if $min is bigger then $max, swap $min and $max
3090            $temp = $max;
3091            $max = $min;
3092            $min = $temp;
3093        }
3094
3095        static $one;
3096        if (!isset($one)) {
3097            $one = new static(1);
3098        }
3099
3100        $max = $max->subtract($min->subtract($one));
3101        $size = strlen(ltrim($max->toBytes(), chr(0)));
3102
3103        /*
3104            doing $random % $max doesn't work because some numbers will be more likely to occur than others.
3105            eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
3106            would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
3107            not all numbers would be equally likely. some would be more likely than others.
3108
3109            creating a whole new random number until you find one that is within the range doesn't work
3110            because, for sufficiently small ranges, the likelihood that you'd get a number within that range
3111            would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
3112            would be pretty high that $random would be greater than $max.
3113
3114            phpseclib works around this using the technique described here:
3115
3116            http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
3117        */
3118        $random_max = new static(chr(1) . str_repeat("\0", $size), 256);
3119        $random = $this->_random_number_helper($size);
3120
3121        list($max_multiple) = $random_max->divide($max);
3122        $max_multiple = $max_multiple->multiply($max);
3123
3124        while ($random->compare($max_multiple) >= 0) {
3125            $random = $random->subtract($max_multiple);
3126            $random_max = $random_max->subtract($max_multiple);
3127            $random = $random->bitwise_leftShift(8);
3128            $random = $random->add($this->_random_number_helper(1));
3129            $random_max = $random_max->bitwise_leftShift(8);
3130            list($max_multiple) = $random_max->divide($max);
3131            $max_multiple = $max_multiple->multiply($max);
3132        }
3133        list(, $random) = $random->divide($max);
3134
3135        return $this->_normalize($random->add($min));
3136    }
3137
3138    /**
3139     * Generate a random prime number.
3140     *
3141     * If there's not a prime within the given range, false will be returned.  If more than $timeout seconds have elapsed,
3142     * give up and return false.
3143     *
3144     * @param \PHPSecLib\Math\BigInteger $arg1
3145     * @param optional \PHPSecLib\Math\BigInteger $arg2
3146     * @param optional Integer $timeout
3147     * @return Mixed
3148     * @access public
3149     * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
3150     */
3151    function randomPrime($arg1, $arg2 = false, $timeout = false)
3152    {
3153        if ($arg1 === false) {
3154            return false;
3155        }
3156
3157        if ($arg2 === false) {
3158            $max = $arg1;
3159            $min = $this;
3160        } else {
3161            $min = $arg1;
3162            $max = $arg2;
3163        }
3164
3165        $compare = $max->compare($min);
3166
3167        if (!$compare) {
3168            return $min->isPrime() ? $min : false;
3169        } else if ($compare < 0) {
3170            // if $min is bigger then $max, swap $min and $max
3171            $temp = $max;
3172            $max = $min;
3173            $min = $temp;
3174        }
3175
3176        static $one, $two;
3177        if (!isset($one)) {
3178            $one = new static(1);
3179            $two = new static(2);
3180        }
3181
3182        $start = time();
3183
3184        $x = $this->random($min, $max);
3185
3186        // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
3187        if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
3188            $p = new static();
3189            $p->value = gmp_nextprime($x->value);
3190
3191            if ($p->compare($max) <= 0) {
3192                return $p;
3193            }
3194
3195            if (!$min->equals($x)) {
3196                $x = $x->subtract($one);
3197            }
3198
3199            return $x->randomPrime($min, $x);
3200        }
3201
3202        if ($x->equals($two)) {
3203            return $x;
3204        }
3205
3206        $x->_make_odd();
3207        if ($x->compare($max) > 0) {
3208            // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
3209            if ($min->equals($max)) {
3210                return false;
3211            }
3212            $x = $min->copy();
3213            $x->_make_odd();
3214        }
3215
3216        $initial_x = $x->copy();
3217
3218        while (true) {
3219            if ($timeout !== false && time() - $start > $timeout) {
3220                return false;
3221            }
3222
3223            if ($x->isPrime()) {
3224                return $x;
3225            }
3226
3227            $x = $x->add($two);
3228
3229            if ($x->compare($max) > 0) {
3230                $x = $min->copy();
3231                if ($x->equals($two)) {
3232                    return $x;
3233                }
3234                $x->_make_odd();
3235            }
3236
3237            if ($x->equals($initial_x)) {
3238                return false;
3239            }
3240        }
3241    }
3242
3243    /**
3244     * Make the current number odd
3245     *
3246     * If the current number is odd it'll be unchanged.  If it's even, one will be added to it.
3247     *
3248     * @see randomPrime()
3249     * @access private
3250     */
3251    function _make_odd()
3252    {
3253        switch ( MATH_BIGINTEGER_MODE ) {
3254            case MATH_BIGINTEGER_MODE_GMP:
3255                gmp_setbit($this->value, 0);
3256                break;
3257            case MATH_BIGINTEGER_MODE_BCMATH:
3258                if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3259                    $this->value = bcadd($this->value, '1');
3260                }
3261                break;
3262            default:
3263                $this->value[0] |= 1;
3264        }
3265    }
3266
3267    /**
3268     * Checks a numer to see if it's prime
3269     *
3270     * Assuming the $t parameter is not set, this function has an error rate of 2**-80.  The main motivation for the
3271     * $t parameter is distributability.  BigInteger::randomPrime() can be distributed across multiple pageloads
3272     * on a website instead of just one.
3273     *
3274     * @param optional \PHPSecLib\Math\BigInteger $t
3275     * @return Boolean
3276     * @access public
3277     * @internal Uses the
3278     *     {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}.  See
3279     *     {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
3280     */
3281    function isPrime($t = false)
3282    {
3283        $length = strlen($this->toBytes());
3284
3285        if (!$t) {
3286            // see HAC 4.49 "Note (controlling the error probability)"
3287            // @codingStandardsIgnoreStart
3288                 if ($length >= 163) { $t =  2; } // floor(1300 / 8)
3289            else if ($length >= 106) { $t =  3; } // floor( 850 / 8)
3290            else if ($length >= 81 ) { $t =  4; } // floor( 650 / 8)
3291            else if ($length >= 68 ) { $t =  5; } // floor( 550 / 8)
3292            else if ($length >= 56 ) { $t =  6; } // floor( 450 / 8)
3293            else if ($length >= 50 ) { $t =  7; } // floor( 400 / 8)
3294            else if ($length >= 43 ) { $t =  8; } // floor( 350 / 8)
3295            else if ($length >= 37 ) { $t =  9; } // floor( 300 / 8)
3296            else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
3297            else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
3298            else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
3299            else                     { $t = 27; }
3300            // @codingStandardsIgnoreEnd
3301        }
3302
3303        // ie. gmp_testbit($this, 0)
3304        // ie. isEven() or !isOdd()
3305        switch ( MATH_BIGINTEGER_MODE ) {
3306            case MATH_BIGINTEGER_MODE_GMP:
3307                return gmp_prob_prime($this->value, $t) != 0;
3308            case MATH_BIGINTEGER_MODE_BCMATH:
3309                if ($this->value === '2') {
3310                    return true;
3311                }
3312                if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3313                    return false;
3314                }
3315                break;
3316            default:
3317                if ($this->value == array(2)) {
3318                    return true;
3319                }
3320                if (~$this->value[0] & 1) {
3321                    return false;
3322                }
3323        }
3324
3325        static $primes, $zero, $one, $two;
3326
3327        if (!isset($primes)) {
3328            $primes = array(
3329                3,    5,    7,    11,   13,   17,   19,   23,   29,   31,   37,   41,   43,   47,   53,   59,
3330                61,   67,   71,   73,   79,   83,   89,   97,   101,  103,  107,  109,  113,  127,  131,  137,
3331                139,  149,  151,  157,  163,  167,  173,  179,  181,  191,  193,  197,  199,  211,  223,  227,
3332                229,  233,  239,  241,  251,  257,  263,  269,  271,  277,  281,  283,  293,  307,  311,  313,
3333                317,  331,  337,  347,  349,  353,  359,  367,  373,  379,  383,  389,  397,  401,  409,  419,
3334                421,  431,  433,  439,  443,  449,  457,  461,  463,  467,  479,  487,  491,  499,  503,  509,
3335                521,  523,  541,  547,  557,  563,  569,  571,  577,  587,  593,  599,  601,  607,  613,  617,
3336                619,  631,  641,  643,  647,  653,  659,  661,  673,  677,  683,  691,  701,  709,  719,  727,
3337                733,  739,  743,  751,  757,  761,  769,  773,  787,  797,  809,  811,  821,  823,  827,  829,
3338                839,  853,  857,  859,  863,  877,  881,  883,  887,  907,  911,  919,  929,  937,  941,  947,
3339                953,  967,  971,  977,  983,  991,  997
3340            );
3341
3342            if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3343                for ($i = 0; $i < count($primes); ++$i) {
3344                    $primes[$i] = new static($primes[$i]);
3345                }
3346            }
3347
3348            $zero = new static();
3349            $one = new static(1);
3350            $two = new static(2);
3351        }
3352
3353        if ($this->equals($one)) {
3354            return false;
3355        }
3356
3357        // see HAC 4.4.1 "Random search for probable primes"
3358        if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3359            foreach ($primes as $prime) {
3360                list(, $r) = $this->divide($prime);
3361                if ($r->equals($zero)) {
3362                    return $this->equals($prime);
3363                }
3364            }
3365        } else {
3366            $value = $this->value;
3367            foreach ($primes as $prime) {
3368                list(, $r) = $this->_divide_digit($value, $prime);
3369                if (!$r) {
3370                    return count($value) == 1 && $value[0] == $prime;
3371                }
3372            }
3373        }
3374
3375        $n   = $this->copy();
3376        $n_1 = $n->subtract($one);
3377        $n_2 = $n->subtract($two);
3378
3379        $r = $n_1->copy();
3380        $r_value = $r->value;
3381        // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
3382        if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
3383            $s = 0;
3384            // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
3385            while ($r->value[strlen($r->value) - 1] % 2 == 0) {
3386                $r->value = bcdiv($r->value, '2', 0);
3387                ++$s;
3388            }
3389        } else {
3390            for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
3391                $temp = ~$r_value[$i] & 0xFFFFFF;
3392                for ($j = 1; ($temp >> $j) & 1; ++$j);
3393                if ($j != 25) {
3394                    break;
3395                }
3396            }
3397            $s = 26 * $i + $j - 1;
3398            $r->_rshift($s);
3399        }
3400
3401        for ($i = 0; $i < $t; ++$i) {
3402            $a = $this->random($two, $n_2);
3403            $y = $a->modPow($r, $n);
3404
3405            if (!$y->equals($one) && !$y->equals($n_1)) {
3406                for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
3407                    $y = $y->modPow($two, $n);
3408                    if ($y->equals($one)) {
3409                        return false;
3410                    }
3411                }
3412
3413                if (!$y->equals($n_1)) {
3414                    return false;
3415                }
3416            }
3417        }
3418        return true;
3419    }
3420
3421    /**
3422     * Logical Left Shift
3423     *
3424     * Shifts BigInteger's by $shift bits.
3425     *
3426     * @param Integer $shift
3427     * @access private
3428     */
3429    function _lshift($shift)
3430    {
3431        if ( $shift == 0 ) {
3432            return;
3433        }
3434
3435        $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
3436        $shift %= MATH_BIGINTEGER_BASE;
3437        $shift = 1 << $shift;
3438
3439        $carry = 0;
3440
3441        for ($i = 0; $i < count($this->value); ++$i) {
3442            $temp = $this->value[$i] * $shift + $carry;
3443            $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
3444            $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
3445        }
3446
3447        if ( $carry ) {
3448            $this->value[count($this->value)] = $carry;
3449        }
3450
3451        while ($num_digits--) {
3452            array_unshift($this->value, 0);
3453        }
3454    }
3455
3456    /**
3457     * Logical Right Shift
3458     *
3459     * Shifts BigInteger's by $shift bits.
3460     *
3461     * @param Integer $shift
3462     * @access private
3463     */
3464    function _rshift($shift)
3465    {
3466        if ($shift == 0) {
3467            return;
3468        }
3469
3470        $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
3471        $shift %= MATH_BIGINTEGER_BASE;
3472        $carry_shift = MATH_BIGINTEGER_BASE - $shift;
3473        $carry_mask = (1 << $shift) - 1;
3474
3475        if ( $num_digits ) {
3476            $this->value = array_slice($this->value, $num_digits);
3477        }
3478
3479        $carry = 0;
3480
3481        for ($i = count($this->value) - 1; $i >= 0; --$i) {
3482            $temp = $this->value[$i] >> $shift | $carry;
3483            $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
3484            $this->value[$i] = $temp;
3485        }
3486
3487        $this->value = $this->_trim($this->value);
3488    }
3489
3490    /**
3491     * Normalize
3492     *
3493     * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
3494     *
3495     * @param \PHPSecLib\Math\BigInteger
3496     * @return \PHPSecLib\Math\BigInteger
3497     * @see _trim()
3498     * @access private
3499     */
3500    function _normalize($result)
3501    {
3502        $result->precision = $this->precision;
3503        $result->bitmask = $this->bitmask;
3504
3505        switch ( MATH_BIGINTEGER_MODE ) {
3506            case MATH_BIGINTEGER_MODE_GMP:
3507                if (!empty($result->bitmask->value)) {
3508                    $result->value = gmp_and($result->value, $result->bitmask->value);
3509                }
3510
3511                return $result;
3512            case MATH_BIGINTEGER_MODE_BCMATH:
3513                if (!empty($result->bitmask->value)) {
3514                    $result->value = bcmod($result->value, $result->bitmask->value);
3515                }
3516
3517                return $result;
3518        }
3519
3520        $value = &$result->value;
3521
3522        if ( !count($value) ) {
3523            return $result;
3524        }
3525
3526        $value = $this->_trim($value);
3527
3528        if (!empty($result->bitmask->value)) {
3529            $length = min(count($value), count($this->bitmask->value));
3530            $value = array_slice($value, 0, $length);
3531
3532            for ($i = 0; $i < $length; ++$i) {
3533                $value[$i] = $value[$i] & $this->bitmask->value[$i];
3534            }
3535        }
3536
3537        return $result;
3538    }
3539
3540    /**
3541     * Trim
3542     *
3543     * Removes leading zeros
3544     *
3545     * @param Array $value
3546     * @return \PHPSecLib\Math\BigInteger
3547     * @access private
3548     */
3549    function _trim($value)
3550    {
3551        for ($i = count($value) - 1; $i >= 0; --$i) {
3552            if ( $value[$i] ) {
3553                break;
3554            }
3555            unset($value[$i]);
3556        }
3557
3558        return $value;
3559    }
3560
3561    /**
3562     * Array Repeat
3563     *
3564     * @param $input Array
3565     * @param $multiplier mixed
3566     * @return Array
3567     * @access private
3568     */
3569    function _array_repeat($input, $multiplier)
3570    {
3571        return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
3572    }
3573
3574    /**
3575     * Logical Left Shift
3576     *
3577     * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
3578     *
3579     * @param $x String
3580     * @param $shift Integer
3581     * @return String
3582     * @access private
3583     */
3584    function _base256_lshift(&$x, $shift)
3585    {
3586        if ($shift == 0) {
3587            return;
3588        }
3589
3590        $num_bytes = $shift >> 3; // eg. floor($shift/8)
3591        $shift &= 7; // eg. $shift % 8
3592
3593        $carry = 0;
3594        for ($i = strlen($x) - 1; $i >= 0; --$i) {
3595            $temp = ord($x[$i]) << $shift | $carry;
3596            $x[$i] = chr($temp);
3597            $carry = $temp >> 8;
3598        }
3599        $carry = ($carry != 0) ? chr($carry) : '';
3600        $x = $carry . $x . str_repeat(chr(0), $num_bytes);
3601    }
3602
3603    /**
3604     * Logical Right Shift
3605     *
3606     * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
3607     *
3608     * @param $x String
3609     * @param $shift Integer
3610     * @return String
3611     * @access private
3612     */
3613    function _base256_rshift(&$x, $shift)
3614    {
3615        if ($shift == 0) {
3616            $x = ltrim($x, chr(0));
3617            return '';
3618        }
3619
3620        $num_bytes = $shift >> 3; // eg. floor($shift/8)
3621        $shift &= 7; // eg. $shift % 8
3622
3623        $remainder = '';
3624        if ($num_bytes) {
3625            $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
3626            $remainder = substr($x, $start);
3627            $x = substr($x, 0, -$num_bytes);
3628        }
3629
3630        $carry = 0;
3631        $carry_shift = 8 - $shift;
3632        for ($i = 0; $i < strlen($x); ++$i) {
3633            $temp = (ord($x[$i]) >> $shift) | $carry;
3634            $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
3635            $x[$i] = chr($temp);
3636        }
3637        $x = ltrim($x, chr(0));
3638
3639        $remainder = chr($carry >> $carry_shift) . $remainder;
3640
3641        return ltrim($remainder, chr(0));
3642    }
3643
3644    // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
3645    // at 32-bits, while java's longs are 64-bits.
3646
3647    /**
3648     * Converts 32-bit integers to bytes.
3649     *
3650     * @param Integer $x
3651     * @return String
3652     * @access private
3653     */
3654    function _int2bytes($x)
3655    {
3656        return ltrim(pack('N', $x), chr(0));
3657    }
3658
3659    /**
3660     * Converts bytes to 32-bit integers
3661     *
3662     * @param String $x
3663     * @return Integer
3664     * @access private
3665     */
3666    function _bytes2int($x)
3667    {
3668        $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3669        return $temp['int'];
3670    }
3671
3672    /**
3673     * DER-encode an integer
3674     *
3675     * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
3676     *
3677     * @see modPow()
3678     * @access private
3679     * @param Integer $length
3680     * @return String
3681     */
3682    function _encodeASN1Length($length)
3683    {
3684        if ($length <= 0x7F) {
3685            return chr($length);
3686        }
3687
3688        $temp = ltrim(pack('N', $length), chr(0));
3689        return pack('Ca*', 0x80 | strlen($temp), $temp);
3690    }
3691
3692    /**
3693     * Single digit division
3694     *
3695     * Even if int64 is being used the division operator will return a float64 value
3696     * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't
3697     * have the precision of int64 this is a problem so, when int64 is being used,
3698     * we'll guarantee that the dividend is divisible by first subtracting the remainder.
3699     *
3700     * @access private
3701     * @param Integer $x
3702     * @param Integer $y
3703     * @return Integer
3704     */
3705    function _safe_divide($x, $y)
3706    {
3707        if (MATH_BIGINTEGER_BASE === 26) {
3708            return (int) ($x / $y);
3709        }
3710
3711        // MATH_BIGINTEGER_BASE === 31
3712        return ($x - ($x % $y)) / $y;
3713    }
3714}