These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 | use Assert\Assertion; |
||
15 | |||
16 | final class BigInteger |
||
17 | { |
||
18 | /** |
||
19 | * Holds the BigInteger's value. |
||
20 | * |
||
21 | * @var resource |
||
22 | */ |
||
23 | private $value; |
||
24 | |||
25 | /** |
||
26 | * Converts base-10 and binary strings (base-256) to BigIntegers. |
||
27 | * |
||
28 | * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using |
||
29 | * two's compliment. The sole exception to this is -10, which is treated the same as 10 is. |
||
30 | * |
||
31 | * Here's an example: |
||
32 | * <code> |
||
33 | * <?php |
||
34 | * $a = new \Jose\Util\in base-16 |
||
35 | * |
||
36 | * echo $a->toString(); // outputs 50 |
||
37 | * ?> |
||
38 | * </code> |
||
39 | * |
||
40 | * @param mixed $value base-10 number or base-$base number if $base set. |
||
41 | * @param int $base |
||
42 | */ |
||
43 | private function __construct($value = 0, $base = 10) |
||
44 | { |
||
45 | if($value instanceof \GMP) { |
||
0 ignored issues
–
show
|
|||
46 | $this->value = $value; |
||
47 | |||
48 | return; |
||
49 | } |
||
50 | |||
51 | $this->value = gmp_init(0); |
||
52 | |||
53 | // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48 |
||
54 | // '0' is the only value like this per http://php.net/empty |
||
55 | if (empty($value) && (abs($base) != 256 || $value !== '0')) { |
||
0 ignored issues
–
show
|
|||
56 | return; |
||
57 | } |
||
58 | |||
59 | if (256 === $base) { |
||
60 | $value = '0x'.bin2hex($value); |
||
61 | $base = 16; |
||
62 | } |
||
63 | |||
64 | $this->value = gmp_init($value, $base); |
||
0 ignored issues
–
show
It seems like
gmp_init($value, $base) of type object<GMP> is incompatible with the declared type resource 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.. ![]() |
|||
65 | } |
||
66 | |||
67 | /** |
||
68 | * @param \GMP $value |
||
69 | * |
||
70 | * @return \Jose\Util\BigInteger |
||
71 | */ |
||
72 | public static function createFromGMPResource($value) |
||
73 | { |
||
74 | Assertion::isInstanceOf($value, \GMP::class); |
||
75 | |||
76 | return new self($value); |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * @param string $value |
||
81 | * @param bool $is_negative |
||
82 | * |
||
83 | * @return \Jose\Util\BigInteger |
||
84 | */ |
||
85 | public static function createFromBinaryString($value, $is_negative = false) |
||
86 | { |
||
87 | Assertion::string($value); |
||
88 | $value = '0x'.bin2hex($value); |
||
89 | if (true === $is_negative) { |
||
90 | $value = '-'.$value; |
||
91 | } |
||
92 | |||
93 | return new self($value, 16); |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * @param string $value |
||
98 | * |
||
99 | * @return \Jose\Util\BigInteger |
||
100 | */ |
||
101 | public static function createFromDecimalString($value) |
||
102 | { |
||
103 | Assertion::string($value); |
||
104 | |||
105 | return new self($value, 10); |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Converts a BigInteger to a byte string (eg. base-256). |
||
110 | * |
||
111 | * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're |
||
112 | * saved as two's compliment. |
||
113 | * |
||
114 | * Here's an example: |
||
115 | * <code> |
||
116 | * <?php |
||
117 | * $a = new \Jose\Util\ger('65'); |
||
118 | * |
||
119 | * echo $a->toBytes(); // outputs chr(65) |
||
120 | * ?> |
||
121 | * </code> |
||
122 | * |
||
123 | * @return string |
||
124 | * |
||
125 | */ |
||
126 | public function toBytes() |
||
127 | { |
||
128 | if (gmp_cmp($this->value, gmp_init(0)) === 0) { |
||
129 | return ''; |
||
130 | } |
||
131 | |||
132 | $temp = gmp_strval(gmp_abs($this->value), 16); |
||
133 | $temp = (strlen($temp) & 1) ? '0'.$temp : $temp; |
||
134 | $temp = hex2bin($temp); |
||
135 | |||
136 | return ltrim($temp, chr(0)); |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * Adds two BigIntegers. |
||
141 | * |
||
142 | * Here's an example: |
||
143 | * <code> |
||
144 | * <?php |
||
145 | * $a = new \Jose\Util\ger('10'); |
||
146 | * $b = new \Jose\Util\ger('20'); |
||
147 | * |
||
148 | * $c = $a->add($b); |
||
149 | * |
||
150 | * echo $c->toString(); // outputs 30 |
||
151 | * ?> |
||
152 | * </code> |
||
153 | * |
||
154 | * @param \Jose\Util\BigInteger $y |
||
155 | * |
||
156 | * @return \Jose\Util\BigInteger |
||
157 | * |
||
158 | */ |
||
159 | public function add(BigInteger $y) |
||
160 | { |
||
161 | $value = gmp_add($this->value, $y->value); |
||
162 | |||
163 | return self::createFromGMPResource($value); |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * Subtracts two BigIntegers. |
||
168 | * |
||
169 | * Here's an example: |
||
170 | * <code> |
||
171 | * <?php |
||
172 | * $a = new \Jose\Util\ger('10'); |
||
173 | * $b = new \Jose\Util\ger('20'); |
||
174 | * |
||
175 | * $c = $a->subtract($b); |
||
176 | * |
||
177 | * echo $c->toString(); // outputs -10 |
||
178 | * ?> |
||
179 | * </code> |
||
180 | * |
||
181 | * @param \Jose\Util\BigInteger $y |
||
182 | * |
||
183 | * @return \Jose\Util\BigInteger |
||
184 | * |
||
185 | */ |
||
186 | public function subtract(BigInteger $y) |
||
187 | { |
||
188 | $value = gmp_sub($this->value, $y->value); |
||
189 | |||
190 | return self::createFromGMPResource($value); |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Multiplies two BigIntegers. |
||
195 | * |
||
196 | * Here's an example: |
||
197 | * <code> |
||
198 | * <?php |
||
199 | * $a = new \Jose\Util\ger('10'); |
||
200 | * $b = new \Jose\Util\ger('20'); |
||
201 | * |
||
202 | * $c = $a->multiply($b); |
||
203 | * |
||
204 | * echo $c->toString(); // outputs 200 |
||
205 | * ?> |
||
206 | * </code> |
||
207 | * |
||
208 | * @param \Jose\Util\BigInteger $x |
||
209 | * |
||
210 | * @return \Jose\Util\BigInteger |
||
211 | */ |
||
212 | public function multiply(BigInteger $x) |
||
213 | { |
||
214 | $value = gmp_mul($this->value, $x->value); |
||
215 | |||
216 | return self::createFromGMPResource($value); |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Divides two BigIntegers. |
||
221 | * |
||
222 | * Returns an array whose first element contains the quotient and whose second element contains the |
||
223 | * "common residue". If the remainder would be positive, the "common residue" and the remainder are the |
||
224 | * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder |
||
225 | * and the divisor (basically, the "common residue" is the first positive modulo). |
||
226 | * |
||
227 | * Here's an example: |
||
228 | * <code> |
||
229 | * <?php |
||
230 | * $a = new \Jose\Util\ger('10'); |
||
231 | * $b = new \Jose\Util\ger('20'); |
||
232 | * |
||
233 | * list($quotient, $remainder) = $a->divide($b); |
||
234 | * |
||
235 | * echo $quotient->toString(); // outputs 0 |
||
236 | * echo "\r\n"; |
||
237 | * echo $remainder->toString(); // outputs 10 |
||
238 | * ?> |
||
239 | * </code> |
||
240 | * @param \Jose\Util\BigInteger $y |
||
241 | * |
||
242 | * @return \Jose\Util\BigInteger[] |
||
243 | * |
||
244 | */ |
||
245 | public function divide(BigInteger $y) |
||
246 | { |
||
247 | list($quotient_value, $remainder_value) = gmp_div_qr($this->value, $y->value); |
||
248 | |||
249 | if (gmp_sign($remainder_value) < 0) { |
||
250 | $remainder_value = gmp_add($remainder_value, gmp_abs($y->value)); |
||
251 | } |
||
252 | |||
253 | return [new self($quotient_value), new self($remainder_value)]; |
||
254 | } |
||
255 | |||
256 | /** |
||
257 | * Performs modular exponentiation. |
||
258 | * |
||
259 | * Here's an example: |
||
260 | * <code> |
||
261 | * <?php |
||
262 | * $a = new \Jose\Util\ger('10'); |
||
263 | * $b = new \Jose\Util\ger('20'); |
||
264 | * $c = new \Jose\Util\ger('30'); |
||
265 | * |
||
266 | * $c = $a->modPow($b, $c); |
||
267 | * |
||
268 | * echo $c->toString(); // outputs 10 |
||
269 | * ?> |
||
270 | * </code> |
||
271 | * |
||
272 | * @param \Jose\Util\BigInteger $e |
||
273 | * @param \Jose\Util\BigInteger $n |
||
274 | * |
||
275 | * @return \Jose\Util\BigInteger|bool |
||
276 | * |
||
277 | * and although the approach involving repeated squaring does vastly better, it, too, is impractical |
||
278 | * for our purposes. The reason being that division - by far the most complicated and time-consuming |
||
279 | * of the basic operations (eg. +,-,*,/) - occurs multiple times within it. |
||
280 | * |
||
281 | * Modular reductions resolve this issue. Although an individual modular reduction takes more time |
||
282 | * then an individual division, when performed in succession (with the same modulo), they're a lot faster. |
||
283 | * |
||
284 | * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, |
||
285 | * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the |
||
286 | * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because |
||
287 | * the product of two odd numbers is odd), but what about when RSA isn't used? |
||
288 | * |
||
289 | * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a |
||
290 | * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the |
||
291 | * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, |
||
292 | * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and |
||
293 | * the other, a power of two - and recombine them, later. This is the method that this modPow function uses. |
||
294 | * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. |
||
295 | */ |
||
296 | public function modPow(BigInteger $e, BigInteger $n) |
||
297 | { |
||
298 | $n = $n->abs(); |
||
299 | |||
300 | if ($e->compare(new self()) < 0) { |
||
301 | $e = $e->abs(); |
||
302 | |||
303 | $temp = $this->modInverse($n); |
||
304 | if ($temp === false) { |
||
305 | return false; |
||
306 | } |
||
307 | |||
308 | return $temp->modPow($e, $n); |
||
309 | } |
||
310 | |||
311 | $value = gmp_powm($this->value, $e->value, $n->value); |
||
312 | |||
313 | return self::createFromGMPResource($value); |
||
314 | } |
||
315 | |||
316 | /** |
||
317 | * Calculates modular inverses. |
||
318 | * |
||
319 | * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. |
||
320 | * |
||
321 | * Here's an example: |
||
322 | * <code> |
||
323 | * <?php |
||
324 | * $a = new \Jose\Util\teger(30); |
||
325 | * $b = new \Jose\Util\teger(17); |
||
326 | * |
||
327 | * $c = $a->modInverse($b); |
||
328 | * echo $c->toString(); // outputs 4 |
||
329 | * |
||
330 | * echo "\r\n"; |
||
331 | * |
||
332 | * $d = $a->multiply($c); |
||
333 | * list(, $d) = $d->divide($b); |
||
334 | * echo $d; // outputs 1 (as per the definition of modular inverse) |
||
335 | * ?> |
||
336 | * </code> |
||
337 | * |
||
338 | * @param \Jose\Util\BigInteger $n |
||
339 | * |
||
340 | * @return \Jose\Util\BigInteger|bool |
||
341 | * |
||
342 | */ |
||
343 | public function modInverse(BigInteger $n) |
||
344 | { |
||
345 | $value = gmp_invert($this->value, $n->value); |
||
346 | |||
347 | return false === $value ? false : new self($value); |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * Absolute value. |
||
352 | * |
||
353 | * @return \Jose\Util\BigInteger |
||
354 | */ |
||
355 | public function abs() |
||
356 | { |
||
357 | $value = gmp_abs($this->value); |
||
358 | |||
359 | return self::createFromGMPResource($value); |
||
360 | } |
||
361 | |||
362 | /** |
||
363 | * Compares two numbers. |
||
364 | * |
||
365 | * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is |
||
366 | * demonstrated thusly: |
||
367 | * |
||
368 | * $x > $y: $x->compare($y) > 0 |
||
369 | * $x < $y: $x->compare($y) < 0 |
||
370 | * $x == $y: $x->compare($y) == 0 |
||
371 | * |
||
372 | * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). |
||
373 | * |
||
374 | * @param \Jose\Util\BigInteger $y |
||
375 | * |
||
376 | * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. |
||
377 | * |
||
378 | */ |
||
379 | public function compare(BigInteger $y) |
||
380 | { |
||
381 | return gmp_cmp($this->value, $y->value); |
||
382 | } |
||
383 | |||
384 | /** |
||
385 | * Logical Left Shift. |
||
386 | * |
||
387 | * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. |
||
388 | * |
||
389 | * @param int $shift |
||
390 | * |
||
391 | * @return \Jose\Util\BigInteger |
||
392 | * |
||
393 | */ |
||
394 | public function bitwise_leftShift($shift) |
||
395 | { |
||
396 | $two = gmp_init('2'); |
||
397 | $value = gmp_mul($this->value, gmp_pow($two, $shift)); |
||
398 | |||
399 | return self::createFromGMPResource($value); |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * Generates a random BigInteger. |
||
404 | * |
||
405 | * Byte length is equal to $length. Uses \phpseclib\Crypt\Random if it's loaded and mt_rand if it's not. |
||
406 | * |
||
407 | * @param int $size |
||
408 | * |
||
409 | * @return \Jose\Util\BigInteger |
||
410 | */ |
||
411 | private static function _random_number_helper($size) |
||
412 | { |
||
413 | return new self(random_bytes($size), 256); |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * Generate a random number. |
||
418 | * |
||
419 | * Returns a random number between $min and $max where $min and $max |
||
420 | * can be defined using one of the two methods: |
||
421 | * |
||
422 | * BigInteger::random($min, $max) |
||
423 | * BigInteger::random($max, $min) |
||
424 | * |
||
425 | * @param \Jose\Util\BigInteger $min |
||
426 | * @param \Jose\Util\BigInteger $max |
||
427 | * |
||
428 | * @return \Jose\Util\BigInteger |
||
429 | */ |
||
430 | public static function random(BigInteger $min, BigInteger $max) |
||
431 | { |
||
432 | $compare = $max->compare($min); |
||
433 | |||
434 | if (!$compare) { |
||
435 | return $min; |
||
436 | } elseif ($compare < 0) { |
||
437 | // if $min is bigger then $max, swap $min and $max |
||
438 | $temp = $max; |
||
439 | $max = $min; |
||
440 | $min = $temp; |
||
441 | } |
||
442 | |||
443 | $one = new self('1'); |
||
444 | |||
445 | $max = $max->subtract($min->subtract($one)); |
||
446 | $size = strlen(ltrim($max->toBytes(), chr(0))); |
||
447 | |||
448 | /* |
||
449 | doing $random % $max doesn't work because some numbers will be more likely to occur than others. |
||
450 | eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145 |
||
451 | would produce 5 whereas the only value of random that could produce 139 would be 139. ie. |
||
452 | not all numbers would be equally likely. some would be more likely than others. |
||
453 | |||
454 | creating a whole new random number until you find one that is within the range doesn't work |
||
455 | because, for sufficiently small ranges, the likelihood that you'd get a number within that range |
||
456 | would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability |
||
457 | would be pretty high that $random would be greater than $max. |
||
458 | |||
459 | phpseclib works around this using the technique described here: |
||
460 | |||
461 | http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string |
||
462 | */ |
||
463 | $random_max = new self(chr(1).str_repeat("\0", $size), 256); |
||
464 | $random = self::_random_number_helper($size); |
||
465 | |||
466 | list($max_multiple) = $random_max->divide($max); |
||
467 | $max_multiple = $max_multiple->multiply($max); |
||
468 | |||
469 | while ($random->compare($max_multiple) >= 0) { |
||
470 | $random = $random->subtract($max_multiple); |
||
471 | $random_max = $random_max->subtract($max_multiple); |
||
472 | $random = $random->bitwise_leftShift(8); |
||
473 | $random = $random->add(self::_random_number_helper(1)); |
||
474 | $random_max = $random_max->bitwise_leftShift(8); |
||
475 | list($max_multiple) = $random_max->divide($max); |
||
476 | $max_multiple = $max_multiple->multiply($max); |
||
477 | } |
||
478 | list(, $random) = $random->divide($max); |
||
479 | |||
480 | return $random->add($min); |
||
481 | } |
||
482 | |||
483 | } |
||
484 |
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 thecomposer.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
orrequire-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 you have not tested against this specific condition, such errors might go unnoticed.