1<?php
2
3if (class_exists('ParagonIE_Sodium_Core32_SipHash', false)) {
4 return;
5}
6
7/**
8 * Class ParagonIE_SodiumCompat_Core32_SipHash
9 *
10 * Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers
11 */
12class ParagonIE_Sodium_Core32_SipHash extends ParagonIE_Sodium_Core32_Util
13{
14 /**
15 * @internal You should not use this directly from another application
16 *
17 * @param array<int, ParagonIE_Sodium_Core32_Int64> $v
18 * @return array<int, ParagonIE_Sodium_Core32_Int64>
19 */
20 public static function sipRound(array $v)
21 {
22 # v0 += v1;
23 $v[0] = $v[0]->addInt64($v[1]);
24
25 # v1 = ROTL(v1, 13);
26 $v[1] = $v[1]->rotateLeft(13);
27
28 # v1 ^= v0;
29 $v[1] = $v[1]->xorInt64($v[0]);
30
31 # v0=ROTL(v0,32);
32 $v[0] = $v[0]->rotateLeft(32);
33
34 # v2 += v3;
35 $v[2] = $v[2]->addInt64($v[3]);
36
37 # v3=ROTL(v3,16);
38 $v[3] = $v[3]->rotateLeft(16);
39
40 # v3 ^= v2;
41 $v[3] = $v[3]->xorInt64($v[2]);
42
43 # v0 += v3;
44 $v[0] = $v[0]->addInt64($v[3]);
45
46 # v3=ROTL(v3,21);
47 $v[3] = $v[3]->rotateLeft(21);
48
49 # v3 ^= v0;
50 $v[3] = $v[3]->xorInt64($v[0]);
51
52 # v2 += v1;
53 $v[2] = $v[2]->addInt64($v[1]);
54
55 # v1=ROTL(v1,17);
56 $v[1] = $v[1]->rotateLeft(17);
57
58 # v1 ^= v2;
59 $v[1] = $v[1]->xorInt64($v[2]);
60
61 # v2=ROTL(v2,32)
62 $v[2] = $v[2]->rotateLeft(32);
63
64 return $v;
65 }
66
67 /**
68 * @internal You should not use this directly from another application
69 *
70 * @param string $in
71 * @param string $key
72 * @return string
73 * @throws SodiumException
74 * @throws TypeError
75 */
76 public static function sipHash24($in, $key)
77 {
78 $inlen = self::strlen($in);
79
80 # /* "somepseudorandomlygeneratedbytes" */
81 # u64 v0 = 0x736f6d6570736575ULL;
82 # u64 v1 = 0x646f72616e646f6dULL;
83 # u64 v2 = 0x6c7967656e657261ULL;
84 # u64 v3 = 0x7465646279746573ULL;
85 $v = array(
86 new ParagonIE_Sodium_Core32_Int64(
87 array(0x736f, 0x6d65, 0x7073, 0x6575)
88 ),
89 new ParagonIE_Sodium_Core32_Int64(
90 array(0x646f, 0x7261, 0x6e64, 0x6f6d)
91 ),
92 new ParagonIE_Sodium_Core32_Int64(
93 array(0x6c79, 0x6765, 0x6e65, 0x7261)
94 ),
95 new ParagonIE_Sodium_Core32_Int64(
96 array(0x7465, 0x6462, 0x7974, 0x6573)
97 )
98 );
99
100 # u64 k0 = LOAD64_LE( k );
101 # u64 k1 = LOAD64_LE( k + 8 );
102 $k = array(
103 ParagonIE_Sodium_Core32_Int64::fromReverseString(
104 self::substr($key, 0, 8)
105 ),
106 ParagonIE_Sodium_Core32_Int64::fromReverseString(
107 self::substr($key, 8, 8)
108 )
109 );
110
111 # b = ( ( u64 )inlen ) << 56;
112 $b = new ParagonIE_Sodium_Core32_Int64(
113 array(($inlen << 8) & 0xffff, 0, 0, 0)
114 );
115
116 # v3 ^= k1;
117 $v[3] = $v[3]->xorInt64($k[1]);
118 # v2 ^= k0;
119 $v[2] = $v[2]->xorInt64($k[0]);
120 # v1 ^= k1;
121 $v[1] = $v[1]->xorInt64($k[1]);
122 # v0 ^= k0;
123 $v[0] = $v[0]->xorInt64($k[0]);
124
125 $left = $inlen;
126 # for ( ; in != end; in += 8 )
127 while ($left >= 8) {
128 # m = LOAD64_LE( in );
129 $m = ParagonIE_Sodium_Core32_Int64::fromReverseString(
130 self::substr($in, 0, 8)
131 );
132
133 # v3 ^= m;
134 $v[3] = $v[3]->xorInt64($m);
135
136 # SIPROUND;
137 # SIPROUND;
138 $v = self::sipRound($v);
139 $v = self::sipRound($v);
140
141 # v0 ^= m;
142 $v[0] = $v[0]->xorInt64($m);
143
144 $in = self::substr($in, 8);
145 $left -= 8;
146 }
147
148 # switch( left )
149 # {
150 # case 7: b |= ( ( u64 )in[ 6] ) << 48;
151 # case 6: b |= ( ( u64 )in[ 5] ) << 40;
152 # case 5: b |= ( ( u64 )in[ 4] ) << 32;
153 # case 4: b |= ( ( u64 )in[ 3] ) << 24;
154 # case 3: b |= ( ( u64 )in[ 2] ) << 16;
155 # case 2: b |= ( ( u64 )in[ 1] ) << 8;
156 # case 1: b |= ( ( u64 )in[ 0] ); break;
157 # case 0: break;
158 # }
159 switch ($left) {
160 case 7:
161 $b = $b->orInt64(
162 ParagonIE_Sodium_Core32_Int64::fromInts(
163 0, self::chrToInt($in[6]) << 16
164 )
165 );
166 case 6:
167 $b = $b->orInt64(
168 ParagonIE_Sodium_Core32_Int64::fromInts(
169 0, self::chrToInt($in[5]) << 8
170 )
171 );
172 case 5:
173 $b = $b->orInt64(
174 ParagonIE_Sodium_Core32_Int64::fromInts(
175 0, self::chrToInt($in[4])
176 )
177 );
178 case 4:
179 $b = $b->orInt64(
180 ParagonIE_Sodium_Core32_Int64::fromInts(
181 self::chrToInt($in[3]) << 24, 0
182 )
183 );
184 case 3:
185 $b = $b->orInt64(
186 ParagonIE_Sodium_Core32_Int64::fromInts(
187 self::chrToInt($in[2]) << 16, 0
188 )
189 );
190 case 2:
191 $b = $b->orInt64(
192 ParagonIE_Sodium_Core32_Int64::fromInts(
193 self::chrToInt($in[1]) << 8, 0
194 )
195 );
196 case 1:
197 $b = $b->orInt64(
198 ParagonIE_Sodium_Core32_Int64::fromInts(
199 self::chrToInt($in[0]), 0
200 )
201 );
202 case 0:
203 break;
204 }
205
206 # v3 ^= b;
207 $v[3] = $v[3]->xorInt64($b);
208
209 # SIPROUND;
210 # SIPROUND;
211 $v = self::sipRound($v);
212 $v = self::sipRound($v);
213
214 # v0 ^= b;
215 $v[0] = $v[0]->xorInt64($b);
216
217 // Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation
218 # v2 ^= 0xff;
219 $v[2]->limbs[3] ^= 0xff;
220
221 # SIPROUND;
222 # SIPROUND;
223 # SIPROUND;
224 # SIPROUND;
225 $v = self::sipRound($v);
226 $v = self::sipRound($v);
227 $v = self::sipRound($v);
228 $v = self::sipRound($v);
229
230 # b = v0 ^ v1 ^ v2 ^ v3;
231 # STORE64_LE( out, b );
232 return $v[0]
233 ->xorInt64($v[1])
234 ->xorInt64($v[2])
235 ->xorInt64($v[3])
236 ->toReverseString();
237 }
238}
239