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 resource |
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
|
|
|
public function __construct($x = 0, $base = 10) |
131
|
|
|
{ |
132
|
|
|
switch (true) { |
133
|
|
|
case is_resource($x) && get_resource_type($x) == 'GMP integer': |
134
|
|
|
// PHP 5.6 switched GMP from using resources to objects |
135
|
|
|
case $x instanceof \GMP: |
|
|
|
|
136
|
|
|
$this->value = $x; |
137
|
|
|
|
138
|
|
|
return; |
139
|
|
|
} |
140
|
|
|
$this->value = gmp_init(0); |
|
|
|
|
141
|
|
|
|
142
|
|
|
// '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48 |
143
|
|
|
// '0' is the only value like this per http://php.net/empty |
144
|
|
|
if (empty($x) && (abs($base) != 256 || $x !== '0')) { |
|
|
|
|
145
|
|
|
return; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
switch ($base) { |
149
|
|
|
case -256: |
150
|
|
|
if (ord($x[0]) & 0x80) { |
151
|
|
|
$x = ~$x; |
152
|
|
|
$this->is_negative = true; |
153
|
|
|
} |
154
|
|
|
case 256: |
155
|
|
|
$sign = $this->is_negative ? '-' : ''; |
156
|
|
|
$this->value = gmp_init($sign.'0x'.bin2hex($x)); |
|
|
|
|
157
|
|
|
|
158
|
|
|
if ($this->is_negative) { |
159
|
|
|
$this->is_negative = false; |
160
|
|
|
$temp = $this->add(new static('-1')); |
161
|
|
|
$this->value = $temp->value; |
162
|
|
|
} |
163
|
|
|
break; |
164
|
|
|
case 16: |
165
|
|
|
case -16: |
166
|
|
|
if ($base > 0 && $x[0] == '-') { |
167
|
|
|
$this->is_negative = true; |
168
|
|
|
$x = substr($x, 1); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
$x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x); |
172
|
|
|
|
173
|
|
|
$is_negative = false; |
174
|
|
|
if ($base < 0 && hexdec($x[0]) >= 8) { |
175
|
|
|
$this->is_negative = $is_negative = true; |
176
|
|
|
$x = bin2hex(~hex2bin($x)); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
$temp = $this->is_negative ? '-0x'.$x : '0x'.$x; |
180
|
|
|
$this->value = gmp_init($temp); |
|
|
|
|
181
|
|
|
$this->is_negative = false; |
182
|
|
|
|
183
|
|
|
if ($is_negative) { |
184
|
|
|
$temp = $this->add(new static('-1')); |
185
|
|
|
$this->value = $temp->value; |
186
|
|
|
} |
187
|
|
|
break; |
188
|
|
|
case 10: |
189
|
|
|
case -10: |
190
|
|
|
// (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that |
191
|
|
|
// (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals) |
192
|
|
|
// [^-0-9].*: find any non-numeric characters and then any characters that follow that |
193
|
|
|
$x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x); |
194
|
|
|
|
195
|
|
|
$this->value = gmp_init($x); |
|
|
|
|
196
|
|
|
break; |
197
|
|
|
case 2: // base-2 support originally implemented by Lluis Pamies - thanks! |
198
|
|
|
case -2: |
199
|
|
|
if ($base > 0 && $x[0] == '-') { |
200
|
|
|
$this->is_negative = true; |
201
|
|
|
$x = substr($x, 1); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
$x = preg_replace('#^([01]*).*#', '$1', $x); |
205
|
|
|
$x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT); |
206
|
|
|
|
207
|
|
|
$str = '0x'; |
208
|
|
|
while (strlen($x)) { |
209
|
|
|
$part = substr($x, 0, 4); |
210
|
|
|
$str .= dechex(bindec($part)); |
211
|
|
|
$x = substr($x, 4); |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
if ($this->is_negative) { |
215
|
|
|
$str = '-'.$str; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
$temp = new static($str, 8 * $base); // ie. either -16 or +16 |
219
|
|
|
$this->value = $temp->value; |
220
|
|
|
$this->is_negative = $temp->is_negative; |
221
|
|
|
|
222
|
|
|
break; |
223
|
|
|
default: |
224
|
|
|
// base not supported, so we'll let $this == 0 |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Converts a BigInteger to a byte string (eg. base-256). |
230
|
|
|
* |
231
|
|
|
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're |
232
|
|
|
* saved as two's compliment. |
233
|
|
|
* |
234
|
|
|
* Here's an example: |
235
|
|
|
* <code> |
236
|
|
|
* <?php |
237
|
|
|
* $a = new \Jose\Util\ger('65'); |
238
|
|
|
* |
239
|
|
|
* echo $a->toBytes(); // outputs chr(65) |
240
|
|
|
* ?> |
241
|
|
|
* </code> |
242
|
|
|
* |
243
|
|
|
* @param bool $twos_compliment |
244
|
|
|
* |
245
|
|
|
* @return string |
246
|
|
|
* |
247
|
|
|
*/ |
248
|
|
|
public function toBytes($twos_compliment = false) |
249
|
|
|
{ |
250
|
|
|
if ($twos_compliment) { |
251
|
|
|
$comparison = $this->compare(new static()); |
252
|
|
|
if ($comparison == 0) { |
253
|
|
|
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
$temp = $comparison < 0 ? $this->add(new static(1)) : $this; |
257
|
|
|
$bytes = $temp->toBytes(); |
258
|
|
|
|
259
|
|
|
if (empty($bytes)) { // eg. if the number we're trying to convert is -1 |
260
|
|
|
$bytes = chr(0); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
if (ord($bytes[0]) & 0x80) { |
264
|
|
|
$bytes = chr(0).$bytes; |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
return $comparison < 0 ? ~$bytes : $bytes; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
if (gmp_cmp($this->value, gmp_init(0)) == 0) { |
271
|
|
|
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
$temp = gmp_strval(gmp_abs($this->value), 16); |
275
|
|
|
$temp = (strlen($temp) & 1) ? '0'.$temp : $temp; |
276
|
|
|
$temp = hex2bin($temp); |
277
|
|
|
|
278
|
|
|
return $this->precision > 0 ? |
279
|
|
|
substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : |
280
|
|
|
ltrim($temp, chr(0)); |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Adds two BigIntegers. |
285
|
|
|
* |
286
|
|
|
* Here's an example: |
287
|
|
|
* <code> |
288
|
|
|
* <?php |
289
|
|
|
* $a = new \Jose\Util\ger('10'); |
290
|
|
|
* $b = new \Jose\Util\ger('20'); |
291
|
|
|
* |
292
|
|
|
* $c = $a->add($b); |
293
|
|
|
* |
294
|
|
|
* echo $c->toString(); // outputs 30 |
295
|
|
|
* ?> |
296
|
|
|
* </code> |
297
|
|
|
* |
298
|
|
|
* @param \Jose\Util\Integer $y |
299
|
|
|
* |
300
|
|
|
* @return \Jose\Util\BigInteger |
301
|
|
|
* |
302
|
|
|
*/ |
303
|
|
|
public function add(BigInteger $y) |
304
|
|
|
{ |
305
|
|
|
$temp = new static(); |
306
|
|
|
$temp->value = gmp_add($this->value, $y->value); |
307
|
|
|
|
308
|
|
|
return $this->_normalize($temp); |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* Subtracts two BigIntegers. |
313
|
|
|
* |
314
|
|
|
* Here's an example: |
315
|
|
|
* <code> |
316
|
|
|
* <?php |
317
|
|
|
* $a = new \Jose\Util\ger('10'); |
318
|
|
|
* $b = new \Jose\Util\ger('20'); |
319
|
|
|
* |
320
|
|
|
* $c = $a->subtract($b); |
321
|
|
|
* |
322
|
|
|
* echo $c->toString(); // outputs -10 |
323
|
|
|
* ?> |
324
|
|
|
* </code> |
325
|
|
|
* |
326
|
|
|
* @param \Jose\Util\Integer $y |
327
|
|
|
* |
328
|
|
|
* @return \Jose\Util\BigInteger |
329
|
|
|
* |
330
|
|
|
*/ |
331
|
|
|
public function subtract(BigInteger $y) |
332
|
|
|
{ |
333
|
|
|
$temp = new static(); |
334
|
|
|
$temp->value = gmp_sub($this->value, $y->value); |
335
|
|
|
|
336
|
|
|
return $this->_normalize($temp); |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* Multiplies two BigIntegers. |
341
|
|
|
* |
342
|
|
|
* Here's an example: |
343
|
|
|
* <code> |
344
|
|
|
* <?php |
345
|
|
|
* $a = new \Jose\Util\ger('10'); |
346
|
|
|
* $b = new \Jose\Util\ger('20'); |
347
|
|
|
* |
348
|
|
|
* $c = $a->multiply($b); |
349
|
|
|
* |
350
|
|
|
* echo $c->toString(); // outputs 200 |
351
|
|
|
* ?> |
352
|
|
|
* </code> |
353
|
|
|
* |
354
|
|
|
* @param \Jose\Util\Integer $x |
355
|
|
|
* |
356
|
|
|
* @return \Jose\Util\BigInteger |
357
|
|
|
*/ |
358
|
|
|
public function multiply(BigInteger $x) |
359
|
|
|
{ |
360
|
|
|
$temp = new static(); |
361
|
|
|
$temp->value = gmp_mul($this->value, $x->value); |
362
|
|
|
|
363
|
|
|
return $this->_normalize($temp); |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
/** |
367
|
|
|
* Divides two BigIntegers. |
368
|
|
|
* |
369
|
|
|
* Returns an array whose first element contains the quotient and whose second element contains the |
370
|
|
|
* "common residue". If the remainder would be positive, the "common residue" and the remainder are the |
371
|
|
|
* same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder |
372
|
|
|
* and the divisor (basically, the "common residue" is the first positive modulo). |
373
|
|
|
* |
374
|
|
|
* Here's an example: |
375
|
|
|
* <code> |
376
|
|
|
* <?php |
377
|
|
|
* $a = new \Jose\Util\ger('10'); |
378
|
|
|
* $b = new \Jose\Util\ger('20'); |
379
|
|
|
* |
380
|
|
|
* list($quotient, $remainder) = $a->divide($b); |
381
|
|
|
* |
382
|
|
|
* echo $quotient->toString(); // outputs 0 |
383
|
|
|
* echo "\r\n"; |
384
|
|
|
* echo $remainder->toString(); // outputs 10 |
385
|
|
|
* ?> |
386
|
|
|
* </code> |
387
|
|
|
* |
388
|
|
|
* @param \Jose\Util\Integer $y |
389
|
|
|
* |
390
|
|
|
* @return array |
391
|
|
|
* |
392
|
|
|
*/ |
393
|
|
|
public function divide(BigInteger $y) |
394
|
|
|
{ |
395
|
|
|
$quotient = new static(); |
396
|
|
|
$remainder = new static(); |
397
|
|
|
|
398
|
|
|
list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value); |
399
|
|
|
|
400
|
|
|
if (gmp_sign($remainder->value) < 0) { |
401
|
|
|
$remainder->value = gmp_add($remainder->value, gmp_abs($y->value)); |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
return [$this->_normalize($quotient), $this->_normalize($remainder)]; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* Performs modular exponentiation. |
409
|
|
|
* |
410
|
|
|
* Here's an example: |
411
|
|
|
* <code> |
412
|
|
|
* <?php |
413
|
|
|
* $a = new \Jose\Util\ger('10'); |
414
|
|
|
* $b = new \Jose\Util\ger('20'); |
415
|
|
|
* $c = new \Jose\Util\ger('30'); |
416
|
|
|
* |
417
|
|
|
* $c = $a->modPow($b, $c); |
418
|
|
|
* |
419
|
|
|
* echo $c->toString(); // outputs 10 |
420
|
|
|
* ?> |
421
|
|
|
* </code> |
422
|
|
|
* |
423
|
|
|
* @param \Jose\Util\Integer $e |
424
|
|
|
* @param \Jose\Util\Integer $n |
425
|
|
|
* |
426
|
|
|
* @return \Jose\Util\BigInteger |
427
|
|
|
* |
428
|
|
|
* and although the approach involving repeated squaring does vastly better, it, too, is impractical |
429
|
|
|
* for our purposes. The reason being that division - by far the most complicated and time-consuming |
430
|
|
|
* of the basic operations (eg. +,-,*,/) - occurs multiple times within it. |
431
|
|
|
* |
432
|
|
|
* Modular reductions resolve this issue. Although an individual modular reduction takes more time |
433
|
|
|
* then an individual division, when performed in succession (with the same modulo), they're a lot faster. |
434
|
|
|
* |
435
|
|
|
* The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, |
436
|
|
|
* although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the |
437
|
|
|
* base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because |
438
|
|
|
* the product of two odd numbers is odd), but what about when RSA isn't used? |
439
|
|
|
* |
440
|
|
|
* In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a |
441
|
|
|
* Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the |
442
|
|
|
* modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, |
443
|
|
|
* uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and |
444
|
|
|
* the other, a power of two - and recombine them, later. This is the method that this modPow function uses. |
445
|
|
|
* {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. |
446
|
|
|
*/ |
447
|
|
|
public function modPow(BigInteger $e, BigInteger $n) |
448
|
|
|
{ |
449
|
|
|
$n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); |
|
|
|
|
450
|
|
|
|
451
|
|
|
if ($e->compare(new static()) < 0) { |
452
|
|
|
$e = $e->abs(); |
453
|
|
|
|
454
|
|
|
$temp = $this->modInverse($n); |
|
|
|
|
455
|
|
|
if ($temp === false) { |
456
|
|
|
return false; |
|
|
|
|
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
return $this->_normalize($temp->modPow($e, $n)); |
|
|
|
|
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
$temp = new static(); |
463
|
|
|
$temp->value = gmp_powm($this->value, $e->value, $n->value); |
464
|
|
|
|
465
|
|
|
return $this->_normalize($temp); |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
/** |
469
|
|
|
* Calculates modular inverses. |
470
|
|
|
* |
471
|
|
|
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. |
472
|
|
|
* |
473
|
|
|
* Here's an example: |
474
|
|
|
* <code> |
475
|
|
|
* <?php |
476
|
|
|
* $a = new \Jose\Util\teger(30); |
477
|
|
|
* $b = new \Jose\Util\teger(17); |
478
|
|
|
* |
479
|
|
|
* $c = $a->modInverse($b); |
480
|
|
|
* echo $c->toString(); // outputs 4 |
481
|
|
|
* |
482
|
|
|
* echo "\r\n"; |
483
|
|
|
* |
484
|
|
|
* $d = $a->multiply($c); |
485
|
|
|
* list(, $d) = $d->divide($b); |
486
|
|
|
* echo $d; // outputs 1 (as per the definition of modular inverse) |
487
|
|
|
* ?> |
488
|
|
|
* </code> |
489
|
|
|
* |
490
|
|
|
* @param \Jose\Util\Integer $n |
491
|
|
|
* |
492
|
|
|
* @return \Jose\Util\eger|false |
493
|
|
|
* |
494
|
|
|
*/ |
495
|
|
|
public function modInverse(BigInteger $n) |
496
|
|
|
{ |
497
|
|
|
$temp = new static(); |
498
|
|
|
$temp->value = gmp_invert($this->value, $n->value); |
499
|
|
|
|
500
|
|
|
return ($temp->value === false) ? false : $this->_normalize($temp); |
501
|
|
|
} |
502
|
|
|
|
503
|
|
|
/** |
504
|
|
|
* Absolute value. |
505
|
|
|
* |
506
|
|
|
* @return \Jose\Util\BigInteger |
507
|
|
|
*/ |
508
|
|
|
public function abs() |
509
|
|
|
{ |
510
|
|
|
$temp = new static(); |
511
|
|
|
|
512
|
|
|
$temp->value = gmp_abs($this->value); |
513
|
|
|
|
514
|
|
|
return $temp; |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* Compares two numbers. |
519
|
|
|
* |
520
|
|
|
* Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is |
521
|
|
|
* demonstrated thusly: |
522
|
|
|
* |
523
|
|
|
* $x > $y: $x->compare($y) > 0 |
524
|
|
|
* $x < $y: $x->compare($y) < 0 |
525
|
|
|
* $x == $y: $x->compare($y) == 0 |
526
|
|
|
* |
527
|
|
|
* Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). |
528
|
|
|
* |
529
|
|
|
* @param \Jose\Util\Integer $y |
530
|
|
|
* |
531
|
|
|
* @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. |
532
|
|
|
* |
533
|
|
|
*/ |
534
|
|
|
public function compare(BigInteger $y) |
535
|
|
|
{ |
536
|
|
|
return gmp_cmp($this->value, $y->value); |
537
|
|
|
} |
538
|
|
|
|
539
|
|
|
/** |
540
|
|
|
* Logical Left Shift. |
541
|
|
|
* |
542
|
|
|
* Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. |
543
|
|
|
* |
544
|
|
|
* @param int $shift |
545
|
|
|
* |
546
|
|
|
* @return \Jose\Util\BigInteger |
547
|
|
|
* |
548
|
|
|
*/ |
549
|
|
|
public function bitwise_leftShift($shift) |
550
|
|
|
{ |
551
|
|
|
$temp = new static(); |
552
|
|
|
|
553
|
|
|
static $two; |
554
|
|
|
|
555
|
|
|
if (!isset($two)) { |
556
|
|
|
$two = gmp_init('2'); |
557
|
|
|
} |
558
|
|
|
|
559
|
|
|
$temp->value = gmp_mul($this->value, gmp_pow($two, $shift)); |
560
|
|
|
|
561
|
|
|
return $this->_normalize($temp); |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* Generates a random BigInteger. |
566
|
|
|
* |
567
|
|
|
* Byte length is equal to $length. Uses \phpseclib\Crypt\Random if it's loaded and mt_rand if it's not. |
568
|
|
|
* |
569
|
|
|
* @param int $size |
570
|
|
|
* |
571
|
|
|
* @return \Jose\Util\BigInteger |
572
|
|
|
*/ |
573
|
|
|
private static function _random_number_helper($size) |
574
|
|
|
{ |
575
|
|
|
return new static(random_bytes($size), 256); |
576
|
|
|
} |
577
|
|
|
|
578
|
|
|
/** |
579
|
|
|
* Generate a random number. |
580
|
|
|
* |
581
|
|
|
* Returns a random number between $min and $max where $min and $max |
582
|
|
|
* can be defined using one of the two methods: |
583
|
|
|
* |
584
|
|
|
* BigInteger::random($min, $max) |
585
|
|
|
* BigInteger::random($max, $min) |
586
|
|
|
* |
587
|
|
|
* @param \Jose\Util\BigInteger $min |
588
|
|
|
* @param \Jose\Util\BigInteger $max |
589
|
|
|
* |
590
|
|
|
* @return \Jose\Util\BigInteger |
591
|
|
|
*/ |
592
|
|
|
public static function random(BigInteger $min, BigInteger $max) |
593
|
|
|
{ |
594
|
|
|
$compare = $max->compare($min); |
595
|
|
|
|
596
|
|
|
if (!$compare) { |
597
|
|
|
return $this->_normalize($min); |
|
|
|
|
598
|
|
|
} elseif ($compare < 0) { |
599
|
|
|
// if $min is bigger then $max, swap $min and $max |
600
|
|
|
$temp = $max; |
601
|
|
|
$max = $min; |
602
|
|
|
$min = $temp; |
603
|
|
|
} |
604
|
|
|
|
605
|
|
|
static $one; |
606
|
|
|
if (!isset($one)) { |
607
|
|
|
$one = new static(1); |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
$max = $max->subtract($min->subtract($one)); |
611
|
|
|
$size = strlen(ltrim($max->toBytes(), chr(0))); |
612
|
|
|
|
613
|
|
|
/* |
614
|
|
|
doing $random % $max doesn't work because some numbers will be more likely to occur than others. |
615
|
|
|
eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145 |
616
|
|
|
would produce 5 whereas the only value of random that could produce 139 would be 139. ie. |
617
|
|
|
not all numbers would be equally likely. some would be more likely than others. |
618
|
|
|
|
619
|
|
|
creating a whole new random number until you find one that is within the range doesn't work |
620
|
|
|
because, for sufficiently small ranges, the likelihood that you'd get a number within that range |
621
|
|
|
would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability |
622
|
|
|
would be pretty high that $random would be greater than $max. |
623
|
|
|
|
624
|
|
|
phpseclib works around this using the technique described here: |
625
|
|
|
|
626
|
|
|
http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string |
627
|
|
|
*/ |
628
|
|
|
$random_max = new static(chr(1).str_repeat("\0", $size), 256); |
629
|
|
|
$random = self::_random_number_helper($size); |
630
|
|
|
|
631
|
|
|
list($max_multiple) = $random_max->divide($max); |
632
|
|
|
$max_multiple = $max_multiple->multiply($max); |
633
|
|
|
|
634
|
|
|
while ($random->compare($max_multiple) >= 0) { |
635
|
|
|
$random = $random->subtract($max_multiple); |
636
|
|
|
$random_max = $random_max->subtract($max_multiple); |
637
|
|
|
$random = $random->bitwise_leftShift(8); |
638
|
|
|
$random = $random->add(self::_random_number_helper(1)); |
639
|
|
|
$random_max = $random_max->bitwise_leftShift(8); |
640
|
|
|
list($max_multiple) = $random_max->divide($max); |
641
|
|
|
$max_multiple = $max_multiple->multiply($max); |
642
|
|
|
} |
643
|
|
|
list(, $random) = $random->divide($max); |
644
|
|
|
|
645
|
|
|
return $random->add($min); |
646
|
|
|
} |
647
|
|
|
|
648
|
|
|
/** |
649
|
|
|
* Normalize. |
650
|
|
|
* |
651
|
|
|
* Removes leading zeros and truncates (if necessary) to maintain the appropriate precision |
652
|
|
|
* |
653
|
|
|
* @param \Jose\Util\BigInteger |
654
|
|
|
* |
655
|
|
|
* @return \Jose\Util\BigInteger |
656
|
|
|
*/ |
657
|
|
|
private function _normalize($result) |
658
|
|
|
{ |
659
|
|
|
$result->precision = $this->precision; |
660
|
|
|
$result->bitmask = $this->bitmask; |
661
|
|
|
|
662
|
|
|
if ($this->bitmask !== false) { |
663
|
|
|
$result->value = gmp_and($result->value, $result->bitmask->value); |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
return $result; |
667
|
|
|
} |
668
|
|
|
} |
669
|
|
|
|
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.