Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'ezimuel/hotfix/rnd'
Browse files Browse the repository at this point in the history
  • Loading branch information
EvanDotPro committed Jun 12, 2012
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 10 deletions.
12 changes: 9 additions & 3 deletions src/Math.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,15 @@ public static function rand($min, $max, $strong = false)
'The supplied range is too great to generate'
);
}
$bytes = (int) max(log($range,2) / 8, 1);
$rnd = hexdec(bin2hex(self::randBytes($bytes, $strong)));
return $min + $rnd % ($range+1);
$log = log($range, 2);
$bytes = (int) ($log / 8) + 1;
$bits = (int) $log + 1;
$filter = (int) (1 << $bits) - 1;
do {
$rnd = hexdec(bin2hex(self::randBytes($bytes, $strong)));
$rnd = $rnd & $filter;
} while ($rnd > $range);
return $min + $rnd;
}

/**
Expand Down
57 changes: 50 additions & 7 deletions test/MathTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,65 @@
*/
class MathTest extends \PHPUnit_Framework_TestCase
{
public static function provideRandInt()
{
return array(
array(2, 1, 10000, 100, 0.9, 1.1, false),
array(2, 1, 10000, 100, 0.8, 1.2, true)
);
}

public function testRandBytes()
{
for ($length=1; $length<4096; $length++) {
$rand = Math::randBytes($length);
$this->assertTrue(!empty($rand));
$this->assertEquals(strlen($rand), $length);
$this->assertEquals($length, strlen($rand));
}
}

public function testRand()
/**
* A Monte Carlo test that generates $cycles numbers from 0 to $tot
* and test if the numbers are above or below the line y=x with a
* frequency range of [$min, $max]
*
* Note: this code is inspired by the random number generator test
* included in the PHP-CryptLib project of Anthony Ferrara
* @see https://github.com/ircmaxell/PHP-CryptLib
*
* @dataProvider provideRandInt
*/
public function testRandInt($num, $valid, $cycles, $tot, $min, $max, $strong)
{
for ($i=0; $i<10000; $i++) {
$min = mt_rand(0,10000);
$max = $min + mt_rand(0,10000);
$rand = Math::rand($min, $max);
$this->assertTrue(($rand >= $min) && ($rand <= $max));
try {
$test = Math::randBytes(1, $strong);
} catch (\Zend\Math\Exception\RuntimeException $e) {
$this->markTestSkipped($e->getMessage());
}
$i = 0;
$count = 0;
do {
$up = 0;
$down = 0;
for ($i=0; $i<$cycles; $i++) {
$x = Math::rand(0, $tot, $strong);
$y = Math::rand(0, $tot, $strong);
if ($x > $y) {
$up++;
} elseif ($x < $y) {
$down++;
}
}
$this->assertGreaterThan(0, $up);
$this->assertGreaterThan(0, $down);
$ratio = $up / $down;
if ($ratio > $min && $ratio < $max) {
$count++;
}
$i++;
} while ($i < $num && $count < $valid);
if ($count < $valid) {
$this->fail('The random number generator failed the Monte Carlo test');
}
}

Expand Down

0 comments on commit a037761

Please sign in to comment.