<?php namespace Mdanter\Ecc\Tests\Math; use Mdanter\Ecc\Math\GmpMath; use Mdanter\Ecc\Math\GmpMathInterface; use Mdanter\Ecc\Tests\AbstractTestCase; class MathTest extends AbstractTestCase { private $knownPrimes; private $startPrime = 31; private $primeCount = 10; protected function setUp() { $file = TEST_DATA_DIR.'/primes.lst'; if (! file_exists($file)) { $this->fail('Primes not found'); } $lines = file($file); if (! $lines) { $this->fail('Empty prime file'); } $this->knownPrimes = array_map(function ($i) { return intval($i); }, $lines); } private $decHexMap = array( '00' => 0, '01' => 1, '02' => 2, '03' => 3, '04' => 4, '05' => 5, '06' => 6, '07' => 7, '08' => 8, '09' => 9, '0a' => 10, '0b' => 11, '0c' => 12, '0d' => 13, '0e' => 14, '0f' => 15, ); /** * @dataProvider getAdapters * @param GmpMathInterface $adapter */ public function testDecHex(GmpMathInterface $adapter) { foreach ($this->decHexMap as $hex => $dec) { $actual = $adapter->decHex($dec); $this->assertTrue($hex === $actual, "$hex === $actual"); } } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage Unable to convert negative integer to string */ public function testDecHexFailure() { $math = new GmpMath(); $math->decHex(-1); } /** * @dataProvider getAdapters * @param GmpMathInterface $adapter */ public function testHexDec(GmpMathInterface $adapter) { foreach ($this->decHexMap as $hex => $dec) { $actual = $adapter->hexDec($hex); $this->assertEquals($actual, $dec); } } /** * @dataProvider getAdapters * @param GmpMathInterface $math */ public function testStrictIntegerReturnValues(GmpMathInterface $math) { $x = gmp_init(10, 10); $y = gmp_init(4, 10); $mod = $math->mod($x, $y); $this->assertTrue(is_object($mod) && $mod instanceof \GMP); $add = $math->add($x, $y); $this->assertTrue(is_object($add) && $add instanceof \GMP); $sub = $math->sub($add, $y); $this->assertTrue(is_object($sub) && $sub instanceof \GMP); $mul = $math->mul($x, $y); $this->assertTrue(is_object($mul) && $mul instanceof \GMP); $div = $math->div($mul, $y); $this->assertTrue(is_object($div) && $div instanceof \GMP); $pow = $math->pow($x, 4); $this->assertTrue(is_object($pow) && $pow instanceof \GMP); $powmod = $math->powmod($x, $y, $y); $this->assertTrue(is_object($powmod) && $powmod instanceof \GMP); $bitwiseand = $math->bitwiseAnd($x, $y); $this->assertTrue(is_object($bitwiseand) && $bitwiseand instanceof \GMP); $hexdec = $math->decHex(10); $this->assertTrue(is_string($hexdec)); $dechex = $math->hexDec($hexdec); $this->assertTrue(is_string($dechex)); } /** * @dataProvider getAdapters * @param GmpMathInterface $math */ public function testKnownPrimesAreCorrectlyDetected(GmpMathInterface $math) { foreach ($this->knownPrimes as $key => $prime) { if (trim($prime) == '') { user_error('Empty prime number detected from line #'.($key + 1), E_USER_WARNING); } $prime = gmp_init($prime, 10); $this->assertTrue($math->isPrime($prime), 'Prime "'.$math->toString($prime).'" is not detected as prime.'); } } /** * @dataProvider getAdapters * @param GmpMathInterface $math */ public function testGetNextPrimes(GmpMathInterface $math) { $currentPrime = $math->nextPrime(gmp_init($this->startPrime)); for ($i = 0; $i < $this->primeCount; $i ++) { $currentPrime = $math->nextPrime($currentPrime); $this->assertTrue($math->isPrime($currentPrime)); $this->assertContains(gmp_strval($currentPrime, 10), $this->knownPrimes); } } /** * @dataProvider getAdapters * @param GmpMathInterface $math */ public function testMultInverseModP(GmpMathInterface $math) { $one = gmp_init(1, 10); for ($i = 0; $i < 100; $i ++) { $m = gmp_init(rand(20, 10000), 10); for ($j = 0; $j < 100; $j ++) { $a = gmp_init(rand(1, gmp_strval(gmp_sub($m, 1), 10)), 10); if ($math->cmp($math->gcd2($a, $m), $one) == 0) { $inv = $math->inverseMod($a, $m); $check = $math->cmp($inv, gmp_init(0)) <= 0 && $math->cmp($inv, $m) >= 0 && $math->cmp($math->mod($math->mul($a, $inv), $m), $one) !== 0; $this->assertFalse($check); } } } } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage Unable to convert negative integer to string */ public function testIntToStringFailure() { $math = new GmpMath(); $math->intToString(gmp_init(-1, 10)); } public function testIntToStringEmpty() { $math = new GmpMath(); $string = $math->intToString(gmp_init(0, 10)); $this->assertEquals(chr(0), $string); } public function testIsPrime_Not() { $math = new GmpMath(); $this->assertFalse($math->isPrime(gmp_init(4, 10))); } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage Negative exponents (-1) not allowed */ public function testPowModNegativeExponent() { $math = new GmpMath(); $this->assertFalse($math->powmod(gmp_init(4, 10), gmp_init(-1), gmp_init(10))); } public function getIntegers() { return $this->_getAdapters([ [ "93259851702730122119414267054829365377133477668952701236709439268796255744233460191271607985102340890642418263347620816406406530568060493365943850327635665063346240624828866919272799277236806918436038761806088791569287622430216141779792651885991485925108198932978264734140243372160469019702162736067941749080", "1233250843753755804484142135313865659065145699339" ], [ "104443069266675154894494056547352496058317849841446240909381080038746954346358262165447797645375413679557833682500843057787107515306791353774008332913645491778683429942183034018591085242029712668821822870400768300036723574280615208480888561125874783371735647662718238661201806144617184418368531833097847399412", "682684192617274218271289237226465578682254228741"], [ "172841652009826205348651485079931564044154859094887053263544940997757724313743387438996921752290855965047976308856703202195438505015061627861419240617458979464242008737456945030261548251059024595728958588559943472687221820376770391244791727824371868459518434718330452193247973239891421410952402113233100227293", "230482896290780683372840719752000455007705001565" ] ]); } /** * @dataProvider getIntegers */ public function testDigestInteger(GmpMathInterface $math, $integer, $result) { $integer = gmp_init($integer, 10); $this->assertEquals($result, gmp_strval($math->digestInteger($integer), 10)); } }