Failed Conditions
Push — PHPSecLib_Rid ( 2ba149...2881a4 )
by Florent
05:10
created

BigInteger::modPow()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 20
rs 8.8571
cc 5
eloc 11
nc 12
nop 2
1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2016 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
namespace Jose\Util;
13
14
class BigInteger
15
{
16
    const MONTGOMERY = 0;
17
18
    const BARRETT = 1;
19
20
    const POWEROF2 = 2;
21
22
    const CLASSIC = 3;
23
24
    const NONE = 4;
25
26
    /**#@+
27
     * Array constants
28
     *
29
     * Rather than create a thousands and thousands of new BigInteger objects in repeated function calls to add() and
30
     * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
31
     *
32
     */
33
    /**
34
     * $result[self::VALUE] contains the value.
35
     */
36
    const VALUE = 0;
37
    /**
38
     * $result[self::SIGN] contains the sign.
39
     */
40
    const SIGN = 1;
41
    /**#@-*/
42
43
    /**#@+
44
     */
45
    /**
46
     * Cache constants.
47
     *
48
     * $cache[self::VARIABLE] tells us whether or not the cached data is still valid.
49
     */
50
    const VARIABLE = 0;
51
    /**
52
     * $cache[self::DATA] contains the cached data.
53
     */
54
    const DATA = 1;
55
    /**#@-*/
56
57
    /**
58
     * Karatsuba Cutoff.
59
     *
60
     * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
61
     */
62
    const KARATSUBA_CUTOFF = 25;
63
64
    /**#@+
65
     * Static properties used by the pure-PHP implementation.
66
     *
67
     * @see __construct()
68
     */
69
    protected static $base;
70
    protected static $baseFull;
71
    protected static $maxDigit;
72
    protected static $msb;
73
74
    /**
75
     * $max10 in greatest $max10Len satisfying
76
     * $max10 = 10**$max10Len <= 2**$base.
77
     */
78
    protected static $max10;
79
80
    /**
81
     * $max10Len in greatest $max10Len satisfying
82
     * $max10 = 10**$max10Len <= 2**$base.
83
     */
84
    protected static $max10Len;
85
    protected static $maxDigit2;
86
    /**#@-*/
87
88
    /**
89
     * Holds the BigInteger's value.
90
     *
91
     * @var array
92
     */
93
    private $value;
94
95
    /**
96
     * Holds the BigInteger's magnitude.
97
     *
98
     * @var bool
99
     */
100
    private $is_negative = false;
101
102
    /**
103
     * Precision.
104
     */
105
    private $precision = -1;
106
107
    /**
108
     * Precision Bitmask.
109
     */
110
    private $bitmask = false;
111
112
    /**
113
     * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
114
     *
115
     * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
116
     * two's compliment.  The sole exception to this is -10, which is treated the same as 10 is.
117
     *
118
     * Here's an example:
119
     * <code>
120
     * <?php
121
     *    $a = new \Jose\Util\in base-16
122
     *
123
     *    echo $a->toString(); // outputs 50
124
     * ?>
125
     * </code>
126
     *
127
     * @param $x base-10 number or base-$base number if $base set.
128
     * @param int $base
129
     *
130
     * @return \Jose\Util\BigInteger
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
131
     */
132
    public function __construct($x = 0, $base = 10)
133
    {
134
        if (extension_loaded('openssl') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
135
            define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
136
        }
137
138
        switch (true) {
139
            case is_resource($x) && get_resource_type($x) == 'GMP integer':
140
                // PHP 5.6 switched GMP from using resources to objects
141
            case $x instanceof \GMP:
0 ignored issues
show
Bug introduced by
The class GMP does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
142
                $this->value = $x;
0 ignored issues
show
Documentation Bug introduced by
It seems like $x of type resource is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
143
144
                return;
145
        }
146
        $this->value = gmp_init(0);
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_init(0) of type object<GMP> is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
147
148
        // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
149
        // '0' is the only value like this per http://php.net/empty
150
        if (empty($x) && (abs($base) != 256 || $x !== '0')) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of $x (integer) and '0' (string) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
151
            return;
152
        }
153
154
        switch ($base) {
155
            case -256:
156
                if (ord($x[0]) & 0x80) {
157
                    $x = ~$x;
158
                    $this->is_negative = true;
159
                }
160
            case 256:
161
                $sign = $this->is_negative ? '-' : '';
162
                $this->value = gmp_init($sign.'0x'.bin2hex($x));
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_init($sign . '0x' . bin2hex($x)) of type object<GMP> is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
163
164
                if ($this->is_negative) {
165
                    $this->is_negative = false;
166
                    $temp = $this->add(new static('-1'));
167
                    $this->value = $temp->value;
168
                }
169
                break;
170
            case 16:
171
            case -16:
172
                if ($base > 0 && $x[0] == '-') {
173
                    $this->is_negative = true;
174
                    $x = substr($x, 1);
175
                }
176
177
                $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
178
179
                $is_negative = false;
180
                if ($base < 0 && hexdec($x[0]) >= 8) {
181
                    $this->is_negative = $is_negative = true;
182
                    $x = bin2hex(~hex2bin($x));
183
                }
184
185
            $temp = $this->is_negative ? '-0x'.$x : '0x'.$x;
186
            $this->value = gmp_init($temp);
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_init($temp) of type object<GMP> is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
187
            $this->is_negative = false;
188
189
                if ($is_negative) {
190
                    $temp = $this->add(new static('-1'));
191
                    $this->value = $temp->value;
192
                }
193
                break;
194
            case 10:
195
            case -10:
196
                // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
197
                // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
198
                // [^-0-9].*: find any non-numeric characters and then any characters that follow that
199
                $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
200
201
                $this->value = gmp_init($x);
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_init($x) of type object<GMP> is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
202
                break;
203
            case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
204
            case -2:
205
                if ($base > 0 && $x[0] == '-') {
206
                    $this->is_negative = true;
207
                    $x = substr($x, 1);
208
                }
209
210
                $x = preg_replace('#^([01]*).*#', '$1', $x);
211
                $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
212
213
                $str = '0x';
214
                while (strlen($x)) {
215
                    $part = substr($x, 0, 4);
216
                    $str .= dechex(bindec($part));
217
                    $x = substr($x, 4);
218
                }
219
220
                if ($this->is_negative) {
221
                    $str = '-'.$str;
222
                }
223
224
                $temp = new static($str, 8 * $base); // ie. either -16 or +16
225
                $this->value = $temp->value;
226
                $this->is_negative = $temp->is_negative;
227
228
                break;
229
            default:
230
                // base not supported, so we'll let $this == 0
231
        }
232
    }
