[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/phpseclib/ -> Math_BigInteger.php (source)

   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   */
  86  define('MATH_BIGINTEGER_MONTGOMERY', 0);
  87  /**
  88   * @see Math_BigInteger::_barrett()
  89   */
  90  define('MATH_BIGINTEGER_BARRETT', 1);
  91  /**
  92   * @see Math_BigInteger::_mod2()
  93   */
  94  define('MATH_BIGINTEGER_POWEROF2', 2);
  95  /**
  96   * @see Math_BigInteger::_remainder()
  97   */
  98  define('MATH_BIGINTEGER_CLASSIC', 3);
  99  /**
 100   * @see Math_BigInteger::__clone()
 101   */
 102  define('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   */
 116  define('MATH_BIGINTEGER_VALUE', 0);
 117  /**
 118   * $result[MATH_BIGINTEGER_SIGN] contains the sign.
 119   */
 120  define('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   */
 133  define('MATH_BIGINTEGER_VARIABLE', 0);
 134  /**
 135   * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
 136   */
 137  define('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   */
 149  define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
 150  /**
 151   * To use the BCMath library
 152   *
 153   * (if enabled; otherwise, the internal implementation will be used)
 154   */
 155  define('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   */
 161  define('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   */
 171  define('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   */
 182  class 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_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
1470  
1471          while ( $x->compare($temp) >= 0 ) {
1472              // calculate the "common residue"
1473              ++$quotient_value[$x_max - $y_max];
1474              $x = $x->subtract($temp);
1475              $x_max = count($x->value) - 1;
1476          }
1477  
1478          for ($i = $x_max; $i >= $y_max + 1; --$i) {
1479              $x_value = &$x->value;
1480              $x_window = array(
1481                  isset($x_value[$i]) ? $x_value[$i] : 0,
1482                  isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
1483                  isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
1484              );
1485              $y_window = array(
1486                  $y_value[$y_max],
1487                  ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
1488              );
1489  
1490              $q_index = $i - $y_max - 1;
1491              if ($x_window[0] == $y_window[0]) {
1492                  $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
1493              } else {
1494                  $quotient_value[$q_index] = (int) (
1495                      ($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1])
1496                      /
1497                      $y_window[0]
1498                  );
1499              }
1500  
1501              $temp_value = array($y_window[1], $y_window[0]);
1502  
1503              $lhs->value = array($quotient_value[$q_index]);
1504              $lhs = $lhs->multiply($temp);
1505  
1506              $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
1507  
1508              while ( $lhs->compare($rhs) > 0 ) {
1509                  --$quotient_value[$q_index];
1510  
1511                  $lhs->value = array($quotient_value[$q_index]);
1512                  $lhs = $lhs->multiply($temp);
1513              }
1514  
1515              $adjust = $this->_array_repeat(0, $q_index);
1516              $temp_value = array($quotient_value[$q_index]);
1517              $temp = $temp->multiply($y);
1518              $temp_value = &$temp->value;
1519              $temp_value = array_merge($adjust, $temp_value);
1520  
1521              $x = $x->subtract($temp);
1522  
1523              if ($x->compare($zero) < 0) {
1524                  $temp_value = array_merge($adjust, $y_value);
1525                  $x = $x->add($temp);
1526  
1527                  --$quotient_value[$q_index];
1528              }
1529  
1530              $x_max = count($x_value) - 1;
1531          }
1532  
1533          // unnormalize the remainder
1534          $x->_rshift($shift);
1535  
1536          $quotient->is_negative = $x_sign != $y_sign;
1537  
1538          // calculate the "common residue", if appropriate
1539          if ( $x_sign ) {
1540              $y->_rshift($shift);
1541              $x = $y->subtract($x);
1542          }
1543  
1544          return array($this->_normalize($quotient), $this->_normalize($x));
1545      }
1546  
1547      /**
1548       * Divides a BigInteger by a regular integer
1549       *
1550       * abc / x = a00 / x + b0 / x + c / x
1551       *
1552       * @param Array $dividend
1553       * @param Array $divisor
1554       * @return Array
1555       * @access private
1556       */
1557      function _divide_digit($dividend, $divisor)
1558      {
1559          $carry = 0;
1560          $result = array();
1561  
1562          for ($i = count($dividend) - 1; $i >= 0; --$i) {
1563              $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];
1564              $result[$i] = (int) ($temp / $divisor);
1565              $carry = (int) ($temp - $divisor * $result[$i]);
1566          }
1567  
1568          return array($result, $carry);
1569      }
1570  
1571      /**
1572       * Performs modular exponentiation.
1573       *
1574       * Here's an example:
1575       * <code>
1576       * <?php
1577       *    include('Math/BigInteger.php');
1578       *
1579       *    $a = new Math_BigInteger('10');
1580       *    $b = new Math_BigInteger('20');
1581       *    $c = new Math_BigInteger('30');
1582       *
1583       *    $c = $a->modPow($b, $c);
1584       *
1585       *    echo $c->toString(); // outputs 10
1586       * ?>
1587       * </code>
1588       *
1589       * @param Math_BigInteger $e
1590       * @param Math_BigInteger $n
1591       * @return Math_BigInteger
1592       * @access public
1593       * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
1594       *    and although the approach involving repeated squaring does vastly better, it, too, is impractical
1595       *    for our purposes.  The reason being that division - by far the most complicated and time-consuming
1596       *    of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
1597       *
1598       *    Modular reductions resolve this issue.  Although an individual modular reduction takes more time
1599       *    then an individual division, when performed in succession (with the same modulo), they're a lot faster.
1600       *
1601       *    The two most commonly used modular reductions are Barrett and Montgomery reduction.  Montgomery reduction,
1602       *    although faster, only works when the gcd of the modulo and of the base being used is 1.  In RSA, when the
1603       *    base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
1604       *    the product of two odd numbers is odd), but what about when RSA isn't used?
1605       *
1606       *    In contrast, Barrett reduction has no such constraint.  As such, some bigint implementations perform a
1607       *    Barrett reduction after every operation in the modpow function.  Others perform Barrett reductions when the
1608       *    modulo is even and Montgomery reductions when the modulo is odd.  BigInteger.java's modPow method, however,
1609       *    uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
1610       *    the other, a power of two - and recombine them, later.  This is the method that this modPow function uses.
1611       *    {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
1612       */
1613      function modPow($e, $n)
1614      {
1615          $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
1616  
1617          if ($e->compare(new Math_BigInteger()) < 0) {
1618              $e = $e->abs();
1619  
1620              $temp = $this->modInverse($n);
1621              if ($temp === false) {
1622                  return false;
1623              }
1624  
1625              return $this->_normalize($temp->modPow($e, $n));
1626          }
1627  
1628          if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) {
1629              $temp = new Math_BigInteger();
1630              $temp->value = gmp_powm($this->value, $e->value, $n->value);
1631  
1632              return $this->_normalize($temp);
1633          }
1634  
1635          if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {
1636              list(, $temp) = $this->divide($n);
1637              return $temp->modPow($e, $n);
1638          }
1639  
1640          if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
1641              $components = array(
1642                  'modulus' => $n->toBytes(true),
1643                  'publicExponent' => $e->toBytes(true)
1644              );
1645  
1646              $components = array(
1647                  'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
1648                  'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
1649              );
1650  
1651              $RSAPublicKey = pack('Ca*a*a*',
1652                  48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
1653                  $components['modulus'], $components['publicExponent']
1654              );
1655  
1656              $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1657              $RSAPublicKey = chr(0) . $RSAPublicKey;
1658              $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
1659  
1660              $encapsulated = pack('Ca*a*',
1661                  48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
1662              );
1663  
1664              $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1665                               chunk_split(base64_encode($encapsulated)) .
1666                               '-----END PUBLIC KEY-----';
1667  
1668              $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
1669  
1670              if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
1671                  return new Math_BigInteger($result, 256);
1672              }
1673          }
1674  
1675          if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
1676                  $temp = new Math_BigInteger();
1677                  $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
1678  
1679                  return $this->_normalize($temp);
1680          }
1681  
1682          if ( empty($e->value) ) {
1683              $temp = new Math_BigInteger();
1684              $temp->value = array(1);
1685              return $this->_normalize($temp);
1686          }
1687  
1688          if ( $e->value == array(1) ) {
1689              list(, $temp) = $this->divide($n);
1690              return $this->_normalize($temp);
1691          }
1692  
1693          if ( $e->value == array(2) ) {
1694              $temp = new Math_BigInteger();
1695              $temp->value = $this->_square($this->value);
1696              list(, $temp) = $temp->divide($n);
1697              return $this->_normalize($temp);
1698          }
1699  
1700          return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
1701  
1702          // is the modulo odd?
1703          if ( $n->value[0] & 1 ) {
1704              return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
1705          }
1706          // if it's not, it's even
1707  
1708          // find the lowest set bit (eg. the max pow of 2 that divides $n)
1709          for ($i = 0; $i < count($n->value); ++$i) {
1710              if ( $n->value[$i] ) {
1711                  $temp = decbin($n->value[$i]);
1712                  $j = strlen($temp) - strrpos($temp, '1') - 1;
1713                  $j+= 26 * $i;
1714                  break;
1715              }
1716          }
1717          // at this point, 2^$j * $n/(2^$j) == $n
1718  
1719          $mod1 = $n->copy();
1720          $mod1->_rshift($j);
1721          $mod2 = new Math_BigInteger();
1722          $mod2->value = array(1);
1723          $mod2->_lshift($j);
1724  
1725          $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
1726          $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
1727  
1728          $y1 = $mod2->modInverse($mod1);
1729          $y2 = $mod1->modInverse($mod2);
1730  
1731          $result = $part1->multiply($mod2);
1732          $result = $result->multiply($y1);
1733  
1734          $temp = $part2->multiply($mod1);
1735          $temp = $temp->multiply($y2);
1736  
1737          $result = $result->add($temp);
1738          list(, $result) = $result->divide($n);
1739  
1740          return $this->_normalize($result);
1741      }
1742  
1743      /**
1744       * Performs modular exponentiation.
1745       *
1746       * Alias for Math_BigInteger::modPow()
1747       *
1748       * @param Math_BigInteger $e
1749       * @param Math_BigInteger $n
1750       * @return Math_BigInteger
1751       * @access public
1752       */
1753      function powMod($e, $n)
1754      {
1755          return $this->modPow($e, $n);
1756      }
1757  
1758      /**
1759       * Sliding Window k-ary Modular Exponentiation
1760       *
1761       * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
1762       * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}.  In a departure from those algorithims,
1763       * however, this function performs a modular reduction after every multiplication and squaring operation.
1764       * As such, this function has the same preconditions that the reductions being used do.
1765       *
1766       * @param Math_BigInteger $e
1767       * @param Math_BigInteger $n
1768       * @param Integer $mode
1769       * @return Math_BigInteger
1770       * @access private
1771       */
1772      function _slidingWindow($e, $n, $mode)
1773      {
1774          static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
1775          //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
1776  
1777          $e_value = $e->value;
1778          $e_length = count($e_value) - 1;
1779          $e_bits = decbin($e_value[$e_length]);
1780          for ($i = $e_length - 1; $i >= 0; --$i) {
1781              $e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT);
1782          }
1783  
1784          $e_length = strlen($e_bits);
1785  
1786          // calculate the appropriate window size.
1787          // $window_size == 3 if $window_ranges is between 25 and 81, for example.
1788          for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);
1789  
1790          $n_value = $n->value;
1791  
1792          // precompute $this^0 through $this^$window_size
1793          $powers = array();
1794          $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
1795          $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
1796  
1797          // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
1798          // in a 1.  ie. it's supposed to be odd.
1799          $temp = 1 << ($window_size - 1);
1800          for ($i = 1; $i < $temp; ++$i) {
1801              $i2 = $i << 1;
1802              $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
1803          }
1804  
1805          $result = array(1);
1806          $result = $this->_prepareReduce($result, $n_value, $mode);
1807  
1808          for ($i = 0; $i < $e_length; ) {
1809              if ( !$e_bits[$i] ) {
1810                  $result = $this->_squareReduce($result, $n_value, $mode);
1811                  ++$i;
1812              } else {
1813                  for ($j = $window_size - 1; $j > 0; --$j) {
1814                      if ( !empty($e_bits[$i + $j]) ) {
1815                          break;
1816                      }
1817                  }
1818  
1819                  for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
1820                      $result = $this->_squareReduce($result, $n_value, $mode);
1821                  }
1822  
1823                  $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
1824  
1825                  $i+=$j + 1;
1826              }
1827          }
1828  
1829          $temp = new Math_BigInteger();
1830          $temp->value = $this->_reduce($result, $n_value, $mode);
1831  
1832          return $temp;
1833      }
1834  
1835      /**
1836       * Modular reduction
1837       *
1838       * For most $modes this will return the remainder.
1839       *
1840       * @see _slidingWindow()
1841       * @access private
1842       * @param Array $x
1843       * @param Array $n
1844       * @param Integer $mode
1845       * @return Array
1846       */
1847      function _reduce($x, $n, $mode)
1848      {
1849          switch ($mode) {
1850              case MATH_BIGINTEGER_MONTGOMERY:
1851                  return $this->_montgomery($x, $n);
1852              case MATH_BIGINTEGER_BARRETT:
1853                  return $this->_barrett($x, $n);
1854              case MATH_BIGINTEGER_POWEROF2:
1855                  $lhs = new Math_BigInteger();
1856                  $lhs->value = $x;
1857                  $rhs = new Math_BigInteger();
1858                  $rhs->value = $n;
1859                  return $x->_mod2($n);
1860              case MATH_BIGINTEGER_CLASSIC:
1861                  $lhs = new Math_BigInteger();
1862                  $lhs->value = $x;
1863                  $rhs = new Math_BigInteger();
1864                  $rhs->value = $n;
1865                  list(, $temp) = $lhs->divide($rhs);
1866                  return $temp->value;
1867              case MATH_BIGINTEGER_NONE:
1868                  return $x;
1869              default:
1870                  // an invalid $mode was provided
1871          }
1872      }
1873  
1874      /**
1875       * Modular reduction preperation
1876       *
1877       * @see _slidingWindow()
1878       * @access private
1879       * @param Array $x
1880       * @param Array $n
1881       * @param Integer $mode
1882       * @return Array
1883       */
1884      function _prepareReduce($x, $n, $mode)
1885      {
1886          if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1887              return $this->_prepMontgomery($x, $n);
1888          }
1889          return $this->_reduce($x, $n, $mode);
1890      }
1891  
1892      /**
1893       * Modular multiply
1894       *
1895       * @see _slidingWindow()
1896       * @access private
1897       * @param Array $x
1898       * @param Array $y
1899       * @param Array $n
1900       * @param Integer $mode
1901       * @return Array
1902       */
1903      function _multiplyReduce($x, $y, $n, $mode)
1904      {
1905          if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1906              return $this->_montgomeryMultiply($x, $y, $n);
1907          }
1908          $temp = $this->_multiply($x, false, $y, false);
1909          return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
1910      }
1911  
1912      /**
1913       * Modular square
1914       *
1915       * @see _slidingWindow()
1916       * @access private
1917       * @param Array $x
1918       * @param Array $n
1919       * @param Integer $mode
1920       * @return Array
1921       */
1922      function _squareReduce($x, $n, $mode)
1923      {
1924          if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1925              return $this->_montgomeryMultiply($x, $x, $n);
1926          }
1927          return $this->_reduce($this->_square($x), $n, $mode);
1928      }
1929  
1930      /**
1931       * Modulos for Powers of Two
1932       *
1933       * Calculates $x%$n, where $n = 2**$e, for some $e.  Since this is basically the same as doing $x & ($n-1),
1934       * we'll just use this function as a wrapper for doing that.
1935       *
1936       * @see _slidingWindow()
1937       * @access private
1938       * @param Math_BigInteger
1939       * @return Math_BigInteger
1940       */
1941      function _mod2($n)
1942      {
1943          $temp = new Math_BigInteger();
1944          $temp->value = array(1);
1945          return $this->bitwise_and($n->subtract($temp));
1946      }
1947  
1948      /**
1949       * Barrett Modular Reduction
1950       *
1951       * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
1952       * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information.  Modified slightly,
1953       * so as not to require negative numbers (initially, this script didn't support negative numbers).
1954       *
1955       * Employs "folding", as described at
1956       * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}.  To quote from
1957       * 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."
1958       *
1959       * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
1960       * usable on account of (1) its not using reasonable radix points as discussed in
1961       * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
1962       * radix points, it only works when there are an even number of digits in the denominator.  The reason for (2) is that
1963       * (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
1964       * comments for details.
1965       *
1966       * @see _slidingWindow()
1967       * @access private
1968       * @param Array $n
1969       * @param Array $m
1970       * @return Array
1971       */
1972      function _barrett($n, $m)
1973      {
1974          static $cache = array(
1975              MATH_BIGINTEGER_VARIABLE => array(),
1976              MATH_BIGINTEGER_DATA => array()
1977          );
1978  
1979          $m_length = count($m);
1980  
1981          // if ($this->_compare($n, $this->_square($m)) >= 0) {
1982          if (count($n) > 2 * $m_length) {
1983              $lhs = new Math_BigInteger();
1984              $rhs = new Math_BigInteger();
1985              $lhs->value = $n;
1986              $rhs->value = $m;
1987              list(, $temp) = $lhs->divide($rhs);
1988              return $temp->value;
1989          }
1990  
1991          // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
1992          if ($m_length < 5) {
1993              return $this->_regularBarrett($n, $m);
1994          }
1995  
1996          // n = 2 * m.length
1997  
1998          if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
1999              $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2000              $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
2001  
2002              $lhs = new Math_BigInteger();
2003              $lhs_value = &$lhs->value;
2004              $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
2005              $lhs_value[] = 1;
2006              $rhs = new Math_BigInteger();
2007              $rhs->value = $m;
2008  
2009              list($u, $m1) = $lhs->divide($rhs);
2010              $u = $u->value;
2011              $m1 = $m1->value;
2012  
2013              $cache[MATH_BIGINTEGER_DATA][] = array(
2014                  'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
2015                  'm1'=> $m1 // m.length
2016              );
2017          } else {
2018              extract($cache[MATH_BIGINTEGER_DATA][$key]);
2019          }
2020  
2021          $cutoff = $m_length + ($m_length >> 1);
2022          $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
2023          $msd = array_slice($n, $cutoff);    // m.length >> 1
2024          $lsd = $this->_trim($lsd);
2025          $temp = $this->_multiply($msd, false, $m1, false);
2026          $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
2027  
2028          if ($m_length & 1) {
2029              return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
2030          }
2031  
2032          // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
2033          $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
2034          // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
2035          // if odd:  ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
2036          $temp = $this->_multiply($temp, false, $u, false);
2037          // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
2038          // if odd:  (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
2039          $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
2040          // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
2041          // if odd:  (m.length - (m.length >> 1)) + m.length     = 2 * m.length - (m.length >> 1)
2042          $temp = $this->_multiply($temp, false, $m, false);
2043  
2044          // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
2045          // number from a m.length + (m.length >> 1) + 1 digit number.  ie. there'd be an extra digit and the while loop
2046          // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
2047  
2048          $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2049  
2050          while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
2051              $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
2052          }
2053  
2054          return $result[MATH_BIGINTEGER_VALUE];
2055      }
2056  
2057      /**
2058       * (Regular) Barrett Modular Reduction
2059       *
2060       * For numbers with more than four digits Math_BigInteger::_barrett() is faster.  The difference between that and this
2061       * is that this function does not fold the denominator into a smaller form.
2062       *
2063       * @see _slidingWindow()
2064       * @access private
2065       * @param Array $x
2066       * @param Array $n
2067       * @return Array
2068       */
2069      function _regularBarrett($x, $n)
2070      {
2071          static $cache = array(
2072              MATH_BIGINTEGER_VARIABLE => array(),
2073              MATH_BIGINTEGER_DATA => array()
2074          );
2075  
2076          $n_length = count($n);
2077  
2078          if (count($x) > 2 * $n_length) {
2079              $lhs = new Math_BigInteger();
2080              $rhs = new Math_BigInteger();
2081              $lhs->value = $x;
2082              $rhs->value = $n;
2083              list(, $temp) = $lhs->divide($rhs);
2084              return $temp->value;
2085          }
2086  
2087          if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2088              $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2089              $cache[MATH_BIGINTEGER_VARIABLE][] = $n;
2090              $lhs = new Math_BigInteger();
2091              $lhs_value = &$lhs->value;
2092              $lhs_value = $this->_array_repeat(0, 2 * $n_length);
2093              $lhs_value[] = 1;
2094              $rhs = new Math_BigInteger();
2095              $rhs->value = $n;
2096              list($temp, ) = $lhs->divide($rhs); // m.length
2097              $cache[MATH_BIGINTEGER_DATA][] = $temp->value;
2098          }
2099  
2100          // 2 * m.length - (m.length - 1) = m.length + 1
2101          $temp = array_slice($x, $n_length - 1);
2102          // (m.length + 1) + m.length = 2 * m.length + 1
2103          $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
2104          // (2 * m.length + 1) - (m.length - 1) = m.length + 2
2105          $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);
2106  
2107          // m.length + 1
2108          $result = array_slice($x, 0, $n_length + 1);
2109          // m.length + 1
2110          $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
2111          // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
2112  
2113          if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
2114              $corrector_value = $this->_array_repeat(0, $n_length + 1);
2115              $corrector_value[] = 1;
2116              $result = $this->_add($result, false, $corrector_value, false);
2117              $result = $result[MATH_BIGINTEGER_VALUE];
2118          }
2119  
2120          // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
2121          $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
2122          while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
2123              $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
2124          }
2125  
2126          return $result[MATH_BIGINTEGER_VALUE];
2127      }
2128  
2129      /**
2130       * Performs long multiplication up to $stop digits
2131       *
2132       * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
2133       *
2134       * @see _regularBarrett()
2135       * @param Array $x_value
2136       * @param Boolean $x_negative
2137       * @param Array $y_value
2138       * @param Boolean $y_negative
2139       * @param Integer $stop
2140       * @return Array
2141       * @access private
2142       */
2143      function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
2144      {
2145          $x_length = count($x_value);
2146          $y_length = count($y_value);
2147  
2148          if ( !$x_length || !$y_length ) { // a 0 is being multiplied
2149              return array(
2150                  MATH_BIGINTEGER_VALUE => array(),
2151                  MATH_BIGINTEGER_SIGN => false
2152              );
2153          }
2154  
2155          if ( $x_length < $y_length ) {
2156              $temp = $x_value;
2157              $x_value = $y_value;
2158              $y_value = $temp;
2159  
2160              $x_length = count($x_value);
2161              $y_length = count($y_value);
2162          }
2163  
2164          $product_value = $this->_array_repeat(0, $x_length + $y_length);
2165  
2166          // the following for loop could be removed if the for loop following it
2167          // (the one with nested for loops) initially set $i to 0, but
2168          // doing so would also make the result in one set of unnecessary adds,
2169          // since on the outermost loops first pass, $product->value[$k] is going
2170          // to always be 0
2171  
2172          $carry = 0;
2173  
2174          for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
2175              $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
2176              $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
2177              $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
2178          }
2179  
2180          if ($j < $stop) {
2181              $product_value[$j] = $carry;
2182          }
2183  
2184          // the above for loop is what the previous comment was talking about.  the
2185          // following for loop is the "one with nested for loops"
2186  
2187          for ($i = 1; $i < $y_length; ++$i) {
2188              $carry = 0;
2189  
2190              for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
2191                  $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
2192                  $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
2193                  $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
2194              }
2195  
2196              if ($k < $stop) {
2197                  $product_value[$k] = $carry;
2198              }
2199          }
2200  
2201          return array(
2202              MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
2203              MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
2204          );
2205      }
2206  
2207      /**
2208       * Montgomery Modular Reduction
2209       *
2210       * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
2211       * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
2212       * improved upon (basically, by using the comba method).  gcd($n, 2) must be equal to one for this function
2213       * to work correctly.
2214       *
2215       * @see _prepMontgomery()
2216       * @see _slidingWindow()
2217       * @access private
2218       * @param Array $x
2219       * @param Array $n
2220       * @return Array
2221       */
2222      function _montgomery($x, $n)
2223      {
2224          static $cache = array(
2225              MATH_BIGINTEGER_VARIABLE => array(),
2226              MATH_BIGINTEGER_DATA => array()
2227          );
2228  
2229          if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2230              $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2231              $cache[MATH_BIGINTEGER_VARIABLE][] = $x;
2232              $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
2233          }
2234  
2235          $k = count($n);
2236  
2237          $result = array(MATH_BIGINTEGER_VALUE => $x);
2238  
2239          for ($i = 0; $i < $k; ++$i) {
2240              $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
2241              $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
2242              $temp = $this->_regularMultiply(array($temp), $n);
2243              $temp = array_merge($this->_array_repeat(0, $i), $temp);
2244              $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
2245          }
2246  
2247          $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);
2248  
2249          if ($this->_compare($result, false, $n, false) >= 0) {
2250              $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
2251          }
2252  
2253          return $result[MATH_BIGINTEGER_VALUE];
2254      }
2255  
2256      /**
2257       * Montgomery Multiply
2258       *
2259       * Interleaves the montgomery reduction and long multiplication algorithms together as described in 
2260       * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
2261       *
2262       * @see _prepMontgomery()
2263       * @see _montgomery()
2264       * @access private
2265       * @param Array $x
2266       * @param Array $y
2267       * @param Array $m
2268       * @return Array
2269       */
2270      function _montgomeryMultiply($x, $y, $m)
2271      {
2272          $temp = $this->_multiply($x, false, $y, false);
2273          return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
2274  
2275          static $cache = array(
2276              MATH_BIGINTEGER_VARIABLE => array(),
2277              MATH_BIGINTEGER_DATA => array()
2278          );
2279  
2280          if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2281              $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2282              $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
2283              $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
2284          }
2285  
2286          $n = max(count($x), count($y), count($m));
2287          $x = array_pad($x, $n, 0);
2288          $y = array_pad($y, $n, 0);
2289          $m = array_pad($m, $n, 0);
2290          $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
2291          for ($i = 0; $i < $n; ++$i) {
2292              $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
2293              $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
2294              $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
2295              $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
2296              $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
2297              $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2298              $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
2299          }
2300          if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
2301              $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
2302          }
2303          return $a[MATH_BIGINTEGER_VALUE];
2304      }
2305  
2306      /**
2307       * Prepare a number for use in Montgomery Modular Reductions
2308       *
2309       * @see _montgomery()
2310       * @see _slidingWindow()
2311       * @access private
2312       * @param Array $x
2313       * @param Array $n
2314       * @return Array
2315       */
2316      function _prepMontgomery($x, $n)
2317      {
2318          $lhs = new Math_BigInteger();
2319          $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
2320          $rhs = new Math_BigInteger();
2321          $rhs->value = $n;
2322  
2323          list(, $temp) = $lhs->divide($rhs);
2324          return $temp->value;
2325      }
2326  
2327      /**
2328       * Modular Inverse of a number mod 2**26 (eg. 67108864)
2329       *
2330       * Based off of the bnpInvDigit function implemented and justified in the following URL:
2331       *
2332       * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
2333       *
2334       * The following URL provides more info:
2335       *
2336       * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
2337       *
2338       * As for why we do all the bitmasking...  strange things can happen when converting from floats to ints. For
2339       * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields 
2340       * int(-2147483648).  To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
2341       * auto-converted to floats.  The outermost bitmask is present because without it, there's no guarantee that
2342       * the "residue" returned would be the so-called "common residue".  We use fmod, in the last step, because the
2343       * maximum possible $x is 26 bits and the maximum $result is 16 bits.  Thus, we have to be able to handle up to
2344       * 40 bits, which only 64-bit floating points will support.
2345       *
2346       * Thanks to Pedro Gimeno Fortea for input!
2347       *
2348       * @see _montgomery()
2349       * @access private
2350       * @param Array $x
2351       * @return Integer
2352       */
2353      function _modInverse67108864($x) // 2**26 == 67,108,864
2354      {
2355          $x = -$x[0];
2356          $result = $x & 0x3; // x**-1 mod 2**2
2357          $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
2358          $result = ($result * (2 - ($x & 0xFF) * $result))  & 0xFF; // x**-1 mod 2**8
2359          $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
2360          $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26
2361          return $result & MATH_BIGINTEGER_MAX_DIGIT;
2362      }
2363  
2364      /**
2365       * Calculates modular inverses.
2366       *
2367       * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
2368       *
2369       * Here's an example:
2370       * <code>
2371       * <?php
2372       *    include('Math/BigInteger.php');
2373       *
2374       *    $a = new Math_BigInteger(30);
2375       *    $b = new Math_BigInteger(17);
2376       *
2377       *    $c = $a->modInverse($b);
2378       *    echo $c->toString(); // outputs 4
2379       *
2380       *    echo "\r\n";
2381       *
2382       *    $d = $a->multiply($c);
2383       *    list(, $d) = $d->divide($b);
2384       *    echo $d; // outputs 1 (as per the definition of modular inverse)
2385       * ?>
2386       * </code>
2387       *
2388       * @param Math_BigInteger $n
2389       * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise.
2390       * @access public
2391       * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
2392       */
2393      function modInverse($n)
2394      {
2395          switch ( MATH_BIGINTEGER_MODE ) {
2396              case MATH_BIGINTEGER_MODE_GMP:
2397                  $temp = new Math_BigInteger();
2398                  $temp->value = gmp_invert($this->value, $n->value);
2399  
2400                  return ( $temp->value === false ) ? false : $this->_normalize($temp);
2401          }
2402  
2403          static $zero, $one;
2404          if (!isset($zero)) {
2405              $zero = new Math_BigInteger();
2406              $one = new Math_BigInteger(1);
2407          }
2408  
2409          // $x mod -$n == $x mod $n.
2410          $n = $n->abs();
2411  
2412          if ($this->compare($zero) < 0) {
2413              $temp = $this->abs();
2414              $temp = $temp->modInverse($n);
2415              return $this->_normalize($n->subtract($temp));
2416          }
2417  
2418          extract($this->extendedGCD($n));
2419  
2420          if (!$gcd->equals($one)) {
2421              return false;
2422          }
2423  
2424          $x = $x->compare($zero) < 0 ? $x->add($n) : $x;
2425  
2426          return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
2427      }
2428  
2429      /**
2430       * Calculates the greatest common divisor and Bezout's identity.
2431       *
2432       * Say you have 693 and 609.  The GCD is 21.  Bezout's identity states that there exist integers x and y such that
2433       * 693*x + 609*y == 21.  In point of fact, there are actually an infinite number of x and y combinations and which
2434       * combination is returned is dependant upon which mode is in use.  See
2435       * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
2436       *
2437       * Here's an example:
2438       * <code>
2439       * <?php
2440       *    include('Math/BigInteger.php');
2441       *
2442       *    $a = new Math_BigInteger(693);
2443       *    $b = new Math_BigInteger(609);
2444       *
2445       *    extract($a->extendedGCD($b));
2446       *
2447       *    echo $gcd->toString() . "\r\n"; // outputs 21
2448       *    echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
2449       * ?>
2450       * </code>
2451       *
2452       * @param Math_BigInteger $n
2453       * @return Math_BigInteger
2454       * @access public
2455       * @internal Calculates the GCD using the binary xGCD algorithim described in
2456       *    {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}.  As the text above 14.61 notes,
2457       *    the more traditional algorithim requires "relatively costly multiple-precision divisions".
2458       */
2459      function extendedGCD($n)
2460      {
2461          switch ( MATH_BIGINTEGER_MODE ) {
2462              case MATH_BIGINTEGER_MODE_GMP:
2463                  extract(gmp_gcdext($this->value, $n->value));
2464  
2465                  return array(
2466                      'gcd' => $this->_normalize(new Math_BigInteger($g)),
2467                      'x'   => $this->_normalize(new Math_BigInteger($s)),
2468                      'y'   => $this->_normalize(new Math_BigInteger($t))
2469                  );
2470              case MATH_BIGINTEGER_MODE_BCMATH:
2471                  // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
2472                  // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway.  as is,
2473                  // the basic extended euclidean algorithim is what we're using.
2474  
2475                  $u = $this->value;
2476                  $v = $n->value;
2477  
2478                  $a = '1';
2479                  $b = '0';
2480                  $c = '0';
2481                  $d = '1';
2482  
2483                  while (bccomp($v, '0', 0) != 0) {
2484                      $q = bcdiv($u, $v, 0);
2485  
2486                      $temp = $u;
2487                      $u = $v;
2488                      $v = bcsub($temp, bcmul($v, $q, 0), 0);
2489  
2490                      $temp = $a;
2491                      $a = $c;
2492                      $c = bcsub($temp, bcmul($a, $q, 0), 0);
2493  
2494                      $temp = $b;
2495                      $b = $d;
2496                      $d = bcsub($temp, bcmul($b, $q, 0), 0);
2497                  }
2498  
2499                  return array(
2500                      'gcd' => $this->_normalize(new Math_BigInteger($u)),
2501                      'x'   => $this->_normalize(new Math_BigInteger($a)),
2502                      'y'   => $this->_normalize(new Math_BigInteger($b))
2503                  );
2504          }
2505  
2506          $y = $n->copy();
2507          $x = $this->copy();
2508          $g = new Math_BigInteger();
2509          $g->value = array(1);
2510  
2511          while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {
2512              $x->_rshift(1);
2513              $y->_rshift(1);
2514              $g->_lshift(1);
2515          }
2516  
2517          $u = $x->copy();
2518          $v = $y->copy();
2519  
2520          $a = new Math_BigInteger();
2521          $b = new Math_BigInteger();
2522          $c = new Math_BigInteger();
2523          $d = new Math_BigInteger();
2524  
2525          $a->value = $d->value = $g->value = array(1);
2526          $b->value = $c->value = array();
2527  
2528          while ( !empty($u->value) ) {
2529              while ( !($u->value[0] & 1) ) {
2530                  $u->_rshift(1);
2531                  if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) {
2532                      $a = $a->add($y);
2533                      $b = $b->subtract($x);
2534                  }
2535                  $a->_rshift(1);
2536                  $b->_rshift(1);
2537              }
2538  
2539              while ( !($v->value[0] & 1) ) {
2540                  $v->_rshift(1);
2541                  if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) {
2542                      $c = $c->add($y);
2543                      $d = $d->subtract($x);
2544                  }
2545                  $c->_rshift(1);
2546                  $d->_rshift(1);
2547              }
2548  
2549              if ($u->compare($v) >= 0) {
2550                  $u = $u->subtract($v);
2551                  $a = $a->subtract($c);
2552                  $b = $b->subtract($d);
2553              } else {
2554                  $v = $v->subtract($u);
2555                  $c = $c->subtract($a);
2556                  $d = $d->subtract($b);
2557              }
2558          }
2559  
2560          return array(
2561              'gcd' => $this->_normalize($g->multiply($v)),
2562              'x'   => $this->_normalize($c),
2563              'y'   => $this->_normalize($d)
2564          );
2565      }
2566  
2567      /**
2568       * Calculates the greatest common divisor
2569       *
2570       * Say you have 693 and 609.  The GCD is 21.
2571       *
2572       * Here's an example:
2573       * <code>
2574       * <?php
2575       *    include('Math/BigInteger.php');
2576       *
2577       *    $a = new Math_BigInteger(693);
2578       *    $b = new Math_BigInteger(609);
2579       *
2580       *    $gcd = a->extendedGCD($b);
2581       *
2582       *    echo $gcd->toString() . "\r\n"; // outputs 21
2583       * ?>
2584       * </code>
2585       *
2586       * @param Math_BigInteger $n
2587       * @return Math_BigInteger
2588       * @access public
2589       */
2590      function gcd($n)
2591      {
2592          extract($this->extendedGCD($n));
2593          return $gcd;
2594      }
2595  
2596      /**
2597       * Absolute value.
2598       *
2599       * @return Math_BigInteger
2600       * @access public
2601       */
2602      function abs()
2603      {
2604          $temp = new Math_BigInteger();
2605  
2606          switch ( MATH_BIGINTEGER_MODE ) {
2607              case MATH_BIGINTEGER_MODE_GMP:
2608                  $temp->value = gmp_abs($this->value);
2609                  break;
2610              case MATH_BIGINTEGER_MODE_BCMATH:
2611                  $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
2612                  break;
2613              default:
2614                  $temp->value = $this->value;
2615          }
2616  
2617          return $temp;
2618      }
2619  
2620      /**
2621       * Compares two numbers.
2622       *
2623       * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this is
2624       * demonstrated thusly:
2625       *
2626       * $x  > $y: $x->compare($y)  > 0
2627       * $x  < $y: $x->compare($y)  < 0
2628       * $x == $y: $x->compare($y) == 0
2629       *
2630       * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
2631       *
2632       * @param Math_BigInteger $y
2633       * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
2634       * @access public
2635       * @see equals()
2636       * @internal Could return $this->subtract($x), but that's not as fast as what we do do.
2637       */
2638      function compare($y)
2639      {
2640          switch ( MATH_BIGINTEGER_MODE ) {
2641              case MATH_BIGINTEGER_MODE_GMP:
2642                  return gmp_cmp($this->value, $y->value);
2643              case MATH_BIGINTEGER_MODE_BCMATH:
2644                  return bccomp($this->value, $y->value, 0);
2645          }
2646  
2647          return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
2648      }
2649  
2650      /**
2651       * Compares two numbers.
2652       *
2653       * @param Array $x_value
2654       * @param Boolean $x_negative
2655       * @param Array $y_value
2656       * @param Boolean $y_negative
2657       * @return Integer
2658       * @see compare()
2659       * @access private
2660       */
2661      function _compare($x_value, $x_negative, $y_value, $y_negative)
2662      {
2663          if ( $x_negative != $y_negative ) {
2664              return ( !$x_negative && $y_negative ) ? 1 : -1;
2665          }
2666  
2667          $result = $x_negative ? -1 : 1;
2668  
2669          if ( count($x_value) != count($y_value) ) {
2670              return ( count($x_value) > count($y_value) ) ? $result : -$result;
2671          }
2672          $size = max(count($x_value), count($y_value));
2673  
2674          $x_value = array_pad($x_value, $size, 0);
2675          $y_value = array_pad($y_value, $size, 0);
2676  
2677          for ($i = count($x_value) - 1; $i >= 0; --$i) {
2678              if ($x_value[$i] != $y_value[$i]) {
2679                  return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;
2680              }
2681          }
2682  
2683          return 0;
2684      }
2685  
2686      /**
2687       * Tests the equality of two numbers.
2688       *
2689       * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()
2690       *
2691       * @param Math_BigInteger $x
2692       * @return Boolean
2693       * @access public
2694       * @see compare()
2695       */
2696      function equals($x)
2697      {
2698          switch ( MATH_BIGINTEGER_MODE ) {
2699              case MATH_BIGINTEGER_MODE_GMP:
2700                  return gmp_cmp($this->value, $x->value) == 0;
2701              default:
2702                  return $this->value === $x->value && $this->is_negative == $x->is_negative;
2703          }
2704      }
2705  
2706      /**
2707       * Set Precision
2708       *
2709       * Some bitwise operations give different results depending on the precision being used.  Examples include left
2710       * shift, not, and rotates.
2711       *
2712       * @param Integer $bits
2713       * @access public
2714       */
2715      function setPrecision($bits)
2716      {
2717          $this->precision = $bits;
2718          if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {
2719              $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
2720          } else {
2721              $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));
2722          }
2723  
2724          $temp = $this->_normalize($this);
2725          $this->value = $temp->value;
2726      }
2727  
2728      /**
2729       * Logical And
2730       *
2731       * @param Math_BigInteger $x
2732       * @access public
2733       * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2734       * @return Math_BigInteger
2735       */
2736      function bitwise_and($x)
2737      {
2738          switch ( MATH_BIGINTEGER_MODE ) {
2739              case MATH_BIGINTEGER_MODE_GMP:
2740                  $temp = new Math_BigInteger();
2741                  $temp->value = gmp_and($this->value, $x->value);
2742  
2743                  return $this->_normalize($temp);
2744              case MATH_BIGINTEGER_MODE_BCMATH:
2745                  $left = $this->toBytes();
2746                  $right = $x->toBytes();
2747  
2748                  $length = max(strlen($left), strlen($right));
2749  
2750                  $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2751                  $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2752  
2753                  return $this->_normalize(new Math_BigInteger($left & $right, 256));
2754          }
2755  
2756          $result = $this->copy();
2757  
2758          $length = min(count($x->value), count($this->value));
2759  
2760          $result->value = array_slice($result->value, 0, $length);
2761  
2762          for ($i = 0; $i < $length; ++$i) {
2763              $result->value[$i]&= $x->value[$i];
2764          }
2765  
2766          return $this->_normalize($result);
2767      }
2768  
2769      /**
2770       * Logical Or
2771       *
2772       * @param Math_BigInteger $x
2773       * @access public
2774       * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2775       * @return Math_BigInteger
2776       */
2777      function bitwise_or($x)
2778      {
2779          switch ( MATH_BIGINTEGER_MODE ) {
2780              case MATH_BIGINTEGER_MODE_GMP:
2781                  $temp = new Math_BigInteger();
2782                  $temp->value = gmp_or($this->value, $x->value);
2783  
2784                  return $this->_normalize($temp);
2785              case MATH_BIGINTEGER_MODE_BCMATH:
2786                  $left = $this->toBytes();
2787                  $right = $x->toBytes();
2788  
2789                  $length = max(strlen($left), strlen($right));
2790  
2791                  $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2792                  $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2793  
2794                  return $this->_normalize(new Math_BigInteger($left | $right, 256));
2795          }
2796  
2797          $length = max(count($this->value), count($x->value));
2798          $result = $this->copy();
2799          $result->value = array_pad($result->value, $length, 0);
2800          $x->value = array_pad($x->value, $length, 0);
2801  
2802          for ($i = 0; $i < $length; ++$i) {
2803              $result->value[$i]|= $x->value[$i];
2804          }
2805  
2806          return $this->_normalize($result);
2807      }
2808  
2809      /**
2810       * Logical Exclusive-Or
2811       *
2812       * @param Math_BigInteger $x
2813       * @access public
2814       * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2815       * @return Math_BigInteger
2816       */
2817      function bitwise_xor($x)
2818      {
2819          switch ( MATH_BIGINTEGER_MODE ) {
2820              case MATH_BIGINTEGER_MODE_GMP:
2821                  $temp = new Math_BigInteger();
2822                  $temp->value = gmp_xor($this->value, $x->value);
2823  
2824                  return $this->_normalize($temp);
2825              case MATH_BIGINTEGER_MODE_BCMATH:
2826                  $left = $this->toBytes();
2827                  $right = $x->toBytes();
2828  
2829                  $length = max(strlen($left), strlen($right));
2830  
2831                  $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2832                  $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2833  
2834                  return $this->_normalize(new Math_BigInteger($left ^ $right, 256));
2835          }
2836  
2837          $length = max(count($this->value), count($x->value));
2838          $result = $this->copy();
2839          $result->value = array_pad($result->value, $length, 0);
2840          $x->value = array_pad($x->value, $length, 0);
2841  
2842          for ($i = 0; $i < $length; ++$i) {
2843              $result->value[$i]^= $x->value[$i];
2844          }
2845  
2846          return $this->_normalize($result);
2847      }
2848  
2849      /**
2850       * Logical Not
2851       *
2852       * @access public
2853       * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2854       * @return Math_BigInteger
2855       */
2856      function bitwise_not()
2857      {
2858          // calculuate "not" without regard to $this->precision
2859          // (will always result in a smaller number.  ie. ~1 isn't 1111 1110 - it's 0)
2860          $temp = $this->toBytes();
2861          $pre_msb = decbin(ord($temp[0]));
2862          $temp = ~$temp;
2863          $msb = decbin(ord($temp[0]));
2864          if (strlen($msb) == 8) {
2865              $msb = substr($msb, strpos($msb, '0'));
2866          }
2867          $temp[0] = chr(bindec($msb));
2868  
2869          // see if we need to add extra leading 1's
2870          $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
2871          $new_bits = $this->precision - $current_bits;
2872          if ($new_bits <= 0) {
2873              return $this->_normalize(new Math_BigInteger($temp, 256));
2874          }
2875  
2876          // generate as many leading 1's as we need to.
2877          $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
2878          $this->_base256_lshift($leading_ones, $current_bits);
2879  
2880          $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT);
2881  
2882          return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
2883      }
2884  
2885      /**
2886       * Logical Right Shift
2887       *
2888       * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
2889       *
2890       * @param Integer $shift
2891       * @return Math_BigInteger
2892       * @access public
2893       * @internal The only version that yields any speed increases is the internal version.
2894       */
2895      function bitwise_rightShift($shift)
2896      {
2897          $temp = new Math_BigInteger();
2898  
2899          switch ( MATH_BIGINTEGER_MODE ) {
2900              case MATH_BIGINTEGER_MODE_GMP:
2901                  static $two;
2902  
2903                  if (!isset($two)) {
2904                      $two = gmp_init('2');
2905                  }
2906  
2907                  $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
2908  
2909                  break;
2910              case MATH_BIGINTEGER_MODE_BCMATH:
2911                  $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
2912  
2913                  break;
2914              default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
2915                       // and I don't want to do that...
2916                  $temp->value = $this->value;
2917                  $temp->_rshift($shift);
2918          }
2919  
2920          return $this->_normalize($temp);
2921      }
2922  
2923      /**
2924       * Logical Left Shift
2925       *
2926       * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
2927       *
2928       * @param Integer $shift
2929       * @return Math_BigInteger
2930       * @access public
2931       * @internal The only version that yields any speed increases is the internal version.
2932       */
2933      function bitwise_leftShift($shift)
2934      {
2935          $temp = new Math_BigInteger();
2936  
2937          switch ( MATH_BIGINTEGER_MODE ) {
2938              case MATH_BIGINTEGER_MODE_GMP:
2939                  static $two;
2940  
2941                  if (!isset($two)) {
2942                      $two = gmp_init('2');
2943                  }
2944  
2945                  $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
2946  
2947                  break;
2948              case MATH_BIGINTEGER_MODE_BCMATH:
2949                  $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
2950  
2951                  break;
2952              default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
2953                       // and I don't want to do that...
2954                  $temp->value = $this->value;
2955                  $temp->_lshift($shift);
2956          }
2957  
2958          return $this->_normalize($temp);
2959      }
2960  
2961      /**
2962       * Logical Left Rotate
2963       *
2964       * Instead of the top x bits being dropped they're appended to the shifted bit string.
2965       *
2966       * @param Integer $shift
2967       * @return Math_BigInteger
2968       * @access public
2969       */
2970      function bitwise_leftRotate($shift)
2971      {
2972          $bits = $this->toBytes();
2973  
2974          if ($this->precision > 0) {
2975              $precision = $this->precision;
2976              if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
2977                  $mask = $this->bitmask->subtract(new Math_BigInteger(1));
2978                  $mask = $mask->toBytes();
2979              } else {
2980                  $mask = $this->bitmask->toBytes();
2981              }
2982          } else {
2983              $temp = ord($bits[0]);
2984              for ($i = 0; $temp >> $i; ++$i);
2985              $precision = 8 * strlen($bits) - 8 + $i;
2986              $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
2987          }
2988  
2989          if ($shift < 0) {
2990              $shift+= $precision;
2991          }
2992          $shift%= $precision;
2993  
2994          if (!$shift) {
2995              return $this->copy();
2996          }
2997  
2998          $left = $this->bitwise_leftShift($shift);
2999          $left = $left->bitwise_and(new Math_BigInteger($mask, 256));
3000          $right = $this->bitwise_rightShift($precision - $shift);
3001          $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
3002          return $this->_normalize($result);
3003      }
3004  
3005      /**
3006       * Logical Right Rotate
3007       *
3008       * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
3009       *
3010       * @param Integer $shift
3011       * @return Math_BigInteger
3012       * @access public
3013       */
3014      function bitwise_rightRotate($shift)
3015      {
3016          return $this->bitwise_leftRotate(-$shift);
3017      }
3018  
3019      /**
3020       * Set random number generator function
3021       *
3022       * This function is deprecated.
3023       *
3024       * @param String $generator
3025       * @access public
3026       */
3027      function setRandomGenerator($generator)
3028      {
3029      }
3030  
3031      /**
3032       * Generate a random number
3033       *
3034       * @param optional Integer $min
3035       * @param optional Integer $max
3036       * @return Math_BigInteger
3037       * @access public
3038       */
3039      function random($min = false, $max = false)
3040      {
3041          if ($min === false) {
3042              $min = new Math_BigInteger(0);
3043          }
3044  
3045          if ($max === false) {
3046              $max = new Math_BigInteger(0x7FFFFFFF);
3047          }
3048  
3049          $compare = $max->compare($min);
3050  
3051          if (!$compare) {
3052              return $this->_normalize($min);
3053          } else if ($compare < 0) {
3054              // if $min is bigger then $max, swap $min and $max
3055              $temp = $max;
3056              $max = $min;
3057              $min = $temp;
3058          }
3059  
3060          $max = $max->subtract($min);
3061          $max = ltrim($max->toBytes(), chr(0));
3062          $size = strlen($max) - 1;
3063  
3064          $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string'));
3065          if ($crypt_random) {
3066              $random = crypt_random_string($size);
3067          } else {
3068              $random = '';
3069  
3070              if ($size & 1) {
3071                  $random.= chr(mt_rand(0, 255));
3072              }
3073  
3074              $blocks = $size >> 1;
3075              for ($i = 0; $i < $blocks; ++$i) {
3076                  // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
3077                  $random.= pack('n', mt_rand(0, 0xFFFF));
3078              }
3079          }
3080  
3081          $fragment = new Math_BigInteger($random, 256);
3082          $leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ?
3083              ord($max[0]) - 1 : ord($max[0]);
3084  
3085          if (!$crypt_random) {
3086              $msb = chr(mt_rand(0, $leading));
3087          } else {
3088              $cutoff = floor(0xFF / $leading) * $leading;
3089              while (true) {
3090                  $msb = ord(crypt_random_string(1));
3091                  if ($msb <= $cutoff) {
3092                      $msb%= $leading;
3093                      break;
3094                  }
3095              }
3096              $msb = chr($msb);
3097          }
3098  
3099          $random = new Math_BigInteger($msb . $random, 256);
3100  
3101          return $this->_normalize($random->add($min));
3102      }
3103  
3104      /**
3105       * Generate a random prime number.
3106       *
3107       * If there's not a prime within the given range, false will be returned.  If more than $timeout seconds have elapsed,
3108       * give up and return false.
3109       *
3110       * @param optional Integer $min
3111       * @param optional Integer $max
3112       * @param optional Integer $timeout
3113       * @return Math_BigInteger
3114       * @access public
3115       * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
3116       */
3117      function randomPrime($min = false, $max = false, $timeout = false)
3118      {
3119          if ($min === false) {
3120              $min = new Math_BigInteger(0);
3121          }
3122  
3123          if ($max === false) {
3124              $max = new Math_BigInteger(0x7FFFFFFF);
3125          }
3126  
3127          $compare = $max->compare($min);
3128  
3129          if (!$compare) {
3130              return $min->isPrime() ? $min : false;
3131          } else if ($compare < 0) {
3132              // if $min is bigger then $max, swap $min and $max
3133              $temp = $max;
3134              $max = $min;
3135              $min = $temp;
3136          }
3137  
3138          static $one, $two;
3139          if (!isset($one)) {
3140              $one = new Math_BigInteger(1);
3141              $two = new Math_BigInteger(2);
3142          }
3143  
3144          $start = time();
3145  
3146          $x = $this->random($min, $max);
3147  
3148          // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
3149          if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
3150              $p = new Math_BigInteger();
3151              $p->value = gmp_nextprime($x->value);
3152  
3153              if ($p->compare($max) <= 0) {
3154                  return $p;
3155              }
3156  
3157              if (!$min->equals($x)) {
3158                  $x = $x->subtract($one);
3159              }
3160  
3161              return $x->randomPrime($min, $x);
3162          }
3163  
3164          if ($x->equals($two)) {
3165              return $x;
3166          }
3167  
3168          $x->_make_odd();
3169          if ($x->compare($max) > 0) {
3170              // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
3171              if ($min->equals($max)) {
3172                  return false;
3173              }
3174              $x = $min->copy();
3175              $x->_make_odd();
3176          }
3177  
3178          $initial_x = $x->copy();
3179  
3180          while (true) {
3181              if ($timeout !== false && time() - $start > $timeout) {
3182                  return false;
3183              }
3184  
3185              if ($x->isPrime()) {
3186                  return $x;
3187              }
3188  
3189              $x = $x->add($two);
3190  
3191              if ($x->compare($max) > 0) {
3192                  $x = $min->copy();
3193                  if ($x->equals($two)) {
3194                      return $x;
3195                  }
3196                  $x->_make_odd();
3197              }
3198  
3199              if ($x->equals($initial_x)) {
3200                  return false;
3201              }
3202          }
3203      }
3204  
3205      /**
3206       * Make the current number odd
3207       *
3208       * If the current number is odd it'll be unchanged.  If it's even, one will be added to it.
3209       *
3210       * @see randomPrime()
3211       * @access private
3212       */
3213      function _make_odd()
3214      {
3215          switch ( MATH_BIGINTEGER_MODE ) {
3216              case MATH_BIGINTEGER_MODE_GMP:
3217                  gmp_setbit($this->value, 0);
3218                  break;
3219              case MATH_BIGINTEGER_MODE_BCMATH:
3220                  if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3221                      $this->value = bcadd($this->value, '1');
3222                  }
3223                  break;
3224              default:
3225                  $this->value[0] |= 1;
3226          }
3227      }
3228  
3229      /**
3230       * Checks a numer to see if it's prime
3231       *
3232       * Assuming the $t parameter is not set, this function has an error rate of 2**-80.  The main motivation for the
3233       * $t parameter is distributability.  Math_BigInteger::randomPrime() can be distributed accross multiple pageloads
3234       * on a website instead of just one.
3235       *
3236       * @param optional Integer $t
3237       * @return Boolean
3238       * @access public
3239       * @internal Uses the
3240       *     {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}.  See 
3241       *     {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
3242       */
3243      function isPrime($t = false)
3244      {
3245          $length = strlen($this->toBytes());
3246  
3247          if (!$t) {
3248              // see HAC 4.49 "Note (controlling the error probability)"
3249                   if ($length >= 163) { $t =  2; } // floor(1300 / 8)
3250              else if ($length >= 106) { $t =  3; } // floor( 850 / 8)
3251              else if ($length >= 81 ) { $t =  4; } // floor( 650 / 8)
3252              else if ($length >= 68 ) { $t =  5; } // floor( 550 / 8)
3253              else if ($length >= 56 ) { $t =  6; } // floor( 450 / 8)
3254              else if ($length >= 50 ) { $t =  7; } // floor( 400 / 8)
3255              else if ($length >= 43 ) { $t =  8; } // floor( 350 / 8)
3256              else if ($length >= 37 ) { $t =  9; } // floor( 300 / 8)
3257              else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
3258              else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
3259              else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
3260              else                     { $t = 27; }
3261          }
3262  
3263          // ie. gmp_testbit($this, 0)
3264          // ie. isEven() or !isOdd()
3265          switch ( MATH_BIGINTEGER_MODE ) {
3266              case MATH_BIGINTEGER_MODE_GMP:
3267                  return gmp_prob_prime($this->value, $t) != 0;
3268              case MATH_BIGINTEGER_MODE_BCMATH:
3269                  if ($this->value === '2') {
3270                      return true;
3271                  }
3272                  if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3273                      return false;
3274                  }
3275                  break;
3276              default:
3277                  if ($this->value == array(2)) {
3278                      return true;
3279                  }
3280                  if (~$this->value[0] & 1) {
3281                      return false;
3282                  }
3283          }
3284  
3285          static $primes, $zero, $one, $two;
3286  
3287          if (!isset($primes)) {
3288              $primes = array(
3289                  3,    5,    7,    11,   13,   17,   19,   23,   29,   31,   37,   41,   43,   47,   53,   59,   
3290                  61,   67,   71,   73,   79,   83,   89,   97,   101,  103,  107,  109,  113,  127,  131,  137,  
3291                  139,  149,  151,  157,  163,  167,  173,  179,  181,  191,  193,  197,  199,  211,  223,  227,  
3292                  229,  233,  239,  241,  251,  257,  263,  269,  271,  277,  281,  283,  293,  307,  311,  313,  
3293                  317,  331,  337,  347,  349,  353,  359,  367,  373,  379,  383,  389,  397,  401,  409,  419,  
3294                  421,  431,  433,  439,  443,  449,  457,  461,  463,  467,  479,  487,  491,  499,  503,  509,  
3295                  521,  523,  541,  547,  557,  563,  569,  571,  577,  587,  593,  599,  601,  607,  613,  617,  
3296                  619,  631,  641,  643,  647,  653,  659,  661,  673,  677,  683,  691,  701,  709,  719,  727,  
3297                  733,  739,  743,  751,  757,  761,  769,  773,  787,  797,  809,  811,  821,  823,  827,  829,  
3298                  839,  853,  857,  859,  863,  877,  881,  883,  887,  907,  911,  919,  929,  937,  941,  947,  
3299                  953,  967,  971,  977,  983,  991,  997
3300              );
3301  
3302              if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3303                  for ($i = 0; $i < count($primes); ++$i) {
3304                      $primes[$i] = new Math_BigInteger($primes[$i]);
3305                  }
3306              }
3307  
3308              $zero = new Math_BigInteger();
3309              $one = new Math_BigInteger(1);
3310              $two = new Math_BigInteger(2);
3311          }
3312  
3313          if ($this->equals($one)) {
3314              return false;
3315          }
3316  
3317          // see HAC 4.4.1 "Random search for probable primes"
3318          if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3319              foreach ($primes as $prime) {
3320                  list(, $r) = $this->divide($prime);
3321                  if ($r->equals($zero)) {
3322                      return $this->equals($prime);
3323                  }
3324              }
3325          } else {
3326              $value = $this->value;
3327              foreach ($primes as $prime) {
3328                  list(, $r) = $this->_divide_digit($value, $prime);
3329                  if (!$r) {
3330                      return count($value) == 1 && $value[0] == $prime;
3331                  }
3332              }
3333          }
3334  
3335          $n   = $this->copy();
3336          $n_1 = $n->subtract($one);
3337          $n_2 = $n->subtract($two);
3338  
3339          $r = $n_1->copy();
3340          $r_value = $r->value;
3341          // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
3342          if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
3343              $s = 0;
3344              // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
3345              while ($r->value[strlen($r->value) - 1] % 2 == 0) {
3346                  $r->value = bcdiv($r->value, '2', 0);
3347                  ++$s;
3348              }
3349          } else {
3350              for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
3351                  $temp = ~$r_value[$i] & 0xFFFFFF;
3352                  for ($j = 1; ($temp >> $j) & 1; ++$j);
3353                  if ($j != 25) {
3354                      break;
3355                  }
3356              }
3357              $s = 26 * $i + $j - 1;
3358              $r->_rshift($s);
3359          }
3360  
3361          for ($i = 0; $i < $t; ++$i) {
3362              $a = $this->random($two, $n_2);
3363              $y = $a->modPow($r, $n);
3364  
3365              if (!$y->equals($one) && !$y->equals($n_1)) {
3366                  for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
3367                      $y = $y->modPow($two, $n);
3368                      if ($y->equals($one)) {
3369                          return false;
3370                      }
3371                  }
3372  
3373                  if (!$y->equals($n_1)) {
3374                      return false;
3375                  }
3376              }
3377          }
3378          return true;
3379      }
3380  
3381      /**
3382       * Logical Left Shift
3383       *
3384       * Shifts BigInteger's by $shift bits.
3385       *
3386       * @param Integer $shift
3387       * @access private
3388       */
3389      function _lshift($shift)
3390      {
3391          if ( $shift == 0 ) {
3392              return;
3393          }
3394  
3395          $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
3396          $shift %= MATH_BIGINTEGER_BASE;
3397          $shift = 1 << $shift;
3398  
3399          $carry = 0;
3400  
3401          for ($i = 0; $i < count($this->value); ++$i) {
3402              $temp = $this->value[$i] * $shift + $carry;
3403              $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
3404              $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
3405          }
3406  
3407          if ( $carry ) {
3408              $this->value[] = $carry;
3409          }
3410  
3411          while ($num_digits--) {
3412              array_unshift($this->value, 0);
3413          }
3414      }
3415  
3416      /**
3417       * Logical Right Shift
3418       *
3419       * Shifts BigInteger's by $shift bits.
3420       *
3421       * @param Integer $shift
3422       * @access private
3423       */
3424      function _rshift($shift)
3425      {
3426          if ($shift == 0) {
3427              return;
3428          }
3429  
3430          $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
3431          $shift %= MATH_BIGINTEGER_BASE;
3432          $carry_shift = MATH_BIGINTEGER_BASE - $shift;
3433          $carry_mask = (1 << $shift) - 1;
3434  
3435          if ( $num_digits ) {
3436              $this->value = array_slice($this->value, $num_digits);
3437          }
3438  
3439          $carry = 0;
3440  
3441          for ($i = count($this->value) - 1; $i >= 0; --$i) {
3442              $temp = $this->value[$i] >> $shift | $carry;
3443              $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
3444              $this->value[$i] = $temp;
3445          }
3446  
3447          $this->value = $this->_trim($this->value);
3448      }
3449  
3450      /**
3451       * Normalize
3452       *
3453       * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
3454       *
3455       * @param Math_BigInteger
3456       * @return Math_BigInteger
3457       * @see _trim()
3458       * @access private
3459       */
3460      function _normalize($result)
3461      {
3462          $result->precision = $this->precision;
3463          $result->bitmask = $this->bitmask;
3464  
3465          switch ( MATH_BIGINTEGER_MODE ) {
3466              case MATH_BIGINTEGER_MODE_GMP:
3467                  if (!empty($result->bitmask->value)) {
3468                      $result->value = gmp_and($result->value, $result->bitmask->value);
3469                  }
3470  
3471                  return $result;
3472              case MATH_BIGINTEGER_MODE_BCMATH:
3473                  if (!empty($result->bitmask->value)) {
3474                      $result->value = bcmod($result->value, $result->bitmask->value);
3475                  }
3476  
3477                  return $result;
3478          }
3479  
3480          $value = &$result->value;
3481  
3482          if ( !count($value) ) {
3483              return $result;
3484          }
3485  
3486          $value = $this->_trim($value);
3487  
3488          if (!empty($result->bitmask->value)) {
3489              $length = min(count($value), count($this->bitmask->value));
3490              $value = array_slice($value, 0, $length);
3491  
3492              for ($i = 0; $i < $length; ++$i) {
3493                  $value[$i] = $value[$i] & $this->bitmask->value[$i];
3494              }
3495          }
3496  
3497          return $result;
3498      }
3499  
3500      /**
3501       * Trim
3502       *
3503       * Removes leading zeros
3504       *
3505       * @param Array $value
3506       * @return Math_BigInteger
3507       * @access private
3508       */
3509      function _trim($value)
3510      {
3511          for ($i = count($value) - 1; $i >= 0; --$i) {
3512              if ( $value[$i] ) {
3513                  break;
3514              }
3515              unset($value[$i]);
3516          }
3517  
3518          return $value;
3519      }
3520  
3521      /**
3522       * Array Repeat
3523       *
3524       * @param $input Array
3525       * @param $multiplier mixed
3526       * @return Array
3527       * @access private
3528       */
3529      function _array_repeat($input, $multiplier)
3530      {
3531          return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
3532      }
3533  
3534      /**
3535       * Logical Left Shift
3536       *
3537       * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
3538       *
3539       * @param $x String
3540       * @param $shift Integer
3541       * @return String
3542       * @access private
3543       */
3544      function _base256_lshift(&$x, $shift)
3545      {
3546          if ($shift == 0) {
3547              return;
3548          }
3549  
3550          $num_bytes = $shift >> 3; // eg. floor($shift/8)
3551          $shift &= 7; // eg. $shift % 8
3552  
3553          $carry = 0;
3554          for ($i = strlen($x) - 1; $i >= 0; --$i) {
3555              $temp = ord($x[$i]) << $shift | $carry;
3556              $x[$i] = chr($temp);
3557              $carry = $temp >> 8;
3558          }
3559          $carry = ($carry != 0) ? chr($carry) : '';
3560          $x = $carry . $x . str_repeat(chr(0), $num_bytes);
3561      }
3562  
3563      /**
3564       * Logical Right Shift
3565       *
3566       * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
3567       *
3568       * @param $x String
3569       * @param $shift Integer
3570       * @return String
3571       * @access private
3572       */
3573      function _base256_rshift(&$x, $shift)
3574      {
3575          if ($shift == 0) {
3576              $x = ltrim($x, chr(0));
3577              return '';
3578          }
3579  
3580          $num_bytes = $shift >> 3; // eg. floor($shift/8)
3581          $shift &= 7; // eg. $shift % 8
3582  
3583          $remainder = '';
3584          if ($num_bytes) {
3585              $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
3586              $remainder = substr($x, $start);
3587              $x = substr($x, 0, -$num_bytes);
3588          }
3589  
3590          $carry = 0;
3591          $carry_shift = 8 - $shift;
3592          for ($i = 0; $i < strlen($x); ++$i) {
3593              $temp = (ord($x[$i]) >> $shift) | $carry;
3594              $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
3595              $x[$i] = chr($temp);
3596          }
3597          $x = ltrim($x, chr(0));
3598  
3599          $remainder = chr($carry >> $carry_shift) . $remainder;
3600  
3601          return ltrim($remainder, chr(0));
3602      }
3603  
3604      // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
3605      // at 32-bits, while java's longs are 64-bits.
3606  
3607      /**
3608       * Converts 32-bit integers to bytes.
3609       *
3610       * @param Integer $x
3611       * @return String
3612       * @access private
3613       */
3614      function _int2bytes($x)
3615      {
3616          return ltrim(pack('N', $x), chr(0));
3617      }
3618  
3619      /**
3620       * Converts bytes to 32-bit integers
3621       *
3622       * @param String $x
3623       * @return Integer
3624       * @access private
3625       */
3626      function _bytes2int($x)
3627      {
3628          $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3629          return $temp['int'];
3630      }
3631  
3632      /**
3633       * DER-encode an integer
3634       *
3635       * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
3636       *
3637       * @see modPow()
3638       * @access private
3639       * @param Integer $length
3640       * @return String
3641       */
3642      function _encodeASN1Length($length)
3643      {
3644          if ($length <= 0x7F) {
3645              return chr($length);
3646          }
3647  
3648          $temp = ltrim(pack('N', $length), chr(0));
3649          return pack('Ca*', 0x80 | strlen($temp), $temp);
3650      }
3651  }