Subversion Repositories oidplus

Rev

Rev 874 | Rev 1101 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
827 daniel-mar 1
<?php
2
 
3
/**
4
 * Base BigInteger Engine
5
 *
6
 * PHP version 5 and 7
7
 *
8
 * @author    Jim Wigginton <terrafrost@php.net>
9
 * @copyright 2017 Jim Wigginton
10
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
11
 * @link      http://pear.php.net/package/Math_BigInteger
12
 */
13
 
14
namespace phpseclib3\Math\BigInteger\Engines;
15
 
16
use phpseclib3\Common\Functions\Strings;
17
use phpseclib3\Crypt\Random;
18
use phpseclib3\Exception\BadConfigurationException;
19
use phpseclib3\Math\BigInteger;
20
 
21
/**
22
 * Base Engine.
23
 *
24
 * @author  Jim Wigginton <terrafrost@php.net>
25
 */
26
abstract class Engine implements \JsonSerializable
27
{
28
    /* final protected */ const PRIMES = [
29
        3,   5,   7,   11,  13,  17,  19,  23,  29,  31,  37,  41,  43,  47,  53,  59,
30
        61,  67,  71,  73,  79,  83,  89,  97,  101, 103, 107, 109, 113, 127, 131, 137,
31
        139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
32
        229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
33
        317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
34
        421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
35
        521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
36
        619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
37
        733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
38
        839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
39
        953, 967, 971, 977, 983, 991, 997,
40
    ];
41
 
42
    /**
43
     * BigInteger(0)
44
     *
45
     * @var array<class-string<static>, static>
46
     */
47
    protected static $zero = [];
48
 
49
    /**
50
     * BigInteger(1)
51
     *
52
     * @var array<class-string<static>, static>
53
     */
54
    protected static $one  = [];
55
 
56
    /**
57
     * BigInteger(2)
58
     *
59
     * @var array<class-string<static>, static>
60
     */
61
    protected static $two = [];
62
 
63
    /**
64
     * Modular Exponentiation Engine
65
     *
66
     * @var array<class-string<static>, class-string<static>>
67
     */
68
    protected static $modexpEngine;
69
 
70
    /**
71
     * Engine Validity Flag
72
     *
73
     * @var array<class-string<static>, bool>
74
     */
75
    protected static $isValidEngine;
76
 
77
    /**
78
     * Holds the BigInteger's value
79
     *
80
     * @var \GMP|string|array|int
81
     */
82
    protected $value;
83
 
84
    /**
85
     * Holds the BigInteger's sign
86
     *
87
     * @var bool
88
     */
89
    protected $is_negative;
90
 
91
    /**
92
     * Precision
93
     *
94
     * @see static::setPrecision()
95
     * @var int
96
     */
97
    protected $precision = -1;
98
 
99
    /**
100
     * Precision Bitmask
101
     *
102
     * @see static::setPrecision()
103
     * @var static|false
104
     */
105
    protected $bitmask = false;
106
 
107
    /**
108
     * Recurring Modulo Function
109
     *
110
     * @var callable
111
     */
112
    protected $reduce;
113
 
114
    /**
115
     * Mode independent value used for serialization.
116
     *
117
     * @see self::__sleep()
118
     * @see self::__wakeup()
119
     * @var string
120
     */
121
    protected $hex;
122
 
123
    /**
124
     * Default constructor
125
     *
126
     * @param int|numeric-string $x integer Base-10 number or base-$base number if $base set.
127
     * @param int $base
128
     */
129
    public function __construct($x = 0, $base = 10)
130
    {
131
        if (!array_key_exists(static::class, static::$zero)) {
132
            static::$zero[static::class] = null; // Placeholder to prevent infinite loop.
133
            static::$zero[static::class] = new static(0);
134
            static::$one[static::class] = new static(1);
135
            static::$two[static::class] = new static(2);
136
        }
137
 
138
        // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
139
        // '0' is the only value like this per http://php.net/empty
140
        if (empty($x) && (abs($base) != 256 || $x !== '0')) {
141
            return;
142
        }
143
 
144
        switch ($base) {
145
            case -256:
146
            case 256:
147
                if ($base == -256 && (ord($x[0]) & 0x80)) {
148
                    $this->value = ~$x;
149
                    $this->is_negative = true;
150
                } else {
151
                    $this->value = $x;
152
                    $this->is_negative = false;
153
                }
154
 
155
                $this->initialize($base);
156
 
157
                if ($this->is_negative) {
158
                    $temp = $this->add(new static('-1'));
159
                    $this->value = $temp->value;
160
                }
161
                break;
162
            case -16:
163
            case 16:
164
                if ($base > 0 && $x[0] == '-') {
165
                    $this->is_negative = true;
166
                    $x = substr($x, 1);
167
                }
168
 
169
                $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
170
 
171
                $is_negative = false;
172
                if ($base < 0 && hexdec($x[0]) >= 8) {
173
                    $this->is_negative = $is_negative = true;
1042 daniel-mar 174
                    $x = Strings::bin2hex(~Strings::hex2bin($x));
827 daniel-mar 175
                }
176
 
177
                $this->value = $x;
178
                $this->initialize($base);
179
 
180
                if ($is_negative) {
181
                    $temp = $this->add(new static('-1'));
182
                    $this->value = $temp->value;
183
                }
184
                break;
185
            case -10:
186
            case 10:
187
                // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
188
                // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
189
                // [^-0-9].*: find any non-numeric characters and then any characters that follow that
190
                $this->value = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
191
                if (!strlen($this->value) || $this->value == '-') {
192
                    $this->value = '0';
193
                }
194
                $this->initialize($base);
195
                break;
196
            case -2:
197
            case 2:
198
                if ($base > 0 && $x[0] == '-') {
199
                    $this->is_negative = true;
200
                    $x = substr($x, 1);
201
                }
202
 
203
                $x = preg_replace('#^([01]*).*#', '$1', $x);
204
 
205
                $temp = new static(Strings::bits2bin($x), 128 * $base); // ie. either -16 or +16
206
                $this->value = $temp->value;
207
                if ($temp->is_negative) {
208
                    $this->is_negative = true;
209
                }
210
 
211
                break;
212
            default:
213
                // base not supported, so we'll let $this == 0
214
        }
215
    }
216
 
217
    /**
218
     * Sets engine type.
219
     *
220
     * Throws an exception if the type is invalid
221
     *
222
     * @param class-string<Engine> $engine
223
     */
224
    public static function setModExpEngine($engine)
225
    {
226
        $fqengine = '\\phpseclib3\\Math\\BigInteger\\Engines\\' . static::ENGINE_DIR . '\\' . $engine;
227
        if (!class_exists($fqengine) || !method_exists($fqengine, 'isValidEngine')) {
228
            throw new \InvalidArgumentException("$engine is not a valid engine");
229
        }
230
        if (!$fqengine::isValidEngine()) {
231
            throw new BadConfigurationException("$engine is not setup correctly on this system");
232
        }
233
        static::$modexpEngine[static::class] = $fqengine;
234
    }
235
 
236
    /**
237
     * Converts a BigInteger to a byte string (eg. base-256).
238
     *
239
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
240
     * saved as two's compliment.
241
     * @return string
242
     */
243
    protected function toBytesHelper()
244
    {
245
        $comparison = $this->compare(new static());
246
        if ($comparison == 0) {
247
            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
248
        }
249
 
250
        $temp = $comparison < 0 ? $this->add(new static(1)) : $this;
251
        $bytes = $temp->toBytes();
252
 
253
        if (!strlen($bytes)) { // eg. if the number we're trying to convert is -1
254
            $bytes = chr(0);
255
        }
256
 
257
        if (ord($bytes[0]) & 0x80) {
258
            $bytes = chr(0) . $bytes;
259
        }
260
 
261
        return $comparison < 0 ? ~$bytes : $bytes;
262
    }
263
 
264
    /**
265
     * Converts a BigInteger to a hex string (eg. base-16).
266
     *
267
     * @param bool $twos_compliment
268
     * @return string
269
     */
270
    public function toHex($twos_compliment = false)
271
    {
1042 daniel-mar 272
        return Strings::bin2hex($this->toBytes($twos_compliment));
827 daniel-mar 273
    }
274
 
275
    /**
276
     * Converts a BigInteger to a bit string (eg. base-2).
277
     *
278
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
279
     * saved as two's compliment.
280
     *
281
     * @param bool $twos_compliment
282
     * @return string
283
     */
284
    public function toBits($twos_compliment = false)
285
    {
286
        $hex = $this->toBytes($twos_compliment);
287
        $bits = Strings::bin2bits($hex);
288
 
289
        $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
290
 
291
        if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) {
292
            return '0' . $result;
293
        }
294
 
295
        return $result;
296
    }
