balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

SipHash.php (8233B)


      1 <?php
      2 
      3 if (class_exists('ParagonIE_Sodium_Core_SipHash', false)) {
      4     return;
      5 }
      6 
      7 /**
      8  * Class ParagonIE_SodiumCompat_Core_SipHash
      9  *
     10  * Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers
     11  */
     12 class ParagonIE_Sodium_Core_SipHash extends ParagonIE_Sodium_Core_Util
     13 {
     14     /**
     15      * @internal You should not use this directly from another application
     16      *
     17      * @param int[] $v
     18      * @return int[]
     19      *
     20      */
     21     public static function sipRound(array $v)
     22     {
     23         # v0 += v1;
     24         list($v[0], $v[1]) = self::add(
     25             array($v[0], $v[1]),
     26             array($v[2], $v[3])
     27         );
     28 
     29         #  v1=ROTL(v1,13);
     30         list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 13);
     31 
     32         #  v1 ^= v0;
     33         $v[2] = (int) $v[2] ^ (int) $v[0];
     34         $v[3] = (int) $v[3] ^ (int) $v[1];
     35 
     36         #  v0=ROTL(v0,32);
     37         list($v[0], $v[1]) = self::rotl_64((int) $v[0], (int) $v[1], 32);
     38 
     39         # v2 += v3;
     40         list($v[4], $v[5]) = self::add(
     41             array((int) $v[4], (int) $v[5]),
     42             array((int) $v[6], (int) $v[7])
     43         );
     44 
     45         # v3=ROTL(v3,16);
     46         list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 16);
     47 
     48         #  v3 ^= v2;
     49         $v[6] = (int) $v[6] ^ (int) $v[4];
     50         $v[7] = (int) $v[7] ^ (int) $v[5];
     51 
     52         # v0 += v3;
     53         list($v[0], $v[1]) = self::add(
     54             array((int) $v[0], (int) $v[1]),
     55             array((int) $v[6], (int) $v[7])
     56         );
     57 
     58         # v3=ROTL(v3,21);
     59         list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 21);
     60 
     61         # v3 ^= v0;
     62         $v[6] = (int) $v[6] ^ (int) $v[0];
     63         $v[7] = (int) $v[7] ^ (int) $v[1];
     64 
     65         # v2 += v1;
     66         list($v[4], $v[5]) = self::add(
     67             array((int) $v[4], (int) $v[5]),
     68             array((int) $v[2], (int) $v[3])
     69         );
     70 
     71         # v1=ROTL(v1,17);
     72         list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 17);
     73 
     74         #  v1 ^= v2;;
     75         $v[2] = (int) $v[2] ^ (int) $v[4];
     76         $v[3] = (int) $v[3] ^ (int) $v[5];
     77 
     78         # v2=ROTL(v2,32)
     79         list($v[4], $v[5]) = self::rotl_64((int) $v[4], (int) $v[5], 32);
     80 
     81         return $v;
     82     }
     83 
     84     /**
     85      * Add two 32 bit integers representing a 64-bit integer.
     86      *
     87      * @internal You should not use this directly from another application
     88      *
     89      * @param int[] $a
     90      * @param int[] $b
     91      * @return array<int, mixed>
     92      */
     93     public static function add(array $a, array $b)
     94     {
     95         /** @var int $x1 */
     96         $x1 = $a[1] + $b[1];
     97         /** @var int $c */
     98         $c = $x1 >> 32; // Carry if ($a + $b) > 0xffffffff
     99         /** @var int $x0 */
    100         $x0 = $a[0] + $b[0] + $c;
    101         return array(
    102             $x0 & 0xffffffff,
    103             $x1 & 0xffffffff
    104         );
    105     }
    106 
    107     /**
    108      * @internal You should not use this directly from another application
    109      *
    110      * @param int $int0
    111      * @param int $int1
    112      * @param int $c
    113      * @return array<int, mixed>
    114      */
    115     public static function rotl_64($int0, $int1, $c)
    116     {
    117         $int0 &= 0xffffffff;
    118         $int1 &= 0xffffffff;
    119         $c &= 63;
    120         if ($c === 32) {
    121             return array($int1, $int0);
    122         }
    123         if ($c > 31) {
    124             $tmp = $int1;
    125             $int1 = $int0;
    126             $int0 = $tmp;
    127             $c &= 31;
    128         }
    129         if ($c === 0) {
    130             return array($int0, $int1);
    131         }
    132         return array(
    133             0xffffffff & (
    134                 ($int0 << $c)
    135                     |
    136                 ($int1 >> (32 - $c))
    137             ),
    138             0xffffffff & (
    139                 ($int1 << $c)
    140                     |
    141                 ($int0 >> (32 - $c))
    142             ),
    143         );
    144     }
    145 
    146     /**
    147      * Implements Siphash-2-4 using only 32-bit numbers.
    148      *
    149      * When we split an int into two, the higher bits go to the lower index.
    150      * e.g. 0xDEADBEEFAB10C92D becomes [
    151      *     0 => 0xDEADBEEF,
    152      *     1 => 0xAB10C92D
    153      * ].
    154      *
    155      * @internal You should not use this directly from another application
    156      *
    157      * @param string $in
    158      * @param string $key
    159      * @return string
    160      * @throws SodiumException
    161      * @throws TypeError
    162      */
    163     public static function sipHash24($in, $key)
    164     {
    165         $inlen = self::strlen($in);
    166 
    167         # /* "somepseudorandomlygeneratedbytes" */
    168         # u64 v0 = 0x736f6d6570736575ULL;
    169         # u64 v1 = 0x646f72616e646f6dULL;
    170         # u64 v2 = 0x6c7967656e657261ULL;
    171         # u64 v3 = 0x7465646279746573ULL;
    172         $v = array(
    173             0x736f6d65, // 0
    174             0x70736575, // 1
    175             0x646f7261, // 2
    176             0x6e646f6d, // 3
    177             0x6c796765, // 4
    178             0x6e657261, // 5
    179             0x74656462, // 6
    180             0x79746573  // 7
    181         );
    182         // v0 => $v[0], $v[1]
    183         // v1 => $v[2], $v[3]
    184         // v2 => $v[4], $v[5]
    185         // v3 => $v[6], $v[7]
    186 
    187         # u64 k0 = LOAD64_LE( k );
    188         # u64 k1 = LOAD64_LE( k + 8 );
    189         $k = array(
    190             self::load_4(self::substr($key, 4, 4)),
    191             self::load_4(self::substr($key, 0, 4)),
    192             self::load_4(self::substr($key, 12, 4)),
    193             self::load_4(self::substr($key, 8, 4))
    194         );
    195         // k0 => $k[0], $k[1]
    196         // k1 => $k[2], $k[3]
    197 
    198         # b = ( ( u64 )inlen ) << 56;
    199         $b = array(
    200             $inlen << 24,
    201             0
    202         );
    203         // See docblock for why the 0th index gets the higher bits.
    204 
    205         # v3 ^= k1;
    206         $v[6] ^= $k[2];
    207         $v[7] ^= $k[3];
    208         # v2 ^= k0;
    209         $v[4] ^= $k[0];
    210         $v[5] ^= $k[1];
    211         # v1 ^= k1;
    212         $v[2] ^= $k[2];
    213         $v[3] ^= $k[3];
    214         # v0 ^= k0;
    215         $v[0] ^= $k[0];
    216         $v[1] ^= $k[1];
    217 
    218         $left = $inlen;
    219         # for ( ; in != end; in += 8 )
    220         while ($left >= 8) {
    221             # m = LOAD64_LE( in );
    222             $m = array(
    223                 self::load_4(self::substr($in, 4, 4)),
    224                 self::load_4(self::substr($in, 0, 4))
    225             );
    226 
    227             # v3 ^= m;
    228             $v[6] ^= $m[0];
    229             $v[7] ^= $m[1];
    230 
    231             # SIPROUND;
    232             # SIPROUND;
    233             $v = self::sipRound($v);
    234             $v = self::sipRound($v);
    235 
    236             # v0 ^= m;
    237             $v[0] ^= $m[0];
    238             $v[1] ^= $m[1];
    239 
    240             $in = self::substr($in, 8);
    241             $left -= 8;
    242         }
    243 
    244         # switch( left )
    245         #  {
    246         #     case 7: b |= ( ( u64 )in[ 6] )  << 48;
    247         #     case 6: b |= ( ( u64 )in[ 5] )  << 40;
    248         #     case 5: b |= ( ( u64 )in[ 4] )  << 32;
    249         #     case 4: b |= ( ( u64 )in[ 3] )  << 24;
    250         #     case 3: b |= ( ( u64 )in[ 2] )  << 16;
    251         #     case 2: b |= ( ( u64 )in[ 1] )  <<  8;
    252         #     case 1: b |= ( ( u64 )in[ 0] ); break;
    253         #     case 0: break;
    254         # }
    255         switch ($left) {
    256             case 7:
    257                 $b[0] |= self::chrToInt($in[6]) << 16;
    258             case 6:
    259                 $b[0] |= self::chrToInt($in[5]) << 8;
    260             case 5:
    261                 $b[0] |= self::chrToInt($in[4]);
    262             case 4:
    263                 $b[1] |= self::chrToInt($in[3]) << 24;
    264             case 3:
    265                 $b[1] |= self::chrToInt($in[2]) << 16;
    266             case 2:
    267                 $b[1] |= self::chrToInt($in[1]) << 8;
    268             case 1:
    269                 $b[1] |= self::chrToInt($in[0]);
    270             case 0:
    271                 break;
    272         }
    273         // See docblock for why the 0th index gets the higher bits.
    274 
    275         # v3 ^= b;
    276         $v[6] ^= $b[0];
    277         $v[7] ^= $b[1];
    278 
    279         # SIPROUND;
    280         # SIPROUND;
    281         $v = self::sipRound($v);
    282         $v = self::sipRound($v);
    283 
    284         # v0 ^= b;
    285         $v[0] ^= $b[0];
    286         $v[1] ^= $b[1];
    287 
    288         // Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation
    289         # v2 ^= 0xff;
    290         $v[5] ^= 0xff;
    291 
    292         # SIPROUND;
    293         # SIPROUND;
    294         # SIPROUND;
    295         # SIPROUND;
    296         $v = self::sipRound($v);
    297         $v = self::sipRound($v);
    298         $v = self::sipRound($v);
    299         $v = self::sipRound($v);
    300 
    301         # b = v0 ^ v1 ^ v2 ^ v3;
    302         # STORE64_LE( out, b );
    303         return  self::store32_le($v[1] ^ $v[3] ^ $v[5] ^ $v[7]) .
    304             self::store32_le($v[0] ^ $v[2] ^ $v[4] ^ $v[6]);
    305     }
    306 }