├── .coveralls.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src └── Sha3.php └── test └── Sha3Test.php /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | src_dir: . 3 | coverage_clover: build/logs/clover.xml 4 | json_path: coveralls-upload.json 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.5 5 | - 5.6 6 | - 7.0 7 | - 7.1 8 | - hhvm 9 | - nightly 10 | 11 | 12 | install: 13 | - travis_retry composer self-update 14 | - travis_retry composer install --prefer-dist --dev 15 | 16 | script: 17 | - mkdir -p build/logs 18 | - phpunit -c phpunit.xml.dist 19 | after_script: 20 | - php vendor/bin/coveralls -v 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Bruno Bierbaumer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-sha3 [![Build Status](https://img.shields.io/travis/0xbb/php-sha3/master.svg?style=flat-square)](https://travis-ci.org/0xbb/php-sha3) [![Coverage Status](https://coveralls.io/repos/0xbb/php-sha3/badge.svg?branch=master&service=github)](https://coveralls.io/github/0xbb/php-sha3?branch=master) 2 | Pure PHP implementation of SHA-3 3 | 4 | 5 | ## Usage 6 | 7 | ```php 8 | =5.4.0" 18 | }, 19 | "autoload": { 20 | "psr-4": { 21 | "bb\\Sha3\\": "src" 22 | } 23 | }, 24 | "autoload-dev": { 25 | "psr-4": { 26 | "bb\\Sha3\\Test\\": "test" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | 16 | test 17 | 18 | 19 | 20 | 21 | 22 | src 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Sha3.php: -------------------------------------------------------------------------------- 1 | > 31)) & (0xFFFFFFFF), 36 | $bc[($i + 4) % 5][1] ^ (($bc[($i + 1) % 5][1] << 1) | ($bc[($i + 1) % 5][0] >> 31)) & (0xFFFFFFFF) 37 | ]; 38 | 39 | for ($j = 0; $j < 25; $j += 5) { 40 | $st[$j + $i] = [ 41 | $st[$j + $i][0] ^ $t[0], 42 | $st[$j + $i][1] ^ $t[1] 43 | ]; 44 | } 45 | } 46 | 47 | // Rho Pi 48 | $t = $st[1]; 49 | for ($i = 0; $i < 24; $i++) { 50 | $j = self::$keccakf_piln[$i]; 51 | 52 | $bc[0] = $st[$j]; 53 | 54 | $n = self::$keccakf_rotc[$i]; 55 | $hi = $t[0]; 56 | $lo = $t[1]; 57 | if ($n >= 32) { 58 | $n -= 32; 59 | $hi = $t[1]; 60 | $lo = $t[0]; 61 | } 62 | 63 | $st[$j] =[ 64 | (($hi << $n) | ($lo >> (32 - $n))) & (0xFFFFFFFF), 65 | (($lo << $n) | ($hi >> (32 - $n))) & (0xFFFFFFFF) 66 | ]; 67 | 68 | $t = $bc[0]; 69 | } 70 | 71 | // Chi 72 | for ($j = 0; $j < 25; $j += 5) { 73 | for ($i = 0; $i < 5; $i++) { 74 | $bc[$i] = $st[$j + $i]; 75 | } 76 | for ($i = 0; $i < 5; $i++) { 77 | $st[$j + $i] = [ 78 | $st[$j + $i][0] ^ ~$bc[($i + 1) % 5][0] & $bc[($i + 2) % 5][0], 79 | $st[$j + $i][1] ^ ~$bc[($i + 1) % 5][1] & $bc[($i + 2) % 5][1] 80 | ]; 81 | } 82 | } 83 | 84 | // Iota 85 | $st[0] = [ 86 | $st[0][0] ^ $keccakf_rndc[$round][0], 87 | $st[0][1] ^ $keccakf_rndc[$round][1] 88 | ]; 89 | } 90 | } 91 | 92 | private static function keccak64($in_raw, $capacity, $outputlength, $suffix, $raw_output) 93 | { 94 | $capacity /= 8; 95 | 96 | $inlen = self::ourStrlen($in_raw); 97 | 98 | $rsiz = 200 - 2 * $capacity; 99 | $rsizw = $rsiz / 8; 100 | 101 | $st = []; 102 | for ($i = 0; $i < 25; $i++) { 103 | $st[] = [0, 0]; 104 | } 105 | 106 | for ($in_t = 0; $inlen >= $rsiz; $inlen -= $rsiz, $in_t += $rsiz) { 107 | for ($i = 0; $i < $rsizw; $i++) { 108 | $t = unpack('V*', self::ourSubstr($in_raw, $i * 8 + $in_t, 8)); 109 | 110 | $st[$i] = [ 111 | $st[$i][0] ^ $t[2], 112 | $st[$i][1] ^ $t[1] 113 | ]; 114 | } 115 | 116 | self::keccakf64($st, self::KECCAK_ROUNDS); 117 | } 118 | 119 | $temp = self::ourSubstr($in_raw, $in_t, $inlen); 120 | $temp = str_pad($temp, $rsiz, "\x0", STR_PAD_RIGHT); 121 | 122 | $temp[$inlen] = chr($suffix); 123 | $temp[$rsiz - 1] = chr(ord($temp[$rsiz - 1]) | 0x80); 124 | 125 | for ($i = 0; $i < $rsizw; $i++) { 126 | $t = unpack('V*', self::ourSubstr($temp, $i * 8, 8)); 127 | 128 | $st[$i] = [ 129 | $st[$i][0] ^ $t[2], 130 | $st[$i][1] ^ $t[1] 131 | ]; 132 | } 133 | 134 | self::keccakf64($st, self::KECCAK_ROUNDS); 135 | 136 | $out = ''; 137 | for ($i = 0; $i < 25; $i++) { 138 | $out .= $t = pack('V*', $st[$i][1], $st[$i][0]); 139 | } 140 | $r = self::ourSubstr($out, 0, $outputlength / 8); 141 | 142 | return $raw_output ? $r : bin2hex($r); 143 | } 144 | 145 | private static function keccakf32(&$st, $rounds) 146 | { 147 | $keccakf_rndc = [ 148 | [0x0000, 0x0000, 0x0000, 0x0001], [0x0000, 0x0000, 0x0000, 0x8082], [0x8000, 0x0000, 0x0000, 0x0808a], [0x8000, 0x0000, 0x8000, 0x8000], 149 | [0x0000, 0x0000, 0x0000, 0x808b], [0x0000, 0x0000, 0x8000, 0x0001], [0x8000, 0x0000, 0x8000, 0x08081], [0x8000, 0x0000, 0x0000, 0x8009], 150 | [0x0000, 0x0000, 0x0000, 0x008a], [0x0000, 0x0000, 0x0000, 0x0088], [0x0000, 0x0000, 0x8000, 0x08009], [0x0000, 0x0000, 0x8000, 0x000a], 151 | [0x0000, 0x0000, 0x8000, 0x808b], [0x8000, 0x0000, 0x0000, 0x008b], [0x8000, 0x0000, 0x0000, 0x08089], [0x8000, 0x0000, 0x0000, 0x8003], 152 | [0x8000, 0x0000, 0x0000, 0x8002], [0x8000, 0x0000, 0x0000, 0x0080], [0x0000, 0x0000, 0x0000, 0x0800a], [0x8000, 0x0000, 0x8000, 0x000a], 153 | [0x8000, 0x0000, 0x8000, 0x8081], [0x8000, 0x0000, 0x0000, 0x8080], [0x0000, 0x0000, 0x8000, 0x00001], [0x8000, 0x0000, 0x8000, 0x8008] 154 | ]; 155 | 156 | $bc = []; 157 | for ($round = 0; $round < $rounds; $round++) { 158 | 159 | // Theta 160 | for ($i = 0; $i < 5; $i++) { 161 | $bc[$i] = [ 162 | $st[$i][0] ^ $st[$i + 5][0] ^ $st[$i + 10][0] ^ $st[$i + 15][0] ^ $st[$i + 20][0], 163 | $st[$i][1] ^ $st[$i + 5][1] ^ $st[$i + 10][1] ^ $st[$i + 15][1] ^ $st[$i + 20][1], 164 | $st[$i][2] ^ $st[$i + 5][2] ^ $st[$i + 10][2] ^ $st[$i + 15][2] ^ $st[$i + 20][2], 165 | $st[$i][3] ^ $st[$i + 5][3] ^ $st[$i + 10][3] ^ $st[$i + 15][3] ^ $st[$i + 20][3] 166 | ]; 167 | } 168 | 169 | for ($i = 0; $i < 5; $i++) { 170 | $t = [ 171 | $bc[($i + 4) % 5][0] ^ ((($bc[($i + 1) % 5][0] << 1) | ($bc[($i + 1) % 5][1] >> 15)) & (0xFFFF)), 172 | $bc[($i + 4) % 5][1] ^ ((($bc[($i + 1) % 5][1] << 1) | ($bc[($i + 1) % 5][2] >> 15)) & (0xFFFF)), 173 | $bc[($i + 4) % 5][2] ^ ((($bc[($i + 1) % 5][2] << 1) | ($bc[($i + 1) % 5][3] >> 15)) & (0xFFFF)), 174 | $bc[($i + 4) % 5][3] ^ ((($bc[($i + 1) % 5][3] << 1) | ($bc[($i + 1) % 5][0] >> 15)) & (0xFFFF)) 175 | ]; 176 | 177 | for ($j = 0; $j < 25; $j += 5) { 178 | $st[$j + $i] = [ 179 | $st[$j + $i][0] ^ $t[0], 180 | $st[$j + $i][1] ^ $t[1], 181 | $st[$j + $i][2] ^ $t[2], 182 | $st[$j + $i][3] ^ $t[3] 183 | ]; 184 | } 185 | } 186 | 187 | // Rho Pi 188 | $t = $st[1]; 189 | for ($i = 0; $i < 24; $i++) { 190 | $j = self::$keccakf_piln[$i]; 191 | $bc[0] = $st[$j]; 192 | 193 | 194 | $n = self::$keccakf_rotc[$i] >> 4; 195 | $m = self::$keccakf_rotc[$i] % 16; 196 | 197 | $st[$j] = [ 198 | ((($t[(0+$n) %4] << $m) | ($t[(1+$n) %4] >> (16-$m))) & (0xFFFF)), 199 | ((($t[(1+$n) %4] << $m) | ($t[(2+$n) %4] >> (16-$m))) & (0xFFFF)), 200 | ((($t[(2+$n) %4] << $m) | ($t[(3+$n) %4] >> (16-$m))) & (0xFFFF)), 201 | ((($t[(3+$n) %4] << $m) | ($t[(0+$n) %4] >> (16-$m))) & (0xFFFF)) 202 | ]; 203 | 204 | $t = $bc[0]; 205 | } 206 | 207 | // Chi 208 | for ($j = 0; $j < 25; $j += 5) { 209 | for ($i = 0; $i < 5; $i++) { 210 | $bc[$i] = $st[$j + $i]; 211 | } 212 | for ($i = 0; $i < 5; $i++) { 213 | $st[$j + $i] = [ 214 | $st[$j + $i][0] ^ ~$bc[($i + 1) % 5][0] & $bc[($i + 2) % 5][0], 215 | $st[$j + $i][1] ^ ~$bc[($i + 1) % 5][1] & $bc[($i + 2) % 5][1], 216 | $st[$j + $i][2] ^ ~$bc[($i + 1) % 5][2] & $bc[($i + 2) % 5][2], 217 | $st[$j + $i][3] ^ ~$bc[($i + 1) % 5][3] & $bc[($i + 2) % 5][3] 218 | ]; 219 | } 220 | } 221 | 222 | // Iota 223 | $st[0] = [ 224 | $st[0][0] ^ $keccakf_rndc[$round][0], 225 | $st[0][1] ^ $keccakf_rndc[$round][1], 226 | $st[0][2] ^ $keccakf_rndc[$round][2], 227 | $st[0][3] ^ $keccakf_rndc[$round][3] 228 | ]; 229 | } 230 | } 231 | 232 | private static function keccak32($in_raw, $capacity, $outputlength, $suffix, $raw_output) 233 | { 234 | $capacity /= 8; 235 | 236 | $inlen = self::ourStrlen($in_raw); 237 | 238 | $rsiz = 200 - 2 * $capacity; 239 | $rsizw = $rsiz / 8; 240 | 241 | $st = []; 242 | for ($i = 0; $i < 25; $i++) { 243 | $st[] = [0, 0, 0, 0]; 244 | } 245 | 246 | for ($in_t = 0; $inlen >= $rsiz; $inlen -= $rsiz, $in_t += $rsiz) { 247 | for ($i = 0; $i < $rsizw; $i++) { 248 | $t = unpack('v*', self::ourSubstr($in_raw, $i * 8 + $in_t, 8)); 249 | 250 | $st[$i] = [ 251 | $st[$i][0] ^ $t[4], 252 | $st[$i][1] ^ $t[3], 253 | $st[$i][2] ^ $t[2], 254 | $st[$i][3] ^ $t[1] 255 | ]; 256 | } 257 | 258 | self::keccakf32($st, self::KECCAK_ROUNDS); 259 | } 260 | 261 | $temp = self::ourSubstr($in_raw, $in_t, $inlen); 262 | $temp = str_pad($temp, $rsiz, "\x0", STR_PAD_RIGHT); 263 | 264 | $temp[$inlen] = chr($suffix); 265 | $temp[$rsiz - 1] = chr($temp[$rsiz - 1] | 0x80); 266 | 267 | for ($i = 0; $i < $rsizw; $i++) { 268 | $t = unpack('v*', self::ourSubstr($temp, $i * 8, 8)); 269 | 270 | $st[$i] = [ 271 | $st[$i][0] ^ $t[4], 272 | $st[$i][1] ^ $t[3], 273 | $st[$i][2] ^ $t[2], 274 | $st[$i][3] ^ $t[1] 275 | ]; 276 | } 277 | 278 | self::keccakf32($st, self::KECCAK_ROUNDS); 279 | 280 | $out = ''; 281 | for ($i = 0; $i < 25; $i++) { 282 | $out .= $t = pack('v*', $st[$i][3],$st[$i][2], $st[$i][1], $st[$i][0]); 283 | } 284 | $r = self::ourSubstr($out, 0, $outputlength / 8); 285 | 286 | return $raw_output ? $r: bin2hex($r); 287 | } 288 | 289 | // 0 = not run, 1 = 64 bit passed, 2 = 32 bit passed, 3 = failed 290 | private static $test_state = 0; 291 | private static function selfTest() 292 | { 293 | if(self::$test_state === 1 || self::$test_state === 2){ 294 | return; 295 | } 296 | 297 | if(self::$test_state === 3){ 298 | throw new \Exception('Sha3 previous self test failed!'); 299 | } 300 | 301 | $in = ''; 302 | $md = '6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7'; 303 | if(self::keccak64($in, 224, 224, 0x06, false) === $md){ 304 | self::$test_state = 1; 305 | return; 306 | } 307 | 308 | if(self::keccak32($in, 224, 224, 0x06, false) === $md){ 309 | self::$test_state = 2; 310 | return; 311 | } 312 | 313 | self::$test_state = 3; 314 | throw new \Exception('Sha3 self test failed!'); 315 | } 316 | 317 | private static function keccak($in_raw, $capacity, $outputlength, $suffix, $raw_output) 318 | { 319 | self::selfTest(); 320 | 321 | if(self::$test_state === 1) { 322 | return self::keccak64($in_raw, $capacity, $outputlength, $suffix, $raw_output); 323 | } 324 | 325 | return self::keccak32($in_raw, $capacity, $outputlength, $suffix, $raw_output); 326 | } 327 | 328 | public static function hash($in, $mdlen, $raw_output = false) 329 | { 330 | if( ! in_array($mdlen, [224, 256, 384, 512], true)) { 331 | throw new \Exception('Unsupported Sha3 Hash output size.'); 332 | } 333 | 334 | return self::keccak($in, $mdlen, $mdlen, 0x06, $raw_output); 335 | } 336 | 337 | public static function shake($in, $security_level, $outlen, $raw_output = false) 338 | { 339 | if( ! in_array($security_level, [128, 256], true)) { 340 | throw new \Exception('Unsupported Sha3 Shake security level.'); 341 | } 342 | 343 | return self::keccak($in, $security_level, $outlen, 0x1f, $raw_output); 344 | } 345 | 346 | /** 347 | * Multi-byte-safe string functions borrowed from https://github.com/sarciszewski/php-future 348 | */ 349 | 350 | /** 351 | * Multi-byte-safe string length calculation 352 | * 353 | * @param string $str 354 | * @return int 355 | */ 356 | private static function ourStrlen($str) 357 | { 358 | // Premature optimization: cache the function_exists() result 359 | static $exists = null; 360 | if ($exists === null) { 361 | $exists = \function_exists('\\mb_strlen'); 362 | } 363 | // If it exists, we need to make sure we're using 8bit mode 364 | if ($exists) { 365 | $length = \mb_strlen($str, '8bit'); 366 | if ($length === false) { 367 | throw new \Exception('mb_strlen() failed.'); 368 | } 369 | return $length; 370 | } 371 | 372 | return \strlen($str); 373 | } 374 | 375 | /** 376 | * Multi-byte-safe substring calculation 377 | * 378 | * @param string $str 379 | * @param int $start 380 | * @param int $length (optional) 381 | * @return string 382 | */ 383 | private static function ourSubstr($str, $start = 0, $length = null) 384 | { 385 | // Premature optimization: cache the function_exists() result 386 | static $exists = null; 387 | if ($exists === null) { 388 | $exists = \function_exists('\\mb_substr'); 389 | } 390 | // If it exists, we need to make sure we're using 8bit mode 391 | if ($exists) { 392 | return \mb_substr($str, $start, $length, '8bit'); 393 | } elseif ($length !== null) { 394 | return \substr($str, $start, $length); 395 | } 396 | return \substr($str, $start); 397 | } 398 | } 399 | -------------------------------------------------------------------------------- /test/Sha3Test.php: -------------------------------------------------------------------------------- 1 | [ 20 | ['','a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26'], 21 | ['The quick brown fox jumps over the lazy dog', '01dedd5de4ef14642445ba5f5b97c15e47b9ad931326e4b0727cd94cefc44fff23f07bf543139939b49128caf436dc1bdee54fcb24023a08d9403f9b4bf0d450'], 22 | ['The quick brown fox jumps over the lazy dog.','18f4f4bd419603f95538837003d9d254c26c23765565162247483f65c50303597bc9ce4d289f21d1c2f1f458828e33dc442100331b35e7eb031b5d38ba6460f8'], 23 | [hex2bin(Sha3Test::short), '001618372e75147af90c0cf16c3bbdaa069ddbc62483b392d028ded49f75084a5dfcc53aecd9f57ddbb73daa041fd71089d8fb5edf6cfaf6f1e4e25ad3de266c'], 24 | [hex2bin(Sha3Test::long), '6e8b8bd195bdd560689af2348bdc74ab7cd05ed8b9a57711e9be71e9726fda4591fee12205edacaf82ffbbaf16dff9e702a708862080166c2ff6ba379bc7ffc2'] 25 | ], 26 | 384 => [ 27 | ['', '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004'], 28 | ['The quick brown fox jumps over the lazy dog', '7063465e08a93bce31cd89d2e3ca8f602498696e253592ed26f07bf7e703cf328581e1471a7ba7ab119b1a9ebdf8be41'], 29 | ['The quick brown fox jumps over the lazy dog.', '1a34d81695b622df178bc74df7124fe12fac0f64ba5250b78b99c1273d4b080168e10652894ecad5f1f4d5b965437fb9'], 30 | [hex2bin(Sha3Test::short), 'feee2ef332515284e0ba247c62f264199044d03877c58e54b51a62e39e91c27aaae384837eb9d479b4c0308cfc6b779b'], 31 | [hex2bin(Sha3Test::long), '128dc611762be9b135b3739484cfaadca7481d68514f3dfd6f5d78bb1863ae68130835cdc7061a7ed964b32f1db75ee1'], 32 | [hex2bin('E35780EB9799AD4C77535D4DDB683CF33EF367715327CF4C4A58ED9CBDCDD486F669F80189D549A9364FA82A51A52654EC721BB3AAB95DCEB4A86A6AFA93826DB923517E928F33E3FBA850D45660EF83B9876ACCAFA2A9987A254B137C6E140A21691E1069413848'), 'd1c0fa85c8d183beff99ad9d752b263e286b477f79f0710b010317017397813344b99daf3bb7b1bc5e8d722bac85943a'], 33 | ], 34 | 256 => [ 35 | ['', 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a'], 36 | ['The quick brown fox jumps over the lazy dog', '69070dda01975c8c120c3aada1b282394e7f032fa9cf32f4cb2259a0897dfc04'], 37 | ['The quick brown fox jumps over the lazy dog.', 'a80f839cd4f83f6c3dafc87feae470045e4eb0d366397d5c6ce34ba1739f734d'], 38 | [hex2bin(Sha3Test::short), '2c7e7cb356fdc68ec8927e499d2a6bae2b781817919c829ebbe8225baed46967'], 39 | [hex2bin(Sha3Test::long), 'c11f3522a8fb7b3532d80b6d40023a92b489addad93bf5d64b23f35e9663521c'], 40 | [hex2bin('9F2FCC7C90DE090D6B87CD7E9718C1EA6CB21118FC2D5DE9F97E5DB6AC1E9C10'), '2f1a5f7159e34ea19cddc70ebf9b81f1a66db40615d7ead3cc1f1b954d82a3af'], 41 | ], 42 | 224 => [ 43 | ['', '6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7'], 44 | ['The quick brown fox jumps over the lazy dog', 'd15dadceaa4d5d7bb3b48f446421d542e08ad8887305e28d58335795'], 45 | ['The quick brown fox jumps over the lazy dog.', '2d0708903833afabdd232a20201176e8b58c5be8a6fe74265ac54db0'], 46 | [hex2bin(Sha3Test::short), 'b1571bed52e54eef377d99df7be4bc6682c43387f2bf9acc92df608f'], 47 | [hex2bin(Sha3Test::long), '94689ea9f347dda8dd798a858605868743c6bd03a6a65c6085d52bed'], 48 | ], 49 | 50 | ]; 51 | 52 | foreach($v as $bitsize => $vectors){ 53 | foreach($vectors as $testcase){ 54 | $this->assertEquals(Sha3::hash($testcase[0], $bitsize), $testcase[1]); 55 | 56 | $this->assertEquals(Sha3::hash($testcase[0], $bitsize, true), hex2bin($testcase[1])); 57 | 58 | $class = new \ReflectionClass('\bb\Sha3\Sha3'); 59 | $p = $class->getProperty('test_state'); 60 | $p->setAccessible(true); 61 | 62 | $p->setValue(1); 63 | $this->assertEquals(Sha3::hash($testcase[0], $bitsize), $testcase[1]); 64 | 65 | $p->setValue(2); 66 | $this->assertEquals(Sha3::hash($testcase[0], $bitsize), $testcase[1]); 67 | } 68 | } 69 | } 70 | 71 | public function testShake() 72 | { 73 | $v = [ 74 | 128 => [ 75 | [256, '', '7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26'], 76 | [256, hex2bin(Sha3Test::short), '3a0faca70c9d2b81d1064d429ea3b05ad27366f64985379ddd75bc73d6a83810'], 77 | [256, hex2bin(Sha3Test::long), '14236e75b9784df4f57935f945356cbe383fe513ed30286f91060759bcb0ef4b'], 78 | [256, 'The quick brown fox jumps over the lazy dog', 'f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e'], 79 | [256, 'The quick brown fox jumps over the lazy dof', '853f4538be0db9621a6cea659a06c1107b1f83f02b13d18297bd39d7411cf10c'], 80 | ], 81 | 256 => [ 82 | [512, '', '46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be'], 83 | [512, hex2bin(Sha3Test::short), '57119c4507f975ad0e9ea4f1166e5f9b590bf2671aaeb41d130d2c570bafc579b0b9ec485cc736a0a848bbc886cbaa79ffcd067ce64b3b410741ab011c544225'], 84 | [512, hex2bin(Sha3Test::long), '8a5199b4a7e133e264a86202720655894d48cff344a928cf8347f48379cef347dfc5bcffab99b27b1f89aa2735e23d30088ffa03b9edb02b9635470ab9f10389'], 85 | ] 86 | ]; 87 | 88 | foreach($v as $bitsize => $vectors){ 89 | foreach($vectors as $testcase){ 90 | $this->assertEquals(Sha3::shake($testcase[1], $bitsize, $testcase[0]), $testcase[2]); 91 | 92 | $this->assertEquals(Sha3::shake($testcase[1], $bitsize, $testcase[0], true), hex2bin($testcase[2])); 93 | 94 | $class = new \ReflectionClass('\bb\Sha3\Sha3'); 95 | $p = $class->getProperty('test_state'); 96 | $p->setAccessible(true); 97 | 98 | $p->setValue(1); 99 | $this->assertEquals(Sha3::shake($testcase[1], $bitsize, $testcase[0]), $testcase[2]); 100 | 101 | $p->setValue(2); 102 | $this->assertEquals(Sha3::shake($testcase[1], $bitsize, $testcase[0]), $testcase[2]); 103 | } 104 | } 105 | } 106 | 107 | public function testSelfTestException() 108 | { 109 | //reset test_state 110 | $class = new \ReflectionClass('\bb\Sha3\Sha3'); 111 | $p = $class->getProperty('test_state'); 112 | $p->setAccessible(true); 113 | $p->setValue(0); 114 | 115 | 116 | //break test 117 | $p = $class->getProperty('keccakf_rotc'); 118 | $p->setAccessible(true); 119 | $p->setValue([2, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44]); 120 | 121 | 122 | try { 123 | Sha3::hash('',224); 124 | } 125 | catch (\Exception $e){ 126 | $this->assertEquals($e->getMessage(), 'Sha3 self test failed!'); 127 | 128 | $p = $class->getProperty('test_state'); 129 | $p->setAccessible(true); 130 | 131 | $this->assertEquals($p->getValue(), 3); 132 | 133 | //correct test 134 | $p->setValue([1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44]); 135 | return; 136 | } 137 | 138 | //correct test 139 | $p->setValue([1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44]); 140 | $this->assertTrue(false); 141 | 142 | } 143 | 144 | public function testSelfTestPreviousFailure() 145 | { 146 | //reset test_state 147 | $class = new \ReflectionClass('\bb\Sha3\Sha3'); 148 | $p = $class->getProperty('test_state'); 149 | $p->setAccessible(true); 150 | $p->setValue(3); 151 | 152 | $this->setExpectedException('Exception', 'Sha3 previous self test failed!'); 153 | Sha3::hash('',224); 154 | } 155 | 156 | 157 | public function testUnsupportedHashOutputSize() 158 | { 159 | $this->setExpectedException('Exception', 'Unsupported Sha3 Hash output size.'); 160 | Sha3::hash('',225); 161 | } 162 | 163 | public function testUnsupportedShakeSecurityLevel() 164 | { 165 | $this->setExpectedException('Exception', 'Unsupported Sha3 Shake security level.'); 166 | Sha3::shake('',129, 256); 167 | } 168 | } --------------------------------------------------------------------------------