233
234
    /**
235
     * Converts a BigInteger to a byte string (eg. base-256).
236
     *
237
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
238
     * saved as two's compliment.
239
     *
240
     * Here's an example:
241
     * <code>
242
     * <?php
243
     *    $a = new \Jose\Util\ger('65');
244
     *
245
     *    echo $a->toBytes(); // outputs chr(65)
246
     * ?>
247
     * </code>
248
     *
249
     * @param bool $twos_compliment
250
     *
251
     * @return string
252
     *
253
     */
254
    public function toBytes($twos_compliment = false)
255
    {
256
        if ($twos_compliment) {
257
            $comparison = $this->compare(new static());
258
            if ($comparison == 0) {
259
                return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
260
            }
261
262
            $temp = $comparison < 0 ? $this->add(new static(1)) : $this;
263
            $bytes = $temp->toBytes();
264
265
            if (empty($bytes)) { // eg. if the number we're trying to convert is -1
266
                $bytes = chr(0);
267
            }
268
269
            if (ord($bytes[0]) & 0x80) {
270
                $bytes = chr(0).$bytes;
271
            }
272
273
            return $comparison < 0 ? ~$bytes : $bytes;
274
        }
275
276
        if (gmp_cmp($this->value, gmp_init(0)) == 0) {
277
            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
278
        }
279
280
        $temp = gmp_strval(gmp_abs($this->value), 16);
281
        $temp = (strlen($temp) & 1) ? '0'.$temp : $temp;
282
        $temp = hex2bin($temp);
283
284
        return $this->precision > 0 ?
285
            substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
286
            ltrim($temp, chr(0));
287
    }
288
289
    /**
290
     * Adds two BigIntegers.
291
     *
292
     * Here's an example:
293
     * <code>
294
     * <?php
295
     *    $a = new \Jose\Util\ger('10');
296
     *    $b = new \Jose\Util\ger('20');
297
     *
298
     *    $c = $a->add($b);
299
     *
300
     *    echo $c->toString(); // outputs 30
301
     * ?>
302
     * </code>
303
     *
304
     * @param \Jose\Util\Integer $y
305
     *
306
     * @return \Jose\Util\BigInteger
307
     *
308
     */