297
 
298
    /**
299
     * Calculates modular inverses.
300
     *
301
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
302
     *
303
     * {@internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.}
304
     *
305
     * @param Engine $n
306
     * @return static|false
307
     */
308
    protected function modInverseHelper(Engine $n)
309
    {
310
        // $x mod -$n == $x mod $n.
311
        $n = $n->abs();
312
 
313
        if ($this->compare(static::$zero[static::class]) < 0) {
314
            $temp = $this->abs();
315
            $temp = $temp->modInverse($n);
316
            return $this->normalize($n->subtract($temp));
317
        }
318
 
319
        extract($this->extendedGCD($n));
320
        /**
321
         * @var Engine $gcd
322
         * @var Engine $x
323
         */
324
 
325
        if (!$gcd->equals(static::$one[static::class])) {
326
            return false;
327
        }
328
 
329
        $x = $x->compare(static::$zero[static::class]) < 0 ? $x->add($n) : $x;
330
 
331
        return $this->compare(static::$zero[static::class]) < 0 ? $this->normalize($n->subtract($x)) : $this->normalize($x);
332
    }
333
 
334
    /**
335
     * Serialize
336
     *
337
     * Will be called, automatically, when serialize() is called on a BigInteger object.
338
     *
339
     * @return array
340
     */
