Subversion Repositories oidplus

Rev

Rev 846 | Rev 1042 | 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
 * Pure-PHP BigInteger Engine
5
 *
6
 * PHP version 5 and 7
7
 *
874 daniel-mar 8
 * @category  Math
9
 * @package   BigInteger
827 daniel-mar 10
 * @author    Jim Wigginton <terrafrost@php.net>
11
 * @copyright 2017 Jim Wigginton
12
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
13
 * @link      http://pear.php.net/package/Math_BigInteger
14
 */
15
 
16
namespace phpseclib3\Math\BigInteger\Engines;
17
 
18
use ParagonIE\ConstantTime\Hex;
19
use phpseclib3\Exception\BadConfigurationException;
20
 
21
/**
22
 * Pure-PHP Engine.
23
 *
874 daniel-mar 24
 * @package PHP
827 daniel-mar 25
 * @author  Jim Wigginton <terrafrost@php.net>
874 daniel-mar 26
 * @access  public
827 daniel-mar 27
 */
28
abstract class PHP extends Engine
29
{
30
    /**#@+
31
     * Array constants
32
     *
33
     * Rather than create a thousands and thousands of new BigInteger objects in repeated function calls to add() and
34
     * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
35
     *
874 daniel-mar 36
     * @access protected
827 daniel-mar 37
     */
38
    /**
39
     * $result[self::VALUE] contains the value.
40
     */
41
    const VALUE = 0;
42
    /**
43
     * $result[self::SIGN] contains the sign.
44
     */
45
    const SIGN = 1;
46
    /**#@-*/
47
 
48
    /**
49
     * Karatsuba Cutoff
50
     *
51
     * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
52
     *
874 daniel-mar 53
     * @access private
827 daniel-mar 54
     */
55
    const KARATSUBA_CUTOFF = 25;
56
 
57
    /**
58
     * Can Bitwise operations be done fast?
59
     *
60
     * @see parent::bitwise_leftRotate()
61
     * @see parent::bitwise_rightRotate()
874 daniel-mar 62
     * @access protected
827 daniel-mar 63
     */
64
    const FAST_BITWISE = true;
65
 
66
    /**
67
     * Engine Directory
68
     *
69
     * @see parent::setModExpEngine
874 daniel-mar 70
     * @access protected
827 daniel-mar 71
     */
72
    const ENGINE_DIR = 'PHP';
73
 
74
    /**
75
     * Default constructor
76
     *
77
     * @param mixed $x integer Base-10 number or base-$base number if $base set.
78
     * @param int $base
79
     * @return PHP
80
     * @see parent::__construct()
81
     */
82
    public function __construct($x = 0, $base = 10)
83
    {
84
        if (!isset(static::$isValidEngine[static::class])) {
85
            static::$isValidEngine[static::class] = static::isValidEngine();
86
        }
87
        if (!static::$isValidEngine[static::class]) {
88
            throw new BadConfigurationException(static::class . ' is not setup correctly on this system');
89
        }
90
 
91
        $this->value = [];
92
        parent::__construct($x, $base);
93
    }
94
 
95
    /**
96
     * Initialize a PHP BigInteger Engine instance
97
     *
98
     * @param int $base
99
     * @see parent::__construct()
100
     */
101
    protected function initialize($base)
102
    {
103
        switch (abs($base)) {
104
            case 16:
105
                $x = (strlen($this->value) & 1) ? '0' . $this->value : $this->value;
106
                $temp = new static(Hex::decode($x), 256);
107
                $this->value = $temp->value;
108
                break;
109
            case 10:
110
                $temp = new static();
111
 
112
                $multiplier = new static();
113
                $multiplier->value = [static::MAX10];
114
 
115
                $x = $this->value;
116
 
117
                if ($x[0] == '-') {
118
                    $this->is_negative = true;
119
                    $x = substr($x, 1);
120
                }
121
 
122
                $x = str_pad(
123
                    $x,
124
                    strlen($x) + ((static::MAX10LEN - 1) * strlen($x)) % static::MAX10LEN,
125
                    0,
126
                    STR_PAD_LEFT
127
                );
128
                while (strlen($x)) {
129
                    $temp = $temp->multiply($multiplier);
130
                    $temp = $temp->add(new static($this->int2bytes(substr($x, 0, static::MAX10LEN)), 256));
131
                    $x = substr($x, static::MAX10LEN);
132
                }
133
 
134
                $this->value = $temp->value;
135
        }
136
    }
137
 
138
    /**
139
     * Pads strings so that unpack may be used on them
140
     *
141
     * @param string $str
142
     * @return string
143
     */
144
    protected function pad($str)
145
    {
146
        $length = strlen($str);
147
 
148
        $pad = 4 - (strlen($str) % 4);
149
 
150
        return str_pad($str, $length + $pad, "\0", STR_PAD_LEFT);
151
    }
152
 
153
    /**
154
     * Converts a BigInteger to a base-10 number.
155
     *
156
     * @return string
157
     */
158
    public function toString()
159
    {
160
        if (!count($this->value)) {
161
            return '0';
162
        }
163
 
164
        $temp = clone $this;
165
        $temp->bitmask = false;
166
        $temp->is_negative = false;
167
 
168
        $divisor = new static();
169
        $divisor->value = [static::MAX10];
170
        $result = '';
171
        while (count($temp->value)) {
172
            list($temp, $mod) = $temp->divide($divisor);
173
            $result = str_pad(
174
                isset($mod->value[0]) ? $mod->value[0] : '',
175
                static::MAX10LEN,
176
                '0',
177
                STR_PAD_LEFT
178
            ) . $result;
179
        }
180
        $result = ltrim($result, '0');
181
        if (empty($result)) {
182
            $result = '0';
183
        }
184
 
185
        if ($this->is_negative) {
186
            $result = '-' . $result;
187
        }
188
 
189
        return $result;
190
    }
191
 
192
    /**
193
     * Converts a BigInteger to a byte string (eg. base-256).
194
     *
195
     * @param bool $twos_compliment
196
     * @return string
197
     */
198
    public function toBytes($twos_compliment = false)
199
    {
200
        if ($twos_compliment) {
201
            return $this->toBytesHelper();
202
        }
203
 
204
        if (!count($this->value)) {
205
            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
206
        }
207
 
208
        $result = $this->bitwise_small_split(8);
209
        $result = implode('', array_map('chr', $result));
210
 
211
        return $this->precision > 0 ?
212
            str_pad(
213
                substr($result, -(($this->precision + 7) >> 3)),
214
                ($this->precision + 7) >> 3,
215
                chr(0),
216
                STR_PAD_LEFT
217
            ) :
218
            $result;
219
    }
220
 
221
    /**
222
     * Performs addition.
223
     *
224
     * @param array $x_value
225
     * @param bool $x_negative
226
     * @param array $y_value
227
     * @param bool $y_negative
228
     * @return array
229
     */
230
    protected static function addHelper(array $x_value, $x_negative, array $y_value, $y_negative)
231
    {
232
        $x_size = count($x_value);
233
        $y_size = count($y_value);
234
 
235
        if ($x_size == 0) {
236
            return [
237
                self::VALUE => $y_value,
238
                self::SIGN => $y_negative
239
            ];
240
        } elseif ($y_size == 0) {
241
            return [
242
                self::VALUE => $x_value,
243
                self::SIGN => $x_negative
244
            ];
245
        }
246
 
247
        // subtract, if appropriate
248
        if ($x_negative != $y_negative) {
249
            if ($x_value == $y_value) {
250
                return [
251
                    self::VALUE => [],
252
                    self::SIGN => false
253
                ];
254
            }
255
 
256
            $temp = self::subtractHelper($x_value, false, $y_value, false);
257
            $temp[self::SIGN] = self::compareHelper($x_value, false, $y_value, false) > 0 ?
258
                $x_negative : $y_negative;
259
 
260
            return $temp;
261
        }
262
 
263
        if ($x_size < $y_size) {
264
            $size = $x_size;
265
            $value = $y_value;
266
        } else {
267
            $size = $y_size;
268
            $value = $x_value;
269
        }
270
 
271
        $value[count($value)] = 0; // just in case the carry adds an extra digit
272
 
273
        $carry = 0;
274
        for ($i = 0, $j = 1; $j < $size; $i += 2, $j += 2) {
275
            //$sum = $x_value[$j] * static::BASE_FULL + $x_value[$i] + $y_value[$j] * static::BASE_FULL + $y_value[$i] + $carry;
276
            $sum = ($x_value[$j] + $y_value[$j]) * static::BASE_FULL + $x_value[$i] + $y_value[$i] + $carry;
277
            $carry = $sum >= static::MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
278
            $sum = $carry ? $sum - static::MAX_DIGIT2 : $sum;
279
 
280
            $temp = static::BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
281
 
282
            $value[$i] = (int)($sum - static::BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
283
            $value[$j] = $temp;
284
        }
285
 
286
        if ($j == $size) { // ie. if $y_size is odd
287
            $sum = $x_value[$i] + $y_value[$i] + $carry;
288
            $carry = $sum >= static::BASE_FULL;
289
            $value[$i] = $carry ? $sum - static::BASE_FULL : $sum;
290
            ++$i; // ie. let $i = $j since we've just done $value[$i]
291
        }
292
 
293
        if ($carry) {
294
            for (; $value[$i] == static::MAX_DIGIT; ++$i) {
295
                $value[$i] = 0;
296
            }
297
            ++$value[$i];
298
        }
299
 
300
        return [
301
            self::VALUE => self::trim($value),
302
            self::SIGN => $x_negative
303
        ];
304
    }
305
 
306
    /**
307
     * Performs subtraction.
308
     *
309
     * @param array $x_value
310
     * @param bool $x_negative
311
     * @param array $y_value
312
     * @param bool $y_negative
313
     * @return array
314
     */
315
    public static function subtractHelper(array $x_value, $x_negative, array $y_value, $y_negative)
316
    {
317
        $x_size = count($x_value);
318
        $y_size = count($y_value);
319
 
320
        if ($x_size == 0) {
321
            return [
322
                self::VALUE => $y_value,
323
                self::SIGN => !$y_negative
324
            ];
325
        } elseif ($y_size == 0) {
326
            return [
327
                self::VALUE => $x_value,
328
                self::SIGN => $x_negative
329
            ];
330
        }
331
 
332
        // add, if appropriate (ie. -$x - +$y or +$x - -$y)
333
        if ($x_negative != $y_negative) {
334
            $temp = self::addHelper($x_value, false, $y_value, false);
335
            $temp[self::SIGN] = $x_negative;
336
 
337
            return $temp;
338
        }
339
 
340
        $diff = self::compareHelper($x_value, $x_negative, $y_value, $y_negative);
341
 
342
        if (!$diff) {
343
            return [
344
                self::VALUE => [],
345
                self::SIGN => false
346
            ];
347
        }
348
 
349
        // switch $x and $y around, if appropriate.
350
        if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) {
351
            $temp = $x_value;
352
            $x_value = $y_value;
353
            $y_value = $temp;
354
 
355
            $x_negative = !$x_negative;
356
 
357
            $x_size = count($x_value);
358
            $y_size = count($y_value);
359
        }
360
 
361
        // at this point, $x_value should be at least as big as - if not bigger than - $y_value
362
 
363
        $carry = 0;
364
        for ($i = 0, $j = 1; $j < $y_size; $i += 2, $j += 2) {
365
            $sum = ($x_value[$j] - $y_value[$j]) * static::BASE_FULL + $x_value[$i] - $y_value[$i] - $carry;
366
 
367
            $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
368
            $sum = $carry ? $sum + static::MAX_DIGIT2 : $sum;
369
 
370
            $temp = static::BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
371
 
372
            $x_value[$i] = (int)($sum - static::BASE_FULL * $temp);
373
            $x_value[$j] = $temp;
374
        }
375
 
376
        if ($j == $y_size) { // ie. if $y_size is odd
377
            $sum = $x_value[$i] - $y_value[$i] - $carry;
378
            $carry = $sum < 0;
379
            $x_value[$i] = $carry ? $sum + static::BASE_FULL : $sum;
380
            ++$i;
381
        }
382
 
383
        if ($carry) {
384
            for (; !$x_value[$i]; ++$i) {
385
                $x_value[$i] = static::MAX_DIGIT;
386
            }
387
            --$x_value[$i];
388
        }
389
 
390
        return [
391
            self::VALUE => self::trim($x_value),
392
            self::SIGN => $x_negative
393
        ];
394
    }
395
 
396
    /**
397
     * Performs multiplication.
398
     *
399
     * @param array $x_value
400
     * @param bool $x_negative
401
     * @param array $y_value
402
     * @param bool $y_negative
403
     * @return array
404
     */
405
    protected static function multiplyHelper(array $x_value, $x_negative, array $y_value, $y_negative)
406
    {
407
        //if ( $x_value == $y_value ) {
408
        //    return [
409
        //        self::VALUE => self::square($x_value),
410
        //        self::SIGN => $x_sign != $y_value
411
        //    ];
412
        //}
413
 
414
        $x_length = count($x_value);
415
        $y_length = count($y_value);
416
 
417
        if (!$x_length || !$y_length) { // a 0 is being multiplied
418
            return [
419
                self::VALUE => [],
420
                self::SIGN => false
421
            ];
422
        }
423
 
424
        return [
425
            self::VALUE => min($x_length, $y_length) < 2 * self::KARATSUBA_CUTOFF ?
426
                self::trim(self::regularMultiply($x_value, $y_value)) :
427
                self::trim(self::karatsuba($x_value, $y_value)),
428
            self::SIGN => $x_negative != $y_negative
429
        ];
430
    }
431
 
432
    /**
433
     * Performs Karatsuba multiplication on two BigIntegers
434
     *
435
     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
436
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
437
     *
438
     * @param array $x_value
439
     * @param array $y_value
440
     * @return array
441
     */
442
    private static function karatsuba(array $x_value, array $y_value)
443
    {
444
        $m = min(count($x_value) >> 1, count($y_value) >> 1);
445
 
446
        if ($m < self::KARATSUBA_CUTOFF) {
447
            return self::regularMultiply($x_value, $y_value);
448
        }
449
 
450
        $x1 = array_slice($x_value, $m);
451
        $x0 = array_slice($x_value, 0, $m);
452
        $y1 = array_slice($y_value, $m);
453
        $y0 = array_slice($y_value, 0, $m);
454
 
455
        $z2 = self::karatsuba($x1, $y1);
456
        $z0 = self::karatsuba($x0, $y0);
457
 
458
        $z1 = self::addHelper($x1, false, $x0, false);
459
        $temp = self::addHelper($y1, false, $y0, false);
460
        $z1 = self::karatsuba($z1[self::VALUE], $temp[self::VALUE]);
461
        $temp = self::addHelper($z2, false, $z0, false);
462
        $z1 = self::subtractHelper($z1, false, $temp[self::VALUE], false);
463
 
464
        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
465
        $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);
466
 
467
        $xy = self::addHelper($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
468
        $xy = self::addHelper($xy[self::VALUE], $xy[self::SIGN], $z0, false);
469
 
470
        return $xy[self::VALUE];
471
    }
472
 
473
    /**
474
     * Performs long multiplication on two BigIntegers
475
     *
476
     * Modeled after 'multiply' in MutableBigInteger.java.
477
     *
478
     * @param array $x_value
479
     * @param array $y_value
480
     * @return array
481
     */
482
    protected static function regularMultiply(array $x_value, array $y_value)
483
    {
484
        $x_length = count($x_value);
485
        $y_length = count($y_value);
486
 
487
        if (!$x_length || !$y_length) { // a 0 is being multiplied
488
            return [];
489
        }
490
 
491
        $product_value = self::array_repeat(0, $x_length + $y_length);
492
 
493
        // the following for loop could be removed if the for loop following it
494
        // (the one with nested for loops) initially set $i to 0, but
495
        // doing so would also make the result in one set of unnecessary adds,
496
        // since on the outermost loops first pass, $product->value[$k] is going
497
        // to always be 0
498
 
499
        $carry = 0;
500
        for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
501
            $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
502
            $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
503
            $product_value[$j] = (int)($temp - static::BASE_FULL * $carry);
504
        }
505
 
506
        $product_value[$j] = $carry;
507
 
508
        // the above for loop is what the previous comment was talking about.  the
509
        // following for loop is the "one with nested for loops"
510
        for ($i = 1; $i < $y_length; ++$i) {
511
            $carry = 0;
512
 
513
            for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
514
                $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
515
                $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
516
                $product_value[$k] = (int)($temp - static::BASE_FULL * $carry);
517
            }
518
 
519
            $product_value[$k] = $carry;
520
        }
