254 if (!defined(
'MATH_BIGINTEGER_MODE')) {
256 case extension_loaded(
'gmp'):
257 define(
'MATH_BIGINTEGER_MODE', self::MODE_GMP);
259 case extension_loaded(
'bcmath'):
260 define(
'MATH_BIGINTEGER_MODE', self::MODE_BCMATH);
263 define(
'MATH_BIGINTEGER_MODE', self::MODE_INTERNAL);
267 if (extension_loaded(
'openssl') && !defined(
'MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined(
'MATH_BIGINTEGER_OPENSSL_ENABLED')) {
271 $content = ob_get_contents();
274 preg_match_all(
'#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
277 if (!empty($matches[1])) {
278 for (
$i = 0;
$i < count($matches[1]);
$i++) {
279 $fullVersion = trim(str_replace(
'=>',
'', strip_tags($matches[2][
$i])));
282 if (!preg_match(
'/(\d+\.\d+\.\d+)/i', $fullVersion,
$m)) {
283 $versions[$matches[1][
$i]] = $fullVersion;
285 $versions[$matches[1][
$i]] =
$m[0];
292 case !isset($versions[
'Header']):
293 case !isset($versions[
'Library']):
294 case $versions[
'Header'] == $versions[
'Library']:
295 define(
'MATH_BIGINTEGER_OPENSSL_ENABLED',
true);
298 define(
'MATH_BIGINTEGER_OPENSSL_DISABLE',
true);
302 if (!defined(
'PHP_INT_SIZE')) {
303 define(
'PHP_INT_SIZE', 4);
306 if (empty(
self::$base) && MATH_BIGINTEGER_MODE == self::MODE_INTERNAL) {
307 switch (PHP_INT_SIZE) {
310 self::$baseFull = 0x80000000;
311 self::$maxDigit = 0x7FFFFFFF;
312 self::$msb = 0x40000000;
313 self::$max10 = 1000000000;
315 self::$maxDigit2 = pow(2, 62);
320 self::$baseFull = 0x4000000;
321 self::$maxDigit = 0x3FFFFFF;
322 self::$msb = 0x2000000;
323 self::$max10 = 10000000;
325 self::$maxDigit2 = pow(2, 52);
329 switch (MATH_BIGINTEGER_MODE) {
332 case is_resource(
$x) && get_resource_type(
$x) ==
'GMP integer':
334 case $x instanceof \GMP:
338 $this->value = gmp_init(0);
340 case self::MODE_BCMATH:
344 $this->value = array();
355 if (ord(
$x[0]) & 0x80) {
357 $this->is_negative =
true;
360 switch (MATH_BIGINTEGER_MODE) {
362 $sign = $this->is_negative ?
'-' :
'';
363 $this->value = gmp_init($sign .
'0x' . bin2hex(
$x));
365 case self::MODE_BCMATH:
367 $len = (strlen(
$x) + 3) & 0xFFFFFFFC;
369 $x = str_pad(
$x, $len, chr(0), STR_PAD_LEFT);
371 for (
$i = 0;
$i < $len;
$i+= 4) {
372 $this->value = bcmul($this->value,
'4294967296', 0);
373 $this->value = bcadd($this->value, 0x1000000 * ord(
$x[
$i]) + ((ord(
$x[$i + 1]) << 16) | (ord(
$x[$i + 2]) << 8) | ord(
$x[$i + 3])), 0);
376 if ($this->is_negative) {
388 if ($this->is_negative) {
389 if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
390 $this->is_negative =
false;
392 $temp = $this->
add(
new static(
'-1'));
393 $this->value = $temp->value;
398 if (
$base > 0 &&
$x[0] ==
'-') {
399 $this->is_negative =
true;
403 $x = preg_replace(
'#^(?:0x)?([A-Fa-f0-9]*).*#',
'$1',
$x);
405 $is_negative =
false;
406 if (
$base < 0 && hexdec(
$x[0]) >= 8) {
407 $this->is_negative = $is_negative =
true;
408 $x = bin2hex(~pack(
'H*',
$x));
411 switch (MATH_BIGINTEGER_MODE) {
413 $temp = $this->is_negative ?
'-0x' .
$x :
'0x' .
$x;
414 $this->value = gmp_init($temp);
415 $this->is_negative =
false;
417 case self::MODE_BCMATH:
418 $x = (strlen(
$x) & 1) ?
'0' .
$x :
$x;
419 $temp =
new static(pack(
'H*',
$x), 256);
420 $this->value = $this->is_negative ?
'-' . $temp->value : $temp->value;
421 $this->is_negative =
false;
424 $x = (strlen(
$x) & 1) ?
'0' .
$x :
$x;
425 $temp =
new static(pack(
'H*',
$x), 256);
426 $this->value = $temp->value;
430 $temp = $this->
add(
new static(
'-1'));
431 $this->value = $temp->value;
439 $x = preg_replace(
'#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#',
'',
$x);
441 switch (MATH_BIGINTEGER_MODE) {
443 $this->value = gmp_init(
$x);
445 case self::MODE_BCMATH:
448 $this->value =
$x ===
'-' ?
'0' : (string)
$x;
451 $temp =
new static();
453 $multiplier =
new static();
454 $multiplier->value = array(self::$max10);
457 $this->is_negative =
true;
461 $x = str_pad(
$x, strlen(
$x) + ((self::$max10Len - 1) * strlen(
$x)) % self::$max10Len, 0, STR_PAD_LEFT);
463 $temp = $temp->multiply($multiplier);
464 $temp = $temp->add(
new static($this->
_int2bytes(substr(
$x, 0, self::$max10Len)), 256));
465 $x = substr(
$x, self::$max10Len);
468 $this->value = $temp->value;
473 if (
$base > 0 &&
$x[0] ==
'-') {
474 $this->is_negative =
true;
478 $x = preg_replace(
'#^([01]*).*#',
'$1',
$x);
479 $x = str_pad(
$x, strlen(
$x) + (3 * strlen(
$x)) % 4, 0, STR_PAD_LEFT);
483 $part = substr(
$x, 0, 4);
484 $str.= dechex(bindec($part));
488 if ($this->is_negative) {
492 $temp =
new static($str, 8 *
$base);
493 $this->value = $temp->value;
494 $this->is_negative = $temp->is_negative;
524 if ($twos_compliment) {
525 $comparison = $this->
compare(
new static());
526 if ($comparison == 0) {
527 return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) :
'';
530 $temp = $comparison < 0 ? $this->
add(
new static(1)) : $this->
copy();
531 $bytes = $temp->toBytes();
537 if (ord($bytes[0]) & 0x80) {
538 $bytes = chr(0) . $bytes;
541 return $comparison < 0 ? ~$bytes : $bytes;
544 switch (MATH_BIGINTEGER_MODE) {
546 if (gmp_cmp($this->value, gmp_init(0)) == 0) {
547 return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) :
'';
550 $temp = gmp_strval(gmp_abs($this->value), 16);
551 $temp = (strlen($temp) & 1) ?
'0' . $temp : $temp;
552 $temp = pack(
'H*', $temp);
554 return $this->precision > 0 ?
555 substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
556 ltrim($temp, chr(0));
557 case self::MODE_BCMATH:
558 if ($this->value ===
'0') {
559 return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) :
'';
569 while (bccomp(
$current,
'0', 0) > 0) {
570 $temp = bcmod(
$current,
'16777216');
571 $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) .
$value;
575 return $this->precision > 0 ?
576 substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
577 ltrim($value, chr(0));
580 if (!count($this->value)) {
581 return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) :
'';
585 $temp = $this->
copy();
587 for (
$i = count($temp->value) - 2;
$i >= 0; --
$i) {
592 return $this->precision > 0 ?
593 str_pad(substr(
$result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
617 function toHex($twos_compliment =
false)
619 return bin2hex($this->
toBytes($twos_compliment));
642 function toBits($twos_compliment =
false)
644 $hex = $this->
toHex($twos_compliment);
647 $bits = str_pad(decbin(hexdec(substr($hex,
$i, 8))), 32,
'0', STR_PAD_LEFT) . $bits;
650 $bits = str_pad(decbin(hexdec(substr($hex, 0,
$start))), 8,
'0', STR_PAD_LEFT) . $bits;
652 $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits,
'0');
654 if ($twos_compliment && $this->
compare(
new static()) > 0 && $this->precision <= 0) {
679 switch (MATH_BIGINTEGER_MODE) {
681 return gmp_strval($this->value);
682 case self::MODE_BCMATH:
683 if ($this->value ===
'0') {
687 return ltrim($this->value,
'0');
690 if (!count($this->value)) {
694 $temp = $this->
copy();
695 $temp->is_negative =
false;
697 $divisor =
new static();
698 $divisor->value = array(self::$max10);
700 while (count($temp->value)) {
701 list($temp, $mod) = $temp->divide($divisor);
702 $result = str_pad(isset($mod->value[0]) ? $mod->value[0] :
'', self::$max10Len,
'0', STR_PAD_LEFT) .
$result;
709 if ($this->is_negative) {
730 $temp =
new static();
766 return $this->
copy();
779 $this->hex = $this->
toHex(
true);
780 $vars = array(
'hex');
781 if ($this->precision > 0) {
782 $vars[] =
'precision';
798 $this->value = $temp->value;
799 $this->is_negative = $temp->is_negative;
800 if ($this->precision > 0) {
816 switch (MATH_BIGINTEGER_MODE) {
820 case self::MODE_BCMATH:
823 case self::MODE_INTERNAL:
825 $opts[] = PHP_INT_SIZE == 8 ?
'64-bit' :
'32-bit';
827 if (MATH_BIGINTEGER_MODE != self::MODE_GMP && defined(
'MATH_BIGINTEGER_OPENSSL_ENABLED')) {
831 $engine.=
' (' . implode($opts,
', ') .
')';
834 'value' =>
'0x' . $this->
toHex(
true),
861 switch (MATH_BIGINTEGER_MODE) {
863 $temp =
new static();
864 $temp->value = gmp_add($this->value,
$y->value);
867 case self::MODE_BCMATH:
868 $temp =
new static();
869 $temp->value = bcadd($this->value,
$y->value, 0);
874 $temp = $this->
_add($this->value, $this->is_negative,
$y->value,
$y->is_negative);
877 $result->value = $temp[self::VALUE];
878 $result->is_negative = $temp[self::SIGN];
893 function _add($x_value, $x_negative, $y_value, $y_negative)
895 $x_size = count($x_value);
896 $y_size = count($y_value);
900 self::VALUE => $y_value,
901 self::SIGN => $y_negative
903 } elseif ($y_size == 0) {
905 self::VALUE => $x_value,
906 self::SIGN => $x_negative
911 if ($x_negative != $y_negative) {
912 if ($x_value == $y_value) {
914 self::VALUE => array(),
919 $temp = $this->
_subtract($x_value,
false, $y_value,
false);
920 $temp[self::SIGN] = $this->
_compare($x_value,
false, $y_value,
false) > 0 ?
921 $x_negative : $y_negative;
926 if ($x_size < $y_size) {
934 $value[count($value)] = 0;
937 for (
$i = 0, $j = 1; $j <
$size;
$i+=2, $j+=2) {
938 $sum = $x_value[$j] * self::$baseFull + $x_value[
$i] + $y_value[$j] * self::$baseFull + $y_value[
$i] + $carry;
939 $carry = $sum >= self::$maxDigit2;
940 $sum = $carry ? $sum - self::$maxDigit2 : $sum;
942 $temp =
self::$base === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
944 $value[
$i] = (int) ($sum - self::$baseFull * $temp);
949 $sum = $x_value[
$i] + $y_value[
$i] + $carry;
950 $carry = $sum >= self::$baseFull;
951 $value[
$i] = $carry ? $sum - self::$baseFull : $sum;
956 for (; $value[
$i] == self::$maxDigit; ++
$i) {
963 self::VALUE => $this->
_trim($value),
964 self::SIGN => $x_negative
990 switch (MATH_BIGINTEGER_MODE) {
992 $temp =
new static();
993 $temp->value = gmp_sub($this->value,
$y->value);
996 case self::MODE_BCMATH:
997 $temp =
new static();
998 $temp->value = bcsub($this->value,
$y->value, 0);
1003 $temp = $this->
_subtract($this->value, $this->is_negative,
$y->value,
$y->is_negative);
1006 $result->value = $temp[self::VALUE];
1007 $result->is_negative = $temp[self::SIGN];
1022 function _subtract($x_value, $x_negative, $y_value, $y_negative)
1024 $x_size = count($x_value);
1025 $y_size = count($y_value);
1029 self::VALUE => $y_value,
1030 self::SIGN => !$y_negative
1032 } elseif ($y_size == 0) {
1034 self::VALUE => $x_value,
1035 self::SIGN => $x_negative
1040 if ($x_negative != $y_negative) {
1041 $temp = $this->
_add($x_value,
false, $y_value,
false);
1042 $temp[self::SIGN] = $x_negative;
1047 $diff = $this->
_compare($x_value, $x_negative, $y_value, $y_negative);
1051 self::VALUE => array(),
1057 if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) {
1059 $x_value = $y_value;
1062 $x_negative = !$x_negative;
1064 $x_size = count($x_value);
1065 $y_size = count($y_value);
1071 for (
$i = 0, $j = 1; $j < $y_size;
$i+=2, $j+=2) {
1072 $sum = $x_value[$j] * self::$baseFull + $x_value[
$i] - $y_value[$j] * self::$baseFull - $y_value[
$i] - $carry;
1074 $sum = $carry ? $sum + self::$maxDigit2 : $sum;
1076 $temp =
self::$base === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
1078 $x_value[
$i] = (int) ($sum - self::$baseFull * $temp);
1079 $x_value[$j] = $temp;
1082 if ($j == $y_size) {
1083 $sum = $x_value[
$i] - $y_value[
$i] - $carry;
1085 $x_value[
$i] = $carry ? $sum + self::$baseFull : $sum;
1090 for (; !$x_value[
$i]; ++
$i) {
1091 $x_value[
$i] = self::$maxDigit;
1097 self::VALUE => $this->
_trim($x_value),
1098 self::SIGN => $x_negative
1123 switch (MATH_BIGINTEGER_MODE) {
1124 case self::MODE_GMP:
1125 $temp =
new static();
1126 $temp->value = gmp_mul($this->value,
$x->value);
1129 case self::MODE_BCMATH:
1130 $temp =
new static();
1131 $temp->value = bcmul($this->value,
$x->value, 0);
1136 $temp = $this->
_multiply($this->value, $this->is_negative,
$x->value,
$x->is_negative);
1138 $product =
new static();
1139 $product->value = $temp[self::VALUE];
1140 $product->is_negative = $temp[self::SIGN];
1155 function _multiply($x_value, $x_negative, $y_value, $y_negative)
1164 $x_length = count($x_value);
1165 $y_length = count($y_value);
1167 if (!$x_length || !$y_length) {
1169 self::VALUE => array(),
1175 self::VALUE => min($x_length, $y_length) < 2 * self::KARATSUBA_CUTOFF ?
1178 self::SIGN => $x_negative != $y_negative
1194 $x_length = count($x_value);
1195 $y_length = count($y_value);
1197 if (!$x_length || !$y_length) {
1201 if ($x_length < $y_length) {
1203 $x_value = $y_value;
1206 $x_length = count($x_value);
1207 $y_length = count($y_value);
1210 $product_value = $this->
_array_repeat(0, $x_length + $y_length);
1220 for ($j = 0; $j < $x_length; ++$j) {
1221 $temp = $x_value[$j] * $y_value[0] + $carry;
1222 $carry =
self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1223 $product_value[$j] = (int) ($temp - self::$baseFull * $carry);
1226 $product_value[$j] = $carry;
1230 for (
$i = 1;
$i < $y_length; ++
$i) {
1233 for ($j = 0, $k =
$i; $j < $x_length; ++$j, ++$k) {
1234 $temp = $product_value[$k] + $x_value[$j] * $y_value[
$i] + $carry;
1235 $carry =
self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1236 $product_value[$k] = (int) ($temp - self::$baseFull * $carry);
1239 $product_value[$k] = $carry;
1242 return $product_value;
1258 $m = min(count($x_value) >> 1, count($y_value) >> 1);
1260 if (
$m < self::KARATSUBA_CUTOFF) {
1264 $x1 = array_slice($x_value,
$m);
1265 $x0 = array_slice($x_value, 0,
$m);
1266 $y1 = array_slice($y_value,
$m);
1267 $y0 = array_slice($y_value, 0,
$m);
1272 $z1 = $this->
_add($x1,
false, $x0,
false);
1273 $temp = $this->
_add($y1,
false, $y0,
false);
1274 $z1 = $this->
_karatsuba($z1[self::VALUE], $temp[self::VALUE]);
1275 $temp = $this->
_add($z2,
false, $z0,
false);
1276 $z1 = $this->
_subtract($z1,
false, $temp[self::VALUE],
false);
1278 $z2 = array_merge(array_fill(0, 2 *
$m, 0), $z2);
1279 $z1[self::VALUE] = array_merge(array_fill(0,
$m, 0), $z1[self::VALUE]);
1281 $xy = $this->
_add($z2,
false, $z1[self::VALUE], $z1[self::SIGN]);
1282 $xy = $this->
_add($xy[self::VALUE], $xy[self::SIGN], $z0,
false);
1284 return $xy[self::VALUE];
1296 return count(
$x) < 2 * self::KARATSUBA_CUTOFF ?
1314 if (empty($value)) {
1319 for (
$i = 0, $max_index = count($value) - 1;
$i <= $max_index; ++
$i) {
1322 $temp = $square_value[$i2] + $value[
$i] * $value[
$i];
1323 $carry =
self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1324 $square_value[$i2] = (int) ($temp - self::$baseFull * $carry);
1327 for ($j =
$i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1328 $temp = $square_value[$k] + 2 * $value[$j] * $value[
$i] + $carry;
1329 $carry =
self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1330 $square_value[$k] = (int) ($temp - self::$baseFull * $carry);
1335 $square_value[
$i + $max_index + 1] = $carry;
1338 return $square_value;
1353 $m = count($value) >> 1;
1355 if (
$m < self::KARATSUBA_CUTOFF) {
1359 $x1 = array_slice($value,
$m);
1360 $x0 = array_slice($value, 0,
$m);
1365 $z1 = $this->
_add($x1,
false, $x0,
false);
1367 $temp = $this->
_add($z2,
false, $z0,
false);
1368 $z1 = $this->
_subtract($z1,
false, $temp[self::VALUE],
false);
1370 $z2 = array_merge(array_fill(0, 2 *
$m, 0), $z2);
1371 $z1[self::VALUE] = array_merge(array_fill(0,
$m, 0), $z1[self::VALUE]);
1373 $xx = $this->
_add($z2,
false, $z1[self::VALUE], $z1[self::SIGN]);
1374 $xx = $this->
_add($xx[self::VALUE], $xx[self::SIGN], $z0,
false);
1376 return $xx[self::VALUE];
1408 switch (MATH_BIGINTEGER_MODE) {
1409 case self::MODE_GMP:
1410 $quotient =
new static();
1411 $remainder =
new static();
1413 list($quotient->value, $remainder->value) = gmp_div_qr($this->value,
$y->value);
1415 if (gmp_sign($remainder->value) < 0) {
1416 $remainder->value = gmp_add($remainder->value, gmp_abs(
$y->value));
1420 case self::MODE_BCMATH:
1421 $quotient =
new static();
1422 $remainder =
new static();
1424 $quotient->value = bcdiv($this->value,
$y->value, 0);
1425 $remainder->value = bcmod($this->value,
$y->value);
1427 if ($remainder->value[0] ==
'-') {
1428 $remainder->value = bcadd($remainder->value,
$y->value[0] ==
'-' ? substr(
$y->value, 1) :
$y->value, 0);
1434 if (count(
$y->value) == 1) {
1436 $quotient =
new static();
1437 $remainder =
new static();
1438 $quotient->value = $q;
1439 $remainder->value = array(
$r);
1440 $quotient->is_negative = $this->is_negative !=
$y->is_negative;
1445 if (!isset($zero)) {
1446 $zero =
new static();
1452 $x_sign =
$x->is_negative;
1453 $y_sign =
$y->is_negative;
1455 $x->is_negative =
$y->is_negative =
false;
1457 $diff =
$x->compare(
$y);
1460 $temp =
new static();
1461 $temp->value = array(1);
1462 $temp->is_negative = $x_sign != $y_sign;
1475 $msb =
$y->value[count(
$y->value) - 1];
1476 for ($shift = 0; !(
$msb & self::$msb); ++$shift) {
1479 $x->_lshift($shift);
1480 $y->_lshift($shift);
1481 $y_value = &
$y->value;
1483 $x_max = count(
$x->value) - 1;
1484 $y_max = count(
$y->value) - 1;
1486 $quotient =
new static();
1487 $quotient_value = &$quotient->value;
1488 $quotient_value = $this->
_array_repeat(0, $x_max - $y_max + 1);
1490 static $temp, $lhs, $rhs;
1491 if (!isset($temp)) {
1492 $temp =
new static();
1493 $lhs =
new static();
1494 $rhs =
new static();
1496 $temp_value = &$temp->value;
1497 $rhs_value = &$rhs->value;
1500 $temp_value = array_merge($this->
_array_repeat(0, $x_max - $y_max), $y_value);
1502 while (
$x->compare($temp) >= 0) {
1504 ++$quotient_value[$x_max - $y_max];
1505 $x =
$x->subtract($temp);
1506 $x_max = count(
$x->value) - 1;
1509 for (
$i = $x_max;
$i >= $y_max + 1; --
$i) {
1510 $x_value = &
$x->value;
1512 isset($x_value[
$i]) ? $x_value[$i] : 0,
1513 isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
1514 isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
1518 ($y_max > 0) ? $y_value[$y_max - 1] : 0
1521 $q_index = $i - $y_max - 1;
1522 if ($x_window[0] == $y_window[0]) {
1523 $quotient_value[$q_index] = self::$maxDigit;
1526 $x_window[0] * self::$baseFull + $x_window[1],
1531 $temp_value = array($y_window[1], $y_window[0]);
1533 $lhs->value = array($quotient_value[$q_index]);
1534 $lhs = $lhs->multiply($temp);
1536 $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
1538 while ($lhs->compare($rhs) > 0) {
1539 --$quotient_value[$q_index];
1541 $lhs->value = array($quotient_value[$q_index]);
1542 $lhs = $lhs->multiply($temp);
1546 $temp_value = array($quotient_value[$q_index]);
1547 $temp = $temp->multiply(
$y);
1548 $temp_value = &$temp->value;
1549 $temp_value = array_merge($adjust, $temp_value);
1551 $x =
$x->subtract($temp);
1553 if (
$x->compare($zero) < 0) {
1554 $temp_value = array_merge($adjust, $y_value);
1555 $x =
$x->add($temp);
1557 --$quotient_value[$q_index];
1560 $x_max = count($x_value) - 1;
1564 $x->_rshift($shift);
1566 $quotient->is_negative = $x_sign != $y_sign;
1570 $y->_rshift($shift);
1592 for (
$i = count($dividend) - 1;
$i >= 0; --
$i) {
1593 $temp = self::$baseFull * $carry + $dividend[
$i];
1595 $carry = (int) ($temp - $divisor *
$result[
$i]);
1598 return array(
$result, $carry);
1643 $n = $this->bitmask !==
false && $this->bitmask->compare(
$n) < 0 ? $this->bitmask :
$n->abs();
1645 if ($e->compare(
new static()) < 0) {
1649 if ($temp ===
false) {
1656 if (MATH_BIGINTEGER_MODE == self::MODE_GMP) {
1657 $temp =
new static();
1658 $temp->value = gmp_powm($this->value, $e->value,
$n->value);
1665 return $temp->modPow($e,
$n);
1668 if (defined(
'MATH_BIGINTEGER_OPENSSL_ENABLED')) {
1669 $components = array(
1670 'modulus' =>
$n->toBytes(
true),
1671 'publicExponent' => $e->toBytes(
true)
1674 $components = array(
1675 'modulus' => pack(
'Ca*a*', 2, $this->
_encodeASN1Length(strlen($components[
'modulus'])), $components[
'modulus']),
1676 'publicExponent' => pack(
'Ca*a*', 2, $this->
_encodeASN1Length(strlen($components[
'publicExponent'])), $components[
'publicExponent'])
1679 $RSAPublicKey = pack(
1682 $this->
_encodeASN1Length(strlen($components[
'modulus']) + strlen($components[
'publicExponent'])),
1683 $components[
'modulus'],
1684 $components[
'publicExponent']
1687 $rsaOID = pack(
'H*',
'300d06092a864886f70d0101010500');
1688 $RSAPublicKey = chr(0) . $RSAPublicKey;
1689 $RSAPublicKey = chr(3) . $this->
_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
1691 $encapsulated = pack(
1695 $rsaOID . $RSAPublicKey
1698 $RSAPublicKey =
"-----BEGIN PUBLIC KEY-----\r\n" .
1699 chunk_split(base64_encode($encapsulated)) .
1700 '-----END PUBLIC KEY-----';
1702 $plaintext = str_pad($this->
toBytes(), strlen(
$n->toBytes(
true)) - 1,
"\0", STR_PAD_LEFT);
1704 if (openssl_public_encrypt($plaintext,
$result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
1705 return new static(
$result, 256);
1709 if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
1710 $temp =
new static();
1711 $temp->value = bcpowmod($this->value, $e->value,
$n->value, 0);
1716 if (empty($e->value)) {
1717 $temp =
new static();
1718 $temp->value = array(1);
1722 if ($e->value == array(1)) {
1727 if ($e->value == array(2)) {
1728 $temp =
new static();
1729 $temp->value = $this->
_square($this->value);
1730 list(, $temp) = $temp->divide(
$n);
1742 if (
$n->value[0] & 1) {
1748 for (
$i = 0;
$i < count(
$n->value); ++
$i) {
1749 if (
$n->value[
$i]) {
1750 $temp = decbin(
$n->value[
$i]);
1751 $j = strlen($temp) - strrpos($temp,
'1') - 1;
1760 $mod2 =
new static();
1761 $mod2->value = array(1);
1764 $part1 = ($mod1->value != array(1)) ? $this->
_slidingWindow($e, $mod1, self::MONTGOMERY) :
new static();
1767 $y1 = $mod2->modInverse($mod1);
1768 $y2 = $mod1->modInverse($mod2);
1770 $result = $part1->multiply($mod2);
1773 $temp = $part2->multiply($mod1);
1774 $temp = $temp->multiply($y2);
1813 static $window_ranges = array(7, 25, 81, 241, 673, 1793);
1816 $e_value = $e->value;
1817 $e_length = count($e_value) - 1;
1818 $e_bits = decbin($e_value[$e_length]);
1819 for (
$i = $e_length - 1;
$i >= 0; --
$i) {
1820 $e_bits.= str_pad(decbin($e_value[
$i]),
self::$base,
'0', STR_PAD_LEFT);
1823 $e_length = strlen($e_bits);
1827 for (
$i = 0, $window_size = 1; $e_length > $window_ranges[
$i] &&
$i < count($window_ranges); ++$window_size, ++
$i) {
1830 $n_value =
$n->value;
1834 $powers[1] = $this->
_prepareReduce($this->value, $n_value, $mode);
1835 $powers[2] = $this->
_squareReduce($powers[1], $n_value, $mode);
1839 $temp = 1 << ($window_size - 1);
1840 for (
$i = 1;
$i < $temp; ++
$i) {
1842 $powers[$i2 + 1] = $this->
_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
1848 for (
$i = 0;
$i < $e_length;) {
1853 for ($j = $window_size - 1; $j > 0; --$j) {
1854 if (!empty($e_bits[$i + $j])) {
1860 for ($k = 0; $k <= $j; ++$k) {
1870 $temp =
new static();
1891 case self::MONTGOMERY:
1895 case self::POWEROF2:
1896 $lhs =
new static();
1898 $rhs =
new static();
1900 return $x->_mod2(
$n);
1902 $lhs =
new static();
1904 $rhs =
new static();
1906 list(, $temp) = $lhs->divide($rhs);
1907 return $temp->value;
1927 if ($mode == self::MONTGOMERY) {
1946 if ($mode == self::MONTGOMERY) {
1950 return $this->
_reduce($temp[self::VALUE],
$n, $mode);
1965 if ($mode == self::MONTGOMERY) {
1984 $temp =
new static();
1985 $temp->value = array(1);
2015 static $cache = array(
2016 self::VARIABLE => array(),
2017 self::DATA => array()
2020 $m_length = count(
$m);
2023 if (count(
$n) > 2 * $m_length) {
2024 $lhs =
new static();
2025 $rhs =
new static();
2028 list(, $temp) = $lhs->divide($rhs);
2029 return $temp->value;
2033 if ($m_length < 5) {
2039 if ((
$key = array_search(
$m, $cache[self::VARIABLE])) ===
false) {
2040 $key = count($cache[self::VARIABLE]);
2041 $cache[self::VARIABLE][] =
$m;
2043 $lhs =
new static();
2044 $lhs_value = &$lhs->value;
2045 $lhs_value = $this->
_array_repeat(0, $m_length + ($m_length >> 1));
2047 $rhs =
new static();
2050 list($u, $m1) = $lhs->divide($rhs);
2054 $cache[self::DATA][] = array(
2059 extract($cache[self::DATA][
$key]);
2062 $cutoff = $m_length + ($m_length >> 1);
2063 $lsd = array_slice(
$n, 0, $cutoff);
2064 $msd = array_slice(
$n, $cutoff);
2065 $lsd = $this->
_trim($lsd);
2066 $temp = $this->
_multiply($msd,
false, $m1,
false);
2067 $n = $this->
_add($lsd,
false, $temp[self::VALUE],
false);
2069 if ($m_length & 1) {
2074 $temp = array_slice(
$n[self::VALUE], $m_length - 1);
2077 $temp = $this->
_multiply($temp,
false, $u,
false);
2080 $temp = array_slice($temp[self::VALUE], ($m_length >> 1) + 1);
2083 $temp = $this->
_multiply($temp,
false,
$m,
false);
2112 static $cache = array(
2113 self::VARIABLE => array(),
2114 self::DATA => array()
2117 $n_length = count(
$n);
2119 if (count(
$x) > 2 * $n_length) {
2120 $lhs =
new static();
2121 $rhs =
new static();
2124 list(, $temp) = $lhs->divide($rhs);
2125 return $temp->value;
2128 if ((
$key = array_search(
$n, $cache[self::VARIABLE])) ===
false) {
2129 $key = count($cache[self::VARIABLE]);
2130 $cache[self::VARIABLE][] =
$n;
2131 $lhs =
new static();
2132 $lhs_value = &$lhs->value;
2135 $rhs =
new static();
2137 list($temp, ) = $lhs->divide($rhs);
2138 $cache[self::DATA][] = $temp->value;
2142 $temp = array_slice(
$x, $n_length - 1);
2144 $temp = $this->
_multiply($temp,
false, $cache[self::DATA][
$key],
false);
2146 $temp = array_slice($temp[self::VALUE], $n_length + 1);
2149 $result = array_slice(
$x, 0, $n_length + 1);
2154 if ($this->
_compare(
$result,
false, $temp[self::VALUE], $temp[self::SIGN]) < 0) {
2156 $corrector_value[count($corrector_value)] = 1;
2186 $x_length = count($x_value);
2187 $y_length = count($y_value);
2189 if (!$x_length || !$y_length) {
2191 self::VALUE => array(),
2196 if ($x_length < $y_length) {
2198 $x_value = $y_value;
2201 $x_length = count($x_value);
2202 $y_length = count($y_value);
2205 $product_value = $this->
_array_repeat(0, $x_length + $y_length);
2215 for ($j = 0; $j < $x_length; ++$j) {
2216 $temp = $x_value[$j] * $y_value[0] + $carry;
2217 $carry =
self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2218 $product_value[$j] = (int) ($temp - self::$baseFull * $carry);
2222 $product_value[$j] = $carry;
2228 for (
$i = 1;
$i < $y_length; ++
$i) {
2231 for ($j = 0, $k =
$i; $j < $x_length && $k < $stop; ++$j, ++$k) {
2232 $temp = $product_value[$k] + $x_value[$j] * $y_value[
$i] + $carry;
2233 $carry =
self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2234 $product_value[$k] = (int) ($temp - self::$baseFull * $carry);
2238 $product_value[$k] = $carry;
2243 self::VALUE => $this->
_trim($product_value),
2244 self::SIGN => $x_negative != $y_negative
2265 static $cache = array(
2266 self::VARIABLE => array(),
2267 self::DATA => array()
2270 if ((
$key = array_search(
$n, $cache[self::VARIABLE])) ===
false) {
2271 $key = count($cache[self::VARIABLE]);
2272 $cache[self::VARIABLE][] =
$x;
2280 for (
$i = 0;
$i < $k; ++
$i) {
2281 $temp =
$result[self::VALUE][
$i] * $cache[self::DATA][
$key];
2282 $temp = $temp - self::$baseFull * (
self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2321 static $cache = array(
2322 self::VARIABLE => array(),
2323 self::DATA => array()
2326 if ((
$key = array_search(
$m, $cache[self::VARIABLE])) ===
false) {
2327 $key = count($cache[self::VARIABLE]);
2328 $cache[self::VARIABLE][] =
$m;
2332 $n = max(count(
$x), count(
$y), count(
$m));
2333 $x = array_pad(
$x,
$n, 0);
2334 $y = array_pad(
$y,
$n, 0);
2335 $m = array_pad(
$m,
$n, 0);
2338 $temp = $a[self::VALUE][0] +
$x[
$i] *
$y[0];
2339 $temp = $temp - self::$baseFull * (
self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2340 $temp = $temp * $cache[self::DATA][
$key];
2341 $temp = $temp - self::$baseFull * (self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2343 $a = $this->
_add($a[self::VALUE],
false, $temp[self::VALUE],
false);
2344 $a[self::VALUE] = array_slice($a[self::VALUE], 1);
2346 if ($this->
_compare($a[self::VALUE],
false,
$m,
false) >= 0) {
2347 $a = $this->
_subtract($a[self::VALUE],
false,
$m,
false);
2349 return $a[self::VALUE];
2364 $lhs =
new static();
2366 $rhs =
new static();
2369 list(, $temp) = $lhs->divide($rhs);
2370 return $temp->value;
2407 return $result & self::$maxDigit;
2439 switch (MATH_BIGINTEGER_MODE) {
2440 case self::MODE_GMP:
2441 $temp =
new static();
2442 $temp->value = gmp_invert($this->value,
$n->value);
2444 return ($temp->value ===
false) ? false : $this->
_normalize($temp);
2448 if (!isset($zero)) {
2449 $zero =
new static();
2450 $one =
new static(1);
2456 if ($this->
compare($zero) < 0) {
2457 $temp = $this->
abs();
2458 $temp = $temp->modInverse(
$n);
2464 if (!$gcd->equals($one)) {
2468 $x =
$x->compare($zero) < 0 ?
$x->add(
$n) :
$x;
2503 switch (MATH_BIGINTEGER_MODE) {
2504 case self::MODE_GMP:
2505 extract(gmp_gcdext($this->value,
$n->value));
2512 case self::MODE_BCMATH:
2525 while (bccomp($v,
'0', 0) != 0) {
2526 $q = bcdiv($u, $v, 0);
2530 $v = bcsub($temp, bcmul($v, $q, 0), 0);
2534 $c = bcsub($temp, bcmul($a, $q, 0), 0);
2538 $d = bcsub($temp, bcmul($b, $q, 0), 0);
2551 $g->value = array(1);
2553 while (!((
$x->value[0] & 1)|| (
$y->value[0] & 1))) {
2567 $a->value =
$d->value = $g->value = array(1);
2568 $b->value =
$c->value = array();
2570 while (!empty($u->value)) {
2571 while (!($u->value[0] & 1)) {
2573 if ((!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1))) {
2575 $b = $b->subtract(
$x);
2581 while (!($v->value[0] & 1)) {
2583 if ((!empty(
$d->value) && (
$d->value[0] & 1)) || (!empty(
$c->value) && (
$c->value[0] & 1))) {
2591 if ($u->compare($v) >= 0) {
2592 $u = $u->subtract($v);
2593 $a = $a->subtract(
$c);
2594 $b = $b->subtract(
$d);
2596 $v = $v->subtract($u);
2597 $c =
$c->subtract($a);
2598 $d =
$d->subtract($b);
2603 'gcd' => $this->
_normalize($g->multiply($v)),
2644 $temp =
new static();
2646 switch (MATH_BIGINTEGER_MODE) {
2647 case self::MODE_GMP:
2648 $temp->value = gmp_abs($this->value);
2650 case self::MODE_BCMATH:
2651 $temp->value = (bccomp($this->value,
'0', 0) < 0) ? substr($this->value, 1) :
$this->value;
2680 switch (MATH_BIGINTEGER_MODE) {
2681 case self::MODE_GMP:
2682 return gmp_cmp($this->value,
$y->value);
2683 case self::MODE_BCMATH:
2684 return bccomp($this->value,
$y->value, 0);
2687 return $this->
_compare($this->value, $this->is_negative,
$y->value,
$y->is_negative);
2701 function _compare($x_value, $x_negative, $y_value, $y_negative)
2703 if ($x_negative != $y_negative) {
2704 return (!$x_negative && $y_negative) ? 1 : -1;
2707 $result = $x_negative ? -1 : 1;
2709 if (count($x_value) != count($y_value)) {
2712 $size = max(count($x_value), count($y_value));
2714 $x_value = array_pad($x_value,
$size, 0);
2715 $y_value = array_pad($y_value,
$size, 0);
2717 for (
$i = count($x_value) - 1;
$i >= 0; --
$i) {
2718 if ($x_value[
$i] != $y_value[
$i]) {
2738 switch (MATH_BIGINTEGER_MODE) {
2739 case self::MODE_GMP:
2740 return gmp_cmp($this->value,
$x->value) == 0;
2742 return $this->value ===
$x->value && $this->is_negative ==
$x->is_negative;
2757 $this->precision = $bits;
2758 if (MATH_BIGINTEGER_MODE != self::MODE_BCMATH) {
2759 $this->bitmask =
new static(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
2761 $this->bitmask =
new static(bcpow(
'2', $bits, 0));
2765 $this->value = $temp->value;
2778 switch (MATH_BIGINTEGER_MODE) {
2779 case self::MODE_GMP:
2780 $temp =
new static();
2781 $temp->value = gmp_and($this->value,
$x->value);
2784 case self::MODE_BCMATH:
2786 $right =
$x->toBytes();
2788 $length = max(strlen($left), strlen($right));
2790 $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2791 $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2793 return $this->
_normalize(
new static($left & $right, 256));
2798 $length = min(count(
$x->value), count($this->value));
2802 for (
$i = 0;
$i < $length; ++
$i) {
2819 switch (MATH_BIGINTEGER_MODE) {
2820 case self::MODE_GMP:
2821 $temp =
new static();
2822 $temp->value = gmp_or($this->value,
$x->value);
2825 case self::MODE_BCMATH:
2827 $right =
$x->toBytes();
2829 $length = max(strlen($left), strlen($right));
2831 $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2832 $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2834 return $this->
_normalize(
new static($left | $right, 256));
2837 $length = max(count($this->value), count(
$x->value));
2840 $x->value = array_pad(
$x->value, $length, 0);
2842 for (
$i = 0;
$i < $length; ++
$i) {
2859 switch (MATH_BIGINTEGER_MODE) {
2860 case self::MODE_GMP:
2861 $temp =
new static();
2862 $temp->value = gmp_xor($this->value,
$x->value);
2865 case self::MODE_BCMATH:
2867 $right =
$x->toBytes();
2869 $length = max(strlen($left), strlen($right));
2871 $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2872 $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2874 return $this->
_normalize(
new static($left ^ $right, 256));
2877 $length = max(count($this->value), count(
$x->value));
2880 $x->value = array_pad(
$x->value, $length, 0);
2882 for (
$i = 0;
$i < $length; ++
$i) {
2904 $pre_msb = decbin(ord($temp[0]));
2906 $msb = decbin(ord($temp[0]));
2907 if (strlen(
$msb) == 8) {
2910 $temp[0] = chr(bindec(
$msb));
2913 $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
2914 $new_bits = $this->precision - $current_bits;
2915 if ($new_bits <= 0) {
2916 return $this->
_normalize(
new static($temp, 256));
2920 $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
2923 $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);
2925 return $this->
_normalize(
new static($leading_ones | $temp, 256));
2940 $temp =
new static();
2942 switch (MATH_BIGINTEGER_MODE) {
2943 case self::MODE_GMP:
2947 $two = gmp_init(
'2');
2950 $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
2953 case self::MODE_BCMATH:
2954 $temp->value = bcdiv($this->value, bcpow(
'2', $shift, 0), 0);
2960 $temp->_rshift($shift);
2978 $temp =
new static();
2980 switch (MATH_BIGINTEGER_MODE) {
2981 case self::MODE_GMP:
2985 $two = gmp_init(
'2');
2988 $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
2991 case self::MODE_BCMATH:
2992 $temp->value = bcmul($this->value, bcpow(
'2', $shift, 0), 0);
2998 $temp->_lshift($shift);
3017 if ($this->precision > 0) {
3019 if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
3020 $mask = $this->bitmask->subtract(
new static(1));
3023 $mask = $this->bitmask->toBytes();
3026 $temp = ord($bits[0]);
3027 for (
$i = 0; $temp >>
$i; ++
$i) {
3029 $precision = 8 * strlen($bits) - 8 +
$i;
3030 $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
3039 return $this->
copy();
3043 $left = $left->bitwise_and(
new static(
$mask, 256));
3045 $result = MATH_BIGINTEGER_MODE != self::MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
3074 if (class_exists(
'\phpseclib\Crypt\Random')) {
3080 $random.= chr(mt_rand(0, 255));
3083 $blocks =
$size >> 1;
3084 for (
$i = 0;
$i < $blocks; ++
$i) {
3086 $random.= pack(
'n', mt_rand(0, 0xFFFF));
3090 return new static($random, 256);
3111 if ($arg1 ===
false) {
3115 if ($arg2 ===
false) {
3123 $compare = $max->compare($min);
3127 } elseif ($compare < 0) {
3136 $one =
new static(1);
3139 $max = $max->subtract($min->subtract($one));
3140 $size = strlen(ltrim($max->toBytes(), chr(0)));
3157 $random_max =
new static(chr(1) . str_repeat(
"\0",
$size), 256);
3160 list($max_multiple) = $random_max->divide($max);
3161 $max_multiple = $max_multiple->multiply($max);
3163 while ($random->compare($max_multiple) >= 0) {
3164 $random = $random->subtract($max_multiple);
3165 $random_max = $random_max->subtract($max_multiple);
3166 $random = $random->bitwise_leftShift(8);
3168 $random_max = $random_max->bitwise_leftShift(8);
3169 list($max_multiple) = $random_max->divide($max);
3170 $max_multiple = $max_multiple->multiply($max);
3172 list(, $random) = $random->divide($max);
3174 return $this->
_normalize($random->add($min));
3192 if ($arg1 ===
false) {
3196 if ($arg2 ===
false) {
3204 $compare = $max->compare($min);
3207 return $min->isPrime() ? $min :
false;
3208 } elseif ($compare < 0) {
3217 $one =
new static(1);
3218 $two =
new static(2);
3226 if (MATH_BIGINTEGER_MODE == self::MODE_GMP && extension_loaded(
'gmp')) {
3228 $p->value = gmp_nextprime(
$x->value);
3230 if ($p->compare($max) <= 0) {
3234 if (!$min->equals(
$x)) {
3235 $x =
$x->subtract($one);
3238 return $x->randomPrime($min,
$x);
3241 if (
$x->equals($two)) {
3246 if (
$x->compare($max) > 0) {
3248 if ($min->equals($max)) {
3255 $initial_x =
$x->copy();
3258 if ($timeout !==
false && time() -
$start > $timeout) {
3262 if (
$x->isPrime()) {
3268 if (
$x->compare($max) > 0) {
3270 if (
$x->equals($two)) {
3276 if (
$x->equals($initial_x)) {
3292 switch (MATH_BIGINTEGER_MODE) {
3293 case self::MODE_GMP:
3294 gmp_setbit($this->value, 0);
3296 case self::MODE_BCMATH:
3297 if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3298 $this->value = bcadd($this->value,
'1');
3302 $this->value[0] |= 1;
3322 $length = strlen($this->
toBytes());
3327 if ($length >= 163) {
$t = 2; }
3328 else if ($length >= 106) {
$t = 3; }
3329 else if ($length >= 81 ) {
$t = 4; }
3330 else if ($length >= 68 ) {
$t = 5; }
3331 else if ($length >= 56 ) {
$t = 6; }
3332 else if ($length >= 50 ) {
$t = 7; }
3333 else if ($length >= 43 ) {
$t = 8; }
3334 else if ($length >= 37 ) {
$t = 9; }
3335 else if ($length >= 31 ) {
$t = 12; }
3336 else if ($length >= 25 ) {
$t = 15; }
3337 else if ($length >= 18 ) {
$t = 18; }
3344 switch (MATH_BIGINTEGER_MODE) {
3345 case self::MODE_GMP:
3346 return gmp_prob_prime($this->value,
$t) != 0;
3347 case self::MODE_BCMATH:
3348 if ($this->value ===
'2') {
3351 if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3356 if ($this->value == array(2)) {
3359 if (~$this->value[0] & 1) {
3364 static $primes, $zero, $one, $two;
3366 if (!isset($primes)) {
3368 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
3369 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
3370 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
3371 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
3372 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
3373 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
3374 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
3375 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
3376 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
3377 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
3378 953, 967, 971, 977, 983, 991, 997
3381 if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
3382 for (
$i = 0;
$i < count($primes); ++
$i) {
3383 $primes[
$i] =
new static($primes[
$i]);
3387 $zero =
new static();
3388 $one =
new static(1);
3389 $two =
new static(2);
3392 if ($this->
equals($one)) {
3397 if (MATH_BIGINTEGER_MODE != self::MODE_INTERNAL) {
3398 foreach ($primes as $prime) {
3399 list(,
$r) = $this->
divide($prime);
3400 if (
$r->equals($zero)) {
3401 return $this->
equals($prime);
3406 foreach ($primes as $prime) {
3409 return count($value) == 1 && $value[0] == $prime;
3415 $n_1 =
$n->subtract($one);
3416 $n_2 =
$n->subtract($two);
3419 $r_value =
$r->value;
3421 if (MATH_BIGINTEGER_MODE == self::MODE_BCMATH) {
3424 while (
$r->value[strlen(
$r->value) - 1] % 2 == 0) {
3425 $r->value = bcdiv(
$r->value,
'2', 0);
3429 for (
$i = 0, $r_length = count($r_value);
$i < $r_length; ++
$i) {
3430 $temp = ~$r_value[
$i] & 0xFFFFFF;
3431 for ($j = 1; ($temp >> $j) & 1; ++$j) {
3437 $s = 26 *
$i + $j - 1;
3442 $a = $this->
random($two, $n_2);
3445 if (!
$y->equals($one) && !
$y->equals($n_1)) {
3446 for ($j = 1; $j <
$s && !
$y->equals($n_1); ++$j) {
3447 $y =
$y->modPow($two,
$n);
3448 if (
$y->equals($one)) {
3453 if (!
$y->equals($n_1)) {
3477 $shift = 1 << $shift;
3481 for (
$i = 0;
$i < count($this->value); ++
$i) {
3482 $temp = $this->value[
$i] * $shift + $carry;
3483 $carry =
self::$base === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
3484 $this->value[
$i] = (int) ($temp - $carry * self::$baseFull);
3488 $this->value[count($this->value)] = $carry;
3491 while ($num_digits--) {
3492 array_unshift($this->value, 0);
3513 $carry_mask = (1 << $shift) - 1;
3516 $this->value = array_slice($this->value, $num_digits);
3521 for (
$i = count($this->value) - 1;
$i >= 0; --
$i) {
3522 $temp = $this->value[
$i] >> $shift | $carry;
3523 $carry = ($this->value[
$i] & $carry_mask) << $carry_shift;
3524 $this->value[
$i] = $temp;
3527 $this->value = $this->
_trim($this->value);
3545 switch (MATH_BIGINTEGER_MODE) {
3546 case self::MODE_GMP:
3547 if ($this->bitmask !==
false) {
3552 case self::MODE_BCMATH:
3553 if (!empty(
$result->bitmask->value)) {
3562 if (!count($value)) {
3566 $value = $this->
_trim($value);
3568 if (!empty(
$result->bitmask->value)) {
3569 $length = min(count($value), count($this->bitmask->value));
3570 $value = array_slice($value, 0, $length);
3572 for (
$i = 0;
$i < $length; ++
$i) {
3573 $value[
$i] = $value[
$i] & $this->bitmask->value[
$i];
3591 for (
$i = count($value) - 1;
$i >= 0; --
$i) {
3611 return ($multiplier) ? array_fill(0, $multiplier,
$input) : array();
3630 $num_bytes = $shift >> 3;
3634 for (
$i = strlen(
$x) - 1;
$i >= 0; --
$i) {
3635 $temp = ord(
$x[
$i]) << $shift | $carry;
3636 $x[
$i] = chr($temp);
3637 $carry = $temp >> 8;
3639 $carry = ($carry != 0) ? chr($carry) :
'';
3640 $x = $carry .
$x . str_repeat(chr(0), $num_bytes);
3656 $x = ltrim(
$x, chr(0));
3660 $num_bytes = $shift >> 3;
3665 $start = $num_bytes > strlen(
$x) ? -strlen(
$x) : -$num_bytes;
3667 $x = substr(
$x, 0, -$num_bytes);
3671 $carry_shift = 8 - $shift;
3672 for (
$i = 0;
$i < strlen(
$x); ++
$i) {
3673 $temp = (ord(
$x[
$i]) >> $shift) | $carry;
3674 $carry = (ord(
$x[$i]) << $carry_shift) & 0xFF;
3675 $x[
$i] = chr($temp);
3677 $x = ltrim(
$x, chr(0));
3679 $remainder = chr($carry >> $carry_shift) . $remainder;
3681 return ltrim($remainder, chr(0));
3696 return ltrim(pack(
'N',
$x), chr(0));
3708 $temp = unpack(
'Nint', str_pad(
$x, 4, chr(0), STR_PAD_LEFT));
3709 return $temp[
'int'];
3724 if ($length <= 0x7F) {
3725 return chr($length);
3728 $temp = ltrim(pack(
'N', $length), chr(0));
3729 return pack(
'Ca*', 0x80 | strlen($temp), $temp);
3748 return (
int) (
$x /
$y);
3752 return (
$x - (
$x %
$y)) / $y;
add($y)
Adds two BigIntegers.
_squareReduce($x, $n, $mode)
Modular square.
_prepMontgomery($x, $n)
Prepare a number for use in Montgomery Modular Reductions.
modPow($e, $n)
Performs modular exponentiation.
_reduce($x, $n, $mode)
Modular reduction.
_multiplyReduce($x, $y, $n, $mode)
Modular multiply.
_compare($x_value, $x_negative, $y_value, $y_negative)
Compares two numbers.
_montgomeryMultiply($x, $y, $m)
Montgomery Multiply.
compare($y)
Compares two numbers.
__debugInfo()
__debugInfo() magic method
_subtract($x_value, $x_negative, $y_value, $y_negative)
Performs subtraction.
_multiply($x_value, $x_negative, $y_value, $y_negative)
Performs multiplication.
_multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
Performs long multiplication up to $stop digits.
_montgomery($x, $n)
Montgomery Modular Reduction.
_add($x_value, $x_negative, $y_value, $y_negative)
Performs addition.
gcd($n)
Calculates the greatest common divisor.
_rshift($shift)
Logical Right Shift.
subtract($y)
Subtracts two BigIntegers.
bitwise_or($x)
Logical Or.
static $max10Len
$max10Len in greatest $max10Len satisfying $max10 = 10**$max10Len <= 2**$base.
const DATA
$cache[self::DATA] contains the cached data.
_make_odd()
Make the current number odd.
bitwise_and($x)
Logical And.
divide($y)
Divides two BigIntegers.
_random_number_helper($size)
Generates a random BigInteger.
_array_repeat($input, $multiplier)
Array Repeat.
toBytes($twos_compliment=false)
Converts a BigInteger to a byte string (eg.
__sleep()
__sleep() magic method
_modInverse67108864($x)
Modular Inverse of a number mod 2**26 (eg.
randomPrime($arg1, $arg2=false, $timeout=false)
Generate a random prime number.
const SIGN
$result[self::SIGN] contains the sign.
const MODE_GMP
To use the GMP library.
bitwise_leftRotate($shift)
Logical Left Rotate.
Pure-PHP arbitrary precision integer arithmetic library.
toString()
Converts a BigInteger to a base-10 number.
_safe_divide($x, $y)
Single digit division.
isPrime($t=false)
Checks a numer to see if it's prime.
multiply($x)
Multiplies two BigIntegers.
bitwise_not()
Logical Not.
_int2bytes($x)
Converts 32-bit integers to bytes.
random($arg1, $arg2=false)
Generate a random number.
_prepareReduce($x, $n, $mode)
Modular reduction preperation.
powMod($e, $n)
Performs modular exponentiation.
_base256_lshift(&$x, $shift)
Logical Left Shift.
_bytes2int($x)
Converts bytes to 32-bit integers.
_lshift($shift)
Logical Left Shift.
static $base
#+ Static properties used by the pure-PHP implementation.
_barrett($n, $m)
Barrett Modular Reduction.
bitwise_leftShift($shift)
Logical Left Shift.
const MONTGOMERY
#+ Reduction constants
__wakeup()
__wakeup() magic method
const MODE_BCMATH
To use the BCMath library.
bitwise_rightRotate($shift)
Logical Right Rotate.
_regularMultiply($x_value, $y_value)
Performs long multiplication on two BigIntegers.
_mod2($n)
Modulos for Powers of Two.
_slidingWindow($e, $n, $mode)
Sliding Window k-ary Modular Exponentiation.
Pure-PHP arbitrary precision integer arithmetic library.
_baseSquare($value)
Performs traditional squaring on two BigIntegers.
toHex($twos_compliment=false)
Converts a BigInteger to a hex string (eg.
toBits($twos_compliment=false)
Converts a BigInteger to a bit string (eg.
__construct($x=0, $base=10)
Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
_karatsubaSquare($value)
Performs Karatsuba "squaring" on two BigIntegers.
setPrecision($bits)
Set Precision.
static string($length)
Generate a random string.
_square($x=false)
Performs squaring.
_karatsuba($x_value, $y_value)
Performs Karatsuba multiplication on two BigIntegers.
_base256_rshift(&$x, $shift)
Logical Right Shift.
$bitmask
Precision Bitmask.
modInverse($n)
Calculates modular inverses.
bitwise_rightShift($shift)
Logical Right Shift.
_encodeASN1Length($length)
DER-encode an integer.
_normalize($result)
Normalize.
bitwise_xor($x)
Logical Exclusive-Or.
__toString()
__toString() magic method
extendedGCD($n)
Calculates the greatest common divisor and Bezout's identity.
static $max10
$max10 in greatest $max10Len satisfying $max10 = 10**$max10Len <= 2**$base.
__clone()
__clone() magic method
_divide_digit($dividend, $divisor)
Divides a BigInteger by a regular integer.
for($i=6; $i< 13; $i++) for($i=1; $i< 13; $i++) $d
_regularBarrett($x, $n)
(Regular) Barrett Modular Reduction
equals($x)
Tests the equality of two numbers.