341
    public function __sleep()
342
    {
343
        $this->hex = $this->toHex(true);
344
        $vars = ['hex'];
345
        if ($this->precision > 0) {
346
            $vars[] = 'precision';
347
        }
348
        return $vars;
349
    }
350
 
351
    /**
352
     * Serialize
353
     *
354
     * Will be called, automatically, when unserialize() is called on a BigInteger object.
355
     *
356
     * @return void
357
     */
358
    public function __wakeup()
359
    {
360
        $temp = new static($this->hex, -16);
361
        $this->value = $temp->value;
362
        $this->is_negative = $temp->is_negative;
363
        if ($this->precision > 0) {
364
            // recalculate $this->bitmask
365
            $this->setPrecision($this->precision);
366
        }
367
    }
368
 
369
    /**
370
     * JSON Serialize
371
     *
372
     * Will be called, automatically, when json_encode() is called on a BigInteger object.
373
     */
374
    #[\ReturnTypeWillChange]
375
    public function jsonSerialize()
376
    {
377
        $result = ['hex' => $this->toHex(true)];
378
        if ($this->precision > 0) {
379
            $result['precision'] = $this->precision;
380
        }
381
        return $result;
382
    }
383
 
384
    /**
385
     * Converts a BigInteger to a base-10 number.
386
     *
387
     * @return string
388
     */
389
    public function __toString()
390
    {
391
        return $this->toString();
392
    }
393
 
394
    /**
395
     *  __debugInfo() magic method
396
     *
397
     * Will be called, automatically, when print_r() or var_dump() are called
398
     *
399
     * @return array
400
     */
401
    public function __debugInfo()
402
    {
403
        $result = [
404
            'value' => '0x' . $this->toHex(true),
405
            'engine' => basename(static::class)
406
        ];
407
        return $this->precision > 0 ? $result + ['precision' => $this->precision] : $result;
408
    }
409
 
410
    /**
411
     * Set Precision
412
     *
413
     * Some bitwise operations give different results depending on the precision being used.  Examples include left
414
     * shift, not, and rotates.
415
     *
416
     * @param int $bits
417
     */
418
    public function setPrecision($bits)
419
    {
420
        if ($bits < 1) {
421
            $this->precision = -1;
422
            $this->bitmask = false;
423
 
424
            return;
425
        }
426
        $this->precision = $bits;
427
        $this->bitmask = static::setBitmask($bits);
428
 
429
        $temp = $this->normalize($this);
430
        $this->value = $temp->value;
431
    }
432
 
433
    /**
434
     * Get Precision
435
     *
436
     * Returns the precision if it exists, -1 if it doesn't
437
     *
438
     * @return int
439
     */
440
    public function getPrecision()
441
    {
442
        return $this->precision;
443
    }
444
 
445
    /**
446
     * Set Bitmask
447
     * @return static
448
     * @param int $bits
449
     * @see self::setPrecision()
450
     */
451
    protected static function setBitmask($bits)
452
    {
453
        return new static(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
454
    }
455
 
456
    /**
457
     * Logical Not
458
     *
459
     * @return Engine|string
460
     */
461
    public function bitwise_not()
462
    {
463
        // calculuate "not" without regard to $this->precision
464
        // (will always result in a smaller number.  ie. ~1 isn't 1111 1110 - it's 0)
465
        $temp = $this->toBytes();
466
        if ($temp == '') {
467
            return $this->normalize(static::$zero[static::class]);
468
        }
469
        $pre_msb = decbin(ord($temp[0]));
470
        $temp = ~$temp;
471
        $msb = decbin(ord($temp[0]));
472
        if (strlen($msb) == 8) {
473
            $msb = substr($msb, strpos($msb, '0'));
474
        }
475
        $temp[0] = chr(bindec($msb));
476
 
477
        // see if we need to add extra leading 1's
478
        $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
479
        $new_bits = $this->precision - $current_bits;
480
        if ($new_bits <= 0) {
481
            return $this->normalize(new static($temp, 256));
482
        }
483
 
484
        // generate as many leading 1's as we need to.
485
        $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
486
 
487
        self::base256_lshift($leading_ones, $current_bits);
488
 
489
        $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);
490
 
491
        return $this->normalize(new static($leading_ones | $temp, 256));
492
    }
493
 
494
    /**
495
     * Logical Left Shift
496
     *
497
     * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
498
     *
499
     * @param string $x
500
     * @param int $shift
501
     * @return void
502
     */
503
    protected static function base256_lshift(&$x, $shift)
504
    {
505
        if ($shift == 0) {
506
            return;
507
        }
508
 
509
        $num_bytes = $shift >> 3; // eg. floor($shift/8)
510
        $shift &= 7; // eg. $shift % 8
511
 
512
        $carry = 0;
513
        for ($i = strlen($x) - 1; $i >= 0; --$i) {
514
            $temp = ord($x[$i]) << $shift | $carry;
515
            $x[$i] = chr($temp);
516
            $carry = $temp >> 8;
517
        }
518
        $carry = ($carry != 0) ? chr($carry) : '';
519
        $x = $carry . $x . str_repeat(chr(0), $num_bytes);
520
    }