521
 
522
        return $product_value;
523
    }
524
 
525
    /**
526
     * Divides two BigIntegers.
527
     *
528
     * Returns an array whose first element contains the quotient and whose second element contains the
529
     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
530
     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
531
     * and the divisor (basically, the "common residue" is the first positive modulo).
532
     *
533
     * @return array{static, static}
534
     * @internal This function is based off of
535
     *     {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
536
     */
537
    protected function divideHelper(PHP $y)
538
    {
539
        if (count($y->value) == 1) {
540
            list($q, $r) = $this->divide_digit($this->value, $y->value[0]);
541
            $quotient = new static();
542
            $remainder = new static();
543
            $quotient->value = $q;
544
            $remainder->value = [$r];
545
            $quotient->is_negative = $this->is_negative != $y->is_negative;
546
            return [$this->normalize($quotient), $this->normalize($remainder)];
547
        }
548
 
549
        $x = clone $this;
550
        $y = clone $y;
551
 
552
        $x_sign = $x->is_negative;
553
        $y_sign = $y->is_negative;
554
 
555
        $x->is_negative = $y->is_negative = false;
556
 
557
        $diff = $x->compare($y);
558
 
559
        if (!$diff) {
560
            $temp = new static();
561
            $temp->value = [1];
562
            $temp->is_negative = $x_sign != $y_sign;
563
            return [$this->normalize($temp), $this->normalize(static::$zero[static::class])];
564
        }
565
 
566
        if ($diff < 0) {
567
            // if $x is negative, "add" $y.
568
            if ($x_sign) {
569
                $x = $y->subtract($x);
570
            }
571
            return [$this->normalize(static::$zero[static::class]), $this->normalize($x)];
572
        }
573
 
574
        // normalize $x and $y as described in HAC 14.23 / 14.24
575
        $msb = $y->value[count($y->value) - 1];
576
        for ($shift = 0; !($msb & static::MSB); ++$shift) {
577
            $msb <<= 1;
578
        }
579
        $x->lshift($shift);
580
        $y->lshift($shift);
581
        $y_value = &$y->value;
582
 
583
        $x_max = count($x->value) - 1;
584
        $y_max = count($y->value) - 1;
585
 
586
        $quotient = new static();
587
        $quotient_value = &$quotient->value;
588
        $quotient_value = self::array_repeat(0, $x_max - $y_max + 1);
589
 
590
        static $temp, $lhs, $rhs;
591
        if (!isset($temp)) {
592
            $temp = new static();
593
            $lhs = new static();
594
            $rhs = new static();
595
        }
596
        if (static::class != get_class($temp)) {
597
            $temp = new static();
598
            $lhs = new static();
599
            $rhs = new static();
600
        }
601
        $temp_value = &$temp->value;
602
        $rhs_value =  &$rhs->value;
603
 
604
        // $temp = $y << ($x_max - $y_max-1) in base 2**26
605
        $temp_value = array_merge(self::array_repeat(0, $x_max - $y_max), $y_value);
606
 
607
        while ($x->compare($temp) >= 0) {
608
            // calculate the "common residue"
609
            ++$quotient_value[$x_max - $y_max];
610
            $x = $x->subtract($temp);
611
            $x_max = count($x->value) - 1;
612
        }
613
 
614
        for ($i = $x_max; $i >= $y_max + 1; --$i) {
615
            $x_value = &$x->value;
616
            $x_window = [
617
                isset($x_value[$i]) ? $x_value[$i] : 0,
618
                isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
619
                isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
620
            ];
621
            $y_window = [
622
                $y_value[$y_max],
623
                ($y_max > 0) ? $y_value[$y_max - 1] : 0
624
            ];
625
 
626
            $q_index = $i - $y_max - 1;
627
            if ($x_window[0] == $y_window[0]) {
628
                $quotient_value[$q_index] = static::MAX_DIGIT;
629
            } else {
630
                $quotient_value[$q_index] = self::safe_divide(
631
                    $x_window[0] * static::BASE_FULL + $x_window[1],
632
                    $y_window[0]
633
                );
634
            }
635
 
636
            $temp_value = [$y_window[1], $y_window[0]];
637
 
638
            $lhs->value = [$quotient_value[$q_index]];
639
            $lhs = $lhs->multiply($temp);
640
 
641
            $rhs_value = [$x_window[2], $x_window[1], $x_window[0]];
642
 
643
            while ($lhs->compare($rhs) > 0) {
644
                --$quotient_value[$q_index];
645
 
646
                $lhs->value = [$quotient_value[$q_index]];
647
                $lhs = $lhs->multiply($temp);
648
            }
649
 
650
            $adjust = self::array_repeat(0, $q_index);
651
            $temp_value = [$quotient_value[$q_index]];
652
            $temp = $temp->multiply($y);
653
            $temp_value = &$temp->value;
654
            if (count($temp_value)) {
655
                $temp_value = array_merge($adjust, $temp_value);
656
            }
657
 
658
            $x = $x->subtract($temp);
659
 
660
            if ($x->compare(static::$zero[static::class]) < 0) {
661
                $temp_value = array_merge($adjust, $y_value);
662
                $x = $x->add($temp);
663
 
664
                --$quotient_value[$q_index];
665
            }
666
 
667
            $x_max = count($x_value) - 1;
668
        }
669
 
670
        // unnormalize the remainder
671
        $x->rshift($shift);
672
 
673
        $quotient->is_negative = $x_sign != $y_sign;
674
 
675
        // calculate the "common residue", if appropriate
676
        if ($x_sign) {
677
            $y->rshift($shift);
678
            $x = $y->subtract($x);
679
        }
680
 
681
        return [$this->normalize($quotient), $this->normalize($x)];
682
    }
