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