xref: /dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php (revision 8e88a29b81301f78509349ab1152bb09c229123e)
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