683
 
684
    /**
685
     * Divides a BigInteger by a regular integer
686
     *
687
     * abc / x = a00 / x + b0 / x + c / x
688
     *
689
     * @param array $dividend
690
     * @param int $divisor
691
     * @return array
692
     */
693
    private static function divide_digit(array $dividend, $divisor)
694
    {
695
        $carry = 0;
696
        $result = [];
697
 
698
        for ($i = count($dividend) - 1; $i >= 0; --$i) {
699
            $temp = static::BASE_FULL * $carry + $dividend[$i];
700
            $result[$i] = self::safe_divide($temp, $divisor);
701
            $carry = (int)($temp - $divisor * $result[$i]);
702
        }
703
 
704
        return [$result, $carry];
705
    }
706
 
707
    /**
708
     * Single digit division
709
     *
710
     * Even if int64 is being used the division operator will return a float64 value
711
     * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't
712
     * have the precision of int64 this is a problem so, when int64 is being used,
713
     * we'll guarantee that the dividend is divisible by first subtracting the remainder.
714
     *
715
     * @param int $x
716
     * @param int $y
717
     * @return int
718
     */
719
    private static function safe_divide($x, $y)
720
    {
721
        if (static::BASE === 26) {
722
            return (int)($x / $y);
723
        }
724
 
725
        // static::BASE === 31
726
        /** @var int */
727
        return ($x - ($x % $y)) / $y;
728
    }
