1
0
mirror of https://github.com/danog/phpseclib.git synced 2025-01-22 04:51:19 +01:00

- rewrote randomPrime()

- fixed a bug in Math_BigInteger::equals() that only manifests itself when the bcmath extension is used


git-svn-id: http://phpseclib.svn.sourceforge.net/svnroot/phpseclib/trunk@90 21d32557-59b3-4da0-833f-c5933fad653e
This commit is contained in:
Jim Wigginton 2010-02-21 07:45:31 +00:00
parent f2ccfdb0ac
commit d574a6770e

View File

@ -67,7 +67,7 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVI Jim Wigginton * @copyright MMVI Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt * @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: BigInteger.php,v 1.28 2010-02-07 01:54:51 terrafrost Exp $ * @version $Id: BigInteger.php,v 1.29 2010-02-21 07:45:31 terrafrost Exp $
* @link http://pear.php.net/package/Math_BigInteger * @link http://pear.php.net/package/Math_BigInteger
*/ */
@ -516,9 +516,9 @@ class Math_BigInteger {
} }
while (bccomp($current, '0', 0) > 0) { while (bccomp($current, '0', 0) > 0) {
$temp = bcmod($current, 0x1000000); $temp = bcmod($current, '16777216');
$value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
$current = bcdiv($current, 0x1000000, 0); $current = bcdiv($current, '16777216', 0);
} }
return $this->precision > 0 ? return $this->precision > 0 ?
@ -1369,7 +1369,7 @@ class Math_BigInteger {
} }
static $zero; static $zero;
if (!isset($zero)) { if ( !isset($zero) ) {
$zero = new Math_BigInteger(); $zero = new Math_BigInteger();
} }
@ -2571,6 +2571,7 @@ class Math_BigInteger {
* @param Array $y_value * @param Array $y_value
* @param Boolean $y_negative * @param Boolean $y_negative
* @return Integer * @return Integer
* @see compare()
* @access private * @access private
*/ */
function _compare($x_value, $x_negative, $y_value, $y_negative) function _compare($x_value, $x_negative, $y_value, $y_negative)
@ -2614,7 +2615,7 @@ class Math_BigInteger {
case MATH_BIGINTEGER_MODE_GMP: case MATH_BIGINTEGER_MODE_GMP:
return gmp_cmp($this->value, $x->value) == 0; return gmp_cmp($this->value, $x->value) == 0;
default: default:
return $this->value == $x->value && $this->is_negative == $x->is_negative; return $this->value === $x->value && $this->is_negative == $x->is_negative;
} }
} }
@ -2816,7 +2817,7 @@ class Math_BigInteger {
case MATH_BIGINTEGER_MODE_GMP: case MATH_BIGINTEGER_MODE_GMP:
static $two; static $two;
if (empty($two)) { if (!isset($two)) {
$two = gmp_init('2'); $two = gmp_init('2');
} }
@ -2854,7 +2855,7 @@ class Math_BigInteger {
case MATH_BIGINTEGER_MODE_GMP: case MATH_BIGINTEGER_MODE_GMP:
static $two; static $two;
if (empty($two)) { if (!isset($two)) {
$two = gmp_init('2'); $two = gmp_init('2');
} }
@ -3025,6 +3026,17 @@ class Math_BigInteger {
*/ */
function randomPrime($min = false, $max = false, $timeout = false) function randomPrime($min = false, $max = false, $timeout = false)
{ {
$compare = $max->compare($min);
if (!$compare) {
return $min;
} else if ($compare < 0) {
// if $min is bigger then $max, swap $min and $max
$temp = $max;
$max = $min;
$min = $temp;
}
// gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>. // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) { if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
// we don't rely on Math_BigInteger::random()'s min / max when gmp_nextprime() is being used since this function // we don't rely on Math_BigInteger::random()'s min / max when gmp_nextprime() is being used since this function
@ -3038,17 +3050,6 @@ class Math_BigInteger {
$max = new Math_BigInteger(0x7FFFFFFF); $max = new Math_BigInteger(0x7FFFFFFF);
} }
$compare = $max->compare($min);
if (!$compare) {
return $min;
} else if ($compare < 0) {
// if $min is bigger then $max, swap $min and $max
$temp = $max;
$max = $min;
$min = $temp;
}
$x = $this->random($min, $max); $x = $this->random($min, $max);
$x->value = gmp_nextprime($x->value); $x->value = gmp_nextprime($x->value);
@ -3066,50 +3067,78 @@ class Math_BigInteger {
return false; return false;
} }
$repeat1 = $repeat2 = array(); static $one, $two;
if (!isset($one)) {
$one = new Math_BigInteger(1); $one = new Math_BigInteger(1);
$two = new Math_BigInteger(2); $two = new Math_BigInteger(2);
}
$start = time(); $start = time();
do { $x = $this->random($min, $max);
if ($x->equals($two)) {
return $x;
}
$x->_make_odd();
if ($x->compare($max) > 0) {
// if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
if ($min->equals($max)) {
return false;
}
$x = $min->copy();
$x->_make_odd();
}
$initial_x = $x->copy();
while (true) {
if ($timeout !== false && time() - $start > $timeout) { if ($timeout !== false && time() - $start > $timeout) {
return false; return false;
} }
$x = $this->random($min, $max); if ($x->isPrime()) {
if ($x->equals($two)) {
return $x; return $x;
} }
// make the number odd $x = $x->add($two);
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
gmp_setbit($x->value, 0);
break;
case MATH_BIGINTEGER_MODE_BCMATH:
if ($x->value[strlen($x->value) - 1] % 2 == 0) {
$x = $x->add($one);
}
break;
default:
$x->value[0] |= 1;
}
// if we've seen this number twice before, assume there are no prime numbers within the given range if ($x->compare($max) > 0) {
if (in_array($x->value, $repeat1)) { $x = $min->copy();
if (in_array($x->value, $repeat2)) { if ($x->equals($two)) {
return false; return $x;
} else {
$repeat2[] = $x->value;
} }
} else { $x->_make_odd();
$repeat1[] = $x->value;
} }
} while (!$x->isPrime());
return $x; if ($x->equals($initial_x)) {
return false;
}
}
}
/**
* Make the current number odd
*
* If the current number is odd it'll be unchanged. If it's even, one will be added to it.
*
* @see randomPrime()
* @access private
*/
function _make_odd()
{
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
gmp_setbit($this->value, 0);
break;
case MATH_BIGINTEGER_MODE_BCMATH:
if ($this->value[strlen($this->value) - 1] % 2 == 0) {
$this->value = bcadd($this->value, '1');
}
break;
default:
$this->value[0] |= 1;
}
} }
/** /**
@ -3152,7 +3181,7 @@ class Math_BigInteger {
case MATH_BIGINTEGER_MODE_GMP: case MATH_BIGINTEGER_MODE_GMP:
return gmp_prob_prime($this->value, $t) != 0; return gmp_prob_prime($this->value, $t) != 0;
case MATH_BIGINTEGER_MODE_BCMATH: case MATH_BIGINTEGER_MODE_BCMATH:
if ($this->value == '2') { if ($this->value === '2') {
return true; return true;
} }
if ($this->value[strlen($this->value) - 1] % 2 == 0) { if ($this->value[strlen($this->value) - 1] % 2 == 0) {
@ -3229,7 +3258,7 @@ class Math_BigInteger {
$s = 0; $s = 0;
// if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
while ($r->value[strlen($r->value) - 1] % 2 == 0) { while ($r->value[strlen($r->value) - 1] % 2 == 0) {
$r->value = bcdiv($r->value, 2, 0); $r->value = bcdiv($r->value, '2', 0);
++$s; ++$s;
} }
} else { } else {