521
 
522
    /**
523
     * Logical Left Rotate
524
     *
525
     * Instead of the top x bits being dropped they're appended to the shifted bit string.
526
     *
527
     * @param int $shift
528
     * @return Engine
529
     */
530
    public function bitwise_leftRotate($shift)
531
    {
532
        $bits = $this->toBytes();
533
 
534
        if ($this->precision > 0) {
535
            $precision = $this->precision;
536
            if (static::FAST_BITWISE) {
537
                $mask = $this->bitmask->toBytes();
538
            } else {
539
                $mask = $this->bitmask->subtract(new static(1));
540
                $mask = $mask->toBytes();
541
            }
542
        } else {
543
            $temp = ord($bits[0]);
544
            for ($i = 0; $temp >> $i; ++$i) {
545
            }
546
            $precision = 8 * strlen($bits) - 8 + $i;
547
            $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
548
        }
549
 
550
        if ($shift < 0) {
551
            $shift += $precision;
552
        }
553
        $shift %= $precision;
554
 
555
        if (!$shift) {
556
            return clone $this;
557
        }
558
 
559
        $left = $this->bitwise_leftShift($shift);
560
        $left = $left->bitwise_and(new static($mask, 256));
561
        $right = $this->bitwise_rightShift($precision - $shift);
562
        $result = static::FAST_BITWISE ? $left->bitwise_or($right) : $left->add($right);
563
        return $this->normalize($result);
564
    }
565
 
566
    /**
567
     * Logical Right Rotate
568
     *
569
     * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
570
     *
571
     * @param int $shift
572
     * @return Engine
573
     */
574
    public function bitwise_rightRotate($shift)
575
    {
576
        return $this->bitwise_leftRotate(-$shift);
577
    }
578
 
579
    /**
580
     * Returns the smallest and largest n-bit number
581
     *
582
     * @param int $bits
583
     * @return array{min: static, max: static}
584
     */
585
    public static function minMaxBits($bits)
586
    {
587
        $bytes = $bits >> 3;
588
        $min = str_repeat(chr(0), $bytes);
589
        $max = str_repeat(chr(0xFF), $bytes);
590
        $msb = $bits & 7;
591
        if ($msb) {
592
            $min = chr(1 << ($msb - 1)) . $min;
593
            $max = chr((1 << $msb) - 1) . $max;
594
        } else {
595
            $min[0] = chr(0x80);
596
        }
597
        return [
598
            'min' => new static($min, 256),
599
            'max' => new static($max, 256)
600
        ];
601
    }
602
 
603
    /**
604
     * Return the size of a BigInteger in bits
605
     *
606
     * @return int
607
     */
608
    public function getLength()
609
    {
610
        return strlen($this->toBits());
611
    }
612
 
613
    /**
614
     * Return the size of a BigInteger in bytes
615
     *
616
     * @return int
617
     */
618
    public function getLengthInBytes()
619
    {
620
        return strlen($this->toBytes());
621
    }
622
 
623
    /**
624
     * Performs some pre-processing for powMod
625
     *
626
     * @param Engine $e
627
     * @param Engine $n
628
     * @return static|false
629
     */
630
    protected function powModOuter(Engine $e, Engine $n)
631
    {
632
        $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
633
 
634
        if ($e->compare(new static()) < 0) {
635
            $e = $e->abs();
636
 
637
            $temp = $this->modInverse($n);
638
            if ($temp === false) {
639
                return false;
640
            }
641
 
642
            return $this->normalize($temp->powModInner($e, $n));
643
        }
644
 
645
        return $this->powModInner($e, $n);
646
    }
647
 
648
    /**
649
     * Sliding Window k-ary Modular Exponentiation
650
     *
651
     * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
652
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}.  In a departure from those algorithims,
653
     * however, this function performs a modular reduction after every multiplication and squaring operation.
654
     * As such, this function has the same preconditions that the reductions being used do.
655
     *
656
     * @template T of Engine
657
     * @param Engine $x
658
     * @param Engine $e
659
     * @param Engine $n
660
     * @param class-string<T> $class
661
     * @return T
662
     */
663
    protected static function slidingWindow(Engine $x, Engine $e, Engine $n, $class)
