diff --git a/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php b/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php index 0abff0ff..c46c2a64 100644 --- a/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php +++ b/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php @@ -62,7 +62,7 @@ abstract class Barrett extends Base $m_length = strlen($m); - if (strlen($n) >= 2 * $m_length) { + if (strlen($n) > 2 * $m_length) { return bcmod($n, $m); } @@ -71,6 +71,13 @@ abstract class Barrett extends Base return self::regularBarrett($n, $m); } // n = 2 * m.length + $correctionNeeded = false; + if ($m_length & 1) { + $correctionNeeded = true; + $n .= '0'; + $m .= '0'; + $m_length++; + } if (($key = array_search($m, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); @@ -127,7 +134,7 @@ abstract class Barrett extends Base $result = bcsub($result, $m); } - return $result; + return $correctionNeeded ? substr($result, 0, -1) : $result; } /** diff --git a/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php b/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php index aeecb9b5..e82f1947 100644 --- a/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php +++ b/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php @@ -55,7 +55,7 @@ abstract class Barrett extends Base $m_length = count($m); // if (self::compareHelper($n, $static::square($m)) >= 0) { - if (count($n) >= 2 * $m_length) { + if (count($n) > 2 * $m_length) { $lhs = new $class(); $rhs = new $class(); $lhs->value = $n; @@ -69,6 +69,13 @@ abstract class Barrett extends Base return self::regularBarrett($n, $m, $class); } // n = 2 * m.length + $correctionNeeded = false; + if ($m_length & 1) { + $correctionNeeded = true; + array_unshift($n, 0); + array_unshift($m, 0); + $m_length++; + } if (($key = array_search($m, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); @@ -108,6 +115,10 @@ abstract class Barrett extends Base $temp = array_slice($n[self::VALUE], $m_length - 1); // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 + // note that these are upper bounds. let's say m.length is 2. then you'd be multiplying a + // 3 digit number by a 1 digit number. if you're doing 999 * 9 (in base 10) the result will + // be a 4 digit number. but if you're multiplying 111 * 1 then the result will be a 3 digit + // number. $temp = $class::multiplyHelper($temp, false, $u, false); // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) @@ -115,17 +126,19 @@ abstract class Barrett extends Base // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) $temp = $class::multiplyHelper($temp, false, $m, false); - - // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit - // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop + // at this point, if m had an odd number of digits, we'd (probably) be subtracting a 2 * m.length - (m.length >> 1) + // digit number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop // following this comment would loop a lot (hence our calling _regularBarrett() in that situation). - $result = $class::subtractHelper($n[self::VALUE], false, $temp[self::VALUE], false); while (self::compareHelper($result[self::VALUE], $result[self::SIGN], $m, false) >= 0) { $result = $class::subtractHelper($result[self::VALUE], $result[self::SIGN], $m, false); } + if ($correctionNeeded) { + array_shift($result[self::VALUE]); + } + return $result[self::VALUE]; } diff --git a/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php b/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php index fee7ad2e..a49d3443 100644 --- a/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php +++ b/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php @@ -67,6 +67,14 @@ abstract class EvalBarrett extends Base return $func; } + $correctionNeeded = false; + if ($m_length & 1) { + $correctionNeeded = true; + $m = clone $m; + array_unshift($m->value, 0); + $m_length++; + } + $lhs = new $class(); $lhs_value = &$lhs->value; @@ -92,8 +100,12 @@ abstract class EvalBarrett extends Base $cutoff = count($m) + (count($m) >> 1); - $code = ' - if (count($n) >= ' . (2 * count($m)) . ') { + $code = $correctionNeeded ? + 'array_unshift($n, 0);' : + ''; + + $code .= ' + if (count($n) > ' . (2 * count($m)) . ') { $lhs = new ' . $class . '(); $rhs = new ' . $class . '(); $lhs->value = $n; @@ -134,6 +146,10 @@ abstract class EvalBarrett extends Base $code .= self::generateInlineCompare($m, 'temp', $subcode); + if ($correctionNeeded) { + $code .= 'array_shift($temp);'; + } + $code .= 'return $temp;'; eval('$func = function ($n) { ' . $code . '};');