PageRenderTime 100ms CodeModel.GetById 5ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 2ms

/wp-content/plugins/updraftplus/includes/phpseclib/Math/BigInteger.php

https://github.com/tjworks/mongoing
PHP | 3681 lines | 1950 code | 484 blank | 1247 comment | 394 complexity | 0c55bcffc71ce248797d384f740a9863 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3
   4/**
   5 * Pure-PHP arbitrary precision integer arithmetic library.
   6 *
   7 * Supports base-2, base-10, base-16, and base-256 numbers.  Uses the GMP or BCMath extensions, if available,
   8 * and an internal implementation, otherwise.
   9 *
  10 * PHP versions 4 and 5
  11 *
  12 * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the 
  13 * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
  14 *
  15 * Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
  16 * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction.  Because the largest possible
  17 * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
  18 * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
  19 * used.  As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
  20 * which only supports integers.  Although this fact will slow this library down, the fact that such a high
  21 * base is being used should more than compensate.
  22 *
  23 * When PHP version 6 is officially released, we'll be able to use 64-bit integers.  This should, once again,
  24 * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /
  25 * subtraction).
  26 *
  27 * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format.  ie.
  28 * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
  29 *
  30 * Useful resources are as follows:
  31 *
  32 *  - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
  33 *  - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
  34 *  - Java's BigInteger classes.  See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
  35 *
  36 * Here's an example of how to use this library:
  37 * <code>
  38 * <?php
  39 *    include('Math/BigInteger.php');
  40 *
  41 *    $a = new Math_BigInteger(2);
  42 *    $b = new Math_BigInteger(3);
  43 *
  44 *    $c = $a->add($b);
  45 *
  46 *    echo $c->toString(); // outputs 5
  47 * ?>
  48 * </code>
  49 *
  50 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  51 * of this software and associated documentation files (the "Software"), to deal
  52 * in the Software without restriction, including without limitation the rights
  53 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  54 * copies of the Software, and to permit persons to whom the Software is
  55 * furnished to do so, subject to the following conditions:
  56 * 
  57 * The above copyright notice and this permission notice shall be included in
  58 * all copies or substantial portions of the Software.
  59 * 
  60 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  61 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  62 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  63 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  64 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  65 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  66 * THE SOFTWARE.
  67 *
  68 * @category   Math
  69 * @package    Math_BigInteger
  70 * @author     Jim Wigginton <terrafrost@php.net>
  71 * @copyright  MMVI Jim Wigginton
  72 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
  73 * @link       http://pear.php.net/package/Math_BigInteger
  74 */
  75
  76/**#@+
  77 * Reduction constants
  78 *
  79 * @access private
  80 * @see Math_BigInteger::_reduce()
  81 */
  82/**
  83 * @see Math_BigInteger::_montgomery()
  84 * @see Math_BigInteger::_prepMontgomery()
  85 */
  86define('MATH_BIGINTEGER_MONTGOMERY', 0);
  87/**
  88 * @see Math_BigInteger::_barrett()
  89 */
  90define('MATH_BIGINTEGER_BARRETT', 1);
  91/**
  92 * @see Math_BigInteger::_mod2()
  93 */
  94define('MATH_BIGINTEGER_POWEROF2', 2);
  95/**
  96 * @see Math_BigInteger::_remainder()
  97 */
  98define('MATH_BIGINTEGER_CLASSIC', 3);
  99/**
 100 * @see Math_BigInteger::__clone()
 101 */
 102define('MATH_BIGINTEGER_NONE', 4);
 103/**#@-*/
 104
 105/**#@+
 106 * Array constants
 107 *
 108 * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
 109 * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
 110 *
 111 * @access private
 112 */
 113/**
 114 * $result[MATH_BIGINTEGER_VALUE] contains the value.
 115 */
 116define('MATH_BIGINTEGER_VALUE', 0);
 117/**
 118 * $result[MATH_BIGINTEGER_SIGN] contains the sign.
 119 */
 120define('MATH_BIGINTEGER_SIGN', 1);
 121/**#@-*/
 122
 123/**#@+
 124 * @access private
 125 * @see Math_BigInteger::_montgomery()
 126 * @see Math_BigInteger::_barrett()
 127 */
 128/**
 129 * Cache constants
 130 *
 131 * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
 132 */
 133define('MATH_BIGINTEGER_VARIABLE', 0);
 134/**
 135 * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
 136 */
 137define('MATH_BIGINTEGER_DATA', 1);
 138/**#@-*/
 139
 140/**#@+
 141 * Mode constants.
 142 *
 143 * @access private
 144 * @see Math_BigInteger::Math_BigInteger()
 145 */
 146/**
 147 * To use the pure-PHP implementation
 148 */
 149define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
 150/**
 151 * To use the BCMath library
 152 *
 153 * (if enabled; otherwise, the internal implementation will be used)
 154 */
 155define('MATH_BIGINTEGER_MODE_BCMATH', 2);
 156/**
 157 * To use the GMP library
 158 *
 159 * (if present; otherwise, either the BCMath or the internal implementation will be used)
 160 */
 161define('MATH_BIGINTEGER_MODE_GMP', 3);
 162/**#@-*/
 163
 164/**
 165 * Karatsuba Cutoff
 166 *
 167 * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
 168 *
 169 * @access private
 170 */
 171define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
 172
 173/**
 174 * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
 175 * numbers.
 176 *
 177 * @author  Jim Wigginton <terrafrost@php.net>
 178 * @version 1.0.0RC4
 179 * @access  public
 180 * @package Math_BigInteger
 181 */
 182class Math_BigInteger {
 183    /**
 184     * Holds the BigInteger's value.
 185     *
 186     * @var Array
 187     * @access private
 188     */
 189    var $value;
 190
 191    /**
 192     * Holds the BigInteger's magnitude.
 193     *
 194     * @var Boolean
 195     * @access private
 196     */
 197    var $is_negative = false;
 198
 199    /**
 200     * Random number generator function
 201     *
 202     * @see setRandomGenerator()
 203     * @access private
 204     */
 205    var $generator = 'mt_rand';
 206
 207    /**
 208     * Precision
 209     *
 210     * @see setPrecision()
 211     * @access private
 212     */
 213    var $precision = -1;
 214
 215    /**
 216     * Precision Bitmask
 217     *
 218     * @see setPrecision()
 219     * @access private
 220     */
 221    var $bitmask = false;
 222
 223    /**
 224     * Mode independent value used for serialization.
 225     *
 226     * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for 
 227     * a variable that'll be serializable regardless of whether or not extensions are being used.  Unlike $this->value,
 228     * however, $this->hex is only calculated when $this->__sleep() is called.
 229     *
 230     * @see __sleep()
 231     * @see __wakeup()
 232     * @var String
 233     * @access private
 234     */
 235    var $hex;
 236
 237    /**
 238     * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
 239     *
 240     * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
 241     * two's compliment.  The sole exception to this is -10, which is treated the same as 10 is.
 242     *
 243     * Here's an example:
 244     * <code>
 245     * &lt;?php
 246     *    include('Math/BigInteger.php');
 247     *
 248     *    $a = new Math_BigInteger('0x32', 16); // 50 in base-16
 249     *
 250     *    echo $a->toString(); // outputs 50
 251     * ?&gt;
 252     * </code>
 253     *
 254     * @param optional $x base-10 number or base-$base number if $base set.
 255     * @param optional integer $base
 256     * @return Math_BigInteger
 257     * @access public
 258     */
 259    function Math_BigInteger($x = 0, $base = 10)
 260    {
 261        if ( !defined('MATH_BIGINTEGER_MODE') ) {
 262            switch (true) {
 263                case extension_loaded('gmp'):
 264                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
 265                    break;
 266                case extension_loaded('bcmath'):
 267                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
 268                    break;
 269                default:
 270                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
 271            }
 272        }
 273
 274        if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
 275            define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
 276        }
 277
 278        if (!defined('PHP_INT_SIZE')) {
 279            define('PHP_INT_SIZE', 4);
 280        }
 281
 282        if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {
 283            switch (PHP_INT_SIZE) {
 284                case 8: // use 64-bit integers if int size is 8 bytes
 285                    define('MATH_BIGINTEGER_BASE',       31);
 286                    define('MATH_BIGINTEGER_BASE_FULL',  0x80000000);
 287                    define('MATH_BIGINTEGER_MAX_DIGIT',  0x7FFFFFFF);
 288                    define('MATH_BIGINTEGER_MSB',        0x40000000);
 289                    // 10**9 is the closest we can get to 2**31 without passing it
 290                    define('MATH_BIGINTEGER_MAX10',      1000000000);
 291                    define('MATH_BIGINTEGER_MAX10_LEN',  9);
 292                    // the largest digit that may be used in addition / subtraction
 293                    define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62));
 294                    break;
 295                //case 4: // use 64-bit floats if int size is 4 bytes
 296                default:
 297                    define('MATH_BIGINTEGER_BASE',       26);
 298                    define('MATH_BIGINTEGER_BASE_FULL',  0x4000000);
 299                    define('MATH_BIGINTEGER_MAX_DIGIT',  0x3FFFFFF);
 300                    define('MATH_BIGINTEGER_MSB',        0x2000000);
 301                    // 10**7 is the closest to 2**26 without passing it
 302                    define('MATH_BIGINTEGER_MAX10',      10000000);
 303                    define('MATH_BIGINTEGER_MAX10_LEN',  7);
 304                    // the largest digit that may be used in addition / subtraction
 305                    // we do pow(2, 52) instead of using 4503599627370496 directly because some
 306                    // PHP installations will truncate 4503599627370496.
 307                    define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52));
 308            }
 309        }
 310
 311        switch ( MATH_BIGINTEGER_MODE ) {
 312            case MATH_BIGINTEGER_MODE_GMP:
 313                if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
 314                    $this->value = $x;
 315                    return;
 316                }
 317                $this->value = gmp_init(0);
 318                break;
 319            case MATH_BIGINTEGER_MODE_BCMATH:
 320                $this->value = '0';
 321                break;
 322            default:
 323                $this->value = array();
 324        }
 325
 326        // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
 327        // '0' is the only value like this per http://php.net/empty
 328        if (empty($x) && (abs($base) != 256 || $x !== '0')) {
 329            return;
 330        }
 331
 332        switch ($base) {
 333            case -256:
 334                if (ord($x[0]) & 0x80) {
 335                    $x = ~$x;
 336                    $this->is_negative = true;
 337                }
 338            case  256:
 339                switch ( MATH_BIGINTEGER_MODE ) {
 340                    case MATH_BIGINTEGER_MODE_GMP:
 341                        $sign = $this->is_negative ? '-' : '';
 342                        $this->value = gmp_init($sign . '0x' . bin2hex($x));
 343                        break;
 344                    case MATH_BIGINTEGER_MODE_BCMATH:
 345                        // round $len to the nearest 4 (thanks, DavidMJ!)
 346                        $len = (strlen($x) + 3) & 0xFFFFFFFC;
 347
 348                        $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
 349
 350                        for ($i = 0; $i < $len; $i+= 4) {
 351                            $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
 352                            $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
 353                        }
 354
 355                        if ($this->is_negative) {
 356                            $this->value = '-' . $this->value;
 357                        }
 358
 359                        break;
 360                    // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
 361                    default:
 362                        while (strlen($x)) {
 363                            $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
 364                        }
 365                }
 366
 367                if ($this->is_negative) {
 368                    if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
 369                        $this->is_negative = false;
 370                    }
 371                    $temp = $this->add(new Math_BigInteger('-1'));
 372                    $this->value = $temp->value;
 373                }
 374                break;
 375            case  16:
 376            case -16:
 377                if ($base > 0 && $x[0] == '-') {
 378                    $this->is_negative = true;
 379                    $x = substr($x, 1);
 380                }
 381
 382                $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
 383
 384                $is_negative = false;
 385                if ($base < 0 && hexdec($x[0]) >= 8) {
 386                    $this->is_negative = $is_negative = true;
 387                    $x = bin2hex(~pack('H*', $x));
 388                }
 389
 390                switch ( MATH_BIGINTEGER_MODE ) {
 391                    case MATH_BIGINTEGER_MODE_GMP:
 392                        $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
 393                        $this->value = gmp_init($temp);
 394                        $this->is_negative = false;
 395                        break;
 396                    case MATH_BIGINTEGER_MODE_BCMATH:
 397                        $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
 398                        $temp = new Math_BigInteger(pack('H*', $x), 256);
 399                        $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
 400                        $this->is_negative = false;
 401                        break;
 402                    default:
 403                        $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
 404                        $temp = new Math_BigInteger(pack('H*', $x), 256);
 405                        $this->value = $temp->value;
 406                }
 407
 408                if ($is_negative) {
 409                    $temp = $this->add(new Math_BigInteger('-1'));
 410                    $this->value = $temp->value;
 411                }
 412                break;
 413            case  10:
 414            case -10:
 415                // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
 416                // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
 417                // [^-0-9].*: find any non-numeric characters and then any characters that follow that
 418                $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
 419
 420                switch ( MATH_BIGINTEGER_MODE ) {
 421                    case MATH_BIGINTEGER_MODE_GMP:
 422                        $this->value = gmp_init($x);
 423                        break;
 424                    case MATH_BIGINTEGER_MODE_BCMATH:
 425                        // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
 426                        // results then doing it on '-1' does (modInverse does $x[0])
 427                        $this->value = $x === '-' ? '0' : (string) $x;
 428                        break;
 429                    default:
 430                        $temp = new Math_BigInteger();
 431
 432                        $multiplier = new Math_BigInteger();
 433                        $multiplier->value = array(MATH_BIGINTEGER_MAX10);
 434
 435                        if ($x[0] == '-') {
 436                            $this->is_negative = true;
 437                            $x = substr($x, 1);
 438                        }
 439
 440                        $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
 441
 442                        while (strlen($x)) {
 443                            $temp = $temp->multiply($multiplier);
 444                            $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
 445                            $x = substr($x, MATH_BIGINTEGER_MAX10_LEN);
 446                        }
 447
 448                        $this->value = $temp->value;
 449                }
 450                break;
 451            case  2: // base-2 support originally implemented by Lluis Pamies - thanks!
 452            case -2:
 453                if ($base > 0 && $x[0] == '-') {
 454                    $this->is_negative = true;
 455                    $x = substr($x, 1);
 456                }
 457
 458                $x = preg_replace('#^([01]*).*#', '$1', $x);
 459                $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
 460
 461                $str = '0x';
 462                while (strlen($x)) {
 463                    $part = substr($x, 0, 4);
 464                    $str.= dechex(bindec($part));
 465                    $x = substr($x, 4);
 466                }
 467
 468                if ($this->is_negative) {
 469                    $str = '-' . $str;
 470                }
 471
 472                $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
 473                $this->value = $temp->value;
 474                $this->is_negative = $temp->is_negative;
 475
 476                break;
 477            default:
 478                // base not supported, so we'll let $this == 0
 479        }
 480    }
 481
 482    /**
 483     * Converts a BigInteger to a byte string (eg. base-256).
 484     *
 485     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
 486     * saved as two's compliment.
 487     *
 488     * Here's an example:
 489     * <code>
 490     * <?php
 491     *    include('Math/BigInteger.php');
 492     *
 493     *    $a = new Math_BigInteger('65');
 494     *
 495     *    echo $a->toBytes(); // outputs chr(65)
 496     * ?>
 497     * </code>
 498     *
 499     * @param Boolean $twos_compliment
 500     * @return String
 501     * @access public
 502     * @internal Converts a base-2**26 number to base-2**8
 503     */
 504    function toBytes($twos_compliment = false)
 505    {
 506        if ($twos_compliment) {
 507            $comparison = $this->compare(new Math_BigInteger());
 508            if ($comparison == 0) {
 509                return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 510            }
 511
 512            $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
 513            $bytes = $temp->toBytes();
 514
 515            if (empty($bytes)) { // eg. if the number we're trying to convert is -1
 516                $bytes = chr(0);
 517            }
 518
 519            if (ord($bytes[0]) & 0x80) {
 520                $bytes = chr(0) . $bytes;
 521            }
 522
 523            return $comparison < 0 ? ~$bytes : $bytes;
 524        }
 525
 526        switch ( MATH_BIGINTEGER_MODE ) {
 527            case MATH_BIGINTEGER_MODE_GMP:
 528                if (gmp_cmp($this->value, gmp_init(0)) == 0) {
 529                    return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 530                }
 531
 532                $temp = gmp_strval(gmp_abs($this->value), 16);
 533                $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
 534                $temp = pack('H*', $temp);
 535
 536                return $this->precision > 0 ?
 537                    substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
 538                    ltrim($temp, chr(0));
 539            case MATH_BIGINTEGER_MODE_BCMATH:
 540                if ($this->value === '0') {
 541                    return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 542                }
 543
 544                $value = '';
 545                $current = $this->value;
 546
 547                if ($current[0] == '-') {
 548                    $current = substr($current, 1);
 549                }
 550
 551                while (bccomp($current, '0', 0) > 0) {
 552                    $temp = bcmod($current, '16777216');
 553                    $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
 554                    $current = bcdiv($current, '16777216', 0);
 555                }
 556
 557                return $this->precision > 0 ?
 558                    substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
 559                    ltrim($value, chr(0));
 560        }
 561
 562        if (!count($this->value)) {
 563            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 564        }
 565        $result = $this->_int2bytes($this->value[count($this->value) - 1]);
 566
 567        $temp = $this->copy();
 568
 569        for ($i = count($temp->value) - 2; $i >= 0; --$i) {
 570            $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
 571            $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
 572        }
 573
 574        return $this->precision > 0 ?
 575            str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
 576            $result;
 577    }
 578
 579    /**
 580     * Converts a BigInteger to a hex string (eg. base-16)).
 581     *
 582     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
 583     * saved as two's compliment.
 584     *
 585     * Here's an example:
 586     * <code>
 587     * <?php
 588     *    include('Math/BigInteger.php');
 589     *
 590     *    $a = new Math_BigInteger('65');
 591     *
 592     *    echo $a->toHex(); // outputs '41'
 593     * ?>
 594     * </code>
 595     *
 596     * @param Boolean $twos_compliment
 597     * @return String
 598     * @access public
 599     * @internal Converts a base-2**26 number to base-2**8
 600     */
 601    function toHex($twos_compliment = false)
 602    {
 603        return bin2hex($this->toBytes($twos_compliment));
 604    }
 605
 606    /**
 607     * Converts a BigInteger to a bit string (eg. base-2).
 608     *
 609     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
 610     * saved as two's compliment.
 611     *
 612     * Here's an example:
 613     * <code>
 614     * <?php
 615     *    include('Math/BigInteger.php');
 616     *
 617     *    $a = new Math_BigInteger('65');
 618     *
 619     *    echo $a->toBits(); // outputs '1000001'
 620     * ?>
 621     * </code>
 622     *
 623     * @param Boolean $twos_compliment
 624     * @return String
 625     * @access public
 626     * @internal Converts a base-2**26 number to base-2**2
 627     */
 628    function toBits($twos_compliment = false)
 629    {
 630        $hex = $this->toHex($twos_compliment);
 631        $bits = '';
 632        for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
 633            $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
 634        }
 635        if ($start) { // hexdec('') == 0
 636            $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
 637        }
 638        $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
 639
 640        if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
 641            return '0' . $result;
 642        }
 643
 644        return $result;
 645    }
 646
 647    /**
 648     * Converts a BigInteger to a base-10 number.
 649     *
 650     * Here's an example:
 651     * <code>
 652     * <?php
 653     *    include('Math/BigInteger.php');
 654     *
 655     *    $a = new Math_BigInteger('50');
 656     *
 657     *    echo $a->toString(); // outputs 50
 658     * ?>
 659     * </code>
 660     *
 661     * @return String
 662     * @access public
 663     * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
 664     */
 665    function toString()
 666    {
 667        switch ( MATH_BIGINTEGER_MODE ) {
 668            case MATH_BIGINTEGER_MODE_GMP:
 669                return gmp_strval($this->value);
 670            case MATH_BIGINTEGER_MODE_BCMATH:
 671                if ($this->value === '0') {
 672                    return '0';
 673                }
 674
 675                return ltrim($this->value, '0');
 676        }
 677
 678        if (!count($this->value)) {
 679            return '0';
 680        }
 681
 682        $temp = $this->copy();
 683        $temp->is_negative = false;
 684
 685        $divisor = new Math_BigInteger();
 686        $divisor->value = array(MATH_BIGINTEGER_MAX10);
 687        $result = '';
 688        while (count($temp->value)) {
 689            list($temp, $mod) = $temp->divide($divisor);
 690            $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result;
 691        }
 692        $result = ltrim($result, '0');
 693        if (empty($result)) {
 694            $result = '0';
 695        }
 696
 697        if ($this->is_negative) {
 698            $result = '-' . $result;
 699        }
 700
 701        return $result;
 702    }
 703
 704    /**
 705     * Copy an object
 706     *
 707     * PHP5 passes objects by reference while PHP4 passes by value.  As such, we need a function to guarantee
 708     * that all objects are passed by value, when appropriate.  More information can be found here:
 709     *
 710     * {@link http://php.net/language.oop5.basic#51624}
 711     *
 712     * @access public
 713     * @see __clone()
 714     * @return Math_BigInteger
 715     */
 716    function copy()
 717    {
 718        $temp = new Math_BigInteger();
 719        $temp->value = $this->value;
 720        $temp->is_negative = $this->is_negative;
 721        $temp->generator = $this->generator;
 722        $temp->precision = $this->precision;
 723        $temp->bitmask = $this->bitmask;
 724        return $temp;
 725    }
 726
 727    /**
 728     *  __toString() magic method
 729     *
 730     * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
 731     * toString().
 732     *
 733     * @access public
 734     * @internal Implemented per a suggestion by Techie-Michael - thanks!
 735     */
 736    function __toString()
 737    {
 738        return $this->toString();
 739    }
 740
 741    /**
 742     * __clone() magic method
 743     *
 744     * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
 745     * directly 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
 746     * only syntax of $y = clone $x.  As such, if you're trying to write an application that works on both PHP4 and PHP5,
 747     * call Math_BigInteger::copy(), instead.
 748     *
 749     * @access public
 750     * @see copy()
 751     * @return Math_BigInteger
 752     */
 753    function __clone()
 754    {
 755        return $this->copy();
 756    }
 757
 758    /**
 759     *  __sleep() magic method
 760     *
 761     * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
 762     *
 763     * @see __wakeup()
 764     * @access public
 765     */
 766    function __sleep()
 767    {
 768        $this->hex = $this->toHex(true);
 769        $vars = array('hex');
 770        if ($this->generator != 'mt_rand') {
 771            $vars[] = 'generator';
 772        }
 773        if ($this->precision > 0) {
 774            $vars[] = 'precision';
 775        }
 776        return $vars;
 777        
 778    }
 779
 780    /**
 781     *  __wakeup() magic method
 782     *
 783     * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
 784     *
 785     * @see __sleep()
 786     * @access public
 787     */
 788    function __wakeup()
 789    {
 790        $temp = new Math_BigInteger($this->hex, -16);
 791        $this->value = $temp->value;
 792        $this->is_negative = $temp->is_negative;
 793        $this->setRandomGenerator($this->generator);
 794        if ($this->precision > 0) {
 795            // recalculate $this->bitmask
 796            $this->setPrecision($this->precision);
 797        }
 798    }
 799
 800    /**
 801     * Adds two BigIntegers.
 802     *
 803     * Here's an example:
 804     * <code>
 805     * <?php
 806     *    include('Math/BigInteger.php');
 807     *
 808     *    $a = new Math_BigInteger('10');
 809     *    $b = new Math_BigInteger('20');
 810     *
 811     *    $c = $a->add($b);
 812     *
 813     *    echo $c->toString(); // outputs 30
 814     * ?>
 815     * </code>
 816     *
 817     * @param Math_BigInteger $y
 818     * @return Math_BigInteger
 819     * @access public
 820     * @internal Performs base-2**52 addition
 821     */
 822    function add($y)
 823    {
 824        switch ( MATH_BIGINTEGER_MODE ) {
 825            case MATH_BIGINTEGER_MODE_GMP:
 826                $temp = new Math_BigInteger();
 827                $temp->value = gmp_add($this->value, $y->value);
 828
 829                return $this->_normalize($temp);
 830            case MATH_BIGINTEGER_MODE_BCMATH:
 831                $temp = new Math_BigInteger();
 832                $temp->value = bcadd($this->value, $y->value, 0);
 833
 834                return $this->_normalize($temp);
 835        }
 836
 837        $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
 838
 839        $result = new Math_BigInteger();
 840        $result->value = $temp[MATH_BIGINTEGER_VALUE];
 841        $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
 842
 843        return $this->_normalize($result);
 844    }
 845
 846    /**
 847     * Performs addition.
 848     *
 849     * @param Array $x_value
 850     * @param Boolean $x_negative
 851     * @param Array $y_value
 852     * @param Boolean $y_negative
 853     * @return Array
 854     * @access private
 855     */
 856    function _add($x_value, $x_negative, $y_value, $y_negative)
 857    {
 858        $x_size = count($x_value);
 859        $y_size = count($y_value);
 860
 861        if ($x_size == 0) {
 862            return array(
 863                MATH_BIGINTEGER_VALUE => $y_value,
 864                MATH_BIGINTEGER_SIGN => $y_negative
 865            );
 866        } else if ($y_size == 0) {
 867            return array(
 868                MATH_BIGINTEGER_VALUE => $x_value,
 869                MATH_BIGINTEGER_SIGN => $x_negative
 870            );
 871        }
 872
 873        // subtract, if appropriate
 874        if ( $x_negative != $y_negative ) {
 875            if ( $x_value == $y_value ) {
 876                return array(
 877                    MATH_BIGINTEGER_VALUE => array(),
 878                    MATH_BIGINTEGER_SIGN => false
 879                );
 880            }
 881
 882            $temp = $this->_subtract($x_value, false, $y_value, false);
 883            $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
 884                                          $x_negative : $y_negative;
 885
 886            return $temp;
 887        }
 888
 889        if ($x_size < $y_size) {
 890            $size = $x_size;
 891            $value = $y_value;
 892        } else {
 893            $size = $y_size;
 894            $value = $x_value;
 895        }
 896
 897        $value[] = 0; // just in case the carry adds an extra digit
 898
 899        $carry = 0;
 900        for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
 901            $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
 902            $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
 903            $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
 904
 905            $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);
 906
 907            $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
 908            $value[$j] = $temp;
 909        }
 910
 911        if ($j == $size) { // ie. if $y_size is odd
 912            $sum = $x_value[$i] + $y_value[$i] + $carry;
 913            $carry = $sum >= MATH_BIGINTEGER_BASE_FULL;
 914            $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
 915            ++$i; // ie. let $i = $j since we've just done $value[$i]
 916        }
 917
 918        if ($carry) {
 919            for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {
 920                $value[$i] = 0;
 921            }
 922            ++$value[$i];
 923        }
 924
 925        return array(
 926            MATH_BIGINTEGER_VALUE => $this->_trim($value),
 927            MATH_BIGINTEGER_SIGN => $x_negative
 928        );
 929    }
 930
 931    /**
 932     * Subtracts two BigIntegers.
 933     *
 934     * Here's an example:
 935     * <code>
 936     * <?php
 937     *    include('Math/BigInteger.php');
 938     *
 939     *    $a = new Math_BigInteger('10');
 940     *    $b = new Math_BigInteger('20');
 941     *
 942     *    $c = $a->subtract($b);
 943     *
 944     *    echo $c->toString(); // outputs -10
 945     * ?>
 946     * </code>
 947     *
 948     * @param Math_BigInteger $y
 949     * @return Math_BigInteger
 950     * @access public
 951     * @internal Performs base-2**52 subtraction
 952     */
 953    function subtract($y)
 954    {
 955        switch ( MATH_BIGINTEGER_MODE ) {
 956            case MATH_BIGINTEGER_MODE_GMP:
 957                $temp = new Math_BigInteger();
 958                $temp->value = gmp_sub($this->value, $y->value);
 959
 960                return $this->_normalize($temp);
 961            case MATH_BIGINTEGER_MODE_BCMATH:
 962                $temp = new Math_BigInteger();
 963                $temp->value = bcsub($this->value, $y->value, 0);
 964
 965                return $this->_normalize($temp);
 966        }
 967
 968        $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
 969
 970        $result = new Math_BigInteger();
 971        $result->value = $temp[MATH_BIGINTEGER_VALUE];
 972        $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
 973
 974        return $this->_normalize($result);
 975    }
 976
 977    /**
 978     * Performs subtraction.
 979     *
 980     * @param Array $x_value
 981     * @param Boolean $x_negative
 982     * @param Array $y_value
 983     * @param Boolean $y_negative
 984     * @return Array
 985     * @access private
 986     */
 987    function _subtract($x_value, $x_negative, $y_value, $y_negative)
 988    {
 989        $x_size = count($x_value);
 990        $y_size = count($y_value);
 991
 992        if ($x_size == 0) {
 993            return array(
 994                MATH_BIGINTEGER_VALUE => $y_value,
 995                MATH_BIGINTEGER_SIGN => !$y_negative
 996            );
 997        } else if ($y_size == 0) {
 998            return array(
 999                MATH_BIGINTEGER_VALUE => $x_value,
1000                MATH_BIGINTEGER_SIGN => $x_negative
1001            );
1002        }
1003
1004        // add, if appropriate (ie. -$x - +$y or +$x - -$y)
1005        if ( $x_negative != $y_negative ) {
1006            $temp = $this->_add($x_value, false, $y_value, false);
1007            $temp[MATH_BIGINTEGER_SIGN] = $x_negative;
1008
1009            return $temp;
1010        }
1011
1012        $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
1013
1014        if ( !$diff ) {
1015            return array(
1016                MATH_BIGINTEGER_VALUE => array(),
1017                MATH_BIGINTEGER_SIGN => false
1018            );
1019        }
1020
1021        // switch $x and $y around, if appropriate.
1022        if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
1023            $temp = $x_value;
1024            $x_value = $y_value;
1025            $y_value = $temp;
1026
1027            $x_negative = !$x_negative;
1028
1029            $x_size = count($x_value);
1030            $y_size = count($y_value);
1031        }
1032
1033        // at this point, $x_value should be at least as big as - if not bigger than - $y_value
1034
1035        $carry = 0;
1036        for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
1037            $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
1038            $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
1039            $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
1040
1041            $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);
1042
1043            $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
1044            $x_value[$j] = $temp;
1045        }
1046
1047        if ($j == $y_size) { // ie. if $y_size is odd
1048            $sum = $x_value[$i] - $y_value[$i] - $carry;
1049            $carry = $sum < 0;
1050            $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
1051            ++$i;
1052        }
1053
1054        if ($carry) {
1055            for (; !$x_value[$i]; ++$i) {
1056                $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
1057            }
1058            --$x_value[$i];
1059        }
1060
1061        return array(
1062            MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
1063            MATH_BIGINTEGER_SIGN => $x_negative
1064        );
1065    }
1066
1067    /**
1068     * Multiplies two BigIntegers
1069     *
1070     * Here's an example:
1071     * <code>
1072     * <?php
1073     *    include('Math/BigInteger.php');
1074     *
1075     *    $a = new Math_BigInteger('10');
1076     *    $b = new Math_BigInteger('20');
1077     *
1078     *    $c = $a->multiply($b);
1079     *
1080     *    echo $c->toString(); // outputs 200
1081     * ?>
1082     * </code>
1083     *
1084     * @param Math_BigInteger $x
1085     * @return Math_BigInteger
1086     * @access public
1087     */
1088    function multiply($x)
1089    {
1090        switch ( MATH_BIGINTEGER_MODE ) {
1091            case MATH_BIGINTEGER_MODE_GMP:
1092                $temp = new Math_BigInteger();
1093                $temp->value = gmp_mul($this->value, $x->value);
1094
1095                return $this->_normalize($temp);
1096            case MATH_BIGINTEGER_MODE_BCMATH:
1097                $temp = new Math_BigInteger();
1098                $temp->value = bcmul($this->value, $x->value, 0);
1099
1100                return $this->_normalize($temp);
1101        }
1102
1103        $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
1104
1105        $product = new Math_BigInteger();
1106        $product->value = $temp[MATH_BIGINTEGER_VALUE];
1107        $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
1108
1109        return $this->_normalize($product);
1110    }
1111
1112    /**
1113     * Performs multiplication.
1114     *
1115     * @param Array $x_value
1116     * @param Boolean $x_negative
1117     * @param Array $y_value
1118     * @param Boolean $y_negative
1119     * @return Array
1120     * @access private
1121     */
1122    function _multiply($x_value, $x_negative, $y_value, $y_negative)
1123    {
1124        //if ( $x_value == $y_value ) {
1125        //    return array(
1126        //        MATH_BIGINTEGER_VALUE => $this->_square($x_value),
1127        //        MATH_BIGINTEGER_SIGN => $x_sign != $y_value
1128        //    );
1129        //}
1130
1131        $x_length = count($x_value);
1132        $y_length = count($y_value);
1133
1134        if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1135            return array(
1136                MATH_BIGINTEGER_VALUE => array(),
1137                MATH_BIGINTEGER_SIGN => false
1138            );
1139        }
1140
1141        return array(
1142            MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1143                $this->_trim($this->_regularMultiply($x_value, $y_value)) :
1144                $this->_trim($this->_karatsuba($x_value, $y_value)),
1145            MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
1146        );
1147    }
1148
1149    /**
1150     * Performs long multiplication on two BigIntegers
1151     *
1152     * Modeled after 'multiply' in MutableBigInteger.java.
1153     *
1154     * @param Array $x_value
1155     * @param Array $y_value
1156     * @return Array
1157     * @access private
1158     */
1159    function _regularMultiply($x_value, $y_value)
1160    {
1161        $x_length = count($x_value);
1162        $y_length = count($y_value);
1163
1164        if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1165            return array();
1166        }
1167
1168        if ( $x_length < $y_length ) {
1169            $temp = $x_value;
1170            $x_value = $y_value;
1171            $y_value = $temp;
1172
1173            $x_length = count($x_value);
1174            $y_length = count($y_value);
1175        }
1176
1177        $product_value = $this->_array_repeat(0, $x_length + $y_length);
1178
1179        // the following for loop could be removed if the for loop following it
1180        // (the one with nested for loops) initially set $i to 0, but
1181        // doing so would also make the result in one set of unnecessary adds,
1182        // since on the outermost loops first pass, $product->value[$k] is going
1183        // to always be 0
1184
1185        $carry = 0;
1186
1187        for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
1188            $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
1189            $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
1190            $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1191        }
1192
1193        $product_value[$j] = $carry;
1194
1195        // the above for loop is what the previous comment was talking about.  the
1196        // following for loop is the "one with nested for loops"
1197        for ($i = 1; $i < $y_length; ++$i) {
1198            $carry = 0;
1199
1200            for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
1201                $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
1202                $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
1203                $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1204            }
1205
1206            $product_value[$k] = $carry;
1207        }
1208
1209        return $product_value;
1210    }
1211
1212    /**
1213     * Performs Karatsuba multiplication on two BigIntegers
1214     *
1215     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1216     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
1217     *
1218     * @param Array $x_value
1219     * @param Array $y_value
1220     * @return Array
1221     * @access private
1222     */
1223    function _karatsuba($x_value, $y_value)
1224    {
1225        $m = min(count($x_value) >> 1, count($y_value) >> 1);
1226
1227        if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1228            return $this->_regularMultiply($x_value, $y_value);
1229        }
1230
1231        $x1 = array_slice($x_value, $m);
1232        $x0 = array_slice($x_value, 0, $m);
1233        $y1 = array_slice($y_value, $m);
1234        $y0 = array_slice($y_value, 0, $m);
1235
1236        $z2 = $this->_karatsuba($x1, $y1);
1237        $z0 = $this->_karatsuba($x0, $y0);
1238
1239        $z1 = $this->_add($x1, false, $x0, false);
1240        $temp = $this->_add($y1, false, $y0, false);
1241        $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
1242        $temp = $this->_add($z2, false, $z0, false);
1243        $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1244
1245        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1246        $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1247
1248        $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1249        $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
1250
1251        return $xy[MATH_BIGINTEGER_VALUE];
1252    }
1253
1254    /**
1255     * Performs squaring
1256     *
1257     * @param Array $x
1258     * @return Array
1259     * @access private
1260     */
1261    function _square($x = false)
1262    {
1263        return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1264            $this->_trim($this->_baseSquare($x)) :
1265            $this->_trim($this->_karatsubaSquare($x));
1266    }
1267
1268    /**
1269     * Performs traditional squaring on two BigIntegers
1270     *
1271     * Squaring can be done faster than multiplying a number by itself can be.  See
1272     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1273     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
1274     *
1275     * @param Array $value
1276     * @return Array
1277     * @access private
1278     */
1279    function _baseSquare($value)
1280    {
1281        if ( empty($value) ) {
1282            return array();
1283        }
1284        $square_value = $this->_array_repeat(0, 2 * count($value));
1285
1286        for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
1287            $i2 = $i << 1;
1288
1289            $temp = $square_value[$i2] + $value[$i] * $value[$i];
1290            $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
1291            $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1292
1293            // note how we start from $i+1 instead of 0 as we do in multiplication.
1294            for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1295                $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
1296                $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
1297                $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1298            }
1299
1300            // the following line can yield values larger 2**15.  at this point, PHP should switch
1301            // over to floats.
1302            $square_value[$i + $max_index + 1] = $carry;
1303        }
1304
1305        return $square_value;
1306    }
1307
1308    /**
1309     * Performs Karatsuba "squaring" on two BigIntegers
1310     *
1311     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1312     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
1313     *
1314     * @param Array $value
1315     * @return Array
1316     * @access private
1317     */
1318    function _karatsubaSquare($value)
1319    {
1320        $m = count($value) >> 1;
1321
1322        if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1323            return $this->_baseSquare($value);
1324        }
1325
1326        $x1 = array_slice($value, $m);
1327        $x0 = array_slice($value, 0, $m);
1328
1329        $z2 = $this->_karatsubaSquare($x1);
1330        $z0 = $this->_karatsubaSquare($x0);
1331
1332        $z1 = $this->_add($x1, false, $x0, false);
1333        $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
1334        $temp = $this->_add($z2, false, $z0, false);
1335        $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1336
1337        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1338        $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1339
1340        $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1341        $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
1342
1343        return $xx[MATH_BIGINTEGER_VALUE];
1344    }
1345
1346    /**
1347     * Divides two BigIntegers.
1348     *
1349     * Returns an array whose first element contains the quotient and whose second element contains the
1350     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
1351     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
1352     * and the divisor (basically, the "common residue" is the first positive modulo).
1353     *
1354     * Here's an example:
1355     * <code>
1356     * <?php
1357     *    include('Math/BigInteger.php');
1358     *
1359     *    $a = new Math_BigInteger('10');
1360     *    $b = new Math_BigInteger('20');
1361     *
1362     *    list($quotient, $remainder) = $a->divide($b);
1363     *
1364     *    echo $quotient->toString(); // outputs 0
1365     *    echo "\r\n";
1366     *    echo $remainder->toString(); // outputs 10
1367     * ?>
1368     * </code>
1369     *
1370     * @param Math_BigInteger $y
1371     * @return Array
1372     * @access public
1373     * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
1374     */
1375    function divide($y)
1376    {
1377        switch ( MATH_BIGINTEGER_MODE ) {
1378            case MATH_BIGINTEGER_MODE_GMP:
1379                $quotient = new Math_BigInteger();
1380                $remainder = new Math_BigInteger();
1381
1382                list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
1383
1384                if (gmp_sign($remainder->value) < 0) {
1385                    $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
1386                }
1387
1388                return array($this->_normalize($quotient), $this->_normalize($remainder));
1389            case MATH_BIGINTEGER_MODE_BCMATH:
1390                $quotient = new Math_BigInteger();
1391                $remainder = new Math_BigInteger();
1392
1393                $quotient->value = bcdiv($this->value, $y->value, 0);
1394                $remainder->value = bcmod($this->value, $y->value);
1395
1396                if ($remainder->value[0] == '-') {
1397                    $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
1398                }
1399
1400                return array($this->_normalize($quotient), $this->_normalize($remainder));
1401        }
1402
1403        if (count($y->value) == 1) {
1404            list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
1405            $quotient = new Math_BigInteger();
1406            $remainder = new Math_BigInteger();
1407            $quotient->value = $q;
1408            $remainder->value = array($r);
1409            $quotient->is_negative = $this->is_negative != $y->is_negative;
1410            return array($this->_normalize($quotient), $this->_normalize($remainder));
1411        }
1412
1413        static $zero;
1414        if ( !isset($zero) ) {
1415            $zero = new Math_BigInteger();
1416        }
1417
1418        $x = $this->copy();
1419        $y = $y->copy();
1420
1421        $x_sign = $x->is_negative;
1422        $y_sign = $y->is_negative;
1423
1424        $x->is_negative = $y->is_negative = false;
1425
1426        $diff = $x->compare($y);
1427
1428        if ( !$diff ) {
1429            $temp = new Math_BigInteger();
1430            $temp->value = array(1);
1431            $temp->is_negative = $x_sign != $y_sign;
1432            return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
1433        }
1434
1435        if ( $diff < 0 ) {
1436            // if $x is negative, "add" $y.
1437            if ( $x_sign ) {
1438                $x = $y->subtract($x);
1439            }
1440            return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
1441        }
1442
1443        // normalize $x and $y as described in HAC 14.23 / 14.24
1444        $msb = $y->value[count($y->value) - 1];
1445        for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {
1446            $msb <<= 1;
1447        }
1448        $x->_lshift($shift);
1449        $y->_lshift($shift);
1450        $y_value = &$y->value;
1451
1452        $x_max = count($x->value) - 1;
1453        $y_max = count($y->value) - 1;
1454
1455        $quotient = new Math_BigInteger();
1456        $quotient_value = &$quotient->value;
1457        $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
1458
1459        static $temp, $lhs, $rhs;
1460        if (!isset($temp)) {
1461            $temp = new Math_BigInteger();
1462            $lhs =  new Math_BigInteger();
1463            $rhs =  new Math_BigInteger();
1464        }
1465        $temp_value = &$temp->value;
1466        $rhs_value =  &$rhs->value;
1467
1468        // $temp = $y << ($x_max - $y_max-1) in base 2**26
1469        $temp_value = array_m…

Large files files are truncated, but you can click here to view the full file