664
    {
665
        static $window_ranges = [7, 25, 81, 241, 673, 1793]; // from BigInteger.java's oddModPow function
666
        //static $window_ranges = [0, 7, 36, 140, 450, 1303, 3529]; // from MPM 7.3.1
667
 
668
        $e_bits = $e->toBits();
669
        $e_length = strlen($e_bits);
670
 
671
        // calculate the appropriate window size.
672
        // $window_size == 3 if $window_ranges is between 25 and 81, for example.
673
        for ($i = 0, $window_size = 1; $i < count($window_ranges) && $e_length > $window_ranges[$i]; ++$window_size, ++$i) {
674
        }
675
 
676
        $n_value = $n->value;
677
 
678
        if (method_exists(static::class, 'generateCustomReduction')) {
679
            static::generateCustomReduction($n, $class);
680
        }
681
 
682
        // precompute $this^0 through $this^$window_size
683
        $powers = [];
684
        $powers[1] = static::prepareReduce($x->value, $n_value, $class);
685
        $powers[2] = static::squareReduce($powers[1], $n_value, $class);
686
 
687
        // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
688
        // in a 1.  ie. it's supposed to be odd.
689
        $temp = 1 << ($window_size - 1);
690
        for ($i = 1; $i < $temp; ++$i) {
691
            $i2 = $i << 1;
692
            $powers[$i2 + 1] = static::multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $class);
693
        }
694
 
695
        $result = new $class(1);
696
        $result = static::prepareReduce($result->value, $n_value, $class);
697
 
698
        for ($i = 0; $i < $e_length;) {
699
            if (!$e_bits[$i]) {
700
                $result = static::squareReduce($result, $n_value, $class);
701
                ++$i;
702
            } else {
703
                for ($j = $window_size - 1; $j > 0; --$j) {
704
                    if (!empty($e_bits[$i + $j])) {
705
                        break;
706
                    }
707
                }
708
 
709
                // eg. the length of substr($e_bits, $i, $j + 1)
710
                for ($k = 0; $k <= $j; ++$k) {
711
                    $result = static::squareReduce($result, $n_value, $class);
712
                }
713
 
714
                $result = static::multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $class);
715
 
716
                $i += $j + 1;
717
            }
718
        }
719
 
720
        $temp = new $class();
721
        $temp->value = static::reduce($result, $n_value, $class);
722
 
723
        return $temp;
724
    }
725
 
726
    /**
727
     * Generates a random number of a certain size
728
     *
729
     * Bit length is equal to $size
730
     *
731
     * @param int $size
732
     * @return Engine
733
     */
734
    public static function random($size)
735
    {
736
        extract(static::minMaxBits($size));
737
        /**
738
         * @var BigInteger $min
739
         * @var BigInteger $max
740
         */
741
        return static::randomRange($min, $max);
742
    }
743
 
744
    /**
745
     * Generates a random prime number of a certain size
746
     *
747
     * Bit length is equal to $size
748
     *
749
     * @param int $size
750
     * @return Engine
751
     */
752
    public static function randomPrime($size)
753
    {
754
        extract(static::minMaxBits($size));
755
        /**
756
         * @var static $min
757
         * @var static $max
758
         */
759
        return static::randomRangePrime($min, $max);
760
    }
761
 
762
    /**
763
     * Performs some pre-processing for randomRangePrime
764
     *
765
     * @param Engine $min
766
     * @param Engine $max
767
     * @return static|false
768
     */
769
    protected static function randomRangePrimeOuter(Engine $min, Engine $max)
770
    {
771
        $compare = $max->compare($min);
772
 
773
        if (!$compare) {
774
            return $min->isPrime() ? $min : false;
775
        } elseif ($compare < 0) {
776
            // if $min is bigger then $max, swap $min and $max
777
            $temp = $max;
778
            $max = $min;
779
            $min = $temp;
780
        }
781
 
782
        $x = static::randomRange($min, $max);
783
 
784
        return static::randomRangePrimeInner($x, $min, $max);
785
    }
786
 
787
    /**
788
     * Generate a random number between a range
789
     *
790
     * Returns a random number between $min and $max where $min and $max
791
     * can be defined using one of the two methods:
792
     *
793
     * BigInteger::randomRange($min, $max)
794
     * BigInteger::randomRange($max, $min)
795
     *
796
     * @param Engine $min
797
     * @param Engine $max
798
     * @return Engine
799
     */
800
    protected static function randomRangeHelper(Engine $min, Engine $max)
801
    {
802
        $compare = $max->compare($min);
803
 
804
        if (!$compare) {
805
            return $min;
806
        } elseif ($compare < 0) {
807
            // if $min is bigger then $max, swap $min and $max
808
            $temp = $max;
809
            $max = $min;
810
            $min = $temp;
811
        }
812
 
813
        if (!isset(static::$one[static::class])) {
814
            static::$one[static::class] = new static(1);
815
        }
816
 
817
        $max = $max->subtract($min->subtract(static::$one[static::class]));
818
 
819
        $size = strlen(ltrim($max->toBytes(), chr(0)));
820
 
821
        /*
822
            doing $random % $max doesn't work because some numbers will be more likely to occur than others.
823
            eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
824
            would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
825
            not all numbers would be equally likely. some would be more likely than others.
826
 
827
            creating a whole new random number until you find one that is within the range doesn't work
828
            because, for sufficiently small ranges, the likelihood that you'd get a number within that range
829
            would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
830
            would be pretty high that $random would be greater than $max.
831
 
832
            phpseclib works around this using the technique described here:
833
 
834
            http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
835
        */
836
        $random_max = new static(chr(1) . str_repeat("\0", $size), 256);
837
        $random = new static(Random::string($size), 256);
838
 
839
        list($max_multiple) = $random_max->divide($max);
840
        $max_multiple = $max_multiple->multiply($max);
841
 
842
        while ($random->compare($max_multiple) >= 0) {
843
            $random = $random->subtract($max_multiple);
844
            $random_max = $random_max->subtract($max_multiple);
845
            $random = $random->bitwise_leftShift(8);
846
            $random = $random->add(new static(Random::string(1), 256));
847
            $random_max = $random_max->bitwise_leftShift(8);
848
            list($max_multiple) = $random_max->divide($max);
849
            $max_multiple = $max_multiple->multiply($max);
850
        }
851
        list(, $random) = $random->divide($max);
852
 
853
        return $random->add($min);
854
    }