729
 
730
    /**
731
     * Convert an array / boolean to a PHP BigInteger object
732
     *
733
     * @param array $arr
734
     * @return static
735
     */
736
    protected function convertToObj(array $arr)
737
    {
738
        $result = new static();
739
        $result->value = $arr[self::VALUE];
740
        $result->is_negative = $arr[self::SIGN];
741
 
742
        return $this->normalize($result);
743
    }
744
 
745
    /**
746
     * Normalize
747
     *
748
     * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
749
     *
750
     * @param PHP $result
751
     * @return static
752
     */
753
    protected function normalize(PHP $result)
754
    {
755
        $result->precision = $this->precision;
756
        $result->bitmask = $this->bitmask;
757
 
758
        $value = &$result->value;
759
 
760
        if (!count($value)) {
761
            $result->is_negative = false;
762
            return $result;
763
        }
764
 
765
        $value = static::trim($value);
766
 
767
        if (!empty($result->bitmask->value)) {
768
            $length = min(count($value), count($result->bitmask->value));
769
            $value = array_slice($value, 0, $length);
770
 
771
            for ($i = 0; $i < $length; ++$i) {
772
                $value[$i] = $value[$i] & $result->bitmask->value[$i];
773
            }
774
 
775
            $value = static::trim($value);
776
        }
777
 
778
        return $result;
779
    }
