mirror of
https://github.com/php/php-src.git
synced 2026-04-22 07:28:09 +02:00
64d9080534
With a single byte we can choose offsets between 0x00 and 0xff, thus 0x100 different offsets. We only need to use the slow path for sources of more than 0x100 bytes. The previous version was correct with regard to the output expectations, it was just slower than necessary. Better fix this now while we still can before being bound by our BC guarantees with regard to emitted sequences. This also adds a test to verify the behavior: For powers of two we never reject any values during rejection sampling, we just need to mask off the unneeded bits. Thus we can specifically verify that the number of calls to the engine match the expected amount. We also verify that all the possible values are emitted to make sure the masking does not remove any required bits. For inputs longer than 0x100 bytes we need trust the `range()` implementation to be unbiased, but still verify the number of engine calls and perform a basic output check.
84 lines
1.6 KiB
PHP
84 lines
1.6 KiB
PHP
<?php
|
|
|
|
namespace Random\Engine\Test;
|
|
|
|
use Random\Engine;
|
|
|
|
final class TestShaEngine implements Engine
|
|
{
|
|
private string $state;
|
|
|
|
public function __construct(?string $state = null)
|
|
{
|
|
if ($state !== null) {
|
|
$this->state = $state;
|
|
} else {
|
|
$this->state = random_bytes(20);
|
|
}
|
|
}
|
|
|
|
public function generate(): string
|
|
{
|
|
$this->state = sha1($this->state, true);
|
|
|
|
return substr($this->state, 0, 8);
|
|
}
|
|
}
|
|
|
|
final class TestWrapperEngine implements Engine
|
|
{
|
|
private int $count = 0;
|
|
|
|
public function __construct(private readonly Engine $engine)
|
|
{
|
|
}
|
|
|
|
public function generate(): string
|
|
{
|
|
$this->count++;
|
|
|
|
return $this->engine->generate();
|
|
}
|
|
|
|
public function getCount(): int
|
|
{
|
|
return $this->count;
|
|
}
|
|
}
|
|
|
|
final class TestXoshiro128PlusPlusEngine implements Engine
|
|
{
|
|
public function __construct(
|
|
private int $s0,
|
|
private int $s1,
|
|
private int $s2,
|
|
private int $s3
|
|
) {
|
|
}
|
|
|
|
private static function rotl($x, $k)
|
|
{
|
|
return (($x << $k) | ($x >> (32 - $k))) & 0xFFFFFFFF;
|
|
}
|
|
|
|
public function generate(): string
|
|
{
|
|
$result = (self::rotl(($this->s0 + $this->s3) & 0xFFFFFFFF, 7) + $this->s0) & 0xFFFFFFFF;
|
|
|
|
$t = ($this->s1 << 9) & 0xFFFFFFFF;
|
|
|
|
$this->s2 ^= $this->s0;
|
|
$this->s3 ^= $this->s1;
|
|
$this->s1 ^= $this->s2;
|
|
$this->s0 ^= $this->s3;
|
|
|
|
$this->s2 ^= $t;
|
|
|
|
$this->s3 = self::rotl($this->s3, 11);
|
|
|
|
return pack('V', $result);
|
|
}
|
|
}
|
|
|
|
?>
|