855
 
856
    /**
857
     * Performs some post-processing for randomRangePrime
858
     *
859
     * @param Engine $x
860
     * @param Engine $min
861
     * @param Engine $max
862
     * @return static|false
863
     */
864
    protected static function randomRangePrimeInner(Engine $x, Engine $min, Engine $max)
865
    {
866
        if (!isset(static::$two[static::class])) {
867
            static::$two[static::class] = new static('2');
868
        }
869
 
870
        $x->make_odd();
871
        if ($x->compare($max) > 0) {
872
            // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
873
            if ($min->equals($max)) {
874
                return false;
875
            }
876
            $x = clone $min;
877
            $x->make_odd();
878
        }
879
 
880
        $initial_x = clone $x;
881
 
882
        while (true) {
883
            if ($x->isPrime()) {
884
                return $x;
885
            }
886
 
887
            $x = $x->add(static::$two[static::class]);
888
 
889
            if ($x->compare($max) > 0) {
890
                $x = clone $min;
891
                if ($x->equals(static::$two[static::class])) {
892
                    return $x;
893
                }
894
                $x->make_odd();
895
            }
896
 
897
            if ($x->equals($initial_x)) {
898
                return false;
899
            }
900
        }
901
    }
902
 
903
    /**
904
     * Sets the $t parameter for primality testing
905
     *
906
     * @return int
907
     */
908
    protected function setupIsPrime()
909
    {
910
        $length = $this->getLengthInBytes();
911
 
912
        // see HAC 4.49 "Note (controlling the error probability)"
913
        // @codingStandardsIgnoreStart
914
             if ($length >= 163) { $t =  2; } // floor(1300 / 8)
915
        else if ($length >= 106) { $t =  3; } // floor( 850 / 8)
916
        else if ($length >= 81 ) { $t =  4; } // floor( 650 / 8)
917
        else if ($length >= 68 ) { $t =  5; } // floor( 550 / 8)
918
        else if ($length >= 56 ) { $t =  6; } // floor( 450 / 8)
919
        else if ($length >= 50 ) { $t =  7; } // floor( 400 / 8)
920
        else if ($length >= 43 ) { $t =  8; } // floor( 350 / 8)
921
        else if ($length >= 37 ) { $t =  9; } // floor( 300 / 8)
922
        else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
923
        else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
924
        else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
925
        else                     { $t = 27; }
926
        // @codingStandardsIgnoreEnd
927
 
928
        return $t;
929
    }
930
 
931
    /**
932
     * Tests Primality
933
     *
934
     * Uses the {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}.
935
     * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24} for more info.
936
     *
937
     * @param int $t
938
     * @return bool
939
     */
940
    protected function testPrimality($t)
941
    {
942
        if (!$this->testSmallPrimes()) {
943
            return false;
944
        }
945
 
946
        $n   = clone $this;
947
        $n_1 = $n->subtract(static::$one[static::class]);
948
        $n_2 = $n->subtract(static::$two[static::class]);
949
 
950
        $r = clone $n_1;
951
        $s = static::scan1divide($r);
952
 
953
        for ($i = 0; $i < $t; ++$i) {
954
            $a = static::randomRange(static::$two[static::class], $n_2);
955
            $y = $a->modPow($r, $n);
956
 
957
            if (!$y->equals(static::$one[static::class]) && !$y->equals($n_1)) {
958
                for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
959
                    $y = $y->modPow(static::$two[static::class], $n);
960
                    if ($y->equals(static::$one[static::class])) {
961
                        return false;
962
                    }
963
                }
964
 
965
                if (!$y->equals($n_1)) {
966
                    return false;
967
                }
968
            }
969
        }
970
 
971
        return true;
972
    }
973
 
974
    /**
975
     * Checks a numer to see if it's prime
976
     *
977
     * Assuming the $t parameter is not set, this function has an error rate of 2**-80.  The main motivation for the
978
     * $t parameter is distributability.  BigInteger::randomPrime() can be distributed across multiple pageloads
979
     * on a website instead of just one.
980
     *
981
     * @param int|bool $t
982
     * @return bool
983
     */