780
 
781
    /**
782
     * Compares two numbers.
783
     *
784
     * @param array $x_value
785
     * @param bool $x_negative
786
     * @param array $y_value
787
     * @param bool $y_negative
788
     * @return int
789
     * @see static::compare()
790
     */
791
    protected static function compareHelper(array $x_value, $x_negative, array $y_value, $y_negative)
792
    {
793
        if ($x_negative != $y_negative) {
794
            return (!$x_negative && $y_negative) ? 1 : -1;
795
        }
796
 
797
        $result = $x_negative ? -1 : 1;
798
 
799
        if (count($x_value) != count($y_value)) {
800
            return (count($x_value) > count($y_value)) ? $result : -$result;
801
        }
802
        $size = max(count($x_value), count($y_value));
803
 
804
        $x_value = array_pad($x_value, $size, 0);
805
        $y_value = array_pad($y_value, $size, 0);
806
 
807
        for ($i = count($x_value) - 1; $i >= 0; --$i) {
808
            if ($x_value[$i] != $y_value[$i]) {
809
                return ($x_value[$i] > $y_value[$i]) ? $result : -$result;
810
            }
811
        }
812
 
813
        return 0;
814
    }
815
 
816
    /**
817
     * Absolute value.
818
     *
819
     * @return PHP
820
     */
