<?php

if (class_exists('ParagonIE_Sodium_Core32_SipHash', false)) {
    return;
}






class ParagonIE_Sodium_Core32_SipHash extends ParagonIE_Sodium_Core32_Util
{
    





    public static function sipRound(array $v)
    {
         
        $v[0] = $v[0]->addInt64($v[1]);

         
        $v[1] = $v[1]->rotateLeft(13);

         
        $v[1] = $v[1]->xorInt64($v[0]);

         
        $v[0] = $v[0]->rotateLeft(32);

         
        $v[2] = $v[2]->addInt64($v[3]);

         
        $v[3] = $v[3]->rotateLeft(16);

         
        $v[3] = $v[3]->xorInt64($v[2]);

         
        $v[0] = $v[0]->addInt64($v[3]);

         
        $v[3] = $v[3]->rotateLeft(21);

         
        $v[3] = $v[3]->xorInt64($v[0]);

         
        $v[2] = $v[2]->addInt64($v[1]);

         
        $v[1] = $v[1]->rotateLeft(17);

         
        $v[1] = $v[1]->xorInt64($v[2]);

         
        $v[2] = $v[2]->rotateLeft(32);

        return $v;
    }

    








    public static function sipHash24($in, $key)
    {
        $inlen = self::strlen($in);

         
         
         
         
         
        $v = array(
            new ParagonIE_Sodium_Core32_Int64(
                array(0x736f, 0x6d65, 0x7073, 0x6575)
            ),
            new ParagonIE_Sodium_Core32_Int64(
                array(0x646f, 0x7261, 0x6e64, 0x6f6d)
            ),
            new ParagonIE_Sodium_Core32_Int64(
                array(0x6c79, 0x6765, 0x6e65, 0x7261)
            ),
            new ParagonIE_Sodium_Core32_Int64(
                array(0x7465, 0x6462, 0x7974, 0x6573)
            )
        );

         
         
        $k = array(
            ParagonIE_Sodium_Core32_Int64::fromReverseString(
                self::substr($key, 0, 8)
            ),
            ParagonIE_Sodium_Core32_Int64::fromReverseString(
                self::substr($key, 8, 8)
            )
        );

         
        $b = new ParagonIE_Sodium_Core32_Int64(
            array(($inlen << 8) & 0xffff, 0, 0, 0)
        );

         
        $v[3] = $v[3]->xorInt64($k[1]);
         
        $v[2] = $v[2]->xorInt64($k[0]);
         
        $v[1] = $v[1]->xorInt64($k[1]);
         
        $v[0] = $v[0]->xorInt64($k[0]);

        $left = $inlen;
         
        while ($left >= 8) {
             
            $m = ParagonIE_Sodium_Core32_Int64::fromReverseString(
                self::substr($in, 0, 8)
            );

             
            $v[3] = $v[3]->xorInt64($m);

             
             
            $v = self::sipRound($v);
            $v = self::sipRound($v);

             
            $v[0] = $v[0]->xorInt64($m);

            $in = self::substr($in, 8);
            $left -= 8;
        }

         
         
         
         
         
         
         
         
         
         
         
        switch ($left) {
            case 7:
                $b = $b->orInt64(
                    ParagonIE_Sodium_Core32_Int64::fromInts(
                        0, self::chrToInt($in[6]) << 16
                    )
                );
            case 6:
                $b = $b->orInt64(
                    ParagonIE_Sodium_Core32_Int64::fromInts(
                        0, self::chrToInt($in[5]) << 8
                    )
                );
            case 5:
                $b = $b->orInt64(
                    ParagonIE_Sodium_Core32_Int64::fromInts(
                        0, self::chrToInt($in[4])
                    )
                );
            case 4:
                $b = $b->orInt64(
                    ParagonIE_Sodium_Core32_Int64::fromInts(
                        self::chrToInt($in[3]) << 24, 0
                    )
                );
            case 3:
                $b = $b->orInt64(
                    ParagonIE_Sodium_Core32_Int64::fromInts(
                        self::chrToInt($in[2]) << 16, 0
                    )
                );
            case 2:
                $b = $b->orInt64(
                    ParagonIE_Sodium_Core32_Int64::fromInts(
                        self::chrToInt($in[1]) << 8, 0
                    )
                );
            case 1:
                $b = $b->orInt64(
                    ParagonIE_Sodium_Core32_Int64::fromInts(
                        self::chrToInt($in[0]), 0
                    )
                );
            case 0:
                break;
        }

         
        $v[3] = $v[3]->xorInt64($b);

         
         
        $v = self::sipRound($v);
        $v = self::sipRound($v);

         
        $v[0] = $v[0]->xorInt64($b);

         
         
        $v[2]->limbs[3] ^= 0xff;

         
         
         
         
        $v = self::sipRound($v);
        $v = self::sipRound($v);
        $v = self::sipRound($v);
        $v = self::sipRound($v);

         
         
        return $v[0]
            ->xorInt64($v[1])
            ->xorInt64($v[2])
            ->xorInt64($v[3])
            ->toReverseString();
    }
}
