1<?php 2 3/** 4 * Pure-PHP arbitrary precision integer arithmetic library. 5 * 6 * Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available, 7 * and an internal implementation, otherwise. 8 * 9 * PHP version 5 and 7 10 * 11 * Here's an example of how to use this library: 12 * <code> 13 * <?php 14 * $a = new \phpseclib3\Math\BigInteger(2); 15 * $b = new \phpseclib3\Math\BigInteger(3); 16 * 17 * $c = $a->add($b); 18 * 19 * echo $c->toString(); // outputs 5 20 * ?> 21 * </code> 22 * 23 * @author Jim Wigginton <terrafrost@php.net> 24 * @copyright 2017 Jim Wigginton 25 * @license http://www.opensource.org/licenses/mit-license.html MIT License 26 */ 27 28namespace phpseclib3\Math; 29 30use phpseclib3\Exception\BadConfigurationException; 31use phpseclib3\Math\BigInteger\Engines\Engine; 32 33/** 34 * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256 35 * numbers. 36 * 37 * @author Jim Wigginton <terrafrost@php.net> 38 */ 39class BigInteger implements \JsonSerializable 40{ 41 /** 42 * Main Engine 43 * 44 * @var class-string<Engine> 45 */ 46 private static $mainEngine; 47 48 /** 49 * Selected Engines 50 * 51 * @var list<string> 52 */ 53 private static $engines; 54 55 /** 56 * The actual BigInteger object 57 * 58 * @var object 59 */ 60 private $value; 61 62 /** 63 * Mode independent value used for serialization. 64 * 65 * @see self::__sleep() 66 * @see self::__wakeup() 67 * @var string 68 */ 69 private $hex; 70 71 /** 72 * Precision (used only for serialization) 73 * 74 * @see self::__sleep() 75 * @see self::__wakeup() 76 * @var int 77 */ 78 private $precision; 79 80 /** 81 * Sets engine type. 82 * 83 * Throws an exception if the type is invalid 84 * 85 * @param string $main 86 * @param list<string> $modexps optional 87 * @return void 88 */ 89 public static function setEngine($main, array $modexps = ['DefaultEngine']) 90 { 91 self::$engines = []; 92 93 $fqmain = 'phpseclib3\\Math\\BigInteger\\Engines\\' . $main; 94 if (!class_exists($fqmain) || !method_exists($fqmain, 'isValidEngine')) { 95 throw new \InvalidArgumentException("$main is not a valid engine"); 96 } 97 if (!$fqmain::isValidEngine()) { 98 throw new BadConfigurationException("$main is not setup correctly on this system"); 99 } 100 /** @var class-string<Engine> $fqmain */ 101 self::$mainEngine = $fqmain; 102 103 $found = false; 104 foreach ($modexps as $modexp) { 105 try { 106 $fqmain::setModExpEngine($modexp); 107 $found = true; 108 break; 109 } catch (\Exception $e) { 110 } 111 } 112 113 if (!$found) { 114 throw new BadConfigurationException("No valid modular exponentiation engine found for $main"); 115 } 116 117 self::$engines = [$main, $modexp]; 118 } 119 120 /** 121 * Returns the engine type 122 * 123 * @return string[] 124 */ 125 public static function getEngine() 126 { 127 self::initialize_static_variables(); 128 129 return self::$engines; 130 } 131 132 /** 133 * Initialize static variables 134 */ 135 private static function initialize_static_variables() 136 { 137 if (!isset(self::$mainEngine)) { 138 $engines = [ 139 ['GMP', ['DefaultEngine']], 140 ['PHP64', ['OpenSSL']], 141 ['BCMath', ['OpenSSL']], 142 ['PHP32', ['OpenSSL']], 143 ['PHP64', ['DefaultEngine']], 144 ['PHP32', ['DefaultEngine']] 145 ]; 146 // per https://phpseclib.com/docs/speed PHP 8.4.0+ _significantly_ sped up BCMath 147 if (version_compare(PHP_VERSION, '8.4.0') >= 0) { 148 $engines[1][0] = 'BCMath'; 149 $engines[2][0] = 'PHP64'; 150 } 151 152 foreach ($engines as $engine) { 153 try { 154 self::setEngine($engine[0], $engine[1]); 155 return; 156 } catch (\Exception $e) { 157 } 158 } 159 160 throw new \UnexpectedValueException('No valid BigInteger found. This is only possible when JIT is enabled on Windows and neither the GMP or BCMath extensions are available so either disable JIT or install GMP / BCMath'); 161 } 162 } 163 164 /** 165 * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers. 166 * 167 * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using 168 * two's compliment. The sole exception to this is -10, which is treated the same as 10 is. 169 * 170 * @param string|int|Engine $x Base-10 number or base-$base number if $base set. 171 * @param int $base 172 */ 173 public function __construct($x = 0, $base = 10) 174 { 175 self::initialize_static_variables(); 176 177 if ($x instanceof self::$mainEngine) { 178 $this->value = clone $x; 179 } elseif ($x instanceof Engine) { 180 $this->value = new static("$x"); 181 $this->value->setPrecision($x->getPrecision()); 182 } else { 183 $this->value = new self::$mainEngine($x, $base); 184 } 185 } 186 187 /** 188 * Converts a BigInteger to a base-10 number. 189 * 190 * @return string 191 */ 192 public function toString() 193 { 194 return $this->value->toString(); 195 } 196 197 /** 198 * __toString() magic method 199 */ 200 public function __toString() 201 { 202 return (string)$this->value; 203 } 204 205 /** 206 * __debugInfo() magic method 207 * 208 * Will be called, automatically, when print_r() or var_dump() are called 209 */ 210 public function __debugInfo() 211 { 212 return $this->value->__debugInfo(); 213 } 214 215 /** 216 * Converts a BigInteger to a byte string (eg. base-256). 217 * 218 * @param bool $twos_compliment 219 * @return string 220 */ 221 public function toBytes($twos_compliment = false) 222 { 223 return $this->value->toBytes($twos_compliment); 224 } 225 226 /** 227 * Converts a BigInteger to a hex string (eg. base-16). 228 * 229 * @param bool $twos_compliment 230 * @return string 231 */ 232 public function toHex($twos_compliment = false) 233 { 234 return $this->value->toHex($twos_compliment); 235 } 236 237 /** 238 * Converts a BigInteger to a bit string (eg. base-2). 239 * 240 * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're 241 * saved as two's compliment. 242 * 243 * @param bool $twos_compliment 244 * @return string 245 */ 246 public function toBits($twos_compliment = false) 247 { 248 return $this->value->toBits($twos_compliment); 249 } 250 251 /** 252 * Adds two BigIntegers. 253 * 254 * @param BigInteger $y 255 * @return BigInteger 256 */ 257 public function add(BigInteger $y) 258 { 259 return new static($this->value->add($y->value)); 260 } 261 262 /** 263 * Subtracts two BigIntegers. 264 * 265 * @param BigInteger $y 266 * @return BigInteger 267 */ 268 public function subtract(BigInteger $y) 269 { 270 return new static($this->value->subtract($y->value)); 271 } 272 273 /** 274 * Multiplies two BigIntegers 275 * 276 * @param BigInteger $x 277 * @return BigInteger 278 */ 279 public function multiply(BigInteger $x) 280 { 281 return new static($this->value->multiply($x->value)); 282 } 283 284 /** 285 * Divides two BigIntegers. 286 * 287 * Returns an array whose first element contains the quotient and whose second element contains the 288 * "common residue". If the remainder would be positive, the "common residue" and the remainder are the 289 * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder 290 * and the divisor (basically, the "common residue" is the first positive modulo). 291 * 292 * Here's an example: 293 * <code> 294 * <?php 295 * $a = new \phpseclib3\Math\BigInteger('10'); 296 * $b = new \phpseclib3\Math\BigInteger('20'); 297 * 298 * list($quotient, $remainder) = $a->divide($b); 299 * 300 * echo $quotient->toString(); // outputs 0 301 * echo "\r\n"; 302 * echo $remainder->toString(); // outputs 10 303 * ?> 304 * </code> 305 * 306 * @param BigInteger $y 307 * @return BigInteger[] 308 */ 309 public function divide(BigInteger $y) 310 { 311 list($q, $r) = $this->value->divide($y->value); 312 return [ 313 new static($q), 314 new static($r) 315 ]; 316 } 317 318 /** 319 * Calculates modular inverses. 320 * 321 * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. 322 * 323 * @param BigInteger $n 324 * @return BigInteger 325 */ 326 public function modInverse(BigInteger $n) 327 { 328 return new static($this->value->modInverse($n->value)); 329 } 330 331 /** 332 * Calculates modular inverses. 333 * 334 * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. 335 * 336 * @param BigInteger $n 337 * @return BigInteger[] 338 */ 339 public function extendedGCD(BigInteger $n) 340 { 341 $extended = $this->value->extendedGCD($n->value); 342 $gcd = $extended['gcd']; 343 $x = $extended['x']; 344 $y = $extended['y']; 345 return [ 346 'gcd' => new static($gcd), 347 'x' => new static($x), 348 'y' => new static($y) 349 ]; 350 } 351 352 /** 353 * Calculates the greatest common divisor 354 * 355 * Say you have 693 and 609. The GCD is 21. 356 * 357 * @param BigInteger $n 358 * @return BigInteger 359 */ 360 public function gcd(BigInteger $n) 361 { 362 return new static($this->value->gcd($n->value)); 363 } 364 365 /** 366 * Absolute value. 367 * 368 * @return BigInteger 369 */ 370 public function abs() 371 { 372 return new static($this->value->abs()); 373 } 374 375 /** 376 * Set Precision 377 * 378 * Some bitwise operations give different results depending on the precision being used. Examples include left 379 * shift, not, and rotates. 380 * 381 * @param int $bits 382 */ 383 public function setPrecision($bits) 384 { 385 $this->value->setPrecision($bits); 386 } 387 388 /** 389 * Get Precision 390 * 391 * Returns the precision if it exists, false if it doesn't 392 * 393 * @return int|bool 394 */ 395 public function getPrecision() 396 { 397 return $this->value->getPrecision(); 398 } 399 400 /** 401 * Serialize 402 * 403 * Will be called, automatically, when serialize() is called on a BigInteger object. 404 * 405 * __sleep() / __wakeup() have been around since PHP 4.0 but were deprecated in PHP 8.5 406 * 407 * \Serializable was introduced in PHP 5.1 and deprecated in PHP 8.1: 408 * https://wiki.php.net/rfc/phase_out_serializable 409 * 410 * __serialize() / __unserialize() were introduced in PHP 7.4: 411 * https://wiki.php.net/rfc/custom_object_serialization 412 * 413 * @return array 414 */ 415 public function __sleep() 416 { 417 $this->hex = $this->toHex(true); 418 $vars = ['hex']; 419 if ($this->getPrecision() > 0) { 420 $vars[] = 'precision'; 421 } 422 return $vars; 423 } 424 425 /** 426 * Serialize 427 * 428 * Will be called, automatically, when unserialize() is called on a BigInteger object. 429 */ 430 public function __wakeup() 431 { 432 $temp = new static($this->hex, -16); 433 $this->value = $temp->value; 434 if ($this->precision > 0) { 435 // recalculate $this->bitmask 436 $this->setPrecision($this->precision); 437 } 438 } 439 440 /** 441 * __serialize() magic method 442 * 443 * @see self::__unserialize() 444 * @return array 445 * @access public 446 */ 447 public function __serialize() 448 { 449 $result = ['hex' => $this->toHex(true)]; 450 if ($this->getPrecision() > 0) { 451 $result['precision'] = $this->getPrecision(); 452 } 453 return $result; 454 } 455 456 /** 457 * __unserialize() magic method 458 * 459 * @see self::__serialize() 460 * @access public 461 */ 462 public function __unserialize(array $data) 463 { 464 $temp = new static($data['hex'], -16); 465 $this->value = $temp->value; 466 if (isset($data['precision']) && $data['precision'] > 0) { 467 // recalculate $this->bitmask 468 $this->setPrecision($data['precision']); 469 } 470 } 471 472 /** 473 * JSON Serialize 474 * 475 * Will be called, automatically, when json_encode() is called on a BigInteger object. 476 * 477 * @return array{hex: string, precision?: int] 478 */ 479 #[\ReturnTypeWillChange] 480 public function jsonSerialize() 481 { 482 $result = ['hex' => $this->toHex(true)]; 483 if ($this->precision > 0) { 484 $result['precision'] = $this->getPrecision(); 485 } 486 return $result; 487 } 488 489 /** 490 * Performs modular exponentiation. 491 * 492 * @param BigInteger $e 493 * @param BigInteger $n 494 * @return BigInteger 495 */ 496 public function powMod(BigInteger $e, BigInteger $n) 497 { 498 return new static($this->value->powMod($e->value, $n->value)); 499 } 500 501 /** 502 * Performs modular exponentiation. 503 * 504 * @param BigInteger $e 505 * @param BigInteger $n 506 * @return BigInteger 507 */ 508 public function modPow(BigInteger $e, BigInteger $n) 509 { 510 return new static($this->value->modPow($e->value, $n->value)); 511 } 512 513 /** 514 * Compares two numbers. 515 * 516 * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this 517 * is demonstrated thusly: 518 * 519 * $x > $y: $x->compare($y) > 0 520 * $x < $y: $x->compare($y) < 0 521 * $x == $y: $x->compare($y) == 0 522 * 523 * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). 524 * 525 * {@internal Could return $this->subtract($x), but that's not as fast as what we do do.} 526 * 527 * @param BigInteger $y 528 * @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. 529 * @see self::equals() 530 */ 531 public function compare(BigInteger $y) 532 { 533 return $this->value->compare($y->value); 534 } 535 536 /** 537 * Tests the equality of two numbers. 538 * 539 * If you need to see if one number is greater than or less than another number, use BigInteger::compare() 540 * 541 * @param BigInteger $x 542 * @return bool 543 */ 544 public function equals(BigInteger $x) 545 { 546 return $this->value->equals($x->value); 547 } 548 549 /** 550 * Logical Not 551 * 552 * @return BigInteger 553 */ 554 public function bitwise_not() 555 { 556 return new static($this->value->bitwise_not()); 557 } 558 559 /** 560 * Logical And 561 * 562 * @param BigInteger $x 563 * @return BigInteger 564 */ 565 public function bitwise_and(BigInteger $x) 566 { 567 return new static($this->value->bitwise_and($x->value)); 568 } 569 570 /** 571 * Logical Or 572 * 573 * @param BigInteger $x 574 * @return BigInteger 575 */ 576 public function bitwise_or(BigInteger $x) 577 { 578 return new static($this->value->bitwise_or($x->value)); 579 } 580 581 /** 582 * Logical Exclusive Or 583 * 584 * @param BigInteger $x 585 * @return BigInteger 586 */ 587 public function bitwise_xor(BigInteger $x) 588 { 589 return new static($this->value->bitwise_xor($x->value)); 590 } 591 592 /** 593 * Logical Right Shift 594 * 595 * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift. 596 * 597 * @param int $shift 598 * @return BigInteger 599 */ 600 public function bitwise_rightShift($shift) 601 { 602 return new static($this->value->bitwise_rightShift($shift)); 603 } 604 605 /** 606 * Logical Left Shift 607 * 608 * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. 609 * 610 * @param int $shift 611 * @return BigInteger 612 */ 613 public function bitwise_leftShift($shift) 614 { 615 return new static($this->value->bitwise_leftShift($shift)); 616 } 617 618 /** 619 * Logical Left Rotate 620 * 621 * Instead of the top x bits being dropped they're appended to the shifted bit string. 622 * 623 * @param int $shift 624 * @return BigInteger 625 */ 626 public function bitwise_leftRotate($shift) 627 { 628 return new static($this->value->bitwise_leftRotate($shift)); 629 } 630 631 /** 632 * Logical Right Rotate 633 * 634 * Instead of the bottom x bits being dropped they're prepended to the shifted bit string. 635 * 636 * @param int $shift 637 * @return BigInteger 638 */ 639 public function bitwise_rightRotate($shift) 640 { 641 return new static($this->value->bitwise_rightRotate($shift)); 642 } 643 644 /** 645 * Returns the smallest and largest n-bit number 646 * 647 * @param int $bits 648 * @return BigInteger[] 649 */ 650 public static function minMaxBits($bits) 651 { 652 self::initialize_static_variables(); 653 654 $class = self::$mainEngine; 655 $minMax = $class::minMaxBits($bits); 656 $min = $minMax['min']; 657 $max = $minMax['max']; 658 return [ 659 'min' => new static($min), 660 'max' => new static($max) 661 ]; 662 } 663 664 /** 665 * Return the size of a BigInteger in bits 666 * 667 * @return int 668 */ 669 public function getLength() 670 { 671 return $this->value->getLength(); 672 } 673 674 /** 675 * Return the size of a BigInteger in bytes 676 * 677 * @return int 678 */ 679 public function getLengthInBytes() 680 { 681 return $this->value->getLengthInBytes(); 682 } 683 684 /** 685 * Generates a random number of a certain size 686 * 687 * Bit length is equal to $size 688 * 689 * @param int $size 690 * @return BigInteger 691 */ 692 public static function random($size) 693 { 694 self::initialize_static_variables(); 695 696 $class = self::$mainEngine; 697 return new static($class::random($size)); 698 } 699 700 /** 701 * Generates a random prime number of a certain size 702 * 703 * Bit length is equal to $size 704 * 705 * @param int $size 706 * @return BigInteger 707 */ 708 public static function randomPrime($size) 709 { 710 self::initialize_static_variables(); 711 712 $class = self::$mainEngine; 713 return new static($class::randomPrime($size)); 714 } 715 716 /** 717 * Generate a random prime number between a range 718 * 719 * If there's not a prime within the given range, false will be returned. 720 * 721 * @param BigInteger $min 722 * @param BigInteger $max 723 * @return false|BigInteger 724 */ 725 public static function randomRangePrime(BigInteger $min, BigInteger $max) 726 { 727 $class = self::$mainEngine; 728 return new static($class::randomRangePrime($min->value, $max->value)); 729 } 730 731 /** 732 * Generate a random number between a range 733 * 734 * Returns a random number between $min and $max where $min and $max 735 * can be defined using one of the two methods: 736 * 737 * BigInteger::randomRange($min, $max) 738 * BigInteger::randomRange($max, $min) 739 * 740 * @param BigInteger $min 741 * @param BigInteger $max 742 * @return BigInteger 743 */ 744 public static function randomRange(BigInteger $min, BigInteger $max) 745 { 746 $class = self::$mainEngine; 747 return new static($class::randomRange($min->value, $max->value)); 748 } 749 750 /** 751 * Checks a numer to see if it's prime 752 * 753 * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the 754 * $t parameter is distributability. BigInteger::randomPrime() can be distributed across multiple pageloads 755 * on a website instead of just one. 756 * 757 * @param int|bool $t 758 * @return bool 759 */ 760 public function isPrime($t = false) 761 { 762 return $this->value->isPrime($t); 763 } 764 765 /** 766 * Calculates the nth root of a biginteger. 767 * 768 * Returns the nth root of a positive biginteger, where n defaults to 2 769 * 770 * @param int $n optional 771 * @return BigInteger 772 */ 773 public function root($n = 2) 774 { 775 return new static($this->value->root($n)); 776 } 777 778 /** 779 * Performs exponentiation. 780 * 781 * @param BigInteger $n 782 * @return BigInteger 783 */ 784 public function pow(BigInteger $n) 785 { 786 return new static($this->value->pow($n->value)); 787 } 788 789 /** 790 * Return the minimum BigInteger between an arbitrary number of BigIntegers. 791 * 792 * @param BigInteger ...$nums 793 * @return BigInteger 794 */ 795 public static function min(BigInteger ...$nums) 796 { 797 $class = self::$mainEngine; 798 $nums = array_map(function ($num) { 799 return $num->value; 800 }, $nums); 801 return new static($class::min(...$nums)); 802 } 803 804 /** 805 * Return the maximum BigInteger between an arbitrary number of BigIntegers. 806 * 807 * @param BigInteger ...$nums 808 * @return BigInteger 809 */ 810 public static function max(BigInteger ...$nums) 811 { 812 $class = self::$mainEngine; 813 $nums = array_map(function ($num) { 814 return $num->value; 815 }, $nums); 816 return new static($class::max(...$nums)); 817 } 818 819 /** 820 * Tests BigInteger to see if it is between two integers, inclusive 821 * 822 * @param BigInteger $min 823 * @param BigInteger $max 824 * @return bool 825 */ 826 public function between(BigInteger $min, BigInteger $max) 827 { 828 return $this->value->between($min->value, $max->value); 829 } 830 831 /** 832 * Clone 833 */ 834 public function __clone() 835 { 836 $this->value = clone $this->value; 837 } 838 839 /** 840 * Is Odd? 841 * 842 * @return bool 843 */ 844 public function isOdd() 845 { 846 return $this->value->isOdd(); 847 } 848 849 /** 850 * Tests if a bit is set 851 * 852 * @param int $x 853 * @return bool 854 */ 855 public function testBit($x) 856 { 857 return $this->value->testBit($x); 858 } 859 860 /** 861 * Is Negative? 862 * 863 * @return bool 864 */ 865 public function isNegative() 866 { 867 return $this->value->isNegative(); 868 } 869 870 /** 871 * Negate 872 * 873 * Given $k, returns -$k 874 * 875 * @return BigInteger 876 */ 877 public function negate() 878 { 879 return new static($this->value->negate()); 880 } 881 882 /** 883 * Scan for 1 and right shift by that amount 884 * 885 * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); 886 * 887 * @param BigInteger $r 888 * @return int 889 */ 890 public static function scan1divide(BigInteger $r) 891 { 892 $class = self::$mainEngine; 893 return $class::scan1divide($r->value); 894 } 895 896 /** 897 * Create Recurring Modulo Function 898 * 899 * Sometimes it may be desirable to do repeated modulos with the same number outside of 900 * modular exponentiation 901 * 902 * @return callable 903 */ 904 public function createRecurringModuloFunction() 905 { 906 $func = $this->value->createRecurringModuloFunction(); 907 return function (BigInteger $x) use ($func) { 908 return new static($func($x->value)); 909 }; 910 } 911 912 /** 913 * Bitwise Split 914 * 915 * Splits BigInteger's into chunks of $split bits 916 * 917 * @param int $split 918 * @return BigInteger[] 919 */ 920 public function bitwise_split($split) 921 { 922 return array_map(function ($val) { 923 return new static($val); 924 }, $this->value->bitwise_split($split)); 925 } 926} 927