821
    public function abs()
822
    {
823
        $temp = new static();
824
        $temp->value = $this->value;
825
 
826
        return $temp;
827
    }
828
 
829
    /**
830
     * Trim
831
     *
832
     * Removes leading zeros
833
     *
834
     * @param list<static> $value
835
     * @return list<static>
836
     */
837
    protected static function trim(array $value)
838
    {
839
        for ($i = count($value) - 1; $i >= 0; --$i) {
840
            if ($value[$i]) {
841
                break;
842
            }
843
            unset($value[$i]);
844
        }
845
 
846
        return $value;
847
    }
848
 
849
    /**
850
     * Logical Right Shift
851
     *
852
     * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
853
     *
854
     * @param int $shift
855
     * @return PHP
856
     */
857
    public function bitwise_rightShift($shift)
858
    {
859
        $temp = new static();
860
 
861
        // could just replace lshift with this, but then all lshift() calls would need to be rewritten
862
        // and I don't want to do that...
863
        $temp->value = $this->value;
864
        $temp->rshift($shift);
865
 
866
        return $this->normalize($temp);
867
    }
868
 
869
    /**
870
     * Logical Left Shift
871
     *
872
     * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
873
     *
874
     * @param int $shift
875
     * @return PHP
876
     */
877
    public function bitwise_leftShift($shift)
878
    {
879
        $temp = new static();
880
        // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
881
        // and I don't want to do that...
882
        $temp->value = $this->value;
883
        $temp->lshift($shift);
884
 
885
        return $this->normalize($temp);
886
    }
887
 
888
    /**
889
     * Converts 32-bit integers to bytes.
890
     *
891
     * @param int $x
892
     * @return string
893
     */
894
    private static function int2bytes($x)
895
    {
896
        return ltrim(pack('N', $x), chr(0));
897
    }
898
 
899
    /**
900
     * Array Repeat
901
     *
902
     * @param int $input
903
     * @param int $multiplier
904
     * @return array
905
     */
906
    protected static function array_repeat($input, $multiplier)
907
    {
908
        return $multiplier ? array_fill(0, $multiplier, $input) : [];
909
    }
910
 
911
    /**
912
     * Logical Left Shift
913
     *
914
     * Shifts BigInteger's by $shift bits.
915
     *
916
     * @param int $shift
917
     */
918
    protected function lshift($shift)
919
    {
920
        if ($shift == 0) {
921
            return;
922
        }
923
 
924
        $num_digits = (int)($shift / static::BASE);
925
        $shift %= static::BASE;
926
        $shift = 1 << $shift;
927
 
928
        $carry = 0;
929
 
930
        for ($i = 0; $i < count($this->value); ++$i) {
931
            $temp = $this->value[$i] * $shift + $carry;
932
            $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
933
            $this->value[$i] = (int)($temp - $carry * static::BASE_FULL);
934
        }
935
 
936
        if ($carry) {
937
            $this->value[count($this->value)] = $carry;
938
        }
939
 
940
        while ($num_digits--) {
941
            array_unshift($this->value, 0);
942
        }
943
    }
944
 
945
    /**
946
     * Logical Right Shift
947
     *
948
     * Shifts BigInteger's by $shift bits.
949
     *
950
     * @param int $shift
951
     */
952
    protected function rshift($shift)
953
    {
954
        if ($shift == 0) {
955
            return;
956
        }
957
 
958
        $num_digits = (int)($shift / static::BASE);
959
        $shift %= static::BASE;
960
        $carry_shift = static::BASE - $shift;
961
        $carry_mask = (1 << $shift) - 1;
962
 
963
        if ($num_digits) {
964
            $this->value = array_slice($this->value, $num_digits);
965
        }
966
 
967
        $carry = 0;
968
 
969
        for ($i = count($this->value) - 1; $i >= 0; --$i) {
970
            $temp = $this->value[$i] >> $shift | $carry;
971
            $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
972
            $this->value[$i] = $temp;
973
        }
974
 
975
        $this->value = static::trim($this->value);
976
    }
977
 
978
    /**
979
     * Performs modular exponentiation.
980
     *
981
     * @param PHP $e
982
     * @param PHP $n
983
     * @return PHP
984
     */
985
    protected function powModInner(PHP $e, PHP $n)
986
    {
987
        try {
988
            $class = static::$modexpEngine[static::class];
989
            return $class::powModHelper($this, $e, $n, static::class);
990
        } catch (\Exception $err) {
991
            return PHP\DefaultEngine::powModHelper($this, $e, $n, static::class);
992
        }
993
    }
994
 
995
    /**
996
     * Performs squaring
997
     *
998
     * @param list<static> $x
999
     * @return list<static>
1000
     */
1001
    protected static function square(array $x)
1002
    {
1003
        return count($x) < 2 * self::KARATSUBA_CUTOFF ?
1004
            self::trim(self::baseSquare($x)) :
1005
            self::trim(self::karatsubaSquare($x));
1006
    }