309
    public function add(BigInteger $y)
310
    {
311
        $temp = new static();
312
        $temp->value = gmp_add($this->value, $y->value);
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_add($this->value, $y->value) of type resource is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
313
314
        return $this->_normalize($temp);
315
    }
316
317
    /**
318
     * Subtracts two BigIntegers.
319
     *
320
     * Here's an example:
321
     * <code>
322
     * <?php
323
     *    $a = new \Jose\Util\ger('10');
324
     *    $b = new \Jose\Util\ger('20');
325
     *
326
     *    $c = $a->subtract($b);
327
     *
328
     *    echo $c->toString(); // outputs -10
329
     * ?>
330
     * </code>
331
     *
332
     * @param \Jose\Util\Integer $y
333
     *
334
     * @return \Jose\Util\BigInteger
335
     *
336
     */
337
    public function subtract(BigInteger $y)
338
    {
339
        $temp = new static();
340
        $temp->value = gmp_sub($this->value, $y->value);
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_sub($this->value, $y->value) of type resource is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
341
342
        return $this->_normalize($temp);
343
    }
344
345
    /**
346
     * Multiplies two BigIntegers.
347
     *
348
     * Here's an example:
349
     * <code>
350
     * <?php
351
     *    $a = new \Jose\Util\ger('10');
352
     *    $b = new \Jose\Util\ger('20');
353
     *
354
     *    $c = $a->multiply($b);
355
     *
356
     *    echo $c->toString(); // outputs 200
357
     * ?>
358
     * </code>
359
     *
360
     * @param \Jose\Util\Integer $x
361
     *
362
     * @return \Jose\Util\BigInteger
363
     */
364
    public function multiply(BigInteger $x)
365
    {
366
        $temp = new static();
367
        $temp->value = gmp_mul($this->value, $x->value);
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_mul($this->value, $x->value) of type resource is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
368
369
        return $this->_normalize($temp);
370
    }
371
372
    /**
373
     * Divides two BigIntegers.
374
     *
375
     * Returns an array whose first element contains the quotient and whose second element contains the
376
     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
377
     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
378
     * and the divisor (basically, the "common residue" is the first positive modulo).
379
     *
380
     * Here's an example:
381
     * <code>
382
     * <?php
383
     *    $a = new \Jose\Util\ger('10');
384
     *    $b = new \Jose\Util\ger('20');
385
     *
386
     *    list($quotient, $remainder) = $a->divide($b);
387
     *
388
     *    echo $quotient->toString(); // outputs 0
389
     *    echo "\r\n";
390
     *    echo $remainder->toString(); // outputs 10
391
     * ?>
392
     * </code>
393
     *
394
     * @param \Jose\Util\Integer $y
395
     *
396
     * @return array
397
     *
398
     */
399
    public function divide(BigInteger $y)
400
    {
401
        $quotient = new static();
402
        $remainder = new static();
403
404
        list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
405
406
        if (gmp_sign($remainder->value) < 0) {
407
            $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_add($remainder->value, gmp_abs($y->value)) of type resource is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
408
        }
409
410
        return [$this->_normalize($quotient), $this->_normalize($remainder)];
411
    }
412
413
    /**
414
     * Performs modular exponentiation.
415
     *
416
     * Here's an example:
417
     * <code>
418
     * <?php
419
     *    $a = new \Jose\Util\ger('10');
420
     *    $b = new \Jose\Util\ger('20');
421
     *    $c = new \Jose\Util\ger('30');
422
     *
423
     *    $c = $a->modPow($b, $c);
424
     *
425
     *    echo $c->toString(); // outputs 10
426
     * ?>
427
     * </code>
428
     *
429
     * @param \Jose\Util\Integer $e
430
     * @param \Jose\Util\Integer $n
431
     *
432
     * @return \Jose\Util\BigInteger
433
     *
434
     *    and although the approach involving repeated squaring does vastly better, it, too, is impractical
435
     *    for our purposes.  The reason being that division - by far the most complicated and time-consuming
436
     *    of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
437
     *
438
     *    Modular reductions resolve this issue.  Although an individual modular reduction takes more time
439
     *    then an individual division, when performed in succession (with the same modulo), they're a lot faster.
440
     *
441
     *    The two most commonly used modular reductions are Barrett and Montgomery reduction.  Montgomery reduction,
442
     *    although faster, only works when the gcd of the modulo and of the base being used is 1.  In RSA, when the
443
     *    base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
444
     *    the product of two odd numbers is odd), but what about when RSA isn't used?
445
     *
446
     *    In contrast, Barrett reduction has no such constraint.  As such, some bigint implementations perform a
447
     *    Barrett reduction after every operation in the modpow function.  Others perform Barrett reductions when the
448
     *    modulo is even and Montgomery reductions when the modulo is odd.  BigInteger.java's modPow method, however,
449
     *    uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
450
     *    the other, a power of two - and recombine them, later.  This is the method that this modPow function uses.
451
     *    {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
452
     */
