> (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); } } } ?>