1007
 
1008
    /**
1009
     * Performs traditional squaring on two BigIntegers
1010
     *
1011
     * Squaring can be done faster than multiplying a number by itself can be.  See
1012
     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1013
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
1014
     *
1015
     * @param array $value
1016
     * @return array
1017
     */
1018
    protected static function baseSquare(array $value)
1019
    {
1020
        if (empty($value)) {
1021
            return [];
1022
        }
1023
        $square_value = self::array_repeat(0, 2 * count($value));
1024
 
1025
        for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
1026
            $i2 = $i << 1;
1027
 
1028
            $temp = $square_value[$i2] + $value[$i] * $value[$i];
1029
            $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1030
            $square_value[$i2] = (int)($temp - static::BASE_FULL * $carry);
1031
 
1032
            // note how we start from $i+1 instead of 0 as we do in multiplication.
1033
            for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1034
                $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
1035
                $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1036
                $square_value[$k] = (int)($temp - static::BASE_FULL * $carry);
1037
            }
1038
 
1039
            // the following line can yield values larger 2**15.  at this point, PHP should switch
1040
            // over to floats.
1041
            $square_value[$i + $max_index + 1] = $carry;
1042
        }
1043
 
1044
        return $square_value;
1045
    }
1046
 
1047
    /**
1048
     * Performs Karatsuba "squaring" on two BigIntegers
1049
     *
1050
     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1051
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
1052
     *
1053
     * @param array $value
1054
     * @return array
1055
     */
1056
    protected static function karatsubaSquare(array $value)
1057
    {
1058
        $m = count($value) >> 1;
1059
 
1060
        if ($m < self::KARATSUBA_CUTOFF) {
1061
            return self::baseSquare($value);
1062
        }
1063
 
1064
        $x1 = array_slice($value, $m);
1065
        $x0 = array_slice($value, 0, $m);
1066
 
1067
        $z2 = self::karatsubaSquare($x1);
1068
        $z0 = self::karatsubaSquare($x0);
1069
 
1070
        $z1 = self::addHelper($x1, false, $x0, false);
1071
        $z1 = self::karatsubaSquare($z1[self::VALUE]);
1072
        $temp = self::addHelper($z2, false, $z0, false);
1073
        $z1 = self::subtractHelper($z1, false, $temp[self::VALUE], false);
1074
 
1075
        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1076
        $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);
1077
 
1078
        $xx = self::addHelper($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
1079
        $xx = self::addHelper($xx[self::VALUE], $xx[self::SIGN], $z0, false);
1080
 
1081
        return $xx[self::VALUE];
1082
    }
1083
 
1084
    /**
1085
     * Make the current number odd
1086
     *
1087
     * If the current number is odd it'll be unchanged.  If it's even, one will be added to it.
1088
     *
1089
     * @see self::randomPrime()
1090
     */
1091
    protected function make_odd()
1092
    {
1093
        $this->value[0] |= 1;
1094
    }
1095
 
1096
    /**
1097
     * Test the number against small primes.
1098
     *
1099
     * @see self::isPrime()
1100
     */
1101
    protected function testSmallPrimes()
1102
    {
1103
        if ($this->value == [1]) {
1104
            return false;
1105
        }
1106
        if ($this->value == [2]) {
1107
            return true;
1108
        }
1109
        if (~$this->value[0] & 1) {
1110
            return false;
1111
        }
1112
 
1113
        $value = $this->value;
1114
        foreach (static::PRIMES as $prime) {
1115
            list(, $r) = self::divide_digit($value, $prime);
1116
            if (!$r) {
1117
                return count($value) == 1 && $value[0] == $prime;
1118
            }
1119
        }
1120
 
1121
        return true;
1122
    }
1123
 
1124
    /**
1125
     * Scan for 1 and right shift by that amount
1126
     *
1127
     * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
1128
     *
1129
     * @param PHP $r
1130
     * @return int
1131
     * @see self::isPrime()
1132
     */
1133
    public static function scan1divide(PHP $r)
1134
    {
1135
        $r_value = &$r->value;
1136
        for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
1137
            $temp = ~$r_value[$i] & static::MAX_DIGIT;
1138
            for ($j = 1; ($temp >> $j) & 1; ++$j) {
1139
            }
1140
            if ($j <= static::BASE) {
1141
                break;
1142
            }
1143
        }
1144
        $s = static::BASE * $i + $j;
1145
        $r->rshift($s);
1146
        return $s;
1147
    }
1148
 
1149
    /**
1150
     * Performs exponentiation.
1151
     *
1152
     * @param PHP $n
1153
     * @return PHP
1154
     */
1155
    protected function powHelper(PHP $n)
1156
    {
1157
        if ($n->compare(static::$zero[static::class]) == 0) {
1158
            return new static(1);
1159
        } // n^0 = 1
1160
 
1161
        $temp = clone $this;
1162
        while (!$n->equals(static::$one[static::class])) {
1163
            $temp = $temp->multiply($this);
1164
            $n = $n->subtract(static::$one[static::class]);
1165
        }
1166
 
1167
        return $temp;
1168
    }
1169
 
1170
    /**
1171
     * Is Odd?
1172
     *
1173
     * @return bool
1174
     */
1175
    public function isOdd()
1176
    {
1177
        return (bool)($this->value[0] & 1);
1178
    }