453
    public function modPow(BigInteger $e, BigInteger $n)
454
    {
455
        $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
0 ignored issues
show
Bug introduced by
The method compare cannot be called on $this->bitmask (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
456
457
        if ($e->compare(new static()) < 0) {
458
            $e = $e->abs();
459
460
            $temp = $this->modInverse($n);
0 ignored issues
show
Bug introduced by
It seems like $n defined by $this->bitmask !== false...is->bitmask : $n->abs() on line 455 can also be of type boolean; however, Jose\Util\BigInteger::modInverse() does only seem to accept object<Jose\Util\BigInteger>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
461
            if ($temp === false) {
462
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Jose\Util\BigInteger::modPow of type Jose\Util\BigInteger.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
463
            }
464
465
            return $this->_normalize($temp->modPow($e, $n));
0 ignored issues
show
Bug introduced by
It seems like $n defined by $this->bitmask !== false...is->bitmask : $n->abs() on line 455 can also be of type boolean; however, Jose\Util\BigInteger::modPow() does only seem to accept object<Jose\Util\BigInteger>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
466
        }
467
468
            $temp = new static();
469
            $temp->value = gmp_powm($this->value, $e->value, $n->value);
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_powm($this->value, $e->value, $n->value) of type resource is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
470
471
            return $this->_normalize($temp);
472
    }
473
474
    /**
475
     * Calculates modular inverses.
476
     *
477
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
478
     *
479
     * Here's an example:
480
     * <code>
481
     * <?php
482
     *    $a = new \Jose\Util\teger(30);
483
     *    $b = new \Jose\Util\teger(17);
484
     *
485
     *    $c = $a->modInverse($b);
486
     *    echo $c->toString(); // outputs 4
487
     *
488
     *    echo "\r\n";
489
     *
490
     *    $d = $a->multiply($c);
491
     *    list(, $d) = $d->divide($b);
492
     *    echo $d; // outputs 1 (as per the definition of modular inverse)
493
     * ?>
494
     * </code>
495
     *
496
     * @param \Jose\Util\Integer $n
497
     *
498
     * @return \Jose\Util\eger|false
499
     *
500
     */
501
    public function modInverse(BigInteger $n)
502
    {
503
        $temp = new static();
504
        $temp->value = gmp_invert($this->value, $n->value);
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_invert($this->value, $n->value) of type resource is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
505
506
        return ($temp->value === false) ? false : $this->_normalize($temp);
507
    }
508
509
    /**
510
     * Absolute value.
511
     *
512
     * @return \Jose\Util\BigInteger
513
     */
514
    public function abs()
515
    {
516
        $temp = new static();
517
518
        $temp->value = gmp_abs($this->value);
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_abs($this->value) of type resource is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
519
520
        return $temp;
521
    }
522
523
    /**
524
     * Compares two numbers.
525
     *
526
     * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this is
527
     * demonstrated thusly:
528
     *
529
     * $x  > $y: $x->compare($y)  > 0
530
     * $x  < $y: $x->compare($y)  < 0
531
     * $x == $y: $x->compare($y) == 0
532
     *
533
     * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
534
     *
535
     * @param \Jose\Util\Integer $y
536
     *
537
     * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
538
     *
539
     */
540
    public function compare(BigInteger $y)
541
    {
542
        return gmp_cmp($this->value, $y->value);
543
    }
544
545
    /**
546
     * Logical Left Shift.
547
     *
548
     * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
549
     *
550
     * @param int $shift
551
     *
552
     * @return \Jose\Util\BigInteger
553
     *
554
     */
555
    public function bitwise_leftShift($shift)
556
    {
557
        $temp = new static();
558
559
        static $two;
560
561
        if (!isset($two)) {
562
            $two = gmp_init('2');
563
        }
564
565
        $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
0 ignored issues
show
Documentation Bug introduced by
It seems like gmp_mul($this->value, gmp_pow($two, $shift)) of type resource is incompatible with the declared type array of property $value.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
566
567
        return $this->_normalize($temp);
568
    }
569
570
    /**
571
     * Generates a random BigInteger.
572
     *
573
     * Byte length is equal to $length. Uses \phpseclib\Crypt\Random if it's loaded and mt_rand if it's not.
574
     *
575
     * @param int $length
0 ignored issues
show
Bug introduced by
There is no parameter named $length. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
576
     *
577
     * @return \Jose\Util\BigInteger
578
     */
579
    private static function _random_number_helper($size)
580
    {
581
        return new static(random_bytes($size), 256);
582
    }
583
584
    /**
585
     * Generate a random number.
586
     *
587
     * Returns a random number between $min and $max where $min and $max
588
     * can be defined using one of the two methods:
589
     *
590
     * BigInteger::random($min, $max)
591
     * BigInteger::random($max, $min)
592
     *
593
     * @param \Jose\Util\eger $arg1
0 ignored issues
show
Bug introduced by
There is no parameter named $arg1. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
594
     * @param \Jose\Util\eger $arg2
0 ignored issues
show
Bug introduced by
There is no parameter named $arg2. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
595
     *
596
     * @return \Jose\Util\BigInteger
597
     */
598
    public static function random(BigInteger $min, BigInteger $max)
599
    {
600
        $compare = $max->compare($min);
601
602
        if (!$compare) {
603
            return $this->_normalize($min);
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
Usage of "$this" in static methods will cause runtime errors
Loading history...
604
        } elseif ($compare < 0) {
605
            // if $min is bigger then $max, swap $min and $max
606
            $temp = $max;
607
            $max = $min;
608
            $min = $temp;
609
        }
610
611
        static $one;
612
        if (!isset($one)) {
613
            $one = new static(1);
614
        }
615
616
        $max = $max->subtract($min->subtract($one));
617
        $size = strlen(ltrim($max->toBytes(), chr(0)));
618
619
        /*
620
            doing $random % $max doesn't work because some numbers will be more likely to occur than others.
621
            eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
622
            would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
623
            not all numbers would be equally likely. some would be more likely than others.
624
625
            creating a whole new random number until you find one that is within the range doesn't work
626
            because, for sufficiently small ranges, the likelihood that you'd get a number within that range
627
            would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
628
            would be pretty high that $random would be greater than $max.
629
630
            phpseclib works around this using the technique described here:
631
632
            http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
633
        */
634
        $random_max = new static(chr(1).str_repeat("\0", $size), 256);
635
        $random = static::_random_number_helper($size);
0 ignored issues
show
Bug introduced by
Since _random_number_helper() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of _random_number_helper() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
636
637
        list($max_multiple) = $random_max->divide($max);
638
        $max_multiple = $max_multiple->multiply($max);
639
640
        while ($random->compare($max_multiple) >= 0) {
641
            $random = $random->subtract($max_multiple);
642
            $random_max = $random_max->subtract($max_multiple);
643
            $random = $random->bitwise_leftShift(8);
644
            $random = $random->add(self::_random_number_helper(1));
645
            $random_max = $random_max->bitwise_leftShift(8);
646
            list($max_multiple) = $random_max->divide($max);
647
            $max_multiple = $max_multiple->multiply($max);
648
        }
649
        list(, $random) = $random->divide($max);
650
651
        return $random->add($min);
652
    }
653
654
    /**
655
     * Normalize.
656
     *
657
     * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
658
     *
659
     * @param \Jose\Util\BigInteger
660
     *
661
     * @return \Jose\Util\BigInteger
662
     */
663
    private function _normalize($result)
664
    {
665
        $result->precision = $this->precision;
666
        $result->bitmask = $this->bitmask;
667
668
        if ($this->bitmask !== false) {
669
            $result->value = gmp_and($result->value, $result->bitmask->value);
670
        }
671
672
        return $result;
673
    }
674
}
675