721 lines
26 KiB
PHP
721 lines
26 KiB
PHP
<?php
|
|
/**
|
|
* Copyright (c) 2012 Francisco Blas Izquierdo Riera (klondike)
|
|
* The Tiger algorithm was written by Eli Biham and Ross Anderson and is
|
|
* available on the official Tiger algorithm page.
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* the algorithm authorsip notice, this list of conditions and the following
|
|
* disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
* 4. If this license is not appropriate for you please write me at
|
|
* klondike ( a t ) klondike ( d o t ) es to negotiate another license.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**/
|
|
|
|
/**
|
|
* This class provides 64-bit long unsigned integers in PHP taking care of the
|
|
* odd way in which PHP takes care of wrapping when overflows happen and the
|
|
* lack of unsigned types.
|
|
**/
|
|
|
|
/**
|
|
* It currently supports 64 and 32 bit arches, other arches may be supported in
|
|
* the future.
|
|
* Take in mind that although code for operations like mul and some special
|
|
* operations is provided it hasn't been tested, since they are unneeded for
|
|
* tiger and is thus commented to prevent complaints.
|
|
**/
|
|
|
|
//This function provides a logical right shift for ints.
|
|
//I still wonder why the PHP guys didn't provide one.
|
|
//$v integer value to rotate
|
|
//$n integer number of positions to rotate $n must be positive!
|
|
function lsr($v, $n) {
|
|
return ((int)$v >> (int)$n) & ((PHP_INT_MAX >> (int)$n) | (1 << (((PHP_INT_SIZE * 8) - 1) - (int)$n)));
|
|
}
|
|
|
|
//This class is the responsible off doing overflow aware unsigned airthmethic
|
|
if (PHP_INT_SIZE == 8) {
|
|
class Uint64 {
|
|
private $val;
|
|
|
|
static private function mask($n) {
|
|
return (((int)$n) & 0xffffffff);
|
|
}
|
|
|
|
private function glh() {
|
|
return self::mask($this->val >> 32);
|
|
}
|
|
|
|
private function grh() {
|
|
return self::mask($this->val);
|
|
}
|
|
|
|
private function joinhalves($hl, $hr) {
|
|
return ($hl << 32 | self::mask($hr));
|
|
}
|
|
|
|
private function notp(&$rv) {
|
|
$rv = ~($this->val);
|
|
}
|
|
|
|
private function xorp(Uint64 $n, &$rv) {
|
|
$rv = ($this->val ^ $n->val);
|
|
}
|
|
|
|
private function andp(Uint64 $n, &$rv) {
|
|
$rv = ($this->val & $n->val);
|
|
}
|
|
|
|
private function orp(Uint64 $n, &$rv) {
|
|
$rv = ($this->val | $n->val);
|
|
}
|
|
|
|
private function shrp(Uint64 $n, &$rv) {
|
|
if ($n->val > 63 || $n->val < 0) {
|
|
$rvl = 0;
|
|
$rvr = 0;
|
|
} else {
|
|
$this->shrip($n->val,$rvl,$rvr);
|
|
}
|
|
}
|
|
|
|
private function shlp(Uint64 $n, &$rv) {
|
|
if ($n->val > 63 || $n->val < 0) {
|
|
$rvl = 0;
|
|
$rvr = 0;
|
|
} else {
|
|
$this->shlip($n->val,$rvl,$rvr);
|
|
}
|
|
}
|
|
|
|
//Comodity for ints
|
|
private function shrip($n, &$rv) {
|
|
$rv = lsr($this->val,$n);
|
|
}
|
|
|
|
private function shlip($n, &$rv) {
|
|
$rv = ($this->val << $n);
|
|
}
|
|
|
|
private function addp(Uint64 $n, &$rv) {
|
|
$vr = $this->grh() + $n->grh(); // Never overflows xD
|
|
$vl = $this->glh() + $n->glh() + ($vr >> 32); // Add with overflow
|
|
//The constructor takes care of masking
|
|
$rv = self::joinhalves($vl,$vr);
|
|
}
|
|
|
|
private function subp(Uint64 $n, &$rv) {
|
|
$vr = $this->grh() - $n->grh(); // Never overflows xD
|
|
$vl = $this->glh() - $n->glh() - (($vr >> 32) & 1); // Add with overflow
|
|
//The constructor takes care of masking
|
|
$rv = self::joinhalves($vl,$vr);
|
|
}
|
|
|
|
// private function mulp(Uint64 $n, &$rv) {
|
|
// // We divide in three parts of around 22 bits each
|
|
// $mask = 0x3fffff; // 22 ones
|
|
// $tvr = ($this->val & $mask);
|
|
// $tvm = (($this->val >> 22) & $mask);
|
|
// $tvl = (($this->val >> 44) & $mask);
|
|
// $nvr = ($n->val & $mask);
|
|
// $nvm = (($n->val >> 22) & $mask);
|
|
// $nvl = (($n->val >> 44) & $mask);
|
|
// //We multiply them, the results we get will be of double the size (44 bits < 63) thus overflows are impossible
|
|
// $v0 = $nvr * $tvr; // The lsb is at pos 0
|
|
// $o01 = $nvm * $tvr; // The lsb is at pos 22
|
|
// $o02 = $nvl * $tvr; // The lsb is at pos 44
|
|
// $o10 = $nvr * $tvm; // The lsb is at pos 22
|
|
// $o11 = $nvm * $tvm; // The lsb is at pos 44
|
|
// $o20 = $nvr * $tvl; // The lsb is at pos 44
|
|
// //We now add the shifted results (propagating the up to 24 bit carries)
|
|
// $v1 = $o01 + $o10 + ($v0 >> 22); // The lsb is at pos 22
|
|
// $v2 = $o02 + $o11 + $o20 + ($v1 >> 22); // The lsb is at pos 44
|
|
// //Mask extra bits
|
|
// $v0 &= mask;
|
|
// $v1 &= mask;
|
|
// //Build the value
|
|
// $rv = ($v0 | ($v1 << 22) | ($v2 << 44));
|
|
// }
|
|
|
|
|
|
|
|
public function gb($n) {
|
|
return (($this->val>>($n*8))&0xff);
|
|
}
|
|
|
|
//Standard operations, return a new copy of the object
|
|
public function not_() {
|
|
$this->notp($ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
public function xor_(Uint64 $n) {
|
|
$this->xorp($n,$ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
public function and_(Uint64 $n) {
|
|
$this->andp($n,$ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
public function or_(Uint64 $n) {
|
|
$this->orp($n,$ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
public function shr_(Uint64 $n) {
|
|
$this->shrp($n,$ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
public function shl_(Uint64 $n) {
|
|
$this->shlp($n,$ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
//Comodity for ints
|
|
public function shri($n) {
|
|
$this->shrip($n,$ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
public function shli($n) {
|
|
$this->shlip($n,$ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
public function add_(Uint64 $n) {
|
|
$this->addp($n,$ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
public function sub_(Uint64 $n) {
|
|
$this->subp($n,$ni);
|
|
return new Uint64 ($ni);
|
|
}
|
|
|
|
// public function mul_(Uint64 $n) {
|
|
// $this->mulp($n,$ni);
|
|
// return new Uint64 ($ni);
|
|
// }
|
|
|
|
//Assignment operations, assign the result to this object
|
|
public function xore(Uint64 $n) {
|
|
$this->xorp($n,$this->val);
|
|
return $this;
|
|
}
|
|
|
|
public function ande(Uint64 $n) {
|
|
$this->andp($n,$this->val);
|
|
return $this;
|
|
}
|
|
|
|
public function ore(Uint64 $n) {
|
|
$this->orp($n,$this->val);
|
|
return $this;
|
|
}
|
|
|
|
public function shre(Uint64 $n) {
|
|
$this->shrp($n,$this->val);
|
|
return $this;
|
|
}
|
|
|
|
public function shle(Uint64 $n) {
|
|
$this->shlp($n,$this->val);
|
|
return $this;
|
|
}
|
|
|
|
//Comodity for ints
|
|
public function shrie($n) {
|
|
$this->shrip($n,$this->val);
|
|
return $this;
|
|
}
|
|
|
|
public function shlie($n) {
|
|
$this->shlip($n,$this->val);
|
|
return $this;
|
|
}
|
|
|
|
public function adde(Uint64 $n) {
|
|
$this->addp($n,$this->val);
|
|
return $this;
|
|
}
|
|
|
|
public function sube(Uint64 $n) {
|
|
$this->subp($n,$this->val);
|
|
return $this;
|
|
}
|
|
|
|
// public function mule(Uint64 $n) {
|
|
// $this->mulp($n,$this->val);
|
|
// return $this;
|
|
// }
|
|
//
|
|
// //Other useful operations
|
|
// //Use when the overflow bit is needed
|
|
// public function addo(Uint64 $n, &$of) {
|
|
// $vr = $this->grh() + $n->grh(); // Never overflows xD
|
|
// $vl = $this->glh() + $n->glh() + ($vr >> 32); // Add with overflow
|
|
// //The constructor takes care of masking
|
|
// return new Uint64 ($vl,$vr);
|
|
// }
|
|
//
|
|
// //Use when the overflow bit is needed
|
|
// public function subo(Uint64 $n, &$of) {
|
|
// $vr = $this->grh() - $n->grh(); // Never overflows xD
|
|
// $vl = $this->glh() - $n->glh() - (($vr >> 32) & 1); // Add with overflow
|
|
// $of = (($vl >> 32)&1);
|
|
// //The constructor takes care of masking
|
|
// return new Uint64 ($vl,$vr);
|
|
// }
|
|
//
|
|
// // Returns two Uint64 the first one is the least significative the right one is the most
|
|
// public function mul2_(Uint64 $n) {
|
|
// // We divide in three parts of around 22 bits each
|
|
// $mask = 0x3fffff; // 22 ones
|
|
// $tvr = ($this->val & $mask);
|
|
// $tvm = (($this->val >> 22) & $mask);
|
|
// $tvl = (($this->val >> 44) & $mask);
|
|
// $nvr = ($n->val & $mask);
|
|
// $nvm = (($n->val >> 22) & $mask);
|
|
// $nvl = (($n->val >> 44) & $mask);
|
|
// //We multiply them, the results we get will be of double the size (44 bits < 63) thus overflows are impossible
|
|
// $v0 = $nvr * $tvr; // The lsb is at pos 0
|
|
// $o01 = $nvm * $tvr; // The lsb is at pos 22
|
|
// $o02 = $nvl * $tvr; // The lsb is at pos 44
|
|
// $o10 = $nvr * $tvm; // The lsb is at pos 22
|
|
// $o11 = $nvm * $tvm; // The lsb is at pos 44
|
|
// $o12 = $nvl * $tvm; // The lsb is at pos 66
|
|
// $o20 = $nvr * $tvl; // The lsb is at pos 44
|
|
// $o21 = $nvm * $tvl; // The lsb is at pos 66
|
|
// $o22 = $nvl * $tvl; // The lsb is at pos 88
|
|
// //We now add the shifted results (propagating the up to 24 bit carries)
|
|
// $v1 = $o01 + $o10 + ($v0 >> 22); // The lsb is at pos 22
|
|
// $v2 = $o02 + $o11 + $o20 + ($v1 >> 22); // The lsb is at pos 44
|
|
// $v3 = $o01 + $o10 + ($v2 >> 22); // The lsb is at pos 66
|
|
// $v4 = $o00 + ($v3 >> 22); // The lsb is at pos 88
|
|
// //Mask extra bits
|
|
// $v0 &= mask;
|
|
// $v1 &= mask;
|
|
// $v2 &= mask;
|
|
// $v3 &= mask;
|
|
// //Build the two values now
|
|
// $rr = $v0 | ($v1 << 22) | ($v2 << 44);
|
|
// $rl = ($v2 >> 20) | ($v2 << 2) | ($v3 << 24);
|
|
// return array (new Uint64 ($rr), new Uint64 ($rl));
|
|
// }
|
|
|
|
private function __construct($a) {
|
|
$this->val = (int)$a;
|
|
}
|
|
|
|
static public function from_hex($a) {
|
|
$hc=array_filter(str_split($a),"ctype_xdigit");
|
|
$reduce = function (array $a) {
|
|
return array_reduce($a,function($v, $w) {
|
|
return (($v << 4) | hexdec($w));
|
|
},0);
|
|
};
|
|
return new Uint64 ($reduce(array_slice($hc,-16,16)));
|
|
}
|
|
|
|
//Little endian string read the bytes with the lsB first
|
|
static public function from_les($a) {
|
|
return self::from_bes(strrev($a));
|
|
}
|
|
|
|
//Big endian string read the bytes with the msB first
|
|
static public function from_bes($a) {
|
|
$hc=str_split($a);
|
|
$reduce = function (array $a) {
|
|
return array_reduce($a,function($v, $w) {
|
|
return (($v << 8) | ord($w));
|
|
},0);
|
|
};
|
|
return new Uint64 ($reduce($hc));
|
|
}
|
|
|
|
//Similar to from_les but it assumes each 8 bytes form a different number
|
|
static public function arr_from_les($a) {
|
|
return array_map('self::from_les',str_split($a,8));
|
|
}
|
|
|
|
//Similar to from_bes but it assumes each 8 bytes form a different number
|
|
static public function arr_from_bes($a) {
|
|
return array_map('self::from_les',str_split($a,8));
|
|
}
|
|
|
|
//This creates a new Uint64 from an integer setting any unused bits to zero
|
|
static public function from_int($a) {
|
|
return new Uint64 ($a);
|
|
}
|
|
}
|
|
} else if (PHP_INT_SIZE == 4) {
|
|
class Uint64 {
|
|
private $vall;
|
|
private $valr;
|
|
|
|
static private function mask($n) {
|
|
return (((int)$n) & 0xffff);
|
|
}
|
|
|
|
//Get the MS 16 bits
|
|
private function g0() {
|
|
return self::mask($this->vall >> 16);
|
|
}
|
|
|
|
//Get the next 16 bits
|
|
private function g1() {
|
|
return self::mask($this->vall);
|
|
}
|
|
|
|
//Get the next 16 bits
|
|
private function g2() {
|
|
return self::mask($this->valr >> 16);
|
|
}
|
|
|
|
//Get the LS 16 bits
|
|
private function g3() {
|
|
return self::mask($this->valr);
|
|
}
|
|
|
|
private function joinhalves($hl, $hr) {
|
|
return ($hl << 16 | self::mask($hr));
|
|
}
|
|
|
|
private function notp(&$rvl, &$rvr) {
|
|
$rvl = ~($this->vall);
|
|
$rvr = ~($this->valr);
|
|
}
|
|
|
|
private function xorp(Uint64 $n, &$rvl, &$rvr) {
|
|
$rvl = ($this->vall ^ $n->vall);
|
|
$rvr = ($this->valr ^ $n->valr);
|
|
}
|
|
|
|
private function andp(Uint64 $n, &$rvl, &$rvr) {
|
|
$rvl = ($this->vall & $n->vall);
|
|
$rvr = ($this->valr & $n->valr);
|
|
}
|
|
|
|
private function orp(Uint64 $n, &$rvl, &$rvr) {
|
|
$rvl = ($this->vall | $n->vall);
|
|
$rvr = ($this->valr | $n->valr);
|
|
}
|
|
|
|
private function shrp(Uint64 $n, &$rvl, &$rvr) {
|
|
if ($n->vall || $n->valr > 63 || $n->valr < 0) {
|
|
$rvl = 0;
|
|
$rvr = 0;
|
|
} else {
|
|
$this->shrip($n->valr,$rvl,$rvr);
|
|
}
|
|
}
|
|
|
|
private function shlp(Uint64 $n, &$rvl, &$rvr) {
|
|
if ($n->vall || $n->valr > 63 || $n->valr < 0) {
|
|
$rvl = 0;
|
|
$rvr = 0;
|
|
} else {
|
|
$this->shlip($n->valr,$rvl,$rvr);
|
|
}
|
|
}
|
|
|
|
//HACK: order here is quite important since we could overwrite our inputs
|
|
//Comodity for ints
|
|
private function shrip($n, &$rvl, &$rvr) {
|
|
$rvr = lsr($this->valr,$n) | ($this->vall << (32 - $n));
|
|
$rvl = lsr($this->vall,$n);
|
|
}
|
|
|
|
private function shlip($n, &$rvl, &$rvr) {
|
|
$rvl = ($this->vall << $n) | lsr($this->valr,32 - $n);
|
|
$rvr = ($this->valr << $n);
|
|
}
|
|
|
|
private function addp(Uint64 $n, &$rvl, &$rvr) {
|
|
$v3 = $this->g3() + $n->g3(); // Never overflows xD
|
|
$v2 = $this->g2() + $n->g2() + ($v3 >> 16); // Add with overflow
|
|
$v1 = $this->g1() + $n->g1() + ($v2 >> 16); // Add with overflow
|
|
$v0 = $this->g0() + $n->g0() + ($v1 >> 16); // Add with overflow
|
|
//The constructor takes care of masking
|
|
$rvl = self::joinhalves($v0,$v1);
|
|
$rvr = self::joinhalves($v2,$v3);
|
|
}
|
|
|
|
private function subp(Uint64 $n, &$rvl, &$rvr) {
|
|
$v3 = $this->g3() - $n->g3(); // Never overflows xD
|
|
$v2 = $this->g2() - $n->g2() - (($v3 >> 16) & 1); // Add with overflow
|
|
$v1 = $this->g1() - $n->g1() - (($v2 >> 16) & 1); // Add with overflow
|
|
$v0 = $this->g0() - $n->g0() - (($v1 >> 16) & 1); // Add with overflow
|
|
//The constructor takes care of masking
|
|
$rvl = self::joinhalves($v0,$v1);
|
|
$rvr = self::joinhalves($v2,$v3);
|
|
}
|
|
|
|
// private function mulp(Uint64 $n, &$rvl, &$rvr) {
|
|
// // We divide in three parts of around 22 bits each
|
|
// $mask = 0x3fffff; // 22 ones
|
|
// $tvr = ($this->val & $mask);
|
|
// $tvm = (($this->val >> 22) & $mask);
|
|
// $tvl = (($this->val >> 44) & $mask);
|
|
// $nvr = ($n->val & $mask);
|
|
// $nvm = (($n->val >> 22) & $mask);
|
|
// $nvl = (($n->val >> 44) & $mask);
|
|
// //We multiply them, the results we get will be of double the size (44 bits < 63) thus overflows are impossible
|
|
// $v0 = $nvr * $tvr; // The lsb is at pos 0
|
|
// $o01 = $nvm * $tvr; // The lsb is at pos 22
|
|
// $o02 = $nvl * $tvr; // The lsb is at pos 44
|
|
// $o10 = $nvr * $tvm; // The lsb is at pos 22
|
|
// $o11 = $nvm * $tvm; // The lsb is at pos 44
|
|
// $o20 = $nvr * $tvl; // The lsb is at pos 44
|
|
// //We now add the shifted results (propagating the up to 24 bit carries)
|
|
// $v1 = $o01 + $o10 + ($v0 >> 22); // The lsb is at pos 22
|
|
// $v2 = $o02 + $o11 + $o20 + ($v1 >> 22); // The lsb is at pos 44
|
|
// //Mask extra bits
|
|
// $v0 &= mask;
|
|
// $v1 &= mask;
|
|
// //Build the value
|
|
// $rv = ($v0 | ($v1 << 22) | ($v2 << 44));
|
|
// }
|
|
|
|
|
|
|
|
public function gb($n) {
|
|
if ($n > 3)
|
|
return (($this->vall>>(($n-4)*8))&0xff);
|
|
else
|
|
return (($this->valr>>($n*8))&0xff);
|
|
}
|
|
|
|
//Standard operations, return a new copy of the object
|
|
public function not_() {
|
|
$this->notp($ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
public function xor_(Uint64 $n) {
|
|
$this->xorp($n,$ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
public function and_(Uint64 $n) {
|
|
$this->andp($n,$ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
public function or_(Uint64 $n) {
|
|
$this->orp($n,$ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
public function shr_(Uint64 $n) {
|
|
$this->shrp($n,$ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
public function shl_(Uint64 $n) {
|
|
$this->shlp($n,$ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
//Comodity for ints
|
|
public function shri($n) {
|
|
$this->shrip($n,$ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
public function shli($n) {
|
|
$this->shlip($n,$ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
public function add_(Uint64 $n) {
|
|
$this->addp($n,$ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
public function sub_(Uint64 $n) {
|
|
$this->subp($n,$ni1, $ni2);
|
|
return new Uint64 ($ni1, $ni2);
|
|
}
|
|
|
|
// public function mul_(Uint64 $n) {
|
|
// $this->mulp($n,$ni1, $ni2);
|
|
// return new Uint64 ($ni1, $ni2);
|
|
// }
|
|
|
|
//Assignment operations, assign the result to this object
|
|
public function xore(Uint64 $n) {
|
|
$this->xorp($n,$this->vall, $this->valr);
|
|
return $this;
|
|
}
|
|
|
|
public function ande(Uint64 $n) {
|
|
$this->andp($n,$this->vall, $this->valr);
|
|
return $this;
|
|
}
|
|
|
|
public function ore(Uint64 $n) {
|
|
$this->orp($n,$this->vall, $this->valr);
|
|
return $this;
|
|
}
|
|
|
|
public function shre(Uint64 $n) {
|
|
$this->shrp($n,$this->vall, $this->valr);
|
|
return $this;
|
|
}
|
|
|
|
public function shle(Uint64 $n) {
|
|
$this->shlp($n,$this->vall, $this->valr);
|
|
return $this;
|
|
}
|
|
|
|
//Comodity for ints
|
|
public function shrie($n) {
|
|
$this->shrip($n,$this->vall, $this->valr);
|
|
return $this;
|
|
}
|
|
|
|
public function shlie($n) {
|
|
$this->shlip($n,$this->vall, $this->valr);
|
|
return $this;
|
|
}
|
|
|
|
public function adde(Uint64 $n) {
|
|
$this->addp($n,$this->vall, $this->valr);
|
|
return $this;
|
|
}
|
|
|
|
public function sube(Uint64 $n) {
|
|
$this->subp($n,$this->vall, $this->valr);
|
|
return $this;
|
|
}
|
|
|
|
// public function mule(Uint64 $n) {
|
|
// $this->mulp($n,$this->vall, $this->valr);
|
|
// return $this;
|
|
// }
|
|
|
|
// //Other useful operations
|
|
// //Use when the overflow bit is needed
|
|
// public function addo(Uint64 $n, &$of) {
|
|
// $vr = $this->grh() + $n->grh(); // Never overflows xD
|
|
// $vl = $this->glh() + $n->glh() + ($vr >> 32); // Add with overflow
|
|
// //The constructor takes care of masking
|
|
// return new Uint64 ($vl,$vr);
|
|
// }
|
|
//
|
|
// //Use when the overflow bit is needed
|
|
// public function subo(Uint64 $n, &$of) {
|
|
// $vr = $this->grh() - $n->grh(); // Never overflows xD
|
|
// $vl = $this->glh() - $n->glh() - (($vr >> 32) & 1); // Add with overflow
|
|
// $of = (($vl >> 32)&1);
|
|
// //The constructor takes care of masking
|
|
// return new Uint64 ($vl,$vr);
|
|
// }
|
|
//
|
|
// // Returns two Uint64 the first one is the least significative the right one is the most
|
|
// public function mul2_(Uint64 $n) {
|
|
// // We divide in three parts of around 22 bits each
|
|
// $mask = 0x3fffff; // 22 ones
|
|
// $tvr = ($this->val & $mask);
|
|
// $tvm = (($this->val >> 22) & $mask);
|
|
// $tvl = (($this->val >> 44) & $mask);
|
|
// $nvr = ($n->val & $mask);
|
|
// $nvm = (($n->val >> 22) & $mask);
|
|
// $nvl = (($n->val >> 44) & $mask);
|
|
// //We multiply them, the results we get will be of double the size (44 bits < 63) thus overflows are impossible
|
|
// $v0 = $nvr * $tvr; // The lsb is at pos 0
|
|
// $o01 = $nvm * $tvr; // The lsb is at pos 22
|
|
// $o02 = $nvl * $tvr; // The lsb is at pos 44
|
|
// $o10 = $nvr * $tvm; // The lsb is at pos 22
|
|
// $o11 = $nvm * $tvm; // The lsb is at pos 44
|
|
// $o12 = $nvl * $tvm; // The lsb is at pos 66
|
|
// $o20 = $nvr * $tvl; // The lsb is at pos 44
|
|
// $o21 = $nvm * $tvl; // The lsb is at pos 66
|
|
// $o22 = $nvl * $tvl; // The lsb is at pos 88
|
|
// //We now add the shifted results (propagating the up to 24 bit carries)
|
|
// $v1 = $o01 + $o10 + ($v0 >> 22); // The lsb is at pos 22
|
|
// $v2 = $o02 + $o11 + $o20 + ($v1 >> 22); // The lsb is at pos 44
|
|
// $v3 = $o01 + $o10 + ($v2 >> 22); // The lsb is at pos 66
|
|
// $v4 = $o00 + ($v3 >> 22); // The lsb is at pos 88
|
|
// //Mask extra bits
|
|
// $v0 &= mask;
|
|
// $v1 &= mask;
|
|
// $v2 &= mask;
|
|
// $v3 &= mask;
|
|
// //Build the two values now
|
|
// $rr = $v0 | ($v1 << 22) | ($v2 << 44);
|
|
// $rl = ($v2 >> 20) | ($v2 << 2) | ($v3 << 24);
|
|
// return array (new Uint64 ($rr), new Uint64 ($rl));
|
|
// }
|
|
|
|
private function __construct($lv, $rv) {
|
|
$this->vall = (int)$lv;
|
|
$this->valr = (int)$rv;
|
|
}
|
|
|
|
static public function from_hex($a) {
|
|
$hc=array_filter(str_split($a),"ctype_xdigit");
|
|
$reduce = function (array $a) {
|
|
return array_reduce($a,function($v, $w) {
|
|
return (($v << 4) | hexdec($w));
|
|
},0);
|
|
};
|
|
return new Uint64 ($reduce(array_slice($hc,-16,8)),$reduce(array_slice($hc,-8,8)));
|
|
}
|
|
|
|
//Little endian string read the bytes with the lsB first
|
|
static public function from_les($a) {
|
|
return self::from_bes(strrev($a));
|
|
}
|
|
|
|
//Big endian string read the bytes with the msB first
|
|
static public function from_bes($a) {
|
|
$hc=str_split($a);
|
|
$reduce = function (array $a) {
|
|
return array_reduce($a,function($v, $w) {
|
|
return (($v << 8) | ord($w));
|
|
},0);
|
|
};
|
|
return new Uint64 ($reduce(array_slice($hc,-8,4)),$reduce(array_slice($hc,-4,4)));
|
|
}
|
|
|
|
//Similar to from_les but it assumes each 8 bytes form a different number
|
|
static public function arr_from_les($a) {
|
|
return array_map('self::from_les',str_split($a,8));
|
|
}
|
|
|
|
//Similar to from_bes but it assumes each 8 bytes form a different number
|
|
static public function arr_from_bes($a) {
|
|
return array_map('self::from_les',str_split($a,8));
|
|
}
|
|
|
|
//This creates a new Uint64 from an integer setting any unused bits to zero
|
|
static public function from_int($a) {
|
|
return new Uint64 (0,$a);
|
|
}
|
|
}
|
|
}
|
|
|
|
?>
|