984
    public function isPrime($t = false)
985
    {
986
        if (!$t) {
987
            $t = $this->setupIsPrime();
988
        }
989
        return $this->testPrimality($t);
990
    }
991
 
992
    /**
993
     * Performs a few preliminary checks on root
994
     *
995
     * @param int $n
996
     * @return Engine
997
     */
998
    protected function rootHelper($n)
999
    {
1000
        if ($n < 1) {
1001
            return clone static::$zero[static::class];
1002
        } // we want positive exponents
1003
        if ($this->compare(static::$one[static::class]) < 0) {
1004
            return clone static::$zero[static::class];
1005
        } // we want positive numbers
1006
        if ($this->compare(static::$two[static::class]) < 0) {
1007
            return clone static::$one[static::class];
1008
        } // n-th root of 1 or 2 is 1
1009
 
1010
        return $this->rootInner($n);
1011
    }
1012
 
1013
    /**
1014
     * Calculates the nth root of a biginteger.
1015
     *
1016
     * Returns the nth root of a positive biginteger, where n defaults to 2
1017
     *
1018
     * {@internal This function is based off of {@link http://mathforum.org/library/drmath/view/52605.html this page} and {@link http://stackoverflow.com/questions/11242920/calculating-nth-root-with-bcmath-in-php this stackoverflow question}.}
1019
     *
1020
     * @param int $n
1021
     * @return Engine
1022
     */
1023
    protected function rootInner($n)
1024
    {
1025
        $n = new static($n);
1026
 
1027
        // g is our guess number
1028
        $g = static::$two[static::class];
1029
        // while (g^n < num) g=g*2
1030
        while ($g->pow($n)->compare($this) < 0) {
1031
            $g = $g->multiply(static::$two[static::class]);
1032
        }
1033
        // if (g^n==num) num is a power of 2, we're lucky, end of job
1034
        // == 0 bccomp(bcpow($g, $n), $n->value)==0
1035
        if ($g->pow($n)->equals($this) > 0) {
1036
            $root = $g;
1037
            return $this->normalize($root);
1038
        }
1039
 
1040
        // if we're here num wasn't a power of 2 :(
1041
        $og = $g; // og means original guess and here is our upper bound
1042
        $g = $g->divide(static::$two[static::class])[0]; // g is set to be our lower bound
1043
        $step = $og->subtract($g)->divide(static::$two[static::class])[0]; // step is the half of upper bound - lower bound
1044
        $g = $g->add($step); // we start at lower bound + step , basically in the middle of our interval
1045
 
1046
        // while step>1
1047
 
1048
        while ($step->compare(static::$one[static::class]) == 1) {
1049
            $guess = $g->pow($n);
1050
            $step = $step->divide(static::$two[static::class])[0];
1051
            $comp = $guess->compare($this); // compare our guess with real number
1052
            switch ($comp) {
1053
                case -1: // if guess is lower we add the new step
1054
                    $g = $g->add($step);
1055
                    break;
1056
                case 1: // if guess is higher we sub the new step
1057
                    $g = $g->subtract($step);
1058
                    break;
1059
                case 0: // if guess is exactly the num we're done, we return the value
1060
                    $root = $g;
1061
                    break 2;
1062
            }
1063
        }
1064
 
1065
        if ($comp == 1) {
1066
            $g = $g->subtract($step);
1067
        }
1068
 
1069
        // whatever happened, g is the closest guess we can make so return it
1070
        $root = $g;
1071
 
1072
        return $this->normalize($root);
1073
    }
1074
 
1075
    /**
1076
     * Calculates the nth root of a biginteger.
1077
     *
1078
     * @param int $n
1079
     * @return Engine
1080
     */
1081
    public function root($n = 2)
1082
    {
1083
        return $this->rootHelper($n);
1084
    }
1085
 
1086
    /**
1087
     * Return the minimum BigInteger between an arbitrary number of BigIntegers.
1088
     *
1089
     * @param array $nums
1090
     * @return Engine
1091
     */
1092
    protected static function minHelper(array $nums)
1093
    {
1094
        if (count($nums) == 1) {
1095
            return $nums[0];
1096
        }
1097
        $min = $nums[0];
1098
        for ($i = 1; $i < count($nums); $i++) {
1099
            $min = $min->compare($nums[$i]) > 0 ? $nums[$i] : $min;
1100
        }
1101
        return $min;
1102
    }
1103
 
1104
    /**
1105
     * Return the minimum BigInteger between an arbitrary number of BigIntegers.
1106
     *
1107
     * @param array $nums
1108
     * @return Engine
1109
     */
1110
    protected static function maxHelper(array $nums)
1111
    {
1112
        if (count($nums) == 1) {
1113
            return $nums[0];
1114
        }
1115
        $max = $nums[0];
1116
        for ($i = 1; $i < count($nums); $i++) {
1117
            $max = $max->compare($nums[$i]) < 0 ? $nums[$i] : $max;
1118
        }
1119
        return $max;
1120
    }
1121
 
