22
33namespace kornrunner ;
44
5+ use Exception ;
6+ use function mb_strlen ;
7+ use function mb_substr ;
8+
59final class Keccak
610{
711 private const KECCAK_ROUNDS = 24 ;
812 private const LFSR = 0x01 ;
13+ private const ENCODING = '8bit ' ;
914 private static $ keccakf_rotc = [1 , 3 , 6 , 10 , 15 , 21 , 28 , 36 , 45 , 55 , 2 , 14 , 27 , 41 , 56 , 8 , 25 , 43 , 62 , 18 , 39 , 61 , 20 , 44 ];
1015 private static $ keccakf_piln = [10 , 7 , 11 , 17 , 18 , 3 , 5 , 16 , 8 , 21 , 24 , 4 , 15 , 23 , 19 , 13 , 12 ,2 , 20 , 14 , 22 , 9 , 6 , 1 ];
16+ private static $ x64 = (PHP_INT_SIZE === 8 );
1117
12- private static function keccakf64 (&$ st , $ rounds )
13- {
18+ private static function keccakf64 (&$ st , $ rounds ): void {
1419 $ keccakf_rndc = [
1520 [0x00000000 , 0x00000001 ], [0x00000000 , 0x00008082 ], [0x80000000 , 0x0000808a ], [0x80000000 , 0x80008000 ],
1621 [0x00000000 , 0x0000808b ], [0x00000000 , 0x80000001 ], [0x80000000 , 0x80008081 ], [0x80000000 , 0x00008009 ],
@@ -90,11 +95,10 @@ private static function keccakf64(&$st, $rounds)
9095 }
9196 }
9297
93- private static function keccak64 ($ in_raw , $ capacity , $ outputlength , $ suffix , $ raw_output )
94- {
98+ private static function keccak64 ($ in_raw , int $ capacity , int $ outputlength , $ suffix , bool $ raw_output ): string {
9599 $ capacity /= 8 ;
96100
97- $ inlen = self :: ourStrlen ($ in_raw );
101+ $ inlen = mb_strlen ($ in_raw, self :: ENCODING );
98102
99103 $ rsiz = 200 - 2 * $ capacity ;
100104 $ rsizw = $ rsiz / 8 ;
@@ -106,7 +110,7 @@ private static function keccak64($in_raw, $capacity, $outputlength, $suffix, $ra
106110
107111 for ($ in_t = 0 ; $ inlen >= $ rsiz ; $ inlen -= $ rsiz , $ in_t += $ rsiz ) {
108112 for ($ i = 0 ; $ i < $ rsizw ; $ i ++) {
109- $ t = unpack ('V* ' , self :: ourSubstr ($ in_raw , $ i * 8 + $ in_t , 8 ));
113+ $ t = unpack ('V* ' , mb_substr ($ in_raw , $ i * 8 + $ in_t , 8 , self :: ENCODING ));
110114
111115 $ st [$ i ] = [
112116 $ st [$ i ][0 ] ^ $ t [2 ],
@@ -117,14 +121,14 @@ private static function keccak64($in_raw, $capacity, $outputlength, $suffix, $ra
117121 self ::keccakf64 ($ st , self ::KECCAK_ROUNDS );
118122 }
119123
120- $ temp = self :: ourSubstr ($ in_raw , $ in_t , $ inlen );
124+ $ temp = mb_substr ($ in_raw , $ in_t , $ inlen, self :: ENCODING );
121125 $ temp = str_pad ($ temp , $ rsiz , "\x0" , STR_PAD_RIGHT );
122126
123127 $ temp [$ inlen ] = chr ($ suffix );
124128 $ temp [$ rsiz - 1 ] = chr (ord ($ temp [$ rsiz - 1 ]) | 0x80 );
125129
126130 for ($ i = 0 ; $ i < $ rsizw ; $ i ++) {
127- $ t = unpack ('V* ' , self :: ourSubstr ($ temp , $ i * 8 , 8 ));
131+ $ t = unpack ('V* ' , mb_substr ($ temp , $ i * 8 , 8 , self :: ENCODING ));
128132
129133 $ st [$ i ] = [
130134 $ st [$ i ][0 ] ^ $ t [2 ],
@@ -138,13 +142,12 @@ private static function keccak64($in_raw, $capacity, $outputlength, $suffix, $ra
138142 for ($ i = 0 ; $ i < 25 ; $ i ++) {
139143 $ out .= $ t = pack ('V* ' , $ st [$ i ][1 ], $ st [$ i ][0 ]);
140144 }
141- $ r = self :: ourSubstr ($ out , 0 , $ outputlength / 8 );
145+ $ r = mb_substr ($ out , 0 , $ outputlength / 8 , self :: ENCODING );
142146
143147 return $ raw_output ? $ r : bin2hex ($ r );
144148 }
145149
146- private static function keccakf32 (&$ st , $ rounds )
147- {
150+ private static function keccakf32 (&$ st , $ rounds ): void {
148151 $ keccakf_rndc = [
149152 [0x0000 , 0x0000 , 0x0000 , 0x0001 ], [0x0000 , 0x0000 , 0x0000 , 0x8082 ], [0x8000 , 0x0000 , 0x0000 , 0x0808a ], [0x8000 , 0x0000 , 0x8000 , 0x8000 ],
150153 [0x0000 , 0x0000 , 0x0000 , 0x808b ], [0x0000 , 0x0000 , 0x8000 , 0x0001 ], [0x8000 , 0x0000 , 0x8000 , 0x08081 ], [0x8000 , 0x0000 , 0x0000 , 0x8009 ],
@@ -230,11 +233,10 @@ private static function keccakf32(&$st, $rounds)
230233 }
231234 }
232235
233- private static function keccak32 ($ in_raw , $ capacity , $ outputlength , $ suffix , $ raw_output )
234- {
236+ private static function keccak32 ($ in_raw , int $ capacity , int $ outputlength , $ suffix , bool $ raw_output ): string {
235237 $ capacity /= 8 ;
236238
237- $ inlen = self :: ourStrlen ($ in_raw );
239+ $ inlen = mb_strlen ($ in_raw, self :: ENCODING );
238240
239241 $ rsiz = 200 - 2 * $ capacity ;
240242 $ rsizw = $ rsiz / 8 ;
@@ -246,7 +248,7 @@ private static function keccak32($in_raw, $capacity, $outputlength, $suffix, $ra
246248
247249 for ($ in_t = 0 ; $ inlen >= $ rsiz ; $ inlen -= $ rsiz , $ in_t += $ rsiz ) {
248250 for ($ i = 0 ; $ i < $ rsizw ; $ i ++) {
249- $ t = unpack ('v* ' , self :: ourSubstr ($ in_raw , $ i * 8 + $ in_t , 8 ));
251+ $ t = unpack ('v* ' , mb_substr ($ in_raw , $ i * 8 + $ in_t , 8 , self :: ENCODING ));
250252
251253 $ st [$ i ] = [
252254 $ st [$ i ][0 ] ^ $ t [4 ],
@@ -259,14 +261,14 @@ private static function keccak32($in_raw, $capacity, $outputlength, $suffix, $ra
259261 self ::keccakf32 ($ st , self ::KECCAK_ROUNDS );
260262 }
261263
262- $ temp = self :: ourSubstr ($ in_raw , $ in_t , $ inlen );
264+ $ temp = mb_substr ($ in_raw , $ in_t , $ inlen, self :: ENCODING );
263265 $ temp = str_pad ($ temp , $ rsiz , "\x0" , STR_PAD_RIGHT );
264266
265267 $ temp [$ inlen ] = chr ($ suffix );
266268 $ temp [$ rsiz - 1 ] = chr ((int ) $ temp [$ rsiz - 1 ] | 0x80 );
267269
268270 for ($ i = 0 ; $ i < $ rsizw ; $ i ++) {
269- $ t = unpack ('v* ' , self :: ourSubstr ($ temp , $ i * 8 , 8 ));
271+ $ t = unpack ('v* ' , mb_substr ($ temp , $ i * 8 , 8 , self :: ENCODING ));
270272
271273 $ st [$ i ] = [
272274 $ st [$ i ][0 ] ^ $ t [4 ],
@@ -282,118 +284,31 @@ private static function keccak32($in_raw, $capacity, $outputlength, $suffix, $ra
282284 for ($ i = 0 ; $ i < 25 ; $ i ++) {
283285 $ out .= $ t = pack ('v* ' , $ st [$ i ][3 ],$ st [$ i ][2 ], $ st [$ i ][1 ], $ st [$ i ][0 ]);
284286 }
285- $ r = self :: ourSubstr ($ out , 0 , $ outputlength / 8 );
287+ $ r = mb_substr ($ out , 0 , $ outputlength / 8 , self :: ENCODING );
286288
287289 return $ raw_output ? $ r : bin2hex ($ r );
288290 }
289291
290- // 0 = not run, 1 = 64 bit passed, 2 = 32 bit passed, 3 = failed
291- private static $ test_state = 0 ;
292- private static function selfTest ()
293- {
294- if (self ::$ test_state === 1 || self ::$ test_state === 2 ){
295- return ;
296- }
297-
298- if (self ::$ test_state === 3 ){
299- throw new \Exception ('Keccak previous self test failed! ' );
300- }
301-
302- $ in = '' ;
303- $ md = 'f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd ' ;
304- if (self ::keccak64 ($ in , 224 , 224 , self ::LFSR , false ) === $ md ){
305- self ::$ test_state = 1 ;
306- return ;
307- }
308-
309- if (self ::keccak32 ($ in , 224 , 224 , self ::LFSR , false ) === $ md ){
310- self ::$ test_state = 2 ;
311- return ;
312- }
313-
314- self ::$ test_state = 3 ;
315- throw new \Exception ('Keccak self test failed! ' );
292+ private static function keccak ($ in_raw , int $ capacity , int $ outputlength , $ suffix , bool $ raw_output ): string {
293+ return self ::$ x64
294+ ? self ::keccak64 ($ in_raw , $ capacity , $ outputlength , $ suffix , $ raw_output )
295+ : self ::keccak32 ($ in_raw , $ capacity , $ outputlength , $ suffix , $ raw_output );
316296 }
317297
318- private static function keccak ($ in_raw , $ capacity , $ outputlength , $ suffix , $ raw_output )
319- {
320- self ::selfTest ();
321-
322- if (self ::$ test_state === 1 ) {
323- return self ::keccak64 ($ in_raw , $ capacity , $ outputlength , $ suffix , $ raw_output );
324- }
325-
326- return self ::keccak32 ($ in_raw , $ capacity , $ outputlength , $ suffix , $ raw_output );
327- }
328-
329- public static function hash ($ in , $ mdlen , $ raw_output = false )
330- {
331- if ( ! in_array ($ mdlen , [224 , 256 , 384 , 512 ], true )) {
332- throw new \Exception ('Unsupported Keccak Hash output size. ' );
298+ public static function hash ($ in , int $ mdlen , bool $ raw_output = false ): string {
299+ if (!in_array ($ mdlen , [224 , 256 , 384 , 512 ], true )) {
300+ throw new Exception ('Unsupported Keccak Hash output size. ' );
333301 }
334302
335303 return self ::keccak ($ in , $ mdlen , $ mdlen , self ::LFSR , $ raw_output );
336304 }
337305
338- public static function shake ($ in , $ security_level , $ outlen , $ raw_output = false )
339- {
340- if ( ! in_array ($ security_level , [128 , 256 ], true )) {
341- throw new \Exception ('Unsupported Keccak Shake security level. ' );
306+ public static function shake ($ in , int $ security_level , int $ outlen , bool $ raw_output = false ): string {
307+ if (!in_array ($ security_level , [128 , 256 ], true )) {
308+ throw new Exception ('Unsupported Keccak Shake security level. ' );
342309 }
343310
344311 return self ::keccak ($ in , $ security_level , $ outlen , 0x1f , $ raw_output );
345312 }
346313
347- /**
348- * Multi-byte-safe string functions borrowed from https://github.com/sarciszewski/php-future
349- */
350-
351- /**
352- * Multi-byte-safe string length calculation
353- *
354- * @param string $str
355- * @return int
356- */
357- private static function ourStrlen ($ str )
358- {
359- // Premature optimization: cache the function_exists() result
360- static $ exists = null ;
361- if ($ exists === null ) {
362- $ exists = \function_exists ('\\mb_strlen ' );
363- }
364- // If it exists, we need to make sure we're using 8bit mode
365- if ($ exists ) {
366- $ length = \mb_strlen ($ str , '8bit ' );
367- if ($ length === false ) {
368- throw new \Exception ('mb_strlen() failed. ' );
369- }
370- return $ length ;
371- }
372-
373- return \strlen ($ str );
374- }
375-
376- /**
377- * Multi-byte-safe substring calculation
378- *
379- * @param string $str
380- * @param int $start
381- * @param int $length (optional)
382- * @return string
383- */
384- private static function ourSubstr ($ str , $ start = 0 , $ length = null )
385- {
386- // Premature optimization: cache the function_exists() result
387- static $ exists = null ;
388- if ($ exists === null ) {
389- $ exists = \function_exists ('\\mb_substr ' );
390- }
391- // If it exists, we need to make sure we're using 8bit mode
392- if ($ exists ) {
393- return \mb_substr ($ str , $ start , $ length , '8bit ' );
394- } elseif ($ length !== null ) {
395- return \substr ($ str , $ start , $ length );
396- }
397- return \substr ($ str , $ start );
398- }
399314}
0 commit comments