0; $remainFill--) { $tmp[] = $filler; } $result = join("", $tmp); $moreLen = $length - strlen($result); if ($moreLen === 0) { return $result; } return $result . substr($filler, 0, $moreLen); } class DummyBlockRNG extends LiteHashDRBG { private int $repeatBlockCnt; /** * * @param string[] $repeatBlock * @param int $stateIdx * @return void * @throws RuntimeException */ public function __construct(protected array $repeatBlock, protected int $stateIdx = 0) { foreach ($repeatBlock as $block) { if (strlen($block) != BLOCK_SIZE) { throw new RuntimeException('Invalid repeat block'); } } $this->repeatBlockCnt = count($this->repeatBlock); $this->genNextBlock(); } protected function genNextBlock(): void { $this->buffer = $this->repeatBlock[$this->stateIdx]; $this->bufferIdx = 0; $this->stateIdx = ($this->stateIdx + 1) % $this->repeatBlockCnt; } } class RNGTest extends PHPUnit\Framework\TestCase { const FIXED_KEY = 'HelloWorld'; public function testDummyRNG() { //Block의 값을 고정하고 입력값을 확인 $rng = new DummyBlockRNG([ fillBlock('', "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff") ]); $this->setName('DummyRNG-SimpleByte'); $this->assertEquals("\x00", $rng->nextBytes(1)); $this->assertEquals("\x11\x22", $rng->nextBytes(2)); $this->assertEquals("\x33\x44\x55", $rng->nextBytes(3)); $this->assertEquals("\x66\x77\x88\x99", $rng->nextBytes(4)); $this->setName('DummyRNG-OverflowBlock'); foreach (range(1, 16) as $_i) { $this->assertEquals( "\xaa\xbb\xcc\xdd\xee\xff\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99", $rng->nextBytes(16) ); } $this->setName('DummyRNG-MultiBlock'); $this->assertEquals( fillBlock('', "\xaa\xbb\xcc\xdd\xee\xff\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99", BLOCK_SIZE * 2), $rng->nextBytes(BLOCK_SIZE * 2) ); $this->setName('DummyRNG-BitTest'); $this->assertEquals("\x00", $rng->nextBits(1)); //aa $this->assertEquals("\x01", $rng->nextBits(1)); //bb $this->assertEquals("\xcc", $rng->nextBits(8)); //cc $this->assertEquals("\xdd\x02", $rng->nextBits(10)); //ddee $this->assertEquals("\x7f", $rng->nextBits(7)); //ff $this->assertEquals("\x00\x11\x22\x33\x44\x55\x06", $rng->nextBits(53)); $this->setName('DummyRNG-Int'); $this->assertEquals(0x77, $rng->nextInt(0xff)); $this->assertEquals(0x9988, $rng->nextInt((1 << 16) - 1)); $this->assertEquals(0xddccbbaa, $rng->nextInt((1 << 32) - 1)); $this->assertEquals(0x0433221100ffee, $rng->nextInt()); $this->assertEquals(0x05, $rng->nextInt(0x0f)); //55 $this->assertEquals(0x06, $rng->nextInt(0x12)); //66 $this->assertEquals(0x08, $rng->nextInt(99)); //77(119 -> 7bit) -> 88(136 -> 8bit -> 8) $this->assertEquals(0x99, $rng->nextInt(0x99)); //99 $this->assertEquals(0xaa, $rng->nextInt(0xaa)); //aa (fit Max) $floatMax = 1 << 53; $this->setName('DummyRNG-Float'); //7개씩 $fa = $rng->nextFloat1(); $this->assertEquals(0x1100ffeeddccbb / $floatMax, $fa, 'float1-1'); $this->assertIsFloat($fa); $this->assertLessThan(0.5313720384, $fa); $this->assertGreaterThan(0.5313720383, $fa); $fb = $rng->nextFloat1(); $this->assertEquals(0x08776655443322 / $floatMax, $fb, 'float1-2'); } public function testRNGInvalidNextBits0() { $rng = new LiteHashDRBG(self::FIXED_KEY); $this->expectException('\InvalidArgumentException'); $rng->nextBits(0); } public function testRNGInvalidNextBitsMinus1() { $rng = new LiteHashDRBG(self::FIXED_KEY); $this->expectException('\InvalidArgumentException'); $rng->nextBits(-1); } public function testRNGInvalidNextBytes0() { $rng = new LiteHashDRBG(self::FIXED_KEY); $this->expectException('\InvalidArgumentException'); $rng->nextBytes(0); } public function testRNGInvalidNextBytesMinus1() { $rng = new LiteHashDRBG(self::FIXED_KEY); $this->expectException('\InvalidArgumentException'); $rng->nextBytes(-1); } public function testRNGInvalidNextIntOverflow() { $rng = new LiteHashDRBG(self::FIXED_KEY); $this->expectException('\InvalidArgumentException'); $rng->nextInt(1 << 53); } public function testRandUtilEmptyChoice() { $this->expectException('\InvalidArgumentException'); $rng = new LiteHashDRBG(self::FIXED_KEY); $randUtil = new RandUtil($rng); $randUtil->choice([]); } public function testRandUtilEmptychoiceUsingWeight() { $this->expectException('\InvalidArgumentException'); $rng = new LiteHashDRBG(self::FIXED_KEY); $randUtil = new RandUtil($rng); $randUtil->choiceUsingWeight([]); } public function testRandUtilEmptychoiceUsingWeightPair() { $this->expectException('\InvalidArgumentException'); $rng = new LiteHashDRBG(self::FIXED_KEY); $randUtil = new RandUtil($rng); $randUtil->choiceUsingWeightPair([]); } /** * @doesNotPerformAssertions */ public function testRNGAcceptable() { $rng = new LiteHashDRBG(self::FIXED_KEY); $rng->nextInt(0); $rng->nextInt(1 << 53 - 1); $rng->nextBytes(65); $rng->nextBits(512); $randUtil = new RandUtil($rng); $randUtil->choice([0, 0, 0]); $randUtil->choiceUsingWeight([0 => 0, 1 => -1]); $randUtil->choiceUsingWeightPair([ [0, 0], [1, 0], [2, -1], ]); $randUtil->nextBool(1.1); $randUtil->nextBool(-0.1); $randUtil->shuffle([]); $randUtil->shuffle([1]); $randUtil->shuffleAssoc([]); $randUtil->shuffleAssoc([1]); $randUtil->nextRange(0, 0); $randUtil->nextRangeInt(0, 0); $randUtil->nextRange(1, -1); $randUtil->nextRangeInt(1, -1); } }