1122
    /**
1123
     * Create Recurring Modulo Function
1124
     *
1125
     * Sometimes it may be desirable to do repeated modulos with the same number outside of
1126
     * modular exponentiation
1127
     *
1128
     * @return callable
1129
     */
1130
    public function createRecurringModuloFunction()
1131
    {
1132
        $class = static::class;
1133
 
1134
        $fqengine = !method_exists(static::$modexpEngine[static::class], 'reduce') ?
1135
            '\\phpseclib3\\Math\\BigInteger\\Engines\\' . static::ENGINE_DIR . '\\DefaultEngine' :
1136
            static::$modexpEngine[static::class];
1137
        if (method_exists($fqengine, 'generateCustomReduction')) {
1138
            $func = $fqengine::generateCustomReduction($this, static::class);
1139
            return eval('return function(' . static::class . ' $x) use ($func, $class) {
1140
                $r = new $class();
1141
                $r->value = $func($x->value);
1142
                return $r;
1143
            };');
1144
        }
1145
        $n = $this->value;
1146
        return eval('return function(' . static::class . ' $x) use ($n, $fqengine, $class) {
1147
            $r = new $class();
1148
            $r->value = $fqengine::reduce($x->value, $n, $class);
1149
            return $r;
1150
        };');
1151
    }
1152
 
1153
    /**
1154
     * Calculates the greatest common divisor and Bezout's identity.
1155
     *
1156
     * @param Engine $n
1157
     * @return array{gcd: Engine, x: Engine, y: Engine}
1158
     */
1159
    protected function extendedGCDHelper(Engine $n)
1160
    {
1161
        $u = clone $this;
1162
        $v = clone $n;
1163
 
1164
        $one = new static(1);
1165
        $zero = new static();
1166
 
1167
        $a = clone $one;
1168
        $b = clone $zero;
1169
        $c = clone $zero;
1170
        $d = clone $one;
1171
 
1172
        while (!$v->equals($zero)) {
1173
            list($q) = $u->divide($v);
1174
 
1175
            $temp = $u;
1176
            $u = $v;
1177
            $v = $temp->subtract($v->multiply($q));
1178
 
1179
            $temp = $a;
1180
            $a = $c;
1181
            $c = $temp->subtract($a->multiply($q));
1182
 
1183
            $temp = $b;
1184
            $b = $d;
1185
            $d = $temp->subtract($b->multiply($q));
1186
        }
1187
 
1188
        return [
1189
            'gcd' => $u,
1190
            'x' => $a,
1191
            'y' => $b
1192
        ];
1193
    }
1194
 
1195
    /**
1196
     * Bitwise Split
1197
     *
1198
     * Splits BigInteger's into chunks of $split bits
1199
     *
1200
     * @param int $split
1201
     * @return Engine[]
1202
     */
1203
    public function bitwise_split($split)
1204
    {
1205
        if ($split < 1) {
1206
            throw new \RuntimeException('Offset must be greater than 1');
1207
        }
1208
 
1209
        $mask = static::$one[static::class]->bitwise_leftShift($split)->subtract(static::$one[static::class]);
1210
 
1211
        $num = clone $this;
1212
 
1213
        $vals = [];
1214
        while (!$num->equals(static::$zero[static::class])) {
1215
            $vals[] = $num->bitwise_and($mask);
1216
            $num = $num->bitwise_rightShift($split);
1217
        }
1218
 
1219
        return array_reverse($vals);
1220
    }
1221
 
1222
    /**
1223
     * Logical And
1224
     *
1225
     * @param Engine $x
1226
     * @return Engine
1227
     */
1228
    protected function bitwiseAndHelper(Engine $x)
1229
    {
1230
        $left = $this->toBytes(true);
1231
        $right = $x->toBytes(true);
1232
 
1233
        $length = max(strlen($left), strlen($right));
1234
 
1235
        $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
1236
        $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
1237
 
1238
        return $this->normalize(new static($left & $right, -256));
1239
    }
1240
 
1241
    /**
1242
     * Logical Or
1243
     *
1244
     * @param Engine $x
1245
     * @return Engine
1246
     */
1247
    protected function bitwiseOrHelper(Engine $x)
1248
    {
1249
        $left = $this->toBytes(true);
1250
        $right = $x->toBytes(true);
1251
 
1252
        $length = max(strlen($left), strlen($right));
1253
 
1254
        $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
1255
        $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
1256
 
1257
        return $this->normalize(new static($left | $right, -256));
1258
    }
1259
 
1260
    /**
1261
     * Logical Exclusive Or
1262
     *
1263
     * @param Engine $x
1264
     * @return Engine
1265
     */
1266
    protected function bitwiseXorHelper(Engine $x)
1267
    {
1268
        $left = $this->toBytes(true);
1269
        $right = $x->toBytes(true);
1270
 
1271
        $length = max(strlen($left), strlen($right));
1272
 
1273
 
1274
        $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
1275
        $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
1276
        return $this->normalize(new static($left ^ $right, -256));
1277
    }
1278
}