1179
 
1180
    /**
1181
     * Tests if a bit is set
1182
     *
1183
     * @return bool
1184
     */
1185
    public function testBit($x)
1186
    {
1187
        $digit = (int) floor($x / static::BASE);
1188
        $bit = $x % static::BASE;
1189
 
1190
        if (!isset($this->value[$digit])) {
1191
            return false;
1192
        }
1193
 
1194
        return (bool)($this->value[$digit] & (1 << $bit));
1195
    }
1196
 
1197
    /**
1198
     * Is Negative?
1199
     *
1200
     * @return bool
1201
     */
1202
    public function isNegative()
1203
    {
1204
        return $this->is_negative;
1205
    }
1206
 
1207
    /**
1208
     * Negate
1209
     *
1210
     * Given $k, returns -$k
1211
     *
1212
     * @return static
1213
     */
1214
    public function negate()
1215
    {
1216
        $temp = clone $this;
1217
        $temp->is_negative = !$temp->is_negative;
1218
 
1219
        return $temp;
1220
    }
1221
 
1222
    /**
1223
     * Bitwise Split
1224
     *
1225
     * Splits BigInteger's into chunks of $split bits
1226
     *
1227
     * @param int $split
1228
     * @return list<static>
1229
     */
1230
    public function bitwise_split($split)
1231
    {
1232
        if ($split < 1) {
1233
            throw new \RuntimeException('Offset must be greater than 1');
1234
        }
1235
 
1236
        $width = (int)($split / static::BASE);
1237
        if (!$width) {
1238
            $arr = $this->bitwise_small_split($split);
1239
            return array_map(function ($digit) {
1240
                $temp = new static();
1241
                $temp->value = $digit != 0 ? [$digit] : [];
1242
                return $temp;
1243
            }, $arr);
1244
        }
1245
 
1246
        $vals = [];
1247
        $val = $this->value;
1248
 
1249
        $i = $overflow = 0;
1250
        $len = count($val);
1251
        while ($i < $len) {
1252
            $digit = [];
1253
            if (!$overflow) {
1254
                $digit = array_slice($val, $i, $width);
1255
                $i += $width;
1256
                $overflow = $split % static::BASE;
1257
                if ($overflow) {
1258
                    $mask = (1 << $overflow) - 1;
1259
                    $temp = isset($val[$i]) ? $val[$i] : 0;
1260
                    $digit[] = $temp & $mask;
1261
                }
1262
            } else {
1263
                $remaining = static::BASE - $overflow;
1264
                $tempsplit = $split - $remaining;
1265
                $tempwidth = (int)($tempsplit / static::BASE + 1);
1266
                $digit = array_slice($val, $i, $tempwidth);
1267
                $i += $tempwidth;
1268
                $tempoverflow = $tempsplit % static::BASE;
1269
                if ($tempoverflow) {
1270
                    $tempmask = (1 << $tempoverflow) - 1;
1271
                    $temp = isset($val[$i]) ? $val[$i] : 0;
1272
                    $digit[] = $temp & $tempmask;
1273
                }
1274
                $newbits = 0;
1275
                for ($j = count($digit) - 1; $j >= 0; $j--) {
1276
                    $temp = $digit[$j] & $mask;
1277
                    $digit[$j] = ($digit[$j] >> $overflow) | ($newbits << $remaining);
1278
                    $newbits = $temp;
1279
                }
1280
                $overflow = $tempoverflow;
1281
                $mask = $tempmask;
1282
            }
1283
            $temp = new static();
1284
            $temp->value = static::trim($digit);
1285
            $vals[] = $temp;
1286
        }
1287
 
1288
        return array_reverse($vals);
1289
    }
1290
 
1291
    /**
1292
     * Bitwise Split where $split < static::BASE
1293
     *
1294
     * @param int $split
1295
     * @return list<int>
1296
     */
1297
    private function bitwise_small_split($split)
1298
    {
1299
        $vals = [];
1300
        $val = $this->value;
1301
 
1302
        $mask = (1 << $split) - 1;
1303
 
1304
        $i = $overflow = 0;
1305
        $len = count($val);
1306
        $val[] = 0;
1307
        $remaining = static::BASE;
1308
        while ($i != $len) {
1309
            $digit = $val[$i] & $mask;
1310
            $val[$i] >>= $split;
1311
            if (!$overflow) {
1312
                $remaining -= $split;
1313
                $overflow = $split <= $remaining ? 0 : $split - $remaining;
1314
 
1315
                if (!$remaining) {
1316
                    $i++;
1317
                    $remaining = static::BASE;
1318
                    $overflow = 0;
1319
                }
1320
            } elseif (++$i != $len) {
1321
                $tempmask = (1 << $overflow) - 1;
1322
                $digit |= ($val[$i] & $tempmask) << $remaining;
1323
                $val[$i] >>= $overflow;
1324
                $remaining = static::BASE - $overflow;
1325
                $overflow = $split <= $remaining ? 0 : $split - $remaining;
1326
            }
1327
 
1328
            $vals[] = $digit;
1329
        }
1330
 
1331
        while ($vals[count($vals) - 1] == 0) {
1332
            unset($vals[count($vals) - 1]);
1333
        }
1334
 
1335
        return array_reverse($vals);
1336
    }
1337
}