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