mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-11-11 16:15:52 +00:00
Use base-2**26 on systems with 32-bit ints and base-2**31 on systems with 64-bit ints
This commit is contained in:
parent
0333805f5c
commit
4a96cc8024
@ -162,16 +162,6 @@ define('MATH_BIGINTEGER_MODE_BCMATH', 2);
|
||||
define('MATH_BIGINTEGER_MODE_GMP', 3);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* The largest digit that may be used in addition / subtraction
|
||||
*
|
||||
* (we do pow(2, 52) instead of using 4503599627370496, directly, because some PHP installations
|
||||
* will truncate 4503599627370496)
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52));
|
||||
|
||||
/**
|
||||
* Karatsuba Cutoff
|
||||
*
|
||||
@ -286,6 +276,40 @@ class Math_BigInteger {
|
||||
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
|
||||
}
|
||||
|
||||
if (!defined('PHP_INT_SIZE')) {
|
||||
define('PHP_INT_SIZE', 4);
|
||||
}
|
||||
|
||||
if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {
|
||||
switch (PHP_INT_SIZE) {
|
||||
case 8: // use 64-bit integers if int size is 8 bytes
|
||||
define('MATH_BIGINTEGER_BASE', 31);
|
||||
define('MATH_BIGINTEGER_BASE_FULL', 0x80000000);
|
||||
define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF);
|
||||
define('MATH_BIGINTEGER_MSB', 0x40000000);
|
||||
// 10**9 is the closest we can get to 2**31 without passing it
|
||||
define('MATH_BIGINTEGER_MAX10', 1000000000);
|
||||
define('MATH_BIGINTEGER_MAX10_LEN', 9);
|
||||
// the largest digit that may be used in addition / subtraction
|
||||
define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62));
|
||||
break;
|
||||
//case 4: // use 64-bit floats if int size is 4 bytes
|
||||
default:
|
||||
define('MATH_BIGINTEGER_BASE', 26);
|
||||
define('MATH_BIGINTEGER_BASE_FULL', 0x4000000);
|
||||
define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF);
|
||||
define('MATH_BIGINTEGER_MSB', 0x2000000);
|
||||
// 10**7 is the closest to 2**26 without passing it
|
||||
define('MATH_BIGINTEGER_MAX10', 10000000);
|
||||
define('MATH_BIGINTEGER_MAX10_LEN', 7);
|
||||
// the largest digit that may be used in addition / subtraction
|
||||
// we do pow(2, 52) instead of using 4503599627370496 directly because some
|
||||
// PHP installations will truncate 4503599627370496.
|
||||
define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
switch ( MATH_BIGINTEGER_MODE ) {
|
||||
case MATH_BIGINTEGER_MODE_GMP:
|
||||
if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
|
||||
@ -338,7 +362,7 @@ class Math_BigInteger {
|
||||
// converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
|
||||
default:
|
||||
while (strlen($x)) {
|
||||
$this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26));
|
||||
$this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,21 +428,20 @@ class Math_BigInteger {
|
||||
default:
|
||||
$temp = new Math_BigInteger();
|
||||
|
||||
// array(10000000) is 10**7 in base-2**26. 10**7 is the closest to 2**26 we can get without passing it.
|
||||
$multiplier = new Math_BigInteger();
|
||||
$multiplier->value = array(10000000);
|
||||
$multiplier->value = array(MATH_BIGINTEGER_MAX10);
|
||||
|
||||
if ($x[0] == '-') {
|
||||
$this->is_negative = true;
|
||||
$x = substr($x, 1);
|
||||
}
|
||||
|
||||
$x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT);
|
||||
$x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
|
||||
|
||||
while (strlen($x)) {
|
||||
$temp = $temp->multiply($multiplier);
|
||||
$temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256));
|
||||
$x = substr($x, 7);
|
||||
$temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
|
||||
$x = substr($x, MATH_BIGINTEGER_MAX10_LEN);
|
||||
}
|
||||
|
||||
$this->value = $temp->value;
|
||||
@ -543,7 +566,7 @@ class Math_BigInteger {
|
||||
$temp = $this->copy();
|
||||
|
||||
for ($i = count($temp->value) - 2; $i >= 0; --$i) {
|
||||
$temp->_base256_lshift($result, 26);
|
||||
$temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
|
||||
$result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
@ -659,11 +682,11 @@ class Math_BigInteger {
|
||||
$temp->is_negative = false;
|
||||
|
||||
$divisor = new Math_BigInteger();
|
||||
$divisor->value = array(10000000); // eg. 10**7
|
||||
$divisor->value = array(MATH_BIGINTEGER_MAX10);
|
||||
$result = '';
|
||||
while (count($temp->value)) {
|
||||
list($temp, $mod) = $temp->divide($divisor);
|
||||
$result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result;
|
||||
$result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result;
|
||||
}
|
||||
$result = ltrim($result, '0');
|
||||
if (empty($result)) {
|
||||
@ -874,25 +897,25 @@ class Math_BigInteger {
|
||||
|
||||
$carry = 0;
|
||||
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
|
||||
$sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry;
|
||||
$carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
|
||||
$sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
|
||||
$sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
|
||||
$carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
|
||||
$sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
|
||||
|
||||
$temp = (int) ($sum / 0x4000000);
|
||||
$temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);
|
||||
|
||||
$value[$i] = (int) ($sum - 0x4000000 * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
|
||||
$value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
|
||||
$value[$j] = $temp;
|
||||
}
|
||||
|
||||
if ($j == $size) { // ie. if $y_size is odd
|
||||
$sum = $x_value[$i] + $y_value[$i] + $carry;
|
||||
$carry = $sum >= 0x4000000;
|
||||
$value[$i] = $carry ? $sum - 0x4000000 : $sum;
|
||||
$carry = $sum >= MATH_BIGINTEGER_BASE_FULL;
|
||||
$value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
|
||||
++$i; // ie. let $i = $j since we've just done $value[$i]
|
||||
}
|
||||
|
||||
if ($carry) {
|
||||
for (; $value[$i] == 0x3FFFFFF; ++$i) {
|
||||
for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {
|
||||
$value[$i] = 0;
|
||||
}
|
||||
++$value[$i];
|
||||
@ -1010,26 +1033,26 @@ class Math_BigInteger {
|
||||
|
||||
$carry = 0;
|
||||
for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
|
||||
$sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry;
|
||||
$sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
|
||||
$carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
|
||||
$sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
|
||||
$sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
|
||||
|
||||
$temp = (int) ($sum / 0x4000000);
|
||||
$temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);
|
||||
|
||||
$x_value[$i] = (int) ($sum - 0x4000000 * $temp);
|
||||
$x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
|
||||
$x_value[$j] = $temp;
|
||||
}
|
||||
|
||||
if ($j == $y_size) { // ie. if $y_size is odd
|
||||
$sum = $x_value[$i] - $y_value[$i] - $carry;
|
||||
$carry = $sum < 0;
|
||||
$x_value[$i] = $carry ? $sum + 0x4000000 : $sum;
|
||||
$x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
|
||||
++$i;
|
||||
}
|
||||
|
||||
if ($carry) {
|
||||
for (; !$x_value[$i]; ++$i) {
|
||||
$x_value[$i] = 0x3FFFFFF;
|
||||
$x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
|
||||
}
|
||||
--$x_value[$i];
|
||||
}
|
||||
@ -1162,8 +1185,8 @@ class Math_BigInteger {
|
||||
|
||||
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
|
||||
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
|
||||
$carry = (int) ($temp / 0x4000000);
|
||||
$product_value[$j] = (int) ($temp - 0x4000000 * $carry);
|
||||
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
||||
$product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
||||
}
|
||||
|
||||
$product_value[$j] = $carry;
|
||||
@ -1175,8 +1198,8 @@ class Math_BigInteger {
|
||||
|
||||
for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
|
||||
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
|
||||
$carry = (int) ($temp / 0x4000000);
|
||||
$product_value[$k] = (int) ($temp - 0x4000000 * $carry);
|
||||
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
||||
$product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
||||
}
|
||||
|
||||
$product_value[$k] = $carry;
|
||||
@ -1263,14 +1286,14 @@ class Math_BigInteger {
|
||||
$i2 = $i << 1;
|
||||
|
||||
$temp = $square_value[$i2] + $value[$i] * $value[$i];
|
||||
$carry = (int) ($temp / 0x4000000);
|
||||
$square_value[$i2] = (int) ($temp - 0x4000000 * $carry);
|
||||
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
||||
$square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
||||
|
||||
// note how we start from $i+1 instead of 0 as we do in multiplication.
|
||||
for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
|
||||
$temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
|
||||
$carry = (int) ($temp / 0x4000000);
|
||||
$square_value[$k] = (int) ($temp - 0x4000000 * $carry);
|
||||
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
||||
$square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
||||
}
|
||||
|
||||
// the following line can yield values larger 2**15. at this point, PHP should switch
|
||||
@ -1418,7 +1441,7 @@ class Math_BigInteger {
|
||||
|
||||
// normalize $x and $y as described in HAC 14.23 / 14.24
|
||||
$msb = $y->value[count($y->value) - 1];
|
||||
for ($shift = 0; !($msb & 0x2000000); ++$shift) {
|
||||
for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {
|
||||
$msb <<= 1;
|
||||
}
|
||||
$x->_lshift($shift);
|
||||
@ -1465,10 +1488,10 @@ class Math_BigInteger {
|
||||
|
||||
$q_index = $i - $y_max - 1;
|
||||
if ($x_window[0] == $y_window[0]) {
|
||||
$quotient_value[$q_index] = 0x3FFFFFF;
|
||||
$quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
|
||||
} else {
|
||||
$quotient_value[$q_index] = (int) (
|
||||
($x_window[0] * 0x4000000 + $x_window[1])
|
||||
($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1])
|
||||
/
|
||||
$y_window[0]
|
||||
);
|
||||
@ -1536,7 +1559,7 @@ class Math_BigInteger {
|
||||
$result = array();
|
||||
|
||||
for ($i = count($dividend) - 1; $i >= 0; --$i) {
|
||||
$temp = 0x4000000 * $carry + $dividend[$i];
|
||||
$temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];
|
||||
$result[$i] = (int) ($temp / $divisor);
|
||||
$carry = (int) ($temp - $divisor * $result[$i]);
|
||||
}
|
||||
@ -1754,7 +1777,7 @@ class Math_BigInteger {
|
||||
$e_length = count($e_value) - 1;
|
||||
$e_bits = decbin($e_value[$e_length]);
|
||||
for ($i = $e_length - 1; $i >= 0; --$i) {
|
||||
$e_bits.= str_pad(decbin($e_value[$i]), 26, '0', STR_PAD_LEFT);
|
||||
$e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
$e_length = strlen($e_bits);
|
||||
@ -2148,8 +2171,8 @@ class Math_BigInteger {
|
||||
|
||||
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
|
||||
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
|
||||
$carry = (int) ($temp / 0x4000000);
|
||||
$product_value[$j] = (int) ($temp - 0x4000000 * $carry);
|
||||
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
||||
$product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
||||
}
|
||||
|
||||
if ($j < $stop) {
|
||||
@ -2164,8 +2187,8 @@ class Math_BigInteger {
|
||||
|
||||
for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
|
||||
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
|
||||
$carry = (int) ($temp / 0x4000000);
|
||||
$product_value[$k] = (int) ($temp - 0x4000000 * $carry);
|
||||
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
||||
$product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
||||
}
|
||||
|
||||
if ($k < $stop) {
|
||||
@ -2213,7 +2236,7 @@ class Math_BigInteger {
|
||||
|
||||
for ($i = 0; $i < $k; ++$i) {
|
||||
$temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
|
||||
$temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
|
||||
$temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
|
||||
$temp = $this->_regularMultiply(array($temp), $n);
|
||||
$temp = array_merge($this->_array_repeat(0, $i), $temp);
|
||||
$result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
|
||||
@ -2265,9 +2288,9 @@ class Math_BigInteger {
|
||||
$a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
|
||||
for ($i = 0; $i < $n; ++$i) {
|
||||
$temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
|
||||
$temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
|
||||
$temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
|
||||
$temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
|
||||
$temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
|
||||
$temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
|
||||
$temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
|
||||
$a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
|
||||
$a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
|
||||
@ -2325,15 +2348,15 @@ class Math_BigInteger {
|
||||
* @param Array $x
|
||||
* @return Integer
|
||||
*/
|
||||
function _modInverse67108864($x) // 2**26 == 67108864
|
||||
function _modInverse67108864($x) // 2**26 == 67,108,864
|
||||
{
|
||||
$x = -$x[0];
|
||||
$result = $x & 0x3; // x**-1 mod 2**2
|
||||
$result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
|
||||
$result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
|
||||
$result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
|
||||
$result = fmod($result * (2 - fmod($x * $result, 0x4000000)), 0x4000000); // x**-1 mod 2**26
|
||||
return $result & 0x3FFFFFF;
|
||||
$result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26
|
||||
return $result & MATH_BIGINTEGER_MAX_DIGIT;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3375,16 +3398,16 @@ class Math_BigInteger {
|
||||
return;
|
||||
}
|
||||
|
||||
$num_digits = (int) ($shift / 26);
|
||||
$shift %= 26;
|
||||
$num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
|
||||
$shift %= MATH_BIGINTEGER_BASE;
|
||||
$shift = 1 << $shift;
|
||||
|
||||
$carry = 0;
|
||||
|
||||
for ($i = 0; $i < count($this->value); ++$i) {
|
||||
$temp = $this->value[$i] * $shift + $carry;
|
||||
$carry = (int) ($temp / 0x4000000);
|
||||
$this->value[$i] = (int) ($temp - $carry * 0x4000000);
|
||||
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
||||
$this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
|
||||
}
|
||||
|
||||
if ( $carry ) {
|
||||
@ -3410,9 +3433,9 @@ class Math_BigInteger {
|
||||
return;
|
||||
}
|
||||
|
||||
$num_digits = (int) ($shift / 26);
|
||||
$shift %= 26;
|
||||
$carry_shift = 26 - $shift;
|
||||
$num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
|
||||
$shift %= MATH_BIGINTEGER_BASE;
|
||||
$carry_shift = MATH_BIGINTEGER_BASE - $shift;
|
||||
$carry_mask = (1 << $shift) - 1;
|
||||
|
||||
if ( $num_digits ) {
|
||||
|
Loading…
Reference in New Issue
Block a user