Spaces:
Sleeping
Sleeping
if (class_exists('ParagonIE_Sodium_Core_SipHash', false)) { | |
return; | |
} | |
/** | |
* Class ParagonIE_SodiumCompat_Core_SipHash | |
* | |
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers | |
*/ | |
class ParagonIE_Sodium_Core_SipHash extends ParagonIE_Sodium_Core_Util | |
{ | |
/** | |
* @internal You should not use this directly from another application | |
* | |
* @param int[] $v | |
* @return int[] | |
* | |
*/ | |
public static function sipRound(array $v) | |
{ | |
# v0 += v1; | |
list($v[0], $v[1]) = self::add( | |
array($v[0], $v[1]), | |
array($v[2], $v[3]) | |
); | |
# v1=ROTL(v1,13); | |
list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 13); | |
# v1 ^= v0; | |
$v[2] = (int) $v[2] ^ (int) $v[0]; | |
$v[3] = (int) $v[3] ^ (int) $v[1]; | |
# v0=ROTL(v0,32); | |
list($v[0], $v[1]) = self::rotl_64((int) $v[0], (int) $v[1], 32); | |
# v2 += v3; | |
list($v[4], $v[5]) = self::add( | |
array((int) $v[4], (int) $v[5]), | |
array((int) $v[6], (int) $v[7]) | |
); | |
# v3=ROTL(v3,16); | |
list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 16); | |
# v3 ^= v2; | |
$v[6] = (int) $v[6] ^ (int) $v[4]; | |
$v[7] = (int) $v[7] ^ (int) $v[5]; | |
# v0 += v3; | |
list($v[0], $v[1]) = self::add( | |
array((int) $v[0], (int) $v[1]), | |
array((int) $v[6], (int) $v[7]) | |
); | |
# v3=ROTL(v3,21); | |
list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 21); | |
# v3 ^= v0; | |
$v[6] = (int) $v[6] ^ (int) $v[0]; | |
$v[7] = (int) $v[7] ^ (int) $v[1]; | |
# v2 += v1; | |
list($v[4], $v[5]) = self::add( | |
array((int) $v[4], (int) $v[5]), | |
array((int) $v[2], (int) $v[3]) | |
); | |
# v1=ROTL(v1,17); | |
list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 17); | |
# v1 ^= v2;; | |
$v[2] = (int) $v[2] ^ (int) $v[4]; | |
$v[3] = (int) $v[3] ^ (int) $v[5]; | |
# v2=ROTL(v2,32) | |
list($v[4], $v[5]) = self::rotl_64((int) $v[4], (int) $v[5], 32); | |
return $v; | |
} | |
/** | |
* Add two 32 bit integers representing a 64-bit integer. | |
* | |
* @internal You should not use this directly from another application | |
* | |
* @param int[] $a | |
* @param int[] $b | |
* @return array<int, mixed> | |
*/ | |
public static function add(array $a, array $b) | |
{ | |
/** @var int $x1 */ | |
$x1 = $a[1] + $b[1]; | |
/** @var int $c */ | |
$c = $x1 >> 32; // Carry if ($a + $b) > 0xffffffff | |
/** @var int $x0 */ | |
$x0 = $a[0] + $b[0] + $c; | |
return array( | |
$x0 & 0xffffffff, | |
$x1 & 0xffffffff | |
); | |
} | |
/** | |
* @internal You should not use this directly from another application | |
* | |
* @param int $int0 | |
* @param int $int1 | |
* @param int $c | |
* @return array<int, mixed> | |
*/ | |
public static function rotl_64($int0, $int1, $c) | |
{ | |
$int0 &= 0xffffffff; | |
$int1 &= 0xffffffff; | |
$c &= 63; | |
if ($c === 32) { | |
return array($int1, $int0); | |
} | |
if ($c > 31) { | |
$tmp = $int1; | |
$int1 = $int0; | |
$int0 = $tmp; | |
$c &= 31; | |
} | |
if ($c === 0) { | |
return array($int0, $int1); | |
} | |
return array( | |
0xffffffff & ( | |
($int0 << $c) | |
| | |
($int1 >> (32 - $c)) | |
), | |
0xffffffff & ( | |
($int1 << $c) | |
| | |
($int0 >> (32 - $c)) | |
), | |
); | |
} | |
/** | |
* Implements Siphash-2-4 using only 32-bit numbers. | |
* | |
* When we split an int into two, the higher bits go to the lower index. | |
* e.g. 0xDEADBEEFAB10C92D becomes [ | |
* 0 => 0xDEADBEEF, | |
* 1 => 0xAB10C92D | |
* ]. | |
* | |
* @internal You should not use this directly from another application | |
* | |
* @param string $in | |
* @param string $key | |
* @return string | |
* @throws SodiumException | |
* @throws TypeError | |
*/ | |
public static function sipHash24($in, $key) | |
{ | |
$inlen = self::strlen($in); | |
# /* "somepseudorandomlygeneratedbytes" */ | |
# u64 v0 = 0x736f6d6570736575ULL; | |
# u64 v1 = 0x646f72616e646f6dULL; | |
# u64 v2 = 0x6c7967656e657261ULL; | |
# u64 v3 = 0x7465646279746573ULL; | |
$v = array( | |
0x736f6d65, // 0 | |
0x70736575, // 1 | |
0x646f7261, // 2 | |
0x6e646f6d, // 3 | |
0x6c796765, // 4 | |
0x6e657261, // 5 | |
0x74656462, // 6 | |
0x79746573 // 7 | |
); | |
// v0 => $v[0], $v[1] | |
// v1 => $v[2], $v[3] | |
// v2 => $v[4], $v[5] | |
// v3 => $v[6], $v[7] | |
# u64 k0 = LOAD64_LE( k ); | |
# u64 k1 = LOAD64_LE( k + 8 ); | |
$k = array( | |
self::load_4(self::substr($key, 4, 4)), | |
self::load_4(self::substr($key, 0, 4)), | |
self::load_4(self::substr($key, 12, 4)), | |
self::load_4(self::substr($key, 8, 4)) | |
); | |
// k0 => $k[0], $k[1] | |
// k1 => $k[2], $k[3] | |
# b = ( ( u64 )inlen ) << 56; | |
$b = array( | |
$inlen << 24, | |
0 | |
); | |
// See docblock for why the 0th index gets the higher bits. | |
# v3 ^= k1; | |
$v[6] ^= $k[2]; | |
$v[7] ^= $k[3]; | |
# v2 ^= k0; | |
$v[4] ^= $k[0]; | |
$v[5] ^= $k[1]; | |
# v1 ^= k1; | |
$v[2] ^= $k[2]; | |
$v[3] ^= $k[3]; | |
# v0 ^= k0; | |
$v[0] ^= $k[0]; | |
$v[1] ^= $k[1]; | |
$left = $inlen; | |
# for ( ; in != end; in += 8 ) | |
while ($left >= 8) { | |
# m = LOAD64_LE( in ); | |
$m = array( | |
self::load_4(self::substr($in, 4, 4)), | |
self::load_4(self::substr($in, 0, 4)) | |
); | |
# v3 ^= m; | |
$v[6] ^= $m[0]; | |
$v[7] ^= $m[1]; | |
# SIPROUND; | |
# SIPROUND; | |
$v = self::sipRound($v); | |
$v = self::sipRound($v); | |
# v0 ^= m; | |
$v[0] ^= $m[0]; | |
$v[1] ^= $m[1]; | |
$in = self::substr($in, 8); | |
$left -= 8; | |
} | |
# switch( left ) | |
# { | |
# case 7: b |= ( ( u64 )in[ 6] ) << 48; | |
# case 6: b |= ( ( u64 )in[ 5] ) << 40; | |
# case 5: b |= ( ( u64 )in[ 4] ) << 32; | |
# case 4: b |= ( ( u64 )in[ 3] ) << 24; | |
# case 3: b |= ( ( u64 )in[ 2] ) << 16; | |
# case 2: b |= ( ( u64 )in[ 1] ) << 8; | |
# case 1: b |= ( ( u64 )in[ 0] ); break; | |
# case 0: break; | |
# } | |
switch ($left) { | |
case 7: | |
$b[0] |= self::chrToInt($in[6]) << 16; | |
case 6: | |
$b[0] |= self::chrToInt($in[5]) << 8; | |
case 5: | |
$b[0] |= self::chrToInt($in[4]); | |
case 4: | |
$b[1] |= self::chrToInt($in[3]) << 24; | |
case 3: | |
$b[1] |= self::chrToInt($in[2]) << 16; | |
case 2: | |
$b[1] |= self::chrToInt($in[1]) << 8; | |
case 1: | |
$b[1] |= self::chrToInt($in[0]); | |
case 0: | |
break; | |
} | |
// See docblock for why the 0th index gets the higher bits. | |
# v3 ^= b; | |
$v[6] ^= $b[0]; | |
$v[7] ^= $b[1]; | |
# SIPROUND; | |
# SIPROUND; | |
$v = self::sipRound($v); | |
$v = self::sipRound($v); | |
# v0 ^= b; | |
$v[0] ^= $b[0]; | |
$v[1] ^= $b[1]; | |
// Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation | |
# v2 ^= 0xff; | |
$v[5] ^= 0xff; | |
# SIPROUND; | |
# SIPROUND; | |
# SIPROUND; | |
# SIPROUND; | |
$v = self::sipRound($v); | |
$v = self::sipRound($v); | |
$v = self::sipRound($v); | |
$v = self::sipRound($v); | |
# b = v0 ^ v1 ^ v2 ^ v3; | |
# STORE64_LE( out, b ); | |
return self::store32_le($v[1] ^ $v[3] ^ $v[5] ^ $v[7]) . | |
self::store32_le($v[0] ^ $v[2] ^ $v[4] ^ $v[6]); | |
} | |
} | |