|
1 <?php |
|
2 |
|
3 /** |
|
4 * Class ParagonIE_Sodium_Core32_Int32 |
|
5 * |
|
6 * Encapsulates a 32-bit integer. |
|
7 * |
|
8 * These are immutable. It always returns a new instance. |
|
9 */ |
|
10 class ParagonIE_Sodium_Core32_Int32 |
|
11 { |
|
12 /** |
|
13 * @var array<int, int> - two 16-bit integers |
|
14 * |
|
15 * 0 is the higher 16 bits |
|
16 * 1 is the lower 16 bits |
|
17 */ |
|
18 public $limbs = array(0, 0); |
|
19 |
|
20 /** |
|
21 * @var int |
|
22 */ |
|
23 public $overflow = 0; |
|
24 |
|
25 /** |
|
26 * @var bool |
|
27 */ |
|
28 public $unsignedInt = false; |
|
29 |
|
30 /** |
|
31 * ParagonIE_Sodium_Core32_Int32 constructor. |
|
32 * @param array $array |
|
33 * @param bool $unsignedInt |
|
34 */ |
|
35 public function __construct($array = array(0, 0), $unsignedInt = false) |
|
36 { |
|
37 $this->limbs = array( |
|
38 (int) $array[0], |
|
39 (int) $array[1] |
|
40 ); |
|
41 $this->overflow = 0; |
|
42 $this->unsignedInt = $unsignedInt; |
|
43 } |
|
44 |
|
45 /** |
|
46 * Adds two int32 objects |
|
47 * |
|
48 * @param ParagonIE_Sodium_Core32_Int32 $addend |
|
49 * @return ParagonIE_Sodium_Core32_Int32 |
|
50 */ |
|
51 public function addInt32(ParagonIE_Sodium_Core32_Int32 $addend) |
|
52 { |
|
53 $i0 = $this->limbs[0]; |
|
54 $i1 = $this->limbs[1]; |
|
55 $j0 = $addend->limbs[0]; |
|
56 $j1 = $addend->limbs[1]; |
|
57 |
|
58 $r1 = $i1 + ($j1 & 0xffff); |
|
59 $carry = $r1 >> 16; |
|
60 |
|
61 $r0 = $i0 + ($j0 & 0xffff) + $carry; |
|
62 $carry = $r0 >> 16; |
|
63 |
|
64 $r0 &= 0xffff; |
|
65 $r1 &= 0xffff; |
|
66 |
|
67 $return = new ParagonIE_Sodium_Core32_Int32( |
|
68 array($r0, $r1) |
|
69 ); |
|
70 $return->overflow = $carry; |
|
71 $return->unsignedInt = $this->unsignedInt; |
|
72 return $return; |
|
73 } |
|
74 |
|
75 /** |
|
76 * Adds a normal integer to an int32 object |
|
77 * |
|
78 * @param int $int |
|
79 * @return ParagonIE_Sodium_Core32_Int32 |
|
80 * @throws SodiumException |
|
81 * @throws TypeError |
|
82 */ |
|
83 public function addInt($int) |
|
84 { |
|
85 ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1); |
|
86 /** @var int $int */ |
|
87 $int = (int) $int; |
|
88 |
|
89 $int = (int) $int; |
|
90 |
|
91 $i0 = $this->limbs[0]; |
|
92 $i1 = $this->limbs[1]; |
|
93 |
|
94 $r1 = $i1 + ($int & 0xffff); |
|
95 $carry = $r1 >> 16; |
|
96 |
|
97 $r0 = $i0 + (($int >> 16) & 0xffff) + $carry; |
|
98 $carry = $r0 >> 16; |
|
99 $r0 &= 0xffff; |
|
100 $r1 &= 0xffff; |
|
101 $return = new ParagonIE_Sodium_Core32_Int32( |
|
102 array($r0, $r1) |
|
103 ); |
|
104 $return->overflow = $carry; |
|
105 $return->unsignedInt = $this->unsignedInt; |
|
106 return $return; |
|
107 } |
|
108 |
|
109 /** |
|
110 * @param int $b |
|
111 * @return int |
|
112 */ |
|
113 public function compareInt($b = 0) |
|
114 { |
|
115 $gt = 0; |
|
116 $eq = 1; |
|
117 |
|
118 $i = 2; |
|
119 $j = 0; |
|
120 while ($i > 0) { |
|
121 --$i; |
|
122 /** @var int $x1 */ |
|
123 $x1 = $this->limbs[$i]; |
|
124 /** @var int $x2 */ |
|
125 $x2 = ($b >> ($j << 4)) & 0xffff; |
|
126 /** @var int $gt */ |
|
127 $gt |= (($x2 - $x1) >> 8) & $eq; |
|
128 /** @var int $eq */ |
|
129 $eq &= (($x2 ^ $x1) - 1) >> 8; |
|
130 } |
|
131 return ($gt + $gt - $eq) + 1; |
|
132 } |
|
133 |
|
134 /** |
|
135 * @param int $m |
|
136 * @return ParagonIE_Sodium_Core32_Int32 |
|
137 */ |
|
138 public function mask($m = 0) |
|
139 { |
|
140 /** @var int $hi */ |
|
141 $hi = ($m >> 16) & 0xffff; |
|
142 /** @var int $lo */ |
|
143 $lo = ($m & 0xffff); |
|
144 return new ParagonIE_Sodium_Core32_Int32( |
|
145 array( |
|
146 (int) ($this->limbs[0] & $hi), |
|
147 (int) ($this->limbs[1] & $lo) |
|
148 ), |
|
149 $this->unsignedInt |
|
150 ); |
|
151 } |
|
152 |
|
153 /** |
|
154 * @param array<int, int> $a |
|
155 * @param array<int, int> $b |
|
156 * @param int $baseLog2 |
|
157 * @return array<int, int> |
|
158 */ |
|
159 public function multiplyLong(array $a, array $b, $baseLog2 = 16) |
|
160 { |
|
161 $a_l = count($a); |
|
162 $b_l = count($b); |
|
163 /** @var array<int, int> $r */ |
|
164 $r = array_fill(0, $a_l + $b_l + 1, 0); |
|
165 $base = 1 << $baseLog2; |
|
166 for ($i = 0; $i < $a_l; ++$i) { |
|
167 $a_i = $a[$i]; |
|
168 for ($j = 0; $j < $a_l; ++$j) { |
|
169 $b_j = $b[$j]; |
|
170 $product = ($a_i * $b_j) + $r[$i + $j]; |
|
171 $carry = ($product >> $baseLog2 & 0xffff); |
|
172 $r[$i + $j] = ($product - (int) ($carry * $base)) & 0xffff; |
|
173 $r[$i + $j + 1] += $carry; |
|
174 } |
|
175 } |
|
176 return array_slice($r, 0, 5); |
|
177 } |
|
178 |
|
179 /** |
|
180 * @param int $int |
|
181 * @return ParagonIE_Sodium_Core32_Int32 |
|
182 */ |
|
183 public function mulIntFast($int) |
|
184 { |
|
185 // Handle negative numbers |
|
186 $aNeg = ($this->limbs[0] >> 15) & 1; |
|
187 $bNeg = ($int >> 31) & 1; |
|
188 $a = array_reverse($this->limbs); |
|
189 $b = array( |
|
190 $int & 0xffff, |
|
191 ($int >> 16) & 0xffff |
|
192 ); |
|
193 if ($aNeg) { |
|
194 for ($i = 0; $i < 2; ++$i) { |
|
195 $a[$i] = ($a[$i] ^ 0xffff) & 0xffff; |
|
196 } |
|
197 ++$a[0]; |
|
198 } |
|
199 if ($bNeg) { |
|
200 for ($i = 0; $i < 2; ++$i) { |
|
201 $b[$i] = ($b[$i] ^ 0xffff) & 0xffff; |
|
202 } |
|
203 ++$b[0]; |
|
204 } |
|
205 // Multiply |
|
206 $res = $this->multiplyLong($a, $b); |
|
207 |
|
208 // Re-apply negation to results |
|
209 if ($aNeg !== $bNeg) { |
|
210 for ($i = 0; $i < 2; ++$i) { |
|
211 $res[$i] = (0xffff ^ $res[$i]) & 0xffff; |
|
212 } |
|
213 // Handle integer overflow |
|
214 $c = 1; |
|
215 for ($i = 0; $i < 2; ++$i) { |
|
216 $res[$i] += $c; |
|
217 $c = $res[$i] >> 16; |
|
218 $res[$i] &= 0xffff; |
|
219 } |
|
220 } |
|
221 |
|
222 // Return our values |
|
223 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
224 $return->limbs = array( |
|
225 $res[1] & 0xffff, |
|
226 $res[0] & 0xffff |
|
227 ); |
|
228 if (count($res) > 2) { |
|
229 $return->overflow = $res[2] & 0xffff; |
|
230 } |
|
231 $return->unsignedInt = $this->unsignedInt; |
|
232 return $return; |
|
233 } |
|
234 |
|
235 /** |
|
236 * @param ParagonIE_Sodium_Core32_Int32 $right |
|
237 * @return ParagonIE_Sodium_Core32_Int32 |
|
238 */ |
|
239 public function mulInt32Fast(ParagonIE_Sodium_Core32_Int32 $right) |
|
240 { |
|
241 $aNeg = ($this->limbs[0] >> 15) & 1; |
|
242 $bNeg = ($right->limbs[0] >> 15) & 1; |
|
243 |
|
244 $a = array_reverse($this->limbs); |
|
245 $b = array_reverse($right->limbs); |
|
246 if ($aNeg) { |
|
247 for ($i = 0; $i < 2; ++$i) { |
|
248 $a[$i] = ($a[$i] ^ 0xffff) & 0xffff; |
|
249 } |
|
250 ++$a[0]; |
|
251 } |
|
252 if ($bNeg) { |
|
253 for ($i = 0; $i < 2; ++$i) { |
|
254 $b[$i] = ($b[$i] ^ 0xffff) & 0xffff; |
|
255 } |
|
256 ++$b[0]; |
|
257 } |
|
258 $res = $this->multiplyLong($a, $b); |
|
259 if ($aNeg !== $bNeg) { |
|
260 if ($aNeg !== $bNeg) { |
|
261 for ($i = 0; $i < 2; ++$i) { |
|
262 $res[$i] = ($res[$i] ^ 0xffff) & 0xffff; |
|
263 } |
|
264 $c = 1; |
|
265 for ($i = 0; $i < 2; ++$i) { |
|
266 $res[$i] += $c; |
|
267 $c = $res[$i] >> 16; |
|
268 $res[$i] &= 0xffff; |
|
269 } |
|
270 } |
|
271 } |
|
272 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
273 $return->limbs = array( |
|
274 $res[1] & 0xffff, |
|
275 $res[0] & 0xffff |
|
276 ); |
|
277 if (count($res) > 2) { |
|
278 $return->overflow = $res[2]; |
|
279 } |
|
280 return $return; |
|
281 } |
|
282 |
|
283 /** |
|
284 * @param int $int |
|
285 * @param int $size |
|
286 * @return ParagonIE_Sodium_Core32_Int32 |
|
287 * @throws SodiumException |
|
288 * @throws TypeError |
|
289 */ |
|
290 public function mulInt($int = 0, $size = 0) |
|
291 { |
|
292 ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1); |
|
293 ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2); |
|
294 if (ParagonIE_Sodium_Compat::$fastMult) { |
|
295 return $this->mulIntFast((int) $int); |
|
296 } |
|
297 /** @var int $int */ |
|
298 $int = (int) $int; |
|
299 /** @var int $size */ |
|
300 $size = (int) $size; |
|
301 |
|
302 if (!$size) { |
|
303 $size = 31; |
|
304 } |
|
305 /** @var int $size */ |
|
306 |
|
307 $a = clone $this; |
|
308 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
309 $return->unsignedInt = $this->unsignedInt; |
|
310 |
|
311 // Initialize: |
|
312 $ret0 = 0; |
|
313 $ret1 = 0; |
|
314 $a0 = $a->limbs[0]; |
|
315 $a1 = $a->limbs[1]; |
|
316 |
|
317 /** @var int $size */ |
|
318 /** @var int $i */ |
|
319 for ($i = $size; $i >= 0; --$i) { |
|
320 $m = (int) (-($int & 1)); |
|
321 $x0 = $a0 & $m; |
|
322 $x1 = $a1 & $m; |
|
323 |
|
324 $ret1 += $x1; |
|
325 $c = $ret1 >> 16; |
|
326 |
|
327 $ret0 += $x0 + $c; |
|
328 |
|
329 $ret0 &= 0xffff; |
|
330 $ret1 &= 0xffff; |
|
331 |
|
332 $a1 = ($a1 << 1); |
|
333 $x1 = $a1 >> 16; |
|
334 $a0 = ($a0 << 1) | $x1; |
|
335 $a0 &= 0xffff; |
|
336 $a1 &= 0xffff; |
|
337 $int >>= 1; |
|
338 } |
|
339 $return->limbs[0] = $ret0; |
|
340 $return->limbs[1] = $ret1; |
|
341 return $return; |
|
342 } |
|
343 |
|
344 /** |
|
345 * @param ParagonIE_Sodium_Core32_Int32 $int |
|
346 * @param int $size |
|
347 * @return ParagonIE_Sodium_Core32_Int32 |
|
348 * @throws SodiumException |
|
349 * @throws TypeError |
|
350 */ |
|
351 public function mulInt32(ParagonIE_Sodium_Core32_Int32 $int, $size = 0) |
|
352 { |
|
353 ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2); |
|
354 if (ParagonIE_Sodium_Compat::$fastMult) { |
|
355 return $this->mulInt32Fast($int); |
|
356 } |
|
357 if (!$size) { |
|
358 $size = 31; |
|
359 } |
|
360 /** @var int $size */ |
|
361 |
|
362 $a = clone $this; |
|
363 $b = clone $int; |
|
364 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
365 $return->unsignedInt = $this->unsignedInt; |
|
366 |
|
367 // Initialize: |
|
368 $ret0 = 0; |
|
369 $ret1 = 0; |
|
370 $a0 = $a->limbs[0]; |
|
371 $a1 = $a->limbs[1]; |
|
372 $b0 = $b->limbs[0]; |
|
373 $b1 = $b->limbs[1]; |
|
374 |
|
375 /** @var int $size */ |
|
376 /** @var int $i */ |
|
377 for ($i = $size; $i >= 0; --$i) { |
|
378 $m = (int) (-($b1 & 1)); |
|
379 $x0 = $a0 & $m; |
|
380 $x1 = $a1 & $m; |
|
381 |
|
382 $ret1 += $x1; |
|
383 $c = $ret1 >> 16; |
|
384 |
|
385 $ret0 += $x0 + $c; |
|
386 |
|
387 $ret0 &= 0xffff; |
|
388 $ret1 &= 0xffff; |
|
389 |
|
390 $a1 = ($a1 << 1); |
|
391 $x1 = $a1 >> 16; |
|
392 $a0 = ($a0 << 1) | $x1; |
|
393 $a0 &= 0xffff; |
|
394 $a1 &= 0xffff; |
|
395 |
|
396 $x0 = ($b0 & 1) << 16; |
|
397 $b0 = ($b0 >> 1); |
|
398 $b1 = (($b1 | $x0) >> 1); |
|
399 |
|
400 $b0 &= 0xffff; |
|
401 $b1 &= 0xffff; |
|
402 |
|
403 } |
|
404 $return->limbs[0] = $ret0; |
|
405 $return->limbs[1] = $ret1; |
|
406 |
|
407 return $return; |
|
408 } |
|
409 |
|
410 /** |
|
411 * OR this 32-bit integer with another. |
|
412 * |
|
413 * @param ParagonIE_Sodium_Core32_Int32 $b |
|
414 * @return ParagonIE_Sodium_Core32_Int32 |
|
415 */ |
|
416 public function orInt32(ParagonIE_Sodium_Core32_Int32 $b) |
|
417 { |
|
418 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
419 $return->unsignedInt = $this->unsignedInt; |
|
420 $return->limbs = array( |
|
421 (int) ($this->limbs[0] | $b->limbs[0]), |
|
422 (int) ($this->limbs[1] | $b->limbs[1]) |
|
423 ); |
|
424 /** @var int overflow */ |
|
425 $return->overflow = $this->overflow | $b->overflow; |
|
426 return $return; |
|
427 } |
|
428 |
|
429 /** |
|
430 * @param int $b |
|
431 * @return bool |
|
432 */ |
|
433 public function isGreaterThan($b = 0) |
|
434 { |
|
435 return $this->compareInt($b) > 0; |
|
436 } |
|
437 |
|
438 /** |
|
439 * @param int $b |
|
440 * @return bool |
|
441 */ |
|
442 public function isLessThanInt($b = 0) |
|
443 { |
|
444 return $this->compareInt($b) < 0; |
|
445 } |
|
446 |
|
447 /** |
|
448 * @param int $c |
|
449 * @return ParagonIE_Sodium_Core32_Int32 |
|
450 * @throws SodiumException |
|
451 * @throws TypeError |
|
452 * @psalm-suppress MixedArrayAccess |
|
453 */ |
|
454 public function rotateLeft($c = 0) |
|
455 { |
|
456 ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); |
|
457 /** @var int $c */ |
|
458 $c = (int) $c; |
|
459 |
|
460 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
461 $return->unsignedInt = $this->unsignedInt; |
|
462 $c &= 31; |
|
463 if ($c === 0) { |
|
464 // NOP, but we want a copy. |
|
465 $return->limbs = $this->limbs; |
|
466 } else { |
|
467 /** @var int $c */ |
|
468 |
|
469 /** @var int $idx_shift */ |
|
470 $idx_shift = ($c >> 4) & 1; |
|
471 |
|
472 /** @var int $sub_shift */ |
|
473 $sub_shift = $c & 15; |
|
474 |
|
475 /** @var array<int, int> $limbs */ |
|
476 $limbs =& $return->limbs; |
|
477 |
|
478 /** @var array<int, int> $myLimbs */ |
|
479 $myLimbs =& $this->limbs; |
|
480 |
|
481 for ($i = 1; $i >= 0; --$i) { |
|
482 /** @var int $j */ |
|
483 $j = ($i + $idx_shift) & 1; |
|
484 /** @var int $k */ |
|
485 $k = ($i + $idx_shift + 1) & 1; |
|
486 $limbs[$i] = (int) ( |
|
487 ( |
|
488 ((int) ($myLimbs[$j]) << $sub_shift) |
|
489 | |
|
490 ((int) ($myLimbs[$k]) >> (16 - $sub_shift)) |
|
491 ) & 0xffff |
|
492 ); |
|
493 } |
|
494 } |
|
495 return $return; |
|
496 } |
|
497 |
|
498 /** |
|
499 * Rotate to the right |
|
500 * |
|
501 * @param int $c |
|
502 * @return ParagonIE_Sodium_Core32_Int32 |
|
503 * @throws SodiumException |
|
504 * @throws TypeError |
|
505 * @psalm-suppress MixedArrayAccess |
|
506 */ |
|
507 public function rotateRight($c = 0) |
|
508 { |
|
509 ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); |
|
510 /** @var int $c */ |
|
511 $c = (int) $c; |
|
512 |
|
513 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
514 $return->unsignedInt = $this->unsignedInt; |
|
515 $c &= 31; |
|
516 /** @var int $c */ |
|
517 if ($c === 0) { |
|
518 // NOP, but we want a copy. |
|
519 $return->limbs = $this->limbs; |
|
520 } else { |
|
521 /** @var int $c */ |
|
522 |
|
523 /** @var int $idx_shift */ |
|
524 $idx_shift = ($c >> 4) & 1; |
|
525 |
|
526 /** @var int $sub_shift */ |
|
527 $sub_shift = $c & 15; |
|
528 |
|
529 /** @var array<int, int> $limbs */ |
|
530 $limbs =& $return->limbs; |
|
531 |
|
532 /** @var array<int, int> $myLimbs */ |
|
533 $myLimbs =& $this->limbs; |
|
534 |
|
535 for ($i = 1; $i >= 0; --$i) { |
|
536 /** @var int $j */ |
|
537 $j = ($i - $idx_shift) & 1; |
|
538 /** @var int $k */ |
|
539 $k = ($i - $idx_shift - 1) & 1; |
|
540 $limbs[$i] = (int) ( |
|
541 ( |
|
542 ((int) ($myLimbs[$j]) >> (int) ($sub_shift)) |
|
543 | |
|
544 ((int) ($myLimbs[$k]) << (16 - (int) ($sub_shift))) |
|
545 ) & 0xffff |
|
546 ); |
|
547 } |
|
548 } |
|
549 return $return; |
|
550 } |
|
551 |
|
552 /** |
|
553 * @param bool $bool |
|
554 * @return self |
|
555 */ |
|
556 public function setUnsignedInt($bool = false) |
|
557 { |
|
558 $this->unsignedInt = !empty($bool); |
|
559 return $this; |
|
560 } |
|
561 |
|
562 /** |
|
563 * @param int $c |
|
564 * @return ParagonIE_Sodium_Core32_Int32 |
|
565 * @throws SodiumException |
|
566 * @throws TypeError |
|
567 */ |
|
568 public function shiftLeft($c = 0) |
|
569 { |
|
570 ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); |
|
571 /** @var int $c */ |
|
572 $c = (int) $c; |
|
573 |
|
574 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
575 $return->unsignedInt = $this->unsignedInt; |
|
576 $c &= 63; |
|
577 /** @var int $c */ |
|
578 if ($c === 0) { |
|
579 $return->limbs = $this->limbs; |
|
580 } elseif ($c < 0) { |
|
581 /** @var int $c */ |
|
582 return $this->shiftRight(-$c); |
|
583 } else { |
|
584 /** @var int $c */ |
|
585 /** @var int $tmp */ |
|
586 $tmp = $this->limbs[1] << $c; |
|
587 $return->limbs[1] = (int)($tmp & 0xffff); |
|
588 /** @var int $carry */ |
|
589 $carry = $tmp >> 16; |
|
590 |
|
591 /** @var int $tmp */ |
|
592 $tmp = ($this->limbs[0] << $c) | ($carry & 0xffff); |
|
593 $return->limbs[0] = (int) ($tmp & 0xffff); |
|
594 } |
|
595 return $return; |
|
596 } |
|
597 |
|
598 /** |
|
599 * @param int $c |
|
600 * @return ParagonIE_Sodium_Core32_Int32 |
|
601 * @throws SodiumException |
|
602 * @throws TypeError |
|
603 * @psalm-suppress MixedAssignment |
|
604 * @psalm-suppress MixedOperand |
|
605 */ |
|
606 public function shiftRight($c = 0) |
|
607 { |
|
608 ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); |
|
609 /** @var int $c */ |
|
610 $c = (int) $c; |
|
611 |
|
612 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
613 $return->unsignedInt = $this->unsignedInt; |
|
614 $c &= 63; |
|
615 /** @var int $c */ |
|
616 if ($c >= 16) { |
|
617 $return->limbs = array( |
|
618 (int) ($this->overflow & 0xffff), |
|
619 (int) ($this->limbs[0]) |
|
620 ); |
|
621 $return->overflow = $this->overflow >> 16; |
|
622 return $return->shiftRight($c & 15); |
|
623 } |
|
624 if ($c === 0) { |
|
625 $return->limbs = $this->limbs; |
|
626 } elseif ($c < 0) { |
|
627 /** @var int $c */ |
|
628 return $this->shiftLeft(-$c); |
|
629 } else { |
|
630 if (!is_int($c)) { |
|
631 throw new TypeError(); |
|
632 } |
|
633 /** @var int $c */ |
|
634 // $return->limbs[0] = (int) (($this->limbs[0] >> $c) & 0xffff); |
|
635 $carryLeft = (int) ($this->overflow & ((1 << ($c + 1)) - 1)); |
|
636 $return->limbs[0] = (int) ((($this->limbs[0] >> $c) | ($carryLeft << (16 - $c))) & 0xffff); |
|
637 $carryRight = (int) ($this->limbs[0] & ((1 << ($c + 1)) - 1)); |
|
638 $return->limbs[1] = (int) ((($this->limbs[1] >> $c) | ($carryRight << (16 - $c))) & 0xffff); |
|
639 $return->overflow >>= $c; |
|
640 } |
|
641 return $return; |
|
642 } |
|
643 |
|
644 /** |
|
645 * Subtract a normal integer from an int32 object. |
|
646 * |
|
647 * @param int $int |
|
648 * @return ParagonIE_Sodium_Core32_Int32 |
|
649 * @throws SodiumException |
|
650 * @throws TypeError |
|
651 */ |
|
652 public function subInt($int) |
|
653 { |
|
654 ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1); |
|
655 /** @var int $int */ |
|
656 $int = (int) $int; |
|
657 |
|
658 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
659 $return->unsignedInt = $this->unsignedInt; |
|
660 |
|
661 /** @var int $tmp */ |
|
662 $tmp = $this->limbs[1] - ($int & 0xffff); |
|
663 /** @var int $carry */ |
|
664 $carry = $tmp >> 16; |
|
665 $return->limbs[1] = (int) ($tmp & 0xffff); |
|
666 |
|
667 /** @var int $tmp */ |
|
668 $tmp = $this->limbs[0] - (($int >> 16) & 0xffff) + $carry; |
|
669 $return->limbs[0] = (int) ($tmp & 0xffff); |
|
670 return $return; |
|
671 } |
|
672 |
|
673 /** |
|
674 * Subtract two int32 objects from each other |
|
675 * |
|
676 * @param ParagonIE_Sodium_Core32_Int32 $b |
|
677 * @return ParagonIE_Sodium_Core32_Int32 |
|
678 */ |
|
679 public function subInt32(ParagonIE_Sodium_Core32_Int32 $b) |
|
680 { |
|
681 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
682 $return->unsignedInt = $this->unsignedInt; |
|
683 |
|
684 /** @var int $tmp */ |
|
685 $tmp = $this->limbs[1] - ($b->limbs[1] & 0xffff); |
|
686 /** @var int $carry */ |
|
687 $carry = $tmp >> 16; |
|
688 $return->limbs[1] = (int) ($tmp & 0xffff); |
|
689 |
|
690 /** @var int $tmp */ |
|
691 $tmp = $this->limbs[0] - ($b->limbs[0] & 0xffff) + $carry; |
|
692 $return->limbs[0] = (int) ($tmp & 0xffff); |
|
693 return $return; |
|
694 } |
|
695 |
|
696 /** |
|
697 * XOR this 32-bit integer with another. |
|
698 * |
|
699 * @param ParagonIE_Sodium_Core32_Int32 $b |
|
700 * @return ParagonIE_Sodium_Core32_Int32 |
|
701 */ |
|
702 public function xorInt32(ParagonIE_Sodium_Core32_Int32 $b) |
|
703 { |
|
704 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
705 $return->unsignedInt = $this->unsignedInt; |
|
706 $return->limbs = array( |
|
707 (int) ($this->limbs[0] ^ $b->limbs[0]), |
|
708 (int) ($this->limbs[1] ^ $b->limbs[1]) |
|
709 ); |
|
710 return $return; |
|
711 } |
|
712 |
|
713 /** |
|
714 * @param int $signed |
|
715 * @return self |
|
716 * @throws SodiumException |
|
717 * @throws TypeError |
|
718 */ |
|
719 public static function fromInt($signed) |
|
720 { |
|
721 ParagonIE_Sodium_Core32_Util::declareScalarType($signed, 'int', 1);; |
|
722 /** @var int $signed */ |
|
723 $signed = (int) $signed; |
|
724 |
|
725 return new ParagonIE_Sodium_Core32_Int32( |
|
726 array( |
|
727 (int) (($signed >> 16) & 0xffff), |
|
728 (int) ($signed & 0xffff) |
|
729 ) |
|
730 ); |
|
731 } |
|
732 |
|
733 /** |
|
734 * @param string $string |
|
735 * @return self |
|
736 * @throws SodiumException |
|
737 * @throws TypeError |
|
738 */ |
|
739 public static function fromString($string) |
|
740 { |
|
741 ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1); |
|
742 $string = (string) $string; |
|
743 if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) { |
|
744 throw new RangeException( |
|
745 'String must be 4 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.' |
|
746 ); |
|
747 } |
|
748 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
749 |
|
750 $return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) << 8); |
|
751 $return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff); |
|
752 $return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) << 8); |
|
753 $return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff); |
|
754 return $return; |
|
755 } |
|
756 |
|
757 /** |
|
758 * @param string $string |
|
759 * @return self |
|
760 * @throws SodiumException |
|
761 * @throws TypeError |
|
762 */ |
|
763 public static function fromReverseString($string) |
|
764 { |
|
765 ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1); |
|
766 $string = (string) $string; |
|
767 if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) { |
|
768 throw new RangeException( |
|
769 'String must be 4 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.' |
|
770 ); |
|
771 } |
|
772 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
773 |
|
774 $return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) << 8); |
|
775 $return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff); |
|
776 $return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) << 8); |
|
777 $return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff); |
|
778 return $return; |
|
779 } |
|
780 |
|
781 /** |
|
782 * @return array<int, int> |
|
783 */ |
|
784 public function toArray() |
|
785 { |
|
786 return array((int) ($this->limbs[0] << 16 | $this->limbs[1])); |
|
787 } |
|
788 |
|
789 /** |
|
790 * @return string |
|
791 * @throws TypeError |
|
792 */ |
|
793 public function toString() |
|
794 { |
|
795 return |
|
796 ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff) . |
|
797 ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . |
|
798 ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) . |
|
799 ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff); |
|
800 } |
|
801 |
|
802 /** |
|
803 * @return int |
|
804 */ |
|
805 public function toInt() |
|
806 { |
|
807 return (int) ( |
|
808 (($this->limbs[0] & 0xffff) << 16) |
|
809 | |
|
810 ($this->limbs[1] & 0xffff) |
|
811 ); |
|
812 } |
|
813 |
|
814 /** |
|
815 * @return ParagonIE_Sodium_Core32_Int32 |
|
816 */ |
|
817 public function toInt32() |
|
818 { |
|
819 $return = new ParagonIE_Sodium_Core32_Int32(); |
|
820 $return->limbs[0] = (int) ($this->limbs[0] & 0xffff); |
|
821 $return->limbs[1] = (int) ($this->limbs[1] & 0xffff); |
|
822 $return->unsignedInt = $this->unsignedInt; |
|
823 $return->overflow = (int) ($this->overflow & 0x7fffffff); |
|
824 return $return; |
|
825 } |
|
826 |
|
827 /** |
|
828 * @return ParagonIE_Sodium_Core32_Int64 |
|
829 */ |
|
830 public function toInt64() |
|
831 { |
|
832 $return = new ParagonIE_Sodium_Core32_Int64(); |
|
833 $return->unsignedInt = $this->unsignedInt; |
|
834 if ($this->unsignedInt) { |
|
835 $return->limbs[0] += (($this->overflow >> 16) & 0xffff); |
|
836 $return->limbs[1] += (($this->overflow) & 0xffff); |
|
837 } else { |
|
838 $neg = -(($this->limbs[0] >> 15) & 1); |
|
839 $return->limbs[0] = (int)($neg & 0xffff); |
|
840 $return->limbs[1] = (int)($neg & 0xffff); |
|
841 } |
|
842 $return->limbs[2] = (int) ($this->limbs[0] & 0xffff); |
|
843 $return->limbs[3] = (int) ($this->limbs[1] & 0xffff); |
|
844 return $return; |
|
845 } |
|
846 |
|
847 /** |
|
848 * @return string |
|
849 * @throws TypeError |
|
850 */ |
|
851 public function toReverseString() |
|
852 { |
|
853 return ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) . |
|
854 ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) . |
|
855 ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . |
|
856 ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff); |
|
857 } |
|
858 |
|
859 /** |
|
860 * @return string |
|
861 */ |
|
862 public function __toString() |
|
863 { |
|
864 try { |
|
865 return $this->toString(); |
|
866 } catch (TypeError $ex) { |
|
867 // PHP engine can't handle exceptions from __toString() |
|
868 return ''; |
|
869 } |
|
870 } |
|
871 } |